diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index ae8a4c1fe..dc5f6486c 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -62,5 +62,5 @@ jobs: ssh-key: ${{ secrets.ACTIONS_DEPLOY_KEY }} repository-name: fury-gl/fury-website folder: ./docs/build/html-web-only - target-folder: v0.10.x + target-folder: v0.11.x clean: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a3bdb5fb8..9ed6db979 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.8, 3.9, '3.10', 3.11] + python-version: [3.9, '3.10', 3.11, 3.12] os: [ubuntu-latest, macos-latest, windows-latest] platform: [x64] install-type: [pip, ] # conda] @@ -34,13 +34,13 @@ jobs: use-pre: [false] include: - os: macos-latest # ubuntu-latest - python-version: '3.10' + python-version: 3.11 install-type: pip depends: OPTIONAL_DEPS coverage: true use-pre: false - os: ubuntu-latest - python-version: '3.10' + python-version: 3.12 install-type: pip depends: OPTIONAL_DEPS coverage: false @@ -53,6 +53,8 @@ jobs: USE_PRE: ${{ matrix.use-pre }} COVERAGE: ${{ matrix.coverage }} PRE_WHEELS: "https://pypi.anaconda.org/scipy-wheels-nightly/simple" + # EAGER_IMPORT: 1 # to explore what is the issue. + steps: - uses: actions/checkout@v4 diff --git a/.mailmap b/.mailmap index e41e11bab..ec1c81c9a 100644 --- a/.mailmap +++ b/.mailmap @@ -63,3 +63,8 @@ Francois Rheault frheault Dwij Raj Hari <75260253+dwijrajhari@users.noreply.github.com> Tania Castillo tvcastillod Tania Castillo Tania Castillo <31288525+tvcastillod@users.noreply.github.com> +Wachiou BOURAÏMA Wachiou BOURAÏMA <100234404+WassCodeur@users.noreply.github.com> +Ishan Kamboj Ishan Kamboj <67258435+IshanKamboj@users.noreply.github.com> +Robin Roy Robin Roy <115863770+robinroy03@users.noreply.github.com> +Robin Roy Robin +Kaustav Deka Kaustav Deka <116963260+deka27@users.noreply.github.com> diff --git a/.pep8speaks.yml b/.pep8speaks.yml index 556c01523..512e66efa 100644 --- a/.pep8speaks.yml +++ b/.pep8speaks.yml @@ -10,3 +10,26 @@ message: # Customize the comment made by the bot header: "Hello @{name}, Thank you for updating!" footer: "To test for issues locally, `pip install flake8` and then run `flake8 fury`." no_errors: "Cheers! There are no style issues detected in this Pull Request. :beers: " + +pycodestyle: + max-line-length: 88 # Default is 79 in PEP8 + # ignore: # Errors and warnings to ignore + # - W391 + # - E203 + # exclude: + # - doc/examples + # - dipy/info.py + # - doc/conf.py +flake8: # Valid if scanner.linter is flake8 + max-line-length: 88 # Default is 79 in PEP8 + ignore: [] + exclude: [] + count: False + show-source: False + statistics: False + hang-closing: False + filename: [] + select: [] + +only_mention_files_with_errors: True # If False, a separate status comment for each file is made. +descending_issues_order: False # If True, PEP8 issues in message will be displayed in descending order of line numbers in the file diff --git a/AUTHORS.rst b/AUTHORS.rst index 3ec11a40b..f7c7e9894 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -17,71 +17,91 @@ Contributors * Serge Koudoro * Eleftherios Garyfallidis -* Soham Biswas +* Mohamed Agour +* Praneeth Shetty * Javier Guaje -* Sajag Swami +* Anand Shivam * Bruno Messias +* Soham Biswas +* Sajag Swami +* Antriksh Misri +* Tania Castillo * Ranveer Aggarwal * Lenix Lobo +* Joao Victor Dell Agli * Marc-Alexandre Côté * Melina Raglin -* Antriksh Misri -* Karan * Ariel Rokem +* Karan +* maharshigor +* Filipi Nascimento Silva * David Reagan -* Vivek Choudhary +* Nasim Anousheh * Prashil +* Vivek Choudhary * Saransh Jain -* Nasim Anousheh * Shreyas Bhujbal * Tushar -* Matthew Brett +* Wachiou BOURAÏMA +* Zhiwen Shi * Charles Poirier +* Ishan Kamboj +* Matthew Brett +* Frank Cerasoli +* Sreekar Chigurupati +* Francois Rheault * Naman Bansal +* Robin Roy * Etienne St-Onge * Kesshi Jordan -* Praneeth Shetty -* ibrahimAnis +* Amit Chaudhari * Bago Amirbekian +* Jon Haitz Legarreta Gorroño * Omar Ocegueda -* Amit Chaudhari -* Meha Bhalodiya +* ibrahimAnis * Kevin Sitek +* Meha Bhalodiya * Sanjay Marreddi +* sparshg * ChenCheng0630 -* Jon Haitz Legarreta Gorroño * Gregory R. Lee -* Filipi Nascimento Silva +* Enes Albay * Liam Donohue -* Anand Shivam +* Rohit Kharsan * Shahnawaz Ahmed -* Tingyi Wanyan -* Enes Albay * Stefan van der Walt -* PrayasJ +* Tingyi Wanyan +* Dwij Raj Hari * Guillaume Favelier +* Johny Daras +* PrayasJ * Samuel St-Jean +* Bishakh Ghosh * Gottipati Gautam -* theaverageguy * Hariharan Ayappane -* Bishakh Ghosh -* Jhalak Gupta +* Maharshi Gor +* theaverageguy * Aju100 -* Christopher Nguyen * Alexandre Gauvin -* Scott Trinkle +* Christopher Nguyen +* Jhalak Gupta * Jiri Borovec * Marssis +* Sara Hamza +* Scott Trinkle +* Siddharth Gautam +* dependabot[bot] * Adam Rybinski -* LoopThrough-i-j -* Ian Nimmo-Smith * Aman Soni +* Daniel S. Katz +* Devanshu Modi * Gauvin Alexandre -* Pietro Astolfi * Gurdit Siyan -* Devanshu Modi -* Daniel S. Katz +* Ian Nimmo-Smith * Jacob Wasserth -* Yaroslav Halchenko +* Kaustav Deka +* LoopThrough-i-j * MIHIR -* Shivam Anand +* Pietro Astolfi +* Yaroslav Halchenko +* sailesh diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index c0cbc1d14..d1e8108e3 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -125,15 +125,15 @@ Checklist before Releasing outstanding issues that can be closed, and whether there are any issues that should delay the release. Label them ! -* Check whether there are no build failing on `Travis`. +* Check whether there are no build failing on `GitHub Actions`. * Review and update the release notes. Get a partial list of contributors with something like:: - git shortlog -nse v0.1.0.. + git shortlog -nse v0.10.0.. - where ``v0.1.0`` was the last release tag name. + where ``v0.10.0`` was the last release tag name. - Then manually go over ``git shortlog v0.1.0..`` to make sure the release notes + Then manually go over ``git shortlog v0.10.0..`` to make sure the release notes are as complete as possible and that every contributor was recognized. * Use the opportunity to update the ``.mailmap`` file if there are any duplicate @@ -145,16 +145,18 @@ Checklist before Releasing * Generate release notes. Go to ``docs/source/ext`` and run ``github_tools.py`` script the following way:: - $ python github_tools.py --tag=v0.1.0 --save --version=0.2.0 + $ python github_tools.py --tag=v0.10.0 --save --version=0.11.0 - This command will generate a new file named ``release0.2.0.rst`` in ``release_notes`` folder. + This command will generate a new file named ``release0.11.0.rst`` in ``release_notes`` folder. + +* Add in ``release-history.rst`` the newly created file ``release0.11.0.rst``. * Check the examples and tutorial - we really need an automated check here. * Make sure all tests pass on your local machine (from the ```` directory):: cd .. - pytest -s --verbose --doctest-modules fury + pytest -svv --doctest-modules fury cd fury # back to the root directory * Check the documentation doctests:: @@ -213,8 +215,7 @@ Doing the release * Publish a release on PyPI:: - python setup.py sdist - python setup.py bdist_wheel + python -m build twine upload dist/* diff --git a/docs/examples/viz_advanced.py b/docs/examples/viz_advanced.py index bf28b0b91..43b569c28 100644 --- a/docs/examples/viz_advanced.py +++ b/docs/examples/viz_advanced.py @@ -11,6 +11,7 @@ the main functions using the following modules. """ +import fury from dipy.data.fetcher import fetch_bundles_2_subjects, read_bundles_2_subjects ############################################################################### @@ -37,7 +38,6 @@ from dipy.tracking.streamline import Streamlines import numpy as np -from fury import actor, ui, window fetch_bundles_2_subjects() @@ -82,13 +82,13 @@ # Now we create, a ``Scene`` object and add the streamlines using the # ``line`` function and an image plane using the ``slice`` function. -scene = window.Scene() -stream_actor = actor.line(streamlines) +scene = fury.window.Scene() +stream_actor = fury.actor.line(streamlines) if not world_coords: - image_actor_z = actor.slicer(data, affine=np.eye(4)) + image_actor_z = fury.actor.slicer(data, affine=np.eye(4)) else: - image_actor_z = actor.slicer(data, affine) + image_actor_z = fury.actor.slicer(data, affine) ############################################################################### # We can also change also the opacity of the slicer. @@ -123,14 +123,14 @@ # ``show``. The more appropriate way is to use them with the ``ShowManager`` # object which allows accessing the pipeline in different areas. Here is how: -show_m = window.ShowManager(scene, size=(1200, 900)) +show_m = fury.window.ShowManager(scene, size=(1200, 900)) ############################################################################### # After we have initialized the ``ShowManager`` we can go ahead and create # sliders to move the slices and change their opacity. -line_slider_z = ui.LineSlider2D( +line_slider_z = fury.ui.LineSlider2D( min_value=0, max_value=shape[2] - 1, initial_value=shape[2] / 2, @@ -138,7 +138,7 @@ length=140, ) -line_slider_x = ui.LineSlider2D( +line_slider_x = fury.ui.LineSlider2D( min_value=0, max_value=shape[0] - 1, initial_value=shape[0] / 2, @@ -146,7 +146,7 @@ length=140, ) -line_slider_y = ui.LineSlider2D( +line_slider_y = fury.ui.LineSlider2D( min_value=0, max_value=shape[1] - 1, initial_value=shape[1] / 2, @@ -154,7 +154,7 @@ length=140, ) -opacity_slider = ui.LineSlider2D( +opacity_slider = fury.ui.LineSlider2D( min_value=0.0, max_value=1.0, initial_value=slicer_opacity, length=140 ) @@ -194,7 +194,7 @@ def change_opacity(slider): def build_label(text): - label = ui.TextBlock2D() + label = fury.ui.TextBlock2D() label.message = text label.font_size = 18 label.font_family = "Arial" @@ -216,7 +216,7 @@ def build_label(text): ############################################################################### # Now we will create a ``panel`` to contain the sliders and labels. -panel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align="right") +panel = fury.ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align="right") panel.center = (1030, 120) panel.add_element(line_slider_label_x, (0.1, 0.75)) @@ -267,7 +267,7 @@ def win_callback(obj, _event): show_m.start() else: - window.record( + fury.window.record( scene, out_path="bundles_and_3_slices.png", size=(1200, 900), reset_camera=False ) diff --git a/docs/examples/viz_animated_surfaces.py b/docs/examples/viz_animated_surfaces.py index da166421c..7ab83ee8f 100644 --- a/docs/examples/viz_animated_surfaces.py +++ b/docs/examples/viz_animated_surfaces.py @@ -13,8 +13,7 @@ import itertools import numpy as np - -from fury import actor, colormap, ui, utils, window +import fury ############################################################################### # The following function is used to create and update the coordinates of the @@ -33,20 +32,22 @@ def update_surface(x, y, equation, cmap_name="viridis"): v = np.copy(z) m_v = np.max(np.abs(v), axis=0) v /= m_v if m_v else 1 - colors = colormap.create_colormap(v, name=cmap_name) + colors = fury.colormap.create_colormap(v, name=cmap_name) return xyz, colors ############################################################################### # Variables and their usage: -# :time - float: initial value of the time variable i.e. value of the time variable at -# the beginning of the program; (default = 0) +# +# time: float +# initial value of the time variable i.e. value of the time variable at +# the beginning of the program; (default = 0) # dt: float -# amount by which ``time`` variable is incremented for every iteration -# of timer_callback function (default = 0.1) +# amount by which ``time`` variable is incremented for every iteration +# of timer_callback function (default = 0.1) # lower_xbound: float -# lower bound of the x values in which the function is plotted +# lower bound of the x values in which the function is plotted # (default = -1) # upper_xbound: float # Upper bound of the x values in which the function is plotted @@ -86,10 +87,10 @@ def update_surface(x, y, equation, cmap_name="viridis"): def create_surface(x, y, equation, colormap_name): xyz, colors = update_surface(x, y, equation=equation, cmap_name=colormap_name) - surf = actor.surface(xyz, colors=colors) + surf = fury.actor.surface(xyz, colors=colors) surf.equation = equation surf.cmap_name = colormap_name - surf.vertices = utils.vertices_from_actor(surf) + surf.vertices = fury.utils.vertices_from_actor(surf) surf.no_vertices_per_point = len(surf.vertices) / npoints**2 surf.initial_vertices = surf.vertices.copy() - np.repeat( xyz, surf.no_vertices_per_point, axis=0 @@ -123,11 +124,11 @@ def create_surface(x, y, equation, colormap_name): ############################################################################### # Creating a scene object and configuring the camera's position -scene = window.Scene() +scene = fury.window.Scene() scene.set_camera( position=(4.45, -21, 12), focal_point=(4.45, 0.0, 0.0), view_up=(0.0, 0.0, 1.0) ) -showm = window.ShowManager(scene, size=(600, 600)) +showm = fury.window.ShowManager(scene, size=(600, 600)) ############################################################################### # Creating a grid to interact with surfaces individually. @@ -135,12 +136,12 @@ def create_surface(x, y, equation, colormap_name): # To store the function names text = [] for i in range(4): - t_actor = actor.vector_text( + t_actor = fury.actor.vector_text( "Function " + str(i + 1), pos=(0, 0, 0), scale=(0.17, 0.2, 0.2) ) text.append(t_actor) -grid_ui = ui.GridUI( +grid_ui = fury.ui.GridUI( actors=surfaces, captions=text, caption_offset=(-0.7, -2.5, 0), @@ -152,12 +153,12 @@ def create_surface(x, y, equation, colormap_name): showm.scene.add(grid_ui) # Adding an axes actor to the first surface. -showm.scene.add(actor.axes()) +showm.scene.add(fury.actor.axes()) ############################################################################### # Initializing text box to print the title of the animation -tb = ui.TextBlock2D(bold=True, position=(200, 60)) +tb = fury.ui.TextBlock2D(bold=True, position=(200, 60)) tb.message = "Animated 2D functions" scene.add(tb) @@ -186,11 +187,11 @@ def timer_callback(_obj, _event): xyz, colors = update_surface( x, y, equation=surf.equation, cmap_name=surf.cmap_name ) - utils.update_surface_actor_colors(surf, colors) + fury.utils.update_surface_actor_colors(surf, colors) surf.vertices[:] = surf.initial_vertices + np.repeat( xyz, surf.no_vertices_per_point, axis=0 ) - utils.update_actor(surf) + fury.utils.update_actor(surf) showm.render() # to end the animation @@ -206,4 +207,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(showm.scene, size=(600, 600), out_path="viz_animated_surfaces.png") +fury.window.record(showm.scene, size=(600, 600), out_path="viz_animated_surfaces.png") diff --git a/docs/examples/viz_arrow.py b/docs/examples/viz_arrow.py index bd6ac3845..afb510e0e 100644 --- a/docs/examples/viz_arrow.py +++ b/docs/examples/viz_arrow.py @@ -6,9 +6,9 @@ This example shows how to use the arrow actor. """ +import fury import numpy as np -from fury import actor, window ############################################################################ # First thing, you have to specify centers, directions, and colors of the @@ -25,7 +25,7 @@ ############################################################################ # The below arrow actor is generated by repeating the arrow primitive. -arrow_actor = actor.arrow(centers, dirs, colors=colors, scales=1.5) +arrow_actor = fury.actor.arrow(centers, dirs, colors=colors, scales=1.5) ############################################################################ # repeating what we did but this time with random centers, directions, and @@ -35,9 +35,9 @@ dir2 = np.random.rand(5, 3) cols2 = np.random.rand(5, 3) -arrow_actor2 = actor.arrow(cen2, dir2, colors=cols2, scales=1.5) +arrow_actor2 = fury.actor.arrow(cen2, dir2, colors=cols2, scales=1.5) -scene = window.Scene() +scene = fury.window.Scene() ############################################################################ # Adding our Arrow actors to scene. @@ -48,6 +48,6 @@ interactive = False if interactive: - window.show(scene, size=(600, 600)) + fury.window.show(scene, size=(600, 600)) -window.record(scene, out_path="viz_arrow.png", size=(600, 600)) +fury.window.record(scene, out_path="viz_arrow.png", size=(600, 600)) diff --git a/docs/examples/viz_ball_collide.py b/docs/examples/viz_ball_collide.py index dd991cf8c..2b95a131f 100644 --- a/docs/examples/viz_ball_collide.py +++ b/docs/examples/viz_ball_collide.py @@ -15,7 +15,7 @@ import numpy as np import pybullet as p -from fury import actor, ui, window +import fury client = p.connect(p.DIRECT) @@ -27,7 +27,7 @@ duration = 50 # Red Ball -red_ball_actor = actor.sphere( +red_ball_actor = fury.actor.sphere( centers=np.array([[0, 0, 0]]), colors=np.array([[1, 0, 0]]), radii=red_radius ) @@ -41,7 +41,7 @@ ) # Blue ball -blue_ball_actor = actor.sphere( +blue_ball_actor = fury.actor.sphere( centers=np.array([[0, 0, 0]]), colors=np.array([[0, 0, 1]]), radii=blue_radius ) @@ -63,12 +63,12 @@ ############################################################################### # We add all the actors to the scene. -scene = window.Scene() -scene.add(actor.axes()) +scene = fury.window.Scene() +scene.add(fury.actor.axes()) scene.add(red_ball_actor) scene.add(blue_ball_actor) -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 700), reset_camera=False, order_transparent=True ) @@ -87,7 +87,7 @@ def sync_actor(actor, multibody): apply_force = True -tb = ui.TextBlock2D(position=(0, 600), font_size=30, color=(1, 0.5, 0), text="") +tb = fury.ui.TextBlock2D(position=(0, 600), font_size=30, color=(1, 0.5, 0), text="") scene.add(tb) scene.set_camera( position=(0.30, -18.78, 0.89), focal_point=(0.15, 0.25, 0.40), view_up=(0, 0, 1.00) @@ -138,4 +138,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, size=(900, 700), out_path="viz_ball_collide.png") +fury.window.record(scene, size=(900, 700), out_path="viz_ball_collide.png") diff --git a/docs/examples/viz_bezier_interpolator.py b/docs/examples/viz_bezier_interpolator.py index 1e833b4c2..ff34396f7 100644 --- a/docs/examples/viz_bezier_interpolator.py +++ b/docs/examples/viz_bezier_interpolator.py @@ -7,10 +7,7 @@ """ import numpy as np - -from fury import actor, window -from fury.animation import Animation, Timeline -from fury.animation.interpolator import cubic_bezier_interpolator +import fury ############################################################################### # Position interpolation using cubic Bezier curve @@ -20,8 +17,8 @@ # This can be achieved using positions and control points between those # positions. -scene = window.Scene() -showm = window.ShowManager( +scene = fury.window.Scene() +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) @@ -31,46 +28,49 @@ # ============================= # In order to make a cubic bezier curve based animation, you need four values # for every keyframe: +# # 1- Timestamp: The time that the keyframe is assigned to. -# 2- value: The value of the keyframe. This might be position, quaternion, or -# scale value. -# 3- In control point: The control point used when the value is the destination -# value. +# +# 2- Value: The value of the keyframe. This might be position, quaternion, or scale +# value. +# +# 3- In control point: The control point used when the value is the destination value. +# # 4- Out control point: The control point used when the value is the departure -# value:: +# value:: # -# keyframe 0 -----------------> keyframe 1 -# (time-0) (value-0) (out-cp-0) -----------------> (time-1) (value-1) (in-cp-1) +# keyframe 0 -----------------> keyframe 1 +# (time-0) (value-0) (out-cp-0) -----------------> (time-1) (value-1) (in-cp-1) +# keyframe 1 -----------------> keyframe 2 +# (time-1) (value-1) (out-cp-1) -----------------> (time-2) (value-2) (in-cp-2) # -# keyframe 1 -----------------> keyframe 2 -# (time-1) (value-1) (out-cp-1) -----------------> (time-2) (value-2) (in-cp-2) keyframe_1 = {"value": [-2, 0, 0], "out_cp": [-15, 6, 0]} keyframe_2 = {"value": [18, 0, 0], "in_cp": [27, 18, 0]} ############################################################################### # Visualizing points -pts_actor = actor.sphere( +pts_actor = fury.actor.sphere( np.array([keyframe_1.get("value"), keyframe_2.get("value")]), (1, 0, 0), radii=0.3 ) ############################################################################### # Visualizing the control points -cps_actor = actor.sphere( +cps_actor = fury.actor.sphere( np.array([keyframe_2.get("in_cp"), keyframe_1.get("out_cp")]), (0, 0, 1), radii=0.6 ) ############################################################################### # Visualizing the connection between the control points and the points -cline_actor = actor.line( +cline_actor = fury.actor.line( np.array([list(keyframe_1.values()), list(keyframe_2.values())]), colors=np.array([0, 1, 0]), ) ############################################################################### # Initializing an ``Animation`` and adding sphere actor to it. -animation = Animation() -sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1)) +animation = fury.animation.Animation() +sphere = fury.actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1)) animation.add_actor(sphere) ############################################################################### @@ -79,10 +79,12 @@ # # Cubic Bezier keyframes consists of 4 data per keyframe # Timestamp, position, in control point, and out control point. +# # - In control point is the cubic bezier control point for the associated # position when this position is the destination position. # - Out control point is the cubic bezier control point for the associated # position when this position is the origin position or departing position. +# # Note: If a control point is not provided or set `None`, this control point # will be the same as the position itself. @@ -95,7 +97,7 @@ ############################################################################### # Changing position interpolation into cubic bezier interpolation -animation.set_position_interpolator(cubic_bezier_interpolator) +animation.set_position_interpolator(fury.animation.cubic_bezier_interpolator) ############################################################################### # Adding the visualization actors to the scene. @@ -110,15 +112,19 @@ if interactive: showm.start() -window.record(scene, out_path="viz_keyframe_animation_bezier_1.png", size=(900, 768)) +fury.window.record( + scene, + out_path="viz_keyframe_animation_bezier_1.png", + size=(900, 768), +) ############################################################################### # A more complex scene scene # ========================== # -scene = window.Scene() -show_manager = window.ShowManager( +scene = fury.window.Scene() +show_manager = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) @@ -134,11 +140,11 @@ ############################################################################### # Create the sphere actor. -sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1)) +sphere = fury.actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1)) ############################################################################### # Create an ``Animation`` and adding the sphere actor to it. -animation = Animation(sphere) +animation = fury.animation.Animation(sphere) ############################################################################### # Setting Cubic Bezier keyframes @@ -146,7 +152,7 @@ ############################################################################### # changing position interpolation into cubic bezier interpolation -animation.set_position_interpolator(cubic_bezier_interpolator) +animation.set_position_interpolator(fury.animation.cubic_bezier_interpolator) ########################################################################### # visualizing the points and control points (only for demonstration) @@ -157,21 +163,23 @@ ########################################################################### # visualizing position keyframe - vis_point = actor.sphere(np.array([pos]), (1, 0, 0), radii=0.3) + vis_point = fury.actor.sphere(np.array([pos]), (1, 0, 0), radii=0.3) scene.add(vis_point) ########################################################################### # Visualizing the control points and their length (if exist) for cp in [in_control_point, out_control_point]: if cp is not None: - vis_cps = actor.sphere(np.array([cp]), (0, 0, 1), radii=0.6) - cline_actor = actor.line(np.array([[pos, cp]]), colors=np.array([0, 1, 0])) + vis_cps = fury.actor.sphere(np.array([cp]), (0, 0, 1), radii=0.6) + cline_actor = fury.actor.line( + np.array([[pos, cp]]), colors=np.array([0, 1, 0]) + ) scene.add(vis_cps, cline_actor) ############################################################################### # Initializing the timeline to be able to control the playback of the # animation. -timeline = Timeline(animation, playback_panel=True) +timeline = fury.animation.Timeline(animation, playback_panel=True) ############################################################################### # We only need to add the ``Timeline`` to the ``ShowManager`` @@ -182,4 +190,6 @@ if interactive: show_manager.start() -window.record(scene, out_path="viz_keyframe_animation_bezier_2.png", size=(900, 768)) +fury.window.record( + showm.scene, out_path="viz_keyframe_animation_bezier_2.png", size=(900, 768) +) diff --git a/docs/examples/viz_billboard_sdf_spheres.py b/docs/examples/viz_billboard_sdf_spheres.py index e9c61e41c..324809d4e 100644 --- a/docs/examples/viz_billboard_sdf_spheres.py +++ b/docs/examples/viz_billboard_sdf_spheres.py @@ -32,15 +32,14 @@ import os +import fury import numpy as np - -from fury import actor, window from fury.shaders import compose_shader, import_fury_shader from fury.utils import represent_actor_as_wireframe ############################################################################### # Now set up a new scene to place our actors in. -scene = window.Scene() +scene = fury.window.Scene() ############################################################################### # This tutorial is divided into two parts. First, we will render spheres in the @@ -66,7 +65,7 @@ [[1, 1, 0], [1, 0, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [0, 1, 0], [0, 1, 1]] ) scales = np.array([6, 1.2, 1, 0.2, 0.7, 3, 2]) -spheres_actor = actor.sphere( +spheres_actor = fury.actor.sphere( centers, colors, radii=scales, phi=8, theta=8, use_primitive=False ) @@ -79,9 +78,9 @@ interactive = False if interactive: - window.show(scene) + fury.window.show(scene) else: - window.record(scene, size=(600, 600), out_path="viz_regular_spheres.png") + fury.window.record(scene, size=(600, 600), out_path="viz_regular_spheres.png") ############################################################################### # Now, let's explore our scene to understand what we have created. Traditional @@ -91,23 +90,23 @@ represent_actor_as_wireframe(spheres_actor) if interactive: - window.show(scene) + fury.window.show(scene) else: - window.record(scene, size=(600, 600), out_path="viz_low_res_wireframe.png") + fury.window.record(scene, size=(600, 600), out_path="viz_low_res_wireframe.png") ############################################################################### # Let's clean the scene and play with the parameters `phi` and `theta`. scene.clear() -spheres_actor = actor.sphere( +spheres_actor = fury.actor.sphere( centers, colors, radii=scales, phi=16, theta=16, use_primitive=False ) represent_actor_as_wireframe(spheres_actor) scene.add(spheres_actor) if interactive: - window.show(scene) + fury.window.show(scene) else: - window.record(scene, size=(600, 600), out_path="viz_hi_res_wireframe.png") + fury.window.record(scene, size=(600, 600), out_path="viz_hi_res_wireframe.png") ############################################################################### # As you might have noticed, these parameters control the resolution of the @@ -131,14 +130,14 @@ ############################################################################### # The billboard actor is suited and continuously improved to render SDFs. To # create and visualize it, we can use the following instructions: -billboards_actor = actor.billboard(centers, colors=colors, scales=scales) +billboards_actor = fury.actor.billboard(centers, colors=colors, scales=scales) represent_actor_as_wireframe(billboards_actor) scene.add(billboards_actor) if interactive: - window.show(scene) + fury.window.show(scene) else: - window.record(scene, size=(600, 600), out_path="viz_billboards_wireframe.png") + fury.window.record(scene, size=(600, 600), out_path="viz_billboards_wireframe.png") ############################################################################### # If you interacted with this actor, you might have noticed how it always @@ -180,15 +179,15 @@ ############################################################################### # We are ready to create and visualize our SDF-billboard actors. -spheres_actor = actor.billboard( +spheres_actor = fury.actor.billboard( centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl ) scene.add(spheres_actor) if interactive: - window.show(scene) + fury.window.show(scene) else: - window.record(scene, size=(600, 600), out_path="viz_billboards_circles.png") + fury.window.record(scene, size=(600, 600), out_path="viz_billboards_circles.png") ############################################################################### # Hold on, those actors don't look exactly like the ones we created using @@ -273,21 +272,20 @@ ############################################################################### # Finally, recreate the SDF billboard actors and visualize them. -spheres_actor = actor.billboard( +spheres_actor = fury.actor.billboard( centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl ) scene.add(spheres_actor) if interactive: - window.show(scene) + fury.window.show(scene) else: - window.record(scene, size=(600, 600), out_path="viz_billboards_spheres.png") + fury.window.record(scene, size=(600, 600), out_path="viz_billboards_spheres.png") ############################################################################### # References # ---------- -# .. [Hart1996] Hart, John C. "Sphere tracing: A geometric method for the +# .. _[Hart1996] Hart, John C. "Sphere tracing: A geometric method for the # antialiased ray tracing of implicit surfaces." The Visual # Computer 12.10 (1996): 527-545. # -# .. include:: ../links_names.inc diff --git a/docs/examples/viz_brick_wall.py b/docs/examples/viz_brick_wall.py index 4d490450e..9e158a6ee 100644 --- a/docs/examples/viz_brick_wall.py +++ b/docs/examples/viz_brick_wall.py @@ -14,8 +14,7 @@ import numpy as np import pybullet as p - -from fury import actor, ui, utils, window +import fury ############################################################################### # Next, we initialize a pybullet client to render the physics. We use `DIRECT` @@ -54,7 +53,7 @@ # Now we define the required parameters to render the Ball. # Ball actor -ball_actor = actor.sphere( +ball_actor = fury.actor.sphere( centers=np.array([[0, 0, 0]]), colors=ball_color, radii=ball_radius ) @@ -75,7 +74,7 @@ ############################################################################### # Render a base plane to support the bricks. -base_actor = actor.box( +base_actor = fury.actor.box( centers=np.array([[0, 0, 0]]), directions=[0, 0, 0], scales=base_size, @@ -132,7 +131,7 @@ p.changeDynamics(bricks[i], -1, lateralFriction=0.1, restitution=0.1) i += 1 -brick_actor = actor.box( +brick_actor = fury.actor.box( centers=brick_centers, directions=brick_directions, scales=brick_sizes, @@ -142,14 +141,14 @@ ############################################################################### # Now, we define a scene and add actors to it. -scene = window.Scene() -scene.add(actor.axes()) +scene = fury.window.Scene() +scene.add(fury.actor.axes()) scene.add(ball_actor) scene.add(base_actor) scene.add(brick_actor) # Create show manager. -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) @@ -172,7 +171,7 @@ ball_actor.SetPosition(*ball_pos) # Calculate the vertices of the bricks. -vertices = utils.vertices_from_actor(brick_actor) +vertices = fury.utils.vertices_from_actor(brick_actor) num_vertices = vertices.shape[0] num_objects = brick_centers.shape[0] sec = int(num_vertices / num_objects) @@ -230,7 +229,7 @@ def sync_actor(actor, multibody): # Here, we define a textblock to display the Avg. FPS and simulation steps. fpss = np.array([]) -tb = ui.TextBlock2D( +tb = fury.ui.TextBlock2D( text="Avg. FPS: \nSim Steps: ", position=(0, 680), font_size=30, color=(1, 0.5, 0) ) scene.add(tb) @@ -280,7 +279,7 @@ def timer_callback(_obj, _event): # Updating the position and orientation of each individual brick. for idx, brick in enumerate(bricks): sync_brick(idx, brick) - utils.update_actor(brick_actor) + fury.utils.update_actor(brick_actor) # Simulate a step. p.stepSimulation() @@ -300,4 +299,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, out_path="viz_brick_wall.png", size=(900, 768)) +fury.window.record(scene, out_path="viz_brick_wall.png", size=(900, 768)) diff --git a/docs/examples/viz_brownian_motion.py b/docs/examples/viz_brownian_motion.py index 65880f900..4fc2c728e 100644 --- a/docs/examples/viz_brownian_motion.py +++ b/docs/examples/viz_brownian_motion.py @@ -10,9 +10,9 @@ """ import numpy as np +import fury from scipy.stats import norm -from fury import actor, ui, utils, window ############################################################################### # Let's define some variable and their description: @@ -58,12 +58,12 @@ def particle( ): _origin = np.asarray(_origin, dtype=float) position = np.tile(origin, (_num_total_steps, 1)) - path_actor = actor.line([position], colors, linewidth=_path_thickness) + path_actor = fury.actor.line([position], colors, linewidth=_path_thickness) path_actor.position = position path_actor.delta = _delta path_actor.num_total_steps = _num_total_steps path_actor.time_step = _total_time / _num_total_steps - path_actor.vertices = utils.vertices_from_actor(path_actor) + path_actor.vertices = fury.utils.vertices_from_actor(path_actor) path_actor.no_vertices_per_point = len(path_actor.vertices) / _num_total_steps path_actor.initial_vertices = path_actor.vertices.copy() - np.repeat( position, path_actor.no_vertices_per_point, axis=0 @@ -85,19 +85,19 @@ def update_path(act, counter_step): act.vertices[:] = act.initial_vertices + np.repeat( act.position, act.no_vertices_per_point, axis=0 ) - utils.update_actor(act) + fury.utils.update_actor(act) ############################################################################### # Creating a scene object and configuring the camera's position -scene = window.Scene() +scene = fury.window.Scene() scene.background((1.0, 1.0, 1.0)) scene.zoom(1.7) scene.set_camera( position=(0, 0, 40), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) ) -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(600, 600), reset_camera=True, order_transparent=True ) @@ -108,10 +108,10 @@ def update_path(act, counter_step): l_particle = [ particle( colors=np.random.rand(1, 3), - origin=origin, - num_total_steps=num_total_steps, - total_time=total_time, - path_thickness=path_thickness, + _origin=origin, + _num_total_steps=num_total_steps, + _total_time=total_time, + _path_thickness=path_thickness, ) for _ in range(num_particles) ] @@ -121,7 +121,7 @@ def update_path(act, counter_step): ############################################################################### # Creating a container (cube actor) inside which the particle(s) move around -container_actor = actor.box( +container_actor = fury.actor.box( centers=np.array([[0, 0, 0]]), colors=(0.5, 0.9, 0.7, 0.4), scales=6 ) scene.add(container_actor) @@ -129,7 +129,7 @@ def update_path(act, counter_step): ############################################################################### # Initializing text box to display the name of the animation -tb = ui.TextBlock2D(bold=True, position=(235, 40), color=(0, 0, 0)) +tb = fury.ui.TextBlock2D(bold=True, position=(235, 40), color=(0, 0, 0)) tb.message = "Brownian Motion" scene.add(tb) @@ -155,4 +155,4 @@ def timer_callback(_obj, _event): showm.add_timer_callback(True, 30, timer_callback) showm.start() -window.record(showm.scene, size=(600, 600), out_path="viz_brownian_motion.png") +fury.window.record(showm.scene, size=(600, 600), out_path="viz_brownian_motion.png") diff --git a/docs/examples/viz_bundles.py b/docs/examples/viz_bundles.py index 092f292de..a7284f238 100644 --- a/docs/examples/viz_bundles.py +++ b/docs/examples/viz_bundles.py @@ -9,9 +9,9 @@ from dipy.data import fetch_bundles_2_subjects, read_bundles_2_subjects from dipy.tracking.streamline import length, transform_streamlines +import fury import numpy as np -from fury import actor, window interactive = False # set to True to show the interactive display window @@ -48,9 +48,9 @@ # # This is the default option when you are using ``line`` or ``streamtube``. -scene = window.Scene() +scene = fury.window.Scene() -stream_actor = actor.line(bundle_native) +stream_actor = fury.actor.line(bundle_native) scene.set_camera( position=(-176.42, 118.52, 128.20), @@ -61,13 +61,13 @@ scene.add(stream_actor) if interactive: - window.show(scene, size=(600, 600), reset_camera=False) + fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="bundle1.png", size=(600, 600)) +fury.window.record(scene, out_path="bundle1.png", size=(600, 600)) ############################################################################### # You may wonder how we knew how to set the camera. This is very easy. You just -# need to run ``window.show`` once see how you want to see the object and then +# need to run ``fury.window.show`` once see how you want to see the object and then # close the window and call the ``camera_info`` method which prints the # position, focal point and view up vectors of the camera. @@ -80,20 +80,20 @@ # Here we will need to input the ``fa`` map in ``streamtube`` or ``line``. scene.clear() -stream_actor2 = actor.line(bundle_native, fa, linewidth=0.1) +stream_actor2 = fury.actor.line(bundle_native, fa, linewidth=0.1) ############################################################################### # We can also show the scalar bar. -bar = actor.scalar_bar() +bar = fury.actor.scalar_bar() scene.add(stream_actor2) scene.add(bar) if interactive: - window.show(scene, size=(600, 600), reset_camera=False) + fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="bundle2.png", size=(600, 600)) +fury.window.record(scene, out_path="bundle2.png", size=(600, 600)) ############################################################################## # Show every point with a value from a volume with your colormap @@ -106,18 +106,20 @@ hue = (0.0, 0.0) # red only saturation = (0.0, 1.0) # white to red -lut_cmap = actor.colormap_lookup_table(hue_range=hue, saturation_range=saturation) +lut_cmap = fury.actor.colormap_lookup_table(hue_range=hue, saturation_range=saturation) -stream_actor3 = actor.line(bundle_native, fa, linewidth=0.1, lookup_colormap=lut_cmap) -bar2 = actor.scalar_bar(lut_cmap) +stream_actor3 = fury.actor.line( + bundle_native, fa, linewidth=0.1, lookup_colormap=lut_cmap +) +bar2 = fury.actor.scalar_bar(lut_cmap) scene.add(stream_actor3) scene.add(bar2) if interactive: - window.show(scene, size=(600, 600), reset_camera=False) + fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="bundle3.png", size=(600, 600)) +fury.window.record(scene, out_path="bundle3.png", size=(600, 600)) ############################################################################### # Show every bundle with a specific color @@ -127,14 +129,14 @@ # orange. scene.clear() -stream_actor4 = actor.line(bundle_native, (1.0, 0.5, 0), linewidth=0.1) +stream_actor4 = fury.actor.line(bundle_native, (1.0, 0.5, 0), linewidth=0.1) scene.add(stream_actor4) if interactive: - window.show(scene, size=(600, 600), reset_camera=False) + fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="bundle4.png", size=(600, 600)) +fury.window.record(scene, out_path="bundle4.png", size=(600, 600)) ############################################################################### # Show every streamline of a bundle with a different color @@ -150,25 +152,25 @@ hue = (0.5, 0.5) # blue only saturation = (0.0, 1.0) # black to white -lut_cmap = actor.colormap_lookup_table( +lut_cmap = fury.actor.colormap_lookup_table( scale_range=(lengths.min(), lengths.max()), hue_range=hue, saturation_range=saturation, ) -stream_actor5 = actor.line( +stream_actor5 = fury.actor.line( bundle_native, lengths, linewidth=0.1, lookup_colormap=lut_cmap ) scene.add(stream_actor5) -bar3 = actor.scalar_bar(lut_cmap) +bar3 = fury.actor.scalar_bar(lut_cmap) scene.add(bar3) if interactive: - window.show(scene, size=(600, 600), reset_camera=False) + fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="bundle5.png", size=(600, 600)) +fury.window.record(scene, out_path="bundle5.png", size=(600, 600)) ############################################################################### # Show every point of every streamline with a different color @@ -182,14 +184,14 @@ colors = [np.random.rand(*streamline.shape) for streamline in bundle_native] -stream_actor6 = actor.line(bundle_native, np.vstack(colors), linewidth=0.2) +stream_actor6 = fury.actor.line(bundle_native, np.vstack(colors), linewidth=0.2) scene.add(stream_actor6) if interactive: - window.show(scene, size=(600, 600), reset_camera=False) + fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="bundle6.png", size=(600, 600)) +fury.window.record(scene, out_path="bundle6.png", size=(600, 600)) ############################################################################### # Add depth cues to streamline rendering @@ -203,14 +205,14 @@ scene.clear() -stream_actor7 = actor.line(bundle_native, linewidth=0.5, depth_cue=True) +stream_actor7 = fury.actor.line(bundle_native, linewidth=0.5, depth_cue=True) scene.add(stream_actor7) if interactive: - window.show(scene, size=(600, 600), reset_camera=False) + fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="bundle7.png", size=(600, 600)) +fury.window.record(scene, out_path="bundle7.png", size=(600, 600)) ############################################################################### # Render streamlines as fake tubes @@ -221,14 +223,14 @@ scene.clear() -stream_actor8 = actor.line(bundle_native, linewidth=3, fake_tube=True) +stream_actor8 = fury.actor.line(bundle_native, linewidth=3, fake_tube=True) scene.add(stream_actor8) if interactive: - window.show(scene, size=(600, 600), reset_camera=False) + fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="bundle8.png", size=(600, 600)) +fury.window.record(scene, out_path="bundle8.png", size=(600, 600)) ############################################################################### # Combine depth cues with fake tubes @@ -240,14 +242,16 @@ scene.clear() -stream_actor9 = actor.line(bundle_native, linewidth=3, depth_cue=True, fake_tube=True) +stream_actor9 = fury.actor.line( + bundle_native, linewidth=3, depth_cue=True, fake_tube=True +) scene.add(stream_actor9) if interactive: - window.show(scene, size=(600, 600), reset_camera=False) + fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="bundle9.png", size=(600, 600)) +fury.window.record(scene, out_path="bundle9.png", size=(600, 600)) ############################################################################### # Render streamlines as tubes @@ -260,14 +264,14 @@ scene.clear() -stream_actor10 = actor.streamtube(bundle_native, linewidth=0.5) +stream_actor10 = fury.actor.streamtube(bundle_native, linewidth=0.5) scene.add(stream_actor10) if interactive: - window.show(scene, size=(600, 600), reset_camera=False) + fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="bundle10.png", size=(600, 600)) +fury.window.record(scene, out_path="bundle10.png", size=(600, 600)) ############################################################################### # In summary, we showed that there are many useful ways for visualizing maps diff --git a/docs/examples/viz_buttons.py b/docs/examples/viz_buttons.py index 8d89b74ce..f0c6eb90d 100644 --- a/docs/examples/viz_buttons.py +++ b/docs/examples/viz_buttons.py @@ -10,7 +10,7 @@ First, some imports. """ -from fury import ui, window +import fury from fury.data import fetch_viz_icons, read_viz_icons ############################################################################## @@ -22,15 +22,15 @@ # Let's create some buttons and text and put them in a panel. # First we'll make the panel. -panel = ui.Panel2D(size=(300, 150), color=(1, 1, 1), align="right") +panel = fury.ui.Panel2D(size=(300, 150), color=(1, 1, 1), align="right") panel.center = (500, 400) ############################################################################### # Then we'll make two text labels and place them on the panel. # Note that we specify the position with integer numbers of pixels. -text = ui.TextBlock2D(text="Click me") -text2 = ui.TextBlock2D(text="Me too") +text = fury.ui.TextBlock2D(text="Click me") +text2 = fury.ui.TextBlock2D(text="Me too") panel.add_element(text, (50, 100)) panel.add_element(text2, (180, 100)) @@ -41,7 +41,7 @@ # percentages of the panel size. -button_example = ui.Button2D( +button_example = fury.ui.Button2D( icon_fnames=[("square", read_viz_icons(fname="stop2.png"))] ) @@ -51,7 +51,7 @@ icon_files.append(("up", read_viz_icons(fname="circle-up.png"))) icon_files.append(("right", read_viz_icons(fname="circle-right.png"))) -second_button_example = ui.Button2D(icon_fnames=icon_files) +second_button_example = fury.ui.Button2D(icon_fnames=icon_files) panel.add_element(button_example, (0.25, 0.33)) panel.add_element(second_button_example, (0.66, 0.33)) @@ -79,7 +79,7 @@ def change_icon_callback(i_ren, _obj, _button): # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title="FURY Button Example") +show_manager = fury.window.ShowManager(size=current_size, title="FURY Button Example") show_manager.scene.add(panel) @@ -88,4 +88,4 @@ def change_icon_callback(i_ren, _obj, _button): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path="viz_button.png") +fury.window.record(show_manager.scene, size=current_size, out_path="viz_button.png") diff --git a/docs/examples/viz_camera.py b/docs/examples/viz_camera.py index ba67dfb2f..13efe2aeb 100644 --- a/docs/examples/viz_camera.py +++ b/docs/examples/viz_camera.py @@ -6,9 +6,9 @@ Camera and opacity keyframe animation explained in this tutorial. """ +import fury import numpy as np -from fury import actor, window from fury.animation import Animation, CameraAnimation, Timeline from fury.animation.interpolator import cubic_spline_interpolator @@ -19,9 +19,9 @@ # The plan here is to animate (scale and translate) 50 spheres randomly, and # show `FURY` text that appears at the end! -scene = window.Scene() +scene = fury.window.Scene() -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) @@ -48,10 +48,10 @@ ############################################################################### # Creating two actors for visualization, and to detect camera's animations. -arrow = actor.arrow( +arrow = fury.actor.arrow( np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), np.array([[1, 1, 0]]), scales=5 ) -plan = actor.box( +plan = fury.actor.box( np.array([[0, 0, 0]]), colors=np.array([[1, 1, 1]]), scales=np.array([[20, 0.2, 20]]), @@ -60,7 +60,7 @@ ############################################################################### # Creating "FURY" text # ==================== -fury_text = actor.vector_text("FURY", pos=(-4.3, 15, 0), scale=(2, 2, 2)) +fury_text = fury.actor.vector_text("FURY", pos=(-4.3, 15, 0), scale=(2, 2, 2)) ############################################################################### # Creating an ``Animation`` to animate the opacity of ``fury_text`` @@ -86,7 +86,7 @@ # create a sphere actor that's centered at the origin and has random color # and radius. actors = [ - actor.sphere( + fury.actor.sphere( np.array([[0, 0, 0]]), np.random.random([1, 3]), np.random.random([1, 3]) ) ] @@ -176,4 +176,4 @@ if interactive: showm.start() -window.record(scene, out_path="viz_keyframe_animation_camera.png", size=(900, 768)) +fury.window.record(scene, out_path="viz_keyframe_animation_camera.png", size=(900, 768)) diff --git a/docs/examples/viz_card.py b/docs/examples/viz_card.py index 579a65fb9..1984938f0 100644 --- a/docs/examples/viz_card.py +++ b/docs/examples/viz_card.py @@ -9,7 +9,7 @@ First, some imports. """ -from fury import ui, window +import fury from fury.data import fetch_viz_icons ############################################################################## @@ -31,7 +31,7 @@ "A software library for scientific visualization in Python." ) -card = ui.elements.Card2D( +card = fury.ui.elements.Card2D( image_path=img_url, title_text=title, body_text=body, @@ -48,7 +48,7 @@ # manager. current_size = (1000, 1000) -show_manager = window.ShowManager(size=current_size, title="FURY Card Example") +show_manager = fury.window.ShowManager(size=current_size, title="FURY Card Example") show_manager.scene.add(card) # To interact with the UI, set interactive = True @@ -57,4 +57,4 @@ if interactive: show_manager.start() -window.record(show_manager.scene, out_path="card_ui.png", size=(1000, 1000)) +fury.window.record(show_manager.scene, out_path="card_ui.png", size=(1000, 1000)) diff --git a/docs/examples/viz_card_sprite_sheet.py b/docs/examples/viz_card_sprite_sheet.py index eb7465a5e..0a783b439 100644 --- a/docs/examples/viz_card_sprite_sheet.py +++ b/docs/examples/viz_card_sprite_sheet.py @@ -10,10 +10,10 @@ First, some imports. """ +import fury import os from tempfile import TemporaryDirectory as InTemporaryDirectory -from fury import ui, window from fury.data import fetch_viz_icons from fury.io import load_image, load_sprite_sheet, save_image @@ -48,7 +48,7 @@ "A software library for scientific visualization in Python." ) -card = ui.elements.Card2D( +card = fury.ui.elements.Card2D( image_path=img_url, title_text=title, body_text=body, @@ -92,7 +92,7 @@ def sprite_to_vtk(): # manager. current_size = (1000, 1000) -show_manager = window.ShowManager(size=current_size, title="FURY Card Example") +show_manager = fury.window.ShowManager(size=current_size, title="FURY Card Example") show_manager.scene.add(card) show_manager.initialize() @@ -110,4 +110,4 @@ def sprite_to_vtk(): if interactive: show_manager.start() -window.record(show_manager.scene, out_path="card_ui.png", size=(1000, 1000)) +fury.window.record(show_manager.scene, out_path="card_ui.png", size=(1000, 1000)) diff --git a/docs/examples/viz_domino.py b/docs/examples/viz_domino.py index 9bb54afa4..104ec4db9 100644 --- a/docs/examples/viz_domino.py +++ b/docs/examples/viz_domino.py @@ -15,7 +15,7 @@ import numpy as np import pybullet as p -from fury import actor, ui, utils, window +import fury # Next, we initialize a pybullet client to render the physics. # We use `DIRECT` mode to initialize pybullet without a GUI. @@ -35,7 +35,7 @@ base_orientation = np.array([0, 0, 0, 1]) # Render a BASE plane to support the Dominoes. -base_actor = actor.box( +base_actor = fury.actor.box( centers=np.array([[0, 0, 0]]), directions=[0, 0, 0], scales=base_size, @@ -94,7 +94,7 @@ p.changeDynamics(dominos[i], -1, lateralFriction=0.2, restitution=0.1) -domino_actor = actor.box( +domino_actor = fury.actor.box( centers=domino_centers, directions=domino_directions, scales=domino_sizes, @@ -103,13 +103,13 @@ ############################################################################### # Now, we define a scene and add actors to it. -scene = window.Scene() -scene.add(actor.axes()) +scene = fury.window.Scene() +scene.add(fury.actor.axes()) scene.add(base_actor) scene.add(domino_actor) # Create show manager. -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) @@ -128,7 +128,7 @@ # Calculate the vertices of the dominos. -vertices = utils.vertices_from_actor(domino_actor) +vertices = fury.utils.vertices_from_actor(domino_actor) num_vertices = vertices.shape[0] num_objects = domino_centers.shape[0] sec = int(num_vertices / num_objects) @@ -173,7 +173,7 @@ def sync_domino(object_index, multibody): # Here, we define a textblock to display the Avg. FPS and simulation steps. fpss = np.array([]) -tb = ui.TextBlock2D( +tb = fury.ui.TextBlock2D( text="Avg. FPS: \nSim Steps: ", position=(0, 680), font_size=30, color=(1, 0.5, 0) ) scene.add(tb) @@ -224,7 +224,7 @@ def timer_callback(_obj, _event): # Updating the position and orientation of individual dominos. for idx, domino in enumerate(dominos): sync_domino(idx, domino) - utils.update_actor(domino_actor) + fury.utils.update_actor(domino_actor) # Simulate a step. p.stepSimulation() @@ -244,4 +244,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, out_path="viz_domino.png", size=(900, 768)) +fury.window.record(scene, out_path="viz_domino.png", size=(900, 768)) diff --git a/docs/examples/viz_drawpanel.py b/docs/examples/viz_drawpanel.py index 6b5295ebe..3a0fe1d76 100644 --- a/docs/examples/viz_drawpanel.py +++ b/docs/examples/viz_drawpanel.py @@ -9,18 +9,17 @@ First, some imports. """ -from fury import ui, window -from fury.data import fetch_viz_new_icons +import fury ############################################################################## # First we need to fetch some icons that are needed for DrawPanel. -fetch_viz_new_icons() +fury.data.fetch_viz_new_icons() ######################################################################### # We then create a DrawPanel Object. -drawing_canvas = ui.DrawPanel(size=(560, 560), position=(40, 10)) +drawing_canvas = fury.ui.DrawPanel(size=(560, 560), position=(40, 10)) ############################################################################### # Show Manager @@ -29,7 +28,7 @@ # Now we add DrawPanel to the scene. current_size = (650, 650) -showm = window.ShowManager(size=current_size, title="DrawPanel UI Example") +showm = fury.window.ShowManager(size=current_size, title="DrawPanel UI Example") showm.scene.add(drawing_canvas) @@ -43,4 +42,4 @@ drawing_canvas.draw_shape(shape_type="circle", current_position=(275, 275)) drawing_canvas.shape_list[-1].resize((50, 50)) - window.record(showm.scene, size=current_size, out_path="viz_drawpanel.png") + fury.window.record(showm.scene, size=current_size, out_path="viz_drawpanel.png") diff --git a/docs/examples/viz_dt_ellipsoids.py b/docs/examples/viz_dt_ellipsoids.py index f9e7ec5ab..4b2d37e02 100644 --- a/docs/examples/viz_dt_ellipsoids.py +++ b/docs/examples/viz_dt_ellipsoids.py @@ -16,28 +16,25 @@ from dipy.io.image import load_nifti import numpy as np -from fury import actor, ui, window -from fury.actor import _color_fa, _fa -from fury.data import fetch_viz_dmri, read_viz_dmri -from fury.primitive import prim_sphere +import fury ############################################################################### # Now, we fetch and load the data needed to display the Diffusion Tensor # Images. -fetch_viz_dmri() +fury.data.fetch_viz_dmri() ############################################################################### # The tensor ellipsoids are expressed as eigenvalues and eigenvectors which are # the decomposition of the diffusion tensor that describes the water diffusion # within a voxel. -slice_evecs, _ = load_nifti(read_viz_dmri("slice_evecs.nii.gz")) -slice_evals, _ = load_nifti(read_viz_dmri("slice_evals.nii.gz")) -roi_evecs, _ = load_nifti(read_viz_dmri("roi_evecs.nii.gz")) -roi_evals, _ = load_nifti(read_viz_dmri("roi_evals.nii.gz")) -whole_brain_evecs, _ = load_nifti(read_viz_dmri("whole_brain_evecs.nii.gz")) -whole_brain_evals, _ = load_nifti(read_viz_dmri("whole_brain_evals.nii.gz")) +slice_evecs, _ = load_nifti(fury.data.read_viz_dmri("slice_evecs.nii.gz")) +slice_evals, _ = load_nifti(fury.data.read_viz_dmri("slice_evals.nii.gz")) +roi_evecs, _ = load_nifti(fury.data.read_viz_dmri("roi_evecs.nii.gz")) +roi_evals, _ = load_nifti(fury.data.read_viz_dmri("roi_evals.nii.gz")) +whole_brain_evecs, _ = load_nifti(fury.data.read_viz_dmri("whole_brain_evecs.nii.gz")) +whole_brain_evals, _ = load_nifti(fury.data.read_viz_dmri("whole_brain_evals.nii.gz")) ############################################################################### # Using tensor_slicer actor @@ -49,7 +46,7 @@ # vertices that made up the sphere, which have a standard number of 100, 200, # and 724 vertices. -vertices, faces = prim_sphere("repulsion100", True) +vertices, faces = fury.prim_sphere("repulsion100", True) ############################################################################### @@ -70,7 +67,7 @@ def __init__(self, vertices, faces): # brain slice. We also define the scale so that the tensors are not so large # and overlap each other. -tensor_slice = actor.tensor_slicer( +tensor_slice = fury.actor.tensor_slicer( evals=slice_evals, evecs=slice_evecs, sphere=sphere100, scale=0.3 ) @@ -78,12 +75,12 @@ def __init__(self, vertices, faces): # Next, we set up a new scene to add and visualize the tensor ellipsoids # created. -scene = window.Scene() +scene = fury.window.Scene() scene.background([255, 255, 255]) scene.add(tensor_slice) # Create show manager -showm = window.ShowManager(scene, size=(600, 600)) +showm = fury.window.ShowManager(scene, size=(600, 600)) # Enables/disables interactive visualization interactive = False @@ -91,7 +88,7 @@ def __init__(self, vertices, faces): if interactive: showm.start() -window.record(showm.scene, size=(600, 600), out_path="tensor_slice_100.png") +fury.window.record(showm.scene, size=(600, 600), out_path="tensor_slice_100.png") ############################################################################### # If we zoom in at the scene to see with detail the tensor ellipsoids displayed @@ -99,14 +96,14 @@ def __init__(self, vertices, faces): scene.roll(10) scene.pitch(90) -showm = window.ShowManager(scene, size=(600, 600), order_transparent=True) +showm = fury.window.ShowManager(scene, size=(600, 600), order_transparent=True) showm.scene.zoom(50) if interactive: showm.render() showm.start() -window.record( +fury.window.record( showm.scene, out_path="tensor_slice_100_zoom.png", size=(600, 300), @@ -151,7 +148,7 @@ def get_params(evecs, evals): # coloring in tensor_slicer that is uses _color_fa that is a way to map # colors to each tensor based on the fractional anisotropy (FA) of each # diffusion tensor. - colors = _color_fa(_fa(fevals), fevecs) + colors = fury.actor._color_fa(fury.actor._fa(fevals), fevecs) return centers, fevecs, fevals, colors @@ -166,7 +163,7 @@ def get_params(evecs, evals): # Now, we can use the ``ellipsoid`` actor to create the tensor ellipsoids as # follows. -tensors = actor.ellipsoid( +tensors = fury.actor.ellipsoid( centers=centers, colors=colors, axes=evecs, lengths=evals, scales=0.6 ) showm.scene.add(tensors) @@ -174,7 +171,7 @@ def get_params(evecs, evals): if interactive: showm.start() -window.record(scene, size=(600, 600), out_path="tensor_slice_sdf.png") +fury.window.record(scene, size=(600, 600), out_path="tensor_slice_sdf.png") ############################################################################### # Thus, one can see that the same result is obtained, however there is a @@ -185,14 +182,14 @@ def get_params(evecs, evals): scene.roll(10) scene.pitch(90) -showm = window.ShowManager(scene, size=(600, 600), order_transparent=True) +showm = fury.window.ShowManager(scene, size=(600, 600), order_transparent=True) showm.scene.zoom(50) if interactive: showm.render() showm.start() -window.record( +fury.window.record( showm.scene, out_path="tensor_slice_sdf_zoom.png", size=(600, 300), @@ -224,17 +221,23 @@ def get_params(evecs, evals): evals[..., :] = mevals evecs[..., :, :] = mevecs -vertices, faces = prim_sphere("repulsion200", True) +vertices, faces = fury.prim_sphere("repulsion200", True) sphere200 = Sphere(vertices, faces) -vertices, faces = prim_sphere("repulsion724", True) +vertices, faces = fury.prim_sphere("repulsion724", True) sphere724 = Sphere(vertices, faces) -tensor_100 = actor.tensor_slicer(evals=evals, evecs=evecs, sphere=sphere100, scale=1.0) -tensor_200 = actor.tensor_slicer(evals=evals, evecs=evecs, sphere=sphere200, scale=1.0) -tensor_724 = actor.tensor_slicer(evals=evals, evecs=evecs, sphere=sphere724, scale=1.0) +tensor_100 = fury.actor.tensor_slicer( + evals=evals, evecs=evecs, sphere=sphere100, scale=1.0 +) +tensor_200 = fury.actor.tensor_slicer( + evals=evals, evecs=evecs, sphere=sphere200, scale=1.0 +) +tensor_724 = fury.actor.tensor_slicer( + evals=evals, evecs=evecs, sphere=sphere724, scale=1.0 +) centers, evecs, evals, colors = get_params(evecs=evecs, evals=evals) -tensor_sdf = actor.ellipsoid( +tensor_sdf = fury.actor.ellipsoid( centers=centers, axes=evecs, lengths=evals, colors=colors, scales=2.0 ) @@ -244,13 +247,13 @@ def get_params(evecs, evals): objects = [tensor_100, tensor_200, tensor_724, tensor_sdf] text = [ - actor.vector_text("Tensor 100"), - actor.vector_text("Tensor 200"), - actor.vector_text("Tensor 724"), - actor.vector_text("Tensor SDF"), + fury.actor.vector_text("Tensor 100"), + fury.actor.vector_text("Tensor 200"), + fury.actor.vector_text("Tensor 724"), + fury.actor.vector_text("Tensor SDF"), ] -grid_ui = ui.GridUI( +grid_ui = fury.ui.GridUI( actors=objects, captions=text, cell_padding=0.1, @@ -258,17 +261,17 @@ def get_params(evecs, evals): dim=(1, 4), ) -scene = window.Scene() +scene = fury.window.Scene() scene.background([255, 255, 255]) scene.zoom(3.5) scene.set_camera(position=(3.2, -20, 12), focal_point=(3.2, 0.0, 0.0)) -showm = window.ShowManager(scene, size=(560, 200)) +showm = fury.window.ShowManager(scene, size=(560, 200)) showm.scene.add(grid_ui) if interactive: showm.start() -window.record( +fury.window.record( showm.scene, size=(560, 200), out_path="tensor_comparison.png", @@ -285,7 +288,7 @@ def get_params(evecs, evals): # ``display_extent()``. Here we can see an example of a region of interest # (ROI) using a sphere of 100 vertices. -tensor_roi = actor.tensor_slicer( +tensor_roi = fury.actor.tensor_slicer( evals=roi_evals, evecs=roi_evecs, sphere=sphere100, scale=0.3 ) @@ -300,7 +303,7 @@ def get_params(evecs, evals): if interactive: showm.start() -window.record(showm.scene, size=(600, 600), out_path="tensor_roi_100.png") +fury.window.record(showm.scene, size=(600, 600), out_path="tensor_roi_100.png") showm.scene.clear() @@ -312,7 +315,7 @@ def get_params(evecs, evals): centers, evecs, evals, colors = get_params(roi_evecs, roi_evals) -tensors = actor.ellipsoid( +tensors = fury.actor.ellipsoid( centers=centers, colors=colors, axes=evecs, lengths=evals, scales=0.6 ) showm.scene.add(tensors) @@ -320,7 +323,7 @@ def get_params(evecs, evals): if interactive: showm.start() -window.record(showm.scene, size=(600, 600), out_path="tensor_roi_sdf.png") +fury.window.record(showm.scene, size=(600, 600), out_path="tensor_roi_sdf.png") showm.scene.clear() @@ -338,19 +341,19 @@ def get_params(evecs, evals): evecs = np.array(list(itertools.compress(evecs, fil))) evals = np.array(list(itertools.compress(evals, fil))) -tensors = actor.ellipsoid( +tensors = fury.actor.ellipsoid( centers=centers, colors=colors, axes=evecs, lengths=evals, scales=0.6 ) -scene = window.Scene() +scene = fury.window.Scene() scene.add(tensors) scene.pitch(180) -showm = window.ShowManager(scene, size=(600, 600)) +showm = fury.window.ShowManager(scene, size=(600, 600)) if interactive: showm.start() -window.record( +fury.window.record( showm.scene, size=(600, 600), reset_camera=False, diff --git a/docs/examples/viz_earth_animation.py b/docs/examples/viz_earth_animation.py index ff430a31b..38675c595 100644 --- a/docs/examples/viz_earth_animation.py +++ b/docs/examples/viz_earth_animation.py @@ -9,18 +9,12 @@ import numpy as np -from fury import actor, io, utils, window -from fury.data import ( - fetch_viz_models, - fetch_viz_textures, - read_viz_models, - read_viz_textures, -) +import fury ############################################################################## # Create a scene to start. -scene = window.Scene() +scene = fury.window.Scene() ############################################################################## # Next, load in a texture for each of the actors. For this tutorial, we will @@ -29,23 +23,23 @@ # and ``read_viz_textures``, then use ``io.load_image`` to load in the # image. -fetch_viz_textures() -earth_filename = read_viz_textures("1_earth_8k.jpg") -earth_image = io.load_image(earth_filename) +fury.data.fetch_viz_textures() +earth_filename = fury.data.read_viz_textures("1_earth_8k.jpg") +earth_image = fury.io.load_image(earth_filename) ############################################################################## # Using ``actor.texture_on_sphere()``, create an earth_actor with your newly # loaded texture. -earth_actor = actor.texture_on_sphere(earth_image) +earth_actor = fury.actor.texture_on_sphere(earth_image) ############################################################################## # Then, do the same for the moon. -moon_filename = read_viz_textures("moon-8k.jpg") -moon_image = io.load_image(moon_filename) +moon_filename = fury.data.read_viz_textures("moon-8k.jpg") +moon_image = fury.io.load_image(moon_filename) -moon_actor = actor.texture_on_sphere(moon_image) +moon_actor = fury.actor.texture_on_sphere(moon_image) ############################################################################## # Add both actors to the already existing scene. @@ -61,13 +55,13 @@ moon_actor.SetPosition(1, 0.1, 0.5) moon_actor.SetScale(0.25, 0.25, 0.25) -utils.rotate(earth_actor, (-90, 1, 0, 0)) +fury.utils.rotate(earth_actor, (-90, 1, 0, 0)) ############################################################################## # The ShowManager class is the interface between the scene, the window and the # interactor. -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) @@ -94,23 +88,23 @@ center = np.array([[-0.39, 0.3175, 0.025]]) radius = 0.002 -sphere_actor = actor.sphere(center, window.colors.blue_medium, radius) +sphere_actor = fury.actor.sphere(center, fury.window.colors.blue_medium, radius) ############################################################################## # Also creating a text actor to add below the sphere. -text_actor = actor.text_3d( - "Bloomington, Indiana", (-0.42, 0.31, 0.03), window.colors.white, 0.004 +text_actor = fury.actor.text_3d( + "Bloomington, Indiana", (-0.42, 0.31, 0.03), fury.window.colors.white, 0.004 ) -utils.rotate(text_actor, (-90, 0, 1, 0)) +fury.utils.rotate(text_actor, (-90, 0, 1, 0)) ############################################################################## # Let's also import a model of a satellite to visualize circling the moon. -fetch_viz_models() -satellite_filename = read_viz_models("satellite_obj.obj") -satellite = io.load_polydata(satellite_filename) -satellite_actor = utils.get_actor_from_polydata(satellite) +fury.data.fetch_viz_models() +satellite_filename = fury.data.read_viz_models("satellite_obj.obj") +satellite = fury.io.load_polydata(satellite_filename) +satellite_actor = fury.utils.get_actor_from_polydata(satellite) satellite_actor.SetPosition(-0.75, 0.1, 0.4) satellite_actor.SetScale(0.005, 0.005, 0.005) @@ -127,7 +121,7 @@ def timer_callback(_obj, _event): cnt = next(counter) showm.render() if cnt < 450: - utils.rotate(earth_actor, (1, 0, 1, 0)) + fury.utils.rotate(earth_actor, (1, 0, 1, 0)) if cnt % 5 == 0 and cnt < 450: showm.scene.azimuth(-1) if cnt == 300: @@ -152,15 +146,15 @@ def timer_callback(_obj, _event): ) scene.zoom(0.03) scene.add(satellite_actor) - utils.rotate(satellite_actor, (180, 0, 1, 0)) + fury.utils.rotate(satellite_actor, (180, 0, 1, 0)) scene.rm(earth_actor) if cnt > 575 and cnt < 750: showm.scene.azimuth(-2) - utils.rotate(moon_actor, (-2, 0, 1, 0)) + fury.utils.rotate(moon_actor, (-2, 0, 1, 0)) satellite_actor.SetPosition(-0.8, 0.1 - cnt / 10000, 0.4) if cnt >= 750 and cnt < 1100: showm.scene.azimuth(-2) - utils.rotate(moon_actor, (-2, 0, 1, 0)) + fury.utils.rotate(moon_actor, (-2, 0, 1, 0)) satellite_actor.SetPosition(-0.8, -0.07 + cnt / 10000, 0.4) if cnt == 1100: showm.exit() @@ -172,4 +166,4 @@ def timer_callback(_obj, _event): showm.add_timer_callback(True, 35, timer_callback) showm.start() -window.record(showm.scene, size=(900, 768), out_path="viz_earth_animation.png") +fury.window.record(showm.scene, size=(900, 768), out_path="viz_earth_animation.png") diff --git a/docs/examples/viz_earth_coordinates.py b/docs/examples/viz_earth_coordinates.py index 3c3c10eec..6b5abd564 100644 --- a/docs/examples/viz_earth_coordinates.py +++ b/docs/examples/viz_earth_coordinates.py @@ -12,28 +12,27 @@ import numpy as np -from fury import actor, io, utils, window -from fury.data import fetch_viz_textures, read_viz_textures +import fury ############################################################################### # Create a new scene, and load in the image of the Earth using # ``fetch_viz_textures`` and ``read_viz_textures``. We will use a 16k # resolution texture for maximum detail. -scene = window.Scene() +scene = fury.window.Scene() -fetch_viz_textures() -earth_file = read_viz_textures("1_earth_16k.jpg") -earth_image = io.load_image(earth_file) -earth_actor = actor.texture_on_sphere(earth_image) +fury.data.fetch_viz_textures() +earth_file = fury.data.read_viz_textures("1_earth_16k.jpg") +earth_image = fury.io.load_image(earth_file) +earth_actor = fury.actor.texture_on_sphere(earth_image) scene.add(earth_actor) ############################################################################### # Rotate the Earth to make sure the texture is correctly oriented. Change it's # scale using ``actor.SetScale()``. -utils.rotate(earth_actor, (-90, 1, 0, 0)) -utils.rotate(earth_actor, (180, 0, 1, 0)) +fury.utils.rotate(earth_actor, (-90, 1, 0, 0)) +fury.utils.rotate(earth_actor, (180, 0, 1, 0)) earth_actor.SetScale(2, 2, 2) ############################################################################### @@ -73,40 +72,40 @@ def latlong_coordinates(lat, lon): centers = np.array([[*locationone], [*locationtwo], [*locationthree]]) colors = np.random.rand(3, 3) radii = np.array([0.005, 0.005, 0.005]) -sphere_actor = actor.sphere(centers, colors, radii) +sphere_actor = fury.actor.sphere(centers, colors, radii) scene.add(sphere_actor) ############################################################################### # Create some text actors to add to the scene indicating each location and its # geographical coordinates. -nyc_actor = actor.text_3d( +nyc_actor = fury.actor.text_3d( "New York City, New York\n40.7128° N, 74.0060° W", (locationone[0] - 0.04, locationone[1], locationone[2] + 0.07), - window.colors.white, + fury.window.colors.white, 0.01, ) -paris_actor = actor.text_3d( +paris_actor = fury.actor.text_3d( "Paris, France\n48.8566° N, 2.3522° E", (locationthree[0] - 0.04, locationthree[1], locationthree[2] - 0.07), - window.colors.white, + fury.window.colors.white, 0.01, ) -beijing_actor = actor.text_3d( +beijing_actor = fury.actor.text_3d( "Beijing, China\n39.9042° N, 116.4074° E", (locationtwo[0] - 0.06, locationtwo[1], locationtwo[2] - 0.07), - window.colors.white, + fury.window.colors.white, 0.01, ) -utils.rotate(paris_actor, (85, 0, 1, 0)) -utils.rotate(beijing_actor, (180, 0, 1, 0)) -utils.rotate(nyc_actor, (5, 1, 0, 0)) +fury.utils.rotate(paris_actor, (85, 0, 1, 0)) +fury.utils.rotate(beijing_actor, (180, 0, 1, 0)) +fury.utils.rotate(nyc_actor, (5, 1, 0, 0)) ############################################################################## # Create a ShowManager object, which acts as the interface between the scene, # the window and the interactor. -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) @@ -157,4 +156,4 @@ def timer_callback(_obj, _event): showm.add_timer_callback(True, 25, timer_callback) showm.start() -window.record(showm.scene, size=(900, 768), out_path="viz_earth_coordinates.png") +fury.window.record(showm.scene, size=(900, 768), out_path="viz_earth_coordinates.png") diff --git a/docs/examples/viz_emwave_animation.py b/docs/examples/viz_emwave_animation.py index 163e0d8d2..3968f5c24 100644 --- a/docs/examples/viz_emwave_animation.py +++ b/docs/examples/viz_emwave_animation.py @@ -19,7 +19,7 @@ import numpy as np -from fury import actor, ui, utils, window +import fury ############################################################################### # function that updates and returns the coordinates of the waves which are @@ -34,17 +34,25 @@ def update_coordinates(wavenumber, ang_frq, time, phase_angle): ############################################################################### -# Variable(s) and their description- -# npoints: For high quality rendering, keep the number of npoints high -# but kindly note that higher values for npoints will slow down the -# rendering process (default = 800) -# wavelength : wavelength of the wave (default = 2) -# wavenumber : 2*pi/wavelength -# time: time (default time i.e. time at beginning of the animation = 0) -# incre_time: value by which time is incremented for each call of -# timer_callback (default = 0.1) -# angular_frq: angular frequency (default = 0.1) -# phase_angle: phase angle (default = 0.002) +# Variable(s) and their description +# +# npoints: int +# For high quality rendering, keep the number of npoints high +# but kindly note that higher values for npoints will slow down the +# rendering process (default = 800) +# wavelength: int +# wavelength of the wave (default = 2) +# wavenumber: float +# 2*pi/wavelength +# time: float +# time (default time i.e. time at beginning of the animation = 0) +# incre_time: float +# value by which time is incremented for each call of +# timer_callback (default = 0.1) +# angular_frq: float +# angular frequency (default = 0.1) +# phase_angle: float +# phase angle (default = 0.002) npoints = 800 @@ -58,11 +66,11 @@ def update_coordinates(wavenumber, ang_frq, time, phase_angle): ############################################################################### # Creating a scene object and configuring the camera's position -scene = window.Scene() +scene = fury.window.Scene() scene.set_camera( position=(-6, 5, -10), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) ) -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(800, 600), reset_camera=True, order_transparent=True ) @@ -74,10 +82,10 @@ def update_coordinates(wavenumber, ang_frq, time, phase_angle): centers = np.array([[3, 0, 0]]) directions = np.array([[-1, 0, 0]]) heights = np.array([6.4]) -arrow_actor = actor.arrow( +arrow_actor = fury.actor.arrow( centers, directions, - window.colors.yellow, + fury.window.colors.yellow, heights, resolution=20, tip_length=0.06, @@ -96,12 +104,12 @@ def update_coordinates(wavenumber, ang_frq, time, phase_angle): pts = np.array(list(zip(x, y, z))) pts = [pts] -colors = window.colors.red -wave_actor1 = actor.line(pts, colors, linewidth=3) +colors = fury.window.colors.red +wave_actor1 = fury.actor.line(pts, colors, linewidth=3) scene.add(wave_actor1) -vertices = utils.vertices_from_actor(wave_actor1) -vcolors = utils.colors_from_actor(wave_actor1, "colors") +vertices = fury.utils.vertices_from_actor(wave_actor1) +vcolors = fury.utils.colors_from_actor(wave_actor1, "colors") no_vertices_per_point = len(vertices) / npoints initial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0) @@ -115,12 +123,12 @@ def update_coordinates(wavenumber, ang_frq, time, phase_angle): pts2 = np.array(list(zip(xx, yy, zz))) pts2 = [pts2] -colors2 = window.colors.blue -wave_actor2 = actor.line(pts2, colors2, linewidth=3) +colors2 = fury.window.colors.blue +wave_actor2 = fury.actor.line(pts2, colors2, linewidth=3) scene.add(wave_actor2) -vertices2 = utils.vertices_from_actor(wave_actor2) -vcolors2 = utils.colors_from_actor(wave_actor2, "colors") +vertices2 = fury.utils.vertices_from_actor(wave_actor2) +vcolors2 = fury.utils.colors_from_actor(wave_actor2, "colors") no_vertices_per_point2 = len(vertices2) / npoints initial_vertices2 = vertices2.copy() - np.repeat(pts2, no_vertices_per_point2, axis=0) @@ -128,7 +136,7 @@ def update_coordinates(wavenumber, ang_frq, time, phase_angle): ############################################################################### # Initializing text box to display the title of the animation -tb = ui.TextBlock2D(bold=True, position=(160, 90)) +tb = fury.ui.TextBlock2D(bold=True, position=(160, 90)) tb.message = "Electromagnetic Wave" scene.add(tb) @@ -156,12 +164,12 @@ def timer_callback(_obj, _event): x, y, z = update_coordinates(wavenumber, angular_frq, phase_angle, time) pts = np.array(list(zip(x, y, z))) vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0) - utils.update_actor(wave_actor1) + fury.utils.update_actor(wave_actor1) xx, zz, yy = update_coordinates(wavenumber, angular_frq, phase_angle, time) pts2 = np.array(list(zip(xx, yy, zz))) vertices2[:] = initial_vertices2 + np.repeat(pts2, no_vertices_per_point2, axis=0) - utils.update_actor(wave_actor2) + fury.utils.update_actor(wave_actor2) showm.render() @@ -178,4 +186,4 @@ def timer_callback(_obj, _event): interactive = False if interactive: showm.start() -window.record(showm.scene, size=(800, 600), out_path="viz_emwave.png") +fury.window.record(showm.scene, size=(800, 600), out_path="viz_emwave.png") diff --git a/docs/examples/viz_fiber_odf.py b/docs/examples/viz_fiber_odf.py index ac327aa7f..dcc078762 100644 --- a/docs/examples/viz_fiber_odf.py +++ b/docs/examples/viz_fiber_odf.py @@ -14,17 +14,15 @@ # First, we import some useful modules and methods. import numpy as np -from fury import actor, ui, window -from fury.data import fetch_viz_dmri, fetch_viz_icons, read_viz_dmri -from fury.utils import fix_winding_order +import fury ############################################################################### # Here, we fetch and load the fiber ODF volume to display. The ODF are # expressed as spherical harmonics (SH) coefficients in a 3D grid. -fetch_viz_dmri() -fetch_viz_icons() +fury.data.fetch_viz_dmri() +fury.data.fetch_viz_icons() -fodf_img = nib.load(read_viz_dmri("fodf.nii.gz")) +fodf_img = nib.load(fury.data.read_viz_dmri("fodf.nii.gz")) sh = fodf_img.get_fdata() affine = fodf_img.affine grid_shape = sh.shape[:-1] @@ -49,7 +47,7 @@ global_cm = False # ODF slicer for axial slice -odf_actor_z = actor.odf_slicer( +odf_actor_z = fury.actor.odf_slicer( sh, affine=affine, sphere=sphere_low, @@ -63,7 +61,7 @@ ) # ODF slicer for coronal slice -odf_actor_y = actor.odf_slicer( +odf_actor_y = fury.actor.odf_slicer( sh, affine=affine, sphere=sphere_low, @@ -80,7 +78,7 @@ ) # ODF slicer for sagittal slice -odf_actor_x = actor.odf_slicer( +odf_actor_x = fury.actor.odf_slicer( sh, affine=affine, sphere=sphere_low, @@ -96,18 +94,18 @@ grid_shape[0] // 2, grid_shape[0] // 2, 0, grid_shape[1] - 1, 0, grid_shape[2] - 1 ) -scene = window.Scene() +scene = fury.window.Scene() scene.add(odf_actor_z) scene.add(odf_actor_y) scene.add(odf_actor_x) -show_m = window.ShowManager(scene, reset_camera=True, size=(1200, 900)) +show_m = fury.window.ShowManager(scene, reset_camera=True, size=(1200, 900)) ############################################################################### # Now that we have a `ShowManager` containing our slicer, we can go on and # configure our UI for changing the slices to visualize. -line_slider_z = ui.LineSlider2D( +line_slider_z = fury.ui.LineSlider2D( min_value=0, max_value=grid_shape[2] - 1, initial_value=grid_shape[2] / 2, @@ -115,7 +113,7 @@ length=140, ) -line_slider_y = ui.LineSlider2D( +line_slider_y = fury.ui.LineSlider2D( min_value=0, max_value=grid_shape[1] - 1, initial_value=grid_shape[1] / 2, @@ -123,7 +121,7 @@ length=140, ) -line_slider_x = ui.LineSlider2D( +line_slider_x = fury.ui.LineSlider2D( min_value=0, max_value=grid_shape[0] - 1, initial_value=grid_shape[0] / 2, @@ -138,7 +136,9 @@ # We fix the order of the faces' three vertices to a clockwise winding. This # ensures all faces have a normal going away from the center of the sphere. -sphere_high.faces = fix_winding_order(sphere_high.vertices, sphere_high.faces, True) +sphere_high.faces = fury.utils.fix_winding_order( + sphere_high.vertices, sphere_high.faces, True +) B_high = sh_to_sf_matrix(sphere_high, 8, return_inv=False) ############################################################################### @@ -147,7 +147,7 @@ "Low resolution": (sphere_low, B_low), "High resolution": (sphere_high, B_high), } -combobox = ui.ComboBox2D(items=list(sphere_dict)) +combobox = fury.ui.ComboBox2D(items=list(sphere_dict)) scene.add(combobox) ############################################################################### @@ -186,7 +186,7 @@ def change_sphere(combobox): def build_label(text): - label = ui.TextBlock2D() + label = fury.ui.TextBlock2D() label.message = text label.font_size = 18 label.font_family = "Arial" @@ -204,7 +204,7 @@ def build_label(text): line_slider_label_y = build_label(text="Y Slice") line_slider_label_x = build_label(text="X Slice") -panel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align="right") +panel = fury.ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align="right") panel.center = (1030, 120) panel.add_element(line_slider_label_x, (0.1, 0.75)) @@ -245,7 +245,7 @@ def win_callback(obj, _event): show_m.render() show_m.start() else: - window.record( + fury.window.record( scene, out_path="odf_slicer_3D.png", size=(1200, 900), reset_camera=False ) diff --git a/docs/examples/viz_fine_tuning_gl_context.py b/docs/examples/viz_fine_tuning_gl_context.py index 2f11ee588..a347bf691 100644 --- a/docs/examples/viz_fine_tuning_gl_context.py +++ b/docs/examples/viz_fine_tuning_gl_context.py @@ -16,9 +16,7 @@ import numpy as np -from fury import actor, window -from fury.shaders import shader_apply_effects -from fury.utils import remove_observer_from_actor +import fury ############################################################################### # We just proceed as usual: creating the actors and initializing a scene in @@ -27,21 +25,21 @@ centers = np.array([[0, 0, 0], [-0.1, 0, 0], [0.1, 0, 0]]) colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) -actor_no_depth_test = actor.markers( +actor_no_depth_test = fury.actor.markers( centers, marker="s", colors=colors, marker_opacity=0.5, scales=0.2, ) -actor_normal_blending = actor.markers( +actor_normal_blending = fury.actor.markers( centers - np.array([[0, -0.5, 0]]), marker="s", colors=colors, marker_opacity=0.5, scales=0.2, ) -actor_add_blending = actor.markers( +actor_add_blending = fury.actor.markers( centers - np.array([[0, -1, 0]]), marker="s", colors=colors, @@ -49,14 +47,14 @@ scales=0.2, ) -actor_sub_blending = actor.markers( +actor_sub_blending = fury.actor.markers( centers - np.array([[0, -1.5, 0]]), marker="s", colors=colors, marker_opacity=0.5, scales=0.2, ) -actor_mul_blending = actor.markers( +actor_mul_blending = fury.actor.markers( centers - np.array([[0, -2, 0]]), marker="s", colors=colors, @@ -65,11 +63,11 @@ ) -scene = window.Scene() +scene = fury.window.Scene() scene.background((0.5, 0.5, 0.5)) -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=False ) @@ -89,36 +87,40 @@ # Here we're using the pre-build FURY window functions which has already a # set of specific behaviors to be applied in the OpenGL context -shader_apply_effects( - showm.window, actor_normal_blending, effects=window.gl_set_normal_blending +fury.shaders.shader_apply_effects( + showm.window, actor_normal_blending, effects=fury.window.gl_set_normal_blending ) # ############################################################################### # It's also possible use a list of effects. The final opengl state it'll # be the composition of each effect that each function has in the opengl state -id_observer = shader_apply_effects( +id_observer = fury.shaders.shader_apply_effects( showm.window, actor_no_depth_test, - effects=[window.gl_reset_blend, window.gl_disable_blend, window.gl_disable_depth], + effects=[ + fury.window.gl_reset_blend, + fury.window.gl_disable_blend, + fury.window.gl_disable_depth, + ], ) -shader_apply_effects( +fury.shaders.shader_apply_effects( showm.window, actor_add_blending, effects=[ - window.gl_reset_blend, - window.gl_enable_depth, - window.gl_set_additive_blending, + fury.window.gl_reset_blend, + fury.window.gl_enable_depth, + fury.window.gl_set_additive_blending, ], ) -shader_apply_effects( - showm.window, actor_sub_blending, effects=window.gl_set_subtractive_blending +fury.shaders.shader_apply_effects( + showm.window, actor_sub_blending, effects=fury.window.gl_set_subtractive_blending ) -shader_apply_effects( - showm.window, actor_mul_blending, effects=window.gl_set_multiplicative_blending +fury.shaders.shader_apply_effects( + showm.window, actor_mul_blending, effects=fury.window.gl_set_multiplicative_blending ) ############################################################################### @@ -137,9 +139,11 @@ def timer_callback(obj, event): # the results of each specific opengl-state showm.scene.azimuth(1) if cnt == 400: - remove_observer_from_actor(actor_no_depth_test, id_observer) - shader_apply_effects( - showm.window, actor_no_depth_test, effects=window.gl_set_additive_blending + fury.utils.remove_observer_from_actor(actor_no_depth_test, id_observer) + fury.shaders.shader_apply_effects( + showm.window, + actor_no_depth_test, + effects=fury.window.gl_set_additive_blending, ) if cnt == 1000: showm.exit() @@ -150,4 +154,4 @@ def timer_callback(obj, event): if interactive: showm.start() -window.record(scene, out_path="viz_fine_tuning_gl_context.png", size=(600, 600)) +fury.window.record(scene, out_path="viz_fine_tuning_gl_context.png", size=(600, 600)) diff --git a/docs/examples/viz_fractals.py b/docs/examples/viz_fractals.py index acbd3061e..a1573c194 100644 --- a/docs/examples/viz_fractals.py +++ b/docs/examples/viz_fractals.py @@ -21,7 +21,7 @@ import numpy as np -from fury import primitive, ui, utils, window +import fury ############################################################################### # Before we create our first fractal, let's set some ground rules for us to @@ -64,7 +64,7 @@ def tetrix(N): offset = (4**N - 1) // 3 + 1 # just need the vertices - U, _ = primitive.prim_tetrahedron() + U, _ = fury.primitive.prim_tetrahedron() def gen_centers(depth, pos, center, dist): if depth == N: @@ -78,7 +78,7 @@ def gen_centers(depth, pos, center, dist): # the division by sqrt(6) is to ensure correct scale gen_centers(0, 1, np.zeros(3), 2 / (6**0.5)) - vertices, faces = primitive.prim_tetrahedron() + vertices, faces = fury.primitive.prim_tetrahedron() # primitive is scaled down depending on level vertices /= 2 ** (N - 1) @@ -87,10 +87,10 @@ def gen_centers(depth, pos, center, dist): bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0) colors = (centers - bounds_min) / (bounds_max - bounds_min) - vertices, triangles, colors, _ = primitive.repeat_primitive( + vertices, triangles, colors, _ = fury.primitive.repeat_primitive( centers=centers, colors=colors, vertices=vertices, faces=faces ) - return utils.get_actor_from_primitive(vertices, triangles, colors) + return fury.utils.get_actor_from_primitive(vertices, triangles, colors) ############################################################################### @@ -149,16 +149,16 @@ def gen_centers(depth, pos, center, dist): gen_centers(0, 1, np.zeros(3), 1 / 3) - vertices, faces = primitive.prim_box() + vertices, faces = fury.primitive.prim_box() vertices /= 3**N bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0) colors = (centers - bounds_min) / (bounds_max - bounds_min) - vertices, triangles, colors, _ = primitive.repeat_primitive( + vertices, triangles, colors, _ = fury.primitive.repeat_primitive( centers=centers, colors=colors, vertices=vertices, faces=faces ) - return utils.get_actor_from_primitive(vertices, triangles, colors) + return fury.utils.get_actor_from_primitive(vertices, triangles, colors) ############################################################################### @@ -204,24 +204,24 @@ def gen_centers(depth, pos, center, side): gen_centers(0, 1, np.zeros(3), 1 / 3) - vertices, faces = primitive.prim_box() + vertices, faces = fury.primitive.prim_box() vertices /= 3**N bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0) colors = (centers - bounds_min) / (bounds_max - bounds_min) - vertices, triangles, colors, _ = primitive.repeat_primitive( + vertices, triangles, colors, _ = fury.primitive.repeat_primitive( centers=centers, colors=colors, vertices=vertices, faces=faces ) - return utils.get_actor_from_primitive(vertices, triangles, colors) + return fury.utils.get_actor_from_primitive(vertices, triangles, colors) ############################################################################### # Now that we have the functions to generate fractals, we can start setting up # the Scene and ShowManager. -scene = window.Scene() -showmgr = window.ShowManager(scene, "Fractals", (800, 800), reset_camera=True) +scene = fury.window.Scene() +showmgr = fury.window.ShowManager(scene, "Fractals", (800, 800), reset_camera=True) ############################################################################### # These values are what work nicely on my machine without lagging. If you have @@ -240,7 +240,7 @@ def gen_centers(depth, pos, center, side): "Snowflake": 2, } -shape_chooser = ui.RadioButton( +shape_chooser = fury.ui.RadioButton( options.keys(), padding=10, font_size=16, @@ -289,4 +289,4 @@ def timer_callback(_obj, _event): if interactive: showmgr.start() else: - window.record(showmgr.scene, out_path="fractals.png", size=(800, 800)) + fury.window.record(showmgr.scene, out_path="fractals.png", size=(800, 800)) diff --git a/docs/examples/viz_gltf.py b/docs/examples/viz_gltf.py index 8d1c50ca4..dbf668e82 100644 --- a/docs/examples/viz_gltf.py +++ b/docs/examples/viz_gltf.py @@ -5,20 +5,18 @@ In this tutorial, we will show how to display a glTF file in a scene. """ -from fury import window -from fury.data import fetch_gltf, read_viz_gltf -from fury.gltf import glTF +import fury ############################################################################## # Create a scene. -scene = window.Scene() +scene = fury.window.Scene() scene.SetBackground(0.1, 0.1, 0.4) ############################################################################## # Retrieving the gltf model. -fetch_gltf("Duck", "glTF") -filename = read_viz_gltf("Duck") +fury.data.fetch_gltf("Duck", "glTF") +filename = fury.data.read_viz_gltf("Duck") ############################################################################## # Initialize the glTF object and get actors using `actors` method. @@ -26,7 +24,7 @@ # or materials manually afterwards. # Experimental: For smooth mesh/actor you can set `apply_normals=True`. -gltf_obj = glTF(filename, apply_normals=False) +gltf_obj = fury.gltf.glTF(filename, apply_normals=False) actors = gltf_obj.actors() ############################################################################## @@ -44,6 +42,6 @@ interactive = False if interactive: - window.show(scene, size=(1280, 720)) + fury.window.show(scene, size=(1280, 720)) -window.record(scene, out_path="viz_gltf.png", size=(1280, 720)) +fury.window.record(scene, out_path="viz_gltf.png", size=(1280, 720)) diff --git a/docs/examples/viz_gltf_animated.py b/docs/examples/viz_gltf_animated.py index a7bf84ced..a664883c0 100644 --- a/docs/examples/viz_gltf_animated.py +++ b/docs/examples/viz_gltf_animated.py @@ -6,16 +6,14 @@ scene. """ -from fury import window -from fury.data import fetch_gltf, read_viz_gltf -from fury.gltf import glTF +import fury ############################################################################## # Create a scene. -scene = window.Scene() +scene = fury.window.Scene() -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) showm.initialize() @@ -23,14 +21,14 @@ ############################################################################## # Retrieving the gltf model. -fetch_gltf("InterpolationTest", "glTF") -filename = read_viz_gltf("InterpolationTest") +fury.data.fetch_gltf("InterpolationTest", "glTF") +filename = fury.data.read_viz_gltf("InterpolationTest") ############################################################################## # Initialize the glTF object and get actors using `actors` method. # Get the main_timeline (which contains multiple Timeline objects). -gltf_obj = glTF(filename) +gltf_obj = fury.gltf.glTF(filename) timeline = gltf_obj.main_animation() ############################################################################## @@ -54,4 +52,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, out_path="viz_gltf_animated.png", size=(900, 768)) +fury.window.record(scene, out_path="viz_gltf_animated.png", size=(900, 768)) diff --git a/docs/examples/viz_gltf_export.py b/docs/examples/viz_gltf_export.py index 9d54a2f8a..bc74bd2a1 100644 --- a/docs/examples/viz_gltf_export.py +++ b/docs/examples/viz_gltf_export.py @@ -7,8 +7,7 @@ import numpy as np -from fury import actor, gltf, window -from fury.data import fetch_gltf, read_viz_gltf +import fury ############################################################################ # Specifying centers and colors for actors. We will use these parameters @@ -20,20 +19,20 @@ ############################################################################## # Create a scene. -scene = window.Scene() +scene = fury.window.Scene() ############################################################################## # Creating actors and adding to scene. -cube = actor.cube(np.add(centers, np.array([2, 0, 0])), colors=colors / 2) +cube = fury.actor.cube(np.add(centers, np.array([2, 0, 0])), colors=colors / 2) scene.add(cube) -sphere = actor.sphere(np.add(centers, np.array([0, 2, 0])), colors=colors) +sphere = fury.actor.sphere(np.add(centers, np.array([0, 2, 0])), colors=colors) scene.add(sphere) -fetch_gltf("BoxTextured", "glTF") -filename = read_viz_gltf("BoxTextured") -gltf_obj = gltf.glTF(filename) +fury.data.fetch_gltf("BoxTextured", "glTF") +filename = fury.data.read_viz_gltf("BoxTextured") +gltf_obj = fury.gltf.glTF(filename) box_actor = gltf_obj.actors() scene.add(box_actor[0]) @@ -47,12 +46,12 @@ ############################################################################## # Exporting scene as a glTF file -gltf.export_scene(scene, filename="viz_gltf_export.gltf") +fury.gltf.export_scene(scene, filename="viz_gltf_export.gltf") ############################################################################## # Reading the newly created glTF file and get actors. -gltf_obj = gltf.glTF("viz_gltf_export.gltf") +gltf_obj = fury.gltf.glTF("viz_gltf_export.gltf") actors = gltf_obj.actors() ############################################################################## @@ -63,6 +62,6 @@ interactive = False if interactive: - window.show(scene, size=(1280, 720)) + fury.window.show(scene, size=(1280, 720)) -window.record(scene, out_path="viz_gltf_export.png", size=(1280, 720)) +fury.window.record(scene, out_path="viz_gltf_export.png", size=(1280, 720)) diff --git a/docs/examples/viz_helical_motion.py b/docs/examples/viz_helical_motion.py index b17f319ff..b3cad3132 100644 --- a/docs/examples/viz_helical_motion.py +++ b/docs/examples/viz_helical_motion.py @@ -20,7 +20,7 @@ import numpy as np -from fury import actor, ui, utils, window +import fury ############################################################################### # Let's define some variable and their description: @@ -50,12 +50,12 @@ ############################################################################### # Creating a scene object and configuring the camera's position -scene = window.Scene() +scene = fury.window.Scene() scene.zoom(1.2) scene.set_camera( position=(10, 12.5, 19), focal_point=(3.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) ) -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(800, 600), reset_camera=True, order_transparent=True ) @@ -64,11 +64,11 @@ # Creating a blue colored arrow which shows the direction of magnetic field and # electric field. -color_arrow = window.colors.blue # color of the arrow can be manipulated +color_arrow = fury.window.colors.blue # color of the arrow can be manipulated centers = np.array([[0, 0, 0]]) directions = np.array([[1, 0, 0]]) heights = np.array([8]) -arrow_actor = actor.arrow( +arrow_actor = fury.actor.arrow( centers, directions, color_arrow, @@ -90,13 +90,13 @@ ############################################################################### # Initializing point actor which will represent the charged particle -color_particle = window.colors.red # color of particle can be manipulated +color_particle = fury.window.colors.red # color of particle can be manipulated pts = np.array([[x, y, z]]) -charge_actor = actor.point(pts, color_particle, point_radius=radius_particle) +charge_actor = fury.actor.point(pts, color_particle, point_radius=radius_particle) scene.add(charge_actor) -vertices = utils.vertices_from_actor(charge_actor) -vcolors = utils.colors_from_actor(charge_actor, "colors") +vertices = fury.utils.vertices_from_actor(charge_actor) +vcolors = fury.utils.colors_from_actor(charge_actor, "colors") no_vertices_per_point = len(vertices) initial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0) @@ -104,7 +104,7 @@ ############################################################################### # Initializing text box to display the name of the animation -tb = ui.TextBlock2D(bold=True, position=(100, 90)) +tb = fury.ui.TextBlock2D(bold=True, position=(100, 90)) m1 = "Motion of a charged particle in a " m2 = "combined electric and magnetic field" tb.message = m1 + m2 @@ -143,13 +143,13 @@ def timer_callback(_obj, _event): vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0) - utils.update_actor(charge_actor) + fury.utils.update_actor(charge_actor) # Plotting the path followed by the particle coor_2 = np.array([x, y, z]) coors = np.array([coor_1, coor_2]) coors = [coors] - line_actor = actor.line(coors, window.colors.cyan, linewidth=3) + line_actor = fury.actor.line(coors, fury.window.colors.cyan, linewidth=3) scene.add(line_actor) coor_1 = coor_2 @@ -166,4 +166,4 @@ def timer_callback(_obj, _event): showm.add_timer_callback(True, 15, timer_callback) showm.start() -window.record(showm.scene, size=(800, 600), out_path="viz_helical_motion.png") +fury.window.record(showm.scene, size=(800, 600), out_path="viz_helical_motion.png") diff --git a/docs/examples/viz_hierarchical_animation.py b/docs/examples/viz_hierarchical_animation.py index 8b727e708..5e0772493 100644 --- a/docs/examples/viz_hierarchical_animation.py +++ b/docs/examples/viz_hierarchical_animation.py @@ -8,26 +8,25 @@ import numpy as np -from fury import actor, window -from fury.animation import Animation +import fury -scene = window.Scene() +scene = fury.window.Scene() -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) showm.initialize() ############################################################################### # Creating the road -road = actor.box( +road = fury.actor.box( np.array([[0, 0, 0]]), colors=np.array([[1, 1, 1]]), scales=np.array([[22, 0.1, 5]]) ) ############################################################################### # Constructing the car geometry -body_actor = actor.box( +body_actor = fury.actor.box( np.array([[0, 0.5, 0], [-0.2, 1, 0]]), scales=((4, 1, 2), (2.5, 1.5, 1.8)), colors=(0.6, 0.3, 0.1), @@ -35,7 +34,7 @@ ############################################################################### # Adding the the car's body to an Animation to be able to animate it later. -car_anim = Animation(body_actor) +car_anim = fury.animation.Animation(body_actor) ############################################################################### # Creating the wheels of the car @@ -50,7 +49,7 @@ ] wheels = [ - actor.cylinder( + fury.actor.cylinder( wheel_center, wheel_direction, (0.1, 0.7, 0.3), @@ -66,7 +65,7 @@ # Animating each wheel and setting its position to the right position using a # single keyframe that will not change. -wheels_animations = [Animation(wheel) for wheel in wheels] +wheels_animations = [fury.animation.Animation(wheel) for wheel in wheels] for wheel_anim in wheels_animations: wheel_anim.set_position(0.0, wheel_positions.pop()) @@ -78,13 +77,13 @@ ############################################################################### # First we create the shaft holding and rotating the radar -radar_shaft = actor.cylinder( +radar_shaft = fury.actor.cylinder( np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), (0, 1, 0), heights=1 ) ############################################################################### # In order to animate the shaft actor we have to add it to an Animation -radar_shaft_anim = Animation(radar_shaft) +radar_shaft_anim = fury.animation.Animation(radar_shaft) ############################################################################### # Setting a single position keyframe will make sure the actor will be placed at @@ -99,11 +98,13 @@ ############################################################################### # Now we create the radar itself -radar = actor.cone(np.array([[0, 0, 0]]), directions=(0, 0, 0), colors=(0.2, 0.2, 0.9)) +radar = fury.actor.cone( + np.array([[0, 0, 0]]), directions=(0, 0, 0), colors=(0.2, 0.2, 0.9) +) ############################################################################### # Then add it to an animation in order to rotate it -radar_animation = Animation(radar) +radar_animation = fury.animation.Animation(radar) ############################################################################### # Set position and rotation as done above with the shaft. @@ -140,6 +141,6 @@ if interactive: showm.start() -window.record( +fury.window.record( scene, out_path="viz_keyframe_hierarchical_animation.png", size=(900, 768) ) diff --git a/docs/examples/viz_interaction.py b/docs/examples/viz_interaction.py index 7becb5964..73eb145dc 100644 --- a/docs/examples/viz_interaction.py +++ b/docs/examples/viz_interaction.py @@ -36,13 +36,11 @@ import numpy as np -from fury import actor, window -from fury.stream.client import FuryStreamClient, FuryStreamInteraction +import fury # if this example it's not working for you and you're using MacOs # uncomment the following line # multiprocessing.set_start_method('spawn') -from fury.stream.server.main import WEBRTC_AVAILABLE, web_server, web_server_raw_array if __name__ == "__main__": interactive = False @@ -77,23 +75,23 @@ centers = np.array([[0, 0, 0], [-1, 0, 0], [1, 0, 0]]) colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) - actors = actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors) - scene = window.Scene() + actors = fury.actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors) + scene = fury.window.Scene() scene.add(actors) - showm = window.ShowManager(scene, size=(window_size[0], window_size[1])) + showm = fury.window.ShowManager(scene, size=(window_size[0], window_size[1])) - stream = FuryStreamClient( + stream = fury.stream.FuryStreamClient( showm, max_window_size=max_window_size, use_raw_array=use_raw_array ) - stream_interaction = FuryStreamInteraction( + stream_interaction = fury.stream.client.FuryStreamInteraction( showm, max_queue_size=max_queue_size, use_raw_array=use_raw_array ) if use_raw_array: p = multiprocessing.Process( - target=web_server_raw_array, + target=fury.stream.server.web_server_raw_array, args=( stream.img_manager.image_buffers, stream.img_manager.info_buffer, @@ -102,13 +100,13 @@ 8000, "localhost", True, - WEBRTC_AVAILABLE, + fury.stream.server.main.WEBRTC_AVAILABLE, ), ) else: p = multiprocessing.Process( - target=web_server, + target=fury.stream.server.web_server, args=( stream.img_manager.image_buffer_names, stream.img_manager.info_buffer_name, @@ -117,7 +115,7 @@ 8000, "localhost", True, - WEBRTC_AVAILABLE, + fury.stream.server.main.WEBRTC_AVAILABLE, ), ) p.start() @@ -143,4 +141,4 @@ stream.cleanup() stream_interaction.cleanup() - window.record(showm.scene, size=window_size, out_path="viz_interaction.png") + fury.window.record(showm.scene, size=window_size, out_path="viz_interaction.png") diff --git a/docs/examples/viz_interpolators.py b/docs/examples/viz_interpolators.py index d6793bb18..104bd40e1 100644 --- a/docs/examples/viz_interpolators.py +++ b/docs/examples/viz_interpolators.py @@ -15,9 +15,7 @@ import numpy as np -from fury import actor, window -from fury.animation import Animation -from fury.animation.interpolator import cubic_spline_interpolator +import fury keyframes = { 1.0: {"value": np.array([0, 0, 0])}, @@ -43,7 +41,7 @@ # Below there is an example on how to use interpolators manually to interpolate # the above defined ``keyframes``. -interpolation_function = cubic_spline_interpolator(keyframes) +interpolation_function = fury.animation.cubic_spline_interpolator(keyframes) ############################################################################### # Now, if we feed any time to this function it would return the cubic @@ -61,21 +59,21 @@ # In order to make any animations in FURY, a `ShowManager` is needed to handle # updating the animation and rendering the scene. -scene = window.Scene() +scene = fury.window.Scene() -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) showm.initialize() -arrow = actor.arrow(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6) +arrow = fury.actor.arrow(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6) ############################################################################### # Creating an ``Animation`` # ========================= # # First step is creating the Animation. -animation = Animation() +animation = fury.animation.Animation() ############################################################################### # Adding the sphere actor to the timeline @@ -104,7 +102,7 @@ # # Below we set the interpolator for position keyframes to be # **cubic spline interpolator**. -animation.set_position_interpolator(cubic_spline_interpolator) +animation.set_position_interpolator(fury.animation.cubic_spline_interpolator) ############################################################################### # Adding some rotation keyframes. @@ -133,4 +131,4 @@ if interactive: showm.start() -window.record(scene, out_path="viz_keyframe_interpolator.png", size=(900, 768)) +fury.window.record(scene, out_path="viz_keyframe_interpolator.png", size=(900, 768)) diff --git a/docs/examples/viz_introduction.py b/docs/examples/viz_introduction.py index f3b2673bf..55c6a124e 100644 --- a/docs/examples/viz_introduction.py +++ b/docs/examples/viz_introduction.py @@ -57,12 +57,11 @@ import numpy as np -from fury import actor, window -from fury.animation import Animation +import fury -scene = window.Scene() +scene = fury.window.Scene() -showm = window.ShowManager(scene, size=(900, 768)) +showm = fury.window.ShowManager(scene, size=(900, 768)) showm.initialize() @@ -73,11 +72,11 @@ # This is a quick demo showing how to translate a sphere from (0, 0, 0) to # (1, 1, 1). # First, we create an ``Animation``. See ``viz_interpolators.py`` tutorial -animation = Animation() +animation = fury.animation.Animation() ############################################################################### # We also create the FURY sphere actor that will be animated. -sphere = actor.sphere(np.zeros([1, 3]), np.ones([1, 3])) +sphere = fury.actor.sphere(np.zeros([1, 3]), np.ones([1, 3])) ############################################################################### # Then lets add the sphere actor to the ``Animation`` @@ -112,6 +111,6 @@ if interactive: showm.start() -window.record( +fury.window.record( scene, out_path="viz_keyframe_animation_introduction.png", size=(900, 768) ) diff --git a/docs/examples/viz_layout.py b/docs/examples/viz_layout.py index c7fd19e92..1859caf96 100644 --- a/docs/examples/viz_layout.py +++ b/docs/examples/viz_layout.py @@ -6,40 +6,41 @@ This example shows how to place different UI elements in different Layouts. The Layouts used here is GridLayout (with different cell shapes). -First, some imports. +First, let's import fury. """ -from fury import ui, window -from fury.layout import GridLayout +import fury ############################################################################### # We create some panels and then we arrange them in a grid fashion # # First, we create some panels with different sizes/positions -panel_1 = ui.Panel2D(size=(200, 200), color=(0.4, 0.6, 0.3), position=(100, 100)) +panel_1 = fury.ui.Panel2D(size=(200, 200), color=(0.4, 0.6, 0.3), position=(100, 100)) -panel_2 = ui.Panel2D(size=(250, 250), color=(0.8, 0.3, 0.5), position=(150, 150)) +panel_2 = fury.ui.Panel2D(size=(250, 250), color=(0.8, 0.3, 0.5), position=(150, 150)) ############################################################################### # Now we create two listboxes -listbox_1 = ui.ListBox2D(size=(150, 150), values=["First", "Second", "Third"]) +listbox_1 = fury.ui.ListBox2D(size=(150, 150), values=["First", "Second", "Third"]) -listbox_2 = ui.ListBox2D(size=(250, 250), values=["First", "Second", "Third"]) +listbox_2 = fury.ui.ListBox2D(size=(250, 250), values=["First", "Second", "Third"]) ############################################################################### # Now we create two different UI i.e. a slider and a listbox -slider = ui.LineSlider2D(length=150) -listbox = ui.ListBox2D(size=(150, 150), values=["First", "Second", "Third"]) +slider = fury.ui.LineSlider2D(length=150) +listbox = fury.ui.ListBox2D(size=(150, 150), values=["First", "Second", "Third"]) ############################################################################### # Now, we create grids with different shapes -rect_grid = GridLayout(position_offset=(0, 0, 0)) -square_grid = GridLayout(cell_shape="square", position_offset=(0, 300, 0)) -diagonal_grid = GridLayout(cell_shape="diagonal", position_offset=(0, 600, 0)) +rect_grid = fury.layout.GridLayout(position_offset=(0, 0, 0)) +square_grid = fury.layout.GridLayout(cell_shape="square", position_offset=(0, 300, 0)) +diagonal_grid = fury.layout.GridLayout( + cell_shape="diagonal", position_offset=(0, 600, 0) +) ############################################################################### @@ -50,7 +51,7 @@ diagonal_grid.apply([slider, listbox]) current_size = (1500, 1500) -show_manager = window.ShowManager(size=current_size, title="FURY UI Layout") +show_manager = fury.window.ShowManager(size=current_size, title="FURY UI Layout") show_manager.scene.add(panel_1, panel_2, listbox_1, listbox_2, slider, listbox) @@ -60,4 +61,4 @@ if interactive: show_manager.start() -window.record(show_manager.scene, out_path="ui_layout.png", size=(400, 400)) +fury.window.record(show_manager.scene, out_path="ui_layout.png", size=(400, 400)) diff --git a/docs/examples/viz_markers.py b/docs/examples/viz_markers.py index 600296c2d..5a532598d 100644 --- a/docs/examples/viz_markers.py +++ b/docs/examples/viz_markers.py @@ -8,7 +8,7 @@ import numpy as np -from fury import actor, window +import fury n = 10000 @@ -26,7 +26,7 @@ ############################################################################ # You can control the edge color and edge width for each marker -nodes_actor = actor.markers( +nodes_actor = fury.actor.markers( centers, marker=markers, edge_width=0.1, @@ -38,14 +38,14 @@ ############################################################################ # In addition, an 3D sphere it's also a valid type of marker -nodes_3d_actor = actor.markers( +nodes_3d_actor = fury.actor.markers( centers + np.ones_like(centers) * 25, marker="3d", colors=colors, scales=0.5, ) -scene = window.Scene() +scene = fury.window.Scene() scene.add(nodes_actor) scene.add(nodes_3d_actor) @@ -53,6 +53,6 @@ interactive = False if interactive: - window.show(scene, size=(600, 600)) + fury.window.show(scene, size=(600, 600)) -window.record(scene, out_path="viz_markers.png", size=(600, 600)) +fury.window.record(scene, out_path="viz_markers.png", size=(600, 600)) diff --git a/docs/examples/viz_morphing.py b/docs/examples/viz_morphing.py index 9bf996759..ecd229e6a 100644 --- a/docs/examples/viz_morphing.py +++ b/docs/examples/viz_morphing.py @@ -5,22 +5,20 @@ In this tutorial, we will show how to use morphing in a glTF model in FURY. """ -from fury import window -from fury.data import fetch_gltf, read_viz_gltf -from fury.gltf import glTF +import fury ############################################################################## # Retrieving the model with morphing in it (look at Khronoos samples). # We're choosing the `MorphStressTest` model here. -fetch_gltf("MorphStressTest", "glTF") -filename = read_viz_gltf("MorphStressTest") +fury.data.fetch_gltf("MorphStressTest", "glTF") +filename = fury.data.read_viz_gltf("MorphStressTest") ############################################################################## # Initializing the glTF object, You can additionally set `apply_normals=True`. # Note: Normals might not work as intended with morphing. -gltf_obj = glTF(filename, apply_normals=True) +gltf_obj = fury.gltf.glTF(filename, apply_normals=True) ############################################################################## # Get the morph timeline using `morph_timeline` method, Choose the animation @@ -40,8 +38,8 @@ # Initialize the show manager and add timeline to the scene (No need to add # actors to the scene separately). -scene = window.Scene() -showm = window.ShowManager( +scene = fury.window.Scene() +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=True, order_transparent=True ) @@ -71,4 +69,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, out_path="viz_morphing.png", size=(900, 768)) +fury.window.record(scene, out_path="viz_morphing.png", size=(900, 768)) diff --git a/docs/examples/viz_multithread.py b/docs/examples/viz_multithread.py index 33060f75f..2d491eefe 100644 --- a/docs/examples/viz_multithread.py +++ b/docs/examples/viz_multithread.py @@ -15,29 +15,29 @@ import numpy as np -from fury import actor, ui, window +import fury # Preparing to draw some spheres xyz = 10 * (np.random.random((100, 3)) - 0.5) colors = np.random.random((100, 4)) radii = np.random.random(100) + 0.5 -scene = window.Scene() -sphere_actor = actor.sphere( +scene = fury.window.Scene() +sphere_actor = fury.actor.sphere( centers=xyz, colors=colors, radii=radii, use_primitive=False ) scene.add(sphere_actor) # Preparing the show manager as usual -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) # showm.initialize() # Creating a text block to show a message and reset the camera -tb = ui.TextBlock2D(bold=True) +tb = fury.ui.TextBlock2D(bold=True) scene.add(tb) scene.ResetCamera() @@ -77,7 +77,7 @@ def add_remove_axes(): for i in range(100): if showm.lock_current(): if current_axes is None: - current_axes = actor.axes(scale=(0.20 * i, 0.20 * i, 0.20 * i)) + current_axes = fury.actor.axes(scale=(0.20 * i, 0.20 * i, 0.20 * i)) scene.add(current_axes) pass else: diff --git a/docs/examples/viz_network.py b/docs/examples/viz_network.py index 13140a96f..c6189fb67 100644 --- a/docs/examples/viz_network.py +++ b/docs/examples/viz_network.py @@ -15,14 +15,12 @@ import numpy as np -from fury import actor, colormap as cmap, window -from fury.data import fetch_viz_wiki_nw +import fury ############################################################################### # Then let's download some available datasets. - -files, folder = fetch_viz_wiki_nw() +files, folder = fury.data.fetch_viz_wiki_nw() categories_file, edges_file, positions_file = sorted(files.keys()) ############################################################################### @@ -40,7 +38,7 @@ index2category = np.unique(categories) -categoryColors = cmap.distinguishable_colormap(nb_colors=len(index2category)) +categoryColors = fury.colormap.distinguishable_colormap(nb_colors=len(index2category)) colors = np.array([categoryColors[category2index[category]] for category in categories]) @@ -68,7 +66,7 @@ # build 2 actors that we represent our data : sphere_actor for the nodes and # lines_actor for the edges. -sphere_actor = actor.sphere( +sphere_actor = fury.actor.sphere( centers=positions, colors=colors, radii=radii * 0.5, @@ -76,7 +74,7 @@ phi=8, ) -lines_actor = actor.line( +lines_actor = fury.actor.line( edgesPositions, colors=edgesColors, opacity=0.1, @@ -86,7 +84,7 @@ # All actors need to be added in a scene, so we build one and add our # lines_actor and sphere_actor. -scene = window.Scene() +scene = fury.window.Scene() scene.add(lines_actor) scene.add(sphere_actor) @@ -98,9 +96,9 @@ interactive = False if interactive: - window.show(scene, size=(600, 600)) + fury.window.show(scene, size=(600, 600)) -window.record(scene, out_path="journal_networks.png", size=(600, 600)) +fury.window.record(scene, out_path="journal_networks.png", size=(600, 600)) ############################################################################### # This example can be improved by adding some interactivy with slider, diff --git a/docs/examples/viz_network_animated.py b/docs/examples/viz_network_animated.py index d68a19e4c..2f144a411 100644 --- a/docs/examples/viz_network_animated.py +++ b/docs/examples/viz_network_animated.py @@ -18,8 +18,7 @@ import numpy as np -from fury import actor, colormap as cmap, window -from fury.utils import compute_bounds, update_actor, vertices_from_actor +import fury ############################################################################### # This demo has two modes. @@ -72,7 +71,7 @@ index2category = np.unique(categories) -category_colors = cmap.distinguishable_colormap(nb_colors=len(index2category)) +category_colors = fury.colormap.distinguishable_colormap(nb_colors=len(index2category)) colors = np.array( [category_colors[category2index[category]] for category in categories] @@ -98,12 +97,12 @@ # build 2 actors that we represent our data : sphere_actor for the nodes and # lines_actor for the edges. -sphere_actor = actor.sphere( +sphere_actor = fury.actor.sphere( centers=np.zeros(positions.shape), colors=colors, radii=radii * 0.5, theta=8, phi=8 ) -lines_actor = actor.line( +lines_actor = fury.actor.line( np.zeros((len(edges), 2, 3)), colors=edges_colors, lod=False, @@ -129,7 +128,7 @@ def new_layout_timer( b = 1.0 deltaT = 1.0 - sphere_geometry = np.array(vertices_from_actor(sphere_actor)) + sphere_geometry = np.array(fury.utils.vertices_from_actor(sphere_actor)) geometry_length = sphere_geometry.shape[0] / vertices_count if vertex_initial_positions is not None: @@ -199,18 +198,18 @@ def _timer(_obj, _event): iterate(1) else: pos[:] += (np.random.random(pos.shape) - 0.5) * 1.5 - spheres_positions = vertices_from_actor(sphere_actor) + spheres_positions = fury.utils.vertices_from_actor(sphere_actor) spheres_positions[:] = sphere_geometry + np.repeat(pos, geometry_length, axis=0) - edges_positions = vertices_from_actor(lines_actor) + edges_positions = fury.utils.vertices_from_actor(lines_actor) edges_positions[::2] = pos[edges_list[:, 0]] edges_positions[1::2] = pos[edges_list[:, 1]] - update_actor(lines_actor) - compute_bounds(lines_actor) + fury.utils.update_actor(lines_actor) + fury.utils.compute_bounds(lines_actor) - update_actor(sphere_actor) - compute_bounds(lines_actor) + fury.utils.update_actor(sphere_actor) + fury.utils.compute_bounds(lines_actor) showm.scene.reset_clipping_range() showm.render() @@ -225,7 +224,7 @@ def _timer(_obj, _event): # lines_actor and sphere_actor. -scene = window.Scene() +scene = fury.window.Scene() camera = scene.camera() @@ -238,7 +237,7 @@ def _timer(_obj, _event): # parameter max_iteractions of the timer callback to let the animation run for # more time. -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, reset_camera=False, size=(900, 768), order_transparent=True, multi_samples=8 ) @@ -255,4 +254,4 @@ def _timer(_obj, _event): showm.start() -window.record(showm.scene, size=(900, 768), out_path="viz_animated_networks.png") +fury.window.record(showm.scene, size=(900, 768), out_path="viz_animated_networks.png") diff --git a/docs/examples/viz_no_interaction.py b/docs/examples/viz_no_interaction.py index d68b70076..1a968a5ef 100644 --- a/docs/examples/viz_no_interaction.py +++ b/docs/examples/viz_no_interaction.py @@ -12,10 +12,7 @@ # multiprocessing.set_start_method('spawn') import numpy as np -from fury import actor, colormap as cmap, window -from fury.data.fetcher import fetch_viz_wiki_nw -from fury.stream.client import FuryStreamClient -from fury.stream.server.main import web_server_raw_array +import fury if __name__ == "__main__": interactive = False @@ -24,7 +21,7 @@ window_size = (400, 400) - files, folder = fetch_viz_wiki_nw() + files, folder = fury.data.fetch_viz_wiki_nw() categories_file, edges_file, positions_file = sorted(files.keys()) positions = np.loadtxt(pjoin(folder, positions_file)) categories = np.loadtxt(pjoin(folder, categories_file), dtype=str) @@ -33,7 +30,9 @@ index2category = np.unique(categories) - categoryColors = cmap.distinguishable_colormap(nb_colors=len(index2category)) + categoryColors = fury.colormap.distinguishable_colormap( + nb_colors=len(index2category) + ) colors = np.array( [categoryColors[category2index[category]] for category in categories] @@ -49,19 +48,19 @@ edgesPositions = np.array(edgesPositions) edgesColors = np.average(np.array(edgesColors), axis=1) - sphere_actor = actor.sdf( + sphere_actor = fury.actor.sdf( centers=positions, colors=colors, primitives="sphere", scales=radii * 0.5, ) - lines_actor = actor.line( + lines_actor = fury.actor.line( edgesPositions, colors=edgesColors, opacity=0.1, ) - scene = window.Scene() + scene = fury.window.Scene() scene.add(lines_actor) scene.add(sphere_actor) @@ -70,7 +69,7 @@ position=(0, 0, 1000), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) ) - showm = window.ShowManager( + showm = fury.window.ShowManager( scene, reset_camera=False, size=(window_size[0], window_size[1]), @@ -82,9 +81,9 @@ ms = 0 - stream = FuryStreamClient(showm, use_raw_array=True) + stream = fury.stream.FuryStreamClient(showm, use_raw_array=True) p = multiprocessing.Process( - target=web_server_raw_array, + target=fury.stream.server.web_server_raw_array, args=( stream.img_manager.image_buffers, stream.img_manager.info_buffer, @@ -100,4 +99,4 @@ stream.stop() stream.cleanup() - window.record(showm.scene, size=window_size, out_path="viz_no_interaction.png") + fury.window.record(showm.scene, size=window_size, out_path="viz_no_interaction.png") diff --git a/docs/examples/viz_pbr_interactive.py b/docs/examples/viz_pbr_interactive.py index 3238e8ac5..768363919 100644 --- a/docs/examples/viz_pbr_interactive.py +++ b/docs/examples/viz_pbr_interactive.py @@ -9,14 +9,7 @@ Let's start by importing the necessary modules: """ -from fury import actor, material, ui, window -from fury.data import fetch_viz_cubemaps, read_viz_cubemap -from fury.io import load_cubemap_texture -from fury.utils import ( - normals_from_actor, - tangents_from_direction_of_anisotropy, - tangents_to_actor, -) +import fury ############################################################################### # The following functions will help us to manage the sliders events. @@ -40,22 +33,22 @@ def change_slice_anisotropy(slider): def change_slice_anisotropy_direction_x(slider): global doa, normals, sphere doa[0] = slider.value - tangents = tangents_from_direction_of_anisotropy(normals, doa) - tangents_to_actor(sphere, tangents) + tangents = fury.utils.tangents_from_direction_of_anisotropy(normals, doa) + fury.utils.tangents_to_actor(sphere, tangents) def change_slice_anisotropy_direction_y(slider): global doa, normals, sphere doa[1] = slider.value - tangents = tangents_from_direction_of_anisotropy(normals, doa) - tangents_to_actor(sphere, tangents) + tangents = fury.utils.tangents_from_direction_of_anisotropy(normals, doa) + fury.utils.tangents_to_actor(sphere, tangents) def change_slice_anisotropy_direction_z(slider): global doa, normals, sphere doa[2] = slider.value - tangents = tangents_from_direction_of_anisotropy(normals, doa) - tangents_to_actor(sphere, tangents) + tangents = fury.utils.tangents_from_direction_of_anisotropy(normals, doa) + fury.utils.tangents_to_actor(sphere, tangents) def change_slice_anisotropy_rotation(slider): @@ -100,19 +93,19 @@ def win_callback(obj, event): ############################################################################### # Let's fetch a skybox texture from the FURY data repository. -fetch_viz_cubemaps() +fury.data.fetch_viz_cubemaps() ############################################################################### # The following function returns the full path of the 6 images composing the # skybox. -textures = read_viz_cubemap("skybox") +textures = fury.data.read_viz_cubemap("skybox") ############################################################################### # Now that we have the location of the textures, let's load them and create a # Cube Map Texture object. -cubemap = load_cubemap_texture(textures) +cubemap = fury.io.load_cubemap_texture(textures) ############################################################################### # The Scene object in FURY can handle cube map textures and extract light @@ -120,13 +113,13 @@ def win_callback(obj, event): # interactions. The ``skybox`` parameter takes as input a cube map texture and # performs the previously described process. -scene = window.Scene(skybox=cubemap) +scene = fury.window.Scene(skybox=cubemap) ############################################################################### # With the scene created, we can then populate it. In this demo we will only # add a sphere actor. -sphere = actor.sphere([[0, 0, 0]], (0.7, 0.7, 0.7), radii=2, theta=64, phi=64) +sphere = fury.actor.sphere([[0, 0, 0]], (0.7, 0.7, 0.7), radii=2, theta=64, phi=64) ############################################################################### # The direction of anisotropy (DoA) defines the direction at which all the @@ -137,17 +130,17 @@ def win_callback(obj, event): ############################################################################### # The following process gets the normals of the actor and computes the tangents # that are aligned to the provided DoA. Then it registers those tangents to the -# actor. +# fury.actor. -normals = normals_from_actor(sphere) -tangents = tangents_from_direction_of_anisotropy(normals, doa) -tangents_to_actor(sphere, tangents) +normals = fury.utils.normals_from_actor(sphere) +tangents = fury.utils.tangents_from_direction_of_anisotropy(normals, doa) +fury.utils.tangents_to_actor(sphere, tangents) ############################################################################### # With the tangents computed and in place, we have all the elements needed to # add some material properties to the actor. -pbr_params = material.manifest_pbr(sphere) +pbr_params = fury.material.manifest_pbr(sphere) ############################################################################### # Our actor is now ready to be added to the scene. @@ -157,7 +150,7 @@ def win_callback(obj, event): ############################################################################### # Let's setup now the window and the UI. -show_m = window.ShowManager( +show_m = fury.window.ShowManager( scene=scene, size=(1920, 1080), reset_camera=False, order_transparent=True ) @@ -165,7 +158,7 @@ def win_callback(obj, event): ############################################################################### # We will create one single panel with all of our labels and sliders. -control_panel = ui.Panel2D( +control_panel = fury.ui.Panel2D( (400, 500), position=(5, 5), color=(0.25, 0.25, 0.25), opacity=0.75, align="right" ) @@ -173,25 +166,25 @@ def win_callback(obj, event): # By using our previously defined function, we can easily create all the labels # we need for this demo. And then add them to the panel. -slider_label_metallic = ui.TextBlock2D(text="Metallic", font_size=16) -slider_label_roughness = ui.TextBlock2D(text="Roughness", font_size=16) -slider_label_anisotropy = ui.TextBlock2D(text="Anisotropy", font_size=16) -slider_label_anisotropy_rotation = ui.TextBlock2D( +slider_label_metallic = fury.ui.TextBlock2D(text="Metallic", font_size=16) +slider_label_roughness = fury.ui.TextBlock2D(text="Roughness", font_size=16) +slider_label_anisotropy = fury.ui.TextBlock2D(text="Anisotropy", font_size=16) +slider_label_anisotropy_rotation = fury.ui.TextBlock2D( text="Anisotropy Rotation", font_size=16 ) -slider_label_anisotropy_direction_x = ui.TextBlock2D( +slider_label_anisotropy_direction_x = fury.ui.TextBlock2D( text="Anisotropy Direction X", font_size=16 ) -slider_label_anisotropy_direction_y = ui.TextBlock2D( +slider_label_anisotropy_direction_y = fury.ui.TextBlock2D( text="Anisotropy Direction Y", font_size=16 ) -slider_label_anisotropy_direction_z = ui.TextBlock2D( +slider_label_anisotropy_direction_z = fury.ui.TextBlock2D( text="Anisotropy Direction Z", font_size=16 ) -slider_label_coat_strength = ui.TextBlock2D(text="Coat Strength", font_size=16) -slider_label_coat_roughness = ui.TextBlock2D(text="Coat Roughness", font_size=16) -slider_label_base_ior = ui.TextBlock2D(text="Base IoR", font_size=16) -slider_label_coat_ior = ui.TextBlock2D(text="Coat IoR", font_size=16) +slider_label_coat_strength = fury.ui.TextBlock2D(text="Coat Strength", font_size=16) +slider_label_coat_roughness = fury.ui.TextBlock2D(text="Coat Roughness", font_size=16) +slider_label_base_ior = fury.ui.TextBlock2D(text="Base IoR", font_size=16) +slider_label_coat_ior = fury.ui.TextBlock2D(text="Coat IoR", font_size=16) control_panel.add_element(slider_label_metallic, (0.01, 0.95)) control_panel.add_element(slider_label_roughness, (0.01, 0.86)) @@ -208,37 +201,37 @@ def win_callback(obj, event): ############################################################################### # Our sliders are created and added to the panel in the following way. -slider_slice_metallic = ui.LineSlider2D( +slider_slice_metallic = fury.ui.LineSlider2D( initial_value=pbr_params.metallic, max_value=1, length=195, text_template="{value:.1f}", ) -slider_slice_roughness = ui.LineSlider2D( +slider_slice_roughness = fury.ui.LineSlider2D( initial_value=pbr_params.roughness, max_value=1, length=195, text_template="{value:.1f}", ) -slider_slice_anisotropy = ui.LineSlider2D( +slider_slice_anisotropy = fury.ui.LineSlider2D( initial_value=pbr_params.anisotropy, max_value=1, length=195, text_template="{value:.1f}", ) -slider_slice_anisotropy_rotation = ui.LineSlider2D( +slider_slice_anisotropy_rotation = fury.ui.LineSlider2D( initial_value=pbr_params.anisotropy_rotation, max_value=1, length=195, text_template="{value:.1f}", ) -slider_slice_coat_strength = ui.LineSlider2D( +slider_slice_coat_strength = fury.ui.LineSlider2D( initial_value=pbr_params.coat_strength, max_value=1, length=195, text_template="{value:.1f}", ) -slider_slice_coat_roughness = ui.LineSlider2D( +slider_slice_coat_roughness = fury.ui.LineSlider2D( initial_value=pbr_params.coat_roughness, max_value=1, length=195, @@ -250,21 +243,21 @@ def win_callback(obj, event): # within that range we cover all the possible 3D directions needed to align the # tangents. -slider_slice_anisotropy_direction_x = ui.LineSlider2D( +slider_slice_anisotropy_direction_x = fury.ui.LineSlider2D( initial_value=doa[0], min_value=-1, max_value=1, length=195, text_template="{value:.1f}", ) -slider_slice_anisotropy_direction_y = ui.LineSlider2D( +slider_slice_anisotropy_direction_y = fury.ui.LineSlider2D( initial_value=doa[1], min_value=-1, max_value=1, length=195, text_template="{value:.1f}", ) -slider_slice_anisotropy_direction_z = ui.LineSlider2D( +slider_slice_anisotropy_direction_z = fury.ui.LineSlider2D( initial_value=doa[2], min_value=-1, max_value=1, @@ -277,14 +270,14 @@ def win_callback(obj, event): # cases, the values are defined in the range [1, 2.3] according to the # documentation of the material. -slider_slice_base_ior = ui.LineSlider2D( +slider_slice_base_ior = fury.ui.LineSlider2D( initial_value=pbr_params.base_ior, min_value=1, max_value=2.3, length=195, text_template="{value:.02f}", ) -slider_slice_coat_ior = ui.LineSlider2D( +slider_slice_coat_ior = fury.ui.LineSlider2D( initial_value=pbr_params.coat_ior, min_value=1, max_value=2.3, @@ -343,4 +336,4 @@ def win_callback(obj, event): if interactive: show_m.start() -window.record(scene, size=(1920, 1080), out_path="viz_pbr_interactive.png") +fury.window.record(scene, size=(1920, 1080), out_path="viz_pbr_interactive.png") diff --git a/docs/examples/viz_pbr_spheres.py b/docs/examples/viz_pbr_spheres.py index 318fcc51e..e0cfa6f59 100644 --- a/docs/examples/viz_pbr_spheres.py +++ b/docs/examples/viz_pbr_spheres.py @@ -17,17 +17,12 @@ import numpy as np -from fury import actor, material, window -from fury.utils import ( - normals_from_actor, - tangents_from_direction_of_anisotropy, - tangents_to_actor, -) +import fury ############################################################################### # Now set up a new scene. -scene = window.Scene() +scene = fury.window.Scene() scene.background((0.9, 0.9, 0.9)) ############################################################################### @@ -59,13 +54,15 @@ center = [[0, -5 * i, 0]] for j in range(num_values): center[0][0] = -25 + 5 * j - sphere = actor.sphere(center, color, radii=2, theta=32, phi=32) - normals = normals_from_actor(sphere) - tangents = tangents_from_direction_of_anisotropy(normals, (0, 1, 0.5)) - tangents_to_actor(sphere, tangents) + sphere = fury.actor.sphere(center, color, radii=2, theta=32, phi=32) + normals = fury.utils.normals_from_actor(sphere) + tangents = fury.utils.tangents_from_direction_of_anisotropy( + normals, (0, 1, 0.5) + ) + fury.utils.tangents_to_actor(sphere, tangents) keys = list(params) params[keys[0]] = np.round(0.1 * j, decimals=1) - material.manifest_pbr(sphere, **params) + fury.material.manifest_pbr(sphere, **params) scene.add(sphere) ############################################################################### @@ -83,12 +80,14 @@ for i, name in enumerate(labels): pos = [-40, -5 * i, 0] - label = actor.vector_text(name, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)) + label = fury.actor.vector_text( + name, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0) + ) scene.add(label) for j in range(num_values): pos = [-26 + 5 * j, 3, 0] - label = actor.vector_text( + label = fury.actor.vector_text( str(np.round(j * 0.1, decimals=1)), pos=pos, scale=(0.8, 0.8, 0.8), @@ -123,10 +122,10 @@ center = [[0, -35 - (5 * i), 0]] for j in range(num_values): center[0][0] = -25 + 5 * j - sphere = actor.sphere(center, color, radii=2, theta=32, phi=32) + sphere = fury.actor.sphere(center, color, radii=2, theta=32, phi=32) keys = list(params) params[keys[0]] = iors[j] - material.manifest_pbr(sphere, **params) + fury.material.manifest_pbr(sphere, **params) scene.add(sphere) ############################################################################### @@ -136,12 +135,14 @@ for i, name in enumerate(labels): pos = [-40, -35 - (5 * i), 0] - label = actor.vector_text(name, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)) + label = fury.actor.vector_text( + name, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0) + ) scene.add(label) for j in range(num_values): pos = [-26 + 5 * j, -32, 0] - label = actor.vector_text( + label = fury.actor.vector_text( "{:.02f}".format(iors[j]), pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0) ) scene.add(label) @@ -151,6 +152,6 @@ interactive = False if interactive: - window.show(scene) + fury.window.show(scene) -window.record(scene, size=(600, 600), out_path="viz_pbr_spheres.png") +fury.window.record(scene, size=(600, 600), out_path="viz_pbr_spheres.png") diff --git a/docs/examples/viz_picking.py b/docs/examples/viz_picking.py index 772ca79d5..954cc9d5a 100644 --- a/docs/examples/viz_picking.py +++ b/docs/examples/viz_picking.py @@ -13,7 +13,7 @@ import numpy as np -from fury import actor, pick, ui, utils, window +import fury centers = 0.5 * np.array([[0, 0, 0], [100, 0, 0], [200, 0, 0.0]]) colors = np.array([[0.8, 0, 0], [0, 0.8, 0], [0, 0, 0.8]]) @@ -24,18 +24,18 @@ ############################################################################### # Let's create a panel to show what is picked -panel = ui.Panel2D(size=(400, 200), color=(1, 0.5, 0.0), align="right") +panel = fury.ui.Panel2D(size=(400, 200), color=(1, 0.5, 0.0), align="right") panel.center = (150, 200) -text_block = ui.TextBlock2D(text="Left click on object \n") +text_block = fury.ui.TextBlock2D(text="Left click on object \n") panel.add_element(text_block, (0.3, 0.3)) ############################################################################### # Build scene and add an actor with many objects. -scene = window.Scene() +scene = fury.window.Scene() -label_actor = actor.vector_text(text="Test") +label_actor = fury.actor.vector_text(text="Test") ############################################################################### # This actor is made with 3 cubes of different orientation @@ -47,23 +47,23 @@ [0, np.sqrt(2) / 2, np.sqrt(2) / 2], ] ) -fury_actor = actor.cube(centers, directions, colors, scales=radii) +fury_actor = fury.actor.cube(centers, directions, colors, scales=radii) ############################################################################### # Access the memory of the vertices of all the cubes -vertices = utils.vertices_from_actor(fury_actor) +vertices = fury.utils.vertices_from_actor(fury_actor) num_vertices = vertices.shape[0] num_objects = centers.shape[0] ############################################################################### # Access the memory of the colors of all the cubes -vcolors = utils.colors_from_actor(fury_actor, "colors") +vcolors = fury.utils.colors_from_actor(fury_actor, "colors") ############################################################################### # Adding an actor showing the axes of the world coordinates -ax = actor.axes(scale=(10, 10, 10)) +ax = fury.actor.axes(scale=(10, 10, 10)) scene.add(fury_actor) scene.add(label_actor) @@ -73,7 +73,7 @@ ############################################################################### # Create the Picking manager -pickm = pick.PickingManager() +pickm = fury.pick.PickingManager() ############################################################################### # Time to make the callback which will be called when we pick an object @@ -117,7 +117,7 @@ def left_click_callback(obj, event): vcolors[object_index * sec : object_index * sec + sec] += color_add # Tell actor that memory is modified - utils.update_actor(fury_actor) + fury.utils.update_actor(fury_actor) face_index = picked_info["face"] @@ -139,7 +139,7 @@ def left_click_callback(obj, event): ############################################################################### # Make the window appear -showm = window.ShowManager(scene, size=(1024, 768), order_transparent=True) +showm = fury.window.ShowManager(scene, size=(1024, 768), order_transparent=True) scene.add(panel) @@ -155,4 +155,4 @@ def left_click_callback(obj, event): ############################################################################### # Save the current framebuffer in a PNG file -window.record(showm.scene, size=(1024, 768), out_path="viz_picking.png") +fury.window.record(showm.scene, size=(1024, 768), out_path="viz_picking.png") diff --git a/docs/examples/viz_play_video.py b/docs/examples/viz_play_video.py index 920d2b1a7..dde63d78d 100644 --- a/docs/examples/viz_play_video.py +++ b/docs/examples/viz_play_video.py @@ -12,7 +12,7 @@ import cv2 import numpy as np -from fury import actor, window +import fury # The VideoCapturer Class @@ -48,16 +48,16 @@ def __init__(self, video, time=10): # Initialize Scene self.initialize_scene() # Create a Show Manager and Initialize it - self.show_manager = window.ShowManager( + self.show_manager = fury.window.ShowManager( self.scene, size=(900, 768), reset_camera=False, order_transparent=True ) # Initialize the Scene with actors def initialize_scene(self): - self.scene = window.Scene() + self.scene = fury.window.Scene() # Initialize a Plane actor with the 1st video frame along with # the actor grid which is to be updated in each iteration - self.plane_actor = actor.texture(self.current_video_frame) + self.plane_actor = fury.actor.texture(self.current_video_frame) self.scene.add(self.plane_actor) # The timer_callback function getting called by the show manager @@ -66,7 +66,7 @@ def timer_callback(self, _obj, _event): if isinstance(self.current_video_frame, np.ndarray): # update texture of the actor with the current frame image # by updating the actor grid - actor.texture_update(self.plane_actor, self.current_video_frame) + fury.actor.texture_update(self.plane_actor, self.current_video_frame) self.show_manager.scene.azimuth(1.5) # to rotate the camera else: self.show_manager.exit() @@ -90,4 +90,6 @@ def run(self): ) vp = VideoPlayer(video_url) vp.run() -window.record(vp.show_manager.scene, out_path="viz_play_video.png", size=(600, 600)) +fury.window.record( + vp.show_manager.scene, out_path="viz_play_video.png", size=(600, 600) +) diff --git a/docs/examples/viz_principled_spheres.py b/docs/examples/viz_principled_spheres.py index 018672433..82ded4337 100644 --- a/docs/examples/viz_principled_spheres.py +++ b/docs/examples/viz_principled_spheres.py @@ -21,12 +21,12 @@ import numpy as np -from fury import actor, material, window +import fury ############################################################################### # Now set up a new scene. -scene = window.Scene() +scene = fury.window.Scene() scene.background((0.9, 0.9, 0.9)) ############################################################################### @@ -56,12 +56,12 @@ center = np.array([[0, -5 * i, 0]]) for j in range(11): center[0][0] = -25 + 5 * j - sphere = actor.sphere( + sphere = fury.actor.sphere( center, colors=material_params[i][0], radii=2, theta=32, phi=32 ) keys = list(material_params[i][1]) material_params[i][1][keys[0]] = np.round(0.1 * j, decimals=1) - material.manifest_principled(sphere, **material_params[i][1]) + fury.material.manifest_principled(sphere, **material_params[i][1]) scene.add(sphere) ############################################################################### @@ -82,14 +82,14 @@ for i in range(10): pos = [-40, -5 * i, 0] - label = actor.vector_text( + label = fury.actor.vector_text( labels[i], pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0) ) scene.add(label) for j in range(11): pos = [-26 + 5 * j, 5, 0] - label = actor.vector_text( + label = fury.actor.vector_text( str(np.round(j * 0.1, decimals=1)), pos=pos, scale=(0.8, 0.8, 0.8), @@ -102,6 +102,6 @@ interactive = False if interactive: - window.show(scene) + fury.window.show(scene) -window.record(scene, size=(600, 600), out_path="viz_principled_spheres.png") +fury.window.record(scene, size=(600, 600), out_path="viz_principled_spheres.png") diff --git a/docs/examples/viz_radio_buttons.py b/docs/examples/viz_radio_buttons.py index 71dd1c6fe..e10e5f376 100644 --- a/docs/examples/viz_radio_buttons.py +++ b/docs/examples/viz_radio_buttons.py @@ -11,13 +11,12 @@ import numpy as np -from fury import actor, ui, utils, window -from fury.data import fetch_viz_icons +import fury ############################################################################## # First we need to fetch some icons that are included in FURY. -fetch_viz_icons() +fury.data.fetch_viz_icons() ######################################################################## # Sphere and Radio Buttons @@ -25,7 +24,7 @@ # # Add a Sphere to the scene. -sphere = actor.sphere( +sphere = fury.actor.sphere( centers=np.array([[50, 0, 0]]), colors=np.array([[0, 0, 1]]), radii=11.0, @@ -36,7 +35,7 @@ # Creating a dict of possible options and mapping it with their values. options = {"Blue": (0, 0, 255), "Red": (255, 0, 0), "Green": (0, 255, 0)} -color_toggler = ui.RadioButton( +color_toggler = fury.ui.RadioButton( list(options), checked_labels=["Blue"], padding=1, @@ -48,10 +47,10 @@ # A callback which will set the values for the box def toggle_color(radio): - vcolors = utils.colors_from_actor(sphere) + vcolors = fury.utils.colors_from_actor(sphere) color = options[radio.checked_labels[0]] vcolors[:] = np.array(color) - utils.update_actor(sphere) + fury.utils.update_actor(sphere) color_toggler.on_change = toggle_color @@ -65,7 +64,7 @@ def toggle_color(radio): # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title="FURY Sphere Example") +show_manager = fury.window.ShowManager(size=current_size, title="FURY Sphere Example") show_manager.scene.add(sphere) show_manager.scene.add(color_toggler) @@ -82,4 +81,6 @@ def toggle_color(radio): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path="viz_radio_buttons.png") +fury.window.record( + show_manager.scene, size=current_size, out_path="viz_radio_buttons.png" +) diff --git a/docs/examples/viz_robot_arm_animation.py b/docs/examples/viz_robot_arm_animation.py index 1e9485d02..b35fd105c 100644 --- a/docs/examples/viz_robot_arm_animation.py +++ b/docs/examples/viz_robot_arm_animation.py @@ -8,13 +8,11 @@ import numpy as np -from fury import actor, window -from fury.animation import Animation, Timeline -from fury.utils import set_actor_origin +import fury -scene = window.Scene() +scene = fury.window.Scene() -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) showm.initialize() @@ -23,16 +21,20 @@ ############################################################################### # Creating robot arm components -base = actor.cylinder( +base = fury.actor.cylinder( np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), colors=(0, 1, 0), radius=1 ) -main_arm = actor.box(np.array([[0, 0, 0]]), colors=(1, 0.5, 0), scales=(12, 1, 1)) +main_arm = fury.actor.box(np.array([[0, 0, 0]]), colors=(1, 0.5, 0), scales=(12, 1, 1)) -sub_arm = actor.box(np.array([[0, 0, 0]]), colors=(0, 0.5, 0.8), scales=(8, 0.7, 0.7)) -joint_1 = actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1]), radii=1.2) -joint_2 = actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1])) +sub_arm = fury.actor.box( + np.array([[0, 0, 0]]), colors=(0, 0.5, 0.8), scales=(8, 0.7, 0.7) +) +joint_1 = fury.actor.sphere( + np.array([[0, 0, 0]]), colors=np.array([1, 0, 1]), radii=1.2 +) +joint_2 = fury.actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1])) -end = actor.cone( +end = fury.actor.cone( np.array([[0, 0, 0]]), np.array([[1, 0, 0]]), np.array([[1, 0, 0]]), @@ -42,18 +44,18 @@ ############################################################################### # Setting the center of both shafts to the beginning. -set_actor_origin(main_arm, np.array([-6, 0, 0])) -set_actor_origin(sub_arm, np.array([-4, 0, 0])) +fury.utils.set_actor_origin(main_arm, np.array([-6, 0, 0])) +fury.utils.set_actor_origin(sub_arm, np.array([-4, 0, 0])) ############################################################################### # Creating a timeline -timeline = Timeline(playback_panel=True) +timeline = fury.animation.Timeline(playback_panel=True) ############################################################################### # Creating animations -main_arm_animation = Animation([main_arm, joint_1], length=2 * np.pi) -child_arm_animation = Animation([sub_arm, joint_2]) -drill_animation = Animation(end) +main_arm_animation = fury.animation.Animation([main_arm, joint_1], length=2 * np.pi) +child_arm_animation = fury.animation.Animation([sub_arm, joint_2]) +drill_animation = fury.animation.Animation(end) ############################################################################### @@ -119,4 +121,4 @@ def rot_drill(t): if interactive: showm.start() -window.record(scene, out_path="viz_robot_arm.png", size=(900, 768)) +fury.window.record(scene, out_path="viz_robot_arm.png", size=(900, 768)) diff --git a/docs/examples/viz_roi_contour.py b/docs/examples/viz_roi_contour.py index 17590a3df..1a8b07806 100644 --- a/docs/examples/viz_roi_contour.py +++ b/docs/examples/viz_roi_contour.py @@ -24,8 +24,7 @@ from dipy.tracking import utils from dipy.tracking.streamline import Streamlines -from fury import actor, window -from fury.colormap import line_colors +import fury ############################################################################### # First, we need to generate some streamlines. For a more complete @@ -39,7 +38,7 @@ white_matter = (labels == 1) | (labels == 2) -csa_model = CsaOdfModel(gtab, sh_order=6) +csa_model = CsaOdfModel(gtab, sh_order_max=6) csa_peaks = peaks_from_model( csa_model, data, @@ -63,7 +62,7 @@ ############################################################################### # We will create a streamline actor from the streamlines. -streamlines_actor = actor.line(streamlines, line_colors(streamlines)) +streamlines_actor = fury.actor.line(streamlines, fury.colormap.line_colors(streamlines)) ############################################################################### # Next, we create a surface actor from the corpus callosum seed ROI. We @@ -74,7 +73,7 @@ surface_opacity = 0.5 surface_color = [0, 1, 1] -seedroi_actor = actor.contour_from_roi( +seedroi_actor = fury.actor.contour_from_roi( seed_mask, affine, surface_color, surface_opacity ) @@ -82,7 +81,7 @@ # Next, we initialize a ''Scene'' object and add both actors # to the rendering. -scene = window.Scene() +scene = fury.window.Scene() scene.add(streamlines_actor) scene.add(seedroi_actor) @@ -92,9 +91,9 @@ interactive = False if interactive: - window.show(scene) + fury.window.show(scene) # scene.zoom(1.5) # scene.reset_clipping_range() -window.record(scene, out_path="contour_from_roi_tutorial.png", size=(600, 600)) +fury.window.record(scene, out_path="contour_from_roi_tutorial.png", size=(600, 600)) diff --git a/docs/examples/viz_sdf_cylinder.py b/docs/examples/viz_sdf_cylinder.py index bebeb4f30..e501237bd 100644 --- a/docs/examples/viz_sdf_cylinder.py +++ b/docs/examples/viz_sdf_cylinder.py @@ -19,13 +19,7 @@ import numpy as np -from fury import actor, window -from fury.shaders import ( - attribute_to_actor, - compose_shader, - import_fury_shader, - shader_to_actor, -) +import fury ############################################################################### # Cylinder using polygons @@ -87,7 +81,7 @@ # of sides used to define the bases of the cylinder) to see how it changes the # surface of the primitive. -cylinders_8 = actor.cylinder( +cylinders_8 = fury.actor.cylinder( centers[:3], dirs[:3], colors[:3], @@ -96,7 +90,7 @@ capped=True, resolution=8, ) -cylinders_16 = actor.cylinder( +cylinders_16 = fury.actor.cylinder( centers[3:6], dirs[3:6], colors[3:6], @@ -105,7 +99,7 @@ capped=True, resolution=16, ) -cylinders_32 = actor.cylinder( +cylinders_32 = fury.actor.cylinder( centers[6:9], dirs[6:9], colors[6:9], @@ -118,7 +112,7 @@ ############################################################################### # Next, we set up a new scene to add and visualize the actors created. -scene = window.Scene() +scene = fury.window.Scene() scene.add(cylinders_8) scene.add(cylinders_16) @@ -127,9 +121,9 @@ interactive = False if interactive: - window.show(scene) + fury.window.show(scene) -window.record(scene, size=(600, 600), out_path="viz_poly_cylinder.png") +fury.window.record(scene, size=(600, 600), out_path="viz_poly_cylinder.png") ############################################################################### # Visualize the surface geometry representation for the object. @@ -139,9 +133,9 @@ cylinders_32.GetProperty().SetRepresentationToWireframe() if interactive: - window.show(scene) + fury.window.show(scene) -window.record(scene, size=(600, 600), out_path="viz_poly_cylinder_geom.png") +fury.window.record(scene, size=(600, 600), out_path="viz_poly_cylinder_geom.png") ############################################################################### # Then we clean the scene to render the boxes we will use to render our @@ -167,7 +161,7 @@ # Now we create cylinders using box actor and SDF implementation on shaders. # For this, we first create a box actor. -box_actor = actor.box( +box_actor = fury.actor.box( centers=centers, directions=dirs, colors=colors, @@ -187,10 +181,10 @@ rep_radii = np.repeat(np.repeat(radius, 9), 8, axis=0) rep_heights = np.repeat(np.repeat(height, 9), 8, axis=0) -attribute_to_actor(box_actor, rep_centers, "center") -attribute_to_actor(box_actor, rep_directions, "direction") -attribute_to_actor(box_actor, rep_radii, "radius") -attribute_to_actor(box_actor, rep_heights, "height") +fury.shaders.attribute_to_actor(box_actor, rep_centers, "center") +fury.shaders.attribute_to_actor(box_actor, rep_directions, "direction") +fury.shaders.attribute_to_actor(box_actor, rep_radii, "radius") +fury.shaders.attribute_to_actor(box_actor, rep_heights, "height") ############################################################################### # Then we have the shader code implementation corresponding to vertex and @@ -225,7 +219,7 @@ # to apply our implementation to the shader creation process, this function # joins our code to the shader template that FURY has by default. -shader_to_actor(box_actor, "vertex", decl_code=vs_dec, impl_code=vs_impl) +fury.shaders.shader_to_actor(box_actor, "vertex", decl_code=vs_dec, impl_code=vs_impl) ############################################################################### # Fragment shaders are used to define the colors of each pixel being processed, @@ -252,14 +246,14 @@ # to transform our position vectors in order to align the direction of # cylinder with respect to the box. -vec_to_vec_rot_mat = import_fury_shader( +vec_to_vec_rot_mat = fury.shaders.import_fury_shader( os.path.join("utils", "vec_to_vec_rot_mat.glsl") ) ############################################################################### # We calculate the distance using the SDF function for the cylinder. -sd_cylinder = import_fury_shader(os.path.join("sdf", "sd_cylinder.frag")) +sd_cylinder = fury.shaders.import_fury_shader(os.path.join("sdf", "sd_cylinder.frag")) ############################################################################### # This is used on calculations for surface normals of the cylinder. @@ -283,24 +277,28 @@ ############################################################################### # We use central differences technique for computing surface normals. -central_diffs_normal = import_fury_shader(os.path.join("sdf", "central_diffs.frag")) +central_diffs_normal = fury.shaders.import_fury_shader( + os.path.join("sdf", "central_diffs.frag") +) ############################################################################### # We use cast_ray for the implementation of Ray Marching. -cast_ray = import_fury_shader(os.path.join("ray_marching", "cast_ray.frag")) +cast_ray = fury.shaders.import_fury_shader( + os.path.join("ray_marching", "cast_ray.frag") +) ############################################################################### # For the illumination of the scene we use the Blinn-Phong model. -blinn_phong_model = import_fury_shader( +blinn_phong_model = fury.shaders.import_fury_shader( os.path.join("lighting", "blinn_phong_model.frag") ) ############################################################################### # Now we use compose_shader to join our pieces of GLSL shader code. -fs_dec = compose_shader( +fs_dec = fury.shaders.compose_shader( [ fs_vars_dec, vec_to_vec_rot_mat, @@ -312,7 +310,7 @@ ] ) -shader_to_actor(box_actor, "fragment", decl_code=fs_dec) +fury.shaders.shader_to_actor(box_actor, "fragment", decl_code=fs_dec) ############################################################################### # Here we have the implementation of all the previous code with all the @@ -350,7 +348,9 @@ } """ -shader_to_actor(box_actor, "fragment", impl_code=sdf_cylinder_frag_impl, block="light") +fury.shaders.shader_to_actor( + box_actor, "fragment", impl_code=sdf_cylinder_frag_impl, block="light" +) ############################################################################### # Finally, we visualize the cylinders made using ray marching and SDFs. @@ -358,9 +358,9 @@ scene.add(box_actor) if interactive: - window.show(scene) + fury.window.show(scene) -window.record(scene, size=(600, 600), out_path="viz_sdf_cylinder.png") +fury.window.record(scene, size=(600, 600), out_path="viz_sdf_cylinder.png") ############################################################################### # References @@ -369,4 +369,3 @@ # antialiased ray tracing of implicit surfaces." The Visual # Computer 12.10 (1996): 527-545. # -# .. include:: ../links_names.inc diff --git a/docs/examples/viz_sdfactor.py b/docs/examples/viz_sdfactor.py index 1223d38aa..7d99356dc 100644 --- a/docs/examples/viz_sdfactor.py +++ b/docs/examples/viz_sdfactor.py @@ -16,7 +16,7 @@ import numpy as np -from fury import actor, window +import fury ############################################################################### # Lets define variables for the SDF Actor @@ -30,7 +30,7 @@ ############################################################################### # Create SDF Actor -sdfactor = actor.sdf( +sdfactor = fury.actor.sdf( centers=centers, directions=dirs, colors=colors, @@ -41,7 +41,7 @@ ############################################################################## # Create a scene -scene = window.Scene() +scene = fury.window.Scene() scene.background((1.0, 0.8, 0.8)) scene.add(sdfactor) @@ -53,11 +53,11 @@ # manager. current_size = (1024, 720) -showm = window.ShowManager(scene, size=current_size, title="Visualize SDF Actor") +showm = fury.window.ShowManager(scene, size=current_size, title="Visualize SDF Actor") interactive = False if interactive: showm.start() -window.record(scene, out_path="viz_sdfactor.png", size=current_size) +fury.window.record(scene, out_path="viz_sdfactor.png", size=current_size) diff --git a/docs/examples/viz_selection.py b/docs/examples/viz_selection.py index 6c0a4c485..58b71ebca 100644 --- a/docs/examples/viz_selection.py +++ b/docs/examples/viz_selection.py @@ -22,7 +22,7 @@ import numpy as np -from fury import actor, pick, utils, window +import fury ############################################################################### # Adding many cubes of different sizes and colors @@ -44,31 +44,31 @@ ############################################################################### # Build scene and add an actor with many objects. -scene = window.Scene() +scene = fury.window.Scene() ############################################################################### # Build the actor containing all the cubes -cube_actor = actor.cube(centers, directions=(1, 0, 0), colors=colors, scales=radii) +cube_actor = fury.actor.cube(centers, directions=(1, 0, 0), colors=colors, scales=radii) ############################################################################### # Access the memory of the vertices of all the cubes -vertices = utils.vertices_from_actor(cube_actor) +vertices = fury.utils.vertices_from_actor(cube_actor) num_vertices = vertices.shape[0] num_objects = centers.shape[0] ############################################################################### # Access the memory of the colors of all the cubes -vcolors = utils.colors_from_actor(cube_actor, "colors") +vcolors = fury.utils.colors_from_actor(cube_actor, "colors") ############################################################################### # Create a rectangular 2d box as a texture rgba = 255 * np.ones((100, 200, 4)) rgba[1:-1, 1:-1] = np.zeros((98, 198, 4)) + 100 -texa = actor.texture_2d(rgba.astype(np.uint8)) +texa = fury.actor.texture_2d(rgba.astype(np.uint8)) scene.add(cube_actor) scene.add(texa) @@ -78,7 +78,7 @@ ############################################################################### # Create the Selection Manager -selm = pick.SelectionManager(select="faces") +selm = fury.pick.SelectionManager(select="faces") ############################################################################### # Tell Selection Manager to avoid selecting specific actors @@ -109,14 +109,14 @@ def hover_callback(_obj, _event): vcolors[object_index * sec : object_index * sec + sec] = ( color_change ) - utils.update_actor(cube_actor) + fury.utils.update_actor(cube_actor) showm.render() ############################################################################### # Make the window appear -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(1024, 768), order_transparent=True, reset_camera=False ) @@ -138,4 +138,4 @@ def hover_callback(_obj, _event): ############################################################################### # Save the current framebuffer in a PNG file -window.record(showm.scene, size=(1024, 768), out_path="viz_selection.png") +fury.window.record(showm.scene, size=(1024, 768), out_path="viz_selection.png") diff --git a/docs/examples/viz_shader.py b/docs/examples/viz_shader.py index 19b1a36ba..479b42289 100644 --- a/docs/examples/viz_shader.py +++ b/docs/examples/viz_shader.py @@ -7,19 +7,17 @@ This example shows how to use shaders to generate a shaded output. We will demonstrate how to load polydata then use a custom shader calls to render a custom shaded model. -First, a bunch of imports. +First, let's import FURY """ -from fury import io, ui, utils, window -from fury.data.fetcher import fetch_viz_models, read_viz_models -from fury.shaders import add_shader_callback, shader_to_actor +import fury ############################################################################### # Let's download and load the model -fetch_viz_models() -model = read_viz_models("utah.obj") +fury.data.fetch_viz_models() +model = fury.data.read_viz_models("utah.obj") ############################################################################### @@ -28,9 +26,9 @@ # For this example we use the standard utah teapot model. # currently supported formats include OBJ, VTK, FIB, PLY, STL and XML -utah = io.load_polydata(model) -utah = utils.get_polymapper_from_polydata(utah) -utah = utils.get_actor_from_polymapper(utah) +utah = fury.io.load_polydata(model) +utah = fury.utils.get_polymapper_from_polydata(utah) +utah = fury.utils.get_actor_from_polymapper(utah) mapper = utah.GetMapper() @@ -58,16 +56,18 @@ fragOutput0 = vec4(col, fragOutput0.a); """ -shader_to_actor( +fury.shaders.shader_to_actor( utah, "vertex", impl_code=vertex_shader_code_impl, decl_code=vertex_shader_code_decl ) -shader_to_actor(utah, "fragment", decl_code=fragment_shader_code_decl) -shader_to_actor(utah, "fragment", impl_code=fragment_shader_code_impl, block="light") +fury.shaders.shader_to_actor(utah, "fragment", decl_code=fragment_shader_code_decl) +fury.shaders.shader_to_actor( + utah, "fragment", impl_code=fragment_shader_code_impl, block="light" +) ############################################################################### # Let's create a scene. -scene = window.Scene() +scene = fury.window.Scene() global timer timer = 0 @@ -98,11 +98,11 @@ def shader_callback(_caller, _event, calldata=None): pass -add_shader_callback(utah, shader_callback) +fury.shaders.add_shader_callback(utah, shader_callback) ############################################################################### # Let's add a textblock to the scene with a custom message -tb = ui.TextBlock2D() +tb = fury.ui.TextBlock2D() tb.message = "Hello Shaders" ############################################################################### @@ -112,7 +112,7 @@ def shader_callback(_caller, _event, calldata=None): # manager. current_size = (1024, 720) -showm = window.ShowManager(scene, size=current_size, reset_camera=False) +showm = fury.window.ShowManager(scene, size=current_size, reset_camera=False) showm.add_timer_callback(True, 30, timer_callback) @@ -124,4 +124,4 @@ def shader_callback(_caller, _event, calldata=None): if interactive: showm.start() -window.record(showm.scene, size=current_size, out_path="viz_shader.png") +fury.window.record(showm.scene, size=current_size, out_path="viz_shader.png") diff --git a/docs/examples/viz_shapes.py b/docs/examples/viz_shapes.py index e7e64361c..33a88ec80 100644 --- a/docs/examples/viz_shapes.py +++ b/docs/examples/viz_shapes.py @@ -10,28 +10,29 @@ First, a bunch of imports. """ -from fury import ui, window -from fury.data import fetch_viz_icons +import fury ############################################################################## # First we need to fetch some icons that are included in FURY. -fetch_viz_icons() +fury.data.fetch_viz_icons() ############################################################################### # Let's draw some simple shapes. First, a rectangle. -rect = ui.Rectangle2D(size=(100, 100), position=(400, 400), color=(1, 0, 1)) +rect = fury.ui.Rectangle2D(size=(100, 100), position=(400, 400), color=(1, 0, 1)) ############################################################################### # Then we can draw a solid circle, or disk. -disk = ui.Disk2D(outer_radius=50, center=(400, 200), color=(1, 1, 0)) +disk = fury.ui.Disk2D(outer_radius=50, center=(400, 200), color=(1, 1, 0)) ############################################################################### # Add an inner radius to make a ring. -ring = ui.Disk2D(outer_radius=50, inner_radius=45, center=(500, 600), color=(0, 1, 1)) +ring = fury.ui.Disk2D( + outer_radius=50, inner_radius=45, center=(500, 600), color=(0, 1, 1) +) ############################################################################### @@ -39,7 +40,7 @@ # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title="FURY Shapes Example") +show_manager = fury.window.ShowManager(size=current_size, title="FURY Shapes Example") show_manager.scene.add(rect) show_manager.scene.add(disk) @@ -50,4 +51,4 @@ if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path="viz_shapes.png") +fury.window.record(show_manager.scene, size=current_size, out_path="viz_shapes.png") diff --git a/docs/examples/viz_skinning.py b/docs/examples/viz_skinning.py index 0657e0b1d..010fbbf1b 100644 --- a/docs/examples/viz_skinning.py +++ b/docs/examples/viz_skinning.py @@ -6,22 +6,20 @@ glTF model in FURY. """ -from fury import window -from fury.data import fetch_gltf, read_viz_gltf -from fury.gltf import glTF +import fury ############################################################################## # Retrieving the model with skeletal animations. # We're choosing the `RiggedFigure` model here. -fetch_gltf("RiggedFigure", "glTF") -filename = read_viz_gltf("RiggedFigure") +fury.data.fetch_gltf("RiggedFigure", "glTF") +filename = fury.data.read_viz_gltf("RiggedFigure") ############################################################################## # Initializing the glTF object, You can additionally set `apply_normals=True`. # Note: Normals might not work well as intended with skinning animations. -gltf_obj = glTF(filename, apply_normals=False) +gltf_obj = fury.gltf.glTF(filename, apply_normals=False) ############################################################################## # Get the skinning timeline using `skin_timeline` method, Choose the animation @@ -43,8 +41,8 @@ # Initialize the show manager and add timeline to the scene (No need to add # actors to the scene separately). -scene = window.Scene() -showm = window.ShowManager( +scene = fury.window.Scene() +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=True, order_transparent=True ) showm.initialize() @@ -73,4 +71,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, out_path="viz_skinning.png", size=(900, 768)) +fury.window.record(scene, out_path="viz_skinning.png", size=(900, 768)) diff --git a/docs/examples/viz_slice.py b/docs/examples/viz_slice.py index 0a8c01303..e198b5aca 100644 --- a/docs/examples/viz_slice.py +++ b/docs/examples/viz_slice.py @@ -11,7 +11,7 @@ from dipy.data import fetch_bundles_2_subjects import nibabel as nib -from fury import actor, ui, window +import fury ############################################################################### # Let's download and load a T1. @@ -35,7 +35,7 @@ ############################################################################### # Create a Scene object which holds all the actors which we want to visualize. -scene = window.Scene() +scene = fury.window.Scene() scene.background((0.5, 0.5, 0.5)) ############################################################################### @@ -53,7 +53,7 @@ # transformation matrix. The default behavior of this function is to show the # middle slice of the last dimension of the resampled data. -slice_actor = actor.slicer(data, affine, value_range) +slice_actor = fury.actor.slicer(data, affine, value_range) ############################################################################### # The ``slice_actor`` contains an axial slice. @@ -81,12 +81,12 @@ ############################################################################### # In order to interact with the data you will need to uncomment the line below. -# window.show(scene, size=(600, 600), reset_camera=False) +# fury.window.show(scene, size=(600, 600), reset_camera=False) ############################################################################### # Otherwise, you can save a screenshot using the following command. -window.record(scene, out_path="slices.png", size=(600, 600), reset_camera=False) +fury.window.record(scene, out_path="slices.png", size=(600, 600), reset_camera=False) ############################################################################### # Render slices from FA with your colormap @@ -111,7 +111,7 @@ ############################################################################### # Notice here how the scale range is. We use FA min and max values to set it up -lut = actor.colormap_lookup_table( +lut = fury.actor.colormap_lookup_table( scale_range=(fa.min(), fa.max()), hue_range=(0.4, 1.0), saturation_range=(1, 1.0), @@ -122,7 +122,7 @@ # This is because the lookup table is applied in the slice after interpolating # to (0, 255). -fa_actor = actor.slicer(fa, affine, lookup_colormap=lut) +fa_actor = fury.actor.slicer(fa, affine, lookup_colormap=lut) scene.clear() scene.add(fa_actor) @@ -130,9 +130,11 @@ scene.reset_camera() scene.zoom(1.4) -# window.show(scene, size=(600, 600), reset_camera=False) +# fury.window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="slices_lut.png", size=(600, 600), reset_camera=False) +fury.window.record( + scene, out_path="slices_lut.png", size=(600, 600), reset_camera=False +) ############################################################################### # Now we would like to add the ability to click on a voxel and show its value @@ -142,19 +144,19 @@ # the ``ShowManager`` object, which allows accessing the pipeline in different # areas. -show_m = window.ShowManager(scene, size=(1200, 900)) +show_m = fury.window.ShowManager(scene, size=(1200, 900)) ############################################################################### # We'll start by creating the panel and adding it to the ``ShowManager`` -label_position = ui.TextBlock2D(text="Position:") -label_value = ui.TextBlock2D(text="Value:") +label_position = fury.ui.TextBlock2D(text="Position:") +label_value = fury.ui.TextBlock2D(text="Value:") -result_position = ui.TextBlock2D(text="") -result_value = ui.TextBlock2D(text="") +result_position = fury.ui.TextBlock2D(text="") +result_value = fury.ui.TextBlock2D(text="") -panel_picking = ui.Panel2D( +panel_picking = fury.ui.Panel2D( size=(250, 125), position=(20, 20), color=(0, 0, 0), opacity=0.75, align="left" ) @@ -203,7 +205,7 @@ def left_click_callback(obj, _ev): result_position.message = "" result_value.message = "" -show_m_mosaic = window.ShowManager(scene, size=(1200, 900)) +show_m_mosaic = fury.window.ShowManager(scene, size=(1200, 900)) def left_click_callback_mosaic(obj, _ev): @@ -260,4 +262,4 @@ def left_click_callback_mosaic(obj, _ev): # zoom in/out using the scroll wheel, and pick voxels with left click. -window.record(scene, out_path="mosaic.png", size=(900, 600), reset_camera=False) +fury.window.record(scene, out_path="mosaic.png", size=(900, 600), reset_camera=False) diff --git a/docs/examples/viz_solar_system.py b/docs/examples/viz_solar_system.py index 2e60bb351..ffd495d0d 100644 --- a/docs/examples/viz_solar_system.py +++ b/docs/examples/viz_solar_system.py @@ -13,21 +13,24 @@ import numpy as np -from fury import actor, io, ui, utils, window -from fury.data import fetch_viz_textures, read_viz_icons, read_viz_textures +import fury ############################################################################## # Create a scene to start. -scene = window.Scene() +scene = fury.window.Scene() # Create a panel and the start/pause buttons -panel = ui.Panel2D(size=(300, 100), color=(1, 1, 1), align="right") +panel = fury.ui.Panel2D(size=(300, 100), color=(1, 1, 1), align="right") panel.center = (400, 50) -pause_button = ui.Button2D(icon_fnames=[("square", read_viz_icons(fname="pause2.png"))]) -start_button = ui.Button2D(icon_fnames=[("square", read_viz_icons(fname="play3.png"))]) +pause_button = fury.ui.Button2D( + icon_fnames=[("square", fury.data.read_viz_icons(fname="pause2.png"))] +) +start_button = fury.ui.Button2D( + icon_fnames=[("square", fury.data.read_viz_icons(fname="play3.png"))] +) # Add the buttons on the panel @@ -91,7 +94,7 @@ }, {"filename": "8k_sun.jpg", "position": 0, "earth_days": 27, "scale": (5, 5, 5)}, ] -fetch_viz_textures() +fury.data.fetch_viz_textures() ############################################################################## # To take advantage of the previously defined data structure we are going to @@ -114,12 +117,12 @@ def init_planet(planet_data): planet_actor: actor The corresponding sphere actor with texture applied. """ - planet_file = read_viz_textures(planet_data["filename"]) - planet_image = io.load_image(planet_file) - planet_actor = actor.texture_on_sphere(planet_image) + planet_file = fury.data.read_viz_textures(planet_data["filename"]) + planet_image = fury.io.load_image(planet_file) + planet_actor = fury.actor.texture_on_sphere(planet_image) planet_actor.SetPosition(planet_data["position"], 0, 0) if planet_data["filename"] != "8k_saturn_ring_alpha.png": - utils.rotate(planet_actor, (90, 1, 0, 0)) + fury.utils.rotate(planet_actor, (90, 1, 0, 0)) planet_actor.SetScale(planet_data["scale"]) scene.add(planet_actor) return planet_actor @@ -185,7 +188,7 @@ def get_orbital_position(radius, time): def rotate_axial(actor, time, radius): axis = (0, radius, 0) angle = 50 / time - utils.rotate(actor, (angle, axis[0], axis[1], axis[2])) + fury.utils.rotate(actor, (angle, axis[0], axis[1], axis[2])) return angle @@ -198,7 +201,7 @@ def rotate_axial(actor, time, radius): # Next, create a ShowManager object. The ShowManager class is the interface # between the scene, the window and the interactor. -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) scene.add(panel) @@ -277,7 +280,7 @@ def calculate_path(r_planet, c): # This is for orbit visualization. We are using line actor for orbits. # After creating an actor we add it to the scene. -orbit_actor = actor.line(planet_tracks, colors=(1, 1, 1), linewidth=0.1) +orbit_actor = fury.actor.line(planet_tracks, colors=(1, 1, 1), linewidth=0.1) scene.add(orbit_actor) ############################################################################## @@ -331,4 +334,6 @@ def pause_animation(i_ren, _obj, _button): showm.add_timer_callback(True, 10, timer_callback) showm.start() -window.record(showm.scene, size=(900, 768), out_path="viz_solar_system_animation.png") +fury.window.record( + showm.scene, size=(900, 768), out_path="viz_solar_system_animation.png" +) diff --git a/docs/examples/viz_sphere.py b/docs/examples/viz_sphere.py index 92df3c73c..f81aae96f 100644 --- a/docs/examples/viz_sphere.py +++ b/docs/examples/viz_sphere.py @@ -7,7 +7,7 @@ import numpy as np -from fury import actor, window +import fury ############################################################################ # First thing, you have to specify centers and colors of the sphere @@ -18,7 +18,7 @@ ############################################################################ # The below sphere actor is generated by repeating the sphere primitive. -prim_sphere_actor = actor.sphere(centers, colors=colors, radii=5) +prim_sphere_actor = fury.actor.sphere(centers, colors=colors, radii=5) ############################################################################ # This time, we're using vtkSphereSource to generate the sphere actor @@ -26,9 +26,9 @@ cen2 = np.add(centers, np.array([12, 0, 0])) cols2 = np.array([1, 0, 0]) -vtk_sphere_actor = actor.sphere(cen2, colors=cols2, radii=5, use_primitive=False) +vtk_sphere_actor = fury.actor.sphere(cen2, colors=cols2, radii=5, use_primitive=False) -scene = window.Scene() +scene = fury.window.Scene() ############################################################################ # Adding our sphere actors to scene. @@ -39,6 +39,6 @@ interactive = False if interactive: - window.show(scene, size=(600, 600)) + fury.window.show(scene, size=(600, 600)) -window.record(scene, out_path="viz_sphere.png", size=(600, 600)) +fury.window.record(scene, out_path="viz_sphere.png", size=(600, 600)) diff --git a/docs/examples/viz_spiky.py b/docs/examples/viz_spiky.py index 3ab10c87c..a8de7e3ca 100644 --- a/docs/examples/viz_spiky.py +++ b/docs/examples/viz_spiky.py @@ -9,7 +9,7 @@ import numpy as np -from fury import actor, primitive, utils, window +import fury ############################################################################## # Create a sphere actor. Define the center, radius and color of a sphere. @@ -17,27 +17,27 @@ # sphere. # Let's create a scene. -scene = window.Scene() +scene = fury.window.Scene() ############################################################################## # The vertices are connected with triangles in order to specify the direction # of the surface normal. # ``prim_sphere`` provides a sphere with evenly distributed points -vertices, triangles = primitive.prim_sphere(name="symmetric362", gen_faces=False) +vertices, triangles = fury.primitive.prim_sphere(name="symmetric362", gen_faces=False) ############################################################################## # To be able to visualize the vertices, let's define a point actor with # green color. -point_actor = actor.point(vertices, point_radius=0.01, colors=(0, 1, 0)) +point_actor = fury.actor.point(vertices, point_radius=0.01, colors=(0, 1, 0)) ############################################################################## # Normals are the vectors that are perpendicular to the surface at each # vertex. We specify the normals at the vertices to tell the system # whether triangles represent curved surfaces. -normals = utils.normals_from_v_f(vertices, triangles) +normals = fury.utils.normals_from_v_f(vertices, triangles) ############################################################################## # The normals are usually used to calculate how the light will bounce on @@ -45,7 +45,7 @@ # spikes (represented with arrows). # So, let's create an arrow actor at the center of each vertex. -arrow_actor = actor.arrow( +arrow_actor = fury.actor.arrow( centers=vertices, directions=normals, colors=(1, 0, 0), @@ -61,7 +61,7 @@ primitive_colors = np.zeros(vertices.shape) primitive_colors[:, 2] = 180 -primitive_actor = utils.get_actor_from_primitive( +primitive_actor = fury.utils.get_actor_from_primitive( vertices=vertices, triangles=triangles, colors=primitive_colors, @@ -75,13 +75,13 @@ scene.add(point_actor) scene.add(arrow_actor) scene.add(primitive_actor) -scene.add(actor.axes()) +scene.add(fury.actor.axes()) ############################################################################## # The ShowManager class is the interface between the scene, the window and the # interactor. -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) @@ -108,7 +108,7 @@ def timer_callback(_obj, _event): showm.add_timer_callback(True, 200, timer_callback) showm.start() -window.record(showm.scene, size=(900, 768), out_path="viz_spiky.png") +fury.window.record(showm.scene, size=(900, 768), out_path="viz_spiky.png") ############################################################################## # Instead of arrows, you can choose other geometrical objects diff --git a/docs/examples/viz_spinbox.py b/docs/examples/viz_spinbox.py index 1fbe02f97..d7b9fdfae 100644 --- a/docs/examples/viz_spinbox.py +++ b/docs/examples/viz_spinbox.py @@ -12,18 +12,17 @@ import numpy as np -from fury import actor, ui, utils, window -from fury.data import fetch_viz_icons +import fury ############################################################################## # First we need to fetch some icons that are included in FURY. -fetch_viz_icons() +fury.data.fetch_viz_icons() ############################################################################### # Let's create a Cone. -cone = actor.cone( +cone = fury.actor.cone( centers=np.random.rand(1, 3), directions=np.random.rand(1, 3), colors=(1, 1, 1), @@ -33,7 +32,7 @@ ############################################################################### # Creating the SpinBox UI. -spinbox = ui.SpinBox( +spinbox = fury.ui.SpinBox( position=(200, 100), size=(300, 100), min_val=0, @@ -47,7 +46,7 @@ # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title="FURY SpinBox Example") +show_manager = fury.window.ShowManager(size=current_size, title="FURY SpinBox Example") show_manager.scene.add(cone) show_manager.scene.add(spinbox) @@ -62,7 +61,7 @@ def rotate_cone(spinbox): global previous_value change_in_value = spinbox.value - previous_value - utils.rotate(cone, (change_in_value, 1, 0, 0)) + fury.utils.rotate(cone, (change_in_value, 1, 0, 0)) previous_value = spinbox.value @@ -76,4 +75,4 @@ def rotate_cone(spinbox): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path="viz_spinbox.png") +fury.window.record(show_manager.scene, size=current_size, out_path="viz_spinbox.png") diff --git a/docs/examples/viz_spline_interpolator.py b/docs/examples/viz_spline_interpolator.py index c5ca86344..eff208200 100644 --- a/docs/examples/viz_spline_interpolator.py +++ b/docs/examples/viz_spline_interpolator.py @@ -8,13 +8,11 @@ import numpy as np -from fury import actor, window -from fury.animation import Animation, Timeline -from fury.animation.interpolator import spline_interpolator +import fury -scene = window.Scene() +scene = fury.window.Scene() -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) @@ -33,15 +31,15 @@ ############################################################################### # creating FURY dots to visualize the position values. -pos_dots = actor.dot(np.array(list(position_keyframes.values()))) +pos_dots = fury.actor.dot(np.array(list(position_keyframes.values()))) ############################################################################### # creating two timelines (one uses linear and the other uses' spline # interpolator), each timeline controls a sphere actor -sphere_linear = actor.sphere(np.array([[0, 0, 0]]), (1, 0.5, 0.2), 0.5) +sphere_linear = fury.actor.sphere(np.array([[0, 0, 0]]), (1, 0.5, 0.2), 0.5) -linear_anim = Animation() +linear_anim = fury.animation.Animation() linear_anim.add_actor(sphere_linear) linear_anim.set_position_keyframes(position_keyframes) @@ -53,13 +51,13 @@ ############################################################################### # creating a second timeline that translates another larger sphere actor using # spline interpolator. -sphere_spline = actor.sphere(np.array([[0, 0, 0]]), (0.3, 0.9, 0.6), 1) -spline_anim = Animation(sphere_spline) +sphere_spline = fury.actor.sphere(np.array([[0, 0, 0]]), (0.3, 0.9, 0.6), 1) +spline_anim = fury.animation.Animation(sphere_spline) spline_anim.set_position_keyframes(position_keyframes) ############################################################################### # Setting 5th degree spline interpolator for position keyframes. -spline_anim.set_position_interpolator(spline_interpolator, degree=5) +spline_anim.set_position_interpolator(fury.animation.spline_interpolator, degree=5) ############################################################################### # Wrapping animations up! @@ -69,7 +67,7 @@ ############################################################################### # First we create a timeline with a playback panel: -timeline = Timeline(playback_panel=True) +timeline = fury.animation.Timeline(playback_panel=True) ############################################################################### # Add visualization dots actor to the scene. @@ -94,4 +92,4 @@ if interactive: showm.start() -window.record(scene, out_path="viz_keyframe_animation_spline.png", size=(900, 768)) +fury.window.record(scene, out_path="viz_keyframe_animation_spline.png", size=(900, 768)) diff --git a/docs/examples/viz_surfaces.py b/docs/examples/viz_surfaces.py index 6cc62c551..fe19ecb91 100644 --- a/docs/examples/viz_surfaces.py +++ b/docs/examples/viz_surfaces.py @@ -14,9 +14,7 @@ import numpy as np -from fury import utils, window -from fury.io import load_polydata, save_polydata -from fury.lib import PolyData +import fury ############################################################################### # Import useful functions @@ -25,7 +23,7 @@ ############################################################################### # Create an empty ``PolyData`` -my_polydata = PolyData() +my_polydata = fury.lib.PolyData() ############################################################################### # Create a cube with vertices and triangles as numpy arrays @@ -65,43 +63,43 @@ ############################################################################### # Set vertices and triangles in the ``PolyData`` -utils.set_polydata_vertices(my_polydata, my_vertices) -utils.set_polydata_triangles(my_polydata, my_triangles) +fury.utils.set_polydata_vertices(my_polydata, my_vertices) +fury.utils.set_polydata_triangles(my_polydata, my_triangles) ############################################################################### # Save the ``PolyData`` file_name = "my_cube.vtk" -save_polydata(my_polydata, file_name) +fury.io.save_polydata(my_polydata, file_name) print("Surface saved in " + file_name) ############################################################################### # Load the ``PolyData`` -cube_polydata = load_polydata(file_name) +cube_polydata = fury.io.load_polydata(file_name) ############################################################################### # add color based on vertices position -cube_vertices = utils.get_polydata_vertices(cube_polydata) +cube_vertices = fury.utils.get_polydata_vertices(cube_polydata) colors = cube_vertices * 255 -utils.set_polydata_colors(cube_polydata, colors) +fury.utils.set_polydata_colors(cube_polydata, colors) print("new surface colors") -print(utils.get_polydata_colors(cube_polydata)) +print(fury.utils.get_polydata_colors(cube_polydata)) ############################################################################### # Visualize surfaces # get Actor -cube_actor = utils.get_actor_from_polydata(cube_polydata) +cube_actor = fury.utils.get_actor_from_polydata(cube_polydata) # Create a scene -scene = window.Scene() +scene = fury.window.Scene() scene.add(cube_actor) scene.set_camera(position=(10, 5, 7), focal_point=(0.5, 0.5, 0.5)) scene.zoom(3) # display -# window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path="cube.png", size=(600, 600)) +# fury.window.show(scene, size=(600, 600), reset_camera=False) +fury.window.record(scene, out_path="cube.png", size=(600, 600)) diff --git a/docs/examples/viz_tab.py b/docs/examples/viz_tab.py index da6f542c1..a4814c71e 100644 --- a/docs/examples/viz_tab.py +++ b/docs/examples/viz_tab.py @@ -15,18 +15,17 @@ import numpy as np -from fury import actor, ui, window -from fury.data import fetch_viz_icons +import fury ############################################################################## # First we need to fetch some icons that are included in FURY. -fetch_viz_icons() +fury.data.fetch_viz_icons() ############################################################################### # First, we create the Tab UI. -tab_ui = ui.TabUI(position=(49, 94), size=(300, 300), nb_tabs=3, draggable=True) +tab_ui = fury.ui.TabUI(position=(49, 94), size=(300, 300), nb_tabs=3, draggable=True) ############################################################################### # We can also define the position of the Tab Bar. @@ -40,9 +39,9 @@ # # Now we prepare content for the first tab. -ring_slider = ui.RingSlider2D(initial_value=0, text_template="{angle:5.1f}°") +ring_slider = fury.ui.RingSlider2D(initial_value=0, text_template="{angle:5.1f}°") -line_slider_x = ui.LineSlider2D( +line_slider_x = fury.ui.LineSlider2D( initial_value=0, min_value=-10, max_value=10, @@ -50,7 +49,7 @@ text_alignment="Top", ) -line_slider_y = ui.LineSlider2D( +line_slider_y = fury.ui.LineSlider2D( initial_value=0, min_value=-10, max_value=10, @@ -58,7 +57,7 @@ text_alignment="Right", ) -cube = actor.box( +cube = fury.actor.box( centers=np.array([[10, 0, 0]]), directions=np.array([[0, 1, 0]]), colors=np.array([[0, 0, 1]]), @@ -105,17 +104,17 @@ def translate_cube_y(slider): # # Now we prepare content for second tab. -cylinder = actor.cylinder( +cylinder = fury.actor.cylinder( centers=np.array([[0, 0, 0]]), directions=np.array([[1, 1, 0]]), colors=np.array([[0, 1, 1]]), radius=1.0, ) -sphere = actor.sphere(centers=np.array([[5, 0, 0]]), colors=(1, 1, 0)) +sphere = fury.actor.sphere(centers=np.array([[5, 0, 0]]), colors=(1, 1, 0)) figure_dict = {"cylinder": cylinder, "sphere": sphere} -checkbox = ui.Checkbox(labels=["cylinder", "sphere"]) +checkbox = fury.ui.Checkbox(labels=["cylinder", "sphere"]) # Get difference between two lists. @@ -149,7 +148,7 @@ def set_figure_visiblity(checkboxes): # # Now we prepare content for third tab. -label = ui.TextBlock2D( +label = fury.ui.TextBlock2D( position=(600, 300), font_size=40, color=(1, 0.5, 0), @@ -168,7 +167,7 @@ def set_figure_visiblity(checkboxes): "Red": (1, 0, 0), } -color_combobox = ui.ComboBox2D( +color_combobox = fury.ui.ComboBox2D( items=list(colors.keys()), placeholder="Choose Text Color", size=(250, 150), @@ -228,7 +227,7 @@ def collapse(tab_ui): ############################################################################### # Next we prepare the scene and render it with the help of show manager. -sm = window.ShowManager(size=(800, 500), title="Viz Tab") +sm = fury.window.ShowManager(size=(800, 500), title="Viz Tab") sm.scene.add(tab_ui, cube, cylinder, sphere, label) # To interact with the ui set interactive = True @@ -237,4 +236,4 @@ def collapse(tab_ui): if interactive: sm.start() -window.record(sm.scene, size=(500, 500), out_path="viz_tab.png") +fury.window.record(sm.scene, size=(500, 500), out_path="viz_tab.png") diff --git a/docs/examples/viz_tesseract.py b/docs/examples/viz_tesseract.py index f037c9026..a66312ea4 100644 --- a/docs/examples/viz_tesseract.py +++ b/docs/examples/viz_tesseract.py @@ -14,8 +14,7 @@ import numpy as np -from fury import actor, utils, window -from fury.ui import TextBlock2D +import fury ############################################################################### # Let's define some variables and their descriptions: @@ -118,11 +117,11 @@ def connect_points(verts3D): ############################################################################### # Creating a scene object and configuring the camera's position -scene = window.Scene() +scene = fury.window.Scene() scene.set_camera( position=(0, 10, -1), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) ) -showm = window.ShowManager(scene, size=(1920, 1080), order_transparent=True) +showm = fury.window.ShowManager(scene, size=(1920, 1080), order_transparent=True) ############################################################################### @@ -130,8 +129,8 @@ def connect_points(verts3D): verts3D = rotate4D(verts4D) if not wireframe: - points = actor.point(verts3D, colors=p_color) - point_verts = utils.vertices_from_actor(points) + points = fury.actor.point(verts3D, colors=p_color) + point_verts = fury.utils.vertices_from_actor(points) no_vertices = len(point_verts) / 16 initial_verts = point_verts.copy() - np.repeat(verts3D, no_vertices, axis=0) @@ -141,8 +140,10 @@ def connect_points(verts3D): # Connecting points with lines actor lines = connect_points(verts3D) -edges = actor.line(lines=lines, colors=e_color, lod=False, fake_tube=True, linewidth=4) -lines_verts = utils.vertices_from_actor(edges) +edges = fury.actor.line( + lines=lines, colors=e_color, lod=False, fake_tube=True, linewidth=4 +) +lines_verts = fury.utils.vertices_from_actor(edges) initial_lines = lines_verts.copy() - np.reshape(lines, (-1, 3)) scene.add(edges) @@ -150,7 +151,7 @@ def connect_points(verts3D): ############################################################################### # Initializing text box to display the name -tb = TextBlock2D(text="Tesseract", position=(900, 950), font_size=20) +tb = fury.ui.TextBlock2D(text="Tesseract", position=(900, 950), font_size=20) showm.scene.add(tb) ############################################################################### @@ -167,11 +168,11 @@ def timer_callback(_obj, _event): verts3D = rotate4D(verts4D) if not wireframe: point_verts[:] = initial_verts + np.repeat(verts3D, no_vertices, axis=0) - utils.update_actor(points) + fury.utils.update_actor(points) lines = connect_points(verts3D) lines_verts[:] = initial_lines + np.reshape(lines, (-1, 3)) - utils.update_actor(edges) + fury.utils.update_actor(edges) showm.render() angle += dtheta @@ -186,4 +187,4 @@ def timer_callback(_obj, _event): showm.add_timer_callback(True, 20, timer_callback) showm.start() -window.record(showm.scene, size=(600, 600), out_path="viz_tesseract.png") +fury.window.record(showm.scene, size=(600, 600), out_path="viz_tesseract.png") diff --git a/docs/examples/viz_texture.py b/docs/examples/viz_texture.py index 31043b706..fe46def4c 100644 --- a/docs/examples/viz_texture.py +++ b/docs/examples/viz_texture.py @@ -5,13 +5,12 @@ In this tutorial, we will show how to create a sphere with a texture. """ -from fury import actor, io, window -from fury.data import fetch_viz_textures, read_viz_textures +import fury ############################################################################## # Create a scene to start. -scene = window.Scene() +scene = fury.window.Scene() ############################################################################## # Load an image (png, bmp, jpeg or jpg) using ``io.load_image``. In this @@ -19,17 +18,17 @@ # Earth's surface from the fury Github after using ''fetch_viz_textures()'' # to download the available textures. -fetch_viz_textures() -filename = read_viz_textures("1_earth_8k.jpg") -image = io.load_image(filename) +fury.data.fetch_viz_textures() +filename = fury.data.read_viz_textures("1_earth_8k.jpg") +image = fury.io.load_image(filename) ############################################################################## -# Next, use ``actor.texture_on_sphere`` to add a sphere with the texture from +# Next, use ``fury.actor.texture_on_sphere`` to add a sphere with the texture from # your loaded image to the already existing scene. # To add a texture to your scene as visualized on a plane, use -# ``actor.texture`` instead. +# ``fury.actor.texture`` instead. -scene.add(actor.texture_on_sphere(image)) +scene.add(fury.actor.texture_on_sphere(image)) ############################################################################## # Lastly, record the scene, or set interactive to True if you would like to @@ -37,5 +36,5 @@ interactive = False if interactive: - window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, size=(900, 768), out_path="viz_texture.png") + fury.window.show(scene, size=(600, 600), reset_camera=False) +fury.window.record(scene, size=(900, 768), out_path="viz_texture.png") diff --git a/docs/examples/viz_timeline.py b/docs/examples/viz_timeline.py index 45218aacc..4e579e57f 100644 --- a/docs/examples/viz_timeline.py +++ b/docs/examples/viz_timeline.py @@ -18,14 +18,13 @@ import numpy as np -from fury import actor, window -from fury.animation import Animation, Timeline +import fury ############################################################################### # We create our ``Scene`` and ``ShowManager`` as usual. -scene = window.Scene() +scene = fury.window.Scene() -showm = window.ShowManager(scene, size=(900, 768)) +showm = fury.window.ShowManager(scene, size=(900, 768)) showm.initialize() ############################################################################### @@ -37,12 +36,12 @@ ############################################################################### # Creating a ``Timeline`` with a PlaybackPanel. -timeline = Timeline(playback_panel=True) +timeline = fury.animation.Timeline(playback_panel=True) ############################################################################### # Creating a Fury Animation as usual -anim = Animation() -sphere = actor.sphere(np.zeros([1, 3]), np.ones([1, 3])) +anim = fury.animation.Animation() +sphere = fury.actor.sphere(np.zeros([1, 3]), np.ones([1, 3])) anim.add_actor(sphere) # Now that the actor is add to the ``Animation``, setting keyframes to the # Animation will animate the actor accordingly. @@ -88,4 +87,6 @@ if interactive: showm.start() -window.record(scene, out_path="viz_keyframe_animation_timeline.png", size=(900, 768)) +fury.window.record( + scene, out_path="viz_keyframe_animation_timeline.png", size=(900, 768) +) diff --git a/docs/examples/viz_timers.py b/docs/examples/viz_timers.py index 4618cee44..e0217a7a5 100644 --- a/docs/examples/viz_timers.py +++ b/docs/examples/viz_timers.py @@ -17,24 +17,24 @@ import numpy as np -from fury import actor, ui, window +import fury xyz = 10 * np.random.rand(100, 3) colors = np.random.rand(100, 4) radii = np.random.rand(100) + 0.5 -scene = window.Scene() +scene = fury.window.Scene() -sphere_actor = actor.sphere(centers=xyz, colors=colors, radii=radii) +sphere_actor = fury.actor.sphere(centers=xyz, colors=colors, radii=radii) scene.add(sphere_actor) -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) -tb = ui.TextBlock2D(bold=True) +tb = fury.ui.TextBlock2D(bold=True) # use itertools to avoid global variables counter = itertools.count() @@ -66,4 +66,4 @@ def timer_callback(_obj, _event): showm.start() -window.record(showm.scene, size=(900, 768), out_path="viz_timer.png") +fury.window.record(showm.scene, size=(900, 768), out_path="viz_timer.png") diff --git a/docs/examples/viz_ui.py b/docs/examples/viz_ui.py index 31eecdc0b..8d50712e2 100644 --- a/docs/examples/viz_ui.py +++ b/docs/examples/viz_ui.py @@ -12,8 +12,7 @@ import numpy as np -from fury import actor, ui, window -from fury.data import fetch_viz_icons, read_viz_icons +import fury ############################################################################### # Shapes @@ -21,17 +20,19 @@ # # Let's start by drawing some simple shapes. First, a rectangle. -rect = ui.Rectangle2D(size=(200, 200), position=(400, 300), color=(1, 0, 1)) +rect = fury.ui.Rectangle2D(size=(200, 200), position=(400, 300), color=(1, 0, 1)) ############################################################################### # Then we can draw a solid circle, or disk. -disk = ui.Disk2D(outer_radius=50, center=(500, 500), color=(1, 1, 0)) +disk = fury.ui.Disk2D(outer_radius=50, center=(500, 500), color=(1, 1, 0)) ############################################################################### # Add an inner radius to make a ring. -ring = ui.Disk2D(outer_radius=50, inner_radius=45, center=(500, 300), color=(0, 1, 1)) +ring = fury.ui.Disk2D( + outer_radius=50, inner_radius=45, center=(500, 300), color=(0, 1, 1) +) ############################################################################### # Image @@ -40,13 +41,13 @@ # Now let's display an image. First we need to fetch some icons that are # included in FURY. -fetch_viz_icons() +fury.data.fetch_viz_icons() ############################################################################### # Now we can create an image container. -img = ui.ImageContainer2D( - img_path=read_viz_icons(fname="home3.png"), position=(450, 350) +img = fury.ui.ImageContainer2D( + img_path=fury.data.read_viz_icons(fname="home3.png"), position=(450, 350) ) ############################################################################### @@ -56,15 +57,15 @@ # Let's create some buttons and text and put them in a panel. First we'll # make the panel. -panel = ui.Panel2D(size=(300, 150), color=(1, 1, 1), align="right") +panel = fury.ui.Panel2D(size=(300, 150), color=(1, 1, 1), align="right") panel.center = (500, 400) ############################################################################### # Then we'll make two text labels and place them on the panel. # Note that we specify the position with integer numbers of pixels. -text = ui.TextBlock2D(text="Click me") -text2 = ui.TextBlock2D(text="Me too") +text = fury.ui.TextBlock2D(text="Click me") +text2 = fury.ui.TextBlock2D(text="Me too") panel.add_element(text, (50, 100)) panel.add_element(text2, (180, 100)) @@ -75,17 +76,17 @@ # percentages of the panel size. -button_example = ui.Button2D( - icon_fnames=[("square", read_viz_icons(fname="stop2.png"))] +button_example = fury.ui.Button2D( + icon_fnames=[("square", fury.data.read_viz_icons(fname="stop2.png"))] ) icon_files = [] -icon_files.append(("down", read_viz_icons(fname="circle-down.png"))) -icon_files.append(("left", read_viz_icons(fname="circle-left.png"))) -icon_files.append(("up", read_viz_icons(fname="circle-up.png"))) -icon_files.append(("right", read_viz_icons(fname="circle-right.png"))) +icon_files.append(("down", fury.data.read_viz_icons(fname="circle-down.png"))) +icon_files.append(("left", fury.data.read_viz_icons(fname="circle-left.png"))) +icon_files.append(("up", fury.data.read_viz_icons(fname="circle-up.png"))) +icon_files.append(("right", fury.data.read_viz_icons(fname="circle-right.png"))) -second_button_example = ui.Button2D(icon_fnames=icon_files) +second_button_example = fury.ui.Button2D(icon_fnames=icon_files) panel.add_element(button_example, (0.25, 0.33)) panel.add_element(second_button_example, (0.66, 0.33)) @@ -114,7 +115,7 @@ def change_icon_callback(i_ren, _obj, _button): # Let's add a cube to the scene and control it with sliders. -cube = actor.cube( +cube = fury.actor.cube( centers=np.array([[15, 0, 0]]), colors=np.array([[0, 0, 1]]), scales=np.array([[20, 20, 20]]), @@ -124,11 +125,11 @@ def change_icon_callback(i_ren, _obj, _button): ############################################################################### # Now we'll add three sliders: one circular and two linear. -ring_slider = ui.RingSlider2D( +ring_slider = fury.ui.RingSlider2D( center=(740, 400), initial_value=0, text_template="{angle:5.1f}°" ) -line_slider_x = ui.LineSlider2D( +line_slider_x = fury.ui.LineSlider2D( center=(500, 250), initial_value=0, min_value=-10, @@ -136,7 +137,7 @@ def change_icon_callback(i_ren, _obj, _button): orientation="horizontal", ) -line_slider_y = ui.LineSlider2D( +line_slider_y = fury.ui.LineSlider2D( center=(650, 350), initial_value=0, min_value=-10, @@ -187,7 +188,7 @@ def translate_cube_y(slider): # Finally, we can add a range slider. This element is composed of two sliders. # The first slider has two handles which let you set the range of the second. -range_slider_x = ui.RangeSlider( +range_slider_x = fury.ui.RangeSlider( line_width=8, handle_side=25, range_slider_center=(450, 450), @@ -201,7 +202,7 @@ def translate_cube_y(slider): shape="square", ) -range_slider_y = ui.RangeSlider( +range_slider_y = fury.ui.RangeSlider( line_width=8, handle_side=25, range_slider_center=(750, 400), @@ -263,7 +264,7 @@ def hide_all_examples(): ############################################################################### # Now we can create the menu. -listbox = ui.ListBox2D( +listbox = fury.ui.ListBox2D( values=values, position=(10, 300), size=(300, 200), multiselection=False ) @@ -291,7 +292,7 @@ def display_element(): # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title="FURY UI Example") +show_manager = fury.window.ShowManager(size=current_size, title="FURY UI Example") show_manager.scene.add(listbox) for example in examples: @@ -309,4 +310,4 @@ def display_element(): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path="viz_ui.png") +fury.window.record(show_manager.scene, size=current_size, out_path="viz_fury.ui.png") diff --git a/docs/examples/viz_ui_listbox.py b/docs/examples/viz_ui_listbox.py index c89335662..146d147b6 100644 --- a/docs/examples/viz_ui_listbox.py +++ b/docs/examples/viz_ui_listbox.py @@ -10,21 +10,20 @@ First, a bunch of imports. """ -from fury import ui, window -from fury.data import fetch_viz_icons +import fury ############################################################################## # First we need to fetch some icons that are included in FURY. -fetch_viz_icons() +fury.data.fetch_viz_icons() ############################################################################### # Create some text blocks that will be shown when # list elements will be selected -welcome_text = ui.TextBlock2D(text="Welcome", font_size=30, position=(500, 400)) -bye_text = ui.TextBlock2D(text="Bye", font_size=30, position=(500, 400)) -fury_text = ui.TextBlock2D(text="Fury", font_size=30, position=(500, 400)) +welcome_text = fury.ui.TextBlock2D(text="Welcome", font_size=30, position=(500, 400)) +bye_text = fury.ui.TextBlock2D(text="Bye", font_size=30, position=(500, 400)) +fury_text = fury.ui.TextBlock2D(text="Fury", font_size=30, position=(500, 400)) example = [welcome_text, bye_text, fury_text] @@ -43,7 +42,7 @@ def hide_all_examples(): # Create ListBox with the values as parameter. values = ["Welcome", "Bye", "Fury"] -listbox = ui.ListBox2D( +listbox = fury.ui.ListBox2D( values=values, position=(10, 300), size=(200, 200), multiselection=False ) @@ -64,7 +63,9 @@ def display_element(): # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title="FURY UI ListBox_Example") +show_manager = fury.window.ShowManager( + size=current_size, title="FURY UI ListBox_Example" +) show_manager.scene.add(listbox) show_manager.scene.add(welcome_text) @@ -75,4 +76,4 @@ def display_element(): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path="viz_listbox.png") +fury.window.record(show_manager.scene, size=current_size, out_path="viz_listbox.png") diff --git a/docs/examples/viz_ui_slider.py b/docs/examples/viz_ui_slider.py index 034761fc3..31e47f0c4 100644 --- a/docs/examples/viz_ui_slider.py +++ b/docs/examples/viz_ui_slider.py @@ -12,13 +12,12 @@ import numpy as np -from fury import actor, ui, window -from fury.data import fetch_viz_icons +import fury ############################################################################## # First we need to fetch some icons that are included in FURY. -fetch_viz_icons() +fury.data.fetch_viz_icons() ############################################################################### # Cube and sliders @@ -26,7 +25,7 @@ # # Add a cube to the scene . -cube = actor.cube( +cube = fury.actor.cube( centers=np.array([[15, 0, 0]]), colors=np.array([[0, 0, 1]]), scales=np.array([[20, 20, 20]]), @@ -37,11 +36,11 @@ # Now we'll add five sliders: 1 circular and 4 linear sliders. # By default the alignments are 'bottom' for horizontal and 'top' for vertical. -ring_slider = ui.RingSlider2D( +ring_slider = fury.ui.RingSlider2D( center=(630, 400), initial_value=0, text_template="{angle:5.1f}°" ) -hor_line_slider_text_top = ui.LineSlider2D( +hor_line_slider_text_top = fury.ui.LineSlider2D( center=(400, 230), initial_value=0, orientation="horizontal", @@ -50,7 +49,7 @@ text_alignment="top", ) -hor_line_slider_text_bottom = ui.LineSlider2D( +hor_line_slider_text_bottom = fury.ui.LineSlider2D( center=(400, 200), initial_value=0, orientation="horizontal", @@ -59,7 +58,7 @@ text_alignment="bottom", ) -ver_line_slider_text_left = ui.LineSlider2D( +ver_line_slider_text_left = fury.ui.LineSlider2D( center=(100, 400), initial_value=0, orientation="vertical", @@ -68,7 +67,7 @@ text_alignment="left", ) -ver_line_slider_text_right = ui.LineSlider2D( +ver_line_slider_text_right = fury.ui.LineSlider2D( center=(150, 400), initial_value=0, orientation="vertical", @@ -118,7 +117,7 @@ def translate_cube_hor(slider): # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title="FURY Cube Example") +show_manager = fury.window.ShowManager(size=current_size, title="FURY Cube Example") show_manager.scene.add(cube) show_manager.scene.add(ring_slider) @@ -150,4 +149,4 @@ def translate_cube_hor(slider): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path="viz_slider.png") +fury.window.record(show_manager.scene, size=current_size, out_path="viz_slider.png") diff --git a/docs/examples/viz_using_time_equations.py b/docs/examples/viz_using_time_equations.py index baf680b2c..a4ae678fd 100644 --- a/docs/examples/viz_using_time_equations.py +++ b/docs/examples/viz_using_time_equations.py @@ -8,21 +8,20 @@ import numpy as np -from fury import actor, window -from fury.animation import Animation +import fury -scene = window.Scene() +scene = fury.window.Scene() -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) -cube = actor.cube(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6) +cube = fury.actor.cube(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6) ############################################################################### # Creating an ``Animation`` to animate the actor and show its motion path. -anim = Animation(length=2 * np.pi, loop=True, motion_path_res=200) +anim = fury.animation.Animation(length=2 * np.pi, loop=True, motion_path_res=200) ############################################################################### # Adding the sphere actor to the timeline @@ -77,4 +76,6 @@ def scale_eval(t): if interactive: showm.start() -window.record(scene, out_path="viz_keyframe_animation_evaluators.png", size=(900, 768)) +fury.window.record( + scene, out_path="viz_keyframe_animation_evaluators.png", size=(900, 768) +) diff --git a/docs/examples/viz_widget.py b/docs/examples/viz_widget.py index 6768a843e..ee7b99da8 100644 --- a/docs/examples/viz_widget.py +++ b/docs/examples/viz_widget.py @@ -42,23 +42,22 @@ import numpy as np -from fury import actor, window -from fury.stream.widget import Widget +import fury interactive = False window_size = (720, 500) N = 4 centers = np.random.normal(size=(N, 3)) colors = np.random.uniform(0.1, 1.0, size=(N, 3)) -actors = actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors) -scene = window.Scene() +actors = fury.actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors) +scene = fury.window.Scene() scene.add(actors) -showm = window.ShowManager(scene, size=(window_size[0], window_size[1])) +showm = fury.window.ShowManager(scene, size=(window_size[0], window_size[1])) ########################################################################## # Create a stream widget -widget = Widget(showm, port=8000) +widget = fury.stream.Widget(showm, port=8000) # if you want to use webRTC, you can pass the argument to choose this encoding # which is a more robust option. @@ -86,4 +85,4 @@ async def main(): time.sleep(time_sleep) widget.stop() -window.record(showm.scene, size=window_size, out_path="viz_widget.png") +fury.window.record(showm.scene, size=window_size, out_path="viz_widget.png") diff --git a/docs/examples/viz_wrecking_ball.py b/docs/examples/viz_wrecking_ball.py index 1e574ccc3..31e9587a3 100644 --- a/docs/examples/viz_wrecking_ball.py +++ b/docs/examples/viz_wrecking_ball.py @@ -15,7 +15,7 @@ import numpy as np import pybullet as p -from fury import actor, ui, utils, window +import fury ############################################################################### # Initiate pybullet and enable gravity. @@ -52,7 +52,7 @@ # Creating the base plane actor. # Base -base_actor = actor.box( +base_actor = fury.actor.box( centers=np.array([[0, 0, 0]]), directions=[0, 0, 0], scales=(5, 5, 0.2), @@ -108,7 +108,7 @@ p.changeDynamics(bricks[idx], -1, lateralFriction=0.1, restitution=0.1) idx += 1 -brick_actor = actor.box( +brick_actor = fury.actor.box( centers=brick_centers, directions=brick_directions, scales=brick_sizes, @@ -160,7 +160,7 @@ link_heights = np.zeros(n_links) link_heights[:] = dx_link -rope_actor = actor.cylinder( +rope_actor = fury.actor.cylinder( centers=linkPositions, directions=linkDirections, colors=np.random.rand(n_links, 3), @@ -213,14 +213,14 @@ rope, -1, -1, -1, p.JOINT_FIXED, [0, 0, 0], [0, 0, 0], [0, 0, 2] ) -box_actor = actor.box( +box_actor = fury.actor.box( centers=np.array([[0, 0, 0]]), directions=np.array([[0, 0, 0]]), scales=(0.02, 0.02, 0.02), colors=np.array([[1, 0, 0]]), ) -ball_actor = actor.sphere( +ball_actor = fury.actor.sphere( centers=np.array([[0, 0, 0]]), radii=ball_radius, colors=np.array([1, 0, 1]) ) @@ -228,12 +228,12 @@ # Now we add the necessary actors to the scene and set the camera for better # visualization. -scene = window.Scene() +scene = fury.window.Scene() scene.set_camera((10.28, -7.10, 6.39), (0.0, 0.0, 0.4), (-0.35, 0.26, 1.0)) -scene.add(actor.axes(scale=(0.5, 0.5, 0.5)), base_actor, brick_actor) +scene.add(fury.actor.axes(scale=(0.5, 0.5, 0.5)), base_actor, brick_actor) scene.add(rope_actor, box_actor, ball_actor) -showm = window.ShowManager( +showm = fury.window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True ) @@ -247,7 +247,7 @@ ############################################################################### # Calculate the vertices of the bricks. -brick_vertices = utils.vertices_from_actor(brick_actor) +brick_vertices = fury.utils.vertices_from_actor(brick_actor) num_vertices = brick_vertices.shape[0] num_objects = brick_centers.shape[0] brick_sec = int(num_vertices / num_objects) @@ -255,7 +255,7 @@ ############################################################################### # Calculate the vertices of the wrecking ball. -chain_vertices = utils.vertices_from_actor(rope_actor) +chain_vertices = fury.utils.vertices_from_actor(rope_actor) num_vertices = chain_vertices.shape[0] num_objects = brick_centers.shape[0] chain_sec = int(num_vertices / num_objects) @@ -316,7 +316,7 @@ def sync_chain(actor_list, multibody): counter = itertools.count() fpss = np.array([]) -tb = ui.TextBlock2D( +tb = fury.ui.TextBlock2D( position=(0, 680), font_size=30, color=(1, 0.5, 0), text="Avg. FPS: \nSim Steps: " ) scene.add(tb) @@ -355,8 +355,8 @@ def timer_callback(_obj, _event): pos = p.getLinkState(rope, p.getNumJoints(rope) - 1)[4] ball_actor.SetPosition(*pos) sync_chain(rope_actor, rope) - utils.update_actor(brick_actor) - utils.update_actor(rope_actor) + fury.utils.update_actor(brick_actor) + fury.utils.update_actor(rope_actor) # Simulate a step. p.stepSimulation() @@ -375,4 +375,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, size=(900, 768), out_path="viz_wrecking_ball.png") +fury.window.record(scene, size=(900, 768), out_path="viz_wrecking_ball.png") diff --git a/docs/experimental/viz_molecular_demo.py b/docs/experimental/viz_molecular_demo.py index d72338a55..6f94154df 100644 --- a/docs/experimental/viz_molecular_demo.py +++ b/docs/experimental/viz_molecular_demo.py @@ -129,10 +129,10 @@ # 3. Creating and adding axes actor to the scene. # 4. Computing the bonding information for the molecule. # 5. Generating and adding various molecular representations to the scene. -scene = window.Scene() +scene = fury.window.Scene() scene.set_camera(position=(20, 10, 0), focal_point=(0, 0, 0), view_up=(0, 1, 0)) scene.zoom(0.8) -axes_actor = actor.axes() +axes_actor = fury.actor.axes() scene.add(axes_actor) molecule = mol.Molecule( @@ -172,9 +172,9 @@ ############################################################################### # creating a ShowManager object -showm = window.ShowManager(scene, size=dims, reset_camera=True, order_transparent=True) +showm = fury.window.ShowManager(scene, size=dims, reset_camera=True, order_transparent=True) -tb = ui.TextBlock2D( +tb = fury.ui.TextBlock2D( text=pdb_code.upper(), position=(screen_x_dim / 2 - 40, screen_y_dim / 12), font_size=30, @@ -189,5 +189,5 @@ interactive = False if interactive: - window.show(scene, size=dims, title=pdb_code.upper()) -window.record(scene, size=dims, out_path=pdb_code.upper() + '.png') + fury.window.show(scene, size=dims, title=pdb_code.upper()) +fury.window.record(scene, size=dims, out_path=pdb_code.upper() + '.png') diff --git a/docs/experimental/viz_multisdf.py b/docs/experimental/viz_multisdf.py index 37a78c5b4..fee954482 100644 --- a/docs/experimental/viz_multisdf.py +++ b/docs/experimental/viz_multisdf.py @@ -46,7 +46,7 @@ vtk.vtkShader.Fragment, '//VTK::Light::Impl', True, fs_impl_code, False ) -scene = window.Scene() +scene = fury.window.Scene() scene.background((1.0, 0.8, 0.8)) centers = np.array([[0, 0, 0]]) @@ -61,7 +61,7 @@ def timer_callback(obj, event): showm.render() -@window.vtk.calldata_type(window.vtk.VTK_OBJECT) +@fury.window.vtk.calldata_type(fury.window.vtk.VTK_OBJECT) def vtk_shader_callback(caller, event, calldata=None): program = calldata global timer @@ -72,15 +72,15 @@ def vtk_shader_callback(caller, event, calldata=None): pass -mapper.AddObserver(window.vtk.vtkCommand.UpdateShaderEvent, vtk_shader_callback) +mapper.AddObserver(fury.window.vtk.vtkCommand.UpdateShaderEvent, vtk_shader_callback) -showm = window.ShowManager(scene, reset_camera=False) +showm = fury.window.ShowManager(scene, reset_camera=False) showm.add_timer_callback(True, 10, timer_callback) scene.add(sdfactor) -scene.add(actor.axes()) +scene.add(fury.actor.axes()) showm.start() diff --git a/docs/source/_static/images/gsdoc-some-sphinx-warnings-addressed_Wachiou.jpg b/docs/source/_static/images/gsdoc-some-sphinx-warnings-addressed_Wachiou.jpg new file mode 100644 index 000000000..2537b2b50 Binary files /dev/null and b/docs/source/_static/images/gsdoc-some-sphinx-warnings-addressed_Wachiou.jpg differ diff --git a/docs/source/_static/images/gsoc-robin-3-fury-discord-bot-references-url.jpg b/docs/source/_static/images/gsoc-robin-3-fury-discord-bot-references-url.jpg new file mode 100644 index 000000000..d9bdec1f4 Binary files /dev/null and b/docs/source/_static/images/gsoc-robin-3-fury-discord-bot-references-url.jpg differ diff --git a/docs/source/_static/images/gsoc_llm_robin_week5.jpg b/docs/source/_static/images/gsoc_llm_robin_week5.jpg new file mode 100644 index 000000000..71be43086 Binary files /dev/null and b/docs/source/_static/images/gsoc_llm_robin_week5.jpg differ diff --git a/docs/source/_static/images/robin_gsoc_FURY_DISCUSSIONS_TEMPLATE.jpg b/docs/source/_static/images/robin_gsoc_FURY_DISCUSSIONS_TEMPLATE.jpg new file mode 100644 index 000000000..f7dbc9c46 Binary files /dev/null and b/docs/source/_static/images/robin_gsoc_FURY_DISCUSSIONS_TEMPLATE.jpg differ diff --git a/docs/source/_static/vendor/styles.css b/docs/source/_static/vendor/styles.css index 7773f27ec..81337a3f6 100644 --- a/docs/source/_static/vendor/styles.css +++ b/docs/source/_static/vendor/styles.css @@ -129,6 +129,7 @@ em { #feature-card { height: 475px; } + #backtotop.visible #backtotop-color:hover { background: var(--colorHighlight); } @@ -159,7 +160,7 @@ p { margin-left: 15px; } -.content-container ol { +.content-container ol { padding: 10px; margin-left: 15px; } @@ -248,6 +249,23 @@ p { background-color: var(--colorPrimaryDark); } +.footer-columns { + display: flex; + font-weight: bold; + justify-content: space-between; + padding: 20px 5vw; + padding-top: 0; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +.footer-columns a { + color: #fff; +} + +.footer-columns a:hover { + color: #fff; +} + .footer-logo-column { display: flex; justify-content: center; @@ -266,9 +284,12 @@ p { flex-shrink: 1; } -.footer-link, .footer-link:hover { +.footer-link { font-size: 1rem; - color: var(--colorSecondary); +} + +.footer-link .footer-link:hover { + color: var(--colorPrimaryLight); } .footer-actions { @@ -276,7 +297,7 @@ p { margin: 20px 25px; } -.footer-actions > p { +.footer-actions>p { padding-top: 0; } @@ -330,6 +351,10 @@ blockquote p::after { @media only screen and (max-width: 850px) { + .footer-columns { + flex-direction: column; + } + .footer-column ul.link-list li.link-list { width: calc(50% - 24px); display: inline-block; @@ -356,7 +381,7 @@ div.sphx-glr-download a { div.sphx-glr-download a:hover { background-color: var(--colorPrimaryDark); - box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 5px rgba(0, 0, 0, .25); text-decoration: none; background-image: none; } diff --git a/docs/source/conf.py b/docs/source/conf.py index 6af7ae93f..a7bbb73a7 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -40,12 +40,12 @@ # ones. extensions = [ "sphinx.ext.autodoc", + "numpydoc", "sphinx.ext.autosummary", "sphinx.ext.githubpages", "sphinx.ext.intersphinx", "sphinx.ext.mathjax", "sphinx.ext.viewcode", - "sphinx.ext.napoleon", "IPython.sphinxext.ipython_directive", "IPython.sphinxext.ipython_console_highlighting", "matplotlib.sphinxext.plot_directive", diff --git a/docs/source/ext/apigen.py b/docs/source/ext/apigen.py index 6a3cb0433..ebc6dff05 100644 --- a/docs/source/ext/apigen.py +++ b/docs/source/ext/apigen.py @@ -38,7 +38,7 @@ class ApiDocWriter: def __init__( self, package_name, - rst_extension=".txt", + rst_extension=".rst", package_skip_patterns=None, module_skip_patterns=None, object_skip_patterns=None, @@ -235,6 +235,7 @@ def _parse_module_with_import(self, uri): functions = [] classes = [] + constant_variables = [] for n in node.body: if not hasattr(n, "name"): if not isinstance(n, ast.Assign): @@ -254,7 +255,7 @@ def _parse_module_with_import(self, uri): if isinstance(n.value, ast.Call): if isinstance(n.targets[0], ast.Tuple): continue - functions.append(n.targets[0].id) + constant_variables.append(n.targets[0].id) elif hasattr(n.value, "attr") and n.value.attr.startswith("vtk"): classes.append(n.targets[0].id) except Exception: @@ -262,7 +263,7 @@ def _parse_module_with_import(self, uri): print(n.lineno) print(n.targets[0]) - return functions, classes + return functions, classes, constant_variables def _parse_lines(self, linesource): """Parse lines of text for functions and classes.""" @@ -302,7 +303,7 @@ def generate_api_doc(self, uri): """ # get the names of all classes and functions - functions, classes = self._parse_module_with_import(uri) + functions, classes, constant_variables = self._parse_module_with_import(uri) if not len(functions) and not len(classes) and DEBUG: print("WARNING: Empty -", uri) # dbg @@ -323,8 +324,21 @@ def generate_api_doc(self, uri): head += title + "\n" + self.rst_section_levels[1] * len(title) head += "\n.. automodule:: " + uri + "\n" + head += "\n.. currentmodule:: " + uri + "\n" + body += "\n.. currentmodule:: " + uri + "\n\n" + + for c in constant_variables: + # must NOT exclude from index to keep cross-refs working + body += c + "\n" + body += self.rst_section_levels[3] * len(c) + "\n" + body += "\n.. autodata:: " + c + "\n" + body += " :no-value:\n" + body += " :annotation:\n" + + body += "\n\n" + for c in classes: body += ( "\n:class:`" @@ -335,23 +349,18 @@ def generate_api_doc(self, uri): ) body += "\n.. autoclass:: " + c + "\n" # must NOT exclude from index to keep cross-refs working - body += ( - " :members:\n" - " :undoc-members:\n" - " :show-inheritance:\n" - "\n" - " .. automethod:: __init__\n\n" - ) + body += " :members:\n" " :undoc-members:\n" " :show-inheritance:\n" "\n" head += ".. autosummary::\n\n" - for f in classes + functions: + for f in constant_variables + classes + functions: head += " " + f + "\n" - head += "\n" + head += "\n\n" for f in functions: # must NOT exclude from index to keep cross-refs working body += f + "\n" body += self.rst_section_levels[3] * len(f) + "\n" - body += "\n.. autofunction:: " + f + "\n\n" + body += "\n.. autofunction:: " + f + "\n" + body += "\n\n" return head, body diff --git a/docs/source/posts/2021/2021-08-16-week-11-antriksh.rst b/docs/source/posts/2021/2021-08-16-week-11-antriksh.rst index b229f0343..a1c68ef79 100644 --- a/docs/source/posts/2021/2021-08-16-week-11-antriksh.rst +++ b/docs/source/posts/2021/2021-08-16-week-11-antriksh.rst @@ -13,7 +13,7 @@ Below are the tasks that I worked on: * `Created PR for sprite sheet animation `_ : This PR adds support for playing animations from a sprite sheet. This feature will be used in Card2D to create a tutorial in which the card will show the animation in the image box. Previously, the utility functions for this were added directly inside the tutorial but now they are refactored to go in their respective modules. * `Finalized the x, y, z layouts `_ : The PR that adds these layouts needed some updates for it to work as intended. These changes were added and this PR is ready to go. * `Resolved all conflicts in the GridLayout PR `_ : As the Horizontal and Vertical layouts were merged this week the GridLayout PR had got some conflicts. These conflicts were resolved and the PR is almost ready. -* **Continuing the work on custom font rendering** : In the last meeting, a few points were brought up. Firstly, to position each glyph to their respective location in the atlas a separate module is used which is freetype-gl. The python bindings for this module are not available which means either we have to write the bindings ourselves or the freetype team will be emailed about this and they will add bindings for that. On the other hand, I looked how latex is rendered in matplotlib. `This `_ is the Text class that is used to represent the string that is to be drawn and `This is the class that it inherits from.`_ Everything is handled internally in matplotlib, to draw the rasterized text `this function is used. `_ The text can be rendered in two ways, the first one is by using the default renderer and the second way is by using PathEffectRenderer that is used to add effects like outlines, anti-aliasing etc. It is a very rigid way of rendering text and is designed to be used internally. +* **Continuing the work on custom font rendering** : In the last meeting, a few points were brought up. Firstly, to position each glyph to their respective location in the atlas a separate module is used which is freetype-gl. The python bindings for this module are not available which means either we have to write the bindings ourselves or the freetype team will be emailed about this and they will add bindings for that. On the other hand, I looked how latex is rendered in matplotlib. `This `_ is the Text class that is used to represent the string that is to be drawn and `This is the class that it inherits from `_. Everything is handled internally in matplotlib, to draw the rasterized text `this function is used. `_ The text can be rendered in two ways, the first one is by using the default renderer and the second way is by using PathEffectRenderer that is used to add effects like outlines, anti-aliasing etc. It is a very rigid way of rendering text and is designed to be used internally. Did I get stuck anywhere? ------------------------- diff --git a/docs/source/posts/2021/2021-16-08-gsoc-devmessias-11.rst b/docs/source/posts/2021/2021-16-08-gsoc-devmessias-11.rst index 1261ba826..7fb79e42f 100644 --- a/docs/source/posts/2021/2021-16-08-gsoc-devmessias-11.rst +++ b/docs/source/posts/2021/2021-16-08-gsoc-devmessias-11.rst @@ -1,4 +1,4 @@ -Week #11: Removing the flickering effect +Week 11: Removing the flickering effect ======================================== .. post:: August 16 2021 @@ -12,69 +12,50 @@ What did I do this week? FURY ^^^^ -- `PR fury-gl/fury#489: `__ +1. `PR fury-gl/fury#489: `_ - This PR give to FURY three - pre-built texture maps using different fonts. However, is quite easy - to create new fonts to be used in a visualization. -| It's was quite hard to develop the shader code and find the correct - positions of the texture maps to be used in the shader. Because we - used the freetype-py to generate the texture and packing the glyps. - However, the lib has some examples with bugs. But fortunately, now - everything is working on FURY. I've also created two different examples - to show how this PR works. +This PR give to FURY three pre-built texture maps using different fonts. However, is quite easy to create new fonts to be used in a visualization. - The first example, viz_huge_amount_of_labels.py, shows that the user can - draw hundreds of thousands of characters. +It's was quite hard to develop the shader code and find the correct positions of the texture maps to be used in the shader. Because we used the freetype-py to generate the texture and packing the glyps. However, the lib has some examples with bugs. But fortunately, now everything is working on FURY. I've also created two different examples to show how this PR works. +The first example, viz_huge_amount_of_labels.py, shows that the user can draw hundreds of thousands of characters. - |image2| - The second example, viz_billboad_labels.py, shows the different behaviors of the label actor. In addition, presents - to the user how to create a new texture atlas font to be used across different visualizations. +|image2| -- `PR fury-gl/fury#437: `__ +The second example, viz_billboad_labels.py, shows the different behaviors of the label actor. In addition, presents to the user how to create a new texture atlas font to be used across different visualizations. - - Fix: avoid multiple OpenGl context on windows using asyncio - The streaming system must be generic, but opengl and vtk behaves in uniques ways in each Operating System. Thus, can be tricky - to have the same behavior acrros different OS. One hard stuff that we founded is that was not possible to use my - TimeIntervals objects (implemented with threading module) with vtk. The reason for this impossibility is because we can't use - vtk in windows in different threads. But fortunely, moving from the threading (multithreading) to the asyncio approcach (concurrency) - have fixed this issue and now the streaming system is ready to be used anywhere. +2. `PR fury-gl/fury#437: `_ - - Flickering: + - Fix: avoid multiple OpenGl context on windows using asyncio - Finally, I could found the cause of the flickering effect on the streaming system. - This flickering was appearing only when the streaming was created using the Widget object. - The cause seems to be a bug or a strange behavior from vtk. - Calling iren.MouseWheelForwardEvent() or iren.MouseWheelBackwardEvent() - inside of a thread without invoking the - Start method from a vtk instance produces a memory corruption. - Fortunately, I could fix this behavior and now the streaming system is - working without this glitch effect. + The streaming system must be generic, but opengl and vtk behaves in uniques ways in each Operating System. Thus, can be tricky to have the same behavior acrros different OS. One hard stuff that we founded is that was not possible to use my + TimeIntervals objects (implemented with threading module) with vtk. The reason for this impossibility is because we can't use vtk in windows in different threads. But fortunely, moving from the threading (multithreading) to the asyncio approcach (concurrency) have fixed this issue and now the streaming system is ready to be used anywhere. + + - Flickering: + + Finally, I could found the cause of the flickering effect on the streaming system. + This flickering was appearing only when the streaming was created using the Widget object. + The cause seems to be a bug or a strange behavior from vtk. + Calling iren.MouseWheelForwardEvent() or iren.MouseWheelBackwardEvent() + inside of a thread without invoking the + Start method from a vtk instance produces a memory corruption. + Fortunately, I could fix this behavior and now the streaming system is + working without this glitch effect. FURY/Helios ^^^^^^^^^^^ -- `PR fury-gl/helios#24 - : `__ +3. `PR fury-gl/helios#24: `__ -This uses the -`PRfury-gl/fury#489: `__ to -give the network label feature to helios. Is possible to draw node -labels, update the colors, change the positions at runtime. In addition, -when a network layout algorithm is running this will automatically -update the node labels positions to follow the nodes across the screen. +This uses the `PRfury-gl/fury#489: `__ to give the network label feature to helios. Is possible to draw node labels, update the colors, change the positions at runtime. In addition, when a network layout algorithm is running this will automatically update the node labels positions to follow the nodes across the screen. |image1| -- `PR fury-gl/helios#23: - Merged. `__ +4. `PR fury-gl/helios#23 (merged): `__ -This PR granted compatibility between IPC Layouts and Windows. Besides -that , now is quite easier to create new network layouts using inter -process communication +This PR granted compatibility between IPC Layouts and Windows. Besides that , now is quite easier to create new network layouts using inter process communication Did I get stuck anywhere? ------------------------- diff --git a/docs/source/posts/2022/2022-09-15-week-13-blog.rst b/docs/source/posts/2022/2022-09-15-week-13-blog.rst index 3d8088c59..b1fbe9a83 100644 --- a/docs/source/posts/2022/2022-09-15-week-13-blog.rst +++ b/docs/source/posts/2022/2022-09-15-week-13-blog.rst @@ -15,6 +15,7 @@ This week I fixed all the issues with skeletal animations, and we got to see our - Implemented a hierarchical timeline system (i.e., one timeline for each bone, and the timeline will contain its parent timeline in a hierarchy). - I figured out that we don't need to apply the parent transform as we're applying it to the vertex data while forming the actor. So the skin matrix becomes + ``SkinMatrix = InverseBindPose * BoneDeform`` where ``BoneDeform = CurrentBoneTransform * ParentBonetransform``. Here's a preview using the ``CesiumMan`` model: diff --git a/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst b/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst index 68cf97c12..807518aa3 100644 --- a/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst +++ b/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst @@ -9,7 +9,7 @@
- fury + FURY
@@ -50,7 +50,7 @@ Modified Objectives * Adding a playback panel for controlling the timeline. * Billboard actor using the geometry shader. * Hierarchical animation support. -* Animating primitives of the same Fury actor separately. +* Animating primitives of the same FURY actor separately. * Color interpolators. Objectives Completed @@ -63,7 +63,7 @@ Objectives Completed * ``Animation`` Class * - The ``Animation`` class is the main part of the FURY animation module. It is responsible for keyframe animations for a single or a group of FURY actors. The ``Animation`` is able to handle multiple attributes and properties of Fury actors such as position, color, scale, rotation, and opacity. It is also capable of doing the following: + The ``Animation`` class is the main part of the FURY animation module. It is responsible for keyframe animations for a single or a group of FURY actors. The ``Animation`` is able to handle multiple attributes and properties of FURY actors such as position, color, scale, rotation, and opacity. It is also capable of doing the following: * Set animation keyframes and events. @@ -153,7 +153,7 @@ Objectives Completed * Billboard actor using the geometry shader - Fury already has a billboard actor implemented using two triangles to construct the billboard. But the new approach uses only one vertex and the canvas of the billboard is generated by the geometry shader. This approach is faster in initialization since only the center is needed and no additional computations to generate the primitive on the CPU side. Also, animating these new billboards using the method mentioned above in the previous objective is way much faster, and faster is one of the reasons why we use billboards. + FURY already has a billboard actor implemented using two triangles to construct the billboard. But the new approach uses only one vertex and the canvas of the billboard is generated by the geometry shader. This approach is faster in initialization since only the center is needed and no additional computations to generate the primitive on the CPU side. Also, animating these new billboards using the method mentioned above in the previous objective is way much faster, and faster is one of the reasons why we use billboards. *Pull Requests:* @@ -223,43 +223,43 @@ Timeline - Blog Post Link * - Week 0\ :raw-html:`
`\ (23-05-2022) - My journey till getting accepted into GSoC22 - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 1\ :raw-html:`
`\ (08-06-2022) - Implementing a basic Keyframe animation API - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 2\ :raw-html:`
`\ (28-06-2022) - Implementing non-linear and color interpolators - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 3\ :raw-html:`
`\ (04-07-2022) - Redesigning the API,\ :raw-html:`
` Implementing cubic Bezier Interpolator,\ :raw-html:`
` and making progress on the GPU side! - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 4\ :raw-html:`
`\ (11-07-2022) - Camera animation, :raw-html:`
`\ interpolation in GLSL, and a single Timeline! - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 5\ :raw-html:`
`\ (19-07-2022) - Slerp implementation, :raw-html:`
`\ documenting the Timeline, and adding unit tests - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 6\ :raw-html:`
`\ (25-07-2022) - Fixing the Timeline issues and equipping it with\ :raw-html:`
` more features - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 7\ :raw-html:`
`\ (01-08-2022) - Billboard spheres and implementing interpolators\ :raw-html:`
` using closures - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 8\ :raw-html:`
`\ (09-08-2022) - Back to the shader-based version of the Timeline - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 9\ :raw-html:`
`\ (16-08-2022) - Animating primitives of the same actor - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 10\ :raw-html:`
`\ (23-08-2022) - Supporting hierarchical animating - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 11\ :raw-html:`
`\ (30-08-2022) - Improving tutorials a little - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 12\ :raw-html:`
`\ (7-09-2022) - Adding new tutorials - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ * - Week 13\ :raw-html:`
`\ (20-09-2022) - Keyframes animation is now a bit easier in FURY - - `FURY `_ - `Python `_ + - `FURY `__ - `Python `__ diff --git a/docs/source/posts/2023/2023-01-29-final-report-shivam.rst b/docs/source/posts/2023/2023-01-29-final-report-shivam.rst index 4e4b5bbac..92fc97639 100644 --- a/docs/source/posts/2023/2023-01-29-final-report-shivam.rst +++ b/docs/source/posts/2023/2023-01-29-final-report-shivam.rst @@ -25,8 +25,7 @@ Google Summer of Code Final Work Product - **Name:** Shivam Anand - **Organisation:** Python Software Foundation - **Sub-Organisation:** FURY -- **Project:** `FURY - glTF - Integration `__ +- **Project:** `FURY - glTF Integration `__ Proposed Objectives @@ -88,7 +87,7 @@ Exporting Scene as a glTF ************************* -The fury scene can contain multiple objects such as actors, cameras, +The FURY scene can contain multiple objects such as actors, cameras, textures, etc. We need to get the primitive information (such as Vertices, Triangles, UVs, Normals, etc.) from these objects and store them into a ``.bin`` file. Added methods that export these @@ -260,55 +259,36 @@ GSoC weekly blogs Timeline -------- - -.. list-table:: - :header-rows: 1 - - * - Date - - Description - - Blog Post Link - * - Week 0\ :raw-html:`
`\ (24-05-2022) - - My journey to GSoC 2022 - - `FURY `_ - `Python `_ - * - Week 1\ :raw-html:`
`\ (20-06-2022) - - A basic glTF Importer - - `FURY `_ - `Python `_ - * - Week 2\ :raw-html:`
`\ (29-06-2022) - - Improving Fetcher and Exporting glTF - - `FURY `_ - `Python `_ - * - Week 3\ :raw-html:`
`\ (04-07-2022) - - Fixing fetcher adding tests and docs - - `FURY `_ - `Python `_ - * - Week 4\ :raw-html:`
`\ (12-07-2022) - - Finalizing glTF loader - - `FURY `_ - `Python `_ - * - Week 5\ :raw-html:`
`\ (19-07-2022) - - Creating PR for glTF exporter and fixing the loader - - `FURY `_ - `Python `_ - * - Week 6\ :raw-html:`
`\ (25-07-2022) - - Extracting the animation data - - `FURY `_ - `Python `_ - * - Week 7\ :raw-html:`
`\ (01-08-2022) - - Fixing bugs in animations - - `FURY `_ - `Python `_ - * - Week 8\ :raw-html:`
`\ (09-08-2022) - - Fixing animation bugs - - `FURY `_ - `Python `_ - * - Week 9\ :raw-html:`
`\ (17-08-2022) - - First working skeletal animation prototype - - `FURY `_ - `Python `_ - * - Week 10\ :raw-html:`
`\ (25-08-2022) - - Multi-node skinning support - - `FURY `_ - `Python `_ - * - Week 11\ :raw-html:`
`\ (31-08-2022) - - Multiple transformations support and adding tests - - `FURY `_ - `Python `_ - * - Week 12\ :raw-html:`
`\ (08-09-2022) - - Adding skeleton as actors and fix global transformation - - `FURY `_ - `Python `_ - * - Week 13\ :raw-html:`
`\ (15-09-2022) - - Multi bone skeletal animations - - `FURY `_ - `Python `_ - * - Week 14\ :raw-html:`
`\ (28-09-2022) - - Morphing is here ! - - `FURY `_ - `Python `_ ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Post Link | ++======================+===========================================================+===========================================================================================================================================================================================================+ +| Week 0 (24-05-2022) | My journey to GSoC 2022 | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 1 (20-06-2022) | A baic glTF Importer | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 2 (29-06-2022) | Improving Fetcher and Exporting glTF | `FURY `__ - `Python Blogs `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3 (04-07-2022) | Fixing fetcher adding tests and docs | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4 (12-07-2022) | Finalizing glTF loader | `FURY `__ -`Python`__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5 (19-07-2022) | Creating PR for glTF exporter and fixing the loader | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6 (25-07-2022) | Extracting the animation data | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7 (01-08-2022) | Fixing bugs in animations | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8 (09-08-2022) | Fixing animation bugs | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9 (17-08-2022) | First working skeletal animation prototype | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10 (25-08-2022) | Multi-node skinning support | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11 (31-08-2022) | Multiple transformations support and adding tests | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 12 (08-09-2022) | Adding skeleton as actors and fix global transformation | `FURY `__ - `Python `__| ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 13 (15-09-2022) | Multi bone skeletal animations | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 14 (28-09-2022) | Morphing is here ! | `FURY `__ - `Python `__ | ++----------------------+-----------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/source/posts/2023/2023-06-26-week-4-joaodellagli.rst b/docs/source/posts/2023/2023-06-26-week-4-joaodellagli.rst index 151b1c719..5fa694354 100644 --- a/docs/source/posts/2023/2023-06-26-week-4-joaodellagli.rst +++ b/docs/source/posts/2023/2023-06-26-week-4-joaodellagli.rst @@ -12,7 +12,7 @@ Welcome again to another weekly blogpost! Today, let's talk about the importance Last Week's Effort ----------------------- So, last week my project was struggling with some supposedly simple in concept, yet intricate in execution issues. If you recall from -my :doc:`last blogpost <2023-06-19-week-3-joaodellagli>`, I could not manage to make the Framebuffer Object setup work, as its method, +my :ref:`last blogpost <2023-06-19-week-3-joaodellagli>`, I could not manage to make the Framebuffer Object setup work, as its method, ``SetContext()``, wasn't being able to generate the FBO inside OpenGL. Well, after some (more) research about that as I also dived in my plan B, that involved studying numba as a way to accelerate a data structure I implemented on my PR `#783 `_, me and one of my mentors decided we needed a pair programming session, that finally happened on thursday. After that session, @@ -34,11 +34,13 @@ Apparently, for the FBO generation to work, it is first needed to initialize the This simple missing line of code was responsible for ending weeks of suffer, as after that, I called: + :: print("FBO of index:", FBO.GetFBOIndex()) print("Number of color attachments:", FBO.GetNumberOfColorAttachments()) That outputted: + :: FBO of index: 4 Number of color attachments: 1 diff --git a/docs/source/posts/2023/2023-06-27-week-4-tvcastillod.rst b/docs/source/posts/2023/2023-06-27-week-4-tvcastillod.rst index 5fd4e8735..00a8811cb 100644 --- a/docs/source/posts/2023/2023-06-27-week-4-tvcastillod.rst +++ b/docs/source/posts/2023/2023-06-27-week-4-tvcastillod.rst @@ -17,7 +17,7 @@ I made a second PR with the implementation of DTI uncertainty calculation and vi :width: 530 :align: center -I had to use some **dipy** functions, specifically: `estimate_sigma `_ for the noise variance calculation, `design_matrix `_ to get the b-matrix, and `tensor_prediction `_ for the signal estimation. The details of this calculations can be found `here `_. +I had to use some **DIPY** functions, specifically: `estimate_sigma `_ for the noise variance calculation, `design_matrix `_ to get the b-matrix, and `tensor_prediction `_ for the signal estimation. The details of this calculations can be found `here `_. What is coming up next? ----------------------- diff --git a/docs/source/posts/2023/2023-07-03-week-5-joaodellagli.rst b/docs/source/posts/2023/2023-07-03-week-5-joaodellagli.rst index 65236da69..bb00a0201 100644 --- a/docs/source/posts/2023/2023-07-03-week-5-joaodellagli.rst +++ b/docs/source/posts/2023/2023-07-03-week-5-joaodellagli.rst @@ -12,7 +12,7 @@ Hello everyone, time for another weekly blogpost! Today, we will talk about taki Last Week's Effort ------------------ After having the FBO properly set up, the plan was to finally *render* something to it. Well, I wished for a less bumpy road -at my :doc:`last blogpost <2023-06-26-week-4-joaodellagli>` but as in this project things apparently tend to go wrong, +at my :ref:`last blogpost <2023-06-26-week-4-joaodellagli>` but as in this project things apparently tend to go wrong, of course the same happened with this step. diff --git a/docs/source/posts/2023/2023-07-10-week-6-joaodellagli.rst b/docs/source/posts/2023/2023-07-10-week-6-joaodellagli.rst index 0cce36b45..7deb2db06 100644 --- a/docs/source/posts/2023/2023-07-10-week-6-joaodellagli.rst +++ b/docs/source/posts/2023/2023-07-10-week-6-joaodellagli.rst @@ -9,9 +9,11 @@ Week 6: Things are Starting to Build Up Hello everyone, time for a other weekly blogpost! Today, I will show you my current progress on my project and latest activities. +W What I did Last Week -------------------- -Last week I had the goal to implement KDE rendering to the screen (if you want to understand what this is, check my :doc:`last blogpost <2023-07-03-week-5-joaodellagli>`_). + +Last week I had the goal to implement KDE rendering to the screen (if you want to understand what this is, check my :ref:`last blogpost <2023-07-03-week-5-joaodellagli>`). After some days diving into the code, I finally managed to do it: .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/buffer_compose.png @@ -29,6 +31,7 @@ to this week, so I had limited time to polish my code, which I plan to do better Where the Problem Was --------------------- + The KDE render basically works rendering the KDE of a point to a texture and summing that texture to the next render. For this to work, the texture, rendered to a billboard, needs to be the same size of the screen, otherwise the captured texture will include the black background. The problem I faced with that is that the billboard scaling isn't exactly well defined, so I had to guess for a fixed screen size @@ -52,6 +55,7 @@ to use the right texture coordinates and finally render the results you see abov This Week's Goals ----------------- + For this week, I plan to try a different approach Filipi, one of my mentors, told me to do. This approach was supposed to be the original one, but a communication failure lead to this path I am currently in. This approach renders each KDE calculation into its own billboard, and those are rendered together with additive blending. After this first pass, this render is captured into a texture and then rendered to diff --git a/docs/source/posts/2023/2023-07-17-week-7-tvcastillod.rst b/docs/source/posts/2023/2023-07-17-week-7-tvcastillod.rst index 99bff5fec..5c47506bd 100644 --- a/docs/source/posts/2023/2023-07-17-week-7-tvcastillod.rst +++ b/docs/source/posts/2023/2023-07-17-week-7-tvcastillod.rst @@ -9,14 +9,14 @@ Week 7: Adjustments on the Uncertainty Cones visualization What did I do this week? ------------------------ -I was told to refactor some parts of the uncertainty PR, since I was relying too much on **dipy** functions which is not good because it makes maintenance more difficult as **dipy** requires **FURY** for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function. +I was told to refactor some parts of the uncertainty PR, since I was relying too much on **DIPY** functions which is not good because it makes maintenance more difficult as **DIPY** requires **FURY** for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function. I also continued working on the ellipsoid tutorial, which I hope to finish this week so that I can ask for a first revision. What is coming up next? ----------------------- -I will finish defining some details of the tutorial so that it is ready for review, and now I will start working on the tutorial related to the uncertainty, while I receive feedback on the other PRs. Also, as preparation for the next step I will start exploring on how to address visualization of spherical harmonics for ODF glyphs visualization, I found that a previous GSoC participant at FURY started working on that and also did several work with raymarching and SDF (:doc:`here is a summary of the work <../2020/2020-08-24-final-work-lenix>`), so I will take a deeper look on that to see if I can get something useful I can start with. +I will finish defining some details of the tutorial so that it is ready for review, and now I will start working on the tutorial related to the uncertainty, while I receive feedback on the other PRs. Also, as preparation for the next step I will start exploring on how to address visualization of spherical harmonics for ODF glyphs visualization, I found that a previous GSoC participant at FURY started working on that and also did several work with raymarching and SDF (:doc:`here is a summary of the work <../2020/2020-08-24-final-work-lenix>`_), so I will take a deeper look on that to see if I can get something useful I can start with. Did I get stuck anywhere? ------------------------- diff --git a/docs/source/posts/2023/2023-07-24-week-8-joaodellagli.rst b/docs/source/posts/2023/2023-07-24-week-8-joaodellagli.rst index e74031109..ba0ad6f41 100644 --- a/docs/source/posts/2023/2023-07-24-week-8-joaodellagli.rst +++ b/docs/source/posts/2023/2023-07-24-week-8-joaodellagli.rst @@ -21,7 +21,7 @@ on how could this work, reaching two options: The first one would have the advantage of being simple and pretty straightforward, as a user would only need to call the actor and have it working on their hands, having the tradeoff of leaving some important steps for a clean API hidden and static. These steps I mention -are related to how this rendering works, as I have previously :doc:`showed you <2023-07-03-week-5-joaodellagli>`, it relies on post-processing effects, +are related to how this rendering works, as I have previously :ref:`showed you <2023-07-03-week-5-joaodellagli>`, it relies on post-processing effects, which need an offscreen rendering, that for example are done by the *callback functions*. In short, these functions are instructions the user gives to the interactor to run inside the interaction loop. Inside FURY there are tree diff --git a/docs/source/posts/2023/2023-07-31-week-9-joaodellagli.rst b/docs/source/posts/2023/2023-07-31-week-9-joaodellagli.rst index 90605dcc3..511c3cf86 100644 --- a/docs/source/posts/2023/2023-07-31-week-9-joaodellagli.rst +++ b/docs/source/posts/2023/2023-07-31-week-9-joaodellagli.rst @@ -71,7 +71,7 @@ That outputted the following (beautiful) results for a set of 1000 random points The third one is still being a trickier challenge. If you recall from my first blogposts, I spent something around *one month* trying to setup float framebuffer objects to FURY with VTK so I could use them in my project. After spending all of that time with no results, -me and Bruno, my mentor, :doc:`found a way <2023-07-03-week-5-joaodellagli.rst>` to do what we wanted to do, but using a different VTK class, +me and Bruno, my mentor, :ref:`found a way <2023-07-03-week-5-joaodellagli>` to do what we wanted to do, but using a different VTK class, `vtkWindowToImageFilter `_. Well, it was a good workaround back then and it lead me all the way here, however now it is costing a price. The float framebuffers were an important part of the project because they would allow us to pass *32-bit float information* from one shader to another, which would be important as they would allow the densities to diff --git a/docs/source/posts/2023/2023-08-14-week-11-joaodellagli.rst b/docs/source/posts/2023/2023-08-14-week-11-joaodellagli.rst index e3dc59bf1..9fbf55051 100644 --- a/docs/source/posts/2023/2023-08-14-week-11-joaodellagli.rst +++ b/docs/source/posts/2023/2023-08-14-week-11-joaodellagli.rst @@ -11,7 +11,8 @@ I was working on with my mentors. Last Week's Effort ------------------ -As I shared with you :doc:`last week <2023-08-07-week-10-joaodellagli>`, the first draft of my API was finally ready for review, as + +As I shared with you :ref:`last week <2023-08-07-week-10-joaodellagli>`, the first draft of my API was finally ready for review, as I finished tweaking some remaining details missing. I was tasked with finding a good example of the usage of the tools we proposed, and I started to do that, however after testing it with some examples, I figured out some significant bugs were to be fixed. Also, after some reviews and hints from some of my mentors and other GSoC contributors, we realised that some refactoring should be done, @@ -19,6 +20,7 @@ mainly focused on avoiding bad API usage from the user. So how did it go? ----------------- + Initially, I thought only one bug was the source of the issues the rendering presented, but it turned out to be two, which I will explain further. @@ -80,6 +82,7 @@ parameters passed. This Week's Goals ----------------- + Having that refactoring made, now I am awaiting for a second review so we could finally wrap it up and merge the first stage of this API. With that being done, I will write the final report and wrap this all up. diff --git a/docs/source/posts/2023/2023-08-16-week-11-tvcastillod.rst b/docs/source/posts/2023/2023-08-16-week-11-tvcastillod.rst index 503fbed41..76c88ed6c 100644 --- a/docs/source/posts/2023/2023-08-16-week-11-tvcastillod.rst +++ b/docs/source/posts/2023/2023-08-16-week-11-tvcastillod.rst @@ -9,7 +9,7 @@ Week 11 : Adjusting ODF implementation and looking for solutions on issues found What did I do this week? ------------------------ -I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients :math:`a^l_m` part of the function :math:`f(\theta, \phi)` described `here `_. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in `this paper `_, which is labeled in *dipy* as *descoteaux07*. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4. +I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients :math:`a^l_m` part of the function :math:`f(\theta, \phi)` described `here `_. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in `this paper `_, which is labeled in *DIPY* as *descoteaux07*. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4. .. image:: https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png :width: 600 @@ -24,7 +24,7 @@ For now, there are 3 things I will continue to work on: - The color and lighting. As these objects present curvatures with quite a bit of detail in some cases, this is something that requires more specific lighting work, in addition to having now not only one color but a color map. - The scaling. This is something I still don't know how to deal with. I had to adjust it manually for now, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled, or maybe there is a proper way to pre-process this data before passing it to the shaders to get the right result at once. -- How to pass the information of the coefficients efficiently. Right now I'm creating one actor per glyph since I'm using a uniform array to pass the coefficients, but the idea is to pass all the data at once. I found several ideas `here `_ of how to pass a list of values to the fragment shader directly, I just need to explore deeper how this can be done on **FURY**, and see which option is most suitable. +- How to pass the information of the coefficients efficiently. Right now I'm creating one actor per glyph since I'm using a uniform array to pass the coefficients, but the idea is to pass all the data at once. I found several ideas `ideas here `_ of how to pass a list of values to the fragment shader directly, I just need to explore deeper how this can be done on **FURY**, and see which option is most suitable. Did I get stuck anywhere? ------------------------- diff --git a/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst b/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst index 33650149a..b1842bffd 100644 --- a/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst +++ b/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst @@ -71,7 +71,7 @@ Objectives Completed properly, as some details seemed to be missing from the documentation, and asking the community haven't solved the problem as well. Reporting that to my mentors, which unsuccessfully tried themselves to make it work, they decided it was better if another path was taken, using `VTK's WindowToImageFilter `_ method as a workaround, described - in this `blogpost `_. This method helped the development of + in `my week5 blogpost `_. This method helped the development of three new functions to FURY, *window_to_texture()*, *texture_to_actor()* and *colormap_to_texture()*, that allow the passing of different kinds of textures to FURY's actor's shaders, the first one to capture a window and pass it as a texture to an actor, the second one to pass an external texture to an actor, and the third one to specifically pass a colormap as a texture to an @@ -160,6 +160,7 @@ Objectives Completed encapsulated inside the *ÈffectManager.kde()* method. It had the following look: .. code-block:: python + from fury.effect_manager import EffectManager from fury import window @@ -334,27 +335,27 @@ Timeline +=====================+====================================================+===========================================================================================================================================================================================================+ | Week 0 (29-05-2023) | The Beginning of Everything | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 1 (05-06-2022) | The FBO Saga | `FURY `__ - `Python `__ | +| Week 1 (05-06-2023) | The FBO Saga | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 2 (12-06-2022) | The Importance of (good) Documentation | `FURY `__ - `Python `__ | +| Week 2 (12-06-2023) | The Importance of (good) Documentation | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 3 (19-06-2022) | Watch Your Expectations | `FURY `__ - `Python `__ | +| Week 3 (19-06-2023) | Watch Your Expectations | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 4 (26-06-2022) | Nothing is Ever Lost | `FURY `__ - `Python `__ | +| Week 4 (26-06-2023) | Nothing is Ever Lost | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 5 (03-07-2022) | All Roads Lead to Rome | `FURY `__ - `Python `__ | +| Week 5 (03-07-2023) | All Roads Lead to Rome | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 6 (10-07-2022) | Things are Starting to Build Up | `FURY `__ - `Python `__ | +| Week 6 (10-07-2023) | Things are Starting to Build Up | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 7 (17-07-2022) | Experimentation Done | `FURY `__ - `Python `__ | +| Week 7 (17-07-2023) | Experimentation Done | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 8 (24-07-2022) | The Birth of a Versatile API | `FURY `__ - `Python `__ | +| Week 8 (24-07-2023) | The Birth of a Versatile API | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 9 (31-07-2022) | It is Polishing Time! | `FURY `__ - `Python `__ | +| Week 9 (31-07-2023) | It is Polishing Time! | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 10 (07-08-2022)| Ready for Review! | `FURY `__ - `Python `__ | +| Week 10 (07-08-2023)| Ready for Review! | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 11 (14-08-2022)| A Refactor is Sometimes Needed | `FURY `__ - `Python `__ | +| Week 11 (14-08-2023)| A Refactor is Sometimes Needed | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Week 12 (21-08-2022)| Now That is (almost) a Wrap! | `FURY `__ - `Python `__ | +| Week 12 (21-08-2023)| Now That is (almost) a Wrap! | `FURY `__ - `Python `__ | +---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/source/posts/2023/2023-08-21-week-12-joaodellagli.rst b/docs/source/posts/2023/2023-08-21-week-12-joaodellagli.rst index 3f8289135..3fc1c7b5f 100644 --- a/docs/source/posts/2023/2023-08-21-week-12-joaodellagli.rst +++ b/docs/source/posts/2023/2023-08-21-week-12-joaodellagli.rst @@ -28,12 +28,15 @@ Using that, I could set the typedhint of the `bandwidth` variable to `float` and So how did it go? ----------------- + All went fine with no difficult at all, thankfully. + The Next Steps -------------- + My next plans are, after having PR `#826 `_ merged, to work on the float encoding issue described in -:doc:`this blogpost<2023-07-31-week-9-joaodellagli>`. Also, I plan to tackle the UI idea once again, to see if I can finally give the user +:ref:`this blogpost <2023-07-31-week-9-joaodellagli>` . Also, I plan to tackle the UI idea once again, to see if I can finally give the user a way to control the intensities of the distributions. Wish me luck! diff --git a/docs/source/posts/2023/2023-08-24-final-report-tvcastillod.rst b/docs/source/posts/2023/2023-08-24-final-report-tvcastillod.rst index a1d730e1b..0b4bb04a1 100644 --- a/docs/source/posts/2023/2023-08-24-final-report-tvcastillod.rst +++ b/docs/source/posts/2023/2023-08-24-final-report-tvcastillod.rst @@ -96,14 +96,14 @@ The implementation is almost complete, but as it is a new addition that includes - **DTI uncertainty visualization (Under Review)** https://github.com/fury-gl/fury/pull/810 -**Future work:** A tutorial will be made explaining in more detail how to calculate the parameters needed for the uncertainty cones using **dipy** functions, specifically: `estimate_sigma `_ for the noise variance calculation, `design_matrix `_ to get the b-matrix, and `tensor_prediction `_ for the signal estimation. Additionally, when the ODF implementation is complete, uncertainty for this other reconstruction model is expected to be added, using semitransparent glyphs representing the mean directional information proposed by Tournier [3]_. +**Future work:** A tutorial will be made explaining in more detail how to calculate the parameters needed for the uncertainty cones using **DIPY** functions, specifically: `estimate_sigma `_ for the noise variance calculation, `design_matrix `_ to get the b-matrix, and `tensor_prediction `_ for the signal estimation. Additionally, when the ODF implementation is complete, uncertainty for this other reconstruction model is expected to be added, using semitransparent glyphs representing the mean directional information proposed by Tournier [3]_. ODF actor implemented with SDF ****************************** HARDI-based techniques require more images than DTI, however, they model the diffusion directions as probability distribution functions (PDFs), and the fitted values are returned as orientation distribution functions (ODFs). ODFs are more diffusion sensitive than the diffusion tensor and, therefore, can determine the structure of multi-directional voxels very common in the white matter regions of the brain [3]_. The current actor to display this kind of glyphs is the ``odf_slicer`` which, given an array of spherical harmonics (SH) coefficients renders a grid of ODFs, which are created from a sphere with a specific number of vertices that fit the data. -For the application of this model using the same SDF ray marching techniques, we need the data of the SH coefficients, which are used to calculate the orientation distribution function (ODF) described `here `_. Different SH bases can be used, but for this first approach we focus on ``descoteaux07`` (as labeled in dipy). After performing the necessary calculations, we obtain an approximate result of the current implementation of FURY, as seen below. +For the application of this model using the same SDF ray marching techniques, we need the data of the SH coefficients, which are used to calculate the orientation distribution function (ODF) described `here `_. Different SH bases can be used, but for this first approach we focus on ``descoteaux07`` (as labeled in DIPY). After performing the necessary calculations, we obtain an approximate result of the current implementation of FURY, as seen below. .. image:: https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png :width: 580 diff --git a/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst b/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst index f2b483c71..39535876d 100644 --- a/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst +++ b/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst @@ -47,6 +47,7 @@ Objectives Completed The ``SpinBoxUI`` element is essential for user interfaces as it allows users to pick a numeric value from a set range. While we had an active pull request (PR) to add this element, updates in the main code caused conflicts and required further changes for added features. At one point, we noticed that text alignment wasn't centered properly within the box due to a flaw. To fix this, we began a PR to adjust the alignment, but it turned into a larger refactoring of the ``TextBlock2D``, a core component connected to various parts. This was a complex task that needed careful handling. After sorting out the ``TextBlock2D``, we returned to the ``SpinBoxUI`` and made a few tweaks. Once we were confident with the changes, the PR was successfully merged after thorough review and testing. **Pull Requests:** + - **SpinBoxUI (Merged)** - https://github.com/fury-gl/fury/pull/499 .. image:: https://user-images.githubusercontent.com/64432063/263165327-c0b19cdc-9ebd-433a-8ff1-99e706a76508.gif @@ -76,6 +77,7 @@ Objectives Completed For more detailed insights into the individual steps and nuances of this process, you can refer to the comprehensive weekly blog post provided below. It delves into the entire journey of this ``TextBlock2D`` refactoring effort. **Pull Requests:** + - **Fixing Justification Issue - 1st Draft (Closed)** - https://github.com/fury-gl/fury/pull/790 - **Adding BoundingBox and fixing Justificaiton (Merged)** - https://github.com/fury-gl/fury/pull/803 - **Adding getters and setter for properties (Merged)** - https://github.com/fury-gl/fury/pull/830 @@ -113,6 +115,7 @@ Other Objectives There was an issue with the ``ComboBox2D`` functionality, where adding it to a ``TabUI`` caused all elements to open simultaneously, which shouldn't be the case. I tested various PRs addressing this problem and identified a suitable solution. I then helped the lead in reviewing the PR that fixed the issue, which was successfully merged. **Pull Requests:** + - **CardUI (Merged)** - https://github.com/fury-gl/fury/pull/398 - **ComboBox Flaw (Merged)** - https://github.com/fury-gl/fury/pull/768 @@ -123,9 +126,11 @@ Other Objectives - **Updating Broken Website Links:** + I addressed an issue with malfunctioning links in the Scientific Section of the website. The problem emerged from alterations introduced in PR `#769 `_. These changes consolidated demos and examples into a unified "auto_examples" folder, and a toml file was utilized to retrieve this data and construct examples. However, this led to challenges with the paths employed in website generation. My responsibility was to rectify these links, ensuring they accurately direct users to the intended content. **Pull Requests:** + - **Updating Broken Links (Merged)** - https://github.com/fury-gl/fury/pull/820 @@ -133,9 +138,11 @@ Objectives in Progress ---------------------- - **FileDialogUI:** + An existing ``FileDialog`` PR by Soham (`#294 `_) was worked upon. The primary task was to rebase the PR to match the current UI structure, resolving compatibility concerns with the older base. In PR `#832 `_, we detailed issues encompassing resizing ``FileDialog`` and components, addressing text overflow, fixing ``ZeroDivisionError``, and correcting ``ListBox2D`` item positioning. The PR is complete with comprehensive testing and documentation. Presently, it's undergoing review, and upon approval, it will be prepared for integration. **Pull Requests:** + - **Soham's FileDialog (Closed)** - https://github.com/fury-gl/fury/pull/294 - **FileDialogUI (Under Review)** - https://github.com/fury-gl/fury/pull/832 @@ -147,9 +154,11 @@ Objectives in Progress - **TreeUI:** + Continuing Antriksh's initial PR for ``TreeUI`` posed some challenges. Antriksh had set the foundation, and I picked up from there. The main issue was with the visibility of TreeUI due to updates in the ``set_visibility`` method of ``Panel2D``. These updates affected how ``TreeUI`` was displayed, and after investigating the actors involved, it was clear that the visibility features had changed. This took some time to figure out, and I had a helpful pair programming session with my mentor, Serge, to narrow down the problem. Now, I've updated the code to address this issue. However, I'm still a bit cautious about potential future problems. The PR is now ready for review. **Pull Requests:** + - **TreeUI (In Progress)** - https://github.com/fury-gl/fury/pull/821 @@ -167,49 +176,32 @@ GSoC Weekly Blogs Timeline -------- -.. list-table:: - :widths: 40 40 20 - :header-rows: 1 - - * - Date - - Description - - Blog Post Link - * - Week 0 (27-05-2023) - - Community Bounding Period - - `FURY `_ - `Python `_ - * - Week 1 (03-06-2023) - - Working with SpinBox and TextBox Enhancements - - `FURY `_ - `Python `_ - * - Week 2 (10-06-2023) - - Tackling Text Justification and Icon Flaw Issues - - `FURY `_ - `Python `_ - * - Week 3 (17-06-2023) - - Resolving Combobox Icon Flaw and TextBox Justification - - `FURY `_ - `Python `_ - * - Week 4 (24-06-2023) - - Exam Preparations and Reviewing - - `FURY `_ - `Python `_ - * - Week 5 (01-07-2023) - - Trying out PRs and Planning Ahead - - `FURY `_ - `Python `_ - * - Week 6 (08-07-2023) - - BoundingBox for TextBlock2D! - - `FURY `_ - `Python `_ - * - Week 7 (15-07-2023) - - Sowing the seeds for TreeUI - - `FURY `_ - `Python `_ - * - Week 8 (22-07-2023) - - Another week with TextBlockUI - - `FURY `_ - `Python `_ - * - Week 9 (29-07-2023) - - TextBlock2D is Finally Merged! - - `FURY `_ - `Python `_ - * - Week 10 (05-08-2023) - - Its time for a Spin-Box! - - `FURY `_ - `Python `_ - * - Week 11 (12-08-2023) - - Bye Bye SpinBox - - `FURY `_ - `Python `_ - * - Week 12 (19-08-2023) - - FileDialog Quest Begins! - - `FURY `_ - `Python `_ ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Post Link | ++=====================+========================================================+========================================================================================================================================================================================================================+ +| Week 0 (27-05-2023) | Community Bounding Period | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------+ +| Week 1 (03-06-2023) | Working with SpinBox and TextBox Enhancements | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------+ +| Week 2 (10-06-2023) | Tackling Text Justification and Icon Flaw Issues | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3 (17-06-2023) | Resolving Combobox Icon Flaw and TextBox Justification | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4 (24-06-2023) | Exam Preparations and Reviewing | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5 (01-07-2023) | Trying out PRs and Planning Ahead | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6 (08-07-2023) | BoundingBox for TextBlock2D! | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7 (15-07-2023) | Sowing the seeds for TreeUI | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8 (22-07-2023) | Another week with TextBlockUI | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9 (29-07-2023) | TextBlock2D is Finally Merged! | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10 (05-08-2023)| Its time for a Spin-Box! | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11 (12-08-2023)| Bye Bye SpinBox | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 12 (19-08-2023)| FileDialog Quest Begins! | `FURY `__ - `Python `__ | ++---------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/source/posts/2024/2024-05-28-first-post-wachiou-bouraima.rst b/docs/source/posts/2024/2024-05-28-week0-wachiou-bouraima.rst similarity index 100% rename from docs/source/posts/2024/2024-05-28-first-post-wachiou-bouraima.rst rename to docs/source/posts/2024/2024-05-28-week0-wachiou-bouraima.rst diff --git a/docs/source/posts/2024/2024-06-06-week-1-robin.rst b/docs/source/posts/2024/2024-06-06-week-1-robin.rst new file mode 100644 index 000000000..c6b5a8495 --- /dev/null +++ b/docs/source/posts/2024/2024-06-06-week-1-robin.rst @@ -0,0 +1,115 @@ +Week 1: It officially begins... +=============================== + +.. post:: June 06 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 1. + +My goal for week 1 was to start with `Retrieval-Augmented Generation (RAG) `_, check different databases and host every endpoint. My week1 and week2 are very intertwined because I applied everything I did during week1 on week2. (I'm writing this blog midway through week2) + +why phi-3-mini-4k-instruct? +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before I detail everything I've done this week, I'll explain why `phi-3 mini 4k `_ was chosen as the LLM, I forgot to mention this in the last blog. Phi-3 is a small 3.8B 4k context model, it means it can work with 4k tokens(similar to words) at a time. Due to its small size, it runs fast both locally and on Huggingface. Performance wise comparatively with other opensource models, it performs decently well. In the `LMSYS LLM leaderboard `_ phi-3 mini 4k comes with an ELO of 1066 (59th position). But it achieves this as a small model. +I also tried Llama3-8B, it performs better than phi-3 mini with an ELO of 1153 and rank 22. But it is considerably slower for inference. Due to this, I chose phi-3 mini for now. + + +Things I did week-1 (and some week2) +------------------------------------ + +1) **Choosing the vector database** + +I decided to choose `Pinecone `_ as the vector DB because it had a very generous free tier. Other options on consideration were `pgvector `_ and `chromadb `_, but they didn't have a free tier. + +2) **PR Submissions and Review** + +I also merged a `PR `_ on FURY which fixes a CI issue. I also spent time doing review of other PRs from my fellow GSoC mates. + +3) **Deciding which embedding model to use** + +A good embedding model is necessary to generate embeddings which we then upsert into the DB. Ollama had embedding model support, but I found the catalogue very small and the models they provided were not powerful enough. Therefore I decided to try using HuggingFace Sentence Transformers. +Sentence Transformers have a very vibrant catalogue of models available of various sizes. I chose `gte-large-en-v1.5 `_ from Alibaba-NLP, an 8k context, 434 million parameter model. It only had a modest memory requirement of 1.62 GB. +Performance wise, it ranks 11th on the `MTEB leaderboard `_. It is a very interesting model due to its size:performance ratio. + +4) **Hosting the embedding model** + +Hosting this sentence-transformer model was confusing. For some reason, the HF spaces were blocking the Python script from writing on ``.cache`` folder. Docker container inside spaces runs with user id 1000 (non-root user), therefore I had to give it permission to download and store files. + +I've hosted 5 gunicorn workers to serve 5 parallel requests at a time. Since the model is small, this is possible. + +5) **Hosting the database endpoint** + +I wrapped the pinecone DB API into an endpoint so it'll be easy to query and receive the results. +It is also configured to accept 5 concurrent requests although I could increase it a lot more. + +I upserted docstrings from ``fury/actor.py`` into the vector DB for testing. So now, whenever you ask a question the model will use some ``actor.py`` function to give you an answer. For now, it could be used like a semantic function search engine. + +I decided to abstract the DB endpoint to reduce the dependency on one provider. We can swap the providers as required and keep all other features running. + +6) **Hosting Discord Bot** + +So with this, all the endpoints are finally online. The bot has some issues, it is going offline midway for some reason. I'll have to see why that happens. + +For some reason, Huggingface spaces decided to not start the bot script. Later a community admin from Huggingface told me to use their official bot implementation as a reference. This is why I had to use threading and gradio to get the bot running (migrating to docker can be done, but this is how they did it and I just took that for now). + +Huggingface spaces need a script to satisfy certain criteria to allow them to run, one of them is a non-blocking I/O on the main loop. So I had to move the discord bot to a new thread. + +Connecting all of them together! +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +So now we have 4 hosted services, all hosted on HuggingFace spaces: + - Discord Bot + - LLM API + - Embeddings API + - Database API + +Now we'll have to connect them all to get an answer to the user query. + +This is the current architecture, there's a lot of room for improvement here. + + + .. raw:: html + + + +The Language Model takes the context and the user query, combines them to form an answer and returns to the user through discord (for now). Maybe moving the core logic from discord bot to a separate node might be good, and connect discord/github/X to that node. +The database takes embeddings and do an Approximate Nearest Neighbor search (a variant of KNN) and returns top-k results (k=3 for now). + + .. raw:: html + + + +What is coming up next week? +---------------------------- + +Answer quality improvements. Also, the discord bot dies randomly, have to fix that also. + +Did you get stuck anywhere? +--------------------------- + +Was stuck in hosting models on Huggingface spaces, fixed it later. + +LINKS: + +- `Discord Bot `_ + +- `Database Repo `_ + +- `Embedding Repo `_ + +- `LLM Repo `_ + +- `Retrieval-Augmented Generation (RAG) `_ +- `phi-3 mini 4k `_ +- `LMSYS LLM leaderboard `_ +- `Pinecone `_ +- `pgvector `_ +- `chromadb `_ +- `PR `_ +- `gte-large-en-v1.5 `_ +- `MTEB leaderboard `_ + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-06-15-week2-wachiou-bouraima.rst b/docs/source/posts/2024/2024-06-15-week2-wachiou-bouraima.rst new file mode 100644 index 000000000..fd87a11c2 --- /dev/null +++ b/docs/source/posts/2024/2024-06-15-week2-wachiou-bouraima.rst @@ -0,0 +1,52 @@ +WEEK 2: Refinements and Further Enhancements +============================================ + +.. post:: June 15, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Hello again, +~~~~~~~~~~~~~ + +Welcome back to my Google Summer of Code (GSoC) 2024 journey! This week has been dedicated to refining and improving the work done so far, with a particular focus on the keyword_only decorator. + + +Renaming and Updating the Decorator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This week, I've updated `this Pull Request `_ by renaming the ``keyword_only`` decorator to ``warn_on_args_to_kwargs`` for greater clarity. The updated decorator now includes version parameters from_version and until_version. This enhancement ensures that the decorator will raise a RuntimeError if the current version of FURY is greater than until_version. + + +Peer Code Review +~~~~~~~~~~~~~~~~~ + +I also spent time reviewing `Kaustav Deka's `_ code. This exercise remains rewarding, as it helps me understand different coding styles and approaches. Constructive feedback and suggestions from my classmates were invaluable, not only in helping my teammates but also in improving my own coding and reviewing skills. + + +Research into lazy loading +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In parallel, I started researching the lazy loading feature and thinking about how to implement it. This feature will optimize performance by loading resources only when they're needed, which is crucial to improving the efficiency of FURY's code base. + + +Acknowledgements +~~~~~~~~~~~~~~~~ + +I am deeply grateful to my classmates `Iñigo Tellaetxe Elorriaga `_, `Robin Roy `_, and `Kaustav Deka `_ for their insightful suggestions and comments on my work. +Special thanks to my mentor, `Serge Koudoro `_, whose guidance and support enabled me to meet the challenges of this project. +Their combined efforts have greatly contributed to my progress, and I appreciate their continued help. + + +What happens next? +~~~~~~~~~~~~~~~~~~ + +For week 3, I plan to : + +- Ensure that the ``warn_on_args_to_kwargs`` decorator is applied consistently in all necessary functions. +- Continue to update the calling of these functions in the code to maintain consistency and avoid warnings. +- Refine decorator as necessary based on feedback and testing. +- Start implementing lazy loading functionality based on my research to optimize performance. + + +🥰 Thank you for taking the time to follow my progress. Your feedback is always welcome and I look forward to sharing more updates with you next week. diff --git a/docs/source/posts/2024/2024-06-16-week-2-robin.rst b/docs/source/posts/2024/2024-06-16-week-2-robin.rst new file mode 100644 index 000000000..cfcb5235b --- /dev/null +++ b/docs/source/posts/2024/2024-06-16-week-2-robin.rst @@ -0,0 +1,79 @@ +Week 2: The first iteration! +============================ + +.. post:: June 16 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 2. + +My goal for week 2 was to connect everything and make a prototype. So now we have a bot working 24x7 to answer all your doubts :) + +Apart from the things mentioned in my `week 1 blog `_, the things I did in week 2 are basically: + - Chunking the files for embedding. + - Upserting the chunks into the database. + - Connecting everything together. + - Making the discord bot async. + - Merging a PR. + +1) **Chunking the files for embedding** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the context of building LLM-related applications, chunking is the process of breaking down large pieces of text into smaller segments. It's an essential technique that helps optimize the relevance of the content we get back from a vector database once we use an embedding model to embed content. For our case with FURY, our data is entirely code. So one approach I tried was to take docstrings and the function/class signature. + +I used a naive parser during week 2, which used a combination of regex and common pattern matching to do this splitting. Later my mentors `Mohamed `_ and `Serge `_ told me to use a better approach, using the python ``inspect`` module. + +Another thing to consider was the chunk size. It is shown that smaller chunks outperform larger chunks. This can be intuitively thought of like this: An embedding model can compress a smaller text to 1024 vectors without much data loss compared to compressing a larger text to 1024 vectors. + +This also introduces another important issue, we need a way to test it based on our model. So we need benchmarking. + + +2) **Upserting chunks into the database** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +I upserted all the chunks into the database, along with the vectors I gave metadata which was the function signature and docstrings. Later in week 3, we'll modify this to show links instead of the big wall of text. + + +3) **Connecting everything together** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +I took the 4 key parts - Discord Bot, LLM API, Embeddings API and the Database API and connected them together. This was explained on the `week 1 blog `_ itself. + + +4) **Making the Discord Bot async** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One of the biggest challenges I faced this week was to get everything running properly. LLM output takes a lot of time to generate (we'll fix this amazingly well in week 3 BTW). +I made a big mistake, I used ``requests`` library to do the REST API calls. It occurred to me later that it is synchronous and does blocking calls. This was the reason my Discord bot was dying randomly. I fixed it by migrating to ``aiohttp``. + +This also made me realize I can use async in a lot of other places. A lot of these tasks are I/O bound. If I make them async we might be able to take many more concurrent requests. + +5) **Merging a PR** +~~~~~~~~~~~~~~~~~~~ + +I merged a `PR `_ which modifies `.gitignore`. I found this while generating the Sphinx docs. + + +What is coming up next week? +---------------------------- + +- A faster LLM inference. +- Better pipeline for data collection. +- Links for citation. + +Did you get stuck anywhere? +--------------------------- + +Took me some time to realize I was using synchronous code inside async. Fixed it later. + + +LINKS: + +- `Week 1 Blog `_ +- `PR `_ +- `Serge Koudoro `_ +- `Mohamed Abouagour `_ +- `Robin :) `_ + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-06-16-week-3-robin.rst b/docs/source/posts/2024/2024-06-16-week-3-robin.rst new file mode 100644 index 000000000..ba6c2e2e9 --- /dev/null +++ b/docs/source/posts/2024/2024-06-16-week-3-robin.rst @@ -0,0 +1,82 @@ +Week 3: Data Data Data! +======================= + +.. post:: June 16 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 3. + +My goal for week 3 was to collect data more efficiently and improve the citations. I also had my mid-terms during this week so I had to get things done fast. + +Things I did in week 3 +---------------------- + +1) **A better data parsing technique** + +My initial approach was naive, it was just regex and some common filtrations. Later, my mentors told me to use the `inspect` module. I studied that module and realized that I needed to parse data using an AST. I didn't use the `inspect` module to do the parsing, since I only had to get the function/class signature and docstrings. So instead I used the ``ast`` module from python stdlib. My mentors gave me the general direction to go through - which was using ASTs to parse data effectively. + +So now we have a script which you run like `python extractor.py fury` and it'll generate the appropriate JSON files. + +`{"path": "../..", "function/class name": "name", "docstring": "..", "class_methods": ["method1", "..."]}` + +I also changed the upserting chunk format. Earlier it was just strings, now it is JSON (same thing above). I do not have a scientific reason for this, but empirically it looks like it helped. Benchmarking is something I'm planning to do next week. + +Metadata format: + +`metadata: {"path": "../..", "function/class name": "name", "docstring": "..", "methods": [(method1, docstring), (method2, docstring), ...]}` + +2) **Links for citation** + +Now the bot shows links for citations. Because of the new parsing, I was able to do that pretty efficiently. + +.. image:: /_static/images/gsoc-robin-3-fury-discord-bot-references-url.jpg + :alt: Link based references for the LLM output. + + +3) **Faster Inference** + +So this is something about the Generative AI field. There are too many things happening you might miss some stuff. `Groq` is a company providing free APIs for the llama and other opensource models (free for now, at least). Its inference speed is also super high. So I decided to integrate that also into our infrastructure. +Since everything is a microservice in our architecture, it is easy to add new things. + +Our architecture: + .. raw:: html + + + +So now, along with Ollama, we have Groq inference also. I aim to make a `router` so that we can swap different providers as required. I'm also very interested in integrating Google Gemini 1.5 Flash and other models. Groq does not support fine-tuning, but Flash supports it and is `free of cost `_ (for now). Our architecture is platform agnostic, so we can try out different things without being locked into any of them. We will also fine-tune our phi3 model since we have the data with us. + + .. raw:: html + + + +4) **Dockerizing Discord Bot** + +I earlier used the huggingface implementation (copied their implementation demo). It was bad. My mentors suggested to dockerize the bot so I did that. + + +What is coming up next week? +---------------------------- + +- Benchmarking. Now we have the data, but we need to properly benchmark to see whether the modifications I make every day are making the bot dumber or smarter. +- Study different techniques to improve model answer accuracy such as `HyDE `_. +- Study how to go forward with fine-tuning. +- Improved references. +- Collect more data. + + +Did you get stuck anywhere? +--------------------------- + +No, everything went well this week. Exam preparation was a pain though😢. + +LINKS: + +- `Gemini Blog `_ + +- `HyDE `_ + +- `Robin :) `_ + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-06-26-week3-wachiou-bouraima.rst b/docs/source/posts/2024/2024-06-26-week3-wachiou-bouraima.rst new file mode 100644 index 000000000..cca107b68 --- /dev/null +++ b/docs/source/posts/2024/2024-06-26-week3-wachiou-bouraima.rst @@ -0,0 +1,74 @@ +WEEK 3: Refinements and Further Enhancements +============================================ + +.. post:: June 26, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Hello everyone, +--------------- + +Welcome to the fourth week of my Google Summer of Code (GSoC) 2024 journey! +This week I've been delving into the technical aspects of my project, +focusing on the consistent application of the ``warn_on_args_to_kwargs`` decorator and the initial implementation of lazy loading. + + +Consistent application of ``warn_on_args_to_kwargs`` +---------------------------------------------------- + +This week I continued to apply the decorator to functions. +To ensure consistency across the code base, I audited all functions that could benefit from the ``warn_on_args_to_kwargs`` decorator. +To do this, I had to: + +1. Identify target functions: + + * Identify functions that could benefit from the decorator. + * continue reviewing the code base to identify functions that accept both positional and keyword arguments. + +2. Applying the Decorator: + + * For each identified function, I added the ``warn_on_args_to_kwargs`` decorator. + * Example: + +.. code-block:: python + + @warn_on_args_to_kwargs() + def get_actor_from_primitive( + vertices, + triangles, + *, + colors=None, + normals=None, + backface_culling=True, + prim_count=1, + ): + +3. Updating Unit Tests: + +* updated all the unit tests for the functions where the ``warn_on_args_to_kwargs`` decorator is applied to ensure they respect the new format. +* Example: + +.. code-block:: python + + actr = get_actor_from_primitive(big_verts, big_faces, colors=big_colors) + +- You can find more details and the implementation in my pull request: `https://github.com/fury-gl/fury/pull/888 `_. + + +What Happens Next? +------------------ + +For week 4, I plan to: + +* Continue refining the ``warn_on_args_to_kwargs`` decorator based on feedback from my Peers `Iñigo Tellaetxe Elorriaga `_, `Robin Roy `_, `Kaustav Deka `_, my guide: `Serge Koudoro `_ and the other community members. +* Apply the ``warn_on_args_to_kwargs`` decorator to all the remaining modules and update all the unit tests of these modules too, to respect the desired format. +* Dive deep into the lazy loading functionality based on my research to optimize performance. +* Further engage in code reviews to support my peers and improve our project. + +Did I get stuck? +---------------- + +I didn't get stuck. + +Thank you for following my progress. Your feedback is always welcome. diff --git a/docs/source/posts/2024/2024-06-26-week4-wachiou-bouraima.rst b/docs/source/posts/2024/2024-06-26-week4-wachiou-bouraima.rst new file mode 100644 index 000000000..427695610 --- /dev/null +++ b/docs/source/posts/2024/2024-06-26-week4-wachiou-bouraima.rst @@ -0,0 +1,112 @@ +WEEK 4: Updating Decorator, Exploring Lazy Loading, and Code Reviews +==================================================================== + +.. post:: June 26, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Hello everyone, +--------------- + +Welcome again to my Google summer of code 2024 (GSoC' 2024) journey 2024!. +This week, I focused on updating the ``warn_on_args_to_kwargs`` decorator, applying it across multiple modules, exploring lazy loading, and continuing with code reviews. + + +Updating the ``warn_on_args_to_kwargs`` decorator +------------------------------------------------- + +Based on feedback from my mentor `Serge Koudoro `_ and peers `Iñigo Tellaetxe Elorriaga `_, `Robin Roy `_, `Kaustav Deka `_, I refined the ``warn_on_args_to_kwargs`` decorator and its associated unit tests: + +1. Improvements: + + - Added conditions to verify if the values of ``from_version``, ``until_version``, and the current version of FURY are respected. This includes handling cases where ``from_version`` is greater than the current version of FURY, ``until_version`` is less than the current version of FURY, and ``until_version`` is greater than or equal to the current version of FURY. + - Ensured the decorator and tests cover a broader range of edge cases. + - Enhanced the warning messages for better clarity and guidance. + +2. Doctest Updates: + + - Updated the doctest considering the values of `from_version` and `until_version`. + - Moved the doctest from the `def decorator()` function to the root function. + +3. Unit Tests: + +.. code-block:: python + + def test_warn_on_args_to_kwargs(): + @warn_on_args_to_kwargs() + def func(a, b, *, c, d=4, e=5): + return a + b + c + d + e + + # if FURY_CURRENT_VERSION is less than from_version + fury.__version__ = "0.0.0" + npt.assert_equal(func(1, 2, 3, 4, 5), 15) + npt.assert_equal(func(1, 2, c=3, d=4, e=5), 15) + npt.assert_raises(TypeError, func, 1, 3) + +- This ensures robust validation and helps catch potential issues early. + + +Applying the ``warn_on_args_to_kwargs`` Decorator +------------------------------------------------- + +This week, I applied the ``warn_on_args_to_kwargs`` decorator to several modules, ensuring consistent usage and improved code quality. The modules updated include: + +- `actors` +- `ui` +- `animation` +- `shares` +- `data` + +For each module, I opened a pull request to track the changes and facilitate reviews: + +- `actors`: https://github.com/fury-gl/fury/pull/898 +- `animation`: https://github.com/fury-gl/fury/pull/899 +- `data`: https://github.com/fury-gl/fury/pull/900 +- `shares`: https://github.com/fury-gl/fury/pull/901 +- `ui`: https://github.com/fury-gl/fury/pull/902 + + +Exploring lazy loading +---------------------- + +In order to optimize performance, I've started exploring and implementing lazy loading. This week, the focus was on the following points: + +- Getting to grips with how the lazy loader works +- Implementing some small script to understand how the lazy loader works +- I also read the SPEC1 document available at `SPEC1 `_ +- Understanding the benefits of lazy loading and how it can be applied to the FURY code base +- Planning the integration of lazy loading into the FURY code base + +Code sample: ``_ + + +Peer Code Review +---------------- + +This week, I continued to dedicate time to reviewing the code of my peers. Specifically, I reviewed Kaustav Deka’s work, providing constructive feedback and suggestions for improvement. You can view the pull request here: `https://github.com/dipy/dipy/pull/3239 `_. + + +Acknowledgements +---------------- + +I am deeply grateful to my classmates `Iñigo Tellaetxe Elorriaga `_, `Robin Roy `_, `Kaustav Deka `_ for their continuous support and insightful suggestions. Special thanks to my mentor, `Serge Koudoro `_ , whose expertise and guidance have been invaluable in navigating these technical challenges. + + +Did I get stuck? +----------------- + +Yes, I was a bit confused about understanding lazy loader, but thanks to the help of my mentor `Serge Koudoro `_ , I was able to understand it better. + + +What's next? +------------ + +For the upcoming week, I plan to: + +- Implement lazy loading in the FURY code base +- Continue refining the ``warn_on_args_to_kwargs`` decorator based on feedback +- Engage in more code reviews to support my peers +- Prepare to working on the FURY website to improve the documentation and user experience + +Thank you for following my progress. Your feedback is always welcome. diff --git a/docs/source/posts/2024/2024-07-01-week-4-robin.rst b/docs/source/posts/2024/2024-07-01-week-4-robin.rst new file mode 100644 index 000000000..214bc1e52 --- /dev/null +++ b/docs/source/posts/2024/2024-07-01-week-4-robin.rst @@ -0,0 +1,74 @@ +Week 4: Pipeline Improvements and Taking The Bot Public! +======================================================== + +.. post:: July 1 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 4. + +My goals for week 4 were to move my Google colab notes to a proper Python script, improve the existing code, and make a working pipeline to upsert data easily. Also, the bot is public now :) Anyone reading this blog could join this `Discord Server `_ and ask questions right away! + +Things I did in Week 4 +---------------------- + +1) **Chunking tutorials and documentation** + +Earlier, only files fitting the context window of the embedding model were upserted. This was because otherwise, we'd have to split the file in half and lose the overall context. This will lead to information loss and retrieval will be messy. Now, I decided I'd upsert everything by splitting information properly. By "properly", what I mean is it won't be a random split, and there'll be logical reasoning behind every chunk. + +This area is still actively studied, and the whole concept is to find ideal chunks which are self-sufficient and contain the most information. This `notebook `_ details 6 different approaches, I read through them and some of their associated literature and decided we'll use `Recursive Character Text Splitting` and `Document Specific Splitting` for now. There is no major reason for this, I just felt it'll work well for now (a reasoning-backed approach will come in a few weeks). There is a lot of experimentation we could do here, a better chunking will result in better ``references`` generation and so on. + +So this is our current process + - if normal function/class definition: no splitting, chunk as it is. + - if rst files, use the ``rst parser`` and split them with a chunk size of ~8000 tokens (max llama could take). RST files in FURY contain documentation & blog posts. + - if tutorial, try chunking as it is, if not possible split at 8000 tokens. + +Function/class definitions are generally under 8000 so I've not done explicit checks for now, the model will trim the remaining if longer (I found some long classes later). + +2) **Move colab files to a proper Python script** + +I did all the upsertion and experiments on colab. It is messy and can't be used in production. We need a one-click approach to upsertion. Something like point to `fury` directory and it should do everything. So I took the messy colab code and made a python script from it. + +One of my key goals is to separate core application logic from LLMs/Database providers. We should be able to swap them as needed without much fuss. I'll talk more about this in week 5. + +3) **Taking the bot public!** + +The whole point of making the bot is to help improve the productivity of FURY developers. So I decided to take it public on `this discord server `_. You could use it today! (actually, you could've used it from the 20th of last month, this blog got delayed😢) + +I'll observe what people are asking and then iterate towards making the bot better in that area. I think it'll be better than making the bot good on what I believe is the best. + +4) **Minor bugfixes and stuff** + +Did some minor bug fixes on things like the Discord bot generation cutoff and error handling improvements. It was Discord message limit (<=2000) that caused the generation to cut off, I split the message into parts to fix that. Error handling was improved generally everywhere. I'll need to bring logging later. + + +Minor Sidequest +~~~~~~~~~~~~~~~ + +This is in no way related to FURY, but it was fun so I thought I'd add it here :) + +So after midterms, I decided to go back home, to maximally use my time I searched for things to do and found a local FOSS event: (`Kochi's FOSS `_). It was done by FOSS United Kochi and it's one of the major FOSS events in my state (Kerala, India). Met some Pythonistas! Explained what FURY is to them. I also ended up finding some lore (`click here to read `_) about how GNU/Linux spread in Kerala, India. Also found some old FOSS event pictures (`this `_ one is talking about Python, 2003 World of Python). This was my first FOSS event outside campus so it was fun :) + + +What is coming up next week? +---------------------------- + +- Benchmarking +- Architecture Update + +Did you get stuck anywhere? +--------------------------- + +No, I did not get stuck. This week was more of learning and experimentation so I think it's normal what I encountered. + +LINKS: + +- `Discord Server `_ +- `A Text Splitting Guide `_ +- `GNU Case of Kerala `_ +- `2003 World of Python `_ +- `FOSS United Kochi `_ +- `Robin :) `_ + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-07-01-week-5-robin.rst b/docs/source/posts/2024/2024-07-01-week-5-robin.rst new file mode 100644 index 000000000..4ea38f342 --- /dev/null +++ b/docs/source/posts/2024/2024-07-01-week-5-robin.rst @@ -0,0 +1,129 @@ +Week 5: LLM Benchmarking & Architecture Modifications +===================================================== + +.. post:: July 1 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 5. + +This week, we'll take all the things we did in the previous weeks, and quantify them. Benchmarking an LLM is the process of grading the LLM answer. To grade properly, we need good rubrics, so that's what I worked on this week. Also, I made some architectural changes, to make the overall development simple. + +Things I did in Week 5 +---------------------- + +1) **Architectural Update** + +Earlier, this was our architecture: + + + .. raw:: html + + + +This had an obvious issue, all the core logic was inside the Discord Bot. So if I want to say, use the LLM inference for making a GitHub bot, or for benchmarking etc, it wasn't possible. So I decided to cut the LLM logic from Discord Bot and made a new ``LLM Router``. It'll handle all the LLM logic from now on, and we do not directly call any other endpoint other than this one. +It makes life simple, every input going into the endpoint goes like this: + +.. code-block:: json + + { + "query": "Render a cube in fury", + "llm": "llama3-70b-8192", + "knn": "3", + "stream": false + } + +Every response coming out will be like this: + +.. code-block:: json + + { + "response": "Yes, this is how it would be done python import fury....", + "references": "1, 2, 3" + } + +What happens on the inside is completely abstracted away. You just call this and it'll + - call the embedding model + - pass embeddings to the database + - return them to LLM (which you can choose) + - returns LLM answer with references to you + +Currently, we support ``ollama``, ``google`` and ``groq`` providers. That itself is 20+ LLM support, and you could swap between them using ``/api/groq or api/google or /api/ollama ...``. Adding another provider is simply adding another endpoint. + +So if you do + +`curl -X POST https://robinroy03-fury-engine.hf.space/api/groq/generate -H "Content-Type: application/json" -d '{"query": "How do I create a sphere in FURY?", "llm": "llama3-70b-8192", "knn": "3", "stream": false}'` + + +You'll get a response from ``llama3-70b-8192`` using ``groq``. If you do ``https://robinroy03-fury-engine.hf.space/api/google/generate`` you can call any google gemini modes like ``gemini-1.5-pro`` or ``gemini-1.5-flash``. Same for ``ollama``. + +This still could be improved, it does not currently account for vision models. I did not add that because we do not use vision models other than for benchmarking now, and that too is done locally. Benchmarking could also be streamlined, I avoided that because benchmarking is still in development so I'll have to rewrite every day. Presently you can use this core ``router`` for a working LLM generation (you'll get the same thing you'll get from the Discord Bot. So if you have a website, all you have to do is call the API). + +This is our present architecture: + +.. image:: /_static/images/gsoc_llm_robin_week5.jpg + :alt: Present LLM architecture. + +It is the same thing as above, except we have two new components - ``LLM Engine`` and a ``Groq & Gemini`` endpoint. When we'll end up having a conversational model setup (right now, it is one question and one answer), this model will be upgraded to accommodate that. My plan is to extend LLM Engine and add that. Other features such as vision also could be added to this as needed. + +2) **Gemini Models added** + +As mentioned above, I added ``Gemini`` models this week. They have a decent free tier. Also, I'm studying the feasibility of fine-tuning using the ``Gemini`` models. + +3) **LLM Benchmarking** + +LLM Benchmarking is the process of evaluating the LLM output and giving a score. With this, making the model better will be simply a function of increasing the score. This area is still under development and the things I've tried here are the current standard procedures. To understand more about benchmarking, you can read: `RAG Evaluation `_, `Using LLM-as-a-judge 🧑‍⚖️ for an automated and versatile evaluation `_ and `Advanced RAG on Hugging Face documentation using LangChain `_. This `course `_ is also amazing. + +I'll anyways give a TL;DR: +LLM benchmarking is essentially like writing an English Literature exam and getting the grades. Your evaluator may give you a 4 or a 5, and the reasoning can be varied. For the same answer, you may even get very varied results from 2 different evaluators! Two common rubrics they use are ``groundedness (whether the answer follows from the material)`` and ``completion (whether the answer is complete, whether it fully answers the question with respect to the material)``. These are the same rubrics we'll use for LLM evaluation. For code, it's different. The code should compile and do exactly what it should. + +Now FURY Bot does 2 things - writing code & writing answers for common questions (on GitHub issues etc). Presently, I've only collected data for coding questions, as they are much easier to evaluate and give a clear sense of direction (also I found more coding data). + +Evaluating FURY code can be done by: + 1) Running the code. + 2) Checking the output. + +Now we do this using ``pytest`` in the FURY repo for tests. But this approach is tedious, as collecting questions and writing test cases take a lot of time, also the orientation of the 3D objects also matters (an LLM generation is not deterministic). So we are using a vision model ``moondream2`` to check the LLM generated output and verify if it is what we actually wanted. +On a high level, this is what we do (for now): + +- Take a QnA pair from the collected dataset (I've collected ~23 questions). +- Ask the LLM to generate a FURY code for that (using the references). +- Run this generated code. +- Check the output using ``moondream2`` and verify whether it is what we wanted. + +There is also ``fast_eval`` which checks whether the code compiles and skips ``moondream2`` entirely. This is obviously faster and is also decently good (is actually a pretty good heuristic). If it runs, assume it works :) + +This is our current stats: (from now on, we can finally talk using numbers) + +Coding benchmark: +~~~~~~~~~~~~~~~~~ +On ``fast_eval`` we have a success rate of ``47.83%`` for ``groq``. + +On ``normal_eval`` we have a success rate of ``13.04%`` for ``groq``. + +Note that ``moondream2`` also sometimes mistakes the output for something else. It is close to ``~45%`` when I checked manually. For now, I'm only going to focus on ``fast_eval`` as fixing ``moondream2`` is a distraction for the moment. (This actually gets very meta, there are projects where they have benchmarks for the evaluator and so on. `Read this `_.) + + +What is coming up next week? +---------------------------- + +- Better benchmark scores :) +- Line number highlighting @ references. +- Some ``references`` improvements. + +Did you get stuck anywhere? +--------------------------- + +No, I did not get stuck anywhere. + +LINKS: + +- `RAG Evaluation `_ +- `LLM Judge `_ +- `Advanced RAG `_ +- `Advanced Retrieval for AI `_ +- `Moondream2 `_ +- `Finding GPT-4 mistakes with GPT-4 `_ + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-07-06-week5-wachiou-bouraima.rst b/docs/source/posts/2024/2024-07-06-week5-wachiou-bouraima.rst new file mode 100644 index 000000000..01a915125 --- /dev/null +++ b/docs/source/posts/2024/2024-07-06-week5-wachiou-bouraima.rst @@ -0,0 +1,112 @@ +WEEK 5: Implementing Lazy Loading in FURY with ``lazy_loader`` +============================================================== + +.. post:: July 6, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Hello everyone, +--------------- + +Welcome back to my Google Summer of Code (GSoC) 2024 journey! This week has been particularly exciting as I introduced a significant performance optimization feature: lazy loading. Here's an overview of my progress and contributions. + + +**Introduction of lazy loading** +-------------------------------- + +This week, I focused on implementing the ``lazy_loader`` feature of `Scientific Python `_ to optimize module loading in FURY. Lazy loading improves performance by deferring the loading of modules until they are actually needed, thus reducing start-up times and memory footprint. + +The implementation involved: + +1. Implementation of Lazy Loading: + + - Application of lazy loading in several FURY modules using the ``lazy_loader`` module to improve performance + +2. Update ``__init__.py`` files: + + - Modified ``__init__.py`` files to support lazy loading where necessary. This ensures that modules are only loaded when they are accessed for the first time + +3. Added Type Stubs (``__init__.pyi``): + + - Adding type stubs (``__init__.pyi``) provides type hints for lazy-loading modules, improving code readability and maintainability + +4. **Improved module organization:** + + - Improved module organization in ``__init__.py`` and ``__init__.pyi`` files, to effectively support lazy loading. + + +**Example Implementation** +--------------------------- + +To give you an idea, here's the actual implementation of how lazy loading was done using the ``lazy_loader`` module in FURY: + +``__init__.py`` File: + +.. code-block:: python + + import lazy_loader as lazy + from fury.pkg_info import __version__, pkg_commit_hash + + __getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) + + _all__ += [ + "__version__", + "disable_warnings", + "enable_warnings", + "get_info", + ] + + # ... (functions) + +``__init__.pyi`` File: + +.. code-block:: python + + # This file is a stub type for the fury package. It provides information about types + # to help type-checking tools like mypy and improve the development experience + # with better autocompletion and documentation in code editors. + + __all__ = [ + "actor", + "actors", + "animation", + "colormap", + # ... (other modules) + , + ] + + from . import ( + actor, + actors, + animation, + colormap, + # ... (other modules) + , + ) + # ... (other functions) + +You can review the implementation in `this pull request `_. + + +Reading ``SPEC1`` +----------------- + +To align myself with best practice, I read the `SPEC1 `_ document available at Scientific Python SPEC1. This document provided valuable hints and guidelines that I took into account when implementing the lazy loading feature. + + +Did I get stuck anywhere? +-------------------------- +No, I didn't encounter any major blockers this week. The implementation of lazy loading went smoothly, and I was able to complete the task. + + +**What's Next?** +----------------- + +For the next week, I plan to: + +1. Review all my Pull Requests with my mentor `Serge Koudoro `_, to ensure everything is up to FURY's standards. +2. Start working on the redesign of the FURY website, making it more user-friendly and visually appealing. + + +Thank you for reading. Stay tuned for more updates on my progress! diff --git a/docs/source/posts/2024/2024-07-27-week-6-robin.rst b/docs/source/posts/2024/2024-07-27-week-6-robin.rst new file mode 100644 index 000000000..6ffff8755 --- /dev/null +++ b/docs/source/posts/2024/2024-07-27-week-6-robin.rst @@ -0,0 +1,49 @@ +Week 6: UI Improvements and RAG performance evaluation +====================================================== + +.. post:: July 27 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 6. + +This week, I worked on some UI improvements and studied and evaluated the RAG performance. + +Things I did in week 6 +---------------------- + +1) **Line number references** + +Earlier, the bot used to reference the Python file directly. This made it difficult to search and find the particular function/class. We had to manually go and search. I modified the code to include a link with line numbers. Now the references section will give a link which wraps around the function/class. To do this I had to re-index the whole library again using the new parser code. The present model points to the latest stable release of FURY. + +I also tried to compress it all into one Discord message, reducing one extra ping :) + + +2) **RAG Performance Evaluation** + +I added a new benchmark to measure RAG performance. It essentially checks whether certain key information was retrieved from the database. There are certain situations where the model fetches data irrelevant to the question, this could help in fixing that. + +The RAG benchmark dataset consists of a prompt to the LLM and expected references to be fetched from the database. I'll give a score based on the % of correct fetches. + + +3) **Fine-tuning feasibility study** + +It was time to start thinking about fine-tuning. Gemini had a generous free tier and it was possible to fine-tune Gemini-1.0-pro. I looked into it and started collecting data for it. For fine-tuning Gemini, I had to format the data as an input/output pair. Most of the data were planned to be collected from Discord and GitHub. + +I also checked into fine-tuning models like phi-3 and llama 7b. It is possible to do the fine-tuning on google colab/kaggle. We could use a small quantized model and fine-tune that without much performance loss. + + +What is coming up next week? +---------------------------- + +I'll be taking a break next week due to my semester final examinations. I'll study model finetuning and keep brainstorming interesting trajectories for FURY. + + +Did you get stuck anywhere? +--------------------------- + +No, I did not get stuck anywhere. + + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-07-27-week-7-robin.rst b/docs/source/posts/2024/2024-07-27-week-7-robin.rst new file mode 100644 index 000000000..5de64df95 --- /dev/null +++ b/docs/source/posts/2024/2024-07-27-week-7-robin.rst @@ -0,0 +1,31 @@ +Week 7: Surviving final examinations +==================================== + +.. post:: July 27 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 7. + +I majorly took this week off due to my semester final examinations :) They were fun. Major topics were x86, ARM and 8051. I had not written a lot of assembly apart from school work. I took the week to experiment with some assembly. The course was more into hardware architecture than programming. I've now enough knowledge to read a given piece of ASM code with a wiki to look up mnemonics (and Gemini/Claude to help). I'm not fast in writing ASM (yet), one day I'll find a project to dive into, or maybe some reverse engineering and CTFs. GPU instruction sets are also something interesting. + + +**Discord data collection** + +I collected some Q&A questions from the FURY discord server. I did it manually because the volume wasn't high, and I wanted it to be correct. Had to cross-check with GitHub also to check whether the answer/code mentioned still stands. The format I used was [User question, Answer]. If the answer/question is spread across multiple conversations, I'll adjust it to this format. + + +What is coming up next week? +---------------------------- + +- Gemini Finetuning +- Collect more Discord data. + + +Did you get stuck anywhere? +--------------------------- + +Not really apart from some silly ASM bugs. + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-07-27-week-8-robin.rst b/docs/source/posts/2024/2024-07-27-week-8-robin.rst new file mode 100644 index 000000000..afa93d235 --- /dev/null +++ b/docs/source/posts/2024/2024-07-27-week-8-robin.rst @@ -0,0 +1,52 @@ +Week 8: Gemini Finetuning +========================= + +.. post:: July 27 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 8. + +This week I worked on finalizing the Discord chat QnA data collection and using it to Fine-Tune the Gemini-1.0-Pro model. + +Things I did in Week 8 +---------------------- + +1) **Discord Data Collection** + +I finished collecting data from all the channels in the Discord server, cross-verifying to check whether they still work. I also added some questions which were on the FURY bot testing server. These QnA pairs were later converted to a CSV with input/output pairs and fed to Gemini for finetuning. + +2) **Gemini Finetuning** + +Finetuning is essentially training the model on the input/output. RAG is giving context and asking the model to form an answer using that. Finetuning updates the model weights as per the input/output. Gemini uses `Parameter-Efficient Fine-Tuning `_ in AI Studio as per some reports. It makes sense because the tuning only takes minutes and PEFT is a good strategy to prevent issues like `catastrophic forgetting `_. + +Finetuning and RAG are complementary to each other. The difference between them can be summarized as follows: + +RAG is like giving an LLM with no prior knowledge about FURY access to some important functions/classes as per the user prompt. It'll use this given context and its knowledge of graphics libraries (knowledge from pretraining) to form an answer. + +Finetuning is used to make the model follow a certain style or behaviour. It is a form of mimicking the input-output. This will help in increasing the model's performance. An interesting thing is I had to train the model 1) with RAG and 2) without RAG. + +For finetuning, the input must be in the format the LLM will get the answer from the user. When you ask a question to the FURY bot, the bot does not get your question directly. We are processing it to add additional information. Therefore I had to process all the collected data with RAG. + +This is an interesting direction, and I have a lot of cool things to try out here. I'll spend the next few weeks trying different ideas. + + +What is coming up next week? +---------------------------- + +- Finetuning strategies. +- Hosting the model on API. + + +Did you get stuck anywhere? +--------------------------- + +No, I did not get stuck anywhere. + +LINKS: + +- `Parameter-Efficient Fine-Tuning `_ +- `catastrophic forgetting `_ + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-07-31-release-announcement.rst b/docs/source/posts/2024/2024-07-31-release-announcement.rst new file mode 100644 index 000000000..d66cbba8d --- /dev/null +++ b/docs/source/posts/2024/2024-07-31-release-announcement.rst @@ -0,0 +1,48 @@ +FURY 0.11.0 Released +==================== + +.. post:: July 31 2024 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.11.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +This Release is mainly a maintenance release. The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.11.0.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are available :ref:`here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.11.0.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/docs/source/posts/2024/2024-08-06-week6-wachiou-bouraima.rst b/docs/source/posts/2024/2024-08-06-week6-wachiou-bouraima.rst new file mode 100644 index 000000000..eb47003a3 --- /dev/null +++ b/docs/source/posts/2024/2024-08-06-week6-wachiou-bouraima.rst @@ -0,0 +1,94 @@ +WEEK 6: Code reviews, relining and crush challenges +=================================================== + +.. post:: August 6, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Hello everyone, +As my Google Summer of Code (GSoC) 2024 journey progresses, week6 has brought me a series of technical challenges and accomplishments. My main focus has been on code reviews, rebasing and commits squashing, with a few notable lessons learned along the way. + + +Code Reviews and Merging ``Pull Requests`` +------------------------------------------- + +One of the main activities this week was receiving and addressing feedback on several of my pull requests. Notably, my mentor `Serge Koudoro `__, reviewed and merged the PRs related to the ``warn_on_args_to_kwargs`` decorator and the application of the ``warn_on_args_to_kwargs`` decorator across various modules. The merging of these PRs was a critical step in ensuring that our codebase adhered to the project's evolving standards for clarity and maintainability. + + +Rebasing and Squashing: Overcoming Challenges +--------------------------------------------- + +- I performed rebasing and squashing to integrate the latest changes and consolidate commits. This process was challenging due to several conflicts that arose. Resolving these conflicts required a deep dive into Git’s functionality, including: + + - **Conflict Resolution:** Manually resolving merge conflicts that affected several files. + + - **Understanding Git Operations:** Gained hands-on experience with rebasing and squashing, which improved my grasp of version control workflows. + + - **Commit Consolidation:** multiple commits into a single commit to streamline the commit history and enhance readability. + +Here are some of the Git commands I used during the rebasing and squashing process: + +.. code-block:: bash + + # Rebase the branch onto the upstream/master branch + + git rebase upstream/master -xtheirs + + # Squash the last "n" commits into a single commit + git rebase -i HEAD~n + + # Continue the rebase process after resolving conflicts + git rebase --continue + + git rebase --abort + + # Amend the last commit with new changes + git commit --amend + + # Push the changes to the remote repository + git push origin branch_name --force + + +- Merged PRs: + + - `warn_on_args_to_kwargs`: https://github.com/fury-gl/fury/pull/888 + - `actors`: https://github.com/fury-gl/fury/pull/898 + - `animation`: https://github.com/fury-gl/fury/pull/899 + - `data`: https://github.com/fury-gl/fury/pull/900 + - `shares`: https://github.com/fury-gl/fury/pull/901 + - `ui`: https://github.com/fury-gl/fury/pull/902 + + +Technical Insights and Lessons Learned +--------------------------------------- + +- **Version Control Mastery:** Through the rebasing and squashing process, I gained a deeper understanding of Git’s capabilities and the importance of maintaining a clean commit history. + + +Acknowledgements +---------------- + +I want to extend my thanks to my mentor `Serge Koudoro `__, for his detailed feedback and guidance. Your support has been crucial in refining my work. I also appreciate the constructive comments from my peers: `Iñigo Tellaetxe Elorriaga `_, `Robin Roy `_, `Kaustav Deka `_, which have been instrumental in improving the quality of my contributions. + + +Did I get stuck anywhere? +-------------------------- + +While the rebasing and squashing process presented challenges, I was able to overcome them with the help of my mentor `Serge Koudoro `__ and online resources and documentation. + +- `How to Squash Commits in Git `_ +- `Git: Theirs vs Ours `_ +- `How to squash and rebase in git `_ + +The experience has enhanced my Git proficiency and prepared me for future code management tasks. + + +What's next ? +------------- + +In the week 7, I plan to: + +1. Review Adjustments: I'll be reviewing the feedback provided by my mentor `Serge Koudoro `__, on the latest changes to ensure that everything meets ``FURY``'s coding standards. +2. Finalizing Lazy Loading: Once the reviews are completed and approved, my mentor `Serge Koudoro `__, will merge the PR related to the lazy loading implementation. This will mark a significant milestone in optimizing the FURY codebase. +3. Sphinx Warning Fixes: I will start addressing Sphinx warnings related to typos in the blog posts to improve the documentation quality. diff --git a/docs/source/posts/2024/2024-08-06-week7-wachiou-bouraima.rst b/docs/source/posts/2024/2024-08-06-week7-wachiou-bouraima.rst new file mode 100644 index 000000000..324d25b59 --- /dev/null +++ b/docs/source/posts/2024/2024-08-06-week7-wachiou-bouraima.rst @@ -0,0 +1,36 @@ +WEEK 7: Fixing Sphinx Warnings in Blog Posts +============================================ + +.. post:: August 6, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Hello everyone, +Welcome back to another update on my GSoC 2024 journey. This week, my focus was primarily on addressing Sphinx warnings caused by typos in blog posts. + + +Addressing Sphinx Warnings +-------------------------- + +This week, I dedicated my time to resolving Sphinx warnings that were popping up due to typos in various blog posts. Out of the 100 warnings that were initially present, I was able to fix 98 of them. This process involved carefully reviewing the documentation, identifying the sources of the warnings, and making the necessary corrections. + +Here’s a snapshot of some of the warnings I addressed: + +.. image:: /_static/images/gsdoc-some-sphinx-warnings-addressed_Wachiou.jpg + :alt: a snapshot of some of the warnings + + +Did I get stuck anywhere ? +-------------------------- + +While most of the warnings were straightforward to fix, a few required a bit more time and attention to detail. In particular, some typos were present in code snippets, which required careful examination to ensure that the corrections did not introduce any errors. + +What's Next ? +-------------- + +In the upcoming week, + +- I will begin addressing Sphinx warnings related to typos in the documentation for certain modules. +- I will also focus on improving the overall readability and clarity of the documentation to enhance the user experience. +- Refining Lazy Loading Implementation according to the feedback received from my mentor `Serge Koudoro `_. diff --git a/docs/source/posts/2024/2024-08-12-week8-wachiou-bouraima.rst b/docs/source/posts/2024/2024-08-12-week8-wachiou-bouraima.rst new file mode 100644 index 000000000..92f0331a9 --- /dev/null +++ b/docs/source/posts/2024/2024-08-12-week8-wachiou-bouraima.rst @@ -0,0 +1,46 @@ +WEEK 8: Refining Lazy Loading Implementation and Simplifying Imports in FURY +============================================================================= + +.. post:: August 12, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Hello everyone, +Welcome back to another update on my Google Summer of Code (GSoC) 2024 journey! This week, my mentor `Serge Koudoro `__ and I focused on refining the lazy loading feature and optimizing import statements within FURY’s ``examples modules``. + + +Reviewing and Refining Lazy Loading +------------------------------------ + +This week was dedicated to a thorough review of the lazy loading implementation I introduced in the previous weeks. My mentor provided invaluable feedback, and together we identified areas where the implementation could be improved. + + +I addressed several issues, including +-------------------------------------- + +- **Error Fixes**: During the review, we identified some edge cases that were not handled correctly by the lazy loading mechanism. I corrected these errors to ensure the feature works seamlessly across the FURY codebase. + +- **Import Simplification**: One significant change was simplifying how FURY is imported in example modules. Previously, the import statements were more complex, like ``from fury import ....`` To align with the lazy loading principles and reduce unnecessary overhead, I updated these statements to a more straightforward ``import fury`` This change ensures that only the necessary components are loaded when they are actually needed, improving performance. + + +Rebasing and Squashing +----------------------- + +After making these adjustments, I proceeded with rebasing and squashing my commits. This process was essential to maintain a clean and organized commit history. Despite the challenges, I managed to resolve all conflicts, and my mentor `Serge Koudoro `__, approved the changes. The pull request was successfully merged, marking another milestone in the project. + + +Did I get stuck anywhere? +-------------------------- + +No, I did not encounter any major roadblocks this week. The tasks were challenging but manageable, and I was able to address them effectively with the guidance of my mentor `Serge Koudoro `__. + +What's Next? +------------ + +In the upcoming week, + +- I will continue addressing Sphinx warnings related. +- start working to improve de FURY website. + +Thank you for following along, and stay tuned for more updates as I continue to make progress on this project! diff --git a/docs/source/posts/2024/2024-08-13-week9-wachiou-bouraima.rst b/docs/source/posts/2024/2024-08-13-week9-wachiou-bouraima.rst new file mode 100644 index 000000000..2ae230e9c --- /dev/null +++ b/docs/source/posts/2024/2024-08-13-week9-wachiou-bouraima.rst @@ -0,0 +1,57 @@ +WEEK 9: Fixing Sphinx Warnings and Investigating Web Footer Issues +================================================================== + +.. post:: August 13, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Hello everyone, +welcome to my Google Summer of Code (GSoC) 2024 journey! Week 9 was devoted to fixing Sphinx warnings caused by indentation errors in some docstrings of some examples in the ``auto_examples`` folder. I also started investigating why the footer of the ``FURY`` site distorts when you try to move the mouse over an element. + + +Continuing the Fight Against Sphinx Warnings +-------------------------------------------- + +My main task this week has been to continue dealing with the Sphinx warnings in our documentation. I focused on the 188 warnings related to the main documentation, as well as 2 warnings in the blog posts. +I fixed 19 warnings caused by the docstring of ``viz_**.py`` modules in the ``source/auto_examples`` folder +by fixing the indentation errors in the docstrings of the examples. + +Here is an example of indentation error in the docstring of the example ``auto_examples/04_demos/viz_animated_surfaces.py``: + +.. code-block:: python + + ... Code block ... + + ############################################################################### + # Variables and their usage: + # :time - float: initial value of the time variable i.e. value of the time variable at + # the beginning of the program; (default = 0) + # dt: float + # amount by which ``time`` variable is incremented for every iteration + # of timer_callback function (default = 0.1) + # lower_xbound: float + + ... Code block ... + + +Investigating Web Footer Issues +------------------------------- + +In parallel, I started investigating an issue with the FURY website's footer, which deforms when hovering over an element with the mouse. This problem affects the user experience and visual consistency of the site. My work this week has focused on diagnosing the underlying cause of this issue and planning the necessary steps to fix it. This task has been both technically intriguing and a great opportunity to sharpen my web development skills. + +issue number: `#874 `_ + + +Did I get stuck anywhere ? +-------------------------- + +I encountered some challenges while fixing the indentation errors in the docstrings of the examples. The errors were caused by inconsistent indentation in the docstrings, which made it difficult to identify the root cause of the warnings. However, I was able to resolve these issues and make progress in addressing the Sphinx warnings. + +What's next ? +------------- + +For week 10, I plan to: + +- Continue fixing the Sphinx warnings in the documentation. +- Start fixing the issue with the footer of the FURY website. diff --git a/docs/source/posts/2024/2024-08-15-week-9-robin.rst b/docs/source/posts/2024/2024-08-15-week-9-robin.rst new file mode 100644 index 000000000..b8cdd3157 --- /dev/null +++ b/docs/source/posts/2024/2024-08-15-week-9-robin.rst @@ -0,0 +1,63 @@ +Week 9: Hosting FineTuned Models +================================ + +.. post:: Aug 15 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 9. + +This week I worked on hosting the Finetuned model as an API and started work on GitHub GraphQL. + +Things I did in Week 9 +---------------------- + +1) **Hosting the fine-tuned API** + +Last week we fine-tuned the Gemini model, but it didn't have an endpoint which we could use to connect with Discord/other frontend applications. I thought it would be a simple task until I realized it wasn't. Some features are still in beta phase, like this one :) + +Fine-tuned models need more permissions to be used under an API, cause it is your data (as per Google policy). Google Gemini API provides only 1 way to achieve this right now, and that is by using a short-lived token. Short-lived tokens can't be used on a server cause we'll have to rotate it, and to rotate them I'll need to sign in to my Google account every time, and I can't program it. + +The way we generally solve this is by using a token with no expiry - but the Gemini API does not support that. I tried making service accounts to bypass expiry but it was all failing. The documentation does not mention anywhere how to fix this issue either. + +After a lot of googling, I ended up checking the `Google Gemini Cookbook repo `_, here we have a notebook which talks about this problem! I was so happy seeing `this Authentication_with_OAuth.ipynb file `_. The solution is to essentially add permission to the fine-tuned model through a REST call. There is no UI/SDK way to do this. You'll have to trigger a certain REST endpoint to update the permissions to "EVERYONE" so anyone can access the fine-tuned model. For FURY it's fine since FURY does not contain any sensitive information. + +So right now our workflow is as follows: + - Fine-tune a model on Google AI Studio. + - Update model permissions using a separate script. + - Call through the FURY-Engine API as usual. + + +2) **GraphQL work** + +The next thing I did was start working on GitHub integration. The Discord Bot is hosted and stable, now it was time to do the same with GitHub. For GitHub, the aim is to use the LLM to give a first response to discussions posts. GitHub uses GraphQL instead of REST APIs. + +If you do not know GraphQL you can learn about it in detail from `this YouTube playlist `_ and later from the `official docs `_. But I'll give you a quick explanation anyway since I think the playlist and docs miss this part: + +GraphQL is essentially HTTP POST/GET calls. We'll avoid all the jargon here and talk from first principles. REST API philosophy is to provide multiple endpoints `/google`, `/groq`, etc (these are FURY-engine endpoints). They do different things. Now these are just styles, remember that. At the end of the day you're still sending network packets to the server, these just dictate which URL you send it to and what data it contains. + +GraphQL is different in the sense it does not have multiple endpoints. There's only one endpoint (example: https://api.github.com/graphql for GitHub). We send all our requests to this endpoint and then the server uses it to do an action and return results. So you may ask "Why" do we need to follow the GraphQL syntax, why not just modify REST API to follow our custom style? You can do that. GraphQL is just a style of doing things that smart people at Meta decided to standardize. + +The reason people use GraphQL is because it reduces the number of queries required. You can read the docs to see example GraphQL queries, it is compact and you can easily get a lot of information with one single call. Different people have different opinions about how to make and consume APIs. But fundamentally it's just another layer of abstraction. + +What is coming up next week? +---------------------------- + +- Work on GitHub App. + + +Did you get stuck anywhere? +--------------------------- + +I was stuck with the Gemini API part but it was fixed. It was also a learning experience to not trust documentation always :) + + +LINKS: + +- `Google Gemini Cookbook repo `_ +- `Authentication_with_OAuth.ipynb file `_ +- `GraphQL YouTube playlist `_ +- `GraphQL official docs `_ + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-08-15-week10-wachiou-bouraima.rst b/docs/source/posts/2024/2024-08-15-week10-wachiou-bouraima.rst new file mode 100644 index 000000000..4641adec0 --- /dev/null +++ b/docs/source/posts/2024/2024-08-15-week10-wachiou-bouraima.rst @@ -0,0 +1,32 @@ +WEEK 10: Investigating Footer Deformation and Limited Progress on Warnings +========================================================================== + +.. post:: August 15, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Welcome to the week 10 of my Google Summer of Code (GSoC) 2024 journey. This week, I focused on resolving an issue with the ``FURY`` website’s footer and made limited progress on fixing documentation warnings. Here’s a detailed overview of my activities and challenges. + + +Investigating Footer Deformation Issue: `#874 `_ +-------------------------------------------------------------------------------------------- + +During this week, I identified the root cause of the footer deformation on the FURY website. The problem arose when hovering over an element, which caused the element’s size to increase. This, in turn, increased the padding of its container and subsequently affected the layout of following elements. +To address this, I initially considered avoiding changes in font size on hover and opted to make elements bold instead. While this approach resolved the deformation issue, it did not align with the design requirements for the homepage footer. +Due to health constraints, I was unable to continue this work. I plan to explore alternative solutions to align with the design specifications in the upcoming week. + + +Limited Progress on Documentation Warnings +------------------------------------------ + +I also aimed to make progress on fixing Sphinx warnings related to documentation typos. Unfortunately, I could not advance significantly in this area due to the time constraints imposed by the footer issue and my health. + + +What's Next ? +------------- + +For week 11, I plan to: + +- Explore alternative solutions to address the footer deformation issue while aligning with the design requirements. +- Continue fixing Sphinx warnings in the documentation and address any remaining issues. diff --git a/docs/source/posts/2024/2024-08-15-week11-wachiou-bouraima.rst b/docs/source/posts/2024/2024-08-15-week11-wachiou-bouraima.rst new file mode 100644 index 000000000..ef5596580 --- /dev/null +++ b/docs/source/posts/2024/2024-08-15-week11-wachiou-bouraima.rst @@ -0,0 +1,67 @@ +WEEK 11: Resolving the Footer Issue and Addressing Sphinx Warnings +================================================================== + +.. post:: August 15, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Hello everyone, +welcome to the update for Week 11 of my Google Summer of Code (GSoC) 2024 journey. This week, I focused on finalizing the footer issue on the ``FURY`` website and tackling some Sphinx warnings related to attribute and property naming conflicts. Here’s a detailed look at what I accomplished and the challenges faced. + + +Fixing the Footer Issue +----------------------- + +In the previous week, I identified the root cause of the footer deformation. The problem arose when hovering over elements, which caused their size to increase, thereby affecting the padding of their container and subsequently the entire footer layout. +To illustrate the issue and the resolution, I have included the following videos: + +Before Fixing the Footer Issue: +Video demonstrating the footer deformation before the fix. + +.. raw:: html + + + + +After Fixing the Footer Issue: +Video showing the footer after applying the fix. + +.. raw:: html + + + + +To address this, I experimented with different approaches. Initially, I tried adjusting the `font-size` of the elements on hover by making them bold instead. This resolved the deformation issue but did not align with the design specifications of the homepage footer. +After reconsidering, I added some properties to the ``.class-columns`` in the ``styles.css`` file to better adapt the footer style and prevent any layout issues. This approach aimed to maintain the design integrity while addressing the layout problem effectively. + + +Handling Sphinx Warnings +------------------------ + +In addition to fixing the footer, I worked on resolving warnings caused by Sphinx due to naming conflicts between attributes and properties. To mitigate these warnings, I initially added ``:no-index:`` directives in the .rst files for functions and classes to prevent indexing issues. +However, during our weekly meeting with my mentor `Serge Koudoro `_, it became clear that this solution might hinder the indexing and referencing of functions, modules, and classes on the ``FURY`` site and the web. Therefore, I need to re-evaluate the issue and find a more suitable solution that ensures proper indexing while addressing the warnings. + + +Did I Get Stuck Anywhere ? +-------------------------- + +While addressing the Sphinx warnings, I encountered some challenges related to the naming conflicts between attributes and properties. The warnings were triggered by the use of the same name for both an attribute and a property in the codebase. This conflict led to Sphinx warnings, which I am currently working to resolve. The complexity of this issue requires a more in-depth analysis to develop an appropriate solution that aligns with the project's requirements and Sphinx guidelines. + + +Acknowledgements +---------------- + +I am deeply grateful to my peers `Iñigo Tellaetxe Elorriaga `_, `Robin Roy `_, `Kaustav Deka `_ for their continuous support and insightful suggestions. Special thanks to my mentor, `Serge Koudoro `_ , whose expertise and guidance have been invaluable in navigating these technical challenges. + + +What’s Next ? +------------- + +For the upcoming week, I plan to: + +- Delve deeper into the Sphinx warnings related to attribute and property naming conflicts to develop a more appropriate solution. +- Continue to refine the footer styling to ensure it meets design specifications while maintaining functionality. +- Start writing my `GSOC'2024` final report. + +Thank you for following my progress. I look forward to sharing further updates and solutions in the coming weeks! diff --git a/docs/source/posts/2024/2024-08-16-week-10-robin.rst b/docs/source/posts/2024/2024-08-16-week-10-robin.rst new file mode 100644 index 000000000..0367fe0ac --- /dev/null +++ b/docs/source/posts/2024/2024-08-16-week-10-robin.rst @@ -0,0 +1,39 @@ +Week 10: Learning GraphQL +========================= + +.. post:: Aug 16 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 10. + +This week I worked on the GitHub GraphQL implementation. I tested out things and was learning GraphQL properly since I have never used it before. + + +**Learning and testing GraphQL** + +I spent time learning and implementing prototypes of the GitHub app. Initially, I tested using `GitHub Explorer `_ to control my account. I initially spent some time searching for other GitHub libraries but later gave up and made my custom scripts. There are no Python GraphQL libraries available, and the ones available do not integrate with Discussion tabs. + +I used Explorer to mainly focus only on the query language, and not on implementation. The plan was to use a GitHub app to send webhooks to the HuggingFace server, which will respond to it. + +We use ``query`` to fetch discussions and ``mutation`` to send a reply. They are GraphQL operations. + + +What is coming up next week? +---------------------------- + +- Working GitHub App + + +Did you get stuck anywhere? +--------------------------- + +No, I did not get stuck anywhere. I was learning new things and experimenting with stuff. + + +LINKS: + +- `GitHub Explorer `_ + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-08-17-week-11-robin.rst b/docs/source/posts/2024/2024-08-17-week-11-robin.rst new file mode 100644 index 000000000..beea2a193 --- /dev/null +++ b/docs/source/posts/2024/2024-08-17-week-11-robin.rst @@ -0,0 +1,63 @@ +Week 11: Getting the App Live +============================= + +.. post:: Aug 17 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 11. + +This week I worked on Getting the GitHub App live. + + +**Getting the App Live** + +Last week I prototyped and got to know the language and the API. But I can't use my account as an automated bot account. So it was required to make a GitHub App. The architecture for it is as follows: + +- Make a GitHub App to listen to Discussion posts +- Send a webhook to https://robinroy03-github-bot.hf.space/github whenever any change happens. +- Respond to the webhook as required. + +I was told by `Serge `_ to try and fit the endpoint inside the Discord Bot script. I tried but it was weird so I left it. The Discord Bot is set up using threading which is a hack (although it is how every discord bot is set up in HuggingFace). Placing it inside any other repository won't be good so I ended up making another new repository. + +I faced an issue while trying to get the app live. I had another documentation rabbit hole situation. So what ended up happening was I was unable to authenticate myself with the GitHub app to send commands. To command an app you have to authenticate as a `GitHub App Installation`. To authenticate as an App installation, you need 3 key things: + +- Installation ID +- App ID +- Private Key of the App + +You use the ``App ID`` and ``Private Key`` to make a ``JWT``. You use the ``JWT`` with ``Installation ID`` to make an ``Installation Access Token``. You'll now use this ``Installation Access Token`` to authorize you and then send commands to the GitHub App. The ``Access Token`` will expire after 1 hour, so we'll have to regenerate it. + +The problem was that the documentation didn't mention how to generate ``Installation Access Token`` and it kept confusing everyone with ``Installation ID``. Even the names were misleading, since it isn't an ``Installation Token`` in the real sense cause it is already installed. I ended up fixing it by landing at `this StackOverflow Post `_ which took me to this `Discussions Post `_. I think the majority uses `Octokit.js SDK` to generate Access Tokens and regenerate JWTs. Sadly Python has no library so we had to go all manual. + +So I ended up sending a PR to GitHub Docs :) + +- Issue: https://github.com/github/docs/issues/34258 +- PR: https://github.com/github/docs/pull/34259 + + +You can test the GitHub App today! Checkout https://github.com/robinroy03/FURY-data-script/discussions + + +What is coming up next week? +---------------------------- + +- Week 12 :) I'll be finalizing stuff. +- Make the GitHub App respond to mentions. + + +Did you get stuck anywhere? +--------------------------- + +Was stuck with the documentation but got it fixed. + + +LINKS: + +- `StackOverflow Post `_ +- `Discussions Post `_ +- https://github.com/github/docs/issues/34258 +- https://github.com/github/docs/pull/34259 + +Thank you for reading! diff --git a/docs/source/posts/2024/2024-08-17-week12-wachiou-bouraima.rst b/docs/source/posts/2024/2024-08-17-week12-wachiou-bouraima.rst new file mode 100644 index 000000000..3ad842384 --- /dev/null +++ b/docs/source/posts/2024/2024-08-17-week12-wachiou-bouraima.rst @@ -0,0 +1,97 @@ +WEEK 12: The final straight +=========================== + +.. post:: August 17, 2024 + :author: Wachiou BOURAIMA + :tags: google + :category: gsoc + +Hello👋🏾 +I'm `Wachiou BOURAIMA `__, +All good things must come to an end, and it's with a mixture of satisfaction and nostalgia that I end this final week of my GSoC 2024 mission. It's been an incredible journey, and I can't wait to share the progress I've made in my final week. + + +Addressing Sphinx Warnings +-------------------------- + +In my final week, I focused on addressing the remaining Sphinx warnings related to the documentation. The primary challenge was understanding and resolving issues that arose from the documentation format. +The core issue stemmed from a conflict between the documentation conventions used. Specifically, the docstrings in our modules followed the ``numpydoc`` convention, while our ``conf.py`` file was set up for ``sphinx.ext.napoleon``. Since these two conventions have different structures and expectations, Sphinx struggled to compile the docstrings correctly, leading to numerous warnings. + +Here's a snippet of the configuration in our ``conf.py`` file: + +.. code-block:: python + + extensions = [ + ... + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.githubpages", + "sphinx.ext.intersphinx", + "sphinx.ext.napoleon", + ... + + ] + + +To address this: +---------------- + +1- Identified the Problem: + +- Discovered that the mismatch between the ``numpydoc`` style and the ``napoleon`` extension caused Sphinx to fail in parsing and generating documentation properly. + +2- Explored Solutions: + +- I reviewed the documentation styles and configurations to understand the differences between ``numpydoc`` and ``napoleon``. +- Evaluated whether to convert the docstrings to match the ``napoleon`` style or update the configuration to align with ``numpydoc``. + +3- Decided on a Path Forward: + +- After careful consideration, I chose to update the configuration to support the ``numpydoc`` style, as it was more consistent with our existing docstrings. +- By making this change, I was able to resolve the conflicts and successfully compile the documentation without warnings. + +Here's a snippet of the updated configuration in our ``conf.py`` file: + +.. code-block:: python + + extensions = [ + ... + "sphinx.ext.autodoc", + "numppydoc", + "sphinx.ext.autosummary", + "sphinx.ext.githubpages", + "sphinx.ext.intersphinx", + ... + ] + + +Did I get stuck? +----------------- + +No, I didn't get stuck. I was able to solve the problems by carefully analyzing them and choosing the most appropriate solution with the help of my mentor `Serge Koudoro `__. This experience further enhanced my troubleshooting skills and deepened my understanding of documentation conventions. + + +Acknowledgements +----------------- + +I'd like to sincerely thank my mentor, `Serge Koudoro `__, my peers: `Iñigo Tellaetxe Elorriaga `_, `Robin Roy `_, `Kaustav Deka `_ and the entire ``FURY`` team and community for their support and advice throughout this adventure. Your help has been essential to the success of this project. + + +Looking Ahead +------------- + +As `GSoC 2024` comes to an end, I'm filled with gratitude for this incredible learning experience. While my official time in `GSoC` is concluding, my journey with open source and ``FURY`` is far from over. I look forward to continuing to contribute and grow alongside the ``FURY`` community. +Thank you for following along with my `GSoC` journey. + + +Links +----- + +- `PR #922 `_ +- `Sphinx `_ +- `numpydoc `_ +- `napoleon `_ +- `Wachiou BOURAIMA `__ + + +Stay tuned for more updates as I continue to explore the world of open source software! diff --git a/docs/source/posts/2024/2024-08-20-week-12-robin.rst b/docs/source/posts/2024/2024-08-20-week-12-robin.rst new file mode 100644 index 000000000..8bfe17216 --- /dev/null +++ b/docs/source/posts/2024/2024-08-20-week-12-robin.rst @@ -0,0 +1,53 @@ +Week 12: Wrapping things up +=========================== + +.. post:: Aug 20 2024 + :author: Robin Roy + :tags: google + :category: gsoc + +Hi, I'm `Robin `_ and this is my blog about week 12. + +As the final official week, I spent my time wrapping things up and also improving the UX of the GitHub Application. + +Things I did in Week 12 +----------------------- + +1) **Improving GitHub App UX** + +Previously the bot responded to every discussion post. It was not a good approach and we tried stuff like @mentions. The problem is GitHub does not support bot mentions natively. Actually `Serge `_ had a better approach that is using Discussion Templates. I integrated that. Right now, you have a checkbox that you can tick to get the LLM answer as the first response. + +The new UI looks like this: + +.. image:: /_static/images/robin_gsoc_FURY_DISCUSSIONS_TEMPLATE.jpg + :alt: Present GitHub Discussions Template + + +2) **Documentation** + +Some of the API endpoints had no documentation, the documentation work is still ongoing. But I worked on adding basic info like how to test locally and stuff. It was added directly to the README.md files. I'll also make a separate GitHub Gists where I'll detail all the components and how they integrate with each other. + +3) **API testing** + +I plan to have testing for every endpoint. Testing includes the following: + +- Check the endpoints with valid data to see the response. Validate the JSON format. +- Check the endpoints with incorrect schema and record the response. +- Test by adjusting parameters like KNN. + +Testing will be a separate file, it'll be production testing. We'll hit the live endpoints directly. + + +What is coming up next week? +---------------------------- + +I'm working on the final report. Also, I'm working on finishing testing, documentation and updating the LLM response. The plan is to use a Re-Ranker to rerank the KNN references and filter ones not in context. + + +Did you get stuck anywhere? +--------------------------- + +No, I did not get stuck. I was having some health issues this week so was unable to make a lot of progress. But the general plan is prepared, and now I'll have to compile everything. + + +Thank you for reading! diff --git a/docs/source/release-history.rst b/docs/source/release-history.rst index 78a1e25b9..40c98cf4b 100644 --- a/docs/source/release-history.rst +++ b/docs/source/release-history.rst @@ -7,6 +7,7 @@ For a full list of the features implemented in the most recent release cycle, ch .. toctree:: :maxdepth: 1 + release_notes/releasev0.11.0 release_notes/releasev0.10.0 release_notes/releasev0.9.0 release_notes/releasev0.8.0 diff --git a/docs/source/release_notes/releasev0.11.0.rst b/docs/source/release_notes/releasev0.11.0.rst new file mode 100644 index 000000000..6f0da3881 --- /dev/null +++ b/docs/source/release_notes/releasev0.11.0.rst @@ -0,0 +1,125 @@ +.. _releasev0.11.0: + +============================== + Release notes v0.11.0 +============================== + +Quick Overview +-------------- + +* New SPEC: Keyword-only adopted. +* New SPEC: Lazy loading adopted. +* New standard for coding style. +* Documentation updated. +* Website updated. + +Details +------- + +GitHub stats for 2024/02/27 - 2024/07/31 (tag: v0.10.0) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 7 authors contributed 70 commits. + +* Ishan Kamboj +* Jon Haitz Legarreta Gorroño +* Kaustav Deka +* Robin Roy +* Serge Koudoro +* Wachiou BOURAÏMA +* dependabot[bot] + + +We closed a total of 83 issues, 35 pull requests and 48 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (35): + +* :ghpull:`919`: NF: Implementation of lazy_loading in `fury.stream.server` +* :ghpull:`918`: DOCS: simplify FURY import +* :ghpull:`916`: DOCS: simplify import +* :ghpull:`915`: [DOCS][FIX]: Update variable descriptions in visualization examples +* :ghpull:`907`: NF: Add lazy_loader feature in FURY +* :ghpull:`914`: DOC: GSoC Blogs Week 6, 7, 8 +* :ghpull:`911`: [DOC][FIX] fix typos in blog posts +* :ghpull:`913`: Fix: Replace setuptools.extern.packaging with direct packaging import +* :ghpull:`909`: RF: add keyword arguments decorator (warn_on_args_to_kwargs) in the module: stream +* :ghpull:`902`: RF: Add keyword arguments decorator to module: UI +* :ghpull:`899`: RF: Add keyword arguments to module: animation +* :ghpull:`901`: RF: Add keyword arguments decorator to module: shaders +* :ghpull:`900`: RF: Add keyword arguments to module: data +* :ghpull:`898`: RF: Add keyword arguments to module: actors +* :ghpull:`888`: NF: Add keyword_only decorator to enforce keyword-only arguments +* :ghpull:`908`: DOC: add Wachiou's week5 Blog post +* :ghpull:`906`: [DOC] GSoC week 4 and 5 +* :ghpull:`905`: DOC: My weeks 3 and 4 blog post +* :ghpull:`903`: CI: remove 3.8 add 3.12 +* :ghpull:`896`: DOC: GSoC Week 2 & 3 +* :ghpull:`897`: DOC: Add wachiou's week 2 blog post +* :ghpull:`892`: [DOC] week 1 blog GSoC +* :ghpull:`894`: DOC: Wachiou Week 1 Blog Post +* :ghpull:`893`: fix: gitignore +* :ghpull:`889`: DOC: Add Wachiou BOURAIMA GSoC'24 first Blog post +* :ghpull:`890`: [DOC] GSoC Blog: Robin Roy (Community Bonding) +* :ghpull:`891`: [TYPO] Typo fix in code +* :ghpull:`886`: DOC: Document the coding style enforcement framework +* :ghpull:`881`: STYLE: Format code using `ruff` +* :ghpull:`884`: build(deps): bump pre-commit/action from 3.0.0 to 3.0.1 in the actions group +* :ghpull:`885`: Fix pycodestyle stream +* :ghpull:`877`: Fixed Pycodestyle errors in fury/actors/odf_slicer.py, fury/actors/peak.py, fury/actors/tensor.py, and fury/data/fetcher.py +* :ghpull:`855`: Fix #780 : Added top/bottom for Tabs Bar in Tab Panel UI +* :ghpull:`879`: STYLE: Transition to `ruff` to enforce import statement sorting +* :ghpull:`868`: Added Dark mode, Fixed Search Bar for documentation site + +Issues (48): + +* :ghissue:`917`: `fury.stream.server` is missing lazy_loading +* :ghissue:`919`: NF: Implementation of lazy_loading in `fury.stream.server` +* :ghissue:`918`: DOCS: simplify FURY import +* :ghissue:`916`: DOCS: simplify import +* :ghissue:`915`: [DOCS][FIX]: Update variable descriptions in visualization examples +* :ghissue:`907`: NF: Add lazy_loader feature in FURY +* :ghissue:`914`: DOC: GSoC Blogs Week 6, 7, 8 +* :ghissue:`911`: [DOC][FIX] fix typos in blog posts +* :ghissue:`912`: Deprecator bug with setuptools >=71.0.3 +* :ghissue:`913`: Fix: Replace setuptools.extern.packaging with direct packaging import +* :ghissue:`910`: ENH: Add a GHA workflow to build docs +* :ghissue:`909`: RF: add keyword arguments decorator (warn_on_args_to_kwargs) in the module: stream +* :ghissue:`902`: RF: Add keyword arguments decorator to module: UI +* :ghissue:`899`: RF: Add keyword arguments to module: animation +* :ghissue:`901`: RF: Add keyword arguments decorator to module: shaders +* :ghissue:`900`: RF: Add keyword arguments to module: data +* :ghissue:`898`: RF: Add keyword arguments to module: actors +* :ghissue:`888`: NF: Add keyword_only decorator to enforce keyword-only arguments +* :ghissue:`908`: DOC: add Wachiou's week5 Blog post +* :ghissue:`906`: [DOC] GSoC week 4 and 5 +* :ghissue:`905`: DOC: My weeks 3 and 4 blog post +* :ghissue:`903`: CI: remove 3.8 add 3.12 +* :ghissue:`896`: DOC: GSoC Week 2 & 3 +* :ghissue:`897`: DOC: Add wachiou's week 2 blog post +* :ghissue:`895`: DOC: Add My week 2 blog post +* :ghissue:`892`: [DOC] week 1 blog GSoC +* :ghissue:`894`: DOC: Wachiou Week 1 Blog Post +* :ghissue:`893`: fix: gitignore +* :ghissue:`889`: DOC: Add Wachiou BOURAIMA GSoC'24 first Blog post +* :ghissue:`890`: [DOC] GSoC Blog: Robin Roy (Community Bonding) +* :ghissue:`871`: `actor.texture` hides all other actors from the scene +* :ghissue:`891`: [TYPO] Typo fix in code +* :ghissue:`887`: NF: Add keyword_only decorator to enforce keyword-only arguments +* :ghissue:`886`: DOC: Document the coding style enforcement framework +* :ghissue:`881`: STYLE: Format code using `ruff` +* :ghissue:`884`: build(deps): bump pre-commit/action from 3.0.0 to 3.0.1 in the actions group +* :ghissue:`883`: Wassiu contributions +* :ghissue:`885`: Fix pycodestyle stream +* :ghissue:`880`: improved readability in fetcher.py +* :ghissue:`882`: Wassiu contributions +* :ghissue:`876`: Pycodestyle errors in fury/actors/odf_slicer.py, fury/actors/peak.py, fury/actors/tensor.py, and fury/data/fetcher.py +* :ghissue:`877`: Fixed Pycodestyle errors in fury/actors/odf_slicer.py, fury/actors/peak.py, fury/actors/tensor.py, and fury/data/fetcher.py +* :ghissue:`878`: Docs: Remove '$' from fury/docs/README.md commands +* :ghissue:`780`: Tabs bar positioning in TabUI +* :ghissue:`855`: Fix #780 : Added top/bottom for Tabs Bar in Tab Panel UI +* :ghissue:`879`: STYLE: Transition to `ruff` to enforce import statement sorting +* :ghissue:`868`: Added Dark mode, Fixed Search Bar for documentation site +* :ghissue:`867`: Added Dark mode, Fixed Search Bar for documentation site diff --git a/fury/__init__.py b/fury/__init__.py index 1447797f9..ae1634876 100644 --- a/fury/__init__.py +++ b/fury/__init__.py @@ -2,8 +2,19 @@ import warnings +import lazy_loader as lazy + from fury.pkg_info import __version__, pkg_commit_hash +__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) + +__all__ += [ + "__version__", + "disable_warnings", + "enable_warnings", + "get_info", +] + def get_info(verbose=False): """Return dict describing the context of this package. diff --git a/fury/__init__.pyi b/fury/__init__.pyi new file mode 100644 index 000000000..9a961b136 --- /dev/null +++ b/fury/__init__.pyi @@ -0,0 +1,490 @@ +# flake8: noqa + +# This file is a stub type for the fury package. It provides information about types +# to help type-checking tools like mypy and improve the development experience +# with better autocompletion and documentation in code editors. + +__all__ = [ + "actor", + "actors", + "animation", + "colormap", + "convert", + "data", + "deprecator", + "decorators", + "gltf", + "interactor", + "io", + "layout", + "lib", + "material", + "molecular", + "optpkg", + "pick", + "pkg_info", + "primitive", + "shaders", + "stream", + "testing", + "transform", + "ui", + "utils", + "window", +] + +# the explicit definition of `__all__` will enable type inference for engines. + +from . import ( + actor, + actors, + animation, + colormap, + convert, + data, + decorators, + deprecator, + gltf, + interactor, + io, + layout, + lib, + material, + molecular, + optpkg, + pick, + pkg_info, + primitive, + shaders, + stream, + testing, + transform, + ui, + utils, + window, +) + +from .actor import ( + Container as Container, + _color_fa as _color_fa, + _fa as _fa, + _makeNd as _makeNd, + _roll_evals as _roll_evals, + _tensor_slicer_mapper as _tensor_slicer_mapper, + _textured_sphere_source as _textured_sphere_source, + arrow as arrow, + axes as axes, + billboard as billboard, + box as box, + cone as cone, + contour_from_label as contour_from_label, + contour_from_roi as contour_from_roi, + cube as cube, + cylinder as cylinder, + disk as disk, + dot as dot, + ellipsoid as ellipsoid, + figure as figure, + frustum as frustum, + grid as grid, + line as line, + markers as markers, + octagonalprism as octagonalprism, + odf_slicer as odf_slicer, + peak as peak, + peak_slicer as peak_slicer, + pentagonalprism as pentagonalprism, + point as point, + rectangle as rectangle, + rhombicuboctahedron as rhombicuboctahedron, + scalar_bar as scalar_bar, + sdf as sdf, + slicer as slicer, + sphere as sphere, + square as square, + streamtube as streamtube, + superquadric as superquadric, + surface as surface, + tensor_slicer as tensor_slicer, + text_3d as text_3d, + texture as texture, + texture_2d as texture_2d, + texture_on_sphere as texture_on_sphere, + texture_update as texture_update, + triangularprism as triangularprism, + uncertainty_cone as uncertainty_cone, + vector_text as vector_text, +) +from .actors import ( + OdfSlicerActor as OdfSlicerActor, + PeakActor as PeakActor, + _orientation_colors as _orientation_colors, + _peaks_colors_from_points as _peaks_colors_from_points, + _points_to_vtk_cells as _points_to_vtk_cells, + double_cone as double_cone, + main_dir_uncertainty as main_dir_uncertainty, + tensor_ellipsoid as tensor_ellipsoid, +) +from .animation import ( + Animation as Animation, + Timeline as Timeline, + color_interpolator as color_interpolator, + cubic_bezier_interpolator as cubic_bezier_interpolator, + cubic_spline_interpolator as cubic_spline_interpolator, + euclidean_distances as euclidean_distances, + get_next_timestamp as get_next_timestamp, + get_previous_timestamp as get_previous_timestamp, + get_time_tau as get_time_tau, + get_timestamps_from_keyframes as get_timestamps_from_keyframes, + get_values_from_keyframes as get_values_from_keyframes, + hsv_color_interpolator as hsv_color_interpolator, + lab_color_interpolator as lab_color_interpolator, + lerp as lerp, + linear_interpolator as linear_interpolator, + slerp as slerp, + spline_interpolator as spline_interpolator, + step_interpolator as step_interpolator, + tan_cubic_spline_interpolator as tan_cubic_spline_interpolator, + xyz_color_interpolator as xyz_color_interpolator, +) +from .colormap import ( + _lab2rgb as _lab2rgb, + _lab2xyz as _lab2xyz, + _lab_delta as _lab_delta, + _rgb2lab as _rgb2lab, + _rgb2xyz as _rgb2xyz, + _rgb_lab_delta as _rgb_lab_delta, + _xyz2lab as _xyz2lab, + _xyz2rgb as _xyz2rgb, + boys2rgb as boys2rgb, + cc as cc, + colormap_lookup_table as colormap_lookup_table, + create_colormap as create_colormap, + distinguishable_colormap as distinguishable_colormap, + get_cmap as get_cmap, + get_xyz_coords as get_xyz_coords, + hex_to_rgb as hex_to_rgb, + hsv2rgb as hsv2rgb, + lab2rgb as lab2rgb, + lab2xyz as lab2xyz, + line_colors as line_colors, + orient2rgb as orient2rgb, + rgb2hsv as rgb2hsv, + rgb2lab as rgb2lab, + rgb2xyz as rgb2xyz, + ss as ss, + xyz2lab as xyz2lab, + xyz2rgb as xyz2rgb, +) +from .convert import matplotlib_figure_to_numpy as matplotlib_figure_to_numpy +from .data import ( + FetcherError as FetcherError, + _already_there_msg as _already_there_msg, + _download as _download, + _fetch_gltf as _fetch_gltf, + _get_file_data as _get_file_data, + _get_file_sha as _get_file_sha, + _make_fetcher as _make_fetcher, + _request as _request, + check_sha as check_sha, + copyfileobj_withprogress as copyfileobj_withprogress, + fetch_data as fetch_data, + fetch_gltf as fetch_gltf, + fetch_viz_cubemaps as fetch_viz_cubemaps, + fetch_viz_dmri as fetch_viz_dmri, + fetch_viz_icons as fetch_viz_icons, + fetch_viz_models as fetch_viz_models, + fetch_viz_new_icons as fetch_viz_new_icons, + fetch_viz_textures as fetch_viz_textures, + fetch_viz_wiki_nw as fetch_viz_wiki_nw, + list_gltf_sample_models as list_gltf_sample_models, + read_viz_cubemap as read_viz_cubemap, + read_viz_dmri as read_viz_dmri, + read_viz_gltf as read_viz_gltf, + read_viz_icons as read_viz_icons, + read_viz_models as read_viz_models, + read_viz_textures as read_viz_textures, + update_progressbar as update_progressbar, +) +from .decorators import ( + doctest_skip_parser as doctest_skip_parser, + warn_on_args_to_kwargs as warn_on_args_to_kwargs, +) +from .deprecator import ( + ArgsDeprecationWarning as ArgsDeprecationWarning, + ExpiredDeprecationError as ExpiredDeprecationError, + _ensure_cr as _ensure_cr, + cmp_pkg_version as cmp_pkg_version, + deprecate_with_version as deprecate_with_version, + deprecated_params as deprecated_params, + is_bad_version as is_bad_version, +) +from .gltf import ( + glTF as glTF, + _connect_primitives as _connect_primitives, + export_scene as export_scene, + get_prim as get_prim, + write_accessor as write_accessor, + write_buffer as write_buffer, + write_bufferview as write_bufferview, + write_camera as write_camera, + write_material as write_material, + write_mesh as write_mesh, + write_node as write_node, + write_scene as write_scene, +) +from .interactor import ( + CustomInteractorStyle as CustomInteractorStyle, + Event as Event, +) +from .io import ( + load_cubemap_texture as load_cubemap_texture, + load_image as load_image, + load_polydata as load_polydata, + load_sprite_sheet as load_sprite_sheet, + load_text as load_text, + save_image as save_image, + save_polydata as save_polydata, +) +from .layout import ( + GridLayout as GridLayout, + HorizontalLayout as HorizontalLayout, + Layout as Layout, + VerticalLayout as VerticalLayout, + XLayout as XLayout, + YLayout as YLayout, + ZLayout as ZLayout, +) +from .material import ( + __PBRParams as __PBRParams, + manifest_pbr as manifest_pbr, + manifest_principled as manifest_principled, + manifest_standard as manifest_standard, +) +from .molecular import ( + Molecule as Molecule, + PTable as PTable, + add_atom as add_atom, + add_bond as add_bond, + ball_stick as ball_stick, + bounding_box as bounding_box, + compute_bonding as compute_bonding, + deep_copy_molecule as deep_copy_molecule, + get_all_atomic_numbers as get_all_atomic_numbers, + get_all_atomic_positions as get_all_atomic_positions, + get_all_bond_orders as get_all_bond_orders, + get_atomic_number as get_atomic_number, + get_atomic_position as get_atomic_position, + get_bond_order as get_bond_order, + ribbon as ribbon, + set_atomic_number as set_atomic_number, + set_atomic_position as set_atomic_position, + set_bond_order as set_bond_order, + sphere_cpk as sphere_cpk, + stick as stick, +) +from .optpkg import ( + TripWire as TripWire, + TripWireError as TripWireError, + is_tripwire as is_tripwire, + optional_package as optional_package, +) +from .pick import PickingManager as PickingManager +from .pkg_info import pkg_commit_hash as pkg_commit_hash +from .primitive import ( + faces_from_sphere_vertices as faces_from_sphere_vertices, + prim_arrow as prim_arrow, + prim_box as prim_box, + prim_cone as prim_cone, + prim_cylinder as prim_cylinder, + prim_frustum as prim_frustum, + prim_icosahedron as prim_icosahedron, + prim_octagonalprism as prim_octagonalprism, + prim_pentagonalprism as prim_pentagonalprism, + prim_rhombicuboctahedron as prim_rhombicuboctahedron, + prim_sphere as prim_sphere, + prim_square as prim_square, + prim_star as prim_star, + prim_superquadric as prim_superquadric, + prim_tetrahedron as prim_tetrahedron, + prim_triangularprism as prim_triangularprism, + repeat_primitive as repeat_primitive, + repeat_primitive_function as repeat_primitive_function, +) +from .shaders import ( + add_shader_callback as add_shader_callback, + attribute_to_actor as attribute_to_actor, + compose_shader as compose_shader, + import_fury_shader as import_fury_shader, + load as load, + load_shader as load_shader, + replace_shader_in_actor as replace_shader_in_actor, + shader_apply_effects as shader_apply_effects, + shader_to_actor as shader_to_actor, +) +from .stream import ( + ArrayCircularQueue as ArrayCircularQueue, + FuryStreamClient as FuryStreamClient, + FuryStreamInteraction as FuryStreamInteraction, + GenericCircularQueue as GenericCircularQueue, + GenericImageBufferManager as GenericImageBufferManager, + GenericMultiDimensionalBuffer as GenericMultiDimensionalBuffer, + IntervalTimer as IntervalTimer, + IntervalTimerThreading as IntervalTimerThreading, + RawArrayImageBufferManager as RawArrayImageBufferManager, + RawArrayMultiDimensionalBuffer as RawArrayMultiDimensionalBuffer, + SharedMemCircularQueue as SharedMemCircularQueue, + SharedMemImageBufferManager as SharedMemImageBufferManager, + SharedMemMultiDimensionalBuffer as SharedMemMultiDimensionalBuffer, + Widget as Widget, + check_port_is_available as check_port_is_available, + interaction_callback as interaction_callback, + remove_shm_from_resource_tracker as remove_shm_from_resource_tracker, +) +from .testing import ( + EventCounter as EventCounter, + assert_arrays_equal as assert_arrays_equal, + assert_operator as assert_operator, + captured_output as captured_output, + clear_and_catch_warnings as clear_and_catch_warnings, + setup_test as setup_test, +) +from .transform import ( + apply_transformation as apply_transformation, + cart2sphere as cart2sphere, + euler_matrix as euler_matrix, + rotate as rotate, + scale as scale, + sphere2cart as sphere2cart, + transform_from_matrix as transform_from_matrix, + translate as translate, +) +from .ui import ( + UI as UI, + Button2D as Button2D, + Card2D as Card2D, + Checkbox as Checkbox, + ComboBox2D as ComboBox2D, + Disk2D as Disk2D, + DrawPanel as DrawPanel, + DrawShape as DrawShape, + FileMenu2D as FileMenu2D, + GridUI as GridUI, + ImageContainer2D as ImageContainer2D, + LineDoubleSlider2D as LineDoubleSlider2D, + LineSlider2D as LineSlider2D, + ListBox2D as ListBox2D, + ListBoxItem2D as ListBoxItem2D, + Option as Option, + Panel2D as Panel2D, + PlaybackPanel as PlaybackPanel, + RadioButton as RadioButton, + RangeSlider as RangeSlider, + Rectangle2D as Rectangle2D, + RingSlider2D as RingSlider2D, + SpinBox as SpinBox, + TabPanel2D as TabPanel2D, + TabUI as TabUI, + TextBlock2D as TextBlock2D, + TextBox2D as TextBox2D, + cal_bounding_box_2d as cal_bounding_box_2d, + check_overflow as check_overflow, + clip_overflow as clip_overflow, + rotate_2d as rotate_2d, + wrap_overflow as wrap_overflow, +) +from .utils import ( + add_polydata_numeric_field as add_polydata_numeric_field, + apply_affine as apply_affine, + apply_affine_to_actor as apply_affine_to_actor, + array_from_actor as array_from_actor, + asbytes as asbytes, + change_vertices_order as change_vertices_order, + color_check as color_check, + colors_from_actor as colors_from_actor, + compute_bounds as compute_bounds, + fix_winding_order as fix_winding_order, + get_actor_from_polydata as get_actor_from_polydata, + get_actor_from_polymapper as get_actor_from_polymapper, + get_actor_from_primitive as get_actor_from_primitive, + get_bounding_box_sizes as get_bounding_box_sizes, + get_bounds as get_bounds, + get_grid_cells_position as get_grid_cells_position, + get_polydata_colors as get_polydata_colors, + get_polydata_field as get_polydata_field, + get_polydata_lines as get_polydata_lines, + get_polydata_normals as get_polydata_normals, + get_polydata_primitives_count as get_polydata_primitives_count, + get_polydata_tangents as get_polydata_tangents, + get_polydata_tcoord as get_polydata_tcoord, + get_polydata_triangles as get_polydata_triangles, + get_polydata_vertices as get_polydata_vertices, + get_polymapper_from_polydata as get_polymapper_from_polydata, + is_ui as is_ui, + lines_to_vtk_polydata as lines_to_vtk_polydata, + map_coordinates_3d_4d as map_coordinates_3d_4d, + normalize_v3 as normalize_v3, + normals_from_actor as normals_from_actor, + normals_from_v_f as normals_from_v_f, + normals_to_actor as normals_to_actor, + numpy_to_vtk_cells as numpy_to_vtk_cells, + numpy_to_vtk_colors as numpy_to_vtk_colors, + numpy_to_vtk_image_data as numpy_to_vtk_image_data, + numpy_to_vtk_matrix as numpy_to_vtk_matrix, + numpy_to_vtk_points as numpy_to_vtk_points, + primitives_count_from_actor as primitives_count_from_actor, + primitives_count_to_actor as primitives_count_to_actor, + remove_observer_from_actor as remove_observer_from_actor, + repeat_sources as repeat_sources, + represent_actor_as_wireframe as represent_actor_as_wireframe, + rgb_to_vtk as rgb_to_vtk, + rotate as rotate, + set_actor_origin as set_actor_origin, + set_input as set_input, + set_polydata_colors as set_polydata_colors, + set_polydata_normals as set_polydata_normals, + set_polydata_primitives_count as set_polydata_primitives_count, + set_polydata_tangents as set_polydata_tangents, + set_polydata_tcoords as set_polydata_tcoords, + set_polydata_triangles as set_polydata_triangles, + set_polydata_vertices as set_polydata_vertices, + shallow_copy as shallow_copy, + tangents_from_actor as tangents_from_actor, + tangents_from_direction_of_anisotropy as tangents_from_direction_of_anisotropy, + tangents_to_actor as tangents_to_actor, + triangle_order as triangle_order, + update_actor as update_actor, + update_polydata_normals as update_polydata_normals, + update_surface_actor_colors as update_surface_actor_colors, + vertices_from_actor as vertices_from_actor, + vtk_matrix_to_numpy as vtk_matrix_to_numpy, +) +from .window import ( + Scene as Scene, + ShowManager as ShowManager, + analyze_scene as analyze_scene, + analyze_snapshot as analyze_snapshot, + antialiasing as antialiasing, + enable_stereo as enable_stereo, + gl_disable_blend as gl_disable_blend, + gl_disable_depth as gl_disable_depth, + gl_enable_blend as gl_enable_blend, + gl_enable_depth as gl_enable_depth, + gl_get_current_state as gl_get_current_state, + gl_reset_blend as gl_reset_blend, + gl_set_additive_blending as gl_set_additive_blending, + gl_set_additive_blending_white_background as gl_set_additive_blending_white_background, + gl_set_multiplicative_blending as gl_set_multiplicative_blending, + gl_set_normal_blending as gl_set_normal_blending, + gl_set_subtractive_blending as gl_set_subtractive_blending, + record as record, + release_context as release_context, + show as show, + snapshot as snapshot, +) + +__version__: str + +def disable_warnings(warnings_origin=...): ... +def enable_warnings(warnings_origin=...): ... +def get_info(verbose=False): ... diff --git a/fury/actor.py b/fury/actor.py index 3094ef112..10c09c25d 100644 --- a/fury/actor.py +++ b/fury/actor.py @@ -15,7 +15,7 @@ tensor_ellipsoid, ) from fury.colormap import colormap_lookup_table -from fury.deprecator import deprecate_with_version, deprecated_params +from fury.decorators import warn_on_args_to_kwargs from fury.io import load_image from fury.lib import ( VTK_UNSIGNED_CHAR, @@ -88,8 +88,10 @@ ) +@warn_on_args_to_kwargs() def slicer( data, + *, affine=None, value_range=None, opacity=1.0, @@ -265,7 +267,8 @@ def display_extent(self, x1, x2, y1, y2, z1, z2): # line = np.array([[xmin, ymin, zmin]]) # self.outline_actor = actor.line() - def display(self, x=None, y=None, z=None): + @warn_on_args_to_kwargs() + def display(self, *, x=None, y=None, z=None): if x is None and y is None and z is None: self.display_extent(ex1, ex2, ey1, ey2, ez2 // 2, ez2 // 2) if x is not None: @@ -321,7 +324,12 @@ def shallow_copy(self): lut = lookup_colormap if lookup_colormap is None: # Create a black/white lookup table. - lut = colormap_lookup_table((r1, r2), (0, 0), (0, 0), (0, 1)) + lut = colormap_lookup_table( + scale_range=(r1, r2), + hue_range=(0, 0), + saturation_range=(0, 0), + value_range=(0, 1), + ) plane_colors = ImageMapToColors() plane_colors.SetOutputFormatToRGB() @@ -345,7 +353,8 @@ def shallow_copy(self): return image_actor -def surface(vertices, faces=None, colors=None, smooth=None, subdivision=3): +@warn_on_args_to_kwargs() +def surface(vertices, *, faces=None, colors=None, smooth=None, subdivision=3): """Generate a surface actor from an array of vertices. The color and smoothness of the surface can be customized by specifying @@ -422,7 +431,8 @@ def surface(vertices, faces=None, colors=None, smooth=None, subdivision=3): return surface_actor -def contour_from_roi(data, affine=None, color=None, opacity=1): +@warn_on_args_to_kwargs() +def contour_from_roi(data, *, affine=None, color=None, opacity=1): """Generate surface actor from a binary ROI. The color and opacity of the surface can be customized. @@ -541,7 +551,8 @@ def contour_from_roi(data, affine=None, color=None, opacity=1): return skin_actor -def contour_from_label(data, affine=None, color=None): +@warn_on_args_to_kwargs() +def contour_from_label(data, *, affine=None, color=None): """Generate surface actor from a labeled Array. The color and opacity of individual surfaces can be customized. @@ -586,15 +597,17 @@ def contour_from_label(data, affine=None, color=None): for i, roi_id in enumerate(unique_roi_id): roi_data = np.isin(data, roi_id).astype(int) roi_surface = contour_from_roi( - roi_data, affine, color=color[i], opacity=opacity[i] + roi_data, affine=affine, color=color[i], opacity=opacity[i] ) unique_roi_surfaces.AddPart(roi_surface) return unique_roi_surfaces +@warn_on_args_to_kwargs() def streamtube( lines, + *, colors=None, opacity=1, linewidth=0.1, @@ -662,7 +675,7 @@ def streamtube( >>> scene = window.Scene() >>> lines = [np.random.rand(10, 3), np.random.rand(20, 3)] >>> colors = np.random.rand(2, 3) - >>> c = actor.streamtube(lines, colors) + >>> c = actor.streamtube(lines, colors=colors) >>> scene.add(c) >>> #window.show(scene) @@ -687,7 +700,7 @@ def streamtube( """ # Poly data with lines and colors - poly_data, color_is_scalar = lines_to_vtk_polydata(lines, colors) + poly_data, color_is_scalar = lines_to_vtk_polydata(lines, colors=colors) next_input = poly_data # set primitives count @@ -760,8 +773,10 @@ def streamtube( return actor +@warn_on_args_to_kwargs() def line( lines, + *, colors=None, opacity=1, linewidth=1, @@ -832,13 +847,13 @@ def line( >>> scene = window.Scene() >>> lines = [np.random.rand(10, 3), np.random.rand(20, 3)] >>> colors = np.random.rand(2, 3) - >>> c = actor.line(lines, colors) + >>> c = actor.line(lines, colors=colors) >>> scene.add(c) >>> #window.show(scene) """ # Poly data with lines and colors - poly_data, color_is_scalar = lines_to_vtk_polydata(lines, colors) + poly_data, color_is_scalar = lines_to_vtk_polydata(lines, colors=colors) next_input = poly_data # set primitives count @@ -882,7 +897,8 @@ def line( if depth_cue: - def callback(_caller, _event, calldata=None): + @warn_on_args_to_kwargs() + def callback(_caller, _event, *, calldata=None): program = calldata if program is not None: program.SetUniformf("linewidth", linewidth) @@ -896,7 +912,8 @@ def callback(_caller, _event, calldata=None): return actor -def scalar_bar(lookup_table=None, title=" "): +@warn_on_args_to_kwargs() +def scalar_bar(*, lookup_table=None, title=" "): """Default scalar bar actor for a given colormap (colorbar). Parameters @@ -927,8 +944,14 @@ def scalar_bar(lookup_table=None, title=" "): return scalar_bar +@warn_on_args_to_kwargs() def axes( - scale=(1, 1, 1), colorx=(1, 0, 0), colory=(0, 1, 0), colorz=(0, 0, 1), opacity=1 + *, + scale=(1, 1, 1), + colorx=(1, 0, 0), + colory=(0, 1, 0), + colorz=(0, 0, 1), + opacity=1, ): """Create an actor with the coordinate's system axes where red = x, green = y, blue = z. @@ -956,12 +979,14 @@ def axes( colors = np.array([colorx + (opacity,), colory + (opacity,), colorz + (opacity,)]) scales = np.asarray(scale) - arrow_actor = arrow(centers, dirs, colors, scales, repeat_primitive=False) + arrow_actor = arrow(centers, dirs, colors, scales=scales, repeat_primitive=False) return arrow_actor +@warn_on_args_to_kwargs() def odf_slicer( odfs, + *, affine=None, mask=None, sphere=None, @@ -1032,7 +1057,7 @@ def odf_slicer( if sphere is None: # Use a default sphere with 100 vertices - vertices, faces = fp.prim_sphere("repulsion100") + vertices, faces = fp.prim_sphere(name="repulsion100") else: vertices = sphere.vertices faces = fix_winding_order(vertices, sphere.faces, clockwise=True) @@ -1065,8 +1090,8 @@ def odf_slicer( global_cm, colormap, opacity, - affine, - B_matrix, + affine=affine, + B=B_matrix, ) @@ -1078,7 +1103,8 @@ def _makeNd(array, ndim): return array.reshape(new_shape) -def _roll_evals(evals, axis=-1): +@warn_on_args_to_kwargs() +def _roll_evals(evals, *, axis=-1): """Check evals shape. Helper function to check that the evals provided to functions calculating @@ -1107,7 +1133,8 @@ def _roll_evals(evals, axis=-1): return evals -def _fa(evals, axis=-1): +@warn_on_args_to_kwargs() +def _fa(evals, *, axis=-1): r"""Return Fractional anisotropy (FA) of a diffusion tensor. Parameters @@ -1133,7 +1160,7 @@ def _fa(evals, axis=-1): \lambda_2^2+\lambda_3^2}} """ - evals = _roll_evals(evals, axis) + evals = _roll_evals(evals, axis=axis) # Make sure not to get nans all_zero = (evals == 0).all(axis=0) ev1, ev2, ev3 = evals @@ -1178,9 +1205,11 @@ def _color_fa(fa, evecs): return np.abs(evecs[..., 0]) * np.clip(fa, 0, 1)[..., None] +@warn_on_args_to_kwargs() def tensor_slicer( evals, evecs, + *, affine=None, mask=None, sphere=None, @@ -1256,7 +1285,8 @@ def display_extent(self, x1, x2, y1, y2, z1, z2): ) self.SetMapper(self.mapper) - def display(self, x=None, y=None, z=None): + @warn_on_args_to_kwargs() + def display(self, *, x=None, y=None, z=None): if x is None and y is None and z is None: self.display_extent( 0, @@ -1283,9 +1313,11 @@ def display(self, x=None, y=None, z=None): return tensor_actor +@warn_on_args_to_kwargs() def _tensor_slicer_mapper( evals, evecs, + *, affine=None, mask=None, sphere=None, @@ -1389,8 +1421,10 @@ def _tensor_slicer_mapper( return mapper +@warn_on_args_to_kwargs() def peak_slicer( peaks_dirs, + *, peaks_values=None, mask=None, affine=None, @@ -1510,7 +1544,8 @@ def display_extent(self, x1, x2, y1, y2, z1, z2): self.SetProperty(self.line.GetProperty()) self.SetMapper(self.line.GetMapper()) - def display(self, x=None, y=None, z=None): + @warn_on_args_to_kwargs() + def display(self, *, x=None, y=None, z=None): if x is None and y is None and z is None: self.display_extent( 0, @@ -1537,8 +1572,10 @@ def display(self, x=None, y=None, z=None): return peak_actor +@warn_on_args_to_kwargs() def peak( peaks_dirs, + *, peaks_values=None, mask=None, affine=None, @@ -1652,7 +1689,8 @@ def peak( ) -def dot(points, colors=None, opacity=None, dot_size=5): +@warn_on_args_to_kwargs() +def dot(points, *, colors=None, opacity=None, dot_size=5): """Create one or more 3d points. Parameters @@ -1699,7 +1737,7 @@ def dot(points, colors=None, opacity=None, dot_size=5): vtk_faces.InsertNextCell(1) vtk_faces.InsertCellPoint(idd) - color_tuple = color_check(len(points), colors) + color_tuple = color_check(len(points), colors=colors) color_array, global_opacity = color_tuple # Create a polydata object @@ -1729,12 +1767,8 @@ def dot(points, colors=None, opacity=None, dot_size=5): return poly_actor -dots = deprecate_with_version( - message="dots function has been renamed dot", since="0.8.1", until="0.9.0" -)(dot) - - -def point(points, colors, point_radius=0.1, phi=8, theta=8, opacity=1.0): +@warn_on_args_to_kwargs() +def point(points, colors, *, point_radius=0.1, phi=8, theta=8, opacity=1.0): """Visualize points as sphere glyphs. Parameters @@ -1778,9 +1812,11 @@ def point(points, colors, point_radius=0.1, phi=8, theta=8, opacity=1.0): ) +@warn_on_args_to_kwargs() def sphere( centers, colors, + *, radii=1.0, phi=16, theta=16, @@ -1863,16 +1899,18 @@ def sphere( big_verts, big_faces, big_colors, _ = res prim_count = len(centers) sphere_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) sphere_actor.GetProperty().SetOpacity(opacity) return sphere_actor +@warn_on_args_to_kwargs() def cylinder( centers, directions, colors, + *, radius=0.05, heights=1, capped=False, @@ -1948,7 +1986,7 @@ def cylinder( big_verts, big_faces, big_colors, _ = res prim_count = len(centers) cylinder_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) else: @@ -1976,10 +2014,12 @@ def cylinder( return cylinder_actor +@warn_on_args_to_kwargs() def disk( centers, directions, colors, + *, rinner=0.3, router=0.7, cresolution=6, @@ -2024,9 +2064,9 @@ def disk( >>> dirs = np.random.rand(5, 3) >>> colors = np.random.rand(5, 4) >>> actor = actor.disk(centers, dirs, colors, - >>> rinner=.1, router=.8, cresolution=30) + ... rinner=.1, router=.8, cresolution=30) >>> scene.add(actor) - >>> window.show(scene) + >>> # window.show(scene) """ if faces is None: @@ -2053,7 +2093,8 @@ def disk( return disk_actor -def square(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): +@warn_on_args_to_kwargs() +def square(centers, *, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): """Visualize one or many squares with different features. Parameters @@ -2077,7 +2118,7 @@ def square(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): >>> scene = window.Scene() >>> centers = np.random.rand(5, 3) >>> dirs = np.random.rand(5, 3) - >>> sq_actor = actor.square(centers, dirs) + >>> sq_actor = actor.square(centers, directions=dirs) >>> scene.add(sq_actor) >>> # window.show(scene) @@ -2095,13 +2136,14 @@ def square(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): big_verts, big_faces, big_colors, _ = res prim_count = len(centers) sq_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) sq_actor.GetProperty().BackfaceCullingOff() return sq_actor -def rectangle(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 0)): +@warn_on_args_to_kwargs() +def rectangle(centers, *, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 0)): """Visualize one or many rectangles with different features. Parameters @@ -2129,7 +2171,7 @@ def rectangle(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 0)) >>> scene = window.Scene() >>> centers = np.random.rand(5, 3) >>> dirs = np.random.rand(5, 3) - >>> rect_actor = actor.rectangle(centers, dirs) + >>> rect_actor = actor.rectangle(centers, directions=dirs) >>> scene.add(rect_actor) >>> # window.show(scene) @@ -2137,8 +2179,8 @@ def rectangle(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 0)) return square(centers=centers, directions=directions, colors=colors, scales=scales) -@deprecated_params(["size", "heights"], ["scales", "scales"], since="0.6", until="0.8") -def box(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 3)): +@warn_on_args_to_kwargs() +def box(centers, *, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 3)): """Visualize one or many boxes with different features. Parameters @@ -2162,7 +2204,7 @@ def box(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 3)): >>> scene = window.Scene() >>> centers = np.random.rand(5, 3) >>> dirs = np.random.rand(5, 3) - >>> box_actor = actor.box(centers, dirs, (1, 1, 1)) + >>> box_actor = actor.box(centers, directions=dirs, colors=(1, 1, 1)) >>> scene.add(box_actor) >>> # window.show(scene) @@ -2180,13 +2222,13 @@ def box(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 3)): big_verts, big_faces, big_colors, _ = res prim_count = len(centers) box_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) return box_actor -@deprecated_params("heights", "scales", since="0.6", until="0.8") -def cube(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): +@warn_on_args_to_kwargs() +def cube(centers, *, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): """Visualize one or many cubes with different features. Parameters @@ -2210,7 +2252,7 @@ def cube(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): >>> scene = window.Scene() >>> centers = np.random.rand(5, 3) >>> dirs = np.random.rand(5, 3) - >>> cube_actor = actor.cube(centers, dirs) + >>> cube_actor = actor.cube(centers, directions=dirs) >>> scene.add(cube_actor) >>> # window.show(scene) @@ -2218,10 +2260,12 @@ def cube(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): return box(centers=centers, directions=directions, colors=colors, scales=scales) +@warn_on_args_to_kwargs() def arrow( centers, directions, colors, + *, heights=1.0, resolution=10, tip_length=0.35, @@ -2270,7 +2314,7 @@ def arrow( >>> centers = np.random.rand(5, 3) >>> directions = np.random.rand(5, 3) >>> heights = np.random.rand(5) - >>> arrow_actor = actor.arrow(centers, directions, (1, 1, 1), heights) + >>> arrow_actor = actor.arrow(centers, directions, (1, 1, 1), heights=heights) >>> scene.add(arrow_actor) >>> # window.show(scene) @@ -2288,7 +2332,7 @@ def arrow( big_vertices, big_faces, big_colors, _ = res prim_count = len(centers) arrow_actor = get_actor_from_primitive( - big_vertices, big_faces, big_colors, prim_count=prim_count + big_vertices, big_faces, colors=big_colors, prim_count=prim_count ) return arrow_actor @@ -2313,10 +2357,12 @@ def arrow( return arrow_actor +@warn_on_args_to_kwargs() def cone( centers, directions, colors, + *, heights=1.0, resolution=10, vertices=None, @@ -2357,7 +2403,7 @@ def cone( >>> centers = np.random.rand(5, 3) >>> directions = np.random.rand(5, 3) >>> heights = np.random.rand(5) - >>> cone_actor = actor.cone(centers, directions, (1, 1, 1), heights) + >>> cone_actor = actor.cone(centers, directions, (1, 1, 1), heights=heights) >>> scene.add(cone_actor) >>> # window.show(scene) @@ -2389,13 +2435,14 @@ def cone( big_verts, big_faces, big_colors, _ = res prim_count = len(centers) cone_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) return cone_actor -def triangularprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): +@warn_on_args_to_kwargs() +def triangularprism(centers, *, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): """Visualize one or many regular triangular prisms with different features. Parameters @@ -2421,11 +2468,11 @@ def triangularprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): >>> dirs = np.random.rand(3, 3) >>> colors = np.random.rand(3, 3) >>> scales = np.random.rand(3, 1) - >>> actor = actor.triangularprism(centers, dirs, colors, scales) + >>> actor = actor.triangularprism(centers, directions=dirs, colors=colors, scales=scales) >>> scene.add(actor) >>> # window.show(scene) - """ + """ # noqa: E501 verts, faces = fp.prim_triangularprism() res = fp.repeat_primitive( verts, @@ -2438,12 +2485,13 @@ def triangularprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): big_verts, big_faces, big_colors, _ = res prim_count = len(centers) tprism_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) return tprism_actor -def rhombicuboctahedron(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): +@warn_on_args_to_kwargs() +def rhombicuboctahedron(centers, *, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): """Visualize one or many rhombicuboctahedron with different features. Parameters @@ -2469,11 +2517,11 @@ def rhombicuboctahedron(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales= >>> dirs = np.random.rand(3, 3) >>> colors = np.random.rand(3, 3) >>> scales = np.random.rand(3, 1) - >>> actor = actor.rhombicuboctahedron(centers, dirs, colors, scales) + >>> actor = actor.rhombicuboctahedron(centers, directions=dirs, colors=colors, scales=scales) >>> scene.add(actor) >>> # window.show(scene) - """ + """ # noqa: E501 verts, faces = fp.prim_rhombicuboctahedron() res = fp.repeat_primitive( verts, @@ -2486,12 +2534,13 @@ def rhombicuboctahedron(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales= big_verts, big_faces, big_colors, _ = res prim_count = len(centers) rcoh_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) return rcoh_actor -def pentagonalprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): +@warn_on_args_to_kwargs() +def pentagonalprism(centers, *, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): """Visualize one or many pentagonal prisms with different features. Parameters @@ -2518,11 +2567,11 @@ def pentagonalprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): >>> dirs = np.random.rand(3, 3) >>> colors = np.random.rand(3, 3) >>> scales = np.random.rand(3, 1) - >>> actor_pentagonal = actor.pentagonalprism(centers, dirs, colors, scales) + >>> actor_pentagonal = actor.pentagonalprism(centers, directions=dirs, colors=colors, scales=scales) >>> scene.add(actor_pentagonal) >>> # window.show(scene) - """ + """ # noqa: E501 verts, faces = fp.prim_pentagonalprism() res = fp.repeat_primitive( verts, @@ -2536,12 +2585,13 @@ def pentagonalprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): big_verts, big_faces, big_colors, _ = res prim_count = len(centers) pent_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) return pent_actor -def octagonalprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): +@warn_on_args_to_kwargs() +def octagonalprism(centers, *, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): """Visualize one or many octagonal prisms with different features. Parameters @@ -2567,11 +2617,11 @@ def octagonalprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): >>> dirs = np.random.rand(3, 3) >>> colors = np.random.rand(3, 3) >>> scales = np.random.rand(3, 1) - >>> actor = actor.octagonalprism(centers, dirs, colors, scales) + >>> actor = actor.octagonalprism(centers, directions=dirs, colors=colors, scales=scales) >>> scene.add(actor) >>> # window.show(scene) - """ + """ # noqa: E501 verts, faces = fp.prim_octagonalprism() res = fp.repeat_primitive( verts, @@ -2585,12 +2635,13 @@ def octagonalprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): big_verts, big_faces, big_colors, _ = res prim_count = len(centers) oct_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) return oct_actor -def frustum(centers, directions=(1, 0, 0), colors=(0, 1, 0), scales=1): +@warn_on_args_to_kwargs() +def frustum(centers, *, directions=(1, 0, 0), colors=(0, 1, 0), scales=1): """Visualize one or many frustum pyramids with different features. Parameters @@ -2616,7 +2667,7 @@ def frustum(centers, directions=(1, 0, 0), colors=(0, 1, 0), scales=1): >>> dirs = np.random.rand(4, 3) >>> colors = np.random.rand(4, 3) >>> scales = np.random.rand(4, 1) - >>> actor = actor.frustum(centers, dirs, colors, scales) + >>> actor = actor.frustum(centers, directions=dirs, colors=colors, scales=scales) >>> scene.add(actor) >>> # window.show(scene) @@ -2634,13 +2685,14 @@ def frustum(centers, directions=(1, 0, 0), colors=(0, 1, 0), scales=1): big_verts, big_faces, big_colors, _ = res prim_count = len(centers) frustum_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) return frustum_actor +@warn_on_args_to_kwargs() def superquadric( - centers, roundness=(1, 1), directions=(1, 0, 0), colors=(1, 0, 0), scales=1 + centers, *, roundness=(1, 1), directions=(1, 0, 0), colors=(1, 0, 0), scales=1 ): """Visualize one or many superquadrics with different features. @@ -2705,13 +2757,15 @@ def have_2_dimensions(arr): big_verts, big_faces, big_colors, _ = res prim_count = len(centers) spq_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) return spq_actor +@warn_on_args_to_kwargs() def billboard( centers, + *, colors=(0, 1, 0), scales=1, vs_dec=None, @@ -2766,7 +2820,7 @@ def billboard( prim_count = len(centers) bb_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) bb_actor.GetMapper().SetVBOShiftScaleMethod(False) bb_actor.GetProperty().BackfaceCullingOff() @@ -2859,7 +2913,9 @@ def billboard( return bb_actor +@warn_on_args_to_kwargs() def vector_text( + *, text="Origin", pos=(0, 0, 0), scale=(0.2, 0.2, 0.2), @@ -2958,15 +3014,10 @@ def add_to_scene(scene): return texta -label = deprecate_with_version( - message="Label function has been renamed" " vector_text", - since="0.7.1", - until="0.9.0", -)(vector_text) - - +@warn_on_args_to_kwargs() def text_3d( text, + *, position=(0, 0, 0), color=(1, 1, 1), font_size=12, @@ -3014,7 +3065,8 @@ def font_size(self, size): self.GetTextProperty().SetFontSize(24) text_actor.SetScale((1.0 / 24.0 * size,) * 3) - def font_family(self, _family="Arial"): + @warn_on_args_to_kwargs() + def font_family(self, *, _family="Arial"): self.GetTextProperty().SetFontFamilyToArial() def justification(self, justification): @@ -3041,7 +3093,8 @@ def vertical_justification(self, justification): "Unknown vertical justification: '{}'".format(justification) ) - def font_style(self, bold=False, italic=False, shadow=False): + @warn_on_args_to_kwargs() + def font_style(self, *, bold=False, italic=False, shadow=False): tprop = self.GetTextProperty() if bold: tprop.BoldOn() @@ -3069,8 +3122,8 @@ def get_position(self): text_actor.message(text) text_actor.font_size(font_size) text_actor.set_position(position) - text_actor.font_family(font_family) - text_actor.font_style(bold, italic, shadow) + text_actor.font_family(_family=font_family) + text_actor.font_style(bold=bold, italic=italic, shadow=shadow) text_actor.color(color) text_actor.justification(justification) text_actor.vertical_justification(vertical_justification) @@ -3096,7 +3149,8 @@ class Container: """ - def __init__(self, layout=None): + @warn_on_args_to_kwargs() + def __init__(self, *, layout=None): """Parameters ---------- layout : ``fury.layout.Layout`` object @@ -3229,8 +3283,10 @@ def __len__(self): return len(self._items) +@warn_on_args_to_kwargs() def grid( actors, + *, captions=None, caption_offset=(0, -100, 0), cell_padding=0, @@ -3311,7 +3367,8 @@ def grid( return grid -def figure(pic, interpolation="nearest"): +@warn_on_args_to_kwargs() +def figure(pic, *, interpolation="nearest"): """Return a figure as an image actor. Parameters @@ -3357,7 +3414,8 @@ def figure(pic, interpolation="nearest"): return image_actor -def texture(rgb, interp=True): +@warn_on_args_to_kwargs() +def texture(rgb, *, interp=True): """Map an RGB or RGBA texture on a plane. Parameters @@ -3424,8 +3482,8 @@ def texture_update(texture_actor, arr): This is the new image to be rendered on the actor. Dtype should be uint8. - Implementation - -------------- + Notes + ----- Check docs/examples/viz_video_on_plane.py """ @@ -3436,7 +3494,8 @@ def texture_update(texture_actor, arr): grid.GetPointData().SetScalars(vtkarr) -def _textured_sphere_source(theta=60, phi=60): +@warn_on_args_to_kwargs() +def _textured_sphere_source(*, theta=60, phi=60): """Use vtkTexturedSphereSource to set the theta and phi. Parameters @@ -3458,7 +3517,8 @@ def _textured_sphere_source(theta=60, phi=60): return tss -def texture_on_sphere(rgb, theta=60, phi=60, interpolate=True): +@warn_on_args_to_kwargs() +def texture_on_sphere(rgb, *, theta=60, phi=60, interpolate=True): """Map an RGB or RGBA texture on a sphere. Parameters @@ -3494,7 +3554,8 @@ def texture_on_sphere(rgb, theta=60, phi=60, interpolate=True): return earthActor -def texture_2d(rgb, interp=False): +@warn_on_args_to_kwargs() +def texture_2d(rgb, *, interp=False): """Create 2D texture from array. Parameters @@ -3560,7 +3621,10 @@ def texture_2d(rgb, interp=False): return act -def sdf(centers, directions=(1, 0, 0), colors=(1, 0, 0), primitives="torus", scales=1): +@warn_on_args_to_kwargs() +def sdf( + centers, *, directions=(1, 0, 0), colors=(1, 0, 0), primitives="torus", scales=1 +): """Create a SDF primitive based actor. Parameters @@ -3597,7 +3661,7 @@ def sdf(centers, directions=(1, 0, 0), colors=(1, 0, 0), primitives="torus", sca rep_verts, rep_faces, rep_colors, rep_centers = repeated prim_count = len(centers) box_actor = get_actor_from_primitive( - rep_verts, rep_faces, rep_colors, prim_count=prim_count + rep_verts, rep_faces, colors=rep_colors, prim_count=prim_count ) box_actor.GetMapper().SetVBOShiftScaleMethod(False) @@ -3641,8 +3705,10 @@ def sdf(centers, directions=(1, 0, 0), colors=(1, 0, 0), primitives="torus", sca return box_actor +@warn_on_args_to_kwargs() def markers( centers, + *, colors=(0, 1, 0), scales=1, marker="3d", @@ -3681,19 +3747,19 @@ def markers( >>> centers = np.random.normal(size=(n, 3), scale=10) >>> colors = np.random.rand(n, 4) >>> nodes_actor = actor.markers( - centers, - marker=markers, - edge_width=.1, - edge_color=[255, 255, 0], - colors=colors, - scales=10, - ) + ... centers, + ... marker=markers, + ... edge_width=.1, + ... edge_color=[255, 255, 0], + ... colors=colors, + ... scales=10, + ... ) >>> center = np.random.normal(size=(1, 3), scale=10) >>> nodes_3d_actor = actor.markers( - center, - marker='3d', - scales=5, - ) + ... center, + ... marker='3d', + ... scales=5, + ... ) >>> scene.add(nodes_actor, nodes_3d_actor) >>> # window.show(scene, size=(600, 600)) @@ -3707,7 +3773,7 @@ def markers( big_verts, big_faces, big_colors, big_centers = res prim_count = len(centers) sq_actor = get_actor_from_primitive( - big_verts, big_faces, big_colors, prim_count=prim_count + big_verts, big_faces, colors=big_colors, prim_count=prim_count ) sq_actor.GetMapper().SetVBOShiftScaleMethod(False) sq_actor.GetProperty().BackfaceCullingOff() @@ -3780,7 +3846,12 @@ def markers( attribute_to_actor(sq_actor, list_of_markers, "marker") def callback( - _caller, _event, calldata=None, uniform_type="f", uniform_name=None, value=None + _caller, + _event, + calldata=None, + uniform_type="f", + uniform_name=None, + value=None, ): program = calldata if program is not None: @@ -3819,7 +3890,16 @@ def callback( return sq_actor -def ellipsoid(centers, axes, lengths, colors=(1, 0, 0), scales=1.0, opacity=1.0): +@warn_on_args_to_kwargs() +def ellipsoid( + centers, + axes, + lengths, + *, + colors=(1, 0, 0), + scales=1.0, + opacity=1.0, +): """VTK actor for visualizing ellipsoids. Parameters @@ -3884,7 +3964,17 @@ def ellipsoid(centers, axes, lengths, colors=(1, 0, 0), scales=1.0, opacity=1.0) return tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity) -def uncertainty_cone(evals, evecs, signal, sigma, b_matrix, scales=0.6, opacity=1.0): +@warn_on_args_to_kwargs() +def uncertainty_cone( + evals, + evecs, + signal, + sigma, + b_matrix, + *, + scales=0.6, + opacity=1.0, +): """VTK actor for visualizing the cone of uncertainty representing the variance of the main direction of diffusion. @@ -3929,3 +4019,186 @@ def uncertainty_cone(evals, evecs, signal, sigma, b_matrix, scales=0.6, opacity= angles = main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix) return double_cone(centers, evecs, angles, colors, scales, opacity) + + +def odf( + centers, + coeffs, + degree=None, + sh_basis='descoteaux', + scales=1.0, + opacity=1.0 +): + """ + FURY actor for visualizing Orientation Distribution Functions (ODFs) given + an array of Spherical Harmonics (SH) coefficients. + + Parameters + ---------- + centers : ndarray(N, 3) + ODFs positions. + coeffs : (N, M) or (N, 6) or (N, 15) or (N, 28) or (N, 45) or (N, 66) or + (N, 91) ndarray. + Corresponding SH coefficients for the ODFs. + degree: int, optional + Index of the highest used band of the spherical harmonics basis. Must + be even, at least 2 and at most 12. If None the degree is set based on + the number of SH coefficients given. + sh_basis: str, optional + Type of basis (descoteaux, tournier) + 'descoteaux' for the default ``descoteaux07`` DYPY basis. + 'tournier' for the default ``tournier07` DYPY basis. + scales : float or ndarray (N, ) + ODFs size. + opacity : float + Takes values from 0 (fully transparent) to 1 (opaque). + + Returns + ------- + odf: Actor + + """ + + if not isinstance(centers, np.ndarray): + centers = np.array(centers) + if centers.ndim == 1: + centers = np.array([centers]) + + if not isinstance(coeffs, np.ndarray): + coeffs = np.array(coeffs) + if coeffs.ndim != 2: + if coeffs.ndim == 1: + coeffs = np.array([coeffs]) + else: + raise ValueError('coeffs should be a 2D array.') + if coeffs.shape[0] != centers.shape[0]: + raise ValueError('number of odf glyphs defined does not match with ' + 'number of centers') + + coeffs_given = coeffs.shape[-1] + max_degree = int((np.sqrt(8 * coeffs_given + 1) - 3) / 2) + if degree is None: + degree = max_degree + else: + if degree % 2 != 0: + warnings.warn('Invalid degree value. Degree must be a positive ' + 'even number lower or equal to 12. Ignoring passed ' + 'value and using maximum degree supported by the ' + 'number of SH coefficients.') + degree = max_degree + else: + coeffs_needed = int(((degree + 1) * (degree + 2)) / 2) + if coeffs_given < coeffs_needed: + warnings.warn('Not enough number of coefficient for SH of ' + 'degree {0}, expected at least {1}. Ignoring ' + 'passed value and using maximum degree supported ' + 'by the number of SH coefficients.' + .format(degree, coeffs_needed)) + degree = max_degree + coeffs = coeffs[:, :int(((degree + 1) * (degree + 2)) / 2)] + + if not isinstance(scales, np.ndarray): + scales = np.array(scales) + if scales.size == 1: + scales = np.repeat(scales, centers.shape[0]) + elif scales.size != centers.shape[0]: + scales = np.concatenate( + (scales, np.ones(centers.shape[0] - scales.shape[0])), axis=None) + + total = np.sum(abs(coeffs), axis=1) + coeffs = np.dot(np.diag(1 / total * scales), coeffs) * 1.7 + + total = np.sum(abs(coeffs), axis=1) + coeffs = np.dot(np.diag(1 / total * scales), coeffs) * 1.7 + + return sh_odf(centers, coeffs, degree, sh_basis, scales, opacity) + + +def odf( + centers, + coeffs, + degree=None, + sh_basis='descoteaux', + scales=1.0, + opacity=1.0 +): + """ + FURY actor for visualizing Orientation Distribution Functions (ODFs) given + an array of Spherical Harmonics (SH) coefficients. + + Parameters + ---------- + centers : ndarray(N, 3) + ODFs positions. + coeffs : (N, M) or (N, 6) or (N, 15) or (N, 28) or (N, 45) or (N, 66) or + (N, 91) ndarray. + Corresponding SH coefficients for the ODFs. + degree: int, optional + Index of the highest used band of the spherical harmonics basis. Must + be even, at least 2 and at most 12. If None the degree is set based on + the number of SH coefficients given. + sh_basis: str, optional + Type of basis (descoteaux, tournier) + 'descoteaux' for the default ``descoteaux07`` DYPY basis. + 'tournier' for the default ``tournier07` DYPY basis. + scales : float or ndarray (N, ) + ODFs size. + opacity : float + Takes values from 0 (fully transparent) to 1 (opaque). + + Returns + ------- + odf: Actor + + """ + + if not isinstance(centers, np.ndarray): + centers = np.array(centers) + if centers.ndim == 1: + centers = np.array([centers]) + + if not isinstance(coeffs, np.ndarray): + coeffs = np.array(coeffs) + if coeffs.ndim != 2: + if coeffs.ndim == 1: + coeffs = np.array([coeffs]) + else: + raise ValueError('coeffs should be a 2D array.') + if coeffs.shape[0] != centers.shape[0]: + raise ValueError('number of odf glyphs defined does not match with ' + 'number of centers') + + coeffs_given = coeffs.shape[-1] + max_degree = int((np.sqrt(8 * coeffs_given + 1) - 3) / 2) + if degree is None: + degree = max_degree + else: + if degree % 2 != 0: + warnings.warn('Invalid degree value. Degree must be a positive ' + 'even number lower or equal to 12. Ignoring passed ' + 'value and using maximum degree supported by the ' + 'number of SH coefficients.') + degree = max_degree + else: + coeffs_needed = int(((degree + 1) * (degree + 2)) / 2) + if coeffs_given < coeffs_needed: + warnings.warn('Not enough number of coefficient for SH of ' + 'degree {0}, expected at least {1}. Ignoring ' + 'passed value and using maximum degree supported ' + 'by the number of SH coefficients.' + .format(degree, coeffs_needed)) + degree = max_degree + coeffs = coeffs[:, :int(((degree + 1) * (degree + 2)) / 2)] + + if not isinstance(scales, np.ndarray): + scales = np.array(scales) + if scales.size == 1: + scales = np.repeat(scales, centers.shape[0]) + elif scales.size != centers.shape[0]: + scales = np.concatenate( + (scales, np.ones(centers.shape[0] - scales.shape[0])), axis=None) + + total = np.sum(abs(coeffs), axis=1) + coeffs = np.dot(np.diag(1 / total * scales), coeffs) * 1.7 + + return sh_odf(centers, coeffs, degree, sh_basis, scales, opacity) diff --git a/fury/actors/__init__.py b/fury/actors/__init__.py index e69de29bb..4f7e0516d 100644 --- a/fury/actors/__init__.py +++ b/fury/actors/__init__.py @@ -0,0 +1,5 @@ +# flake8: noqa: F401 + +import lazy_loader as lazy + +__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) diff --git a/fury/actors/__init__.pyi b/fury/actors/__init__.pyi new file mode 100644 index 000000000..88d8e7fc3 --- /dev/null +++ b/fury/actors/__init__.pyi @@ -0,0 +1,28 @@ +# This file is used to define the exported modules and +# classes for the fury.actors package. +# Explicitly define the exported modules +# This will enable type hinting for engines. + +__all__ = [ + "PeakActor", + "OdfSlicerActor", + "_orientation_colors", + "_peaks_colors_from_points", + "_points_to_vtk_cells", + "double_cone", + "main_dir_uncertainty", + "tensor_ellipsoid", +] + +from .odf_slicer import OdfSlicerActor +from .peak import ( + PeakActor, + _orientation_colors, + _peaks_colors_from_points, + _points_to_vtk_cells, +) +from .tensor import ( + double_cone, + main_dir_uncertainty, + tensor_ellipsoid, +) diff --git a/fury/actors/odf.py b/fury/actors/odf.py new file mode 100644 index 000000000..2f2b07f39 --- /dev/null +++ b/fury/actors/odf.py @@ -0,0 +1,376 @@ +import os + +import numpy as np + +from fury import actor +from fury.lib import FloatArray, Texture +from fury.shaders import ( + attribute_to_actor, + compose_shader, + import_fury_shader, + shader_to_actor, +) +from fury.utils import ( + numpy_to_vtk_image_data, + set_polydata_tcoords, + minmax_norm +) +from fury.texture.utils import uv_calculations + + +def sh_odf(centers, coeffs, degree, sh_basis, scales, opacity): + """ + Visualize one or many ODFs with different features. + + Parameters + ---------- + centers : ndarray(N, 3) + ODFs positions. + coeffs : ndarray + 2D ODFs array in SH coefficients. + sh_basis: str, optional + Type of basis (descoteaux, tournier) + 'descoteaux' for the default ``descoteaux07`` DYPY basis. + 'tournier' for the default ``tournier07` DYPY basis. + degree: int, optional + Index of the highest used band of the spherical harmonics basis. Must + be even, at least 2 and at most 12. + scales : float or ndarray (N, ) + ODFs size. + opacity : float + Takes values from 0 (fully transparent) to 1 (opaque). + + Returns + ------- + box_actor: Actor + + """ + odf_actor = actor.box(centers=centers, scales=scales) + odf_actor.GetMapper().SetVBOShiftScaleMethod(False) + odf_actor.GetProperty().SetOpacity(opacity) + + big_centers = np.repeat(centers, 8, axis=0) + attribute_to_actor(odf_actor, big_centers, "center") + + minmax = np.array([coeffs.min(axis=1), coeffs.max(axis=1)]).T + big_minmax = np.repeat(minmax, 8, axis=0) + attribute_to_actor(odf_actor, big_minmax, "minmax") + + odf_actor_pd = odf_actor.GetMapper().GetInput() + + n_glyphs = coeffs.shape[0] + # Coordinates to locate the data of each glyph in the texture. + uv_vals = np.array(uv_calculations(n_glyphs)) + num_pnts = uv_vals.shape[0] + + # Definition of texture coordinates to be associated with the actor. + t_coords = FloatArray() + t_coords.SetNumberOfComponents(2) + t_coords.SetNumberOfTuples(num_pnts) + [t_coords.SetTuple(i, uv_vals[i]) for i in range(num_pnts)] + + set_polydata_tcoords(odf_actor_pd, t_coords) + + # The coefficient data is stored in a texture to be passed to the shaders. + + # Data is normalized to a range of 0 to 1. + arr = minmax_norm(coeffs) + # Data is turned into values within the RGB color range, and then converted + # into a vtk image data. + arr *= 255 + grid = numpy_to_vtk_image_data(arr.astype(np.uint8)) + + # Vtk image data is associated to a texture. + texture = Texture() + texture.SetInputDataObject(grid) + texture.Update() + + # Texture is associated with the actor + odf_actor.GetProperty().SetTexture("texture0", texture) + + # The number of coefficients is associated to the order of the SH + odf_actor.GetShaderProperty().GetFragmentCustomUniforms().SetUniformf( + "numCoeffs", ((degree + 1) * (degree + 2)) / 2 + ) + + # Start of shader implementation + + vs_dec = \ + """ + in vec3 center; + in vec2 minmax; + + out vec4 vertexMCVSOutput; + out vec3 centerMCVSOutput; + out vec2 minmaxVSOutput; + out vec3 camPosMCVSOutput; + out vec3 camRightMCVSOutput; + out vec3 camUpMCVSOutput; + """ + + vs_impl = \ + """ + vertexMCVSOutput = vertexMC; + centerMCVSOutput = center; + minmaxVSOutput = minmax; + camPosMCVSOutput = -MCVCMatrix[3].xyz * mat3(MCVCMatrix); + camRightMCVSOutput = vec3( + MCVCMatrix[0][0], MCVCMatrix[1][0], MCVCMatrix[2][0]); + camUpMCVSOutput = vec3( + MCVCMatrix[0][1], MCVCMatrix[1][1], MCVCMatrix[2][1]); + """ + + shader_to_actor(odf_actor, "vertex", decl_code=vs_dec, impl_code=vs_impl) + + # The index of the highest used band of the spherical harmonics basis. Must + # be even, at least 2 and at most 12. + def_sh_degree = "#define SH_DEGREE " + str(degree) + + # The number of spherical harmonics basis functions + def_sh_count = "#define SH_COUNT (((SH_DEGREE + 1) * (SH_DEGREE + 2)) / 2)" + + # Degree of polynomials for which we have to find roots + def_max_degree = "#define MAX_DEGREE (2 * SH_DEGREE + 2)" + + # If GL_EXT_control_flow_attributes is available, these defines should be + # defined as [[unroll]] and [[loop]] to give reasonable hints to the + # compiler. That avoids register spilling, which makes execution + # considerably faster. + def_gl_ext_control_flow_attributes = \ + """ + #ifndef _unroll_ + #define _unroll_ + #endif + #ifndef _loop_ + #define _loop_ + #endif + """ + + # When there are fewer intersections/roots than theoretically possible, + # some array entries are set to this value + def_no_intersection = "#define NO_INTERSECTION 3.4e38" + + # pi and its reciprocal + def_pis = \ + """ + #define M_PI 3.141592653589793238462643 + #define M_INV_PI 0.318309886183790671537767526745 + """ + + fs_vs_vars = \ + """ + in vec4 vertexMCVSOutput; + in vec3 centerMCVSOutput; + in vec2 minmaxVSOutput; + in vec3 camPosMCVSOutput; + in vec3 camRightMCVSOutput; + in vec3 camUpMCVSOutput; + """ + + coeffs_norm = import_fury_shader(os.path.join("utils", "minmax_norm.glsl")) + + eval_sh_composed = "" + for i in range(2, degree + 1, 2): #PUT sh_degree + eval_sh = import_fury_shader( + os.path.join("rt_odfs", sh_basis, "eval_sh_" + str(i) + ".frag") + ) + eval_sh_grad = import_fury_shader( + os.path.join( + "rt_odfs", sh_basis, "eval_sh_grad_" + str(i) + ".frag" + ) + ) + eval_sh_composed = compose_shader( + [eval_sh_composed, eval_sh, eval_sh_grad] + ) + + # Searches a single root of a polynomial within a given interval. + # param out_root The location of the found root. + # param out_end_value The value of the given polynomial at end. + # param poly Coefficients of the polynomial for which a root should be + # found. + # Coefficient poly[i] is multiplied by x^i. + # param begin The beginning of an interval where the polynomial is + # monotonic. + # param end The end of said interval. + # param begin_value The value of the given polynomial at begin. + # param error_tolerance The error tolerance for the returned root + # location. + # Typically the error will be much lower but in theory it can be + # bigger. + # + # return true if a root was found, false if no root exists. + newton_bisection = import_fury_shader( + os.path.join("utils", "newton_bisection.frag") + ) + + # Finds all roots of the given polynomial in the interval [begin, end] and + # writes them to out_roots. Some entries will be NO_INTERSECTION but other + # than that the array is sorted. The last entry is always NO_INTERSECTION. + find_roots = import_fury_shader(os.path.join("utils", "find_roots.frag")) + + # Evaluates the spherical harmonics basis in bands 0, 2, ..., SH_DEGREE. + # Conventions are as in the following paper. + # M. Descoteaux, E. Angelino, S. Fitzgibbons, and R. Deriche. Regularized, + # fast, and robust analytical q-ball imaging. Magnetic Resonance in + # Medicine, 58(3), 2007. https://doi.org/10.1002/mrm.21277 + # param out_shs Values of SH basis functions in bands 0, 2, ..., + # SH_DEGREE in this order. + # param point The point on the unit sphere where the basis should be + # evaluated. + eval_sh = import_fury_shader(os.path.join("rt_odfs", "eval_sh.frag")) + + # Evaluates the gradient of each basis function given by eval_sh() and the + # basis itself + eval_sh_grad = import_fury_shader( + os.path.join("rt_odfs", "eval_sh_grad.frag") + ) + + # Outputs a matrix that turns equidistant samples on the unit circle of a + # homogeneous polynomial into coefficients of that polynomial. + get_inv_vandermonde = import_fury_shader( + os.path.join("rt_odfs", "get_inv_vandermonde.frag") + ) + + # Determines all intersections between a ray and a spherical harmonics + # glyph. + # param out_ray_params The ray parameters at intersection points. The + # points themselves are at ray_origin + out_ray_params[i] * ray_dir. + # Some entries may be NO_INTERSECTION but other than that the array + # is sorted. + # param sh_coeffs SH_COUNT spherical harmonic coefficients defining the + # glyph. Their exact meaning is defined by eval_sh(). + # param ray_origin The origin of the ray, relative to the glyph center. + # param ray_dir The normalized direction vector of the ray. + ray_sh_glyph_intersections = import_fury_shader( + os.path.join("rt_odfs", "ray_sh_glyph_intersections.frag") + ) + + # Provides a normalized normal vector for a spherical harmonics glyph. + # param sh_coeffs SH_COUNT spherical harmonic coefficients defining the + # glyph. Their exact meaning is defined by eval_sh(). + # param point A point on the surface of the glyph, relative to its + # center. + # + # return A normalized surface normal pointing away from the origin. + get_sh_glyph_normal = import_fury_shader( + os.path.join("rt_odfs", "get_sh_glyph_normal.frag") + ) + + # Applies the non-linearity that maps linear RGB to sRGB + linear_to_srgb = import_fury_shader( + os.path.join("lighting", "linear_to_srgb.frag") + ) + + # Inverse of linear_to_srgb() + srgb_to_linear = import_fury_shader( + os.path.join("lighting", "srgb_to_linear.frag") + ) + + # Turns a linear RGB color (i.e. rec. 709) into sRGB + linear_rgb_to_srgb = import_fury_shader( + os.path.join("lighting", "linear_rgb_to_srgb.frag") + ) + + # Inverse of linear_rgb_to_srgb() + srgb_to_linear_rgb = import_fury_shader( + os.path.join("lighting", "srgb_to_linear_rgb.frag") + ) + + # Logarithmic tonemapping operator. Input and output are linear RGB. + tonemap = import_fury_shader(os.path.join("rt_odfs", "tonemap.frag")) + + # Blinn-Phong illumination model + blinn_phong_model = import_fury_shader( + os.path.join("lighting", "blinn_phong_model.frag") + ) + + # fmt: off + fs_dec = compose_shader([ + def_sh_degree, def_sh_count, def_max_degree, + def_gl_ext_control_flow_attributes, def_no_intersection, def_pis, + fs_vs_vars, coeffs_norm, eval_sh_composed, newton_bisection, find_roots, + eval_sh, eval_sh_grad, get_inv_vandermonde, ray_sh_glyph_intersections, + get_sh_glyph_normal, blinn_phong_model, linear_to_srgb, srgb_to_linear, + linear_rgb_to_srgb, srgb_to_linear_rgb, tonemap + ]) + # fmt: on + + shader_to_actor(odf_actor, "fragment", decl_code=fs_dec) + + point_from_vs = "vec3 pnt = vertexMCVSOutput.xyz;" + + # Ray origin is the camera position in world space + ray_origin = "vec3 ro = camPosMCVSOutput;" + + # Ray direction is the normalized difference between the fragment and the + # camera position/ray origin + ray_direction = "vec3 rd = normalize(pnt - ro);" + + # Light direction in a retroreflective model is the normalized difference + # between the camera position/ray origin and the fragment + light_direction = "vec3 ld = normalize(ro - pnt);" + + # Define SH coefficients (measured up to band 8, noise beyond that) + sh_coeffs = \ + """ + float i = 1 / (numCoeffs * 2); + float sh_coeffs[SH_COUNT]; + for(int j=0; j 0.0) { + first_ray_param = ray_params[i]; + break; + } + } + """ + + # Evaluate shading for a directional light + directional_light = \ + """ + vec3 color = vec3(1.); + if (first_ray_param != NO_INTERSECTION) { + vec3 intersection = ro - centerMCVSOutput + first_ray_param * rd; + vec3 normal = get_sh_glyph_normal(sh_coeffs, intersection); + vec3 colorDir = srgb_to_linear_rgb(abs(normalize(intersection))); + float attenuation = dot(ld, normal); + color = blinnPhongIllumModel( + attenuation, lightColor0, colorDir, specularPower, + specularColor, ambientColor); + } else { + discard; + } + """ + + frag_output = \ + """ + vec3 out_color = linear_rgb_to_srgb(tonemap(color)); + fragOutput0 = vec4(out_color, opacity); + """ + + fs_impl = compose_shader([ + point_from_vs, ray_origin, ray_direction, light_direction, sh_coeffs, + intersection_test, first_intersection, directional_light, frag_output + ]) + + shader_to_actor(odf_actor, "fragment", impl_code=fs_impl, block="picking") + + return odf_actor diff --git a/fury/actors/odf_slicer.py b/fury/actors/odf_slicer.py index 8b75d200a..1fe075b44 100644 --- a/fury/actors/odf_slicer.py +++ b/fury/actors/odf_slicer.py @@ -2,6 +2,7 @@ import numpy as np from fury.colormap import create_colormap +from fury.decorators import warn_on_args_to_kwargs from fury.lib import Actor, PolyData, PolyDataMapper from fury.utils import ( apply_affine, @@ -51,6 +52,7 @@ class OdfSlicerActor(Actor): """ + @warn_on_args_to_kwargs() def __init__( self, odfs, @@ -64,6 +66,7 @@ def __init__( global_cm, colormap, opacity, + *, affine=None, B=None, ): @@ -122,7 +125,8 @@ def display_extent(self, x1, x2, y1, y2, z1, z2): self._update_mapper() - def slice_along_axis(self, slice_index, axis="zaxis"): + @warn_on_args_to_kwargs() + def slice_along_axis(self, slice_index, *, axis="zaxis"): """Slice ODF field at given `slice_index` along axis in ['xaxis', 'yaxis', zaxis']. """ @@ -156,16 +160,17 @@ def slice_along_axis(self, slice_index, axis="zaxis"): else: raise ValueError("Invalid axis name {0}.".format(axis)) - def display(self, x=None, y=None, z=None): + @warn_on_args_to_kwargs() + def display(self, *, x=None, y=None, z=None): """Display a slice along x, y, or z axis.""" if x is None and y is None and z is None: self.slice_along_axis(self.grid_shape[2] // 2) elif x is not None: - self.slice_along_axis(x, "xaxis") + self.slice_along_axis(x, axis="xaxis") elif y is not None: - self.slice_along_axis(y, "yaxis") + self.slice_along_axis(y, axis="yaxis") elif z is not None: - self.slice_along_axis(z, "zaxis") + self.slice_along_axis(z, axis="zaxis") def update_sphere(self, vertices, faces, B): """Dynamically change the sphere used for SH to SF projection.""" @@ -254,14 +259,14 @@ def _generate_color_for_vertices(self, sf): if self.colormap is None: raise IOError("if global_cm=True, colormap must be defined.") else: - all_colors = create_colormap(sf.ravel(), self.colormap) * 255 + all_colors = create_colormap(sf.ravel(), name=self.colormap) * 255 elif self.colormap is not None: if isinstance(self.colormap, str): # Map ODFs values [min, max] to [0, 1] for each ODF range_sf = sf.max(axis=-1) - sf.min(axis=-1) rescaled = sf - sf.min(axis=-1, keepdims=True) rescaled[range_sf > 0] /= range_sf[range_sf > 0][..., None] - all_colors = create_colormap(rescaled.ravel(), self.colormap) * 255 + all_colors = create_colormap(rescaled.ravel(), name=self.colormap) * 255 else: all_colors = np.tile( np.array(self.colormap).reshape(1, 3), diff --git a/fury/actors/peak.py b/fury/actors/peak.py index 931f9db5d..1f06dd754 100644 --- a/fury/actors/peak.py +++ b/fury/actors/peak.py @@ -3,6 +3,7 @@ import numpy as np from fury.colormap import boys2rgb, colormap_lookup_table, orient2rgb +from fury.decorators import warn_on_args_to_kwargs from fury.lib import ( VTK_OBJECT, Actor, @@ -27,45 +28,61 @@ class PeakActor(Actor): Parameters ---------- + directions : ndarray - Peak directions. The shape of the array should be (X, Y, Z, D, 3). + + Peak directions. The shape of the array should be (X, Y, Z, D, 3). + indices : tuple - Indices given in tuple(x_indices, y_indices, z_indices) - format for mapping 2D ODF array to 3D voxel grid. + + Indices given in tuple(x_indices, y_indices, z_indices) + format for mapping 2D ODF array to 3D voxel grid. + values : ndarray, optional - Peak values. The shape of the array should be (X, Y, Z, D). + + Peak values. The shape of the array should be (X, Y, Z, D). + affine : array, optional - 4x4 transformation array from native coordinates to world coordinates. - colors : None or string ('rgb_standard') or tuple (3D or 4D) or - array/ndarray (N, 3 or 4) or array/ndarray (K, 3 or 4) or - array/ndarray(N, ) or array/ndarray (K, ) - If None a standard orientation colormap is used for every line. - If one tuple of color is used. Then all streamlines will have the same - color. - If an array (N, 3 or 4) is given, where N is equal to the number of - points. Then every point is colored with a different RGB(A) color. - If an array (K, 3 or 4) is given, where K is equal to the number of - lines. Then every line is colored with a different RGB(A) color. - If an array (N, ) is given, where N is the number of points then these - are considered as the values to be used by the colormap. - If an array (K,) is given, where K is the number of lines then these - are considered as the values to be used by the colormap. + + 4x4 transformation array from native coordinates to world coordinates. + + colors : None or string ('rgb_standard') or tuple (3D or 4D) or array/ndarray (N, 3 or 4) or array/ndarray (K, 3 or 4) or array/ndarray(N, ) or array/ndarray (K, ) + + If None a standard orientation colormap is used for every line. + If one tuple of color is used. Then all streamlines will have the same + color. + If an array (N, 3 or 4) is given, where N is equal to the number of + points. Then every point is colored with a different RGB(A) color. + If an array (K, 3 or 4) is given, where K is equal to the number of + lines. Then every line is colored with a different RGB(A) color. + If an array (N, ) is given, where N is the number of points then these + are considered as the values to be used by the colormap. + If an array (K,) is given, where K is the number of lines then these + are considered as the values to be used by the colormap. + lookup_colormap : vtkLookupTable, optional - Add a default lookup table to the colormap. Default is None which calls - :func:`fury.actor.colormap_lookup_table`. + + Add a default lookup table to the colormap. Default is None which calls + :func:`fury.actor.colormap_lookup_table`. + linewidth : float, optional - Line thickness. Default is 1. + + Line thickness. Default is 1. + symmetric: bool, optional - If True, peaks are drawn for both peaks_dirs and -peaks_dirs. Else, - peaks are only drawn for directions given by peaks_dirs. Default is - True. - """ + If True, peaks are drawn for both peaks_dirs and -peaks_dirs. Else, + peaks are only drawn for directions given by peaks_dirs. Default is + True. + + """ # noqa: E501 + @warn_on_args_to_kwargs() def __init__( self, directions, indices, + *, values=None, affine=None, colors=None, @@ -210,11 +227,12 @@ def __init__( self.__cross_section = self.__high_ranges // 2 self.__mapper.AddObserver( - Command.UpdateShaderEvent, self.__display_peaks_vtk_callback + Command.UpdateShaderEvent, self.__display_peaks_vtk_callback(None, None) ) + @warn_on_args_to_kwargs() @calldata_type(VTK_OBJECT) - def __display_peaks_vtk_callback(self, caller, event, calldata=None): + def __display_peaks_vtk_callback(self, caller, event, *, calldata=None): if calldata is not None: calldata.SetUniformi("isRange", self.__is_range) calldata.SetUniform3f("highRanges", self.__high_ranges) @@ -275,7 +293,8 @@ def min_centers(self): return self.__min_centers -def _orientation_colors(points, cmap="rgb_standard"): +@warn_on_args_to_kwargs() +def _orientation_colors(points, *, cmap="rgb_standard"): """ Parameters ---------- @@ -306,7 +325,8 @@ def _orientation_colors(points, cmap="rgb_standard"): return np.asarray(col_list) -def _peaks_colors_from_points(points, colors=None, points_per_line=2): +@warn_on_args_to_kwargs() +def _peaks_colors_from_points(points, *, colors=None, points_per_line=2): """Return a VTK scalar array containing colors information for each one of the peaks according to the policy defined by the parameter colors. @@ -376,7 +396,8 @@ def _peaks_colors_from_points(points, colors=None, points_per_line=2): return color_array, colors_are_scalars, global_opacity -def _points_to_vtk_cells(points, points_per_line=2): +@warn_on_args_to_kwargs() +def _points_to_vtk_cells(points, *, points_per_line=2): """Return the VTK cell array for the peaks given the set of points coordinates. diff --git a/fury/actors/tensor.py b/fury/actors/tensor.py index 5bb701b9e..2ad06a639 100644 --- a/fury/actors/tensor.py +++ b/fury/actors/tensor.py @@ -400,18 +400,22 @@ def main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix): ---------- evals : ndarray (3, ) or (N, 3) Eigenvalues. + evecs : ndarray (3, 3) or (N, 3, 3) Eigenvectors. + signal : 3D or 4D ndarray Predicted signal. + sigma : ndarray Standard deviation of the noise. + b_matrix : array (N, 7) Design matrix for DTI. Returns ------- - angles: array + angles : array Notes ----- @@ -421,12 +425,12 @@ def main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix): directly from estimated D and its estimated covariance matrix :math:`\\Delta D` (see [2]_, equation 4). The angle :math:`\\Theta` between the perturbed principal eigenvector of D, - :math:`\\epsilon_1+\\Delta\\epsilon_1`, and the estimated eigenvector + :math:`\\epsilon_1 + \\Delta\\epsilon_1`, and the estimated eigenvector :math:`\\epsilon_1`, measures the angular deviation of the main fiber direction and can be approximated by: .. math:: - \\Theta=tan^{-1}(\\|\\Delta\\epsilon_1\\|) + \\Theta = tan^{-1}(\\|\\Delta \\ epsilon_1\\|) Giving way to a graphical construct for displaying both the main eigenvector of D and its associated uncertainty, with the so-called @@ -435,13 +439,13 @@ def main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix): References ---------- .. [1] Basser, P. J. (1997). Quantifying errors in fiber direction and - diffusion tensor field maps resulting from MR noise. In 5th Scientific - Meeting of the ISMRM (Vol. 1740). + diffusion tensor field maps resulting from MR noise. In 5th Scientific + Meeting of the ISMRM (Vol. 1740). .. [2] Chang, L. C., Koay, C. G., Pierpaoli, C., & Basser, P. J. (2007). - Variance of estimated DTI-derived parameters via first-order perturbation - methods. Magnetic Resonance in Medicine: An Official Journal of the - International Society for Magnetic Resonance in Medicine, 57(1), 141-149. + Variance of estimated DTI-derived parameters via first-order perturbation + methods. Magnetic Resonance in Medicine: An Official Journal of the + International Society for Magnetic Resonance in Medicine, 57(1), 141-149. """ angles = np.ones(evecs.shape[0]) diff --git a/fury/animation/__init__.py b/fury/animation/__init__.py index 10cd5a103..62d86f776 100644 --- a/fury/animation/__init__.py +++ b/fury/animation/__init__.py @@ -1,8 +1,3 @@ -from fury.animation.animation import Animation, CameraAnimation -from fury.animation.timeline import Timeline +import lazy_loader as lazy -__all__ = [ - "Animation", - "CameraAnimation", - "Timeline", -] +__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) diff --git a/fury/animation/__init__.pyi b/fury/animation/__init__.pyi new file mode 100644 index 000000000..daa5e4709 --- /dev/null +++ b/fury/animation/__init__.pyi @@ -0,0 +1,51 @@ +# This file is used to enable type hinting for the `fury.animation` module. +# explicit definition of `__all__` will enable type inference for engines. + +__all__ = [ + "Animation", + "CameraAnimation", + "Timeline", + "euclidean_distances", + "get_next_timestamp", + "get_previous_timestamp", + "get_time_tau", + "get_timestamps_from_keyframes", + "get_values_from_keyframes", + "lerp", + "color_interpolator", + "cubic_bezier_interpolator", + "cubic_spline_interpolator", + "hsv_color_interpolator", + "lab_color_interpolator", + "linear_interpolator", + "slerp", + "spline_interpolator", + "step_interpolator", + "tan_cubic_spline_interpolator", + "xyz_color_interpolator", +] + +from .animation import Animation, CameraAnimation +from .helpers import ( + euclidean_distances, + get_next_timestamp, + get_previous_timestamp, + get_time_tau, + get_timestamps_from_keyframes, + get_values_from_keyframes, + lerp, +) +from .interpolator import ( + color_interpolator, + cubic_bezier_interpolator, + cubic_spline_interpolator, + hsv_color_interpolator, + lab_color_interpolator, + linear_interpolator, + slerp, + spline_interpolator, + step_interpolator, + tan_cubic_spline_interpolator, + xyz_color_interpolator, +) +from .timeline import Timeline diff --git a/fury/animation/animation.py b/fury/animation/animation.py index f2fa56bb9..faee0dfec 100644 --- a/fury/animation/animation.py +++ b/fury/animation/animation.py @@ -13,6 +13,7 @@ spline_interpolator, step_interpolator, ) +from fury.decorators import warn_on_args_to_kwargs from fury.lib import Actor, Camera, Transform @@ -42,7 +43,8 @@ class Animation: """ - def __init__(self, actors=None, length=None, loop=True, motion_path_res=None): + @warn_on_args_to_kwargs() + def __init__(self, *, actors=None, length=None, loop=True, motion_path_res=None): super().__init__() self._data = defaultdict(dict) self._animations = [] @@ -191,7 +193,8 @@ def _get_attribute_data(self, attrib): } return data.get(attrib) - def get_keyframes(self, attrib=None): + @warn_on_args_to_kwargs() + def get_keyframes(self, *, attrib=None): """Get a keyframe for a specific or all attributes. Parameters @@ -209,8 +212,9 @@ def get_keyframes(self, attrib=None): } return data.get(attrib, {}).get("keyframes", {}) + @warn_on_args_to_kwargs() def set_keyframe( - self, attrib, timestamp, value, update_interpolator=True, **kwargs + self, attrib, timestamp, value, *, update_interpolator=True, **kwargs ): """Set a keyframe for a certain attribute. @@ -263,7 +267,7 @@ def set_keyframe( self._timeline.update_duration() else: self.update_duration() - self.update_animation(0) + self.update_animation(time=0) self.update_motion_path() def set_keyframes(self, attrib, keyframes): @@ -279,11 +283,12 @@ def set_keyframes(self, attrib, keyframes): Notes ----- Keyframes can be on any of the following forms: + >>> import numpy as np >>> key_frames_simple = {1: [1, 2, 1], 2: [3, 4, 5]} >>> key_frames_bezier = {1: {'value': [1, 2, 1]}, - >>> 2: {'value': [3, 4, 5], 'in_cp': [1, 2, 3]}} + ... 2: {'value': [3, 4, 5], 'in_cp': [1, 2, 3]}} >>> pos_keyframes = {1: np.array([1, 2, 3]), 3: np.array([5, 5, 5])} - >>> Animation.set_keyframes('position', pos_keyframes) + >>> Animation.set_keyframes('position', pos_keyframes) # doctest: +SKIP """ for t, keyframe in keyframes.items(): @@ -359,7 +364,8 @@ def _handle_scene_event(self, timestamp): self._scene.rm(*self._actors) self._added_to_scene = False - def set_interpolator(self, attrib, interpolator, is_evaluator=False, **kwargs): + @warn_on_args_to_kwargs() + def set_interpolator(self, attrib, interpolator, *, is_evaluator=False, **kwargs): """Set keyframes interpolator for a certain property Parameters @@ -372,8 +378,9 @@ def set_interpolator(self, attrib, interpolator, is_evaluator=False, **kwargs): is_evaluator: bool, optional Specifies whether the `interpolator` is time-only based evaluation function that does not depend on keyframes such as: - >>> def get_position(t): - >>> return np.array([np.sin(t), np.cos(t) * 5, 5]) + + def get_position(t): + return np.array([np.sin(t), np.cos(t) * 5, 5]) Other Parameters ---------------- @@ -390,10 +397,9 @@ def set_interpolator(self, attrib, interpolator, is_evaluator=False, **kwargs): Examples -------- - >>> Animation.set_interpolator('position', linear_interpolator) - - >>> pos_fun = lambda t: np.array([np.sin(t), np.cos(t), 0]) - >>> Animation.set_interpolator('position', pos_fun) + >>> Animation.set_interpolator('position', linear_interpolator) # doctest: +SKIP + >>> pos_fun = lambda t: np.array([np.sin(t), np.cos(t), 0]) # doctest: +SKIP + >>> Animation.set_interpolator('position', pos_fun) # doctest: +SKIP """ attrib_data = self._get_attribute_data(attrib) @@ -437,7 +443,8 @@ def is_interpolatable(self, attrib): data = self._data return bool(data.get(attrib, {}).get("interpolator", {}).get("func")) - def set_position_interpolator(self, interpolator, is_evaluator=False, **kwargs): + @warn_on_args_to_kwargs() + def set_position_interpolator(self, interpolator, *, is_evaluator=False, **kwargs): """Set the position interpolator. Parameters @@ -457,14 +464,15 @@ def set_position_interpolator(self, interpolator, is_evaluator=False, **kwargs): Examples -------- - >>> Animation.set_position_interpolator(spline_interpolator, degree=5) + >>> Animation.set_position_interpolator(spline_interpolator, degree=5) # doctest: +SKIP - """ + """ # noqa: E501 self.set_interpolator( "position", interpolator, is_evaluator=is_evaluator, **kwargs ) - def set_scale_interpolator(self, interpolator, is_evaluator=False): + @warn_on_args_to_kwargs() + def set_scale_interpolator(self, interpolator, *, is_evaluator=False): """Set the scale interpolator. Parameters @@ -478,12 +486,13 @@ def set_scale_interpolator(self, interpolator, is_evaluator=False): Examples -------- - >>> Animation.set_scale_interpolator(step_interpolator) + >>> Animation.set_scale_interpolator(step_interpolator) # doctest: +SKIP """ self.set_interpolator("scale", interpolator, is_evaluator=is_evaluator) - def set_rotation_interpolator(self, interpolator, is_evaluator=False): + @warn_on_args_to_kwargs() + def set_rotation_interpolator(self, interpolator, *, is_evaluator=False): """Set the rotation interpolator . Parameters @@ -497,12 +506,13 @@ def set_rotation_interpolator(self, interpolator, is_evaluator=False): Examples -------- - >>> Animation.set_rotation_interpolator(slerp) + >>> Animation.set_rotation_interpolator(slerp) # doctest: +SKIP """ self.set_interpolator("rotation", interpolator, is_evaluator=is_evaluator) - def set_color_interpolator(self, interpolator, is_evaluator=False): + @warn_on_args_to_kwargs() + def set_color_interpolator(self, interpolator, *, is_evaluator=False): """Set the color interpolator. Parameters @@ -516,12 +526,13 @@ def set_color_interpolator(self, interpolator, is_evaluator=False): Examples -------- - >>> Animation.set_color_interpolator(lab_color_interpolator) + >>> Animation.set_color_interpolator(lab_color_interpolator) # doctest: +SKIP """ self.set_interpolator("color", interpolator, is_evaluator=is_evaluator) - def set_opacity_interpolator(self, interpolator, is_evaluator=False): + @warn_on_args_to_kwargs() + def set_opacity_interpolator(self, interpolator, *, is_evaluator=False): """Set the opacity interpolator. Parameters @@ -535,7 +546,7 @@ def set_opacity_interpolator(self, interpolator, is_evaluator=False): Examples -------- - >>> Animation.set_opacity_interpolator(step_interpolator) + >>> Animation.set_opacity_interpolator(step_interpolator) # doctest: +SKIP """ self.set_interpolator("opacity", interpolator, is_evaluator=is_evaluator) @@ -614,8 +625,8 @@ def set_position_keyframes(self, keyframes): Examples -------- - >>> pos_keyframes = {1, np.array([0, 0, 0]), 3, np.array([50, 6, 6])} - >>> Animation.set_position_keyframes(pos_keyframes) + >>> pos_keyframes = {1, (0, 0, 0), 3, (50, 6, 6)} + >>> Animation.set_position_keyframes(pos_keyframes) # doctest: +SKIP """ self.set_keyframes("position", keyframes) @@ -694,8 +705,8 @@ def set_scale_keyframes(self, keyframes): Examples -------- - >>> scale_keyframes = {1, np.array([1, 1, 1]), 3, np.array([2, 2, 3])} - >>> Animation.set_scale_keyframes(scale_keyframes) + >>> scale_keyframes = {1, (1, 1, 1), 3, (2, 2, 3)} + >>> Animation.set_scale_keyframes(scale_keyframes) # doctest: +SKIP """ self.set_keyframes("scale", keyframes) @@ -725,8 +736,9 @@ def set_color_keyframes(self, keyframes): Examples -------- - >>> color_keyframes = {1, np.array([1, 0, 1]), 3, np.array([0, 0, 1])} - >>> Animation.set_color_keyframes(color_keyframes) + >>> import numpy as np + >>> color_keyframes = {1, (1, 0, 1), 3, (0, 0, 1)} + >>> Animation.set_color_keyframes(color_keyframes) # doctest: +SKIP """ self.set_keyframes("color", keyframes) @@ -760,8 +772,8 @@ def set_opacity_keyframes(self, keyframes): Examples -------- - >>> opacity = {1, np.array([1, 1, 1]), 3, np.array([2, 2, 3])} - >>> Animation.set_scale_keyframes(opacity) + >>> opacity = {1, (1, 1, 1), 3, (2, 2, 3)} + >>> Animation.set_scale_keyframes(opacity) # doctest: +SKIP """ self.set_keyframes("opacity", keyframes) @@ -899,7 +911,8 @@ def add_child_animation(self, animation): self._animations.append(animation) self.update_duration() - def add_actor(self, actor, static=False): + @warn_on_args_to_kwargs() + def add_actor(self, actor, *, static=False): """Add an actor or list of actors to the Animation. Parameters @@ -1094,7 +1107,8 @@ def add_update_callback(self, callback, prop=None): attrib = self._get_attribute_data(prop) attrib.get("callbacks", []).append(callback) - def update_animation(self, time=None): + @warn_on_args_to_kwargs() + def update_animation(self, *, time=None): """Update the animation. Update the animation at a certain time. This will make sure all @@ -1168,7 +1182,7 @@ def update_animation(self, time=None): [callback(time) for callback in self._general_callbacks] # Also update all child Animations. - [animation.update_animation(time) for animation in self._animations] + [animation.update_animation(time=time) for animation in self._animations] if self._scene and not has_handler: self._scene.reset_clipping_range() @@ -1184,7 +1198,7 @@ def add_to_scene(self, scene): self._scene = scene self._added_to_scene = True self._start_time = perf_counter() - self.update_animation(0) + self.update_animation(time=0) def remove_from_scene(self, scene): """Remove Animation, its actors and sub Animations from the scene""" @@ -1217,7 +1231,8 @@ class CameraAnimation(Animation): """ - def __init__(self, camera=None, length=None, loop=True, motion_path_res=None): + @warn_on_args_to_kwargs() + def __init__(self, *, camera=None, length=None, loop=True, motion_path_res=None): super(CameraAnimation, self).__init__( length=length, loop=loop, motion_path_res=motion_path_res ) @@ -1286,8 +1301,8 @@ def set_focal_keyframes(self, keyframes): Examples -------- - >>> focal_pos = {0, np.array([1, 1, 1]), 3, np.array([20, 0, 0])} - >>> CameraAnimation.set_focal_keyframes(focal_pos) + >>> focal_pos = {0, (1, 1, 1), 3, (20, 0, 0)} + >>> CameraAnimation.set_focal_keyframes(focal_pos) # doctest: +SKIP """ self.set_keyframes("focal", keyframes) @@ -1305,8 +1320,8 @@ def set_view_up_keyframes(self, keyframes): Examples -------- - >>> view_ups = {0, np.array([1, 0, 0]), 3, np.array([0, 1, 0])} - >>> CameraAnimation.set_view_up_keyframes(view_ups) + >>> view_ups = {0, np.array([1, 0, 0]), 3, np.array([0, 1, 0])} # doctest: +SKIP + >>> CameraAnimation.set_view_up_keyframes(view_ups) # doctest: +SKIP """ self.set_keyframes("view_up", keyframes) @@ -1353,7 +1368,8 @@ def get_view_up(self, t): """ return self.get_value("view_up", t) - def set_focal_interpolator(self, interpolator, is_evaluator=False): + @warn_on_args_to_kwargs() + def set_focal_interpolator(self, interpolator, *, is_evaluator=False): """Set the camera focal position interpolator. Parameters @@ -1368,7 +1384,8 @@ def set_focal_interpolator(self, interpolator, is_evaluator=False): """ self.set_interpolator("focal", interpolator, is_evaluator=is_evaluator) - def set_view_up_interpolator(self, interpolator, is_evaluator=False): + @warn_on_args_to_kwargs() + def set_view_up_interpolator(self, interpolator, *, is_evaluator=False): """Set the camera up-view vector animation interpolator. Parameters @@ -1383,7 +1400,8 @@ def set_view_up_interpolator(self, interpolator, is_evaluator=False): """ self.set_interpolator("view_up", interpolator, is_evaluator=is_evaluator) - def update_animation(self, time=None): + @warn_on_args_to_kwargs() + def update_animation(self, *, time=None): """Update the camera animation. Parameters @@ -1396,7 +1414,7 @@ def update_animation(self, time=None): if self._camera is None: if self._scene: self._camera = self._scene.camera() - self.update_animation(time) + self.update_animation(tile=time) return else: if self.is_interpolatable("rotation"): diff --git a/fury/animation/helpers.py b/fury/animation/helpers.py index 03746f386..6ea49da20 100644 --- a/fury/animation/helpers.py +++ b/fury/animation/helpers.py @@ -1,7 +1,10 @@ import numpy as np +from fury.decorators import warn_on_args_to_kwargs -def get_previous_timestamp(timestamps, current_time, include_last=False): + +@warn_on_args_to_kwargs() +def get_previous_timestamp(timestamps, current_time, *, include_last=False): """Return the maximum previous timestamp of a given time. Parameters @@ -26,7 +29,8 @@ def get_previous_timestamp(timestamps, current_time, include_last=False): return timestamps[0] -def get_next_timestamp(timestamps, current_time, include_first=False): +@warn_on_args_to_kwargs() +def get_next_timestamp(timestamps, current_time, *, include_first=False): """Return the minimum next timestamp of a given time. Parameters diff --git a/fury/animation/interpolator.py b/fury/animation/interpolator.py index a7228a7dd..9e3e9cf83 100644 --- a/fury/animation/interpolator.py +++ b/fury/animation/interpolator.py @@ -25,7 +25,7 @@ def spline_interpolator(keyframes, degree): keyframes: dict Keyframe data containing timestamps and values to form the spline curve. Data should be on the following format: - >>> {1: {'value': np.array([...])}, 2: {'value': np.array([...])}} + {1: {'value': np.array([...])}, 2: {'value': np.array([...])}} Returns ------- diff --git a/fury/animation/tests/test_animation.py b/fury/animation/tests/test_animation.py index 207e94a61..469996345 100644 --- a/fury/animation/tests/test_animation.py +++ b/fury/animation/tests/test_animation.py @@ -30,14 +30,14 @@ def test_animation(): anim.add_static_actor(cube_actor) assert cube_actor in anim.static_actors - anim = Animation(cube_actor) + anim = Animation(actors=cube_actor) assert cube_actor in anim.actors anim_main = Animation() anim_main.add_child_animation(anim) assert anim in anim_main.child_animations - anim = Animation(cube_actor) + anim = Animation(actors=cube_actor) anim.set_position(0, np.array([1, 1, 1])) # overriding a keyframe anim.set_position(0, np.array([0, 0, 0])) @@ -79,7 +79,7 @@ def test_animation(): cube = actor.cube(np.array([[0, 0, 0]])) anim.add_actor(cube) - anim.update_animation(0) + anim.update_animation(time=0) if not shaders: transform = cube.GetUserTransform() npt.assert_almost_equal(anim.get_position(0), transform.GetPosition()) @@ -89,7 +89,7 @@ def test_animation(): def test_camera_animation(): cam = Camera() - anim = CameraAnimation(cam) + anim = CameraAnimation(camera=cam) assert anim.camera is cam @@ -101,13 +101,13 @@ def test_camera_animation(): anim.set_rotation(0, np.array([180, 0, 0])) - anim.update_animation(0) + anim.update_animation(time=0) npt.assert_almost_equal(cam.GetPosition(), np.array([1, 2, 3])) npt.assert_almost_equal(cam.GetFocalPoint(), np.array([10, 20, 30])) - anim.update_animation(3) + anim.update_animation(time=3) npt.assert_almost_equal(cam.GetPosition(), np.array([3, 2, 1])) npt.assert_almost_equal(cam.GetFocalPoint(), np.array([30, 20, 10])) - anim.update_animation(1.5) + anim.update_animation(time=1.5) npt.assert_almost_equal(cam.GetPosition(), np.array([2, 2, 2])) npt.assert_almost_equal(cam.GetFocalPoint(), np.array([20, 20, 20])) rot = np.zeros(16) diff --git a/fury/animation/tests/test_timeline.py b/fury/animation/tests/test_timeline.py index 79a3301be..1a1618ac3 100644 --- a/fury/animation/tests/test_timeline.py +++ b/fury/animation/tests/test_timeline.py @@ -57,7 +57,7 @@ def test_timeline(): anim.set_position(12, [1, 2, 1]) assert tl_2.duration == length - tl_2 = Timeline(anim, length=11) + tl_2 = Timeline(animations=anim, length=11) assert tl_2.duration == 11 tl = Timeline(playback_panel=True) diff --git a/fury/animation/timeline.py b/fury/animation/timeline.py index 7156a809d..17d342b93 100644 --- a/fury/animation/timeline.py +++ b/fury/animation/timeline.py @@ -6,6 +6,7 @@ from fury import window from fury.animation.animation import Animation +from fury.decorators import warn_on_args_to_kwargs from fury.lib import RenderWindow, WindowToImageFilter, numpy_support from fury.ui.elements import PlaybackPanel @@ -33,7 +34,10 @@ class Timeline: """ - def __init__(self, animations=None, playback_panel=False, loop=True, length=None): + @warn_on_args_to_kwargs() + def __init__( + self, *, animations=None, playback_panel=False, loop=True, length=None + ): self._scene = None self.playback_panel = None self._current_timestamp = 0 @@ -284,8 +288,10 @@ def has_playback_panel(self): """ return self.playback_panel is not None + @warn_on_args_to_kwargs() def record( self, + *, fname=None, fps=30, speed=1.0, @@ -450,7 +456,8 @@ def animations(self) -> "list[Animation]": """ return self._animations - def update(self, force=False): + @warn_on_args_to_kwargs() + def update(self, *, force=False): """Update the timeline. Update the Timeline and all the animations that it controls. As well as @@ -477,7 +484,7 @@ def update(self, force=False): else: self.pause() if self.playing or force: - [anim.update_animation(time) for anim in self._animations] + [anim.update_animation(time=time) for anim in self._animations] def add_to_scene(self, scene): """Add Timeline and all of its Animations to the scene""" diff --git a/fury/colormap.py b/fury/colormap.py index 932191227..3666d31d5 100644 --- a/fury/colormap.py +++ b/fury/colormap.py @@ -6,6 +6,7 @@ from scipy import linalg from fury.data import DATA_DIR +from fury.decorators import warn_on_args_to_kwargs from fury.lib import LookupTable # Allow import, but disable doctests if we don't have matplotlib @@ -14,7 +15,9 @@ cm, have_matplotlib, _ = optional_package("matplotlib.cm") +@warn_on_args_to_kwargs() def colormap_lookup_table( + *, scale_range=(0, 1), hue_range=(0.8, 0), saturation_range=(1, 1), @@ -242,7 +245,8 @@ def orient2rgb(v): return orient -def line_colors(streamlines, cmap="rgb_standard"): +@warn_on_args_to_kwargs() +def line_colors(streamlines, *, cmap="rgb_standard"): """Create colors for streamlines to be used in actor.line. Parameters @@ -308,7 +312,8 @@ def simple_cmap(v): return simple_cmap -def create_colormap(v, name="plasma", auto=True): +@warn_on_args_to_kwargs() +def create_colormap(v, *, name="plasma", auto=True): """Create colors from a specific colormap and return it as an array of shape (N,3) where every row gives the corresponding r,g,b value. The colormaps we use are similar with those of matplotlib. @@ -511,7 +516,8 @@ def _lab2rgb(lab): return _xyz2rgb(tmp) -def distinguishable_colormap(bg=(0, 0, 0), exclude=None, nb_colors=None): +@warn_on_args_to_kwargs() +def distinguishable_colormap(*, bg=(0, 0, 0), exclude=None, nb_colors=None): """Generate colors that are maximally perceptually distinct. This function generates a set of colors which are distinguishable @@ -544,15 +550,9 @@ def distinguishable_colormap(bg=(0, 0, 0), exclude=None, nb_colors=None): Examples -------- - >>> from dipy.viz.colormap import distinguishable_colormap + >>> from fury.colormap import distinguishable_colormap >>> # Generate 5 colors - >>> [c for i, c in zip(range(5), distinguishable_colormap())] - [array([ 0., 1., 0.]), - array([ 1., 0., 1.]), - array([ 1. , 0.75862069, 0.03448276]), - array([ 0. , 1. , 0.89655172]), - array([ 0. , 0.17241379, 1. ])] - + >>> _ = [c for i, c in zip(range(5), distinguishable_colormap())] Notes ----- @@ -669,7 +669,7 @@ def rgb2hsv(rgb): out_v = rgb.max(-1) # -- S channel - delta = rgb.ptp(-1) + delta = np.ptp(rgb, -1) # Ignore warning for zero divided by zero old_settings = np.seterr(invalid="ignore") out_s = delta / out_v @@ -887,10 +887,14 @@ def get_xyz_coords(illuminant, observer): Notes ----- Original Implementation from scikit-image package. - it can be found at: + it can be found here: https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py This implementation might have been modified. + References + ---------- + .. [1] scikit-image, `colorconv.py` source code + """ illuminant = illuminant.upper() observer = observer.upper() @@ -903,7 +907,8 @@ def get_xyz_coords(illuminant, observer): ) from err -def xyz2lab(xyz, illuminant="D65", observer="2"): +@warn_on_args_to_kwargs() +def xyz2lab(xyz, *, illuminant="D65", observer="2"): """XYZ to CIE-LAB color space conversion. Parameters @@ -950,7 +955,8 @@ def xyz2lab(xyz, illuminant="D65", observer="2"): return np.concatenate([x[..., np.newaxis] for x in [L, a, b]], axis=-1) -def lab2xyz(lab, illuminant="D65", observer="2"): +@warn_on_args_to_kwargs() +def lab2xyz(lab, *, illuminant="D65", observer="2"): """CIE-LAB to XYZcolor space conversion. Parameters @@ -1001,7 +1007,8 @@ def lab2xyz(lab, illuminant="D65", observer="2"): return out -def rgb2lab(rgb, illuminant="D65", observer="2"): +@warn_on_args_to_kwargs() +def rgb2lab(rgb, *, illuminant="D65", observer="2"): """Conversion from the sRGB color space (IEC 61966-2-1:1999) to the CIE Lab colorspace under the given illuminant and observer. @@ -1028,10 +1035,11 @@ def rgb2lab(rgb, illuminant="D65", observer="2"): This implementation might have been modified. """ - return xyz2lab(rgb2xyz(rgb), illuminant, observer) + return xyz2lab(rgb2xyz(rgb), illuminant=illuminant, observer=observer) -def lab2rgb(lab, illuminant="D65", observer="2"): +@warn_on_args_to_kwargs() +def lab2rgb(lab, *, illuminant="D65", observer="2"): """Lab to RGB color space conversion. Parameters @@ -1057,4 +1065,4 @@ def lab2rgb(lab, illuminant="D65", observer="2"): This implementation might have been modified. """ - return xyz2rgb(lab2xyz(lab, illuminant, observer)) + return xyz2rgb(lab2xyz(lab, illuminant=illuminant, observer=observer)) diff --git a/fury/convert.py b/fury/convert.py index 25ad4d1a8..3945375d7 100644 --- a/fury/convert.py +++ b/fury/convert.py @@ -3,11 +3,13 @@ import numpy as np +from fury.decorators import warn_on_args_to_kwargs from fury.io import load_image +@warn_on_args_to_kwargs() def matplotlib_figure_to_numpy( - fig, dpi=100, fname=None, flip_up_down=True, transparent=False + fig, *, dpi=100, fname=None, flip_up_down=True, transparent=False ): """Convert a Matplotlib figure to a 3D numpy array with RGBA channels. @@ -54,7 +56,11 @@ def matplotlib_figure_to_numpy( arr = load_image(fname) else: fig.savefig( - fname, dpi=dpi, transparent=transparent, bbox_inches="tight", pad_inches=0 + fname, + dpi=dpi, + transparent=transparent, + bbox_inches="tight", + pad_inches=0, ) arr = load_image(fname) diff --git a/fury/data/__init__.py b/fury/data/__init__.py index bea342c0e..0eb5c77fc 100644 --- a/fury/data/__init__.py +++ b/fury/data/__init__.py @@ -1,42 +1,11 @@ """Read or fetch test or example data.""" + from os.path import dirname, join as pjoin -from fury.data.fetcher import ( - fetch_gltf, - fetch_viz_cubemaps, - fetch_viz_dmri, - fetch_viz_icons, - fetch_viz_models, - fetch_viz_new_icons, - fetch_viz_textures, - fetch_viz_wiki_nw, - list_gltf_sample_models, - read_viz_cubemap, - read_viz_dmri, - read_viz_gltf, - read_viz_icons, - read_viz_models, - read_viz_textures, -) +import lazy_loader as lazy DATA_DIR = pjoin(dirname(__file__), "files") +__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) -__all__ = [ - "DATA_DIR", - "fetch_viz_cubemaps", - "read_viz_cubemap", - "fetch_viz_icons", - "fetch_viz_new_icons", - "read_viz_icons", - "fetch_viz_textures", - "read_viz_textures", - "fetch_viz_wiki_nw", - "fetch_viz_models", - "read_viz_models", - "fetch_viz_dmri", - "read_viz_dmri", - "fetch_gltf", - "read_viz_gltf", - "list_gltf_sample_models", -] +__all__.append("DATA_DIR") diff --git a/fury/data/__init__.pyi b/fury/data/__init__.pyi new file mode 100644 index 000000000..d598294fb --- /dev/null +++ b/fury/data/__init__.pyi @@ -0,0 +1,64 @@ +# this file is used to define the public API of the `fury.data` module. +# the explicit definition of `__all__` will enable type inference for engines. + +__all__ = [ + "FetcherError", + "update_progressbar", + "copyfileobj_withprogress", + "_already_there_msg", + "_get_file_sha", + "check_sha", + "_get_file_data", + "fetch_data", + "_make_fetcher", + "_request", + "_download", + "_fetch_gltf", + "fetch_gltf", + "fetch_viz_cubemaps", + "fetch_viz_icons", + "fetch_viz_new_icons", + "fetch_viz_wiki_nw", + "fetch_viz_models", + "fetch_viz_dmri", + "fetch_viz_textures", + "read_viz_cubemap", + "read_viz_icons", + "read_viz_models", + "read_viz_textures", + "read_viz_dmri", + "read_viz_gltf", + "list_gltf_sample_models", +] + +from .fetcher import ( + FetcherError, + _already_there_msg, + _download, + _fetch_gltf, + _get_file_data, + _get_file_sha, + _make_fetcher, + _request, + check_sha, + copyfileobj_withprogress, + fetch_data, + fetch_gltf, + fetch_viz_cubemaps, + fetch_viz_dmri, + fetch_viz_icons, + fetch_viz_models, + fetch_viz_new_icons, + fetch_viz_textures, + fetch_viz_wiki_nw, + list_gltf_sample_models, + read_viz_cubemap, + read_viz_dmri, + read_viz_gltf, + read_viz_icons, + read_viz_models, + read_viz_textures, + update_progressbar, +) + +DATA_DIR: str diff --git a/fury/data/fetcher.py b/fury/data/fetcher.py index 71d804f10..42b5e8d9b 100644 --- a/fury/data/fetcher.py +++ b/fury/data/fetcher.py @@ -16,6 +16,8 @@ import aiohttp +from fury.decorators import warn_on_args_to_kwargs + # Set a user-writeable file-system location to put files: if "FURY_HOME" in os.environ: fury_home = os.environ["FURY_HOME"] @@ -78,7 +80,8 @@ def update_progressbar(progress, total_length): sys.stdout.flush() -def copyfileobj_withprogress(fsrc, fdst, total_length, length=16 * 1024): +@warn_on_args_to_kwargs() +def copyfileobj_withprogress(fsrc, fdst, total_length, *, length=16 * 1024): copied = 0 while True: buf = fsrc.read(length) @@ -118,7 +121,8 @@ def _get_file_sha(filename): return sha256_data.hexdigest() -def check_sha(filename, stored_sha256=None): +@warn_on_args_to_kwargs() +def check_sha(filename, *, stored_sha256=None): """Check the generated sha checksum. Parameters @@ -160,7 +164,8 @@ def _get_file_data(fname, url): copyfileobj_withprogress(opener, data, response_size) -def fetch_data(files, folder, data_size=None): +@warn_on_args_to_kwargs() +def fetch_data(files, folder, *, data_size=None): """Download files to folder and checks their sha checksums. Parameters @@ -200,19 +205,21 @@ def fetch_data(files, folder, data_size=None): all_skip = False print('Downloading "%s" to %s' % (f, folder)) _get_file_data(fullpath, url) - check_sha(fullpath, sha) + check_sha(fullpath, stored_sha256=sha) if all_skip: _already_there_msg(folder) else: print("Files successfully downloaded to %s" % (folder)) +@warn_on_args_to_kwargs() def _make_fetcher( name, folder, baseurl, remote_fnames, local_fnames, + *, sha_list=None, doc="", data_size=None, @@ -261,7 +268,7 @@ def fetcher(): files = {} for i, (f, n) in enumerate(zip(remote_fnames, local_fnames)): files[n] = (baseurl + f, sha_list[i] if sha_list is not None else None) - fetch_data(files, folder, data_size) + fetch_data(files, folder, data_size=data_size) if msg is not None: print(msg) @@ -312,7 +319,8 @@ async def _request(session, url): return await response.json() -async def _download(session, url, filename, size=None): +@warn_on_args_to_kwargs() +async def _download(session, url, filename, *, size=None): """Download file from url. Parameters @@ -394,13 +402,14 @@ async def _fetch_gltf(name, mode): async with aiohttp.ClientSession() as session: await asyncio.gather( - *[_download(session, url, name, s) for url, name, s in zip_url] + *[_download(session, url, name, size=s) for url, name, s in zip_url] ) return f_names, folder -def fetch_gltf(name=None, mode="glTF"): +@warn_on_args_to_kwargs() +def fetch_gltf(*, name=None, mode="glTF"): """Download glTF samples from Khronos Group Github. Parameters @@ -448,7 +457,7 @@ def fetch_gltf(name=None, mode="glTF"): "skybox-py.jpg", "skybox-pz.jpg", ], - [ + sha_list=[ "12B1CE6C91AA3AAF258A8A5944DF739A6C1CC76E89D4D7119D1F795A30FC1BF2", "E18FE2206B63D3DF2C879F5E0B9937A61D99734B6C43AC288226C58D2418D23E", "00DDDD1B715D5877AF2A74C014FF6E47891F07435B471D213CD0673A8C47F2B2", @@ -465,7 +474,7 @@ def fetch_gltf(name=None, mode="glTF"): UW_RW_URL + "1773/38478/", ["icomoon.tar.gz"], ["icomoon.tar.gz"], - ["BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735"], + sha_list=["BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735"], data_size="12KB", doc="Download icons for fury", unzip=True, @@ -511,7 +520,7 @@ def fetch_gltf(name=None, mode="glTF"): "selection-pressed.png", "selection.png", ], - [ + sha_list=[ "CD859F244DF1BA719C65C869C3FAF6B8563ABF82F457730ADBFBD7CA72DDB7BC", "5896BDC9FF9B3D1054134D7D9A854677CE9FA4E64F494F156BB2E3F0E863F207", "937C46C25BC38B62021B01C97A4EE3CDE5F7C8C4A6D0DB75BF4E4CACE2AF1226", @@ -539,7 +548,7 @@ def fetch_gltf(name=None, mode="glTF"): FURY_DATA_URL, ["wiki_categories.txt", "wiki_edges.txt", "wiki_positions.txt"], ["wiki_categories.txt", "wiki_edges.txt", "wiki_positions.txt"], - [ + sha_list=[ "1679241B13D2FD01209160F0C186E14AB55855478300B713D5369C12854CFF82", "702EE8713994243C8619A29C9ECE32F95305737F583B747C307500F3EC4A6B56", "044917A8FBD0EB980D93B6C406A577BEA416FA934E897C26C87E91C218EF4432", @@ -559,7 +568,7 @@ def fetch_gltf(name=None, mode="glTF"): MODEL_DATA_URL, ["utah.obj", "suzanne.obj", "satellite_obj.obj", "dragon.obj"], ["utah.obj", "suzanne.obj", "satellite_obj.obj", "dragon.obj"], - [ + sha_list= [ "0B50F12CEDCDC27377AC702B1EE331223BECEC59593B3F00A9E06B57A9C1B7C3", "BB4FF4E65D65D71D53000E06D2DC7BF89B702223657C1F64748811A3A6C8D621", "90213FAC81D89BBB59FA541643304E0D95C2D446157ACE044D46F259454C0E74", @@ -590,7 +599,7 @@ def fetch_gltf(name=None, mode="glTF"): "whole_brain_evecs.nii.gz", "whole_brain_evals.nii.gz", ], - [ + sha_list=[ "767ca3e4cd296e78421d83c32201b30be2d859c332210812140caac1b93d492b", "8843ECF3224CB8E3315B7251D1E303409A17D7137D3498A8833853C4603C6CC2", "3096B190B1146DD0EADDFECC0B4FBBD901F4933692ADD46A83F637F28B22122D", @@ -643,7 +652,7 @@ def fetch_gltf(name=None, mode="glTF"): "1_earth_16k.jpg", "clouds.jpg", ], - [ + sha_list=[ "0D66DC62768C43D763D3288CE67128AAED27715B11B0529162DC4117F710E26F", "5CF740C72287AF7B3ACCF080C3951944ADCB1617083B918537D08CBD9F2C5465", "DF443F3E20C7724803690A350D9F6FDB36AD8EBC011B0345FB519A8B321F680A", @@ -666,7 +675,8 @@ def fetch_gltf(name=None, mode="glTF"): ) -def read_viz_cubemap(name, suffix_type=1, ext=".jpg"): +@warn_on_args_to_kwargs() +def read_viz_cubemap(name, *, suffix_type=1, ext=".jpg"): """Read specific cube map with specific suffix type and extension. Parameters @@ -708,7 +718,8 @@ def read_viz_cubemap(name, suffix_type=1, ext=".jpg"): return cubemap_fnames -def read_viz_icons(style="icomoon", fname="infinity.png"): +@warn_on_args_to_kwargs() +def read_viz_icons(*, style="icomoon", fname="infinity.png"): """Read specific icon from specific style. Parameters @@ -791,7 +802,8 @@ def read_viz_dmri(fname): return pjoin(folder, fname) -def read_viz_gltf(fname, mode="glTF"): +@warn_on_args_to_kwargs() +def read_viz_gltf(fname, *, mode="glTF"): """Read specific gltf sample. Parameters diff --git a/fury/data/tests/test_fetcher.py b/fury/data/tests/test_fetcher.py index 08af70da6..6fd6eb15f 100644 --- a/fury/data/tests/test_fetcher.py +++ b/fury/data/tests/test_fetcher.py @@ -26,7 +26,7 @@ def tests_fetch_gltf(): os.remove(pjoin(boxtex, path)) os.rmdir(boxtex) - fetch_gltf(models_list) + fetch_gltf(name=models_list) list_gltf = os.listdir(folder) results = [model in list_gltf for model in models_list] @@ -43,7 +43,7 @@ def tests_fetch_gltf(): items = os.listdir(boxtex) npt.assert_array_equal(len(items), 3) - filenames, path = fetch_gltf("Box", "glTF-Binary") + filenames, path = fetch_gltf(name="Box", mode="glTF-Binary") npt.assert_equal(len(filenames), 1) npt.assert_equal(os.listdir(path), filenames) @@ -63,8 +63,8 @@ def test_list_gltf_sample_models(): def test_read_viz_gltf(): gltf_dir = pjoin(fury_home, "glTF") - filenames, path = fetch_gltf("Box", "glTF-Binary") - filename = read_viz_gltf("Box", "glTF-Binary") + filenames, path = fetch_gltf(name="Box", mode="glTF-Binary") + filename = read_viz_gltf("Box", mode="glTF-Binary") npt.assert_equal(filename, pjoin(path, filenames[0])) npt.assert_raises(ValueError, read_viz_gltf, "FURY", "glTF") @@ -77,7 +77,7 @@ def test_read_viz_gltf(): os.rmdir(mode) npt.assert_raises(ValueError, read_viz_gltf, "Box") - filenames, path = fetch_gltf("Box") + filenames, path = fetch_gltf(name="Box") out_path = read_viz_gltf("Box").split(os.sep) mode = out_path[-2:][0] npt.assert_equal(mode, "glTF") diff --git a/fury/decorators.py b/fury/decorators.py index 4cb1ee2cf..1d5323155 100644 --- a/fury/decorators.py +++ b/fury/decorators.py @@ -1,8 +1,15 @@ """Decorators for FURY tests.""" +from functools import wraps +from inspect import signature import platform import re import sys +from warnings import warn + +from packaging import version + +import fury skip_linux = is_linux = platform.system().lower() == "linux" skip_osx = is_osx = platform.system().lower() == "darwin" @@ -15,9 +22,11 @@ def doctest_skip_parser(func): """Decorator replaces custom skip test markup in doctests. Say a function has a docstring:: - >>> something # skip if not HAVE_AMODULE - >>> something + else - >>> something # skip if HAVE_BMODULE + + something # skip if not HAVE_AMODULE + something + else + something # skip if HAVE_BMODULE + This decorator will evaluate the expression after ``skip if``. If this evaluates to True, then the comment is replaced by ``# doctest: +SKIP``. If False, then the comment is just removed. The expression is evaluated in @@ -25,9 +34,10 @@ def doctest_skip_parser(func): For example, if the module global ``HAVE_AMODULE`` is False, and module global ``HAVE_BMODULE`` is False, the returned function will have docstring:: - >>> something # doctest: +SKIP - >>> something + else - >>> something + + something # doctest: +SKIP + something + else + something """ lines = func.__doc__.split("\n") @@ -43,3 +53,151 @@ def doctest_skip_parser(func): new_lines.append(code) func.__doc__ = "\n".join(new_lines) return func + + +def warn_on_args_to_kwargs( + from_version="0.11.0", + until_version="0.14.0", +): + """Decorator to enforce keyword-only arguments. + + This decorator enforces that all arguments after the first one are + keyword-only arguments. It also checks that all keyword arguments are + expected by the function. + + Parameters + ---------- + from_version: str, optional + The version of fury from which the function was supported. + until_version: str, optional + The version of fury until which the function was supported. + + Returns + ------- + decorator: Callable + Decorator function. + + Examples + -------- + >>> from fury.decorators import warn_on_args_to_kwargs + >>> import fury + >>> @warn_on_args_to_kwargs() + ... def f(a, b, *, c, d=1, e=1): + ... return a + b + c + d + e + >>> CURRENT_VERSION = fury.__version__ + >>> fury.__version__ = "0.11.0" + >>> f(1, 2, 3, 4, 5) + 15 + >>> f(1, 2, c=3, d=4, e=5) + 15 + >>> f(1, 2, 2, 4, e=5) + 14 + >>> f(1, 2, c=3, d=4) + 11 + >>> f(1, 2, d=3, e=5) + Traceback (most recent call last): + ... + TypeError: f() missing 1 required keyword-only argument: 'c' + """ # noqa: E501 + + def decorator(func): + """Decorator function. This function enforces that all arguments after + the first one are keyword-only arguments. It also checks that all + keyword arguments are expected by the function. + + Parameters + ---------- + func: function + Function to be decorated. + + Returns + ------- + wrapper: Callable + Decorated function. + """ + + @wraps(func) + def wrapper(*args, **kwargs): + sig = signature(func) + params = sig.parameters + # + KEYWORD_ONLY_ARGS = [ + arg.name for arg in params.values() if arg.kind == arg.KEYWORD_ONLY + ] + POSITIONAL_ARGS = [ + arg.name + for arg in params.values() + if arg.kind in (arg.POSITIONAL_OR_KEYWORD, arg.POSITIONAL_ONLY) + ] + + # Keyword-only arguments that do not have default values and not in kwargs + missing_kwargs = [ + arg + for arg in KEYWORD_ONLY_ARGS + if arg not in kwargs and params[arg].default == params[arg].empty + ] + + # Keyword-only arguments that have default values + ARG_DEFAULT = [ + arg + for arg in KEYWORD_ONLY_ARGS + if arg not in kwargs and params[arg].default != params[arg].empty + ] + func_params_sample = [] + + # Create a sample of the function parameters + for arg in params.values(): + if arg.kind in (arg.POSITIONAL_OR_KEYWORD, arg.POSITIONAL_ONLY): + func_params_sample.append(f"{arg.name}_value") + elif arg.kind == arg.KEYWORD_ONLY: + func_params_sample.append(f"{arg.name}='value'") + func_params_sample = ", ".join(func_params_sample) + args_kwargs_len = len(args) + len(kwargs) + params_len = len(params) + try: + return func(*args, **kwargs) + except TypeError as e: + FURY_CURRENT_VERSION = fury.__version__ + + if ARG_DEFAULT: + missing_kwargs += ARG_DEFAULT + if missing_kwargs and params_len >= args_kwargs_len: + # if the version of fury is greater than until_version, + # an error should be displayed, + if version.parse(FURY_CURRENT_VERSION) > version.parse( + until_version + ): + raise TypeError(e) from e + + positional_args_len = len(POSITIONAL_ARGS) + args_k = list(args[positional_args_len:]) + args = list(args[:positional_args_len]) + kwargs.update(dict(zip(missing_kwargs, args_k))) + result = func(*args, **kwargs) + + # if from_version is less or equal to fury.__version__ and, + # less or equal to until_version + # a warning should be displayed. + if ( + version.parse(from_version) + <= version.parse(FURY_CURRENT_VERSION) + <= version.parse(until_version) + ): + warn( + f"We'll no longer accept the way you call the " + f"{func.__name__} function in future versions of FURY.\n\n" + "Here's how to call the Function {}: {}({})\n".format( + func.__name__, func.__name__, func_params_sample + ), + UserWarning, + stacklevel=3, + ) + + # if the current version of fury is less than from_version, + # the function should be called without any changes. + + return result + + return wrapper + + return decorator diff --git a/fury/deprecator.py b/fury/deprecator.py index d928836b9..66eea584f 100644 --- a/fury/deprecator.py +++ b/fury/deprecator.py @@ -13,13 +13,9 @@ import re import warnings -from fury import __version__ -from fury.optpkg import optional_package +from packaging import version -# packaging.version.parse is a third-party utility but is used by setuptools -# (so probably already installed) and is conformant to the current PEP 440. -# But just if it is not the case, we use distutils -packaging, have_pkg, _ = optional_package("setuptools.extern.packaging") +from fury import __version__ _LEADING_WHITE = re.compile(r"^(\s*)") @@ -116,7 +112,7 @@ def cmp_pkg_version(version_str, pkg_version_str=__version__): -1 """ - version_cmp = packaging.version.parse if have_pkg else None + version_cmp = version.parse if any(re.match(r"^[a-z, A-Z]", v) for v in [version_str, pkg_version_str]): msg = "Invalid version {0} or {1}".format(version_str, pkg_version_str) diff --git a/fury/gltf.py b/fury/gltf.py index 5b02ff68d..58c1df6c4 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -17,6 +17,7 @@ step_interpolator, tan_cubic_spline_interpolator, ) +from fury.decorators import warn_on_args_to_kwargs from fury.lib import Camera, Matrix4x4, Texture, Transform, numpy_support comp_type = { @@ -32,7 +33,8 @@ class glTF: - def __init__(self, filename, apply_normals=False): + @warn_on_args_to_kwargs() + def __init__(self, filename, *, apply_normals=False): """Read and generate actors from glTF files. Parameters @@ -87,7 +89,7 @@ def __init__(self, filename, apply_normals=False): self.morph_vertices = [] self.morph_weights = [] - self.inspect_scene(0) + self.inspect_scene(scene_id=0) self._actors = [] self._bactors = {} @@ -121,7 +123,8 @@ def actors(self): return self._actors - def inspect_scene(self, scene_id=0): + @warn_on_args_to_kwargs() + def inspect_scene(self, *, scene_id=0): """Loop over nodes in a scene. Parameters @@ -138,7 +141,8 @@ def inspect_scene(self, scene_id=0): for i, animation in enumerate(self.gltf.animations): self.transverse_channels(animation, i) - def transverse_node(self, nextnode_id, matrix, parent=None, is_joint=False): + @warn_on_args_to_kwargs() + def transverse_node(self, nextnode_id, matrix, *, parent=None, is_joint=False): """Load mesh and generates transformation matrix. Parameters @@ -204,7 +208,9 @@ def transverse_node(self, nextnode_id, matrix, parent=None, is_joint=False): for bone, ibm in zip(joints, ibms): self.bones.append(bone) self.ibms[bone] = ibm - self.transverse_node(joints[0], np.identity(4), parent, is_joint=True) + self.transverse_node( + joints[0], np.identity(4), parent=parent, is_joint=True + ) if node.camera is not None: camera_id = node.camera @@ -212,7 +218,12 @@ def transverse_node(self, nextnode_id, matrix, parent=None, is_joint=False): if node.children: for child_id in node.children: - self.transverse_node(child_id, next_matrix, parent, is_joint) + self.transverse_node( + child_id, + next_matrix, + parent=parent, + is_joint=is_joint, + ) def load_mesh(self, mesh_id, transform_mat, parent): """Load the mesh data from accessor and applies the transformation. @@ -645,12 +656,14 @@ def generate_tmatrix(self, transf, prop): matrix = transf return matrix + @warn_on_args_to_kwargs() def transverse_animations( self, animation, bone_id, timestamp, joint_matrices, + *, parent_bone_deform=None, ): """Calculate skinning matrix (Joint Matrices) and transform bone for @@ -696,7 +709,11 @@ def transverse_animations( c_bones = node.children for c_anim, c_bone in zip(c_animations, c_bones): self.transverse_animations( - c_anim, c_bone, timestamp, joint_matrices, new_deform + c_anim, + c_bone, + timestamp, + joint_matrices, + parent_bone_deform=new_deform, ) def update_skin(self, animation): @@ -722,16 +739,25 @@ def update_skin(self, animation): parent_transform = np.identity(4) for child in _animation.child_animations: self.transverse_animations( - child, self.bones[0], timestamp, joint_matrices, parent_transform + child, + self.bones[0], + timestamp, + joint_matrices, + parent_bone_deform=parent_transform, ) for i, vertex in enumerate(self._vertices): - vertex[:] = self.apply_skin_matrix(self._vcopy[i], joint_matrices, i) + vertex[:] = self.apply_skin_matrix( + self._vcopy[i], + joint_matrices, + actor_index=i, + ) actor_transf = self.transformations[i] vertex[:] = transform.apply_transformation(vertex, actor_transf) utils.update_actor(self._actors[i]) utils.compute_bounds(self._actors[i]) - def initialize_skin(self, animation, bones=False, length=0.2): + @warn_on_args_to_kwargs() + def initialize_skin(self, animation, *, bones=False, length=0.2): """Create bones and add to the animation and initialise `update_skin` Parameters @@ -748,11 +774,12 @@ def initialize_skin(self, animation, bones=False, length=0.2): """ self.show_bones = bones if bones: - self.get_joint_actors(length, False) + self.get_joint_actors(length=length, with_transforms=False) animation.add_actor(list(self._bactors.values())) self.update_skin(animation) - def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): + @warn_on_args_to_kwargs() + def apply_skin_matrix(self, vertices, joint_matrices, *, actor_index=0): """Apply the skinnig matrix, that transform the vertices. Parameters @@ -845,7 +872,8 @@ def skin_animation(self): root_animation.add_actor(self._actors) return root_animations - def get_joint_actors(self, length=0.5, with_transforms=False): + @warn_on_args_to_kwargs() + def get_joint_actors(self, *, length=0.5, with_transforms=False): """Create an arrow actor for each bone in a skinned model. Parameters @@ -1039,7 +1067,8 @@ def main_animation(self): return main_animation -def export_scene(scene, filename="default.gltf"): +@warn_on_args_to_kwargs() +def export_scene(scene, *, filename="default.gltf"): """Generate gltf from FURY scene. Parameters @@ -1175,8 +1204,8 @@ def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): gltflib.FLOAT, len(vertices) // atype, gltflib.VEC3, - amax, - amin, + max=amax, + min=amin, ) byteoffset += blength vertex = count @@ -1200,8 +1229,8 @@ def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): gltflib.FLOAT, len(normals) // atype, gltflib.VEC3, - amax, - amin, + max=amax, + min=amin, ) byteoffset += blength normal = count @@ -1251,7 +1280,7 @@ def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): color = count count += 1 material = None if tcoords is None else 0 - prim = get_prim(vertex, index, color, tcoord, normal, material, mode) + prim = get_prim(vertex, index, color, tcoord, normal, material, mode=mode) return prim, byteoffset, count @@ -1271,7 +1300,8 @@ def write_scene(gltf, nodes): gltf.scenes.append(scene) -def write_node(gltf, mesh_id=None, camera_id=None): +@warn_on_args_to_kwargs() +def write_node(gltf, *, mesh_id=None, camera_id=None): """Create node Parameters @@ -1339,7 +1369,8 @@ def write_camera(gltf, camera): gltf.cameras.append(cam) -def get_prim(vertex, index, color, tcoord, normal, material, mode=4): +@warn_on_args_to_kwargs() +def get_prim(vertex, index, color, tcoord, normal, material, *, mode=4): """Return a Primitive object. Parameters @@ -1409,8 +1440,9 @@ def write_material(gltf, basecolortexture: int, uri: str): gltf.images.append(image) +@warn_on_args_to_kwargs() def write_accessor( - gltf, bufferview, byte_offset, comp_type, count, accssor_type, max=None, min=None + gltf, bufferview, byte_offset, comp_type, count, accssor_type, *, max=None, min=None ): """Write accessor in the gltf. @@ -1418,8 +1450,7 @@ def write_accessor( ---------- gltf: GLTF2 Pygltflib GLTF2 objecomp_type - - bufferview: int + bufferview: int BufferView Index byte_offset: int ByteOffset of the accessor @@ -1435,6 +1466,7 @@ def write_accessor( Minimum elements of an array """ + accessor = gltflib.Accessor() accessor.bufferView = bufferview accessor.byteOffset = byte_offset @@ -1447,7 +1479,8 @@ def write_accessor( gltf.accessors.append(accessor) -def write_bufferview(gltf, buffer, byte_offset, byte_length, byte_stride=None): +@warn_on_args_to_kwargs() +def write_bufferview(gltf, buffer, byte_offset, byte_length, *, byte_stride=None): """Write bufferview in the gltf. Parameters diff --git a/fury/interactor.py b/fury/interactor.py index 399f44992..febe0d610 100644 --- a/fury/interactor.py +++ b/fury/interactor.py @@ -4,6 +4,7 @@ import numpy as np +from fury.decorators import warn_on_args_to_kwargs from fury.lib import ( Command, InteractorStyle, @@ -173,7 +174,8 @@ def _process_event(self, obj, evt): self.event.reset() # Event fully processed. - def _button_clicked(self, button, last_event=-1, before_last_event=-2): + @warn_on_args_to_kwargs() + def _button_clicked(self, button, *, last_event=-1, before_last_event=-2): if len(self.history) < abs(before_last_event): return False @@ -186,7 +188,10 @@ def _button_clicked(self, button, last_event=-1, before_last_event=-2): return True def _button_double_clicked(self, button): - if not (self._button_clicked(button) and self._button_clicked(button, -3, -4)): + if not ( + self._button_clicked(button) + and self._button_clicked(button, last_event=-3, before_last_event=-4) + ): return False return True @@ -383,7 +388,8 @@ def force_render(self): """Causes the scene to refresh.""" self.GetInteractor().GetRenderWindow().Render() - def add_callback(self, prop, event_type, callback, priority=0, args=None): + @warn_on_args_to_kwargs() + def add_callback(self, prop, event_type, callback, *, priority=0, args=None): """Add a callback associated to a specific event for a VTK prop. Parameters diff --git a/fury/io.py b/fury/io.py index 828002c2d..8f2900014 100644 --- a/fury/io.py +++ b/fury/io.py @@ -6,6 +6,7 @@ from PIL import Image import numpy as np +from fury.decorators import warn_on_args_to_kwargs from fury.lib import ( BMPReader, BMPWriter, @@ -34,7 +35,8 @@ from fury.utils import set_input -def load_cubemap_texture(fnames, interpolate_on=True, mipmap_on=True): +@warn_on_args_to_kwargs() +def load_cubemap_texture(fnames, *, interpolate_on=True, mipmap_on=True): """Load a cube map texture from a list of 6 images. Parameters @@ -74,7 +76,8 @@ def load_cubemap_texture(fnames, interpolate_on=True, mipmap_on=True): return texture -def load_image(filename, as_vtktype=False, use_pillow=True): +@warn_on_args_to_kwargs() +def load_image(filename, *, as_vtktype=False, use_pillow=True): """Load an image. Parameters @@ -92,8 +95,8 @@ def load_image(filename, as_vtktype=False, use_pillow=True): desired image array """ - is_url = filename.lower().startswith("http://") or filename.lower().startswith( - "https://" + is_url = (filename.lower().startswith("http://")) or ( + filename.lower().startswith("https://") ) if is_url: @@ -135,7 +138,14 @@ def load_image(filename, as_vtktype=False, use_pillow=True): # width, height vtk_image.SetDimensions(image.shape[1], image.shape[0], depth) - vtk_image.SetExtent(0, image.shape[1] - 1, 0, image.shape[0] - 1, 0, 0) + vtk_image.SetExtent( + 0, + image.shape[1] - 1, + 0, + image.shape[0] - 1, + 0, + 0, + ) vtk_image.SetSpacing(1.0, 1.0, 1.0) vtk_image.SetOrigin(0.0, 0.0, 0.0) @@ -210,9 +220,11 @@ def load_text(file): return text +@warn_on_args_to_kwargs() def save_image( arr, filename, + *, compression_quality=75, compression_type="deflation", use_pillow=True, @@ -307,7 +319,13 @@ def save_image( writer.SetQuality(compression_quality) if extension.lower() in [".tif", ".tiff"]: compression_type = compression_type or "nocompression" - l_compression = ["nocompression", "packbits", "jpeg", "deflate", "lzw"] + l_compression = [ + "nocompression", + "packbits", + "jpeg", + "deflate", + "lzw", + ] if compression_type.lower() in l_compression: comp_id = l_compression.index(compression_type.lower()) @@ -363,7 +381,8 @@ def load_polydata(file_name): return reader.GetOutput() -def save_polydata(polydata, file_name, binary=False, color_array_name=None): +@warn_on_args_to_kwargs() +def save_polydata(polydata, file_name, *, binary=False, color_array_name=None): """Save a vtk polydata to a supported format file. Save formats can be VTK, FIB, PLY, STL and XML. @@ -413,7 +432,8 @@ def save_polydata(polydata, file_name, binary=False, color_array_name=None): writer.Write() -def load_sprite_sheet(sheet_path, nb_rows, nb_cols, as_vtktype=False): +@warn_on_args_to_kwargs() +def load_sprite_sheet(sheet_path, nb_rows, nb_cols, *, as_vtktype=False): """Process and load sprites from a sprite sheet. Parameters @@ -450,13 +470,18 @@ def load_sprite_sheet(sheet_path, nb_rows, nb_cols, as_vtktype=False): nxt_col * sprite_size_y, ) - sprite_arr = sprite_sheet[box[0] : box[2], box[1] : box[3]] + sprite_arr = sprite_sheet[ + box[0] : box[2], box[1] : box[3] # noqa: E203 + ] if as_vtktype: with InTemporaryDirectory() as tdir: tmp_img_path = os.path.join(tdir, f"{row}{col}.png") save_image(sprite_arr, tmp_img_path, compression_quality=100) - sprite_dicts[(row, col)] = load_image(tmp_img_path, as_vtktype=True) + sprite_dicts[(row, col)] = load_image( + tmp_img_path, + as_vtktype=True, + ) else: sprite_dicts[(row, col)] = sprite_arr diff --git a/fury/layout.py b/fury/layout.py index 7647949b5..f227b99cd 100644 --- a/fury/layout.py +++ b/fury/layout.py @@ -2,6 +2,7 @@ import numpy as np +from fury.decorators import warn_on_args_to_kwargs from fury.utils import get_bounding_box_sizes, get_grid_cells_position, is_ui @@ -32,8 +33,10 @@ class GridLayout(Layout): """ + @warn_on_args_to_kwargs() def __init__( self, + *, cell_padding=0, cell_shape="rect", aspect_ratio=16 / 9.0, @@ -88,11 +91,25 @@ def get_cells_shape(self, actors): """ if self.cell_shape == "rect": - bounding_box_sizes = np.asarray(list(map(self.compute_sizes, actors))) + bounding_box_sizes = np.asarray( + list( + map( + self.compute_sizes, + actors, + ) + ) + ) cell_shape = np.max(bounding_box_sizes, axis=0)[:2] shapes = [cell_shape] * len(actors) elif self.cell_shape == "square": - bounding_box_sizes = np.asarray(list(map(self.compute_sizes, actors))) + bounding_box_sizes = np.asarray( + list( + map( + self.compute_sizes, + actors, + ) + ) + ) cell_shape = np.max(bounding_box_sizes, axis=0)[:2] shapes = [(max(cell_shape),) * 2] * len(actors) elif self.cell_shape == "diagonal": @@ -110,7 +127,11 @@ def get_cells_shape(self, actors): longest_diagonal = np.max(diagonals) shapes = [(longest_diagonal, longest_diagonal)] * len(actors) else: - raise ValueError("Unknown cell shape: '{0}'".format(self.cell_shape)) + raise ValueError( + "Unknown cell shape: '{0}'".format( + self.cell_shape, + ) + ) return shapes @@ -133,7 +154,11 @@ def compute_positions(self, actors): # Add padding, if any, around every cell. shapes = [np.array(self.cell_padding) / 2.0 + s for s in shapes] - positions = get_grid_cells_position(shapes, self.aspect_ratio, self.dim) + positions = get_grid_cells_position( + shapes, + aspect_ratio=self.aspect_ratio, + dim=self.dim, + ) positions += self.position_offset return positions @@ -161,7 +186,8 @@ def compute_sizes(self, actor): class HorizontalLayout(GridLayout): """Provide functionalities for laying out actors in a horizontal layout.""" - def __init__(self, cell_padding=0, cell_shape="rect"): + @warn_on_args_to_kwargs() + def __init__(self, *, cell_padding=0, cell_shape="rect"): """Initialize the Horizontal layout. Parameters @@ -216,7 +242,8 @@ def compute_positions(self, actors): class VerticalLayout(GridLayout): """Provide functionalities for laying out actors in a vertical stack.""" - def __init__(self, cell_padding=0, cell_shape="rect"): + @warn_on_args_to_kwargs() + def __init__(self, *, cell_padding=0, cell_shape="rect"): """Initialize the Vertical layout. Parameters @@ -270,7 +297,8 @@ def compute_positions(self, actors): class XLayout(HorizontalLayout): """Provide functionalities for laying out actors along x-axis.""" - def __init__(self, direction="x+", cell_padding=0, cell_shape="rect"): + @warn_on_args_to_kwargs() + def __init__(self, *, direction="x+", cell_padding=0, cell_shape="rect"): """Initialize the X layout. Parameters @@ -297,7 +325,10 @@ def __init__(self, direction="x+", cell_padding=0, cell_shape="rect"): if self.direction not in ["x+", "x-"]: raise ValueError(f"{direction} is not a valid direction") - super(XLayout, self).__init__(cell_padding=cell_padding, cell_shape=cell_shape) + super(XLayout, self).__init__( + cell_padding=cell_padding, + cell_shape=cell_shape, + ) def get_cells_shape(self, actors): """Get the 2D shape (on the xy-plane) of some actors according to @@ -352,7 +383,8 @@ def apply(self, actors): class YLayout(VerticalLayout): """Provide functionalities for laying out actors along y-axis.""" - def __init__(self, direction="y+", cell_padding=0, cell_shape="rect"): + @warn_on_args_to_kwargs() + def __init__(self, *, direction="y+", cell_padding=0, cell_shape="rect"): """Initialize the Y layout. Parameters @@ -379,7 +411,10 @@ def __init__(self, direction="y+", cell_padding=0, cell_shape="rect"): if self.direction not in ["y+", "y-"]: raise ValueError(f"{direction} is not a valid direction") - super(YLayout, self).__init__(cell_padding=cell_padding, cell_shape=cell_shape) + super(YLayout, self).__init__( + cell_padding=cell_padding, + cell_shape=cell_shape, + ) def get_cells_shape(self, actors): """Get the 2D shape (on the xy-plane) of some actors according to @@ -434,7 +469,8 @@ def apply(self, actors): class ZLayout(GridLayout): """Provide functionalities for laying out actors along z-axis.""" - def __init__(self, direction="z+", cell_padding=0, cell_shape="rect"): + @warn_on_args_to_kwargs() + def __init__(self, *, direction="z+", cell_padding=0, cell_shape="rect"): """Initialize the Z layout. Parameters @@ -461,7 +497,10 @@ def __init__(self, direction="z+", cell_padding=0, cell_shape="rect"): if self.direction not in ["z+", "z-"]: raise ValueError(f"{direction} is not a valid direction") - super(ZLayout, self).__init__(cell_padding=cell_padding, cell_shape=cell_shape) + super(ZLayout, self).__init__( + cell_padding=cell_padding, + cell_shape=cell_shape, + ) def get_cells_shape(self, actors): """Get the shape (on the z-plane) of some actors according to @@ -482,7 +521,14 @@ def get_cells_shape(self, actors): actors = actors[::-1] if self.cell_shape == "rect" or self.cell_shape == "square": - bounding_box_sizes = np.asarray(list(map(get_bounding_box_sizes, actors))) + bounding_box_sizes = np.asarray( + list( + map( + get_bounding_box_sizes, + actors, + ) + ) + ) cell_shape = np.max(bounding_box_sizes, axis=0)[2] shapes = [cell_shape] * len(actors) elif self.cell_shape == "diagonal": @@ -491,7 +537,11 @@ def get_cells_shape(self, actors): longest_diagonal = np.max([a.GetLength() for a in actors]) shapes = [longest_diagonal] * len(actors) else: - raise ValueError("Unknown cell shape: '{0}'".format(self.cell_shape)) + raise ValueError( + "Unknown cell shape: '{0}'".format( + self.cell_shape, + ) + ) return shapes diff --git a/fury/lib.py b/fury/lib.py index dc0bf6a47..fc43eb4ed 100644 --- a/fury/lib.py +++ b/fury/lib.py @@ -245,8 +245,7 @@ UnstructuredGrid = cdmvtk.vtkUnstructuredGrid #: class for Polygon Polygon = cdmvtk.vtkPolygon -#: class for DataObject -DataObject = cdmvtk.vtkDataObject + #: class for Molecule Molecule = cdmvtk.vtkMolecule #: class for DataSetAttributes diff --git a/fury/material.py b/fury/material.py index 22891395a..98b97eae4 100644 --- a/fury/material.py +++ b/fury/material.py @@ -1,6 +1,7 @@ import os import warnings +from fury.decorators import warn_on_args_to_kwargs from fury.lib import VTK_OBJECT, calldata_type from fury.shaders import ( add_shader_callback, @@ -134,8 +135,10 @@ def coat_ior(self, coat_ior): self.__actor_properties.SetCoatIOR(coat_ior) +@warn_on_args_to_kwargs() def manifest_pbr( actor, + *, metallic=0, roughness=0.5, anisotropy=0, @@ -208,8 +211,10 @@ def manifest_pbr( return None +@warn_on_args_to_kwargs() def manifest_principled( actor, + *, subsurface=0, metallic=0, specular=0, @@ -284,20 +289,40 @@ def manifest_principled( @calldata_type(VTK_OBJECT) def uniforms_callback(_caller, _event, calldata=None): if calldata is not None: - calldata.SetUniformf("subsurface", principled_params["subsurface"]) + calldata.SetUniformf( + "subsurface", + principled_params["subsurface"], + ) calldata.SetUniformf("metallic", principled_params["metallic"]) - calldata.SetUniformf("specularTint", principled_params["specular_tint"]) - calldata.SetUniformf("roughness", principled_params["roughness"]) - calldata.SetUniformf("anisotropic", principled_params["anisotropic"]) + calldata.SetUniformf( + "specularTint", + principled_params["specular_tint"], + ) + calldata.SetUniformf( + "roughness", + principled_params["roughness"], + ) + calldata.SetUniformf( + "anisotropic", + principled_params["anisotropic"], + ) calldata.SetUniformf("sheen", principled_params["sheen"]) - calldata.SetUniformf("sheenTint", principled_params["sheen_tint"]) - calldata.SetUniformf("clearcoat", principled_params["clearcoat"]) calldata.SetUniformf( - "clearcoatGloss", principled_params["clearcoat_gloss"] + "sheenTint", + principled_params["sheen_tint"], + ) + calldata.SetUniformf( + "clearcoat", + principled_params["clearcoat"], + ) + calldata.SetUniformf( + "clearcoatGloss", + principled_params["clearcoat_gloss"], ) calldata.SetUniform3f( - "anisotropicDirection", principled_params["anisotropic_direction"] + "anisotropicDirection", + principled_params["anisotropic_direction"], ) add_shader_callback(actor, uniforms_callback) @@ -374,7 +399,13 @@ def uniforms_callback(_caller, _event, calldata=None): # Importing Geometry Shadowing and Masking Function (GF): Smith Ground # Glass Unknown (G_{GGX}) needed for the Isotropic Specular and Clear # Coat lobes - smith_ggx = import_fury_shader(os.path.join("lighting", "gf", "smith_ggx.frag")) + smith_ggx = import_fury_shader( + os.path.join( + "lighting", + "gf", + "smith_ggx.frag", + ) + ) # Importing Geometry Shadowing and Masking Function (GF): Anisotropic # form of the Smith Ground Glass Unknown (G_{GGXanisotropic}) needed @@ -390,7 +421,13 @@ def uniforms_callback(_caller, _event, calldata=None): subsurface = import_fury_shader( os.path.join("lighting", "principled", "subsurface.frag") ) - sheen = import_fury_shader(os.path.join("lighting", "principled", "sheen.frag")) + sheen = import_fury_shader( + os.path.join( + "lighting", + "principled", + "sheen.frag", + ) + ) specular_isotropic = import_fury_shader( os.path.join("lighting", "principled", "specular_isotropic.frag") ) @@ -574,8 +611,10 @@ def uniforms_callback(_caller, _event, calldata=None): return None +@warn_on_args_to_kwargs() def manifest_standard( actor, + *, ambient_level=0, ambient_color=(1, 1, 1), diffuse_level=1, diff --git a/fury/molecular.py b/fury/molecular.py index 394591297..ea0e13b52 100644 --- a/fury/molecular.py +++ b/fury/molecular.py @@ -5,6 +5,7 @@ import numpy as np from fury.actor import streamtube +from fury.decorators import warn_on_args_to_kwargs from fury.lib import ( VTK_FLOAT, VTK_ID_TYPE, @@ -34,8 +35,10 @@ class Molecule(Mol): This is a more pythonic version of ``Molecule``. """ + @warn_on_args_to_kwargs() def __init__( self, + *, atomic_numbers=None, coords=None, atom_names=None, @@ -107,7 +110,10 @@ def __init__( self.helix = helix self.is_hetatm = is_hetatm coords = numpy_to_vtk_points(coords) - atom_nums = nps.numpy_to_vtk(atomic_numbers, array_type=VTK_UNSIGNED_SHORT) + atom_nums = nps.numpy_to_vtk( + atomic_numbers, + array_type=VTK_UNSIGNED_SHORT, + ) atom_nums.SetName("Atomic Numbers") fieldData = DataSetAttributes() fieldData.AddArray(atom_nums) @@ -151,7 +157,8 @@ def add_atom(molecule, atomic_num, x_coord, y_coord, z_coord): molecule.AppendAtom(atomic_num, x_coord, y_coord, z_coord) -def add_bond(molecule, atom1_index, atom2_index, bond_order=1): +@warn_on_args_to_kwargs() +def add_bond(molecule, atom1_index, atom2_index, *, bond_order=1): """Add bonding data to our molecule. Establish a bond of type bond_order between the atom at atom1_index and the atom at atom2_index. @@ -413,7 +420,8 @@ def atomic_number(self, element_name): """ return self.GetAtomicNumber(element_name) - def atomic_radius(self, atomic_number, radius_type="VDW"): + @warn_on_args_to_kwargs() + def atomic_radius(self, atomic_number, *, radius_type="VDW"): """Given an atomic number, return either the covalent radius of the atom (in Å) or return the Van Der Waals radius (in Å) of the atom depending on radius_type. @@ -457,7 +465,8 @@ def atom_color(self, atomic_number): return rgb -def sphere_cpk(molecule, colormode="discrete"): +@warn_on_args_to_kwargs() +def sphere_cpk(molecule, *, colormode="discrete"): """Create an actor for sphere molecular representation. It's also referred to as CPK model and space-filling model. @@ -502,7 +511,10 @@ def sphere_cpk(molecule, colormode="discrete"): msp_mapper.SetAtomColorMode(0) else: msp_mapper.SetAtomColorMode(1) - warnings.warn("Incorrect colormode specified! Using discrete.", stacklevel=2) + warnings.warn( + "Incorrect colormode specified! Using discrete.", + stacklevel=2, + ) # To-Do manipulate shading properties to make it look aesthetic molecule_actor = Actor() @@ -510,8 +522,10 @@ def sphere_cpk(molecule, colormode="discrete"): return molecule_actor +@warn_on_args_to_kwargs() def ball_stick( molecule, + *, colormode="discrete", atom_scale_factor=0.3, bond_thickness=0.1, @@ -586,13 +600,17 @@ def ball_stick( bs_mapper.SetBondColorMode(0) else: bs_mapper.SetAtomColorMode(1) - warnings.warn("Incorrect colormode specified! Using discrete.", stacklevel=2) + warnings.warn( + "Incorrect colormode specified! Using discrete.", + stacklevel=2, + ) molecule_actor = Actor() molecule_actor.SetMapper(bs_mapper) return molecule_actor -def stick(molecule, colormode="discrete", bond_thickness=0.1): +@warn_on_args_to_kwargs() +def stick(molecule, *, colormode="discrete", bond_thickness=0.1): """Create an actor for stick molecular representation. Parameters @@ -623,7 +641,10 @@ def stick(molecule, colormode="discrete", bond_thickness=0.1): """ if molecule.total_num_bonds == 0: raise ValueError( - "No bonding data available for the molecule! Stick " "model cannot be made!" + ( + "No bonding data available for the molecule! Stick " + "model cannot be made!" + ) ) colormode = colormode.lower() mst_mapper = OpenGLMoleculeMapper() @@ -641,7 +662,10 @@ def stick(molecule, colormode="discrete", bond_thickness=0.1): mst_mapper.SetBondColorMode(0) else: mst_mapper.SetAtomColorMode(1) - warnings.warn("Incorrect colormode specified! Using discrete.", stacklevel=2) + warnings.warn( + "Incorrect colormode specified! Using discrete.", + stacklevel=2, + ) molecule_actor = Actor() molecule_actor.SetMapper(mst_mapper) return molecule_actor @@ -677,13 +701,21 @@ def ribbon(molecule): resi = molecule.residue_seq[i] for j, _ in enumerate(molecule.sheet): sheet = molecule.sheet[j] - if molecule.chain[i] != sheet[0] or resi < sheet[1] or resi > sheet[3]: + if ( + (molecule.chain[i] != sheet[0]) + or (resi < sheet[1]) + or (resi > sheet[3]) + ): continue secondary_structures[i] = ord("s") for j, _ in enumerate(molecule.helix): helix = molecule.helix[j] - if molecule.chain[i] != helix[0] or resi < helix[1] or resi > helix[3]: + if ( + (molecule.chain[i] != helix[0]) + or (resi < helix[1]) + or (resi > helix[3]) + ): continue secondary_structures[i] = ord("h") @@ -735,13 +767,21 @@ def ribbon(molecule): # for secondary structures begin newarr = np.ones(num_total_atoms) - s_sb = nps.numpy_to_vtk(num_array=newarr, deep=True, array_type=VTK_UNSIGNED_CHAR) + s_sb = nps.numpy_to_vtk( + num_array=newarr, + deep=True, + array_type=VTK_UNSIGNED_CHAR, + ) s_sb.SetName("secondary_structures_begin") output.GetPointData().AddArray(s_sb) # for secondary structures end newarr = np.ones(num_total_atoms) - s_se = nps.numpy_to_vtk(num_array=newarr, deep=True, array_type=VTK_UNSIGNED_CHAR) + s_se = nps.numpy_to_vtk( + num_array=newarr, + deep=True, + array_type=VTK_UNSIGNED_CHAR, + ) s_se.SetName("secondary_structures_end") output.GetPointData().AddArray(s_se) @@ -766,10 +806,17 @@ def ribbon(molecule): rgb = np.ones((num_total_atoms, 3)) for i in range(num_total_atoms): - radii[i] = np.repeat(table.atomic_radius(all_atomic_numbers[i], "VDW"), 3) + radii[i] = np.repeat( + table.atomic_radius(all_atomic_numbers[i], radius_type="VDW"), + 3, + ) rgb[i] = table.atom_color(all_atomic_numbers[i]) - Rgb = nps.numpy_to_vtk(num_array=rgb, deep=True, array_type=VTK_UNSIGNED_CHAR) + Rgb = nps.numpy_to_vtk( + num_array=rgb, + deep=True, + array_type=VTK_UNSIGNED_CHAR, + ) Rgb.SetName("rgb_colors") output.GetPointData().SetScalars(Rgb) @@ -792,7 +839,8 @@ def ribbon(molecule): return molecule_actor -def bounding_box(molecule, colors=(1, 1, 1), linewidth=0.3): +@warn_on_args_to_kwargs() +def bounding_box(molecule, *, colors=(1, 1, 1), linewidth=0.3): """Create a bounding box for a molecule. Parameters diff --git a/fury/optpkg.py b/fury/optpkg.py index 053b62c6b..6b3b860dd 100644 --- a/fury/optpkg.py +++ b/fury/optpkg.py @@ -2,6 +2,8 @@ import importlib +from fury.decorators import warn_on_args_to_kwargs + try: import pytest except ImportError: @@ -46,7 +48,7 @@ class TripWire: ... except ImportError: ... silly_module_name = TripWire('We do not have silly_module_name') >>> msg = 'with silly string' - >>> silly_module_name.do_silly_thing(msg) #doctest: +IGNORE_EXCEPTION_DETAIL + >>> silly_module_name.do_silly_thing(msg) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... TripWireError: We do not have silly_module_name @@ -65,7 +67,8 @@ def __call__(self, *args, **kwargs): raise TripWireError(self._msg) -def optional_package(name, trip_msg=None): +@warn_on_args_to_kwargs() +def optional_package(name, *, trip_msg=None): """Return package-like thing and module setup for package `name`. Parameters @@ -94,20 +97,19 @@ def optional_package(name, trip_msg=None): optional package: >>> from fury.optpkg import optional_package >>> pkg, have_pkg, setup_module = optional_package('not_a_package') - Of course in this case the package doesn't exist, and so, in the module: + >>> # Of course in this case the package doesn't exist, and so, in the module: >>> have_pkg False - and >>> pkg.some_function() #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... TripWireError: We need package not_a_package for these functions, but ``import not_a_package`` raised an ImportError - If the module does exist - we get the module + >>> # If the module does exist - we get the module >>> pkg, _, _ = optional_package('os') >>> hasattr(pkg, 'path') True - Or a submodule if that's what we asked for + >>> # Or a submodule if that's what we asked for >>> subpkg, _, _ = optional_package('os.path') >>> hasattr(subpkg, 'dirname') True diff --git a/fury/pick.py b/fury/pick.py index 6949638c5..49941849a 100644 --- a/fury/pick.py +++ b/fury/pick.py @@ -2,6 +2,7 @@ import numpy as np +from fury.decorators import warn_on_args_to_kwargs from fury.lib import ( CellPicker, DataObject, @@ -16,7 +17,15 @@ class PickingManager: """Picking Manager helps with picking 3D objects.""" - def __init__(self, vertices=True, faces=True, actors=True, world_coords=True): + @warn_on_args_to_kwargs() + def __init__( + self, + *, + vertices=True, + faces=True, + actors=True, + world_coords=True, + ): """Initialize Picking Manager. Parameters @@ -120,7 +129,8 @@ def pickable_off(self, actors): class SelectionManager: """Selection Manager helps with picking many objects simultaneously.""" - def __init__(self, select="faces"): + @warn_on_args_to_kwargs() + def __init__(self, *, select="faces"): """Initialize Selection Manager. Parameters @@ -171,7 +181,8 @@ def pick(self, disp_xy, sc): """ return self.select(disp_xy, sc, area=0)[0] - def select(self, disp_xy, sc, area=0): + @warn_on_args_to_kwargs() + def select(self, disp_xy, sc, *, area=0): """Select multiple objects using display coordinates. Parameters @@ -202,26 +213,49 @@ def select(self, disp_xy, sc, area=0): res = self.hsel.Select() except OverflowError: - return {0: {"node": None, "vertex": None, "face": None, "actor": None}} + return { + 0: { + "node": None, + "vertex": None, + "face": None, + "actor": None, + } + } num_nodes = res.GetNumberOfNodes() if num_nodes < 1: sel_node = None - return {0: {"node": None, "vertex": None, "face": None, "actor": None}} + return { + 0: { + "node": None, + "vertex": None, + "face": None, + "actor": None, + } + } else: for i in range(num_nodes): sel_node = res.GetNode(i) - info = {"node": None, "vertex": None, "face": None, "actor": None} + info = { + "node": None, + "vertex": None, + "face": None, + "actor": None, + } if sel_node is not None: selected_nodes = set( np.floor( - numpy_support.vtk_to_numpy(sel_node.GetSelectionList()) + numpy_support.vtk_to_numpy( + sel_node.GetSelectionList(), + ) ).astype(int) ) info["node"] = sel_node - info["actor"] = sel_node.GetProperties().Get(sel_node.PROP()) + info["actor"] = sel_node.GetProperties().Get( + sel_node.PROP(), + ) if self.selected_type == "faces": info["face"] = list(selected_nodes) if self.selected_type == "vertex": diff --git a/fury/pkg_info.py b/fury/pkg_info.py index 7bd7da41e..3773fbf22 100644 --- a/fury/pkg_info.py +++ b/fury/pkg_info.py @@ -4,6 +4,8 @@ from packaging.version import Version +from fury.decorators import warn_on_args_to_kwargs + try: from ._version import __version__ except ImportError: @@ -12,6 +14,7 @@ COMMIT_HASH = "$Format:%h$" +@warn_on_args_to_kwargs() def pkg_commit_hash(pkg_path: str | None = None) -> tuple[str, str]: """Get short form of commit hash diff --git a/fury/primitive.py b/fury/primitive.py index 768a92626..67a94663d 100644 --- a/fury/primitive.py +++ b/fury/primitive.py @@ -9,6 +9,7 @@ from scipy.version import short_version from fury.data import DATA_DIR +from fury.decorators import warn_on_args_to_kwargs from fury.transform import cart2sphere, sphere2cart from fury.utils import fix_winding_order @@ -46,8 +47,9 @@ def faces_from_sphere_vertices(vertices): return faces +@warn_on_args_to_kwargs() def repeat_primitive_function( - func, centers, func_args=None, directions=(1, 0, 0), colors=(1, 0, 0), scales=1 + func, centers, *, func_args=None, directions=(1, 0, 0), colors=(1, 0, 0), scales=1 ): """Repeat Vertices and triangles of a specific primitive function. @@ -91,12 +93,11 @@ def repeat_primitive_function( "sq_params should 1 or equal to the numbers \ of centers" ) - vertices = np.concatenate([func(i)[0] for i in func_args]) return repeat_primitive( - vertices=vertices, - faces=faces, - centers=centers, + vertices, + faces, + centers, directions=directions, colors=colors, scales=scales, @@ -104,10 +105,12 @@ def repeat_primitive_function( ) +@warn_on_args_to_kwargs() def repeat_primitive( vertices, faces, centers, + *, directions=None, colors=(1, 0, 0), scales=1, @@ -173,7 +176,8 @@ def repeat_primitive( axis=0, ).reshape((big_triangles.shape[0], 1)) - def normalize_input(arr, arr_name=""): + @warn_on_args_to_kwargs() + def normalize_input(arr, *, arr_name=""): if ( isinstance(arr, (tuple, list, np.ndarray)) and len(arr) in [3, 4] @@ -192,12 +196,12 @@ def normalize_input(arr, arr_name=""): return np.array(arr) # update colors - colors = normalize_input(colors, "colors") + colors = normalize_input(colors, arr_name="colors") big_colors = np.repeat(colors, unit_verts_size, axis=0) big_colors *= 255 # update orientations - directions = normalize_input(directions, "directions") + directions = normalize_input(directions, arr_name="directions") for pts, dirs in enumerate(directions): # Normal vector of the object. dir_abs = np.linalg.norm(dirs) @@ -295,7 +299,8 @@ def prim_box(): return vertices, triangles -def prim_sphere(name="symmetric362", gen_faces=False, phi=None, theta=None): +@warn_on_args_to_kwargs() +def prim_sphere(*, name="symmetric362", gen_faces=False, phi=None, theta=None): """Provide vertices and triangles of the spheres. Parameters @@ -413,7 +418,7 @@ def _fexp(x, p): """Return a different kind of exponentiation.""" return np.sign(x) * (np.abs(x) ** p) - sphere_verts, sphere_triangles = prim_sphere(sphere_name) + sphere_verts, sphere_triangles = prim_sphere(name=sphere_name) _, sphere_phi, sphere_theta = cart2sphere(*sphere_verts.T) phi, theta = roundness @@ -605,7 +610,8 @@ def prim_rhombicuboctahedron(): return vertices, triangles -def prim_star(dim=2): +@warn_on_args_to_kwargs() +def prim_star(*, dim=2): """Return vertices and triangle for star geometry. Parameters @@ -918,7 +924,8 @@ def prim_frustum(): return vertices, triangles -def prim_cylinder(radius=0.5, height=1, sectors=36, capped=True): +@warn_on_args_to_kwargs() +def prim_cylinder(*, radius=0.5, height=1, sectors=36, capped=True): """Return vertices and triangles for a cylinder. Parameters @@ -1045,8 +1052,14 @@ def prim_cylinder(radius=0.5, height=1, sectors=36, capped=True): return vertices, triangles +@warn_on_args_to_kwargs() def prim_arrow( - height=1.0, resolution=10, tip_length=0.35, tip_radius=0.1, shaft_radius=0.03 + *, + height=1.0, + resolution=10, + tip_length=0.35, + tip_radius=0.1, + shaft_radius=0.03, ): """Return vertices and triangle for arrow geometry. @@ -1135,7 +1148,8 @@ def prim_arrow( return vertices, triangles -def prim_cone(radius=0.5, height=1, sectors=10): +@warn_on_args_to_kwargs() +def prim_cone(*, radius=0.5, height=1, sectors=10): """Return vertices and triangle of a Cone. Parameters diff --git a/fury/py.typed b/fury/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/fury/shaders/__init__.py b/fury/shaders/__init__.py index c8a9378d7..62d86f776 100644 --- a/fury/shaders/__init__.py +++ b/fury/shaders/__init__.py @@ -1,23 +1,3 @@ -from fury.shaders.base import ( - add_shader_callback, - attribute_to_actor, - compose_shader, - import_fury_shader, - load, - load_shader, - replace_shader_in_actor, - shader_apply_effects, - shader_to_actor, -) +import lazy_loader as lazy -__all__ = [ - "add_shader_callback", - "attribute_to_actor", - "compose_shader", - "import_fury_shader", - "load_shader", - "load", - "replace_shader_in_actor", - "shader_apply_effects", - "shader_to_actor", -] +__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) diff --git a/fury/shaders/__init__.pyi b/fury/shaders/__init__.pyi new file mode 100644 index 000000000..0327ad0c7 --- /dev/null +++ b/fury/shaders/__init__.pyi @@ -0,0 +1,23 @@ +__all__ = [ + "add_shader_callback", + "attribute_to_actor", + "compose_shader", + "import_fury_shader", + "load_shader", + "load", + "replace_shader_in_actor", + "shader_apply_effects", + "shader_to_actor", +] + +from .base import ( + add_shader_callback, + attribute_to_actor, + compose_shader, + import_fury_shader, + load, + load_shader, + replace_shader_in_actor, + shader_apply_effects, + shader_to_actor, +) diff --git a/fury/shaders/base.py b/fury/shaders/base.py index 7540db6e8..cf1769759 100644 --- a/fury/shaders/base.py +++ b/fury/shaders/base.py @@ -1,7 +1,8 @@ from functools import partial import os -from fury import enable_warnings +import fury +from fury.decorators import warn_on_args_to_kwargs from fury.deprecator import deprecate_with_version from fury.io import load_text from fury.lib import ( @@ -168,9 +169,11 @@ def load(filename): return shader_file.read() +@warn_on_args_to_kwargs() def shader_to_actor( actor, shader_type, + *, impl_code="", decl_code="", block="valuepass", @@ -236,7 +239,7 @@ def shader_to_actor( impl_code = block_impl + "\n" + impl_code if debug: - enable_warnings() + fury.enable_warnings() error_msg = "\n\n--- DEBUG: THIS LINE GENERATES AN ERROR ---\n\n" impl_code += error_msg @@ -279,7 +282,8 @@ def replace_shader_in_actor(actor, shader_type, code): getattr(sp, function)(code) -def add_shader_callback(actor, callback, priority=0.0): +@warn_on_args_to_kwargs() +def add_shader_callback(actor, callback, *, priority=0.0): """Add a shader callback to the actor. Parameters @@ -328,34 +332,35 @@ def callbackMean(_caller, _event, calldata=None): test_values.append(500) fs.add_shader_callback( - actor, callbackHigh, 999) + actor, callbackHigh, priority=999) fs.add_shader_callback( - actor, callbackLow, 0) + actor, callbackLow, priority=0) id_mean = fs.add_shader_callback( - actor, callbackMean, 500) + actor, callbackMean, priority=500) showm.start() # test_values = [999, 500, 0, 999, 500, 0, ...] """ - - @calldata_type(VTK_OBJECT) - def cbk(caller, event, calldata=None): - callback(caller, event, calldata) - if not isinstance(priority, (float, int)): - raise TypeError( + raise ValueError( """ add_shader_callback priority argument should be a float/int""" ) + # @warn_on_args_to_kwargs() + @calldata_type(VTK_OBJECT) + def cbk(caller, event, calldata=None): + callback(caller, event, calldata=calldata) + mapper = actor.GetMapper() id_observer = mapper.AddObserver(Command.UpdateShaderEvent, cbk, priority) return id_observer -def shader_apply_effects(window, actor, effects, priority=0): +@warn_on_args_to_kwargs() +def shader_apply_effects(window, actor, effects, *, priority=0): """This applies a specific opengl state (effect) or a list of effects just before the actor's shader is executed. @@ -381,7 +386,8 @@ def shader_apply_effects(window, actor, effects, priority=0): if not isinstance(effects, list): effects = [effects] - def callback(_caller, _event, calldata=None, effects=None, window=None): + @warn_on_args_to_kwargs() + def callback(_caller, _event, *, calldata=None, effects=None, window=None): program = calldata glState = window.GetState() if program is not None: @@ -389,13 +395,14 @@ def callback(_caller, _event, calldata=None, effects=None, window=None): func(glState) id_observer = add_shader_callback( - actor, partial(callback, effects=effects, window=window), priority + actor, partial(callback, effects=effects, window=window), priority=priority ) return id_observer -def attribute_to_actor(actor, arr, attr_name, deep=True): +@warn_on_args_to_kwargs() +def attribute_to_actor(actor, arr, attr_name, *, deep=True): """Link a numpy array with vertex attribute. Parameters diff --git a/fury/shaders/lighting/linear_rgb_to_srgb.frag b/fury/shaders/lighting/linear_rgb_to_srgb.frag new file mode 100644 index 000000000..d1c72c83b --- /dev/null +++ b/fury/shaders/lighting/linear_rgb_to_srgb.frag @@ -0,0 +1,4 @@ +vec3 linear_rgb_to_srgb(vec3 linear) +{ + return vec3(linear_to_srgb(linear.r), linear_to_srgb(linear.g), linear_to_srgb(linear.b)); +} diff --git a/fury/shaders/lighting/linear_to_srgb.frag b/fury/shaders/lighting/linear_to_srgb.frag new file mode 100644 index 000000000..ac686853c --- /dev/null +++ b/fury/shaders/lighting/linear_to_srgb.frag @@ -0,0 +1,4 @@ +float linear_to_srgb(float linear) +{ + return (linear <= 0.0031308) ? (12.92 * linear) : (1.055 * pow(linear, 1.0 / 2.4) - 0.055); +} diff --git a/fury/shaders/lighting/srgb_to_linear.frag b/fury/shaders/lighting/srgb_to_linear.frag new file mode 100644 index 000000000..78c765c20 --- /dev/null +++ b/fury/shaders/lighting/srgb_to_linear.frag @@ -0,0 +1,4 @@ +float srgb_to_linear(float non_linear) +{ + return (non_linear <= 0.04045) ? ((1.0 / 12.92) * non_linear) : pow(non_linear * (1.0 / 1.055) + 0.055 / 1.055, 2.4); +} diff --git a/fury/shaders/lighting/srgb_to_linear_rgb.frag b/fury/shaders/lighting/srgb_to_linear_rgb.frag new file mode 100644 index 000000000..e4c2ef22a --- /dev/null +++ b/fury/shaders/lighting/srgb_to_linear_rgb.frag @@ -0,0 +1,4 @@ +vec3 srgb_to_linear_rgb(vec3 srgb) +{ + return vec3(srgb_to_linear(srgb.r), srgb_to_linear(srgb.g), srgb_to_linear(srgb.b)); +} diff --git a/fury/shaders/tests/test_base.py b/fury/shaders/tests/test_base.py index 7fc7f3438..554d61710 100644 --- a/fury/shaders/tests/test_base.py +++ b/fury/shaders/tests/test_base.py @@ -3,7 +3,6 @@ import numpy as np import numpy.testing as npt -import pytest from fury import actor, window from fury.deprecator import ExpiredDeprecationError @@ -191,7 +190,7 @@ def test_add_shader_callback(): scene = window.Scene() scene.add(cube) - showm = window.ShowManager(scene) + showm = window.ShowManager(scene=scene) class Timer: idx = 0.0 @@ -232,10 +231,11 @@ def callbackLow(_caller, _event, calldata=None): if program is not None: test_values.append(0) - id_observer = add_shader_callback(cone_actor, callbackLow, 0) + id_observer = add_shader_callback(cone_actor, callbackLow, priority=0) - with pytest.raises(Exception): # noqa: B017 - add_shader_callback(cone_actor, callbackLow, priority="str") + npt.assert_raises( + ValueError, add_shader_callback, cone_actor, callbackLow, priority="str" + ) mapper = cone_actor.GetMapper() mapper.RemoveObserver(id_observer) @@ -258,10 +258,10 @@ def callbackMean(_caller, _event, calldata=None): if program is not None: test_values.append(500) - add_shader_callback(cone_actor, callbackHigh, 999) - add_shader_callback(cone_actor, callbackLow, 0) + add_shader_callback(cone_actor, callbackHigh, priority=999) + add_shader_callback(cone_actor, callbackLow, priority=0) - id_mean = add_shader_callback(cone_actor, callbackMean, 500) + id_mean = add_shader_callback(cone_actor, callbackMean, priority=500) # check the priority of each call window.snapshot(scene, size=(200, 200)) diff --git a/fury/shaders/utils/find_roots.frag b/fury/shaders/utils/find_roots.frag new file mode 100644 index 000000000..e5b80f7a4 --- /dev/null +++ b/fury/shaders/utils/find_roots.frag @@ -0,0 +1,82 @@ +void find_roots(out float out_roots[MAX_DEGREE + 1], float poly[MAX_DEGREE + 1], float begin, float end) { + float tolerance = (end - begin) * 1.0e-4; + // Construct the quadratic derivative of the polynomial. We divide each + // derivative by the factorial of its order, such that the constant + // coefficient can be copied directly from poly. That is a safeguard + // against overflow and makes it easier to avoid spilling below. The + // factors happen to be binomial coefficients then. + float derivative[MAX_DEGREE + 1]; + derivative[0] = poly[MAX_DEGREE - 2]; + derivative[1] = float(MAX_DEGREE - 1) * poly[MAX_DEGREE - 1]; + derivative[2] = (0.5 * float((MAX_DEGREE - 1) * MAX_DEGREE)) * poly[MAX_DEGREE - 0]; + _unroll_ + for (int i = 3; i != MAX_DEGREE + 1; ++i) + derivative[i] = 0.0; + // Compute its two roots using the quadratic formula + float discriminant = derivative[1] * derivative[1] - 4.0 * derivative[0] * derivative[2]; + if (discriminant >= 0.0) { + float sqrt_discriminant = sqrt(discriminant); + float scaled_root = derivative[1] + ((derivative[1] > 0.0) ? sqrt_discriminant : (-sqrt_discriminant)); + float root_0 = clamp(-2.0 * derivative[0] / scaled_root, begin, end); + float root_1 = clamp(-0.5 * scaled_root / derivative[2], begin, end); + out_roots[MAX_DEGREE - 2] = min(root_0, root_1); + out_roots[MAX_DEGREE - 1] = max(root_0, root_1); + } + else { + // Indicate that the cubic derivative has a single root + out_roots[MAX_DEGREE - 2] = begin; + out_roots[MAX_DEGREE - 1] = begin; + } + // The last entry in the root array is set to end to make it easier to + // iterate over relevant intervals, all untouched roots are set to begin + out_roots[MAX_DEGREE] = end; + _unroll_ + for (int i = 0; i != MAX_DEGREE - 2; ++i) + out_roots[i] = begin; + // Work your way up to derivatives of higher degree until you reach the + // polynomial itself. This implementation may seem peculiar: It always + // treats the derivative as though it had degree MAX_DEGREE and it + // constructs the derivatives in a contrived way. Changing that would + // reduce the number of arithmetic instructions roughly by a factor of two. + // However, it would also cause register spilling, which has a far more + // negative impact on the overall run time. Profiling indicates that the + // current implementation has no spilling whatsoever. + _loop_ + for (int degree = 3; degree != MAX_DEGREE + 1; ++degree) { + // Take the integral of the previous derivative (scaled such that the + // constant coefficient can still be copied directly from poly) + float prev_derivative_order = float(MAX_DEGREE + 1 - degree); + _unroll_ + for (int i = MAX_DEGREE; i != 0; --i) + derivative[i] = derivative[i - 1] * (prev_derivative_order * (1.0 / float(i))); + // Copy the constant coefficient without causing spilling. This part + // would be harder if the derivative were not scaled the way it is. + _unroll_ + for (int i = 0; i != MAX_DEGREE - 2; ++i) + derivative[0] = (degree == MAX_DEGREE - i) ? poly[i] : derivative[0]; + // Determine the value of this derivative at begin + float begin_value = derivative[MAX_DEGREE]; + _unroll_ + for (int i = MAX_DEGREE - 1; i != -1; --i) + begin_value = begin_value * begin + derivative[i]; + // Iterate over the intervals where roots may be found + _unroll_ + for (int i = 0; i != MAX_DEGREE; ++i) { + if (i < MAX_DEGREE - degree) + continue; + float current_begin = out_roots[i]; + float current_end = out_roots[i + 1]; + // Try to find a root + float root; + if (newton_bisection(root, begin_value, derivative, current_begin, current_end, begin_value, tolerance)) + out_roots[i] = root; + else if (degree < MAX_DEGREE) + // Create an empty interval for the next iteration + out_roots[i] = out_roots[i - 1]; + else + out_roots[i] = NO_INTERSECTION; + } + } + // We no longer need this array entry + out_roots[MAX_DEGREE] = NO_INTERSECTION; +} diff --git a/fury/shaders/utils/newton_bisection.frag b/fury/shaders/utils/newton_bisection.frag new file mode 100644 index 000000000..3f4b7f81f --- /dev/null +++ b/fury/shaders/utils/newton_bisection.frag @@ -0,0 +1,47 @@ +bool newton_bisection(out float out_root, out float out_end_value, + float poly[MAX_DEGREE + 1], float begin, float end, + float begin_value, float error_tolerance) +{ + if (begin == end) { + out_end_value = begin_value; + return false; + } + // Evaluate the polynomial at the end of the interval + out_end_value = poly[MAX_DEGREE]; + _unroll_ + for (int i = MAX_DEGREE - 1; i != -1; --i) + out_end_value = out_end_value * end + poly[i]; + // If the values at both ends have the same non-zero sign, there is no root + if (begin_value * out_end_value > 0.0) + return false; + // Otherwise, we find the root iteratively using Newton bisection (with + // bounded iteration count) + float current = 0.5 * (begin + end); + _loop_ + for (int i = 0; i != 90; ++i) { + // Evaluate the polynomial and its derivative + float value = poly[MAX_DEGREE] * current + poly[MAX_DEGREE - 1]; + float derivative = poly[MAX_DEGREE]; + _unroll_ + for (int j = MAX_DEGREE - 2; j != -1; --j) { + derivative = derivative * current + value; + value = value * current + poly[j]; + } + // Shorten the interval + bool right = begin_value * value > 0.0; + begin = right ? current : begin; + end = right ? end : current; + // Apply Newton's method + float guess = current - value / derivative; + // Pick a guess + float middle = 0.5 * (begin + end); + float next = (guess >= begin && guess <= end) ? guess : middle; + // Move along or terminate + bool done = abs(next - current) < error_tolerance; + current = next; + if (done) + break; + } + out_root = current; + return true; +} diff --git a/fury/stream/__init__.py b/fury/stream/__init__.py index e69de29bb..62d86f776 100644 --- a/fury/stream/__init__.py +++ b/fury/stream/__init__.py @@ -0,0 +1,3 @@ +import lazy_loader as lazy + +__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) diff --git a/fury/stream/__init__.pyi b/fury/stream/__init__.pyi new file mode 100644 index 000000000..c1dc81234 --- /dev/null +++ b/fury/stream/__init__.pyi @@ -0,0 +1,45 @@ +__all__ = [ + "FuryStreamClient", + "FuryStreamInteraction", + "interaction_callback", + "ArrayCircularQueue", + "GenericCircularQueue", + "GenericImageBufferManager", + "GenericMultiDimensionalBuffer", + "IntervalTimer", + "IntervalTimerThreading", + "RawArrayImageBufferManager", + "RawArrayMultiDimensionalBuffer", + "SharedMemCircularQueue", + "SharedMemImageBufferManager", + "SharedMemMultiDimensionalBuffer", + "remove_shm_from_resource_tracker", + "Widget", + "check_port_is_available", + "server", + "client", + "tools", +] + +from . import ( + client, + server, + tools, + widget as widget, +) +from .client import FuryStreamClient, FuryStreamInteraction, interaction_callback +from .tools import ( + ArrayCircularQueue, + GenericCircularQueue, + GenericImageBufferManager, + GenericMultiDimensionalBuffer, + IntervalTimer, + IntervalTimerThreading, + RawArrayImageBufferManager, + RawArrayMultiDimensionalBuffer, + SharedMemCircularQueue, + SharedMemImageBufferManager, + SharedMemMultiDimensionalBuffer, + remove_shm_from_resource_tracker, +) +from .widget import Widget, check_port_is_available diff --git a/fury/stream/client.py b/fury/stream/client.py index 88da17caa..4bc5ead23 100644 --- a/fury/stream/client.py +++ b/fury/stream/client.py @@ -6,6 +6,7 @@ import numpy as np import vtk +from fury.decorators import warn_on_args_to_kwargs from fury.stream.constants import PY_VERSION_8, _CQUEUE from fury.stream.tools import ( ArrayCircularQueue, @@ -47,9 +48,11 @@ def callback_stream_client(stream_client): class FuryStreamClient: """This obj is responsible to create a StreamClient.""" + @warn_on_args_to_kwargs() def __init__( self, showm, + *, max_window_size=None, use_raw_array=True, whithout_iren_start=False, @@ -119,7 +122,8 @@ def __init__( self.use_raw_array = use_raw_array self._started = False - def start(self, ms=0, use_asyncio=False): + @warn_on_args_to_kwargs() + def start(self, *, ms=0, use_asyncio=False): """Start the stream client. Parameters @@ -134,6 +138,7 @@ def start(self, ms=0, use_asyncio=False): """ + @warn_on_args_to_kwargs() def callback_for_vtk(caller, event, *args, **kwargs): callback_stream_client(**{"stream_client": kwargs["stream_client"]}) @@ -270,8 +275,9 @@ def interaction_callback(circular_queue, showm, iren, render_after): class FuryStreamInteraction: """This obj. is responsible to manage the user interaction""" + @warn_on_args_to_kwargs() def __init__( - self, showm, max_queue_size=50, use_raw_array=True, whithout_iren_start=False + self, showm, *, max_queue_size=50, use_raw_array=True, whithout_iren_start=False ): """Initialize the StreamInteraction obj. @@ -306,7 +312,8 @@ def __init__( self._whithout_iren_start = whithout_iren_start self._started = False - def start(self, ms=3, use_asyncio=False): + @warn_on_args_to_kwargs() + def start(self, *, ms=3, use_asyncio=False): """Start the stream interaction client. Parameters diff --git a/fury/stream/server/__init__.py b/fury/stream/server/__init__.py index af5b0e0ce..62d86f776 100644 --- a/fury/stream/server/__init__.py +++ b/fury/stream/server/__init__.py @@ -1,3 +1,3 @@ -from fury.stream.server.main import web_server, web_server_raw_array +import lazy_loader as lazy -__all__ = ["web_server", "web_server_raw_array"] +__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) diff --git a/fury/stream/server/__init__.pyi b/fury/stream/server/__init__.pyi new file mode 100644 index 000000000..1947f3dcc --- /dev/null +++ b/fury/stream/server/__init__.pyi @@ -0,0 +1,22 @@ +__all__ = ["async_app", "main"] +from . import ( + async_app, + main, +) +from .async_app import ( + get_app as get_app, + index as index, + javascript as javascript, + mjpeg_handler as mjpeg_handler, + offer as offer, + on_shutdown as on_shutdown, + set_mouse as set_mouse, + set_mouse_click as set_mouse_click, + set_weel as set_weel, + websocket_handler as websocket_handler, +) +from .main import ( + RTCServer as RTCServer, + web_server as web_server, + web_server_raw_array as web_server_raw_array, +) diff --git a/fury/stream/server/async_app.py b/fury/stream/server/async_app.py index eac612818..ad99b9a21 100644 --- a/fury/stream/server/async_app.py +++ b/fury/stream/server/async_app.py @@ -8,6 +8,8 @@ from aiohttp import MultipartWriter, WSCloseCode, web import numpy as np +from fury.decorators import warn_on_args_to_kwargs + try: from aiortc import RTCPeerConnection, RTCSessionDescription from aiortc.contrib.media import MediaRelay @@ -215,7 +217,9 @@ async def websocket_handler(request, **kwargs): return ws +@warn_on_args_to_kwargs() def get_app( + *, rtc_server=None, folder=None, circular_queue=None, diff --git a/fury/stream/server/main.py b/fury/stream/server/main.py index 1b7656857..dd795dd93 100644 --- a/fury/stream/server/main.py +++ b/fury/stream/server/main.py @@ -4,6 +4,7 @@ from aiohttp import web import numpy as np +from fury.decorators import warn_on_args_to_kwargs from fury.stream.constants import PY_VERSION_8, _CQUEUE from fury.stream.server.async_app import get_app from fury.stream.tools import ( @@ -111,7 +112,9 @@ def release(self): pass +@warn_on_args_to_kwargs() def web_server_raw_array( + *, image_buffers=None, info_buffer=None, queue_head_tail_buffer=None, @@ -183,7 +186,7 @@ def web_server_raw_array( ) app_fury = get_app( - rtc_server, + rtc_server=rtc_server, circular_queue=circular_queue, image_buffer_manager=image_buffer_manager, provides_mjpeg=provides_mjpeg, @@ -201,7 +204,9 @@ def web_server_raw_array( image_buffer_manager.cleanup() +@warn_on_args_to_kwargs() def web_server( + *, image_buffer_names=None, info_buffer_name=None, queue_head_tail_buffer_name=None, @@ -280,7 +285,7 @@ def web_server( ) app_fury = get_app( - rtc_server, + rtc_server=rtc_server, circular_queue=circular_queue, image_buffer_manager=image_buffer_manager, provides_mjpeg=provides_mjpeg, diff --git a/fury/stream/tools.py b/fury/stream/tools.py index a9cbe1c3f..b9fa90fde 100644 --- a/fury/stream/tools.py +++ b/fury/stream/tools.py @@ -9,6 +9,7 @@ from PIL import Image, ImageDraw import numpy as np +from fury.decorators import warn_on_args_to_kwargs from fury.stream.constants import PY_VERSION_8 if PY_VERSION_8: @@ -65,7 +66,8 @@ def fix_unregister(name, rtype): class GenericMultiDimensionalBuffer(ABC): """This implements a abstract (generic) multidimensional buffer.""" - def __init__(self, max_size=None, dimension=8): + @warn_on_args_to_kwargs() + def __init__(self, *, max_size=None, dimension=8): """Initialize the multidimensional buffer. Parameters @@ -129,7 +131,8 @@ def cleanup(self): ... # pragma: no cover class RawArrayMultiDimensionalBuffer(GenericMultiDimensionalBuffer): """This implements a multidimensional buffer with RawArray.""" - def __init__(self, max_size, dimension=4, buffer=None): + @warn_on_args_to_kwargs() + def __init__(self, max_size, *, dimension=4, buffer=None): """Stream system uses that to implement the CircularQueue with shared memory resources. @@ -147,7 +150,7 @@ def __init__(self, max_size, dimension=4, buffer=None): a already created RawArray """ - super().__init__(max_size, dimension) + super().__init__(max_size=max_size, dimension=dimension) if buffer is None: self.create_mem_resource() else: @@ -178,7 +181,8 @@ class SharedMemMultiDimensionalBuffer(GenericMultiDimensionalBuffer): with SharedMemory. """ - def __init__(self, max_size, dimension=4, buffer_name=None): + @warn_on_args_to_kwargs() + def __init__(self, max_size, *, dimension=4, buffer_name=None): """Stream system uses that to implement the CircularQueue with shared memory resources. @@ -193,7 +197,7 @@ def __init__(self, max_size, dimension=4, buffer_name=None): a already created SharedMemory """ - super().__init__(max_size, dimension) + super().__init__(max_size=max_size, dimension=dimension) if buffer_name is None: self.create_mem_resource() self._created = True @@ -271,8 +275,10 @@ class GenericCircularQueue(ABC): shared memory resources. """ + @warn_on_args_to_kwargs() def __init__( self, + *, max_size=None, dimension=8, use_shared_mem=False, @@ -389,7 +395,8 @@ class ArrayCircularQueue(GenericCircularQueue): Arrays and RawArrays. """ - def __init__(self, max_size=10, dimension=6, head_tail_buffer=None, buffer=None): + @warn_on_args_to_kwargs() + def __init__(self, *, max_size=10, dimension=6, head_tail_buffer=None, buffer=None): """Stream system uses that to implement user interactions Parameters @@ -410,7 +417,12 @@ def __init__(self, max_size=10, dimension=6, head_tail_buffer=None, buffer=None) RawArray to store the data """ - super().__init__(max_size, dimension, use_shared_mem=False, buffer=buffer) + super().__init__( + max_size=max_size, + dimension=dimension, + use_shared_mem=False, + buffer=buffer, + ) if head_tail_buffer is None: self.create_mem_resource() @@ -456,8 +468,9 @@ class SharedMemCircularQueue(GenericCircularQueue): SharedMemory. """ + @warn_on_args_to_kwargs() def __init__( - self, max_size=10, dimension=6, head_tail_buffer_name=None, buffer_name=None + self, *, max_size=10, dimension=6, head_tail_buffer_name=None, buffer_name=None ): """Stream system uses that to implement user interactions @@ -479,7 +492,10 @@ def __init__( """ super().__init__( - max_size, dimension, use_shared_mem=True, buffer_name=buffer_name + max_size=max_size, + dimension=dimension, + use_shared_mem=True, + buffer_name=buffer_name, ) if head_tail_buffer_name is None: @@ -564,7 +580,8 @@ class GenericImageBufferManager(ABC): the n-buffer technique. """ - def __init__(self, max_window_size=None, num_buffers=2, use_shared_mem=False): + @warn_on_args_to_kwargs() + def __init__(self, *, max_window_size=None, num_buffers=2, use_shared_mem=False): """Initialize the ImageBufferManager. Parameters @@ -669,7 +686,8 @@ def get_jpeg(self): return bytes_img - async def async_get_jpeg(self, ms=33): + @warn_on_args_to_kwargs() + async def async_get_jpeg(self, *, ms=33): jpeg = self.get_jpeg() await asyncio.sleep(ms / 1000) return jpeg @@ -690,8 +708,10 @@ def cleanup(self): class RawArrayImageBufferManager(GenericImageBufferManager): """This implements an ImageBufferManager using RawArrays.""" + @warn_on_args_to_kwargs() def __init__( self, + *, max_window_size=(100, 100), num_buffers=2, image_buffers=None, @@ -714,7 +734,11 @@ def __init__( A list of buffers with each one containing a frame. """ - super().__init__(max_window_size, num_buffers, use_shared_mem=False) + super().__init__( + max_window_size=max_window_size, + num_buffers=num_buffers, + use_shared_mem=False, + ) if image_buffers is None or info_buffer is None: self.create_mem_resource() else: @@ -767,8 +791,10 @@ class SharedMemImageBufferManager(GenericImageBufferManager): SharedMemory approach. """ + @warn_on_args_to_kwargs() def __init__( self, + *, max_window_size=(100, 100), num_buffers=2, image_buffer_names=None, @@ -795,7 +821,11 @@ def __init__( Python >=3.8 is a requirement to use this object. """ - super().__init__(max_window_size, num_buffers, use_shared_mem=True) + super().__init__( + max_window_size=max_window_size, + num_buffers=num_buffers, + use_shared_mem=True, + ) if image_buffer_names is None or info_buffer_name is None: self.create_mem_resource() self._created = True diff --git a/fury/stream/widget.py b/fury/stream/widget.py index 469da2ca9..14d9f1bbe 100644 --- a/fury/stream/widget.py +++ b/fury/stream/widget.py @@ -13,6 +13,7 @@ except ImportError: IPYTHON_AVAILABLE = False +from fury.decorators import warn_on_args_to_kwargs from fury.stream.client import FuryStreamClient, FuryStreamInteraction from fury.stream.constants import PY_VERSION_8 @@ -46,9 +47,11 @@ class Widget: using the SharedMemory object from Python multiprocessing. """ + @warn_on_args_to_kwargs() def __init__( self, showm, + *, ms_stream=33, ms_interaction=33, host="localhost", @@ -130,7 +133,8 @@ def command_string(self): s += ")" return s - def _start_fury_client(self, use_asyncio=False): + @warn_on_args_to_kwargs() + def _start_fury_client(self, *, use_asyncio=False): """Start the fury image buffer client and the interaction client Parameters @@ -193,12 +197,14 @@ def url(self): url += f"?iframe=1&encoding={self.encoding}" return url - def return_iframe(self, height=200): + @warn_on_args_to_kwargs() + def return_iframe(self, *, height=200): """Return the jupyter div iframe used to show the stream""" if IPYTHON_AVAILABLE: display(IFrame(self.url, "100%", f"{int(height)}px")) - def start(self, use_asyncio=False): + @warn_on_args_to_kwargs() + def start(self, *, use_asyncio=False): """Start the fury client and the interaction client and return the url Parameters @@ -215,7 +221,8 @@ def start(self, use_asyncio=False): return False print(f"url: {self.url}") - def display(self, height=150): + @warn_on_args_to_kwargs() + def display(self, *, height=150): """Start the server and display the url in an iframe""" self._start_fury_client() ok = self.run_command() diff --git a/fury/testing.py b/fury/testing.py index 79f790f7a..7904f77c4 100644 --- a/fury/testing.py +++ b/fury/testing.py @@ -13,6 +13,8 @@ from numpy.testing import assert_array_equal import scipy # type: ignore +from fury.decorators import warn_on_args_to_kwargs + @contextmanager def captured_output(): @@ -37,13 +39,18 @@ def captured_output(): sys.stdout, sys.stderr = old_out, old_err -def assert_operator(value1, value2, msg="", op=operator.eq): +@warn_on_args_to_kwargs() +def assert_operator(value1, value2, *, msg="", op=operator.eq): """Check Boolean statement.""" if not op(value1, value2): raise AssertionError(msg.format(str(value2), str(value1))) -assert_greater_equal = partial(assert_operator, op=operator.ge, msg="{0} >= {1}") +assert_greater_equal = partial( + assert_operator, + op=operator.ge, + msg="{0} >= {1}", +) assert_greater = partial(assert_operator, op=operator.gt, msg="{0} > {1}") assert_less_equal = partial(assert_operator, op=operator.le, msg="{0} =< {1}") assert_less = partial(assert_operator, op=operator.lt, msg="{0} < {1}") @@ -63,7 +70,8 @@ def assert_arrays_equal(arrays1, arrays2): class EventCounter: - def __init__(self, events_names=None): + @warn_on_args_to_kwargs() + def __init__(self, *, events_names=None): if events_names is None: events_names = [ "CharEvent", @@ -113,7 +121,11 @@ def check_counts(self, expected): msg = "Wrong count for '{}'." for event, count in expected.events_counts.items(): - assert_equal(self.events_counts[event], count, msg=msg.format(event)) + assert_equal( + self.events_counts[event], + count, + msg=msg.format(event), + ) class clear_and_catch_warnings(warnings.catch_warnings): @@ -161,7 +173,8 @@ class clear_and_catch_warnings(warnings.catch_warnings): class_modules = () - def __init__(self, record=True, modules=()): + @warn_on_args_to_kwargs() + def __init__(self, *, record=True, modules=()): self.modules = set(modules).union(self.class_modules) self._warnreg_copies = {} super(clear_and_catch_warnings, self).__init__(record=record) diff --git a/fury/tests/test_actors.py b/fury/tests/test_actors.py index 46625250d..043cc0992 100644 --- a/fury/tests/test_actors.py +++ b/fury/tests/test_actors.py @@ -10,7 +10,6 @@ from fury import actor, primitive as fp, shaders, window from fury.actor import grid from fury.decorators import skip_linux, skip_osx, skip_win -from fury.deprecator import ExpiredDeprecationError # Allow import, but disable doctests if we don't have dipy from fury.optpkg import optional_package @@ -48,8 +47,8 @@ def test_slicer(verbose=False): scene = window.Scene() data = 255 * np.random.rand(50, 50, 50) affine = np.eye(4) - slicer = actor.slicer(data, affine, value_range=[data.min(), data.max()]) - slicer.display(None, None, 25) + slicer = actor.slicer(data, affine=affine, value_range=[data.min(), data.max()]) + slicer.display(x=None, y=None, z=25) scene.add(slicer) scene.reset_camera() @@ -57,7 +56,7 @@ def test_slicer(verbose=False): # window.show(scene) # copy pixels in numpy array directly - arr = window.snapshot(scene, "test_slicer.png", offscreen=True) + arr = window.snapshot(scene, fname="test_slicer.png", offscreen=True) if verbose: print(arr.sum()) @@ -80,14 +79,22 @@ def test_slicer(verbose=False): # save pixels in png file not a numpy array with InTemporaryDirectory() as tmpdir: fname = os.path.join(tmpdir, "slice.png") - window.snapshot(scene, fname, offscreen=True) + window.snapshot(scene, fname=fname, offscreen=True) report = window.analyze_snapshot(fname, find_objects=True) npt.assert_equal(report.objects, 1) # Test Errors data_4d = 255 * np.random.rand(50, 50, 50, 50) - npt.assert_raises(ValueError, actor.slicer, data_4d) - npt.assert_raises(ValueError, actor.slicer, np.ones(10)) + npt.assert_raises( + ValueError, + actor.slicer, + data_4d, + ) + npt.assert_raises( + ValueError, + actor.slicer, + np.ones(10), + ) scene.clear() @@ -114,9 +121,9 @@ def test_slicer(verbose=False): scene.clear() slicer_lut = actor.slicer(data, lookup_colormap=lut) - slicer_lut.display(10, None, None) - slicer_lut.display(None, 10, None) - slicer_lut.display(None, None, 10) + slicer_lut.display(x=10, y=None, z=None) + slicer_lut.display(x=None, y=10, z=None) + slicer_lut.display(x=None, y=None, z=10) slicer_lut.opacity(0.5) slicer_lut.tolerance(0.03) @@ -125,7 +132,7 @@ def test_slicer(verbose=False): npt.assert_equal(slicer_lut2.picker.GetTolerance(), 0.03) slicer_lut2.opacity(1) slicer_lut2.tolerance(0.025) - slicer_lut2.display(None, None, 10) + slicer_lut2.display(x=None, y=None, z=10) scene.add(slicer_lut2) scene.reset_clipping_range() @@ -138,8 +145,8 @@ def test_slicer(verbose=False): data = 255 * np.random.rand(50, 50, 50) affine = np.diag([1, 3, 2, 1]) - slicer = actor.slicer(data, affine, interpolation="nearest") - slicer.display(None, None, 25) + slicer = actor.slicer(data, affine=affine, interpolation="nearest") + slicer.display(x=None, y=None, z=25) scene.add(slicer) scene.reset_camera() @@ -187,7 +194,7 @@ def test_surface(): ) scene.add(surface_actor) # window.show(scene, size=(600, 600), reset_camera=False) - arr = window.snapshot(scene, "test_surface.png", offscreen=True) + arr = window.snapshot(scene, fname="test_surface.png", offscreen=True) report = window.analyze_snapshot(arr, find_objects=True) npt.assert_equal(report.objects, 1) @@ -200,7 +207,7 @@ def test_contour_from_roi(interactive=False): data[25, 20:30, 25] = 1.0 affine = np.eye(4) surface = actor.contour_from_roi( - data, affine, color=np.array([1, 0, 1]), opacity=0.5 + data, affine=affine, color=np.array([1, 0, 1]), opacity=0.5 ) scene.add(surface) @@ -219,7 +226,7 @@ def test_contour_from_roi(interactive=False): data2[35:40, 25, 25] = 1.0 affine = np.eye(4) surface2 = actor.contour_from_roi( - data2, affine, color=np.array([0, 1, 1]), opacity=0.5 + data2, affine=affine, color=np.array([0, 1, 1]), opacity=0.5 ) scene2.add(surface2) @@ -228,8 +235,8 @@ def test_contour_from_roi(interactive=False): if interactive: window.show(scene2) - arr = window.snapshot(scene, "test_surface.png", offscreen=True) - arr2 = window.snapshot(scene2, "test_surface2.png", offscreen=True) + arr = window.snapshot(scene, fname="test_surface.png", offscreen=True) + arr2 = window.snapshot(scene2, fname="test_surface2.png", offscreen=True) report = window.analyze_snapshot(arr, find_objects=True) report2 = window.analyze_snapshot(arr2, find_objects=True) @@ -287,10 +294,10 @@ def test_contour_from_label(interactive=False): window.show(scene2) arr = window.snapshot( - scene, "test_surface.png", offscreen=True, order_transparent=False + scene, fname="test_surface.png", offscreen=True, order_transparent=False ) arr2 = window.snapshot( - scene2, "test_surface2.png", offscreen=True, order_transparent=True + scene2, fname="test_surface2.png", offscreen=True, order_transparent=True ) report = window.analyze_snapshot( @@ -312,14 +319,14 @@ def test_streamtube_and_line_actors(): lines = [line1, line2] colors = np.array([[1, 0, 0], [0, 0, 1.0]]) - c = actor.line(lines, colors, linewidth=3) + c = actor.line(lines, colors=colors, linewidth=3) scene.add(c) - c = actor.line(lines, colors, spline_subdiv=5, linewidth=3) + c = actor.line(lines, colors=colors, spline_subdiv=5, linewidth=3) scene.add(c) # create streamtubes of the same lines and shift them a bit - c2 = actor.streamtube(lines, colors, linewidth=0.1) + c2 = actor.streamtube(lines, colors=colors, linewidth=0.1) c2.SetPosition(2, 0, 0) scene.add(c2) @@ -333,7 +340,7 @@ def test_streamtube_and_line_actors(): npt.assert_equal(report.colors_found, [True, True]) # as before with splines - c2 = actor.streamtube(lines, colors, spline_subdiv=5, linewidth=0.1) + c2 = actor.streamtube(lines, colors=colors, spline_subdiv=5, linewidth=0.1) c2.SetPosition(2, 0, 0) scene.add(c2) @@ -346,7 +353,7 @@ def test_streamtube_and_line_actors(): npt.assert_equal(report.objects, 4) npt.assert_equal(report.colors_found, [True, True]) - c3 = actor.line(lines, colors, depth_cue=True, fake_tube=True) + c3 = actor.line(lines, colors=colors, depth_cue=True, fake_tube=True) shader_obj = c3.GetShaderProperty() mapper_code = shader_obj.GetGeometryShaderCode() @@ -355,9 +362,9 @@ def test_streamtube_and_line_actors(): npt.assert_equal(c3.GetProperty().GetRenderLinesAsTubes(), True) - c4 = actor.streamtube(lines, colors, replace_strips=False) + c4 = actor.streamtube(lines, colors=colors, replace_strips=False) - c5 = actor.streamtube(lines, colors, replace_strips=True) + c5 = actor.streamtube(lines, colors=colors, replace_strips=True) strips4 = c4.GetMapper().GetInput().GetStrips().GetData().GetSize() strips5 = c5.GetMapper().GetInput().GetStrips().GetData().GetSize() @@ -398,9 +405,9 @@ def test_bundle_maps(): value_range=(1.0, 1), ) - line = actor.line(bundle, metric, linewidth=0.1, lookup_colormap=lut) + line = actor.line(bundle, colors=metric, linewidth=0.1, lookup_colormap=lut) scene.add(line) - scene.add(actor.scalar_bar(lut, " ")) + scene.add(actor.scalar_bar(lookup_table=lut, title=" ")) report = window.analyze_scene(scene) @@ -413,7 +420,7 @@ def test_bundle_maps(): values = 100 * np.random.rand(nb_points) # values[:nb_points/2] = 0 - line = actor.streamtube(bundle, values, linewidth=0.1, lookup_colormap=lut) + line = actor.streamtube(bundle, colors=values, linewidth=0.1, lookup_colormap=lut) scene.add(line) # window.show(scene) @@ -425,7 +432,7 @@ def test_bundle_maps(): colors = np.random.rand(nb_points, 3) # values[:nb_points/2] = 0 - line = actor.line(bundle, colors, linewidth=2) + line = actor.line(bundle, colors=colors, linewidth=2) scene.add(line) # window.show(scene) @@ -439,8 +446,8 @@ def test_bundle_maps(): # try other input options for colors scene.clear() - actor.line(bundle, (1.0, 0.5, 0)) - actor.line(bundle, np.arange(len(bundle))) + actor.line(bundle, colors=(1.0, 0.5, 0)) + actor.line(bundle, colors=np.arange(len(bundle))) actor.line(bundle) colors = [np.random.rand(*b.shape) for b in bundle] actor.line(bundle, colors=colors) @@ -452,7 +459,7 @@ def test_odf_slicer(interactive=False): # vertices and faces of a sphere rather that needing # a specific type of sphere. We can use prim_sphere # as an alternative to get_sphere. - vertices, faces = prim_sphere("repulsion100", True) + vertices, faces = prim_sphere(name="repulsion100", gen_faces=True) sphere = Sphere() sphere.vertices = vertices sphere.faces = faces @@ -521,13 +528,13 @@ def test_odf_slicer(interactive=False): # Test that odf_slicer.display works properly scene.clear() scene.add(odf_actor) - scene.add(actor.axes((11, 11, 11))) + scene.add(actor.axes(scale=(11, 11, 11))) for i in range(11): - odf_actor.display(i, None, None) + odf_actor.display(x=i, y=None, z=None) if interactive: window.show(scene) for j in range(11): - odf_actor.display(None, j, None) + odf_actor.display(x=None, y=j, z=None) if interactive: window.show(scene) @@ -562,7 +569,7 @@ def test_odf_slicer(interactive=False): global_cm=True, ) - vertices2, faces2 = prim_sphere("repulsion200", True) + vertices2, faces2 = prim_sphere(name="repulsion200", gen_faces=True) sphere2 = Sphere() sphere2.vertices = vertices2 sphere2.faces = faces2 @@ -607,13 +614,13 @@ def test_peak_slicer(interactive=False): scene = window.Scene() peak_actor = actor.peak_slicer(peak_dirs) scene.add(peak_actor) - scene.add(actor.axes((11, 11, 11))) + scene.add(actor.axes(scale=(11, 11, 11))) if interactive: window.show(scene) scene.clear() scene.add(peak_actor) - scene.add(actor.axes((11, 11, 11))) + scene.add(actor.axes(scale=(11, 11, 11))) for k in range(11): peak_actor.display_extent(0, 10, 0, 10, k, k) @@ -621,13 +628,13 @@ def test_peak_slicer(interactive=False): peak_actor.display_extent(0, 10, j, j, 0, 10) for i in range(11): - peak_actor.display(i, None, None) + peak_actor.display(x=i, y=None, z=None) scene.rm_all() peak_actor_sym = actor.peak_slicer( peak_dirs, - peak_values, + peaks_values=peak_values, mask=None, affine=np.diag([3, 2, 1, 1]), colors=None, @@ -640,7 +647,7 @@ def test_peak_slicer(interactive=False): peak_actor_asym = actor.peak_slicer( peak_dirs, - peak_values, + peaks_values=peak_values, mask=None, affine=np.diag([3, 2, 1, 1]), colors=None, @@ -654,7 +661,7 @@ def test_peak_slicer(interactive=False): scene.add(peak_actor_sym) scene.add(peak_actor_asym) - scene.add(actor.axes((11, 11, 11))) + scene.add(actor.axes(scale=(11, 11, 11))) if interactive: window.show(scene) @@ -739,7 +746,7 @@ def test_tensor_slicer(interactive=False): mevals[..., :] = evals mevecs[..., :, :] = evecs - vertices, faces = prim_sphere("symmetric724", True) + vertices, faces = prim_sphere(name="symmetric724", gen_faces=True) sphere = Sphere() sphere.vertices = vertices sphere.faces = faces @@ -891,8 +898,7 @@ def test_points(interactive=False): def test_vector_text(interactive=False): - npt.assert_raises(ExpiredDeprecationError, actor.label, "FURY Rocks") - text_actor = actor.vector_text("FURY Rocks", direction=None) + text_actor = actor.vector_text(text="FURY Rocks", direction=None) scene = window.Scene() scene.add(text_actor) @@ -904,35 +910,35 @@ def test_vector_text(interactive=False): if interactive: window.show(scene, reset_camera=False) - text_actor = actor.vector_text("FURY Rocks") + text_actor = actor.vector_text(text="FURY Rocks") npt.assert_equal(scene.GetActors().GetNumberOfItems(), 1) center = np.array(text_actor.GetCenter()) [assert_greater_equal(v, 0) for v in center] - text_actor_centered = actor.vector_text("FURY Rocks", align_center=True) + text_actor_centered = actor.vector_text(text="FURY Rocks", align_center=True) center = np.array(text_actor_centered.GetCenter()) npt.assert_equal(center, np.zeros(3)) - text_actor_rot_1 = actor.vector_text("FURY Rocks", direction=(1, 1, 1)) - text_actor_rot_2 = actor.vector_text("FURY Rocks", direction=(1, 1, 0)) + text_actor_rot_1 = actor.vector_text(text="FURY Rocks", direction=(1, 1, 1)) + text_actor_rot_2 = actor.vector_text(text="FURY Rocks", direction=(1, 1, 0)) center_1 = text_actor_rot_1.GetCenter() center_2 = text_actor_rot_2.GetCenter() assert_not_equal(np.linalg.norm(center_1), np.linalg.norm(center_2)) # test centered - text_centered = actor.vector_text("FURY Rocks", align_center=True) + text_centered = actor.vector_text(text="FURY Rocks", align_center=True) center_3 = text_centered.GetCenter() npt.assert_almost_equal(np.linalg.norm(center_3), 0.0) text_extruded = actor.vector_text( - "FURY Rocks", scale=(0.2, 0.2, 0.2), extrusion=1.123 + text="FURY Rocks", scale=(0.2, 0.2, 0.2), extrusion=1.123 ) z_max = text_extruded.GetBounds()[-1] npt.assert_almost_equal(z_max, 1.123) text_extruded_centered = actor.vector_text( - "FURY Rocks", + text="FURY Rocks", scale=(0.2, 0.2, 0.2), direction=None, align_center=True, @@ -1253,16 +1259,31 @@ def test_container(): def test_grid(_interactive=False): vol1 = np.zeros((100, 100, 100)) vol1[25:75, 25:75, 25:75] = 100 - contour_actor1 = actor.contour_from_roi(vol1, np.eye(4), (1.0, 0, 0), 1.0) + contour_actor1 = actor.contour_from_roi( + vol1, + affine=np.eye(4), + color=(1.0, 0, 0), + opacity=1.0, + ) vol2 = np.zeros((100, 100, 100)) vol2[25:75, 25:75, 25:75] = 100 - contour_actor2 = actor.contour_from_roi(vol2, np.eye(4), (1.0, 0.5, 0), 1.0) + contour_actor2 = actor.contour_from_roi( + vol2, + affine=np.eye(4), + color=(1.0, 0.5, 0), + opacity=1.0, + ) vol3 = np.zeros((100, 100, 100)) vol3[25:75, 25:75, 25:75] = 100 - contour_actor3 = actor.contour_from_roi(vol3, np.eye(4), (1.0, 0.5, 0.5), 1.0) + contour_actor3 = actor.contour_from_roi( + vol3, + affine=np.eye(4), + color=(1.0, 0.5, 0.5), + opacity=1.0, + ) scene = window.Scene() actors = [] @@ -1303,11 +1324,11 @@ def test_grid(_interactive=False): scene.add(container) - scene.projection("orthogonal") + scene.projection(proj_type="orthogonal") counter = itertools.count() - show_m = window.ShowManager(scene) + show_m = window.ShowManager(scene=scene) def timer_callback(_obj, _event): nonlocal counter @@ -1329,7 +1350,7 @@ def timer_callback(_obj, _event): scene.rm_all() counter = itertools.count() - show_m = window.ShowManager(scene) + show_m = window.ShowManager(scene=scene) # show the grid with the captions container = grid( @@ -1461,8 +1482,8 @@ def test_matplotlib_figure(): arr = matplotlib_figure_to_numpy(fig, dpi=500, transparent=True) plt.close("all") - fig_actor = actor.figure(arr, "cubic") - fig_actor2 = actor.figure(arr, "cubic") + fig_actor = actor.figure(arr, interpolation="cubic") + fig_actor2 = actor.figure(arr, interpolation="cubic") scene = window.Scene() scene.background((1, 1, 1.0)) @@ -1473,7 +1494,7 @@ def test_matplotlib_figure(): ax_actor.SetPosition(-50, 500, -800) fig_actor2.SetPosition(500, 800, -400) display = window.snapshot( - scene, "test_mpl.png", order_transparent=False, offscreen=True + scene, fname="test_mpl.png", order_transparent=False, offscreen=True ) _ = window.analyze_snapshot( display, bg_color=(255, 255, 255.0), colors=[(31, 119, 180)], find_objects=False @@ -1643,7 +1664,13 @@ def test_sdf_actor(interactive=False): scales = [1, 2, 3, 4] primitive = ["sphere", "ellipsoid", "torus", "capsule"] - sdf_actor = actor.sdf(centers, directions, colors, primitive, scales) + sdf_actor = actor.sdf( + centers, + directions=directions, + colors=colors, + primitives=primitive, + scales=scales, + ) scene.add(sdf_actor) scene.add(actor.axes()) if interactive: @@ -1656,7 +1683,13 @@ def test_sdf_actor(interactive=False): # Draw 3 spheres as the primitive type is str scene.clear() primitive = "sphere" - sdf_actor = actor.sdf(centers, directions, colors, primitive, scales) + sdf_actor = actor.sdf( + centers, + directions=directions, + colors=colors, + primitives=primitive, + scales=scales, + ) scene.add(sdf_actor) scene.add(actor.axes()) if interactive: @@ -1671,7 +1704,13 @@ def test_sdf_actor(interactive=False): scene.clear() primitive = ["sphere"] with npt.assert_warns(UserWarning): - sdf_actor = actor.sdf(centers, directions, colors, primitive, scales) + sdf_actor = actor.sdf( + centers, + directions=directions, + colors=colors, + primitives=primitive, + scales=scales, + ) scene.add(sdf_actor) scene.add(actor.axes()) @@ -1687,7 +1726,13 @@ def test_sdf_actor(interactive=False): scene.clear() primitive = ["sphere", "ellipsoid"] with npt.assert_warns(UserWarning): - sdf_actor = actor.sdf(centers, directions, colors, primitive, scales) + sdf_actor = actor.sdf( + centers, + directions=directions, + colors=colors, + primitives=primitive, + scales=scales, + ) scene.add(sdf_actor) scene.add(actor.axes()) @@ -1905,3 +1950,78 @@ def test_actors_primitives_count(): primitives_count = test_case[2] act = act_func(**args) npt.assert_equal(primitives_count_from_actor(act), primitives_count) + + +def test_odf_actor(interactive=False): + # number of odf glyphs does not match with number of centers + centers = np.array([[0, -1, 0]]) + coeffs = np.array([[0.282, 0.152, -0.040, -0.112, -0.045, 0.149], + [0.285, 0.097, -0.115, 0.125, -0.001, 0.003]]) + npt.assert_raises(ValueError, actor.odf, centers, coeffs) + + scene = window.Scene() + centers = np.array([[0, -1, 0], [1, -1, 0], [2, -1, 0]]) + coeffs = np.array([ + [0.2820735, 0.15236554, -0.04038717, -0.11270988, -0.04532376, + 0.14921817, 0.00257928, 0.0040734, -0.05313807, 0.03486542, + 0.04083064, 0.02105767, -0.04389586, -0.04302812, 0.1048641], + [0.28549338, 0.0978267, -0.11544838, 0.12525354, -0.00126003, + 0.00320594, 0.04744155, -0.07141446, 0.03211689, 0.04711322, + 0.08064896, 0.00154299, 0.00086506, 0.00162543, -0.00444893], + [0.28208936, -0.13133252, -0.04701012, -0.06303016, -0.0468775, + 0.02348355, 0.03991898, 0.02587433, 0.02645416, 0.00668765, + 0.00890633, 0.02189304, 0.00387415, 0.01665629, -0.01427194] + ]) + odf_actor = actor.odf(centers=centers, coeffs=coeffs) + scene.add(odf_actor) + + if interactive: + window.show(scene) + + report = window.analyze_scene(scene) + npt.assert_equal(report.actors, 1) + scene.clear() + + # given degree is not even + npt.assert_warns(UserWarning, actor.odf, centers, coeffs, 3) + + centers = np.array([0, 0, 0]) + coeffs = np.array([ + [-0.2739740312099, 0.2526670396328, 1.8922271728516, 0.2878578901291, + -0.5339795947075, -0.2620058953762, 0.1580424904823, 0.0329004973173, + -0.1322413831949, -0.1332057565451, 1.0894461870193, -0.6319401264191, + -0.0416776277125, -1.0772529840469, 0.1423762738705, 0.7941166162491, + 0.7490307092667, -0.3428381681442, 0.1024847552180, -0.0219132602215, + 0.0499043911695, 0.2162453681231, 0.0921059995890, -0.2611238956451, + 0.2549301385880, -0.4534865319729, 0.1922748684883, -0.6200597286224] + ]) + odf_actor = actor.odf(centers=centers, coeffs=coeffs, degree=6) + scene.add(odf_actor) + + if interactive: + window.show(scene) + + report = window.analyze_scene(scene) + npt.assert_equal(report.actors, 1) + scene.clear() + + odf_actor = actor.odf(centers=centers, coeffs=coeffs, degree=4) + scene.add(odf_actor) + + if interactive: + window.show(scene) + + report = window.analyze_scene(scene) + npt.assert_equal(report.actors, 1) + scene.clear() + + odf_actor = actor.odf(centers=centers, coeffs=coeffs, degree=8) + # not enough coefficients for given degree + npt.assert_warns(UserWarning, actor.odf, centers, coeffs, 8) + scene.add(odf_actor) + + if interactive: + window.show(scene) + + npt.assert_equal(report.actors, 1) + scene.clear() diff --git a/fury/tests/test_colormap.py b/fury/tests/test_colormap.py index 14b79a117..653fe271e 100644 --- a/fury/tests/test_colormap.py +++ b/fury/tests/test_colormap.py @@ -71,8 +71,20 @@ def test_line_colors(): def test_create_colormap(): value = np.arange(25) - npt.assert_raises(ValueError, colormap.create_colormap, value.reshape((5, 5))) - npt.assert_raises(AttributeError, colormap.create_colormap, value, name="fake") + npt.assert_raises( + ValueError, + colormap.create_colormap, + value.reshape((5, 5)), + name="plasma", + auto=True, + ) + npt.assert_raises( + AttributeError, + colormap.create_colormap, + value, + name="fake", + auto=True, + ) npt.assert_warns( PendingDeprecationWarning, colormap.create_colormap, @@ -163,14 +175,16 @@ def test_color_converters(): illuminant = "D65" observer = "2" expected_lab = np.array([31.57976662, -1.86550104, -17.84845331]) - lab_color = colormap.rgb2lab(color, illuminant, observer) - rgb_color = colormap.lab2rgb(expected_lab, illuminant, observer) + lab_color = colormap.rgb2lab(color, illuminant=illuminant, observer=observer) + rgb_color = colormap.lab2rgb(expected_lab, illuminant=illuminant, observer=observer) npt.assert_almost_equal(lab_color, expected_lab) npt.assert_almost_equal(rgb_color, color) for color in colors: - lab_color = colormap.rgb2lab(color, illuminant, observer) - rgb_from_lab_color = colormap.lab2rgb(lab_color, illuminant, observer) + lab_color = colormap.rgb2lab(color, illuminant=illuminant, observer=observer) + rgb_from_lab_color = colormap.lab2rgb( + lab_color, illuminant=illuminant, observer=observer + ) npt.assert_almost_equal(rgb_from_lab_color, color) # testing rgb2hsv and hsv2rgb diff --git a/fury/tests/test_decorators.py b/fury/tests/test_decorators.py index 914424484..9437fe121 100644 --- a/fury/tests/test_decorators.py +++ b/fury/tests/test_decorators.py @@ -2,11 +2,13 @@ import numpy.testing as npt -from fury.decorators import doctest_skip_parser +import fury +from fury.decorators import doctest_skip_parser, warn_on_args_to_kwargs from fury.testing import assert_true HAVE_AMODULE = False HAVE_BMODULE = True +FURY_CURRENT_VERSION = fury.__version__ def test_skipper(): @@ -49,3 +51,45 @@ def f(): del HAVE_AMODULE f.__doc__ = docstring npt.assert_raises(NameError, doctest_skip_parser, f) + + +def test_warn_on_args_to_kwargs(): + @warn_on_args_to_kwargs() + def func(a, b, *, c, d=4, e=5): + return a + b + c + d + e + + # if FURY_CURRENT_VERSION is less than from_version + fury.__version__ = "0.1.0" + npt.assert_equal(func(1, 2, 3, 4, 5), 15) + npt.assert_equal(func(1, 2, c=3, d=4, e=5), 15) + npt.assert_raises(TypeError, func, 1, 3) + + # if FURY_CURRENT_VERSION is greater than until_version + fury.__version__ = "50.0.0" + npt.assert_equal(func(1, 2, c=3, d=4, e=5), 15) + npt.assert_equal(func(1, 2, c=3, d=5), 16) + npt.assert_equal(func(1, 2, c=3), 15) + npt.assert_raises(TypeError, func, 1, 3, 4) + npt.assert_raises(TypeError, func, 1, 3) + + # if FURY_CURRENT_VERSION is less than until_version + fury.__version__ = "0.12.0" + npt.assert_equal(func(1, 2, c=3, d=4, e=5), 15) + npt.assert_equal(func(1, 2, c=3, d=5), 16) + with npt.assert_warns(UserWarning): + npt.assert_equal(func(1, 2, 3, 4, 5), 15) + with npt.assert_warns(UserWarning): + npt.assert_equal(func(1, 2, 4), 16) + npt.assert_raises(TypeError, func, 1, 3) + + # if FURY_CURRENT_VERSION is equal to until_version + fury.__version__ = "0.14.0" + with npt.assert_warns(UserWarning): + npt.assert_equal(func(1, 2, 3, 6), 17) + with npt.assert_warns(UserWarning): + npt.assert_equal(func(1, 2, 10), 22) + npt.assert_raises(TypeError, func, 1, 2, e=10) + npt.assert_raises(TypeError, func, 1, 2, d=10) + npt.assert_raises(TypeError, func, 1, 3) + + fury.__version__ = FURY_CURRENT_VERSION diff --git a/fury/tests/test_deprecator.py b/fury/tests/test_deprecator.py index ca1bacad8..88f261eab 100644 --- a/fury/tests/test_deprecator.py +++ b/fury/tests/test_deprecator.py @@ -108,20 +108,20 @@ class CustomError(Exception): dec = deprecate_with_version func = dec("foo")(func_no_doc) - with clear_and_catch_warnings(modules=[my_mod]) as w: + with clear_and_catch_warnings(record=True, modules=[my_mod]) as w: warnings.simplefilter("always") npt.assert_equal(func(), None) npt.assert_equal(len(w), 1) assert_true(w[0].category is DeprecationWarning) npt.assert_equal(func.__doc__, "foo\n") func = dec("foo")(func_doc) - with clear_and_catch_warnings(modules=[my_mod]) as w: + with clear_and_catch_warnings(record=True, modules=[my_mod]) as w: warnings.simplefilter("always") npt.assert_equal(func(1), None) npt.assert_equal(len(w), 1) npt.assert_equal(func.__doc__, "A docstring\n\nfoo\n") func = dec("foo")(func_doc_long) - with clear_and_catch_warnings(modules=[my_mod]) as w: + with clear_and_catch_warnings(record=True, modules=[my_mod]) as w: warnings.simplefilter("always") npt.assert_equal(func(1, 2), None) npt.assert_equal(len(w), 1) @@ -130,12 +130,12 @@ class CustomError(Exception): # Try some since and until versions func = dec("foo", "0.2")(func_no_doc) npt.assert_equal(func.__doc__, "foo\n\n* deprecated from version: 0.2\n") - with clear_and_catch_warnings(modules=[my_mod]) as w: + with clear_and_catch_warnings(record=True, modules=[my_mod]) as w: warnings.simplefilter("always") npt.assert_equal(func(), None) npt.assert_equal(len(w), 1) func = dec("foo", until="10.6")(func_no_doc) - with clear_and_catch_warnings(modules=[my_mod]) as w: + with clear_and_catch_warnings(record=True, modules=[my_mod]) as w: warnings.simplefilter("always") npt.assert_equal(func(), None) npt.assert_equal(len(w), 1) @@ -168,14 +168,14 @@ class CustomError(Exception): # Check different warnings and errors func = dec("foo", warn_class=UserWarning)(func_no_doc) - with clear_and_catch_warnings(modules=[my_mod]) as w: + with clear_and_catch_warnings(record=True, modules=[my_mod]) as w: warnings.simplefilter("always") npt.assert_equal(func(), None) npt.assert_equal(len(w), 1) assert_true(w[0].category is UserWarning) func = dec("foo", error_class=CustomError)(func_no_doc) - with clear_and_catch_warnings(modules=[my_mod]) as w: + with clear_and_catch_warnings(record=True, modules=[my_mod]) as w: warnings.simplefilter("always") npt.assert_equal(func(), None) npt.assert_equal(len(w), 1) diff --git a/fury/tests/test_gltf.py b/fury/tests/test_gltf.py index 8e9febe2f..896a7f8d5 100644 --- a/fury/tests/test_gltf.py +++ b/fury/tests/test_gltf.py @@ -24,8 +24,8 @@ def test_load_gltf(): - fetch_gltf("Duck") - filename = read_viz_gltf("Duck", "glTF") + fetch_gltf(name="Duck") + filename = read_viz_gltf("Duck", mode="glTF") importer = glTF(filename) polydatas = importer.polydatas vertices = utils.get_polydata_vertices(polydatas[0]) @@ -44,8 +44,8 @@ def test_load_gltf(): def test_load_texture(): - fetch_gltf("Duck") - filename = read_viz_gltf("Duck", "glTF") + fetch_gltf(name="Duck") + filename = read_viz_gltf("Duck", mode="glTF") importer = glTF(filename) actor = importer.actors()[0] @@ -62,8 +62,8 @@ def test_load_texture(): @pytest.mark.skipif(True, reason="This test is failing on CI, not sure why yet") def test_colors(): # vertex colors - fetch_gltf("BoxVertexColors") - file = read_viz_gltf("BoxVertexColors", "glTF") + fetch_gltf(name="BoxVertexColors") + file = read_viz_gltf("BoxVertexColors", mode="glTF") importer = glTF(file) actor = importer.actors()[0] scene = window.Scene() @@ -79,8 +79,8 @@ def test_colors(): scene.clear() # material colors - fetch_gltf("BoxAnimated") - file = read_viz_gltf("BoxAnimated", "glTF") + fetch_gltf(name="BoxAnimated") + file = read_viz_gltf("BoxAnimated", mode="glTF") importer = glTF(file) actors = importer.actors() scene.add(*actors) @@ -95,8 +95,8 @@ def test_colors(): def test_orientation(): - fetch_gltf("BoxTextured", "glTF-Embedded") - file = read_viz_gltf("BoxTextured", "glTF-Embedded") + fetch_gltf(name="BoxTextured", mode="glTF-Embedded") + file = read_viz_gltf("BoxTextured", mode="glTF-Embedded") importer = glTF(file) actor = importer.actors()[0] @@ -129,14 +129,14 @@ def test_export_gltf(): cube = actor.cube(np.add(centers, np.array([2, 0, 0])), colors=colors) scene.add(cube) - export_scene(scene, "test.gltf") + export_scene(scene, filename="test.gltf") gltf_obj = glTF("test.gltf") actors = gltf_obj.actors() npt.assert_equal(len(actors), 1) sphere = actor.sphere(centers, np.array([1, 0, 0]), use_primitive=False) scene.add(sphere) - export_scene(scene, "test.gltf") + export_scene(scene, filename="test.gltf") gltf_obj = glTF("test.gltf") actors = gltf_obj.actors() @@ -149,7 +149,7 @@ def test_export_gltf(): focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 1.0), ) - export_scene(scene, "test.gltf") + export_scene(scene, filename="test.gltf") gltf_obj = glTF("test.gltf") actors = gltf_obj.actors() @@ -162,12 +162,12 @@ def test_export_gltf(): scene.reset_camera_tight() scene.clear() - fetch_gltf("BoxTextured", "glTF") + fetch_gltf(name="BoxTextured", mode="glTF") filename = read_viz_gltf("BoxTextured") gltf_obj = glTF(filename) box_actor = gltf_obj.actors() scene.add(*box_actor) - export_scene(scene, "test.gltf") + export_scene(scene, filename="test.gltf") scene.clear() gltf_obj = glTF("test.gltf") @@ -185,14 +185,14 @@ def test_export_gltf(): def test_simple_animation(): - fetch_gltf("BoxAnimated", "glTF") + fetch_gltf(name="BoxAnimated", mode="glTF") file = read_viz_gltf("BoxAnimated") gltf_obj = glTF(file) timeline = Timeline() animation = gltf_obj.main_animation() timeline.add_animation(animation) scene = window.Scene() - showm = window.ShowManager(scene, size=(900, 768)) + showm = window.ShowManager(scene=scene, size=(900, 768)) showm.initialize() scene.add(timeline) @@ -217,11 +217,11 @@ def test_simple_animation(): def test_skinning(): # animation test - fetch_gltf("SimpleSkin", "glTF") + fetch_gltf(name="SimpleSkin", mode="glTF") file = read_viz_gltf("SimpleSkin") gltf_obj = glTF(file) animation = gltf_obj.skin_animation()["anim_0"] - timeline = Timeline(animation) + timeline = Timeline(animations=animation) # checking weights and joints weights = np.array( [ @@ -259,7 +259,7 @@ def test_skinning(): npt.assert_equal(len(ibms), 2) scene = window.Scene() - showm = window.ShowManager(scene, size=(900, 768)) + showm = window.ShowManager(scene=scene, size=(900, 768)) showm.initialize() scene.add(timeline) @@ -321,7 +321,7 @@ def timer_callback(_obj, _event): def test_morphing(): - fetch_gltf("MorphStressTest", "glTF") + fetch_gltf(name="MorphStressTest", mode="glTF") file = read_viz_gltf("MorphStressTest") gltf_obj = glTF(file) animations = gltf_obj.morph_animation() @@ -333,7 +333,7 @@ def test_morphing(): gltf_obj.update_morph(anim_1) scene = window.Scene() - showm = window.ShowManager(scene, size=(900, 768)) + showm = window.ShowManager(scene=scene, size=(900, 768)) showm.initialize() timeline_1 = Timeline() diff --git a/fury/tests/test_interactor.py b/fury/tests/test_interactor.py index 33c6132ce..5608bde62 100644 --- a/fury/tests/test_interactor.py +++ b/fury/tests/test_interactor.py @@ -24,7 +24,10 @@ def test_custom_interactor_style_events(recording=False): # in steps so that the widgets can be added properly interactor_style = interactor.CustomInteractorStyle() show_manager = window.ShowManager( - scene, size=(800, 800), reset_camera=False, interactor_style=interactor_style + scene=scene, + size=(800, 800), + reset_camera=False, + interactor_style=interactor_style, ) # Create a cursor, a circle that will follow the mouse. @@ -56,8 +59,8 @@ def follow_mouse(iren, obj): np.array([[-1, 1, 0.0], [1, 1, 0.0]]), ] colors = np.array([[1.0, 0.0, 0.0], [0.3, 0.7, 0.0]]) - tube1 = actor.streamtube([lines[0]], colors[0]) - tube2 = actor.streamtube([lines[1]], colors[1]) + tube1 = actor.streamtube([lines[0]], colors=colors[0]) + tube2 = actor.streamtube([lines[1]], colors=colors[1]) scene.add(tube1) scene.add(tube2) @@ -157,8 +160,8 @@ def test_double_click_events(recording=False): cube = actor.cube( np.array([(0, 0, 0)]), - np.array([(0.16526678, 0.0186237, 0.01906076)]), - (1, 1, 1), + directions=np.array([(0.16526678, 0.0186237, 0.01906076)]), + colors=(1, 1, 1), scales=3, ) diff --git a/fury/tests/test_io.py b/fury/tests/test_io.py index 277a25e2e..84d0c679e 100644 --- a/fury/tests/test_io.py +++ b/fury/tests/test_io.py @@ -44,8 +44,22 @@ def test_save_and_load_polydata(): npt.assert_array_equal(data, out_data) - npt.assert_raises(IOError, save_polydata, PolyData(), "test.vti") - npt.assert_raises(IOError, save_polydata, PolyData(), "test.obj") + npt.assert_raises( + IOError, + save_polydata, + PolyData(), + "test.vti", + binary=False, + color_array_name=None, + ) + npt.assert_raises( + IOError, + save_polydata, + PolyData(), + "test.obj", + binary=False, + color_array_name=None, + ) npt.assert_raises(IOError, load_polydata, "test.vti") npt.assert_raises(FileNotFoundError, load_polydata, "does-not-exist.obj") @@ -136,21 +150,56 @@ def test_save_load_image(): data[..., 0], out_image[..., 0], decimal=0 ) - npt.assert_raises(IOError, load_image, invalid_link) - npt.assert_raises(IOError, load_image, "test.vtk") - npt.assert_raises(IOError, load_image, "test.vtk", use_pillow=False) npt.assert_raises( - IOError, save_image, np.random.randint(0, 255, size=(50, 3)), "test.vtk" + IOError, + load_image, + invalid_link, + as_vtktype=False, + use_pillow=True, + ) + npt.assert_raises( + IOError, + load_image, + "test.vtk", + as_vtktype=False, + use_pillow=True, + ) + npt.assert_raises( + IOError, + load_image, + "test.vtk", + as_vtktype=False, + use_pillow=False, ) npt.assert_raises( IOError, save_image, np.random.randint(0, 255, size=(50, 3)), "test.vtk", + compression_quality=75, + compression_type="deflation", + use_pillow=True, + dpi=(72, 72), + ) + npt.assert_raises( + IOError, + save_image, + np.random.randint(0, 255, size=(50, 3)), + "test.vtk", + compression_quality=75, + compression_type="deflation", use_pillow=False, + dpi=(72, 72), ) npt.assert_raises( - IOError, save_image, np.random.randint(0, 255, size=(50, 3, 1, 1)), "test.png" + IOError, + save_image, + np.random.randint(0, 255, size=(50, 3, 1, 1)), + "test.png", + compression_quality=75, + compression_type="deflation", + use_pillow=True, + dpi=(72, 72), ) compression_type = [None, "bits", "random"] @@ -221,7 +270,13 @@ def test_load_cubemap_texture(): save_image(data, fname_path) fnames = [fname_path] * 5 - npt.assert_raises(IOError, load_cubemap_texture, fnames) + npt.assert_raises( + IOError, + load_cubemap_texture, + fnames, + interpolate_on=True, + mipmap_on=True, + ) fnames = [fname_path] * 6 texture = load_cubemap_texture(fnames) @@ -234,7 +289,13 @@ def test_load_cubemap_texture(): ) fnames = [fname_path] * 7 - npt.assert_raises(IOError, load_cubemap_texture, fnames) + npt.assert_raises( + IOError, + load_cubemap_texture, + fnames, + interpolate_on=True, + mipmap_on=True, + ) def test_load_sprite_sheet(): diff --git a/fury/tests/test_layout.py b/fury/tests/test_layout.py index e7480b46c..48f3b0ce3 100644 --- a/fury/tests/test_layout.py +++ b/fury/tests/test_layout.py @@ -46,11 +46,17 @@ def get_default_cubes( cube_first_scale, cube_second_scale = scales cube_first = actor.cube( - cube_first_center, cube_first_direction, cube_first_color, cube_first_scale + cube_first_center, + directions=cube_first_direction, + colors=cube_first_color, + scales=cube_first_scale, ) cube_second = actor.cube( - cube_second_center, cube_second_direction, cube_second_color, cube_second_scale + cube_second_center, + directions=cube_second_direction, + colors=cube_second_color, + scales=cube_second_scale, ) return (cube_first, cube_second) @@ -263,7 +269,11 @@ def test_x_layout(): negative_x_layout = XLayout(direction="x-") with npt.assert_raises(ValueError): - _ = XLayout(direction="Invalid direction") + _ = XLayout( + direction="Invalid direction", + cell_padding=0, + cell_shape="rect", + ) positive_positions = positive_x_layout.compute_positions(actors) negative_positions = negative_x_layout.compute_positions(actors) @@ -300,7 +310,11 @@ def test_y_layout(): negative_y_layout = YLayout(direction="y-") with npt.assert_raises(ValueError): - _ = YLayout(direction="Invalid direction") + _ = YLayout( + direction="Invalid direction", + cell_padding=0, + cell_shape="rect", + ) positive_positions = positive_y_layout.compute_positions(actors) negative_positions = negative_y_layout.compute_positions(actors) @@ -338,7 +352,11 @@ def test_z_layout(): diagonal_z_layout = ZLayout(direction="z+", cell_shape="diagonal") with npt.assert_raises(ValueError): - _ = XLayout(direction="Invalid direction") + _ = XLayout( + direction="Invalid direction", + cell_padding=0, + cell_shape="rect", + ) with npt.assert_raises(ValueError): invalid_shape_layout = ZLayout(direction="z+", cell_shape="Invalid Shape") diff --git a/fury/tests/test_molecular.py b/fury/tests/test_molecular.py index f3ab32116..2a1aa5099 100644 --- a/fury/tests/test_molecular.py +++ b/fury/tests/test_molecular.py @@ -10,12 +10,12 @@ def test_periodic_table(): npt.assert_equal(table.atomic_number("C"), 6) npt.assert_equal(table.element_name(7), "Nitrogen") npt.assert_equal(table.atomic_symbol(8), "O") - npt.assert_allclose(table.atomic_radius(1, "VDW"), 1.2, 0.1, 0) - npt.assert_allclose(table.atomic_radius(6, "Covalent"), 0.75, 0.1, 0) + npt.assert_allclose(table.atomic_radius(1, radius_type="VDW"), 1.2, 0.1, 0) + npt.assert_allclose(table.atomic_radius(6, radius_type="Covalent"), 0.75, 0.1, 0) npt.assert_array_almost_equal(table.atom_color(1), np.array([1, 1, 1])) # Test errors - npt.assert_raises(ValueError, table.atomic_radius, 4, "test") + npt.assert_raises(ValueError, table.atomic_radius, 4, radius_type="test") def get_default_molecular_info(all_info=False): @@ -64,17 +64,41 @@ def test_molecule_creation(): # Test errors elements = np.array([6, 6]) - npt.assert_raises(ValueError, mol.Molecule, elements, atom_coords) + npt.assert_raises( + ValueError, + mol.Molecule, + atomic_numbers=elements, + coords=atom_coords, + atom_names=None, + model=None, + residue_seq=None, + chain=None, + sheet=None, + helix=None, + is_hetatm=None, + ) elements = list(range(8)) - npt.assert_raises(ValueError, mol.Molecule, elements, atom_coords) + npt.assert_raises( + ValueError, + mol.Molecule, + atomic_numbers=elements, + coords=atom_coords, + atom_names=None, + model=None, + residue_seq=None, + chain=None, + sheet=None, + helix=None, + is_hetatm=None, + ) def test_add_atom_bond_creation(): molecule = mol.Molecule() mol.add_atom(molecule, 6, 0, 0, 0) mol.add_atom(molecule, 6, 1, 0, 0) - mol.add_bond(molecule, 0, 1, 1) + mol.add_bond(molecule, 0, 1, bond_order=1) npt.assert_equal(molecule.total_num_bonds, 1) npt.assert_equal(molecule.total_num_atoms, 2) @@ -116,7 +140,7 @@ def test_bond_order(): molecule = mol.Molecule() mol.add_atom(molecule, 6, 0, 0, 0) mol.add_atom(molecule, 6, 1, 0, 0) - mol.add_bond(molecule, 0, 1, 3) + mol.add_bond(molecule, 0, 1, bond_order=3) npt.assert_equal(mol.get_bond_order(molecule, 0), 3) # Testing set_bond_order @@ -131,7 +155,7 @@ def test_deep_copy_molecule(): molecule1 = mol.Molecule() mol.add_atom(molecule1, 6, 0, 0, 0) mol.add_atom(molecule1, 6, 1, 0, 0) - mol.add_bond(molecule1, 0, 1, 1) + mol.add_bond(molecule1, 0, 1, bond_order=1) molecule2 = mol.Molecule() mol.deep_copy_molecule(molecule2, molecule1) npt.assert_equal(molecule2.total_num_bonds, 1) @@ -140,14 +164,14 @@ def test_deep_copy_molecule(): def test_compute_bonding(): atomic_numbers, atom_coords = get_default_molecular_info() - molecule = mol.Molecule(atomic_numbers, atom_coords) + molecule = mol.Molecule(atomic_numbers=atomic_numbers, coords=atom_coords) mol.compute_bonding(molecule) npt.assert_equal(molecule.total_num_bonds, 7) def test_sphere_cpk(interactive=False): atomic_numbers, atom_coords = get_default_molecular_info() - molecule = mol.Molecule(atomic_numbers, atom_coords) + molecule = mol.Molecule(atomic_numbers=atomic_numbers, coords=atom_coords) table = mol.PTable() colormodes = ["discrete", "single"] colors = np.array( @@ -159,7 +183,7 @@ def test_sphere_cpk(interactive=False): ) scene = window.Scene() for i, colormode in enumerate(colormodes): - test_actor = mol.sphere_cpk(molecule, colormode) + test_actor = mol.sphere_cpk(molecule, colormode=colormode) scene.add(test_actor) scene.reset_camera() @@ -176,7 +200,7 @@ def test_sphere_cpk(interactive=False): scene.clear() # Testing warnings - npt.assert_warns(UserWarning, mol.sphere_cpk, molecule, "multiple") + npt.assert_warns(UserWarning, mol.sphere_cpk, molecule, colormode="multiple") def test_bstick(interactive=False): @@ -185,9 +209,17 @@ def test_bstick(interactive=False): mol.add_atom(molecule, 6, 2, 0, 0) # Test errors for inadequate bonding data - npt.assert_raises(ValueError, mol.ball_stick, molecule) + npt.assert_raises( + ValueError, + mol.ball_stick, + molecule, + colormode="discrete", + atom_scale_factor=0.3, + bond_thickness=0.1, + multiple_bonds=True, + ) - mol.add_bond(molecule, 0, 1, 1) + mol.add_bond(molecule, 0, 1, bond_order=1) colormodes = ["discrete", "single"] atom_scale_factor = [0.3, 0.4] bond_thickness = [0.1, 0.2] @@ -204,10 +236,10 @@ def test_bstick(interactive=False): for i, colormode in enumerate(colormodes): test_actor = mol.ball_stick( molecule, - colormode, - atom_scale_factor[i], - bond_thickness[i], - multiple_bonds[i], + colormode=colormode, + atom_scale_factor=atom_scale_factor[i], + bond_thickness=bond_thickness[i], + multiple_bonds=multiple_bonds[i], ) scene.add(test_actor) scene.reset_camera() @@ -224,7 +256,15 @@ def test_bstick(interactive=False): scene.clear() # Testing warnings - npt.assert_warns(UserWarning, mol.ball_stick, molecule, "multiple") + npt.assert_warns( + UserWarning, + mol.ball_stick, + molecule, + colormode="multiple", + atom_scale_factor=0.3, + bond_thickness=0.1, + multiple_bonds=True, + ) def test_stick(interactive=False): @@ -233,8 +273,10 @@ def test_stick(interactive=False): mol.add_atom(molecule, 6, 2, 0, 0) # Test errors for inadequate bonding data - npt.assert_raises(ValueError, mol.stick, molecule) - mol.add_bond(molecule, 0, 1, 1) + npt.assert_raises( + ValueError, mol.stick, molecule, colormode="discrete", bond_thickness=0.1 + ) + mol.add_bond(molecule, 0, 1, bond_order=1) colormodes = ["discrete", "single"] bond_thickness = [0.1, 0.12] @@ -248,7 +290,11 @@ def test_stick(interactive=False): ) scene = window.Scene() for i, colormode in enumerate(colormodes): - test_actor = mol.stick(molecule, colormode, bond_thickness[i]) + test_actor = mol.stick( + molecule, + colormode=colormode, + bond_thickness=bond_thickness[i], + ) scene.add(test_actor) scene.reset_camera() scene.reset_clipping_range() @@ -264,7 +310,9 @@ def test_stick(interactive=False): scene.clear() # Testing warnings - npt.assert_warns(UserWarning, mol.stick, molecule, "multiple") + npt.assert_warns( + UserWarning, mol.stick, molecule, colormode="multiple", bond_thickness=0.1 + ) def test_ribbon(interactive=False): @@ -337,18 +385,22 @@ def test_ribbon(interactive=False): helix = secondary_structure sheet = [] molecule = mol.Molecule( - elements, - atom_coords, - atom_names, - model, - residue_seq, - chain, - sheet, - helix, - is_hetatm, + atomic_numbers=elements, + coords=atom_coords, + atom_names=atom_names, + model=model, + residue_seq=residue_seq, + chain=chain, + sheet=sheet, + helix=helix, + is_hetatm=is_hetatm, ) test_actor = mol.ribbon(molecule) - scene.set_camera((28, 113, 74), (34, 106, 70), (-0.37, 0.29, -0.88)) + scene.set_camera( + position=(28, 113, 74), + focal_point=(34, 106, 70), + view_up=(-0.37, 0.29, -0.88), + ) scene.add(test_actor) scene.reset_camera() scene.reset_clipping_range() @@ -367,7 +419,7 @@ def test_bounding_box(interactive=False): molecule = mol.Molecule() mol.add_atom(molecule, 6, 0, 0, 0) mol.add_atom(molecule, 6, 1, 1, 1) - mol.add_bond(molecule, 0, 1, 1) + mol.add_bond(molecule, 0, 1, bond_order=1) molecule_actor = mol.stick(molecule) test_box = mol.bounding_box(molecule, colors=(0, 1, 1), linewidth=0.1) diff --git a/fury/tests/test_primitive.py b/fury/tests/test_primitive.py index baac44a2b..9325eaa34 100644 --- a/fury/tests/test_primitive.py +++ b/fury/tests/test_primitive.py @@ -24,7 +24,7 @@ def test_vertices_primitives(): npt.assert_equal(vertices.min(), e_min) npt.assert_equal(vertices.max(), e_max) - vertices, _ = fp.prim_star(3) + vertices, _ = fp.prim_star(dim=3) npt.assert_equal(vertices.shape, (12, 3)) npt.assert_almost_equal(abs(np.mean(vertices)), 0.11111111) npt.assert_equal(vertices.min(), -3) @@ -108,7 +108,7 @@ def test_spheres_primitives(): ] for name, nb_verts, nb_triangles in l_primitives: - verts, faces = fp.prim_sphere(name) + verts, faces = fp.prim_sphere(name=name) npt.assert_equal(verts.shape, (nb_verts, 3)) npt.assert_almost_equal(np.mean(verts), 0) npt.assert_equal(len(faces), nb_triangles) @@ -116,7 +116,14 @@ def test_spheres_primitives(): list(set(np.concatenate(faces, axis=None))), list(range(len(verts))) ) - npt.assert_raises(ValueError, fp.prim_sphere, "sym362") + npt.assert_raises( + ValueError, + fp.prim_sphere, + name="sym362", + gen_faces=False, + phi=None, + theta=None, + ) l_primitives = [ (10, 10, 82, 160), @@ -138,7 +145,7 @@ def test_spheres_primitives(): def test_superquadric_primitives(): # test default, should be like a sphere 362 sq_verts, sq_faces = fp.prim_superquadric() - s_verts, s_faces = fp.prim_sphere("symmetric362") + s_verts, s_faces = fp.prim_sphere(name="symmetric362") npt.assert_equal(sq_verts.shape, s_verts.shape) npt.assert_equal(sq_faces.shape, s_faces.shape) @@ -211,7 +218,7 @@ def test_cone_primitive(): ) # test warnings - npt.assert_raises(ValueError, fp.prim_cone, 0.5, 1, 2) + npt.assert_raises(ValueError, fp.prim_cone, radius=0.5, height=1, sectors=2) def test_repeat_primitive(): @@ -223,9 +230,7 @@ def test_repeat_primitive(): for i in [-1, 1]: dirs = dirs * i - res = fp.repeat_primitive( - vertices=verts, faces=faces, centers=centers, directions=dirs, colors=colors - ) + res = fp.repeat_primitive(verts, faces, centers, directions=dirs, colors=colors) big_verts, big_faces, big_colors, big_centers = res @@ -263,8 +268,8 @@ def test_repeat_primitive_function(): phi_theta = np.array([[1, 1], [1, 2], [2, 1]]) _ = fp.repeat_primitive_function( - func=fp.prim_superquadric, - centers=centers, + fp.prim_superquadric, + centers, func_args=phi_theta, directions=dirs, colors=colors, diff --git a/fury/tests/test_stream.py b/fury/tests/test_stream.py index 5db6a05da..68e198d0a 100644 --- a/fury/tests/test_stream.py +++ b/fury/tests/test_stream.py @@ -56,7 +56,7 @@ def test(use_raw_array, ms_stream=16): scene = window.Scene() scene.add(actors) showm = window.ShowManager( - scene, + scene=scene, reset_camera=False, size=(width_0, height_0), order_transparent=False, @@ -78,7 +78,7 @@ def test(use_raw_array, ms_stream=16): rtc_server = RTCServer(img_buffer_manager) showm.render() - stream.start(ms_stream) + stream.start(ms=ms_stream) showm.render() loop.run_until_complete(rtc_server.recv()) # sassert frame.width == width_0 and frame.height == height_0 @@ -108,7 +108,7 @@ def test_pillow(): scene = window.Scene() scene.add(actors) showm = window.ShowManager( - scene, + scene=scene, reset_camera=False, size=(width_0, height_0), order_transparent=False, @@ -129,7 +129,7 @@ def test_pillow(): ) showm.render() - stream.start(ms_stream) + stream.start(ms=ms_stream) showm.render() # test jpeg method img_buffer_manager.get_jpeg() @@ -165,7 +165,7 @@ def test_rtc_video_stream_whitout_cython(loop: asyncio.AbstractEventLoop): scene = window.Scene() scene.add(actors) showm = window.ShowManager( - scene, + scene=scene, reset_camera=False, size=(width_0, height_0), order_transparent=False, @@ -187,7 +187,7 @@ def test_rtc_video_stream_whitout_cython(loop: asyncio.AbstractEventLoop): rtc_server = RTCServer(img_buffer_manager) showm.render() - stream.start(ms_stream) + stream.start(ms=ms_stream) showm.render() loop.run_until_complete(rtc_server.recv()) # assert frame.width == showm.size[0] and frame.height == showm.size[1] @@ -212,7 +212,7 @@ def test(use_raw_array, ms_stream=16): scene = window.Scene() scene.add(actors) showm = window.ShowManager( - scene, + scene=scene, reset_camera=False, size=(width_0, height_0), order_transparent=False, @@ -233,7 +233,7 @@ def test(use_raw_array, ms_stream=16): ) showm.render() - stream.start(ms_stream) + stream.start(ms=ms_stream) showm.render() # test jpeg method img_buffer_manager.get_jpeg() @@ -275,7 +275,7 @@ def test(use_raw_array, ms_stream=16, whithout_iren_start=False): scene = window.Scene() scene.add(actors) showm = window.ShowManager( - scene, + scene=scene, reset_camera=False, size=(width_0, height_0), order_transparent=False, @@ -286,10 +286,10 @@ def test(use_raw_array, ms_stream=16, whithout_iren_start=False): ) showm.render() - stream.start(ms_stream) + stream.start(ms=ms_stream) npt.assert_equal(stream._started, True) # test if stop method has been called - stream.start(ms_stream) + stream.start(ms=ms_stream) npt.assert_equal(stream._started, True) showm.render() stream.stop() @@ -314,7 +314,7 @@ def test_stream_client_resize(): scene = window.Scene() scene.add(actors) showm = window.ShowManager( - scene, + scene=scene, reset_camera=False, size=(width_0, height_0), order_transparent=False, @@ -360,7 +360,7 @@ async def test(use_raw_array, ms_stream=16): scene = window.Scene() scene.add(actors) showm = window.ShowManager( - scene, + scene=scene, reset_camera=False, size=(width_0, height_0), order_transparent=False, @@ -423,7 +423,7 @@ async def test(use_raw_array, ms_stream=16): ) ) - stream_interaction.start(ms_stream, use_asyncio=True) + stream_interaction.start(ms=ms_stream, use_asyncio=True) while stream_interaction.circular_queue.head != -1: showm.render() await asyncio.sleep(0.01) @@ -448,7 +448,7 @@ def test(use_raw_array, ms_stream, whitouth_iren_start): scene = window.Scene() scene.add(actors) - showm = window.ShowManager(scene, size=(width_0, height_0)) + showm = window.ShowManager(scene=scene, size=(width_0, height_0)) stream = FuryStreamClient( showm, use_raw_array=use_raw_array, whithout_iren_start=whitouth_iren_start @@ -464,11 +464,11 @@ def test(use_raw_array, ms_stream, whitouth_iren_start): # ms should always be greater than 0 with npt.assert_raises(ValueError): - stream_interaction.start(-1) + stream_interaction.start(ms=-1) - stream_interaction.start(ms_stream) + stream_interaction.start(ms=ms_stream) # test double start - stream_interaction.start(ms_stream) + stream_interaction.start(ms=ms_stream) while stream_interaction.circular_queue.head != -1: showm.render() time.sleep(0.01) @@ -563,14 +563,14 @@ def test_comm(use_raw_array=True): max_size=max_size, dimension=dimension ) m_buffer_0 = tools.RawArrayMultiDimensionalBuffer( - max_size, dimension, buffer=m_buffer_org.buffer + max_size, dimension=dimension, buffer=m_buffer_org.buffer ) else: m_buffer_org = tools.SharedMemMultiDimensionalBuffer( max_size=max_size, dimension=dimension ) m_buffer_0 = tools.SharedMemMultiDimensionalBuffer( - max_size, dimension, buffer_name=m_buffer_org.buffer_name + max_size, dimension=dimension, buffer_name=m_buffer_org.buffer_name ) m_buffer_0[1] = np.array([0.2, 0.3, 0.4, 0.5]) @@ -734,7 +734,7 @@ def test(use_raw_array): scene = window.Scene() scene.add(actors) showm = window.ShowManager( - scene, + scene=scene, reset_camera=False, size=(width_0, height_0), order_transparent=False, @@ -744,27 +744,27 @@ def test(use_raw_array): if use_raw_array: web_server_raw_array( - stream.img_manager.image_buffers, - stream.img_manager.info_buffer, - stream_interaction.circular_queue.head_tail_buffer, - stream_interaction.circular_queue.buffer._buffer, - 8000, - "localhost", - True, - True, + image_buffers=stream.img_manager.image_buffers, + info_buffer=stream.img_manager.info_buffer, + queue_head_tail_buffer=stream_interaction.circular_queue.head_tail_buffer, # noqa E501 + queue_buffer=stream_interaction.circular_queue.buffer._buffer, + port=8000, + host="localhost", + provides_mjpeg=True, + provides_webrtc=True, run_app=False, ) else: web_server( - stream.img_manager.image_buffer_names, - stream.img_manager.info_buffer_name, - stream_interaction.circular_queue.head_tail_buffer_name, - stream_interaction.circular_queue.buffer.buffer_name, - 8000, - "localhost", - True, - True, - True, + image_buffer_names=stream.img_manager.image_buffer_names, + info_buffer_name=stream.img_manager.info_buffer_name, + queue_head_tail_buffer_name=stream_interaction.circular_queue.head_tail_buffer_name, # noqa E501 + queue_buffer_name=stream_interaction.circular_queue.buffer.buffer_name, + port=8000, + host="localhost", + provides_mjpeg=True, + provides_webrtc=True, + avoid_unlink_shared_mem=True, run_app=False, ) @@ -790,7 +790,7 @@ def test_widget(): scene = window.Scene() scene.add(actors) showm = window.ShowManager( - scene, + scene=scene, reset_camera=False, size=(width_0, height_0), order_transparent=False, diff --git a/fury/tests/test_testing.py b/fury/tests/test_testing.py index 39aae8bf7..416531353 100644 --- a/fury/tests/test_testing.py +++ b/fury/tests/test_testing.py @@ -1,5 +1,6 @@ """Testing file unittest.""" +import operator import sys import warnings @@ -48,7 +49,9 @@ def _add_to_scene(self, _scene): simple_ui = SimplestUI() current_size = (900, 600) scene = window.Scene() - show_manager = window.ShowManager(scene, size=current_size, title="FURY GridUI") + show_manager = window.ShowManager( + scene=scene, size=current_size, title="FURY GridUI" + ) scene.add(simple_ui) event_counter = ft.EventCounter() event_counter.monitor(simple_ui) @@ -69,14 +72,26 @@ def foo(): def test_assert(): - npt.assert_raises(AssertionError, ft.assert_false, True) - npt.assert_raises(AssertionError, ft.assert_true, False) - npt.assert_raises(AssertionError, ft.assert_less, 2, 1) - npt.assert_raises(AssertionError, ft.assert_less_equal, 2, 1) - npt.assert_raises(AssertionError, ft.assert_greater, 1, 2) - npt.assert_raises(AssertionError, ft.assert_greater_equal, 1, 2) - npt.assert_raises(AssertionError, ft.assert_not_equal, 5, 5) - npt.assert_raises(AssertionError, ft.assert_operator, 2, 1) + npt.assert_raises( + AssertionError, ft.assert_false, True, msg="True is not false", op=operator.eq + ) + npt.assert_raises( + AssertionError, ft.assert_true, False, msg="False is not true", op=operator.eq + ) + npt.assert_raises( + AssertionError, ft.assert_less, 2, 1, msg="{0} < {1}", op=operator.lt + ) + npt.assert_raises( + AssertionError, ft.assert_less_equal, 2, 1, msg="{0} =< {1}", op=operator.le + ) + npt.assert_raises( + AssertionError, ft.assert_greater, 1, 2, msg="{0} > {1}", op=operator.gt + ) + npt.assert_raises( + AssertionError, ft.assert_greater_equal, 1, 2, msg="{0} >= {1}", op=operator.ge + ) + npt.assert_raises(AssertionError, ft.assert_not_equal, 5, 5, msg="", op=operator.ne) + npt.assert_raises(AssertionError, ft.assert_operator, 2, 1, msg="", op=operator.eq) arr = [np.arange(k) for k in range(2, 12, 3)] arr2 = [np.arange(k) for k in range(2, 12, 4)] diff --git a/fury/tests/test_thread.py b/fury/tests/test_thread.py index 35e2ac041..8c26e30d4 100644 --- a/fury/tests/test_thread.py +++ b/fury/tests/test_thread.py @@ -20,7 +20,7 @@ def test_multithreading(): # Preparing the show manager as usual showm = window.ShowManager( - scene, size=(900, 768), reset_camera=False, order_transparent=True + scene=scene, size=(900, 768), reset_camera=False, order_transparent=True ) # showm.initialize() diff --git a/fury/tests/test_transform.py b/fury/tests/test_transform.py index 8c463592e..dfb260024 100644 --- a/fury/tests/test_transform.py +++ b/fury/tests/test_transform.py @@ -66,17 +66,17 @@ def test_sphere_cart(): def test_euler_matrix(): - rotation = euler_matrix(1, 2, 3, "syxz") + rotation = euler_matrix(1, 2, 3, axes="syxz") npt.assert_equal(np.allclose(np.sum(rotation[0]), -1.34786452), True) - rotation = euler_matrix(1, 2, 3, (0, 1, 0, 1)) + rotation = euler_matrix(1, 2, 3, axes=(0, 1, 0, 1)) npt.assert_equal(np.allclose(np.sum(rotation[0]), -0.383436184), True) ai, aj, ak = (4.0 * np.pi) * (np.random.random(3) - 0.5) for axes in _AXES2TUPLE.keys(): - _ = euler_matrix(ai, aj, ak, axes) + _ = euler_matrix(ai, aj, ak, axes=axes) for axes in _TUPLE2AXES.keys(): - _ = euler_matrix(ai, aj, ak, axes) + _ = euler_matrix(ai, aj, ak, axes=axes) def test_translate(): diff --git a/fury/tests/test_utils.py b/fury/tests/test_utils.py index 7fdc3230e..f1758fa95 100644 --- a/fury/tests/test_utils.py +++ b/fury/tests/test_utils.py @@ -54,6 +54,7 @@ update_surface_actor_colors, vertices_from_actor, vtk_matrix_to_numpy, + minmax_norm, ) dipy, have_dipy, _ = optional_package("dipy") @@ -135,7 +136,7 @@ def test_polydata_lines(): line_2 = line_1 + np.array([0.5, 0.0, 0.0]) lines = [line_1, line_2] - pd_lines, is_cmap = utils.lines_to_vtk_polydata(lines, colors) + pd_lines, is_cmap = utils.lines_to_vtk_polydata(lines, colors=colors) res_lines = utils.get_polydata_lines(pd_lines) npt.assert_array_equal(lines, res_lines) npt.assert_equal(is_cmap, False) @@ -440,7 +441,14 @@ def test_numpy_to_vtk_image_data(): numpy_img_array = numpy_support.vtk_to_numpy(vtk_img_array) npt.assert_equal(np.flipud(array), numpy_img_array.reshape(h, w, elements)) - npt.assert_raises(IOError, utils.numpy_to_vtk_image_data, np.array([1, 2, 3])) + npt.assert_raises( + IOError, + utils.numpy_to_vtk_image_data, + np.array([1, 2, 3]), + spacing=(1, 1, 1), + origin=(0, 0, 0), + deep=True, + ) def test_get_grid_cell_position(): @@ -475,7 +483,7 @@ def test_rotate(interactive=False): rot = (90, 1, 0, 0) - rotate(act2, rot) + rotate(act2, rotation=rot) act3 = utils.shallow_copy(act) @@ -483,7 +491,7 @@ def test_rotate(interactive=False): rot = (90, 0, 1, 0) - rotate(act3, rot) + rotate(act3, rotation=rot) scene.add(act3) @@ -554,7 +562,7 @@ def test_vertices_from_actor(interactive=False): big_verts = res[0] big_faces = res[1] big_colors = res[2] - actr = get_actor_from_primitive(big_verts, big_faces, big_colors) + actr = get_actor_from_primitive(big_verts, big_faces, colors=big_colors) actr.GetProperty().BackfaceCullingOff() if interactive: scene = window.Scene() @@ -643,7 +651,14 @@ def test_get_actor_from_primitive(): vertices, triangles = fp.prim_frustum() colors = np.array([1, 0, 0]) npt.assert_raises( - ValueError, get_actor_from_primitive, vertices, triangles, colors=colors + ValueError, + get_actor_from_primitive, + vertices, + triangles, + colors=colors, + normals=None, + backface_culling=True, + prim_count=1, ) @@ -824,7 +839,7 @@ def test_color_check(): points = np.array([[0, 0, 0], [0, 1, 0], [1, 0, 0]]) colors = np.array([[1, 0, 0, 0.5], [0, 1, 0, 0.5], [0, 0, 1, 0.5]]) - color_tuple = color_check(len(points), colors) + color_tuple = color_check(len(points), colors=colors) color_array, global_opacity = color_tuple npt.assert_equal(color_array, np.floor(colors * 255)) @@ -833,7 +848,7 @@ def test_color_check(): points = np.array([[0, 0, 0], [0, 1, 0], [1, 0, 0]]) colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) - color_tuple = color_check(len(points), colors) + color_tuple = color_check(len(points), colors=colors) color_array, global_opacity = color_tuple npt.assert_equal(color_array, np.floor(colors * 255)) @@ -842,7 +857,7 @@ def test_color_check(): points = np.array([[0, 0, 0], [0, 1, 0], [1, 0, 0]]) colors = (1, 1, 1, 0.5) - color_tuple = color_check(len(points), colors) + color_tuple = color_check(len(points), colors=colors) color_array, global_opacity = color_tuple npt.assert_equal(color_array, np.floor(np.array([colors] * 3) * 255)) @@ -851,7 +866,7 @@ def test_color_check(): points = np.array([[0, 0, 0], [0, 1, 0], [1, 0, 0]]) colors = (1, 0, 0) - color_tuple = color_check(len(points), colors) + color_tuple = color_check(len(points), colors=colors) color_array, global_opacity = color_tuple npt.assert_equal(color_array, np.floor(np.array([colors] * 3) * 255)) @@ -878,12 +893,17 @@ def test_is_ui(): def test_empty_list_to_polydata(): lines = [[]] - npt.assert_raises(ValueError, utils.lines_to_vtk_polydata, lines) + npt.assert_raises( + ValueError, + utils.lines_to_vtk_polydata, + lines, + colors=None, + ) def test_empty_array_to_polydata(): lines = np.array([[]]) - npt.assert_raises(ValueError, utils.lines_to_vtk_polydata, lines) + npt.assert_raises(ValueError, utils.lines_to_vtk_polydata, lines, colors=None) @pytest.mark.skipif(not have_dipy, reason="Requires DIPY") @@ -891,7 +911,7 @@ def test_empty_array_sequence_to_polydata(): from dipy.tracking.streamline import Streamlines lines = Streamlines() - npt.assert_raises(ValueError, utils.lines_to_vtk_polydata, lines) + npt.assert_raises(ValueError, utils.lines_to_vtk_polydata, lines, colors=None) def test_set_polydata_primitives_count(): @@ -944,10 +964,38 @@ def test_set_actor_origin(): cube = actor.cube(np.array([[0, 0, 0]])) orig_vert = np.copy(vertices_from_actor(cube)) - utils.set_actor_origin(cube, np.array([0.5, 0.5, 0.5])) + utils.set_actor_origin(cube, center=np.array([0.5, 0.5, 0.5])) new_vert = np.copy(vertices_from_actor(cube)) npt.assert_array_equal(orig_vert, new_vert + np.array([0.5, 0.5, 0.5])) utils.set_actor_origin(cube) centered_cube_vertices = np.copy(vertices_from_actor(cube)) npt.assert_array_equal(orig_vert, centered_cube_vertices) + + +def test_minmax_normalization(): + data1d = np.array([2, -2, 5, -1, 8]) + actual_data1d = minmax_norm(data1d) + expected_data1d = np.array([[0.4, 0. , 0.7, 0.1, 1. ]]) + npt.assert_array_almost_equal(actual_data1d, expected_data1d, decimal=1) + + data3d = np.array([[[2, 7, 7, 9], [2, -1, -3, 5]], + [[-4, 5, 6, 0], [1, 1, -9, 3]]]) + npt.assert_raises(ValueError, utils.minmax_norm, data3d) + + data = np.array([[1, 2, -1, 3], [4, -1, 3, 5], [-1, 9, 8, 0]]) + actual = minmax_norm(data, axis=0) + expected = np.array([[0.4, 0.3, 0, 0.6], [1, 0, 0.444, 1], [0, 1, 1, 0]]) + npt.assert_array_almost_equal(actual, expected, decimal=3) + actual = minmax_norm(data, axis=1) + expected = np.array([[0.5, 0.75, 0, 1], [0.833, 0, 0.666, 1], + [0, 1, 0.9, 0.1]]) + npt.assert_array_almost_equal(actual, expected, decimal=3) + + data2 = np.array([1, 3, 9, 6]) + actual2 = minmax_norm(data2, axis=0) + expected2 = np.array([[1, 3, 9, 6]]) + npt.assert_array_equal(actual2, expected2) + actual2 = minmax_norm(data2, axis=1) + expected2 = np.array([[0, 0.25, 1, 0.625]]) + npt.assert_array_almost_equal(actual2, expected2, decimal=3) diff --git a/fury/tests/test_window.py b/fury/tests/test_window.py index 87115298e..608da3852 100644 --- a/fury/tests/test_window.py +++ b/fury/tests/test_window.py @@ -36,26 +36,26 @@ def test_scene(): axes = actor.axes() scene.add(axes) arr = window.snapshot(scene) - report = window.analyze_snapshot(arr, bg_color) + report = window.analyze_snapshot(arr, bg_color=bg_color) npt.assert_equal(report.objects, 1) # Test remove actor function by analyzing a snapshot scene.rm(axes) arr = window.snapshot(scene) - report = window.analyze_snapshot(arr, bg_color) + report = window.analyze_snapshot(arr, bg_color=bg_color) npt.assert_equal(report.objects, 0) # Add actor to scene to test the remove all actors function by analyzing a # snapshot scene.add(axes) arr = window.snapshot(scene) - report = window.analyze_snapshot(arr, bg_color) + report = window.analyze_snapshot(arr, bg_color=bg_color) npt.assert_equal(report.objects, 1) # Test remove all actors function by analyzing a snapshot scene.rm_all() arr = window.snapshot(scene) - report = window.analyze_snapshot(arr, bg_color) + report = window.analyze_snapshot(arr, bg_color=bg_color) npt.assert_equal(report.objects, 0) # Test change background color from scene by analyzing the scene - ren2 = window.Scene(bg_float) + ren2 = window.Scene(background=bg_float) ren2.background((0, 0, 0.0)) report = window.analyze_scene(ren2) npt.assert_equal(report.bg_color, (0, 0, 0)) @@ -130,7 +130,9 @@ def test_active_camera(): direction = scene.camera_direction() position, focal_point, view_up = scene.get_camera() - scene.set_camera((0.0, 0.0, 1.0), (0.0, 0.0, 0), view_up) + scene.set_camera( + position=(0.0, 0.0, 1.0), focal_point=(0.0, 0.0, 0), view_up=view_up + ) position, focal_point, view_up = scene.get_camera() npt.assert_almost_equal(np.dot(direction, position), -1) @@ -168,7 +170,9 @@ def test_active_camera(): report = window.analyze_snapshot(arr, colors=(0, 255, 0)) npt.assert_equal(report.colors_found, [True]) - scene.set_camera((0.0, 0.0, 1.0), (0.0, 0.0, 0), view_up) + scene.set_camera( + position=(0.0, 0.0, 1.0), focal_point=(0.0, 0.0, 0), view_up=view_up + ) # vertical rotation of the camera around the focal point scene.pitch(10) @@ -203,14 +207,14 @@ def test_parallel_projection(): # Put the camera on a angle so that the # camera can show the difference between perspective # and parallel projection - scene.set_camera((1.5, 1.5, 1.5)) + scene.set_camera(position=(1.5, 1.5, 1.5)) scene.GetActiveCamera().Zoom(2) # window.show(scene, reset_camera=True) scene.reset_camera() arr = window.snapshot(scene) - scene.projection("parallel") + scene.projection(proj_type="parallel") # window.show(scene, reset_camera=False) arr2 = window.snapshot(scene) # Because of the parallel projection the two axes @@ -218,7 +222,7 @@ def test_parallel_projection(): # pixels rather than in perspective projection were # the axes being further will be smaller. npt.assert_equal(np.sum(arr2 > 0) > np.sum(arr > 0), True) - scene.projection("perspective") + scene.projection(proj_type="perspective") arr2 = window.snapshot(scene) npt.assert_equal(np.sum(arr2 > 0), np.sum(arr > 0)) @@ -322,7 +326,7 @@ def test_save_screenshot(): scene.add(sphere_actor) window_sz = (400, 400) - show_m = window.ShowManager(scene, size=window_sz) + show_m = window.ShowManager(scene=scene, size=window_sz) with InTemporaryDirectory(): fname = "test.png" @@ -359,7 +363,7 @@ def test_stereo(): np.array([[-1, 1, 0.0], [1, 1, 0.0]]), ] colors = np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) - stream_actor = actor.streamtube(lines, colors, linewidth=0.3, opacity=0.5) + stream_actor = actor.streamtube(lines, colors=colors, linewidth=0.3, opacity=0.5) scene.add(stream_actor) @@ -398,7 +402,7 @@ def test_frame_rate(): scene.add(sphere_actor) showm = window.ShowManager( - scene, size=(900, 768), reset_camera=False, order_transparent=True + scene=scene, size=(900, 768), reset_camera=False, order_transparent=True ) counter = itertools.count() @@ -540,7 +544,7 @@ def test_opengl_state_simple(): scales=0.2, ) showm = window.ShowManager( - scene, size=(900, 768), reset_camera=False, order_transparent=False + scene=scene, size=(900, 768), reset_camera=False, order_transparent=False ) scene.add(actors) @@ -566,7 +570,7 @@ def test_opengl_state_add_remove_and_check(): scales=0.2, ) showm = window.ShowManager( - scene, size=(900, 768), reset_camera=False, order_transparent=False + scene=scene, size=(900, 768), reset_camera=False, order_transparent=False ) scene.add(actor_no_depth_test) @@ -608,7 +612,7 @@ def test_add_animation_to_show_manager(): cube = actor.cube(np.array([[2, 2, 3]])) timeline = Timeline(playback_panel=True) - animation = Animation(cube) + animation = Animation(actors=cube) timeline.add_animation(animation) showm.add_animation(timeline) diff --git a/fury/texture/tests/__init__.py b/fury/texture/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/fury/texture/tests/test_utils.py b/fury/texture/tests/test_utils.py new file mode 100644 index 000000000..71f108596 --- /dev/null +++ b/fury/texture/tests/test_utils.py @@ -0,0 +1,41 @@ +import numpy as np +import numpy.testing as npt +from fury.texture.utils import uv_calculations + +def test_uv_calculations(): + uv_coords = uv_calculations(1) + expected_uv1 = np.array([ + [0.001, 0.001], [0.001, 0.999], [0.999, 0.999], [0.999, 0.001], + [0.001, 0.001], [0.001, 0.999], [0.999, 0.999], [0.999, 0.001] + ]) + npt.assert_array_almost_equal(uv_coords, expected_uv1, decimal=3) + + uv_coords = uv_calculations(3) + expected_uv3 = np.array([ + [0.001, 0.667], [0.001, 0.999], [0.999, 0.999], [0.999, 0.667], + [0.001, 0.667], [0.001, 0.999], [0.999, 0.999], [0.999, 0.667], + [0.001, 0.334], [0.001, 0.665], [0.999, 0.665], [0.999, 0.334], + [0.001, 0.334], [0.001, 0.665], [0.999, 0.665], [0.999, 0.334], + [0.001, 0.001], [0.001, 0.332], [0.999, 0.332], [0.999, 0.001], + [0.001, 0.001], [0.001, 0.332], [0.999, 0.332], [0.999, 0.001] + ]) + npt.assert_array_almost_equal(uv_coords, expected_uv3, decimal=3) + + uv_coords = uv_calculations(7) + expected_uv7 = np.array([ + [0.001, 0.858], [0.001, 0.999], [0.999, 0.999], [0.999, 0.858], + [0.001, 0.858], [0.001, 0.999], [0.999, 0.999], [0.999, 0.858], + [0.001, 0.715], [0.001, 0.856], [0.999, 0.856], [0.999, 0.715], + [0.001, 0.715], [0.001, 0.856], [0.999, 0.856], [0.999, 0.715], + [0.001, 0.572], [0.001, 0.713], [0.999, 0.713], [0.999, 0.572], + [0.001, 0.572], [0.001, 0.713], [0.999, 0.713], [0.999, 0.572], + [0.001, 0.429], [0.001, 0.570], [0.999, 0.570], [0.999, 0.429], + [0.001, 0.429], [0.001, 0.570], [0.999, 0.570], [0.999, 0.429], + [0.001, 0.286], [0.001, 0.427], [0.999, 0.427], [0.999, 0.286], + [0.001, 0.286], [0.001, 0.427], [0.999, 0.427], [0.999, 0.286], + [0.001, 0.143], [0.001, 0.284], [0.999, 0.284], [0.999, 0.143], + [0.001, 0.143], [0.001, 0.284], [0.999, 0.284], [0.999, 0.143], + [0.001, 0.001], [0.001, 0.141], [0.999, 0.141], [0.999, 0.001], + [0.001, 0.001], [0.001, 0.141], [0.999, 0.141], [0.999, 0.001] + ]) + npt.assert_array_almost_equal(uv_coords, expected_uv7, decimal=3) diff --git a/fury/texture/utils.py b/fury/texture/utils.py new file mode 100644 index 000000000..25da3a714 --- /dev/null +++ b/fury/texture/utils.py @@ -0,0 +1,31 @@ +def uv_calculations(n): + """Return UV coordinates based on the number of elements. + + Parameters + ---------- + n : int + number of elements. + + Returns + ------- + uvs : ndrray + UV coordinates for each element. + + """ + uvs = [] + for i in range(0, n): + a = (n - (i + 1)) / n + b = (n - i) / n + uvs.extend( + [ + [0.001, a + 0.001], + [0.001, b - 0.001], + [0.999, b - 0.001], + [0.999, a + 0.001], + [0.001, a + 0.001], + [0.001, b - 0.001], + [0.999, b - 0.001], + [0.999, a + 0.001], + ] + ) + return uvs diff --git a/fury/transform.py b/fury/transform.py index ac9c1aba8..d8818493c 100644 --- a/fury/transform.py +++ b/fury/transform.py @@ -3,6 +3,8 @@ import numpy as np from scipy.spatial.transform import Rotation as Rot # type: ignore +from fury.decorators import warn_on_args_to_kwargs + # axis sequences for Euler angles _NEXT_AXIS = [1, 2, 0, 1] @@ -37,7 +39,8 @@ _TUPLE2AXES = {v: k for k, v in _AXES2TUPLE.items()} -def euler_matrix(ai, aj, ak, axes="sxyz"): +@warn_on_args_to_kwargs() +def euler_matrix(ai, aj, ak, *, axes="sxyz"): """Return homogeneous rotation matrix from Euler angles and axis sequence. Code modified from the work of Christoph Gohlke link provided here @@ -239,20 +242,23 @@ def translate(translation): Examples -------- - >>> import numpy as np + >>> import numpy as np; import fury >>> tran = np.array([0.3, 0.2, 0.25]) - >>> transform = translate(tran) + >>> transform = fury.transform.translate(tran) >>> transform - >>> [[1. 0. 0. 0.3 ] - [0. 1. 0. 0.2 ] - [0. 0. 1. 0.25] - [0. 0. 0. 1. ]] + array([[1. , 0. , 0. , 0.3 ], + [0. , 1. , 0. , 0.2 ], + [0. , 0. , 1. , 0.25], + [0. , 0. , 0. , 1. ]]) """ iden = np.identity(4) translation = np.append(translation, 0).reshape(-1, 1) - t = np.array([[0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1]], np.float32) + t = np.array( + [[0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1]], + np.float32, + ) translation = np.multiply(t, translation) translation = np.add(iden, translation) @@ -274,14 +280,14 @@ def rotate(quat): Examples -------- - >>> import numpy as np + >>> import numpy as np; import fury >>> quat = np.array([0.259, 0.0, 0.0, 0.966]) - >>> rotation = rotate(quat) + >>> rotation = fury.transform.rotate(quat) >>> rotation - >>> [[1. 0. 0. 0.] - [0. 0.866 -0.5 0.] - [0. 0.5 0.866 0.] - [0. 0. 0. 1.]] + array([[ 1. , 0. , 0. , 0. ], + [ 0. , 0.86586979, -0.50026944, 0. ], + [ 0. , 0.50026944, 0.86586979, 0. ], + [ 0. , 0. , 0. , 1. ]]) """ iden = np.identity(3) @@ -312,14 +318,14 @@ def scale(scales): Examples -------- - >>> import numpy as np + >>> import numpy as np; import fury >>> scales = np.array([2.0, 1.0, 0.5]) - >>> transform = scale(scales) + >>> transform = fury.transform.scale(scales) >>> transform - >>> [[2. 0. 0. 0.] - [0. 1. 0. 0.] - [0. 0. 0.5 0.] - [0. 0. 0. 1.]] + array([[2. , 0. , 0. , 0. ], + [0. , 1. , 0. , 0. ], + [0. , 0. , 0.5, 0. ], + [0. , 0. , 0. , 1. ]]) """ scale_mat = np.identity(4) diff --git a/fury/ui/__init__.py b/fury/ui/__init__.py index f6fdc9bd3..62d86f776 100644 --- a/fury/ui/__init__.py +++ b/fury/ui/__init__.py @@ -1,50 +1,3 @@ -from fury.ui.containers import GridUI, ImageContainer2D, Panel2D, TabPanel2D, TabUI -from fury.ui.core import Button2D, Disk2D, Rectangle2D, TextBlock2D -from fury.ui.elements import ( - Card2D, - Checkbox, - ComboBox2D, - DrawPanel, - DrawShape, - FileMenu2D, - LineDoubleSlider2D, - LineSlider2D, - ListBox2D, - ListBoxItem2D, - Option, - PlaybackPanel, - RadioButton, - RangeSlider, - RingSlider2D, - SpinBox, - TextBox2D, -) +import lazy_loader as lazy -__all__ = [ - "Panel2D", - "TabPanel2D", - "TabUI", - "ImageContainer2D", - "GridUI", - "Rectangle2D", - "Disk2D", - "TextBlock2D", - "Button2D", - "TextBox2D", - "LineSlider2D", - "LineDoubleSlider2D", - "RingSlider2D", - "RangeSlider", - "Checkbox", - "Option", - "RadioButton", - "ComboBox2D", - "ListBox2D", - "ListBoxItem2D", - "FileMenu2D", - "DrawShape", - "DrawPanel", - "PlaybackPanel", - "Card2D", - "SpinBox", -] +__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__) diff --git a/fury/ui/__init__.pyi b/fury/ui/__init__.pyi new file mode 100644 index 000000000..52bd7c956 --- /dev/null +++ b/fury/ui/__init__.pyi @@ -0,0 +1,69 @@ +__all__ = [ + "Panel2D", + "TabPanel2D", + "TabUI", + "ImageContainer2D", + "GridUI", + "Rectangle2D", + "Disk2D", + "TextBlock2D", + "Button2D", + "TextBox2D", + "LineSlider2D", + "LineDoubleSlider2D", + "RingSlider2D", + "RangeSlider", + "Checkbox", + "Option", + "RadioButton", + "ComboBox2D", + "ListBox2D", + "ListBoxItem2D", + "FileMenu2D", + "DrawShape", + "DrawPanel", + "PlaybackPanel", + "Card2D", + "SpinBox", + "UI", + "cal_bounding_box_2d", + "check_overflow", + "clip_overflow", + "rotate_2d", + "wrap_overflow", +] + +from . import ( + containers as containers, + core as core, + elements as elements, + helpers as helpers, +) +from .containers import GridUI, ImageContainer2D, Panel2D, TabPanel2D, TabUI +from .core import UI, Button2D, Disk2D, Rectangle2D, TextBlock2D +from .elements import ( + Card2D, + Checkbox, + ComboBox2D, + DrawPanel, + DrawShape, + FileMenu2D, + LineDoubleSlider2D, + LineSlider2D, + ListBox2D, + ListBoxItem2D, + Option, + PlaybackPanel, + RadioButton, + RangeSlider, + RingSlider2D, + SpinBox, + TextBox2D, +) +from .helpers import ( + cal_bounding_box_2d, + check_overflow, + clip_overflow, + rotate_2d, + wrap_overflow, +) diff --git a/fury/ui/containers.py b/fury/ui/containers.py index ca1606108..3f1d4f0fe 100644 --- a/fury/ui/containers.py +++ b/fury/ui/containers.py @@ -5,6 +5,7 @@ import numpy as np from fury.actor import grid +from fury.decorators import warn_on_args_to_kwargs from fury.io import load_image from fury.lib import ( CellArray, @@ -32,9 +33,11 @@ class Panel2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, size, + *, position=(0, 0), color=(0.1, 0.1, 0.1), opacity=0.7, @@ -68,7 +71,7 @@ def __init__( self.has_border = has_border self._border_color = border_color self._border_width = border_width - super(Panel2D, self).__init__(position) + super(Panel2D, self).__init__(position=position) self.resize(size) self.alignment = align self.color = color @@ -205,7 +208,8 @@ def opacity(self): def opacity(self, opacity): self.background.opacity = opacity - def add_element(self, element, coords, anchor="position"): + @warn_on_args_to_kwargs() + def add_element(self, element, coords, *, anchor="position"): """Add a UI component to the panel. The coordinates represent an offset from the lower left corner of the @@ -255,7 +259,8 @@ def remove_element(self, element): del self._elements[idx] del self.element_offsets[idx] - def update_element(self, element, coords, anchor="position"): + @warn_on_args_to_kwargs() + def update_element(self, element, coords, *, anchor="position"): """Update the position of a UI component in the panel. Parameters @@ -271,7 +276,7 @@ def update_element(self, element, coords, anchor="position"): """ self.remove_element(element) - self.add_element(element, coords, anchor) + self.add_element(element, coords, anchor=anchor) def left_button_pressed(self, i_ren, _obj, panel2d_object): click_pos = np.array(i_ren.event.position) @@ -382,8 +387,10 @@ class TabPanel2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, + *, position=(0, 0), size=(100, 100), title="New Tab", @@ -572,7 +579,8 @@ def title_italic(self, italic): """ self.text_block.italic = italic - def add_element(self, element, coords, anchor="position"): + @warn_on_args_to_kwargs() + def add_element(self, element, coords, *, anchor="position"): """Add a UI component to the content panel. The coordinates represent an offset from the lower left corner of the @@ -590,7 +598,7 @@ def add_element(self, element, coords, anchor="position"): """ element.set_visibility(False) - self.content_panel.add_element(element, coords, anchor) + self.content_panel.add_element(element, coords, anchor=anchor) def remove_element(self, element): """Remove a UI component from the content panel. @@ -603,7 +611,8 @@ def remove_element(self, element): """ self.content_panel.remove_element(element) - def update_element(self, element, coords, anchor="position"): + @warn_on_args_to_kwargs() + def update_element(self, element, coords, *, anchor="position"): """Update the position of a UI component in the content panel. Parameters @@ -631,8 +640,10 @@ class TabUI(UI): """ + @warn_on_args_to_kwargs() def __init__( self, + *, position=(0, 0), size=(100, 100), nb_tabs=1, @@ -835,10 +846,11 @@ def collapse_tab_ui(self, iren, _obj, _tab_comp): iren.force_render() iren.event.abort() - def add_element(self, tab_idx, element, coords, anchor="position"): + @warn_on_args_to_kwargs() + def add_element(self, tab_idx, element, coords, *, anchor="position"): """Add element to content panel after checking its existence.""" if tab_idx < self.nb_tabs and tab_idx >= 0: - self.tabs[tab_idx].add_element(element, coords, anchor) + self.tabs[tab_idx].add_element(element, coords, anchor=anchor) if tab_idx == self.active_tab_idx: element.set_visibility(True) else: @@ -851,10 +863,11 @@ def remove_element(self, tab_idx, element): else: raise IndexError("Tab with index " "{} does not exist".format(tab_idx)) - def update_element(self, tab_idx, element, coords, anchor="position"): + @warn_on_args_to_kwargs() + def update_element(self, tab_idx, element, coords, *, anchor="position"): """Update element on content panel after checking its existence.""" if tab_idx < self.nb_tabs and tab_idx >= 0: - self.tabs[tab_idx].update_element(element, coords, anchor) + self.tabs[tab_idx].update_element(element, coords, anchor=anchor) else: raise IndexError("Tab with index " "{} does not exist".format(tab_idx)) @@ -886,7 +899,8 @@ class ImageContainer2D(UI): """ - def __init__(self, img_path, position=(0, 0), size=(100, 100)): + @warn_on_args_to_kwargs() + def __init__(self, img_path, *, position=(0, 0), size=(100, 100)): """Init class instance. Parameters @@ -899,7 +913,7 @@ def __init__(self, img_path, position=(0, 0), size=(100, 100)): Width and height in pixels of the image. """ - super(ImageContainer2D, self).__init__(position) + super(ImageContainer2D, self).__init__(position=position) self.img = load_image(img_path, as_vtktype=True) self.set_img(self.img) self.resize(size) @@ -1028,9 +1042,11 @@ def set_img(self, img): class GridUI(UI): """Add actors in a grid and interact with them individually.""" + @warn_on_args_to_kwargs() def __init__( self, actors, + *, captions=None, caption_offset=(0, -100, 0), cell_padding=0, diff --git a/fury/ui/core.py b/fury/ui/core.py index 5507a613a..1ff2b1720 100644 --- a/fury/ui/core.py +++ b/fury/ui/core.py @@ -4,6 +4,7 @@ import numpy as np +from fury.decorators import warn_on_args_to_kwargs from fury.interactor import CustomInteractorStyle from fury.io import load_image from fury.lib import ( @@ -79,7 +80,8 @@ class UI(object, metaclass=abc.ABCMeta): """ - def __init__(self, position=(0, 0)): + @warn_on_args_to_kwargs() + def __init__(self, *, position=(0, 0)): """Init scene. Parameters @@ -175,9 +177,12 @@ def add_to_scene(self, scene): if callback[0] == self._scene: iren.add_callback(iren, callback[1], callback[2], args=[self]) else: - iren.add_callback(*callback, args=[self]) + # iren.add_callback(*callback, args=[self]) + if len(callback) > 3: + iren.add_callback(*callback[:3], priority=callback[3], args=[self]) - def add_callback(self, prop, event_type, callback, priority=0): + @warn_on_args_to_kwargs() + def add_callback(self, prop, event_type, callback, *, priority=0): """Add a callback to a specific event for this UI component. Parameters @@ -351,7 +356,8 @@ def key_press_callback(i_ren, obj, self): class Rectangle2D(UI): """A 2D rectangle sub-classed from UI.""" - def __init__(self, size=(0, 0), position=(0, 0), color=(1, 1, 1), opacity=1.0): + @warn_on_args_to_kwargs() + def __init__(self, *, size=(0, 0), position=(0, 0), color=(1, 1, 1), opacity=1.0): """Initialize a rectangle. Parameters @@ -366,7 +372,7 @@ def __init__(self, size=(0, 0), position=(0, 0), color=(1, 1, 1), opacity=1.0): Must take values in [0, 1]. """ - super(Rectangle2D, self).__init__(position) + super(Rectangle2D, self).__init__(position=position) self.color = color self.opacity = opacity self.resize(size) @@ -517,8 +523,15 @@ def opacity(self, opacity): class Disk2D(UI): """A 2D disk UI component.""" + @warn_on_args_to_kwargs() def __init__( - self, outer_radius, inner_radius=0, center=(0, 0), color=(1, 1, 1), opacity=1.0 + self, + outer_radius, + *, + inner_radius=0, + center=(0, 0), + color=(1, 1, 1), + opacity=1.0, ): """Initialize a 2D Disk. @@ -691,8 +704,10 @@ class TextBlock2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, + *, text="Text Block", font_size=18, font_family="Arial", @@ -779,7 +794,7 @@ def resize(self, size): Text bounding box size(width, height) in pixels. """ - self.update_bounding_box(size) + self.update_bounding_box(size=size) def _get_actors(self): """Get the actors composing this UI component.""" @@ -1090,7 +1105,7 @@ def auto_font_scale(self, flag): if flag: self.actor.SetTextScaleModeToProp() self._justification = "left" - self.update_bounding_box(self.size) + self.update_bounding_box(size=self.size) else: self.actor.SetTextScaleModeToNone() @@ -1163,7 +1178,8 @@ def cal_size_from_message(self): max_length = max(len(line) for line in lines) return [max_length * self.font_size, len(lines) * self.font_size] - def update_bounding_box(self, size=None): + @warn_on_args_to_kwargs() + def update_bounding_box(self, *, size=None): """Update Text Bounding Box. Parameters @@ -1224,7 +1240,8 @@ class Button2D(UI): """ - def __init__(self, icon_fnames, position=(0, 0), size=(30, 30)): + @warn_on_args_to_kwargs() + def __init__(self, icon_fnames, *, position=(0, 0), size=(30, 30)): """Init class instance. Parameters @@ -1237,7 +1254,7 @@ def __init__(self, icon_fnames, position=(0, 0), size=(30, 30)): Width and height in pixels of the button. """ - super(Button2D, self).__init__(position) + super(Button2D, self).__init__(position=position) self.icon_extents = {} self.icons = self._build_icons(icon_fnames) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 8ba6675f7..490c705ab 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -31,6 +31,7 @@ from PIL import Image, UnidentifiedImageError from fury.data import read_viz_icons +from fury.decorators import warn_on_args_to_kwargs from fury.lib import Command from fury.ui.containers import ImageContainer2D, Panel2D from fury.ui.core import UI, Button2D, Disk2D, Rectangle2D, TextBlock2D @@ -74,10 +75,12 @@ class TextBox2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, width, height, + *, text="Enter Text", position=(100, 10), color=(0, 0, 0), @@ -227,7 +230,7 @@ def handle_character(self, key, key_char): """ if key.lower() == "return": - self.render_text(False) + self.render_text(show_caret=False) self.off_focus(self) return True elif key_char != "" and key_char in printable: @@ -339,7 +342,8 @@ def showable_text(self, show_caret): ret_text = ret_text[self.window_left : self.window_right + 1] return ret_text - def render_text(self, show_caret=True): + @warn_on_args_to_kwargs() + def render_text(self, *, show_caret=True): """Render text after processing. Parameters @@ -423,8 +427,10 @@ class LineSlider2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, + *, center=(0, 0), initial_value=50, min_value=0, @@ -800,8 +806,10 @@ class LineDoubleSlider2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, + *, line_width=5, inner_radius=0, outer_radius=10, @@ -1389,8 +1397,10 @@ class RingSlider2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, + *, center=(0, 0), initial_value=180, min_value=0, @@ -1665,8 +1675,10 @@ class RangeSlider(UI): """ + @warn_on_args_to_kwargs() def __init__( self, + *, line_width=5, inner_radius=0, outer_radius=10, @@ -1838,7 +1850,8 @@ class Option(UI): """ - def __init__(self, label, position=(0, 0), font_size=18, checked=False): + @warn_on_args_to_kwargs() + def __init__(self, label, *, position=(0, 0), font_size=18, checked=False): """Init this class instance. Parameters @@ -1859,7 +1872,7 @@ def __init__(self, label, position=(0, 0), font_size=18, checked=False): self.checked = checked self.button_size = (font_size * 1.2, font_size * 1.2) self.button_label_gap = 10 - super(Option, self).__init__(position) + super(Option, self).__init__(position=position) # Offer some standard hooks to the user. self.on_change = lambda obj: None @@ -1949,9 +1962,11 @@ class Checkbox(UI): """ + @warn_on_args_to_kwargs() def __init__( self, labels, + *, checked_labels=(), padding=1, font_size=18, @@ -1982,7 +1997,7 @@ def __init__( self._font_size = font_size self.font_family = font_family self.checked_labels = list(checked_labels) - super(Checkbox, self).__init__(position) + super(Checkbox, self).__init__(position=position) self.on_change = lambda checkbox: None def _setup(self): @@ -2093,10 +2108,12 @@ class RadioButton(Checkbox): """ + @warn_on_args_to_kwargs() def __init__( self, labels, checked_labels, + *, padding=1, font_size=18, font_family="Arial", @@ -2157,8 +2174,10 @@ class ComboBox2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, + *, items=None, position=(0, 0), size=(300, 200), @@ -2496,9 +2515,11 @@ class ListBox2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, values, + *, position=(0, 0), size=(100, 300), multiselection=True, @@ -2864,7 +2885,8 @@ def update_scrollbar(self): def clear_selection(self): del self.selected[:] - def select(self, item, multiselect=False, range_select=False): + @warn_on_args_to_kwargs() + def select(self, item, *, multiselect=False, range_select=False): """Select the item. Parameters @@ -2909,10 +2931,12 @@ def select(self, item, multiselect=False, range_select=False): class ListBoxItem2D(UI): """The text displayed in a listbox.""" + @warn_on_args_to_kwargs() def __init__( self, list_box, size, + *, text_color=(1.0, 0.0, 0.0), selected_color=(0.4, 0.4, 0.4), unselected_color=(0.9, 0.9, 0.9), @@ -3031,7 +3055,9 @@ def left_button_clicked(self, i_ren, _obj, _list_box_item): """ multiselect = i_ren.event.ctrl_key range_select = i_ren.event.shift_key - self.list_box.select(self, multiselect, range_select) + self.list_box.select( + item=self, multiselect=multiselect, range_select=range_select + ) i_ren.force_render() def resize(self, size): @@ -3053,9 +3079,11 @@ class FileMenu2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, directory_path, + *, extensions=None, position=(0, 0), size=(100, 300), @@ -3307,7 +3335,8 @@ def directory_click_callback(self, i_ren, _obj, listboxitem): class DrawShape(UI): """Create and Manage 2D Shapes.""" - def __init__(self, shape_type, drawpanel=None, position=(0, 0)): + @warn_on_args_to_kwargs() + def __init__(self, shape_type, *, drawpanel=None, position=(0, 0)): """Init this UI element. Parameters @@ -3325,7 +3354,7 @@ def __init__(self, shape_type, drawpanel=None, position=(0, 0)): self.drawpanel = drawpanel self.max_size = None self.rotation = 0 - super(DrawShape, self).__init__(position) + super(DrawShape, self).__init__(position=position) self.shape.color = np.random.random(3) def _setup(self): @@ -3388,7 +3417,7 @@ def update_shape_position(self, center_position): """ new_center = self.clamp_position(center=center_position) - self.drawpanel.canvas.update_element(self, new_center, "center") + self.drawpanel.canvas.update_element(self, new_center, anchor="center") self.cal_bounding_box() @property @@ -3457,7 +3486,8 @@ def cal_bounding_box(self): self._bounding_box_offset = self.position - self._bounding_box_min - def clamp_position(self, center=None): + @warn_on_args_to_kwargs() + def clamp_position(self, *, center=None): """Clamp the given center according to the DrawPanel canvas. Parameters @@ -3539,7 +3569,8 @@ def left_button_released(self, i_ren, _obj, shape): class DrawPanel(UI): """The main Canvas(Panel2D) on which everything would be drawn.""" - def __init__(self, size=(400, 400), position=(0, 0), is_draggable=False): + @warn_on_args_to_kwargs() + def __init__(self, *, size=(400, 400), position=(0, 0), is_draggable=False): """Init this UI element. Parameters @@ -3553,7 +3584,7 @@ def __init__(self, size=(400, 400), position=(0, 0), is_draggable=False): """ self.panel_size = size - super(DrawPanel, self).__init__(position) + super(DrawPanel, self).__init__(position=position) self.is_draggable = is_draggable self.current_mode = None @@ -3817,11 +3848,12 @@ class PlaybackPanel(UI): such as play, pause, stop, and seek. """ - def __init__(self, loop=False, position=(0, 0), width=None): + @warn_on_args_to_kwargs() + def __init__(self, *, loop=False, position=(0, 0), width=None): self._width = width if width is not None else 900 self._auto_width = width is None self._position = position - super(PlaybackPanel, self).__init__(position) + super(PlaybackPanel, self).__init__(position=position) self._playing = False self._loop = None self.loop() if loop else self.play_once() @@ -4186,9 +4218,11 @@ class Card2D(UI): """ + @warn_on_args_to_kwargs() def __init__( self, image_path, + *, body_text="", draggable=True, title_text="", @@ -4453,8 +4487,10 @@ def left_button_dragged(self, i_ren, _obj, _sub_component): class SpinBox(UI): """SpinBox UI.""" + @warn_on_args_to_kwargs() def __init__( self, + *, position=(350, 400), size=(300, 100), padding=10, @@ -4502,7 +4538,7 @@ def __init__( self.max_column = max_column self.max_line = max_line - super(SpinBox, self).__init__(position) + super(SpinBox, self).__init__(position=position) self.value = initial_val self.resize(size) diff --git a/fury/ui/helpers.py b/fury/ui/helpers.py index 8a9c39de5..939519a27 100644 --- a/fury/ui/helpers.py +++ b/fury/ui/helpers.py @@ -2,10 +2,13 @@ import numpy as np +from fury.decorators import warn_on_args_to_kwargs + TWO_PI = 2 * np.pi -def clip_overflow(textblock, width, side="right"): +@warn_on_args_to_kwargs() +def clip_overflow(textblock, width, *, side="right"): """Clips overflowing text of TextBlock2D with respect to width. Parameters @@ -27,7 +30,7 @@ def clip_overflow(textblock, width, side="right"): original_str = textblock.message prev_bg = textblock.have_bg - clip_idx = check_overflow(textblock, width, "...", side) + clip_idx = check_overflow(textblock, width, overflow_postfix="...", side=side) if clip_idx == 0: return original_str @@ -36,7 +39,8 @@ def clip_overflow(textblock, width, side="right"): return textblock.message -def wrap_overflow(textblock, wrap_width, side="right"): +@warn_on_args_to_kwargs() +def wrap_overflow(textblock, wrap_width, *, side="right"): """Wraps overflowing text of TextBlock2D with respect to width. Parameters @@ -59,7 +63,7 @@ def wrap_overflow(textblock, wrap_width, side="right"): str_copy = textblock.message wrap_idxs = [] - wrap_idx = check_overflow(textblock, wrap_width, "", side) + wrap_idx = check_overflow(textblock, wrap_width, overflow_postfix="", side=side) if wrap_idx == 0: return original_str @@ -69,7 +73,7 @@ def wrap_overflow(textblock, wrap_width, side="right"): while wrap_idx != 0: str_copy = str_copy[wrap_idx:] textblock.message = str_copy - wrap_idx = check_overflow(textblock, wrap_width, "", side) + wrap_idx = check_overflow(textblock, wrap_width, overflow_postfix="", side=side) if wrap_idx != 0: wrap_idxs.append(wrap_idxs[-1] + wrap_idx + 1) @@ -80,7 +84,8 @@ def wrap_overflow(textblock, wrap_width, side="right"): return textblock.message -def check_overflow(textblock, width, overflow_postfix="", side="right"): +@warn_on_args_to_kwargs() +def check_overflow(textblock, width, *, overflow_postfix="", side="right"): """Checks if the text is overflowing. Parameters diff --git a/fury/ui/tests/test_containers.py b/fury/ui/tests/test_containers.py index 333fb7b44..1c016290d 100644 --- a/fury/ui/tests/test_containers.py +++ b/fury/ui/tests/test_containers.py @@ -22,7 +22,7 @@ def setup_module(): def test_wrong_interactor_style(): panel = ui.Panel2D(size=(300, 150)) dummy_scene = window.Scene() - _ = window.ShowManager(dummy_scene, interactor_style="trackball") + _ = window.ShowManager(scene=dummy_scene, interactor_style="trackball") npt.assert_raises(TypeError, panel.add_to_scene, dummy_scene) @@ -35,17 +35,32 @@ def test_grid_ui1(interactive=False): vol1[25:75, 25:75, 25:75] = 100 colors = distinguishable_colormap(nb_colors=3) - contour_actor1 = actor.contour_from_roi(vol1, np.eye(4), colors[0], 1.0) + contour_actor1 = actor.contour_from_roi( + vol1, + affine=np.eye(4), + color=colors[0], + opacity=1.0, + ) vol2 = np.zeros((100, 100, 100)) vol2[25:75, 25:75, 25:75] = 100 - contour_actor2 = actor.contour_from_roi(vol2, np.eye(4), colors[1], 1.0) + contour_actor2 = actor.contour_from_roi( + vol2, + affine=np.eye(4), + color=colors[1], + opacity=1.0, + ) vol3 = np.zeros((100, 100, 100)) vol3[25:75, 25:75, 25:75] = 100 - contour_actor3 = actor.contour_from_roi(vol3, np.eye(4), colors[2], 1.0) + contour_actor3 = actor.contour_from_roi( + vol3, + affine=np.eye(4), + color=colors[2], + opacity=1.0, + ) scene = window.Scene() actors = [] @@ -88,7 +103,7 @@ def test_grid_ui1(interactive=False): texts.append(text_actor3) counter = itertools.count() - show_m = window.ShowManager(scene) + show_m = window.ShowManager(scene=scene) def timer_callback(_obj, _event): nonlocal show_m, counter @@ -136,17 +151,32 @@ def test_grid_ui2(interactive=False): vol1[25:75, 25:75, 25:75] = 100 colors = distinguishable_colormap(nb_colors=3) - contour_actor1 = actor.contour_from_roi(vol1, np.eye(4), colors[0], 1.0) + contour_actor1 = actor.contour_from_roi( + vol1, + affine=np.eye(4), + color=colors[0], + opacity=1.0, + ) vol2 = np.zeros((100, 100, 100)) vol2[25:75, 25:75, 25:75] = 100 - contour_actor2 = actor.contour_from_roi(vol2, np.eye(4), colors[1], 1.0) + contour_actor2 = actor.contour_from_roi( + vol2, + affine=np.eye(4), + color=colors[1], + opacity=1.0, + ) vol3 = np.zeros((100, 100, 100)) vol3[25:75, 25:75, 25:75] = 100 - contour_actor3 = actor.contour_from_roi(vol3, np.eye(4), colors[2], 1.0) + contour_actor3 = actor.contour_from_roi( + vol3, + affine=np.eye(4), + color=colors[2], + opacity=1.0, + ) scene = window.Scene() actors = [] @@ -198,7 +228,9 @@ def test_grid_ui2(interactive=False): current_size = (900, 600) scene = window.Scene() - show_manager = window.ShowManager(scene, size=current_size, title="FURY GridUI") + show_manager = window.ShowManager( + scene=scene, size=current_size, title="FURY GridUI" + ) grid_ui2 = ui.GridUI( actors=actors, diff --git a/fury/ui/tests/test_core.py b/fury/ui/tests/test_core.py index 5e76a1cfe..0377d3385 100644 --- a/fury/ui/tests/test_core.py +++ b/fury/ui/tests/test_core.py @@ -276,7 +276,7 @@ def test_text_block_2d_justification(): texts = [] texts += [ ui.TextBlock2D( - "HH", + text="HH", position=(left, top), font_size=font_size, color=(1, 0, 0), @@ -287,7 +287,7 @@ def test_text_block_2d_justification(): ] texts += [ ui.TextBlock2D( - "HH", + text="HH", position=(center, top), font_size=font_size, color=(0, 1, 0), @@ -298,7 +298,7 @@ def test_text_block_2d_justification(): ] texts += [ ui.TextBlock2D( - "HH", + text="HH", position=(right, top), font_size=font_size, color=(0, 0, 1), @@ -310,7 +310,7 @@ def test_text_block_2d_justification(): texts += [ ui.TextBlock2D( - "HH", + text="HH", position=(left, middle), font_size=font_size, color=(1, 1, 0), @@ -321,7 +321,7 @@ def test_text_block_2d_justification(): ] texts += [ ui.TextBlock2D( - "HH", + text="HH", position=(center, middle), font_size=font_size, color=(0, 1, 1), @@ -332,7 +332,7 @@ def test_text_block_2d_justification(): ] texts += [ ui.TextBlock2D( - "HH", + text="HH", position=(right, middle), font_size=font_size, color=(1, 0, 1), @@ -344,7 +344,7 @@ def test_text_block_2d_justification(): texts += [ ui.TextBlock2D( - "HH", + text="HH", position=(left, bottom), font_size=font_size, color=(0.5, 0, 1), @@ -355,7 +355,7 @@ def test_text_block_2d_justification(): ] texts += [ ui.TextBlock2D( - "HH", + text="HH", position=(center, bottom), font_size=font_size, color=(1, 0.5, 0), @@ -366,7 +366,7 @@ def test_text_block_2d_justification(): ] texts += [ ui.TextBlock2D( - "HH", + text="HH", position=(right, bottom), font_size=font_size, color=(0, 1, 0.5), diff --git a/fury/ui/tests/test_elements.py b/fury/ui/tests/test_elements.py index 7df1645b1..2f72949cc 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -1171,7 +1171,7 @@ def test_ui_draw_shape(): current_size = (900, 900) scene = window.Scene() show_manager = window.ShowManager( - scene, size=current_size, title="DrawShape UI Example" + scene=scene, size=current_size, title="DrawShape UI Example" ) scene.add(line, circle, quad) diff --git a/fury/ui/tests/test_elements_callback.py b/fury/ui/tests/test_elements_callback.py index 89c6aa506..4fa62e34b 100644 --- a/fury/ui/tests/test_elements_callback.py +++ b/fury/ui/tests/test_elements_callback.py @@ -51,7 +51,7 @@ def test_frame_rate_and_anti_aliasing(): counter = itertools.count() showm = window.ShowManager( - scene, + scene=scene, size=(1980, 1080), reset_camera=False, order_transparent=True, @@ -103,7 +103,7 @@ def timer_callback(_obj, _event): counter = itertools.count() multi_samples = 0 showm = window.ShowManager( - scene, + scene=scene, size=(1980, 1080), reset_camera=False, order_transparent=True, @@ -145,7 +145,7 @@ def test_timer(): sphere_actor = actor.sphere(centers=xyzr[:, :3], colors=colors[:], radii=xyzr[:, 3]) - vertices, faces = prim_sphere("repulsion724") + vertices, faces = prim_sphere(name="repulsion724") sphere_actor2 = actor.sphere( centers=xyzr2[:, :3], @@ -161,7 +161,10 @@ def test_timer(): tb = ui.TextBlock2D() counter = itertools.count() showm = window.ShowManager( - scene, size=(1024, 768), reset_camera=False, order_transparent=True + scene=scene, + size=(1024, 768), + reset_camera=False, + order_transparent=True, ) scene.add(tb) diff --git a/fury/ui/tests/test_helpers.py b/fury/ui/tests/test_helpers.py index 039d28d83..34f7c1039 100644 --- a/fury/ui/tests/test_helpers.py +++ b/fury/ui/tests/test_helpers.py @@ -32,26 +32,26 @@ def test_clip_overflow(): npt.assert_equal("A ...", text.message) text.message = "Hello" - clip_overflow(text, text.size[0], "left") + clip_overflow(text, text.size[0], side="left") npt.assert_equal("Hello", text.message) text.message = "Hello wassup" - clip_overflow(text, text.size[0], "left") + clip_overflow(text, text.size[0], side="left") npt.assert_equal("...up", text.message) text.message = "A very very long message to clip text overflow" - clip_overflow(text, text.size[0], "left") + clip_overflow(text, text.size[0], side="left") npt.assert_equal("...ow", text.message) text.message = "A very very long message to clip text overflow" - clip_overflow(text, text.size[0], "LeFT") + clip_overflow(text, text.size[0], side="LeFT") npt.assert_equal("...ow", text.message) text.message = "A very very long message to clip text overflow" - clip_overflow(text, text.size[0], "RigHT") + clip_overflow(text, text.size[0], side="RigHT") npt.assert_equal("A ...", text.message) - npt.assert_raises(ValueError, clip_overflow, text, text.size[0], "middle") + npt.assert_raises(ValueError, clip_overflow, text, text.size[0], side="middle") def test_wrap_overflow(): @@ -97,7 +97,7 @@ def test_check_overflow(): text.message = "A very very long message to clip text overflow" - overflow_idx = check_overflow(text, 100, "~") + overflow_idx = check_overflow(text, 100, overflow_postfix="~") npt.assert_equal(4, overflow_idx) npt.assert_equal("A ve~", text.message) diff --git a/fury/utils.py b/fury/utils.py index 12aeb2214..2b170a2a2 100644 --- a/fury/utils.py +++ b/fury/utils.py @@ -2,6 +2,7 @@ from scipy.ndimage import map_coordinates from fury.colormap import line_colors +from fury.decorators import warn_on_args_to_kwargs from fury.lib import ( VTK_DOUBLE, VTK_FLOAT, @@ -116,7 +117,8 @@ def numpy_to_vtk_colors(colors): return vtk_colors -def numpy_to_vtk_cells(data, is_coords=True): +@warn_on_args_to_kwargs() +def numpy_to_vtk_cells(data, *, is_coords=True): """Convert numpy array to a vtk cell array. Parameters @@ -172,8 +174,9 @@ def numpy_to_vtk_cells(data, is_coords=True): return cell_array +@warn_on_args_to_kwargs() def numpy_to_vtk_image_data( - array, spacing=(1.0, 1.0, 1.0), origin=(0.0, 0.0, 0.0), deep=True + array, *, spacing=(1.0, 1.0, 1.0), origin=(0.0, 0.0, 0.0), deep=True ): """Convert numpy array to a vtk image data. @@ -243,7 +246,8 @@ def map_coordinates_3d_4d(input_array, indices): return np.ascontiguousarray(np.array(values_4d).T) -def lines_to_vtk_polydata(lines, colors=None): +@warn_on_args_to_kwargs() +def lines_to_vtk_polydata(lines, *, colors=None): """Create a vtkPolyData with lines and colors. Parameters @@ -501,7 +505,8 @@ def get_polydata_colors(polydata): return numpy_support.vtk_to_numpy(vtk_colors) -def get_polydata_field(polydata, field_name, as_vtk=False): +@warn_on_args_to_kwargs() +def get_polydata_field(polydata, field_name, *, as_vtk=False): """Get a field from a vtk polydata. Parameters @@ -526,7 +531,8 @@ def get_polydata_field(polydata, field_name, as_vtk=False): return numpy_support.vtk_to_numpy(vtk_field_data) -def add_polydata_numeric_field(polydata, field_name, field_data, array_type=VTK_INT): +@warn_on_args_to_kwargs() +def add_polydata_numeric_field(polydata, field_name, field_data, *, array_type=VTK_INT): """Add a field to a vtk polydata. Parameters @@ -668,7 +674,8 @@ def set_polydata_tangents(polydata, tangents): return polydata -def set_polydata_colors(polydata, colors, array_name="colors"): +@warn_on_args_to_kwargs() +def set_polydata_colors(polydata, colors, *, array_name="colors"): """Set polydata colors with a numpy array (ndarrays Nx3 int). Parameters @@ -781,8 +788,15 @@ def get_actor_from_polydata(polydata): return get_actor_from_polymapper(poly_mapper) +@warn_on_args_to_kwargs() def get_actor_from_primitive( - vertices, triangles, colors=None, normals=None, backface_culling=True, prim_count=1 + vertices, + triangles, + *, + colors=None, + normals=None, + backface_culling=True, + prim_count=1, ): """Get actor from a vtkPolyData. @@ -831,9 +845,11 @@ def get_actor_from_primitive( return current_actor +@warn_on_args_to_kwargs() def repeat_sources( centers, colors, + *, active_scalars=1.0, directions=None, source=None, @@ -972,13 +988,13 @@ def apply_affine(aff, pts): [16, 17, 28], [20, 23, 36], [24, 29, 44]]...) - Just to show that in the simple 3D case, it is equivalent to: + >>> # Just to show that in the simple 3D case, it is equivalent to: >>> (np.dot(aff[:3,:3], pts.T) + aff[:3,3:4]).T #doctest: +ELLIPSIS array([[14, 14, 24], [16, 17, 28], [20, 23, 36], [24, 29, 44]]...) - But `pts` can be a more complicated shape: + >>> # But `pts` can be a more complicated shape: >>> pts = pts.reshape((2,2,3)) >>> apply_affine(aff, pts) #doctest: +ELLIPSIS array([[[14, 14, 24], @@ -1047,7 +1063,8 @@ def get_bounding_box_sizes(actor): return (X2 - X1, Y2 - Y1, Z2 - Z1) -def get_grid_cells_position(shapes, aspect_ratio=16 / 9.0, dim=None): +@warn_on_args_to_kwargs() +def get_grid_cells_position(shapes, *, aspect_ratio=16 / 9.0, dim=None): """Construct a XY-grid based on the cells content shape. This function generates the coordinates of every grid cell. The width and @@ -1103,7 +1120,8 @@ def shallow_copy(vtk_object): return copy -def rotate(actor, rotation=(90, 1, 0, 0)): +@warn_on_args_to_kwargs() +def rotate(actor, *, rotation=(90, 1, 0, 0)): """Rotate actor around axis by angle. Parameters @@ -1286,7 +1304,8 @@ def change_vertices_order(triangle): return np.array([triangle[2], triangle[1], triangle[0]]) -def fix_winding_order(vertices, triangles, clockwise=False): +@warn_on_args_to_kwargs() +def fix_winding_order(vertices, triangles, *, clockwise=False): """Return corrected triangles. Given an ordering of the triangle's three vertices, a triangle can appear @@ -1318,7 +1337,8 @@ def fix_winding_order(vertices, triangles, clockwise=False): return corrected_triangles -def vertices_from_actor(actor, as_vtk=False): +@warn_on_args_to_kwargs() +def vertices_from_actor(actor, *, as_vtk=False): """Access to vertices from actor. Parameters @@ -1339,7 +1359,8 @@ def vertices_from_actor(actor, as_vtk=False): return numpy_support.vtk_to_numpy(vtk_array) -def colors_from_actor(actor, array_name="colors", as_vtk=False): +@warn_on_args_to_kwargs() +def colors_from_actor(actor, *, array_name="colors", as_vtk=False): """Access colors from actor which uses polydata. Parameters @@ -1392,7 +1413,8 @@ def tangents_from_actor(act): return get_polydata_tangents(polydata) -def array_from_actor(actor, array_name, as_vtk=False): +@warn_on_args_to_kwargs() +def array_from_actor(actor, array_name, *, as_vtk=False): """Access array from actor which uses polydata. Parameters @@ -1459,7 +1481,8 @@ def compute_bounds(actor): actor.GetMapper().GetInput().ComputeBounds() -def update_actor(actor, all_arrays=True): +@warn_on_args_to_kwargs() +def update_actor(actor, *, all_arrays=True): """Update actor. Parameters @@ -1524,7 +1547,8 @@ def update_surface_actor_colors(actor, colors): ) -def color_check(pts_len, colors=None): +@warn_on_args_to_kwargs() +def color_check(pts_len, *, colors=None): """Returns a VTK scalar array containing colors information for each one of the points according to the policy defined by the parameter colors. @@ -1580,7 +1604,8 @@ def is_ui(actor): return all(hasattr(actor, attr) for attr in ["add_to_scene", "_setup"]) -def set_actor_origin(actor, center=None): +@warn_on_args_to_kwargs() +def set_actor_origin(actor, *, center=None): """Change the origin of an actor to a custom position. Parameters @@ -1597,3 +1622,36 @@ def set_actor_origin(actor, center=None): center = np.mean(vertices) vertices[:] -= center update_actor(actor) + + +def minmax_norm(data, axis=1): + """Returns the min-max normalization of data along an axis. + + Parameters + ---------- + data: ndarray + 2D array + axis: int + axis for the function to be applied on + + Returns + ------- + output : ndarray + + """ + + if not isinstance(data, np.ndarray): + data = np.array(data) + if data.ndim == 1: + data = np.array([data]) + elif data.ndim > 2: + raise ValueError('the dimension of the array must be 2.') + + minimum = data.min(axis=axis) + maximum = data.max(axis=axis) + if np.array_equal(minimum, maximum): + return data + if (axis == 0): + return (data - minimum)/(maximum - minimum) + if (axis == 1): + return (data - minimum[:, None])/(maximum - minimum)[:, None] diff --git a/fury/window.py b/fury/window.py index 6a47af9f7..742f9a4b9 100644 --- a/fury/window.py +++ b/fury/window.py @@ -11,6 +11,7 @@ import fury.animation as anim from fury import __version__ as fury_version import fury.animation as anim +from fury.decorators import warn_on_args_to_kwargs from fury.interactor import CustomInteractorStyle from fury.io import load_image, save_image from fury.lib import ( @@ -32,11 +33,6 @@ from fury.shaders.base import GL_NUMBERS as _GL from fury.utils import asbytes -try: - _ = basestring -except NameError: - basestring = str - class Scene(OpenGLRenderer): """Your scene class. @@ -48,7 +44,8 @@ class Scene(OpenGLRenderer): available in ``vtkRenderer`` if necessary. """ - def __init__(self, background=(0, 0, 0), skybox=None): + @warn_on_args_to_kwargs() + def __init__(self, *, background=(0, 0, 0), skybox=None): self.__skybox = skybox self.__skybox_actor = None if skybox: @@ -62,7 +59,8 @@ def background(self, color): """Set a background color.""" self.SetBackground(color) - def skybox(self, visible=True, gamma_correct=True): + @warn_on_args_to_kwargs() + def skybox(self, *, visible=True, gamma_correct=True): """Show or hide the skybox. Parameters @@ -113,7 +111,8 @@ def rm_all(self): """Remove all actors from the scene.""" self.RemoveAllViewProps() - def projection(self, proj_type="perspective"): + @warn_on_args_to_kwargs() + def projection(self, *, proj_type="perspective"): """Decide between parallel or perspective projection. Parameters @@ -131,7 +130,8 @@ def reset_camera(self): """Reset the camera to an automatic position given by the engine.""" self.ResetCamera() - def reset_camera_tight(self, margin_factor=1.02): + @warn_on_args_to_kwargs() + def reset_camera_tight(self, *, margin_factor=1.02): """Resets camera so the content fit tightly within the window. Parameters @@ -181,7 +181,8 @@ def camera_info(self): print(" Focal Point (%.2f, %.2f, %.2f)" % cam.GetFocalPoint()) print(" View Up (%.2f, %.2f, %.2f)" % cam.GetViewUp()) - def set_camera(self, position=None, focal_point=None, view_up=None): + @warn_on_args_to_kwargs() + def set_camera(self, *, position=None, focal_point=None, view_up=None): """Set up camera position / Focal Point / View Up.""" if position is not None: self.GetActiveCamera().SetPosition(*position) @@ -291,8 +292,10 @@ def fxaa_off(self): class ShowManager: """Class interface between the scene, the window and the interactor.""" + @warn_on_args_to_kwargs() def __init__( self, + *, scene=None, title="FURY", size=(300, 300), @@ -522,7 +525,8 @@ def is_done(self): except AttributeError: return True - def start(self, multithreaded=False, desired_fps=60): + @warn_on_args_to_kwargs() + def start(self, *, multithreaded=False, desired_fps=60): """Start interaction. Parameters @@ -667,7 +671,8 @@ def _stop_recording_and_close(_obj, _evt): events = f.read() return events - def record_events_to_file(self, filename="record.log"): + @warn_on_args_to_kwargs() + def record_events_to_file(self, *, filename="record.log"): """Record events during the interaction. The recording is represented as a list of VTK events @@ -745,7 +750,8 @@ def play_events_from_file(self, filename): self.play_events(events) - def add_window_callback(self, win_callback, event=Command.ModifiedEvent): + @warn_on_args_to_kwargs() + def add_window_callback(self, win_callback, *, event=Command.ModifiedEvent): """Add window callbacks.""" self.window.AddObserver(event, win_callback) self.window.Render() @@ -762,7 +768,8 @@ def add_timer_callback(self, repeat, duration, timer_callback): self.timers.append(timer_id) return timer_id - def add_iren_callback(self, iren_callback, event="MouseMoveEvent"): + @warn_on_args_to_kwargs() + def add_iren_callback(self, iren_callback, *, event="MouseMoveEvent"): if not self.iren.GetInitialized(): self.initialize() self.iren.AddObserver(event, iren_callback) @@ -785,7 +792,8 @@ def exit(self): self.destroy_timers() self.timers.clear() - def save_screenshot(self, fname, magnification=1, size=None, stereo=None): + @warn_on_args_to_kwargs() + def save_screenshot(self, fname, *, magnification=1, size=None, stereo=None): """Save a screenshot of the current window in the specified filename. Parameters @@ -830,8 +838,10 @@ def save_screenshot(self, fname, magnification=1, size=None, stereo=None): ) +@warn_on_args_to_kwargs() def show( scene, + *, title="FURY", size=(300, 300), png_magnify=1, @@ -894,7 +904,7 @@ def show( >>> colors=np.array([[0.2,0.2,0.2],[0.8,0.8,0.8]]) >>> c=actor.line(lines,colors) >>> r.add(c) - >>> l=actor.label(text="Hello") + >>> l=actor.vector_text(text="Hello") >>> r.add(l) >>> #window.show(r) @@ -905,12 +915,12 @@ def show( """ show_manager = ShowManager( - scene, - title, - size, - png_magnify, - reset_camera, - order_transparent, + scene=scene, + title=title, + size=size, + png_magnify=png_magnify, + reset_camera=reset_camera, + order_transparent=order_transparent, stereo=stereo, multi_samples=multi_samples, max_peels=max_peels, @@ -920,7 +930,9 @@ def show( show_manager.start() +@warn_on_args_to_kwargs() def record( + *, scene=None, cam_pos=None, cam_focal=None, @@ -1074,7 +1086,8 @@ def record( renWin.Finalize() -def antialiasing(scene, win, multi_samples=8, max_peels=4, occlusion_ratio=0.0): +@warn_on_args_to_kwargs() +def antialiasing(scene, win, *, multi_samples=8, max_peels=4, occlusion_ratio=0.0): """Enable anti-aliasing and ordered transparency. Parameters @@ -1117,8 +1130,10 @@ def antialiasing(scene, win, multi_samples=8, max_peels=4, occlusion_ratio=0.0): scene.SetOcclusionRatio(occlusion_ratio) +@warn_on_args_to_kwargs() def snapshot( scene, + *, fname=None, size=(300, 300), offscreen=True, @@ -1191,7 +1206,11 @@ def snapshot( if order_transparent: antialiasing( - scene, render_window, multi_samples, max_peels, occlusion_ratio + scene, + render_window, + multi_samples=multi_samples, + max_peels=max_peels, + occlusion_ratio=occlusion_ratio, ) render_window.Render() @@ -1239,8 +1258,9 @@ class ReportScene: return report +@warn_on_args_to_kwargs() def analyze_snapshot( - im, bg_color=colors.black, colors=None, find_objects=True, strel=None + im, *, bg_color=colors.black, colors=None, find_objects=True, strel=None ): """Analyze snapshot from memory or file. @@ -1265,7 +1285,7 @@ def analyze_snapshot( information about what was found in the current snapshot array ``im``. """ - if isinstance(im, basestring): + if isinstance(im, str): im = load_image(im) class ReportSnapshot: @@ -1376,8 +1396,8 @@ def gl_reset_blend(gl_state): ---------- gl_state : vtkOpenGLState - See more - --------- + References + ---------- [1] https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBlendEquation.xhtml [2] https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBlendFunc.xhtml vtk specification: @@ -1430,12 +1450,11 @@ def gl_disable_blend(gl_state): ---------- gl_state : vtkOpenGLState - See more - -------- + References + ---------- [1] https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glFrontFace.xhtml - """ # noqa - + """ gl_state.vtkglDisable(_GL["GL_CULL_FACE"]) gl_state.vtkglDisable(_GL["GL_BLEND"]) diff --git a/pyproject.toml b/pyproject.toml index 87a8a26bb..0e779f2b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ dependencies = [ "packaging >=17.0", "pygltflib>=1.15.3", "aiohttp>=3.8.4", + "lazy_loader>=0.4", ] dynamic = ["version"] diff --git a/requirements/default.txt b/requirements/default.txt index 3ea054543..7c6d4a338 100644 --- a/requirements/default.txt +++ b/requirements/default.txt @@ -6,3 +6,4 @@ packaging pillow>=8.0.1 aiohttp>=3.8.4 pygltflib>=1.15.1 +lazy_loader>=0.4 diff --git a/requirements/docs.txt b/requirements/docs.txt index 312b9d259..bc61d0090 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -1,6 +1,7 @@ # These are dependencies of various sphinx extensions for documentation. sphinx>=5.0.0 ipython +numpydoc matplotlib sphinx-copybutton sphinx-gallery>=0.10.0