From 5e8fd1dad29ffe3c166966003681c2cb78e0ce79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Haitz=20Legarreta=20Gorro=C3=B1o?= Date: Sat, 27 Apr 2024 12:32:47 -0400 Subject: [PATCH] STYLE: Format code using `ruff` Format the code using `ruff`: supersedes `flake8` and `blue`. `blue` was not being applied previously as the relevant `pre-commit` hook config block was commented in the. Remove the `.flake8` config file: in practice few rules were being applied as the config file contained a significant number fo ignored rules. Bump `ruff-pre-commit` pre-commit hook version to v0.4.3 (May 3, 2024): the version being used previously was v0.1.7 was from Dec 4, 2023. Made changes consistent between changes being observed locally vs on the GitHub action. Sort the imports according to the new version: new sorting is dictated by the default value of `force-sort-within-sections` (`false`): imports are sorted by module. Fix the warnings reported by `ruff`, e.g. C408, F401, etc. --- .flake8 | 14 - .pre-commit-config.yaml | 15 +- docs/examples/collision-particles.py | 6 +- docs/examples/viz_advanced.py | 36 +- docs/examples/viz_animated_surfaces.py | 23 +- docs/examples/viz_arrow.py | 2 +- docs/examples/viz_ball_collide.py | 7 +- docs/examples/viz_bezier_interpolator.py | 31 +- docs/examples/viz_billboard_sdf_spheres.py | 98 ++-- docs/examples/viz_brick_wall.py | 7 +- docs/examples/viz_brownian_motion.py | 28 +- docs/examples/viz_bundles.py | 28 +- docs/examples/viz_buttons.py | 23 +- docs/examples/viz_camera.py | 6 +- docs/examples/viz_card.py | 35 +- docs/examples/viz_card_sprite_sheet.py | 50 +- docs/examples/viz_chain.py | 8 +- docs/examples/viz_check_boxes.py | 18 +- docs/examples/viz_color_interpolators.py | 12 +- docs/examples/viz_combobox.py | 27 +- docs/examples/viz_cone.py | 2 +- docs/examples/viz_custom_interpolator.py | 21 +- docs/examples/viz_domino.py | 7 +- docs/examples/viz_drawpanel.py | 9 +- docs/examples/viz_dt_ellipsoids.py | 130 +++-- docs/examples/viz_earth_animation.py | 10 +- docs/examples/viz_earth_coordinates.py | 10 +- docs/examples/viz_emwave_animation.py | 16 +- docs/examples/viz_fiber_odf.py | 34 +- docs/examples/viz_fine_tuning_gl_context.py | 12 +- docs/examples/viz_fractals.py | 12 +- docs/examples/viz_gltf.py | 6 +- docs/examples/viz_gltf_animated.py | 6 +- docs/examples/viz_gltf_export.py | 11 +- docs/examples/viz_helical_motion.py | 8 +- docs/examples/viz_hierarchical_animation.py | 3 +- docs/examples/viz_interaction.py | 8 +- docs/examples/viz_interpolators.py | 10 +- docs/examples/viz_introduction.py | 3 +- docs/examples/viz_layout.py | 14 +- docs/examples/viz_markers.py | 7 +- docs/examples/viz_morphing.py | 8 +- docs/examples/viz_multithread.py | 6 +- docs/examples/viz_network.py | 2 +- docs/examples/viz_network_animated.py | 2 +- docs/examples/viz_no_interaction.py | 7 +- docs/examples/viz_pbr_interactive.py | 50 +- docs/examples/viz_pbr_spheres.py | 48 +- docs/examples/viz_picking.py | 32 +- docs/examples/viz_play_video.py | 6 +- docs/examples/viz_principled_spheres.py | 42 +- docs/examples/viz_radio_buttons.py | 10 +- docs/examples/viz_robot_arm_animation.py | 3 +- docs/examples/viz_roi_contour.py | 2 +- docs/examples/viz_sdf_cylinder.py | 30 +- docs/examples/viz_sdfactor.py | 6 +- docs/examples/viz_selection.py | 21 +- docs/examples/viz_shader.py | 14 +- docs/examples/viz_shapes.py | 4 +- docs/examples/viz_skinning.py | 8 +- docs/examples/viz_slice.py | 58 +- docs/examples/viz_solar_system.py | 106 ++-- docs/examples/viz_sphere.py | 2 +- docs/examples/viz_spiky.py | 4 +- docs/examples/viz_spinbox.py | 26 +- docs/examples/viz_spline_interpolator.py | 2 +- docs/examples/viz_surfaces.py | 10 +- docs/examples/viz_tab.py | 53 +- docs/examples/viz_tesseract.py | 4 +- docs/examples/viz_texture.py | 4 +- docs/examples/viz_timeline.py | 3 +- docs/examples/viz_timers.py | 3 +- docs/examples/viz_ui.py | 48 +- docs/examples/viz_ui_listbox.py | 13 +- docs/examples/viz_ui_slider.py | 23 +- docs/examples/viz_using_time_equations.py | 5 +- docs/examples/viz_widget.py | 4 +- docs/examples/viz_wrecking_ball.py | 8 +- docs/source/conf.py | 206 ++++--- docs/source/ext/apigen.py | 155 +++-- docs/source/ext/build_modref_templates.py | 40 +- docs/source/ext/github.py | 71 ++- docs/source/ext/github_tools.py | 314 ++++++----- docs/source/ext/prepare_gallery.py | 59 +- docs/source/ext/rstjinja.py | 4 +- docs/source/ext/scrap.py | 15 +- docs/upload_to_gh-pages.py | 85 ++- fury/__init__.py | 53 +- fury/actor.py | 595 ++++++++------------ fury/actors/odf_slicer.py | 63 +-- fury/actors/peak.py | 77 ++- fury/actors/tensor.py | 180 +++--- fury/actors/tests/test_peak.py | 6 +- fury/animation/__init__.py | 6 + fury/animation/animation.py | 201 +++---- fury/animation/helpers.py | 5 +- fury/animation/interpolator.py | 54 +- fury/animation/tests/test_helpers.py | 22 +- fury/animation/tests/test_interpolators.py | 124 ++-- fury/animation/tests/test_timeline.py | 1 - fury/animation/timeline.py | 59 +- fury/colormap.py | 151 ++--- fury/convert.py | 10 +- fury/data/__init__.py | 28 +- fury/data/fetcher.py | 477 +++++++++------- fury/data/tests/test_fetcher.py | 54 +- fury/decorators.py | 15 +- fury/deprecator.py | 105 ++-- fury/gltf.py | 299 ++++------ fury/interactor.py | 154 +++-- fury/io.py | 149 +++-- fury/layout.py | 87 ++- fury/material.py | 333 +++++++---- fury/molecular.py | 100 ++-- fury/optpkg.py | 11 +- fury/pick.py | 95 ++-- fury/pkg_info.py | 18 +- fury/primitive.py | 126 ++--- fury/shaders/__init__.py | 18 +- fury/shaders/base.py | 124 ++-- fury/shaders/tests/test_base.py | 60 +- fury/stream/client.py | 78 +-- fury/stream/constants.py | 42 +- fury/stream/server/__init__.py | 2 +- fury/stream/server/async_app.py | 162 +++--- fury/stream/server/main.py | 13 +- fury/stream/tools.py | 104 +--- fury/stream/widget.py | 39 +- fury/testing.py | 74 ++- fury/tests/test_actors.py | 338 ++++++----- fury/tests/test_colormap.py | 27 +- fury/tests/test_convert.py | 14 +- fury/tests/test_deprecator.py | 204 +++---- fury/tests/test_gltf.py | 95 ++-- fury/tests/test_interactor.py | 114 ++-- fury/tests/test_io.py | 98 ++-- fury/tests/test_layout.py | 69 +-- fury/tests/test_material.py | 37 +- fury/tests/test_molecular.py | 69 ++- fury/tests/test_optpkg.py | 38 +- fury/tests/test_pick.py | 76 ++- fury/tests/test_primitive.py | 30 +- fury/tests/test_stream.py | 70 +-- fury/tests/test_testing.py | 45 +- fury/tests/test_thread.py | 27 +- fury/tests/test_transform.py | 2 +- fury/tests/test_utils.py | 100 ++-- fury/tests/test_window.py | 89 ++- fury/transform.py | 57 +- fury/ui/__init__.py | 53 +- fury/ui/containers.py | 167 +++--- fury/ui/core.py | 147 ++--- fury/ui/elements.py | 572 ++++++++++--------- fury/ui/helpers.py | 36 +- fury/ui/tests/test_containers.py | 145 +++-- fury/ui/tests/test_core.py | 145 ++--- fury/ui/tests/test_elements.py | 515 ++++++++--------- fury/ui/tests/test_elements_callback.py | 20 +- fury/ui/tests/test_helpers.py | 82 +-- fury/utils.py | 165 ++---- fury/window.py | 185 +++--- pyproject.toml | 16 +- ruff.toml | 33 +- 163 files changed, 5286 insertions(+), 5407 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 764d78acb..000000000 --- a/.flake8 +++ /dev/null @@ -1,14 +0,0 @@ -[flake8] -max-line-length = 88 -ignore = D100,D101,D102,D103,D104,D105,D200,D201,D202,D204,D205,D208,D209,D210,D300,D301,D400,D401,D403,E24,E121,E123,E126,E226,E266,E402,E704,E731,F821,I100,I101,I201,N802,N803,N804,N806,W503,W504,W605, E203 -exclude = - .git - __pycache__ - build - dist - fury/_version.py - docs/source/conf.py - docs/experimental - *test* - *sphinx* - */__init__.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dec382b2e..988c0ad67 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,15 +16,6 @@ repos: - id: detect-aws-credentials args: [--allow-missing-credentials] - id: detect-private-key - # - repo: https://github.com/grantjenks/blue - # rev: v0.9.1 - # hooks: - # - id: blue - - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - exclude: "^(docs/experimental|tools)/" - repo: https://github.com/codespell-project/codespell rev: v2.2.2 hooks: @@ -47,8 +38,10 @@ repos: args: ["fury"] pass_filenames: false - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.7 + rev: v0.4.3 hooks: # Run the linter - id: ruff - args: [ --fix ] + args: [ --fix] + # Run the formatter + - id: ruff-format diff --git a/docs/examples/collision-particles.py b/docs/examples/collision-particles.py index c93167615..1eedb520e 100644 --- a/docs/examples/collision-particles.py +++ b/docs/examples/collision-particles.py @@ -24,7 +24,6 @@ def box_edges(box_lx, box_ly, box_lz): - edge1 = 0.5 * np.array( [ [box_lx, box_ly, box_lz], @@ -54,7 +53,6 @@ def collision(): sec = int(num_vertices / num_particles) for i, j in np.ndindex(num_particles, num_particles): - if i == j: continue distance = np.linalg.norm(xyz[i] - xyz[j]) @@ -148,7 +146,7 @@ def collision(): counter = itertools.count() vertices = utils.vertices_from_actor(sphere_actor) -vcolors = utils.colors_from_actor(sphere_actor, 'colors') +vcolors = utils.colors_from_actor(sphere_actor, "colors") no_vertices_per_sphere = len(vertices) / num_particles initial_vertices = vertices.copy() - np.repeat(xyz, no_vertices_per_sphere, axis=0) @@ -177,4 +175,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(showm.scene, size=(900, 768), out_path='simple_collisions.png') +window.record(showm.scene, size=(900, 768), out_path="simple_collisions.png") diff --git a/docs/examples/viz_advanced.py b/docs/examples/viz_advanced.py index c6d815ba7..bf28b0b91 100644 --- a/docs/examples/viz_advanced.py +++ b/docs/examples/viz_advanced.py @@ -46,19 +46,19 @@ # ``af left`` (left arcuate fasciculus) and maps, e.g. FA for a specific # subject. -res = read_bundles_2_subjects('subj_1', ['t1', 'fa'], ['af.left', 'cst.right', 'cc_1']) +res = read_bundles_2_subjects("subj_1", ["t1", "fa"], ["af.left", "cst.right", "cc_1"]) ############################################################################### # We will use 3 bundles, FA and the affine transformation that brings the voxel # coordinates to world coordinates (RAS 1mm). -streamlines = Streamlines(res['af.left']) -streamlines.extend(res['cst.right']) -streamlines.extend(res['cc_1']) +streamlines = Streamlines(res["af.left"]) +streamlines.extend(res["cst.right"]) +streamlines.extend(res["cc_1"]) -data = res['fa'] +data = res["fa"] shape = data.shape -affine = res['affine'] +affine = res["affine"] ############################################################################### # With our current design it is easy to decide in which space you want the @@ -134,7 +134,7 @@ min_value=0, max_value=shape[2] - 1, initial_value=shape[2] / 2, - text_template='{value:.0f}', + text_template="{value:.0f}", length=140, ) @@ -142,7 +142,7 @@ min_value=0, max_value=shape[0] - 1, initial_value=shape[0] / 2, - text_template='{value:.0f}', + text_template="{value:.0f}", length=140, ) @@ -150,7 +150,7 @@ min_value=0, max_value=shape[1] - 1, initial_value=shape[1] / 2, - text_template='{value:.0f}', + text_template="{value:.0f}", length=140, ) @@ -197,8 +197,8 @@ def build_label(text): label = ui.TextBlock2D() label.message = text label.font_size = 18 - label.font_family = 'Arial' - label.justification = 'left' + label.font_family = "Arial" + label.justification = "left" label.bold = False label.italic = False label.shadow = False @@ -208,15 +208,15 @@ def build_label(text): return label -line_slider_label_z = build_label(text='Z Slice') -line_slider_label_x = build_label(text='X Slice') -line_slider_label_y = build_label(text='Y Slice') -opacity_slider_label = build_label(text='Opacity') +line_slider_label_z = build_label(text="Z Slice") +line_slider_label_x = build_label(text="X Slice") +line_slider_label_y = build_label(text="Y Slice") +opacity_slider_label = build_label(text="Opacity") ############################################################################### # 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 = 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)) @@ -262,15 +262,13 @@ def win_callback(obj, _event): scene.reset_clipping_range() if interactive: - show_m.add_window_callback(win_callback) show_m.render() show_m.start() else: - window.record( - scene, out_path='bundles_and_3_slices.png', size=(1200, 900), reset_camera=False + scene, out_path="bundles_and_3_slices.png", size=(1200, 900), reset_camera=False ) del show_m diff --git a/docs/examples/viz_animated_surfaces.py b/docs/examples/viz_animated_surfaces.py index 2ff361e0e..da166421c 100644 --- a/docs/examples/viz_animated_surfaces.py +++ b/docs/examples/viz_animated_surfaces.py @@ -24,8 +24,7 @@ # the z coordinate is a function of time. -def update_surface(x, y, equation, cmap_name='viridis'): - +def update_surface(x, y, equation, cmap_name="viridis"): # z is the function F i.e. F(x, y, t) z = eval(equation) xyz = np.vstack([x, y, z]).T @@ -100,17 +99,17 @@ def create_surface(x, y, equation, colormap_name): ############################################################################### # Equations to be plotted -eq1 = 'np.abs(np.sin(x*2*np.pi*np.cos(time/2)))**1*np.cos(time/2)*\ - np.abs(np.cos(y*2*np.pi*np.sin(time/2)))**1*np.sin(time/2)*1.2' -eq2 = '((x**2 - y**2)/(x**2 + y**2))**(2)*np.cos(6*np.pi*x*y-1.8*time)*0.24' -eq3 = '(np.sin(np.pi*2*x-np.sin(1.8*time))*np.cos(np.pi*2*y+np.cos(1.8*time)))\ - *0.48' -eq4 = 'np.cos(24*np.sqrt(x**2 + y**2) - 2*time)*0.18' +eq1 = "np.abs(np.sin(x*2*np.pi*np.cos(time/2)))**1*np.cos(time/2)*\ + np.abs(np.cos(y*2*np.pi*np.sin(time/2)))**1*np.sin(time/2)*1.2" +eq2 = "((x**2 - y**2)/(x**2 + y**2))**(2)*np.cos(6*np.pi*x*y-1.8*time)*0.24" +eq3 = "(np.sin(np.pi*2*x-np.sin(1.8*time))*np.cos(np.pi*2*y+np.cos(1.8*time)))\ + *0.48" +eq4 = "np.cos(24*np.sqrt(x**2 + y**2) - 2*time)*0.18" equations = [eq1, eq2, eq3, eq4] ############################################################################### # List of colormaps to be used for the various functions. -cmap_names = ['hot', 'plasma', 'viridis', 'ocean'] +cmap_names = ["hot", "plasma", "viridis", "ocean"] ############################################################################### # Creating a list of surfaces. @@ -137,7 +136,7 @@ def create_surface(x, y, equation, colormap_name): text = [] for i in range(4): t_actor = actor.vector_text( - 'Function ' + str(i + 1), pos=(0, 0, 0), scale=(0.17, 0.2, 0.2) + "Function " + str(i + 1), pos=(0, 0, 0), scale=(0.17, 0.2, 0.2) ) text.append(t_actor) @@ -159,7 +158,7 @@ def create_surface(x, y, equation, colormap_name): ############################################################################### # Initializing text box to print the title of the animation tb = ui.TextBlock2D(bold=True, position=(200, 60)) -tb.message = 'Animated 2D functions' +tb.message = "Animated 2D functions" scene.add(tb) ############################################################################### @@ -207,4 +206,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(showm.scene, size=(600, 600), out_path='viz_animated_surfaces.png') +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 f65c6bf8e..bd6ac3845 100644 --- a/docs/examples/viz_arrow.py +++ b/docs/examples/viz_arrow.py @@ -50,4 +50,4 @@ if interactive: window.show(scene, size=(600, 600)) -window.record(scene, out_path='viz_arrow.png', size=(600, 600)) +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 517673a2e..dd991cf8c 100644 --- a/docs/examples/viz_ball_collide.py +++ b/docs/examples/viz_ball_collide.py @@ -9,6 +9,7 @@ First some imports. """ + import itertools import numpy as np @@ -86,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 = 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) @@ -122,7 +123,7 @@ def timer_callback(_obj, _event): # Get various collision information using `p.getContactPoints`. contact = p.getContactPoints(red_ball, blue_ball, -1, -1) if len(contact) != 0: - tb.message = 'Collision!!' + tb.message = "Collision!!" p.stepSimulation() @@ -137,4 +138,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, size=(900, 700), out_path='viz_ball_collide.png') +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 241370a62..1e833b4c2 100644 --- a/docs/examples/viz_bezier_interpolator.py +++ b/docs/examples/viz_bezier_interpolator.py @@ -5,6 +5,7 @@ Keyframe animation using cubic Bezier interpolator. """ + import numpy as np from fury import actor, window @@ -44,19 +45,19 @@ # 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]} +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( - np.array([keyframe_1.get('value'), keyframe_2.get('value')]), (1, 0, 0), radii=0.3 + np.array([keyframe_1.get("value"), keyframe_2.get("value")]), (1, 0, 0), radii=0.3 ) ############################################################################### # Visualizing the control points cps_actor = actor.sphere( - np.array([keyframe_2.get('in_cp'), keyframe_1.get('out_cp')]), (0, 0, 1), radii=0.6 + np.array([keyframe_2.get("in_cp"), keyframe_1.get("out_cp")]), (0, 0, 1), radii=0.6 ) ############################################################################### @@ -86,10 +87,10 @@ # will be the same as the position itself. animation.set_position( - 0.0, np.array(keyframe_1.get('value')), out_cp=np.array(keyframe_1.get('out_cp')) + 0.0, np.array(keyframe_1.get("value")), out_cp=np.array(keyframe_1.get("out_cp")) ) animation.set_position( - 5.0, np.array(keyframe_2.get('value')), in_cp=np.array(keyframe_2.get('in_cp')) + 5.0, np.array(keyframe_2.get("value")), in_cp=np.array(keyframe_2.get("in_cp")) ) ############################################################################### @@ -109,7 +110,7 @@ if interactive: showm.start() -window.record(scene, out_path='viz_keyframe_animation_bezier_1.png', size=(900, 768)) +window.record(scene, out_path="viz_keyframe_animation_bezier_1.png", size=(900, 768)) ############################################################################### # A more complex scene scene @@ -126,9 +127,9 @@ # point it controls. keyframes = { # time - position - in control point - out control point - 0.0: {'value': [-2, 0, 0], 'out_cp': [-15, 6, 0]}, - 5.0: {'value': [18, 0, 0], 'in_cp': [27, 18, 0], 'out_cp': [27, -18, 0]}, - 9.0: {'value': [-5, -10, -10]}, + 0.0: {"value": [-2, 0, 0], "out_cp": [-15, 6, 0]}, + 5.0: {"value": [18, 0, 0], "in_cp": [27, 18, 0], "out_cp": [27, -18, 0]}, + 9.0: {"value": [-5, -10, -10]}, } ############################################################################### @@ -149,10 +150,10 @@ ########################################################################### # visualizing the points and control points (only for demonstration) -for t, keyframe in keyframes.items(): - pos = keyframe.get('value') - in_control_point = keyframe.get('in_cp') - out_control_point = keyframe.get('out_cp') +for keyframe in keyframes.values(): + pos = keyframe.get("value") + in_control_point = keyframe.get("in_cp") + out_control_point = keyframe.get("out_cp") ########################################################################### # visualizing position keyframe @@ -181,4 +182,4 @@ if interactive: show_manager.start() -window.record(scene, out_path='viz_keyframe_animation_bezier_2.png', size=(900, 768)) +window.record(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 10bc5b698..e9c61e41c 100644 --- a/docs/examples/viz_billboard_sdf_spheres.py +++ b/docs/examples/viz_billboard_sdf_spheres.py @@ -51,15 +51,24 @@ # ============================ # FURY provides an easy way to create sphere glyphs from numpy arrays as # follows: -centers = np.array([ - [0, 0, 0], [-6, -6, -6], [8, 8, 8], [8.5, 9.5, 9.5], [10, -10, 10], - [-13, 13, -13], [-17, -17, 17]]) -colors = np.array([ - [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, .2, .7, 3, 2]) +centers = np.array( + [ + [0, 0, 0], + [-6, -6, -6], + [8, 8, 8], + [8.5, 9.5, 9.5], + [10, -10, 10], + [-13, 13, -13], + [-17, -17, 17], + ] +) +colors = np.array( + [[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( - centers, colors, radii=scales, phi=8, theta=8, use_primitive=False) + centers, colors, radii=scales, phi=8, theta=8, use_primitive=False +) ############################################################################### # To interactively visualize the recently created actors, we only need to add @@ -72,7 +81,7 @@ if interactive: window.show(scene) else: - window.record(scene, size=(600, 600), out_path='viz_regular_spheres.png') + 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 @@ -84,20 +93,21 @@ if interactive: window.show(scene) else: - window.record(scene, size=(600, 600), out_path='viz_low_res_wireframe.png') + 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( - centers, colors, radii=scales, phi=16, theta=16, use_primitive=False) + 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) else: - window.record(scene, size=(600, 600), out_path='viz_hi_res_wireframe.png') + 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 @@ -128,8 +138,7 @@ if interactive: window.show(scene) else: - window.record( - scene, size=(600, 600), out_path='viz_billboards_wireframe.png') + 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 @@ -141,23 +150,22 @@ ############################################################################### # FURY already includes a shader function with the definition of a Signed # Distance Sphere. So we can load it and use it like this: -sd_sphere = import_fury_shader(os.path.join('sdf', 'sd_sphere.frag')) +sd_sphere = import_fury_shader(os.path.join("sdf", "sd_sphere.frag")) ############################################################################### # Additionally, we need to define the radii of our spheres. Since we prefer # these to be determined by the billboards' size, we will use the maximum # radius distance allowed by our billboards. -sphere_radius = 'const float RADIUS = 1.;' +sphere_radius = "const float RADIUS = 1.;" ############################################################################### # Let's calculate the distance to the sphere by combining the previously # defined variables. -sphere_dist = 'float dist = sdSphere(point, RADIUS);' +sphere_dist = "float dist = sdSphere(point, RADIUS);" ############################################################################### # Now, evaluate the signed distance function. -sdf_eval = \ - """ +sdf_eval = """ if (dist < 0) fragOutput0 = vec4(color, opacity); else @@ -173,14 +181,14 @@ ############################################################################### # We are ready to create and visualize our SDF-billboard actors. spheres_actor = actor.billboard( - centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl) + centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl +) scene.add(spheres_actor) if interactive: window.show(scene) else: - window.record( - scene, size=(600, 600), out_path='viz_billboards_circles.png') + 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 @@ -195,14 +203,12 @@ # into detail in the gradient and derivatives of SDFs, so we will use the # central differences technique implemented in the following FURY shader # function: -central_diffs_normal = import_fury_shader( - os.path.join('sdf', 'central_diffs.frag')) +central_diffs_normal = import_fury_shader(os.path.join("sdf", "central_diffs.frag")) ############################################################################### # To use the central differences technique, we need to define a map function # that wraps our SDF and evaluates only a point. -sd_sphere_normal = \ - """ +sd_sphere_normal = """ float map(vec3 p) { return sdSphere(p, RADIUS); @@ -212,14 +218,21 @@ ############################################################################### # Then we can load the Blinn-Phong illumination model. blinn_phong_model = import_fury_shader( - os.path.join('lighting', 'blinn_phong_model.frag')) + os.path.join("lighting", "blinn_phong_model.frag") +) ############################################################################### # Again, let's bring all of our declarations (constants and functions) # together. -fs_dec = compose_shader([ - sphere_radius, sd_sphere, sd_sphere_normal, central_diffs_normal, - blinn_phong_model]) +fs_dec = compose_shader( + [ + sphere_radius, + sd_sphere, + sd_sphere_normal, + central_diffs_normal, + blinn_phong_model, + ] +) ############################################################################### # Now, we can start our fragment shader implementation with the signed distance @@ -227,49 +240,48 @@ # if statement but a `step` function, which is a more efficient way to perform # this evaluation. You can also replace the `step` function with a `smoothstep` # operation and, in that way, add a very efficient form of antialiasing. -sdf_eval = 'opacity *= 1 - step(0, dist);' +sdf_eval = "opacity *= 1 - step(0, dist);" ############################################################################### # In this case, we also need the absolute value of the distance to compensate # for the depth of the SDF sphere. -abs_dist = 'float absDist = abs(dist);' +abs_dist = "float absDist = abs(dist);" ############################################################################### # We are ready to calculate the normals. -normal = 'vec3 normal = centralDiffsNormals(vec3(point.xy, absDist), .0001);' +normal = "vec3 normal = centralDiffsNormals(vec3(point.xy, absDist), .0001);" ############################################################################### # With the normals we can calculate a light attenuation factor. -light_attenuation = 'float lightAttenuation = normal.z;' +light_attenuation = "float lightAttenuation = normal.z;" ############################################################################### # Now, we are ready to calculate the color and output it. -color = \ - """ +color = """ color = blinnPhongIllumModel( lightAttenuation, lightColor0, diffuseColor, specularPower, specularColor, ambientColor); """ -frag_output = 'fragOutput0 = vec4(color, opacity);' +frag_output = "fragOutput0 = vec4(color, opacity);" ############################################################################### # As before, we can bring our implementation code together. -fs_impl = compose_shader([ - sphere_dist, sdf_eval, abs_dist, normal, light_attenuation, color, - frag_output]) +fs_impl = compose_shader( + [sphere_dist, sdf_eval, abs_dist, normal, light_attenuation, color, frag_output] +) ############################################################################### # Finally, recreate the SDF billboard actors and visualize them. spheres_actor = actor.billboard( - centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl) + centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl +) scene.add(spheres_actor) if interactive: window.show(scene) else: - window.record( - scene, size=(600, 600), out_path='viz_billboards_spheres.png') + window.record(scene, size=(600, 600), out_path="viz_billboards_spheres.png") ############################################################################### # References diff --git a/docs/examples/viz_brick_wall.py b/docs/examples/viz_brick_wall.py index b61166f18..4d490450e 100644 --- a/docs/examples/viz_brick_wall.py +++ b/docs/examples/viz_brick_wall.py @@ -9,6 +9,7 @@ First some imports. """ + import itertools import numpy as np @@ -230,7 +231,7 @@ def sync_actor(actor, multibody): fpss = np.array([]) tb = ui.TextBlock2D( - text='Avg. FPS: \nSim Steps: ', position=(0, 680), font_size=30, color=(1, 0.5, 0) + text="Avg. FPS: \nSim Steps: ", position=(0, 680), font_size=30, color=(1, 0.5, 0) ) scene.add(tb) @@ -259,7 +260,7 @@ def timer_callback(_obj, _event): fps = showm.frame_rate fpss = np.append(fpss, fps) tb.message = ( - 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + "Avg. FPS: " + str(np.round(np.mean(fpss), 0)) + "\nSim Steps: " + str(cnt) ) # Get the position and orientation of the ball. @@ -299,4 +300,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, out_path='viz_brick_wall.png', size=(900, 768)) +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 8150bc28c..65880f900 100644 --- a/docs/examples/viz_brownian_motion.py +++ b/docs/examples/viz_brownian_motion.py @@ -50,21 +50,21 @@ def particle( colors, - origin=[0, 0, 0], - num_total_steps=300, - total_time=5, - delta=1.8, - path_thickness=3, + _origin=origin, + _num_total_steps=num_total_steps, + _total_time=total_time, + _delta=delta, + _path_thickness=path_thickness, ): - origin = np.asarray(origin, dtype=float) - position = np.tile(origin, (num_total_steps, 1)) - path_actor = actor.line([position], colors, linewidth=path_thickness) + _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.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.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.no_vertices_per_point = len(path_actor.vertices) / num_total_steps + 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 ) @@ -130,7 +130,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.message = 'Brownian Motion' +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') +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 849b57043..092f292de 100644 --- a/docs/examples/viz_bundles.py +++ b/docs/examples/viz_bundles.py @@ -17,23 +17,23 @@ fetch_bundles_2_subjects() dix = read_bundles_2_subjects( - subj_id='subj_1', metrics=['fa'], bundles=['cg.left', 'cst.right'] + subj_id="subj_1", metrics=["fa"], bundles=["cg.left", "cst.right"] ) ############################################################################### # Store fractional anisotropy. -fa = dix['fa'] +fa = dix["fa"] ############################################################################### # Store grid to world transformation matrix. -affine = dix['affine'] +affine = dix["affine"] ############################################################################### # Store the cingulum bundle. A bundle is a list of streamlines. -bundle = dix['cg.left'] +bundle = dix["cg.left"] ############################################################################### # It happened that this bundle is in world coordinates and therefore we need to @@ -63,7 +63,7 @@ if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='bundle1.png', size=(600, 600)) +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 @@ -93,7 +93,7 @@ if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='bundle2.png', size=(600, 600)) +window.record(scene, out_path="bundle2.png", size=(600, 600)) ############################################################################## # Show every point with a value from a volume with your colormap @@ -117,7 +117,7 @@ if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='bundle3.png', size=(600, 600)) +window.record(scene, out_path="bundle3.png", size=(600, 600)) ############################################################################### # Show every bundle with a specific color @@ -134,7 +134,7 @@ if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='bundle4.png', size=(600, 600)) +window.record(scene, out_path="bundle4.png", size=(600, 600)) ############################################################################### # Show every streamline of a bundle with a different color @@ -168,7 +168,7 @@ if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='bundle5.png', size=(600, 600)) +window.record(scene, out_path="bundle5.png", size=(600, 600)) ############################################################################### # Show every point of every streamline with a different color @@ -189,7 +189,7 @@ if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='bundle6.png', size=(600, 600)) +window.record(scene, out_path="bundle6.png", size=(600, 600)) ############################################################################### # Add depth cues to streamline rendering @@ -210,7 +210,7 @@ if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='bundle7.png', size=(600, 600)) +window.record(scene, out_path="bundle7.png", size=(600, 600)) ############################################################################### # Render streamlines as fake tubes @@ -228,7 +228,7 @@ if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='bundle8.png', size=(600, 600)) +window.record(scene, out_path="bundle8.png", size=(600, 600)) ############################################################################### # Combine depth cues with fake tubes @@ -247,7 +247,7 @@ if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='bundle9.png', size=(600, 600)) +window.record(scene, out_path="bundle9.png", size=(600, 600)) ############################################################################### # Render streamlines as tubes @@ -267,7 +267,7 @@ if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='bundle10.png', size=(600, 600)) +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 58eaf8d0a..8d89b74ce 100644 --- a/docs/examples/viz_buttons.py +++ b/docs/examples/viz_buttons.py @@ -9,6 +9,7 @@ First, some imports. """ + from fury import ui, window from fury.data import fetch_viz_icons, read_viz_icons @@ -21,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 = 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 = ui.TextBlock2D(text="Click me") +text2 = ui.TextBlock2D(text="Me too") panel.add_element(text, (50, 100)) panel.add_element(text2, (180, 100)) @@ -41,14 +42,14 @@ button_example = ui.Button2D( - icon_fnames=[('square', read_viz_icons(fname='stop2.png'))] + icon_fnames=[("square", 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", 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"))) second_button_example = ui.Button2D(icon_fnames=icon_files) @@ -61,7 +62,7 @@ def change_text_callback(i_ren, _obj, _button): - text.message = 'Clicked!' + text.message = "Clicked!" i_ren.force_render() @@ -78,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 = window.ShowManager(size=current_size, title="FURY Button Example") show_manager.scene.add(panel) @@ -87,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') +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 6593a7a4a..ba67dfb2f 100644 --- a/docs/examples/viz_camera.py +++ b/docs/examples/viz_camera.py @@ -60,7 +60,7 @@ ############################################################################### # Creating "FURY" text # ==================== -fury_text = actor.vector_text('FURY', pos=(-4.3, 15, 0), scale=(2, 2, 2)) +fury_text = actor.vector_text("FURY", pos=(-4.3, 15, 0), scale=(2, 2, 2)) ############################################################################### # Creating an ``Animation`` to animate the opacity of ``fury_text`` @@ -81,7 +81,7 @@ # ================================= # -for i in range(50): +for _ in range(50): ########################################################################### # create a sphere actor that's centered at the origin and has random color # and radius. @@ -176,4 +176,4 @@ if interactive: showm.start() -window.record(scene, out_path='viz_keyframe_animation_camera.png', size=(900, 768)) +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 61dbb5834..579a65fb9 100644 --- a/docs/examples/viz_card.py +++ b/docs/examples/viz_card.py @@ -8,6 +8,7 @@ First, some imports. """ + from fury import ui, window from fury.data import fetch_viz_icons @@ -19,27 +20,35 @@ ############################################################################### # Let's create a card and add it to the show manager -img_url = "https://raw.githubusercontent.com/fury-gl"\ - "/fury-communication-assets/main/fury-logo.png" +img_url = ( + "https://raw.githubusercontent.com/fury-gl" + "/fury-communication-assets/main/fury-logo.png" +) title = "FURY" -body = "FURY - Free Unified Rendering in pYthon."\ - "A software library for scientific visualization in Python." - -card = ui.elements.Card2D(image_path=img_url, title_text=title, - body_text=body, - image_scale=0.55, size=(300, 300), - bg_color=(1, 0.294, 0.180), - bg_opacity=0.8, border_width=5, - border_color=(0.1, 0.4, 0.4)) +body = ( + "FURY - Free Unified Rendering in pYthon." + "A software library for scientific visualization in Python." +) + +card = ui.elements.Card2D( + image_path=img_url, + title_text=title, + body_text=body, + image_scale=0.55, + size=(300, 300), + bg_color=(1, 0.294, 0.180), + bg_opacity=0.8, + border_width=5, + border_color=(0.1, 0.4, 0.4), +) ############################################################################### # Now that the card has been initialised, we add it to the show # manager. current_size = (1000, 1000) -show_manager = window.ShowManager(size=current_size, - title="FURY Card Example") +show_manager = window.ShowManager(size=current_size, title="FURY Card Example") show_manager.scene.add(card) # To interact with the UI, set interactive = True diff --git a/docs/examples/viz_card_sprite_sheet.py b/docs/examples/viz_card_sprite_sheet.py index a0840c811..eb7465a5e 100644 --- a/docs/examples/viz_card_sprite_sheet.py +++ b/docs/examples/viz_card_sprite_sheet.py @@ -9,6 +9,7 @@ First, some imports. """ + import os from tempfile import TemporaryDirectory as InTemporaryDirectory @@ -24,28 +25,40 @@ fetch_viz_icons() -sprite_sheet = load_sprite_sheet('https://raw.githubusercontent.com/fury-gl/' - 'fury-data/master/unittests/fury_sprite.png', - 5, 5) +sprite_sheet = load_sprite_sheet( + "https://raw.githubusercontent.com/fury-gl/" + "fury-data/master/unittests/fury_sprite.png", + 5, + 5, +) CURRENT_SPRITE_IDX = 0 vtk_sprites = [] ############################################################################### # Let's create a card and add it to the show manager -img_url = "https://raw.githubusercontent.com/fury-gl"\ - "/fury-communication-assets/main/fury-logo.png" +img_url = ( + "https://raw.githubusercontent.com/fury-gl" + "/fury-communication-assets/main/fury-logo.png" +) title = "FURY" -body = "FURY - Free Unified Rendering in pYthon."\ - "A software library for scientific visualization in Python." - -card = ui.elements.Card2D(image_path=img_url, title_text=title, - body_text=body, - image_scale=0.55, size=(300, 300), - bg_color=(1, 0.294, 0.180), - bg_opacity=0.8, border_width=5, - border_color=(0.1, 0.4, 0.8)) +body = ( + "FURY - Free Unified Rendering in pYthon." + "A software library for scientific visualization in Python." +) + +card = ui.elements.Card2D( + image_path=img_url, + title_text=title, + body_text=body, + image_scale=0.55, + size=(300, 300), + bg_color=(1, 0.294, 0.180), + bg_opacity=0.8, + border_width=5, + border_color=(0.1, 0.4, 0.8), +) ############################################################################### # Now we define the callback to update the image on card after some delay. @@ -56,11 +69,11 @@ def timer_callback(_obj, _evt): CURRENT_SPRITE_IDX += 1 sprite = vtk_sprites[CURRENT_SPRITE_IDX % len(vtk_sprites)] card.image.set_img(sprite) - i_ren = show_manager.scene.GetRenderWindow()\ - .GetInteractor().GetInteractorStyle() + i_ren = show_manager.scene.GetRenderWindow().GetInteractor().GetInteractorStyle() i_ren.force_render() + ############################################################################### # Lets create a function to convert the sprite to vtkImageData @@ -68,7 +81,7 @@ def timer_callback(_obj, _evt): def sprite_to_vtk(): with InTemporaryDirectory() as tdir: for idx, sprite in enumerate(list(sprite_sheet.values())): - sprite_path = os.path.join(tdir, f'{idx}.png') + sprite_path = os.path.join(tdir, f"{idx}.png") save_image(sprite, sprite_path, compression_quality=100) vtk_sprite = load_image(sprite_path, as_vtktype=True) vtk_sprites.append(vtk_sprite) @@ -79,8 +92,7 @@ def sprite_to_vtk(): # manager. current_size = (1000, 1000) -show_manager = window.ShowManager(size=current_size, - title="FURY Card Example") +show_manager = window.ShowManager(size=current_size, title="FURY Card Example") show_manager.scene.add(card) show_manager.initialize() diff --git a/docs/examples/viz_chain.py b/docs/examples/viz_chain.py index f9898c240..fc3502924 100644 --- a/docs/examples/viz_chain.py +++ b/docs/examples/viz_chain.py @@ -8,6 +8,7 @@ First some imports. """ + import itertools import numpy as np @@ -163,6 +164,7 @@ ############################################################################### # We define a couple of syncing methods for the base and chain. + # Function for syncing actors with multi-bodies. def sync_actor(actor, multibody): pos, orn = p.getBasePositionAndOrientation(multibody) @@ -204,7 +206,7 @@ def sync_joints(actor_list, multibody): fpss = np.array([]) tb = ui.TextBlock2D( - position=(0, 680), font_size=30, color=(1, 0.5, 0), text='Avg. FPS: \nSim Steps: ' + position=(0, 680), font_size=30, color=(1, 0.5, 0), text="Avg. FPS: \nSim Steps: " ) scene.add(tb) @@ -227,7 +229,7 @@ def timer_callback(_obj, _event): fps = showm.frame_rate fpss = np.append(fpss, fps) tb.message = ( - 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + "Avg. FPS: " + str(np.round(np.mean(fpss), 0)) + "\nSim Steps: " + str(cnt) ) # some trajectory @@ -262,4 +264,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, size=(900, 768), out_path='viz_chain.png') +window.record(scene, size=(900, 768), out_path="viz_chain.png") diff --git a/docs/examples/viz_check_boxes.py b/docs/examples/viz_check_boxes.py index 99c9fada1..4caed6c4b 100644 --- a/docs/examples/viz_check_boxes.py +++ b/docs/examples/viz_check_boxes.py @@ -90,9 +90,9 @@ def toggle_color(checkboxes): color_array = np.array([0, 0, 0]) for col in colors: - if col == 'Red': + if col == "Red": color_array[0] = 255 - elif col == 'Green': + elif col == "Green": color_array[1] = 255 else: color_array[2] = 255 @@ -104,26 +104,26 @@ def toggle_color(checkboxes): # We define a dictionary to store the actors with their names as keys. # A checkbox is created with actor names as it's options. -figure_dict = {'cube': cube, 'sphere': sphere, 'cone': cone, 'arrow': arrow} +figure_dict = {"cube": cube, "sphere": sphere, "cone": cone, "arrow": arrow} check_box = ui.Checkbox( list(figure_dict), list(figure_dict), padding=1, font_size=18, - font_family='Arial', + font_family="Arial", position=(400, 85), ) ############################################################################### # A similar checkbox is created for changing colors. -options = {'Blue': (0, 0, 1), 'Red': (1, 0, 0), 'Green': (0, 1, 0)} +options = {"Blue": (0, 0, 1), "Red": (1, 0, 0), "Green": (0, 1, 0)} color_toggler = ui.Checkbox( list(options), - checked_labels=['Blue'], + checked_labels=["Blue"], padding=1, font_size=16, - font_family='Arial', + font_family="Arial", position=(600, 120), ) @@ -140,7 +140,7 @@ def toggle_color(checkboxes): # manager. current_size = (1000, 1000) -show_manager = window.ShowManager(size=current_size, title='FURY Checkbox Example') +show_manager = window.ShowManager(size=current_size, title="FURY Checkbox Example") show_manager.scene.add(cube) show_manager.scene.add(sphere) @@ -161,4 +161,4 @@ def toggle_color(checkboxes): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path='viz_checkbox.png') +window.record(show_manager.scene, size=current_size, out_path="viz_checkbox.png") diff --git a/docs/examples/viz_color_interpolators.py b/docs/examples/viz_color_interpolators.py index a7347ef8b..af90f4aca 100644 --- a/docs/examples/viz_color_interpolators.py +++ b/docs/examples/viz_color_interpolators.py @@ -41,11 +41,11 @@ ############################################################################### # Static labels for different interpolators (for show) -linear_text = actor.vector_text('Linear', (-2.64, -1, 0)) -lab_text = actor.vector_text('LAB', (-0.37, -1, 0)) -hsv_text = actor.vector_text('HSV', (1.68, -1, 0)) -xyz_text = actor.vector_text('XYZ', (3.6, -1, 0)) -step_text = actor.vector_text('Step', (5.7, -1, 0)) +linear_text = actor.vector_text("Linear", (-2.64, -1, 0)) +lab_text = actor.vector_text("LAB", (-0.37, -1, 0)) +hsv_text = actor.vector_text("HSV", (1.68, -1, 0)) +xyz_text = actor.vector_text("XYZ", (3.6, -1, 0)) +step_text = actor.vector_text("Step", (5.7, -1, 0)) scene.add(step_text, lab_text, linear_text, hsv_text, xyz_text) ############################################################################### @@ -108,4 +108,4 @@ if interactive: showm.start() -window.record(scene, out_path='viz_keyframe_animation_colors.png', size=(900, 768)) +window.record(scene, out_path="viz_keyframe_animation_colors.png", size=(900, 768)) diff --git a/docs/examples/viz_combobox.py b/docs/examples/viz_combobox.py index c6a6f5687..5b41808a9 100644 --- a/docs/examples/viz_combobox.py +++ b/docs/examples/viz_combobox.py @@ -8,6 +8,7 @@ First, some imports. """ + from fury import ui, window from fury.data import fetch_viz_icons @@ -23,9 +24,9 @@ position=(200, 300), font_size=40, color=(1, 0.5, 0), - justification='center', - vertical_justification='top', - text='FURY rocks!!!', + justification="center", + vertical_justification="top", + text="FURY rocks!!!", ) ######################################################################## @@ -33,13 +34,13 @@ # RGB values as its value. colors = { - 'Violet': (0.6, 0, 0.8), - 'Indigo': (0.3, 0, 0.5), - 'Blue': (0, 0, 1), - 'Green': (0, 1, 0), - 'Yellow': (1, 1, 0), - 'Orange': (1, 0.5, 0), - 'Red': (1, 0, 0), + "Violet": (0.6, 0, 0.8), + "Indigo": (0.3, 0, 0.5), + "Blue": (0, 0, 1), + "Green": (0, 1, 0), + "Yellow": (1, 1, 0), + "Orange": (1, 0.5, 0), + "Red": (1, 0, 0), } ######################################################################## @@ -50,7 +51,7 @@ color_combobox = ui.ComboBox2D( items=list(colors.keys()), - placeholder='Choose Text Color', + placeholder="Choose Text Color", position=(75, 50), size=(250, 150), ) @@ -77,7 +78,7 @@ def change_color(combobox): # Now we add label and combobox to the scene. current_size = (400, 400) -showm = window.ShowManager(size=current_size, title='ComboBox UI Example') +showm = window.ShowManager(size=current_size, title="ComboBox UI Example") showm.scene.add(label, color_combobox) # To interact with the UI, set interactive = True @@ -86,4 +87,4 @@ def change_color(combobox): if interactive: showm.start() -window.record(showm.scene, out_path='combobox_ui.png', size=(400, 400)) +window.record(showm.scene, out_path="combobox_ui.png", size=(400, 400)) diff --git a/docs/examples/viz_cone.py b/docs/examples/viz_cone.py index 188bafbfc..1ca7d2ca7 100644 --- a/docs/examples/viz_cone.py +++ b/docs/examples/viz_cone.py @@ -44,4 +44,4 @@ if interactive: window.show(scene, size=(600, 600)) -window.record(scene, out_path='viz_cone.png', size=(600, 600)) +window.record(scene, out_path="viz_cone.png", size=(600, 600)) diff --git a/docs/examples/viz_custom_interpolator.py b/docs/examples/viz_custom_interpolator.py index 067b45b80..1e30d70a3 100644 --- a/docs/examples/viz_custom_interpolator.py +++ b/docs/examples/viz_custom_interpolator.py @@ -5,6 +5,7 @@ Keyframe animation using custom interpolator. """ + import numpy as np from fury import actor, window @@ -66,11 +67,11 @@ def tan_cubic_spline_interpolator(keyframes): # Setting the tangent to a zero vector in this case is the best choice for time in keyframes: data = keyframes.get(time) - value = data.get('value') - if data.get('in_tangent') is None: - data['in_tangent'] = np.zeros_like(value) - if data.get('in_tangent') is None: - data['in_tangent'] = np.zeros_like(value) + value = data.get("value") + if data.get("in_tangent") is None: + data["in_tangent"] = np.zeros_like(value) + if data.get("in_tangent") is None: + data["in_tangent"] = np.zeros_like(value) def interpolate(t): # `get_previous_timestamp`and `get_next_timestamp` functions take @@ -96,10 +97,10 @@ def interpolate(t): # {'value': array(1, 1, 1), 'custom_field': array(2, 3, 1)} # # now we continue with the cubic spline equation. - p0 = keyframes.get(t0).get('value') - tan_0 = keyframes.get(t0).get('out_tangent') * time_delta - p1 = keyframes.get(t1).get('value') - tan_1 = keyframes.get(t1).get('in_tangent') * time_delta + p0 = keyframes.get(t0).get("value") + tan_0 = keyframes.get(t0).get("out_tangent") * time_delta + p1 = keyframes.get(t1).get("value") + tan_1 = keyframes.get(t1).get("in_tangent") * time_delta # cubic spline equation using tangents t2 = dt * dt t3 = t2 * dt @@ -163,4 +164,4 @@ def interpolate(t): if interactive: showm.start() -window.record(scene, out_path='viz_keyframe_custom_interpolator.png', size=(900, 768)) +window.record(scene, out_path="viz_keyframe_custom_interpolator.png", size=(900, 768)) diff --git a/docs/examples/viz_domino.py b/docs/examples/viz_domino.py index 8316c96eb..9bb54afa4 100644 --- a/docs/examples/viz_domino.py +++ b/docs/examples/viz_domino.py @@ -9,6 +9,7 @@ First some imports. """ + import itertools import numpy as np @@ -173,7 +174,7 @@ def sync_domino(object_index, multibody): fpss = np.array([]) tb = ui.TextBlock2D( - text='Avg. FPS: \nSim Steps: ', position=(0, 680), font_size=30, color=(1, 0.5, 0) + text="Avg. FPS: \nSim Steps: ", position=(0, 680), font_size=30, color=(1, 0.5, 0) ) scene.add(tb) @@ -202,7 +203,7 @@ def timer_callback(_obj, _event): fps = showm.frame_rate fpss = np.append(fpss, fps) tb.message = ( - 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + "Avg. FPS: " + str(np.round(np.mean(fpss), 0)) + "\nSim Steps: " + str(cnt) ) # Get the position and orientation of the first domino. @@ -243,4 +244,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, out_path='viz_domino.png', size=(900, 768)) +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 f872b5870..6b5295ebe 100644 --- a/docs/examples/viz_drawpanel.py +++ b/docs/examples/viz_drawpanel.py @@ -8,6 +8,7 @@ First, some imports. """ + from fury import ui, window from fury.data import fetch_viz_new_icons @@ -28,7 +29,7 @@ # Now we add DrawPanel to the scene. current_size = (650, 650) -showm = window.ShowManager(size=current_size, title='DrawPanel UI Example') +showm = window.ShowManager(size=current_size, title="DrawPanel UI Example") showm.scene.add(drawing_canvas) @@ -38,8 +39,8 @@ showm.start() else: # If the UI isn't interactive, then adding a circle to the canvas - drawing_canvas.current_mode = 'circle' - drawing_canvas.draw_shape(shape_type='circle', current_position=(275, 275)) + drawing_canvas.current_mode = "circle" + 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') + 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 82c2362d0..f9e7ec5ab 100644 --- a/docs/examples/viz_dt_ellipsoids.py +++ b/docs/examples/viz_dt_ellipsoids.py @@ -10,6 +10,7 @@ We start by importing the necessary modules: """ + import itertools from dipy.io.image import load_nifti @@ -31,12 +32,12 @@ # 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(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")) ############################################################################### # Using tensor_slicer actor @@ -48,13 +49,14 @@ # 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 = prim_sphere("repulsion100", True) ############################################################################### # As we need to provide a sphere object we create a class Sphere to which we # assign the values obtained from vertices and faces. + class Sphere: def __init__(self, vertices, faces): self.vertices = vertices @@ -68,8 +70,9 @@ 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(evals=slice_evals, evecs=slice_evecs, - sphere=sphere100, scale=.3) +tensor_slice = actor.tensor_slicer( + evals=slice_evals, evecs=slice_evecs, sphere=sphere100, scale=0.3 +) ############################################################################### # Next, we set up a new scene to add and visualize the tensor ellipsoids @@ -88,7 +91,7 @@ def __init__(self, vertices, faces): if interactive: showm.start() -window.record(showm.scene, size=(600, 600), out_path='tensor_slice_100.png') +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 @@ -103,8 +106,12 @@ def __init__(self, vertices, faces): showm.render() showm.start() -window.record(showm.scene, out_path='tensor_slice_100_zoom.png', - size=(600, 300), reset_camera=False) +window.record( + showm.scene, + out_path="tensor_slice_100_zoom.png", + size=(600, 300), + reset_camera=False, +) ############################################################################### # To render the same tensor slice using a different sphere we redefine the @@ -127,6 +134,7 @@ def __init__(self, vertices, faces): # function to facilitate the correct setting of the parameters before passing # them to the actor. + def get_params(evecs, evals): # We define the centers which corresponds to the ellipsoids positions. valid_mask = np.abs(evecs).max(axis=(-2, -1)) > 0 @@ -158,14 +166,15 @@ def get_params(evecs, evals): # Now, we can use the ``ellipsoid`` actor to create the tensor ellipsoids as # follows. -tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs, - lengths=evals, scales=.6) +tensors = actor.ellipsoid( + centers=centers, colors=colors, axes=evecs, lengths=evals, scales=0.6 +) showm.scene.add(tensors) if interactive: showm.start() -window.record(scene, size=(600, 600), out_path='tensor_slice_sdf.png') +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 @@ -183,8 +192,12 @@ def get_params(evecs, evals): showm.render() showm.start() -window.record(showm.scene, out_path='tensor_slice_sdf_zoom.png', - size=(600, 300), reset_camera=False) +window.record( + showm.scene, + out_path="tensor_slice_sdf_zoom.png", + size=(600, 300), + reset_camera=False, +) showm.scene.clear() showm.scene.pitch(-90) @@ -201,7 +214,9 @@ def get_params(evecs, evals): # We first set up the required data and create the actors. mevals = np.array([1.4, 1.0, 0.35]) * 10 ** (-3) -mevecs = np.array([[2/3, -2/3, 1/3], [1/3, 2/3, 2/3], [2/3, 1/3, -2/3]]) +mevecs = np.array( + [[2 / 3, -2 / 3, 1 / 3], [1 / 3, 2 / 3, 2 / 3], [2 / 3, 1 / 3, -2 / 3]] +) evals = np.zeros((1, 1, 1, 3)) evecs = np.zeros((1, 1, 1, 3, 3)) @@ -209,32 +224,39 @@ def get_params(evecs, evals): evals[..., :] = mevals evecs[..., :, :] = mevecs -vertices, faces = prim_sphere('repulsion200', True) +vertices, faces = prim_sphere("repulsion200", True) sphere200 = Sphere(vertices, faces) -vertices, faces = prim_sphere('repulsion724', True) +vertices, faces = 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 = 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) centers, evecs, evals, colors = get_params(evecs=evecs, evals=evals) -tensor_sdf = actor.ellipsoid(centers=centers, axes=evecs, lengths=evals, - colors=colors, scales=2.0) +tensor_sdf = actor.ellipsoid( + centers=centers, axes=evecs, lengths=evals, colors=colors, scales=2.0 +) ############################################################################### # Next, we made use of `GridUI` which allows us to add the actors in a grid and # interact with them individually. 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')] - -grid_ui = ui.GridUI(actors=objects, captions=text, cell_padding=.1, - caption_offset=(-0.7, -2.5, 0), dim=(1, 4)) +text = [ + actor.vector_text("Tensor 100"), + actor.vector_text("Tensor 200"), + actor.vector_text("Tensor 724"), + actor.vector_text("Tensor SDF"), +] + +grid_ui = ui.GridUI( + actors=objects, + captions=text, + cell_padding=0.1, + caption_offset=(-0.7, -2.5, 0), + dim=(1, 4), +) scene = window.Scene() scene.background([255, 255, 255]) @@ -246,8 +268,13 @@ def get_params(evecs, evals): if interactive: showm.start() -window.record(showm.scene, size=(560, 200), out_path='tensor_comparison.png', - reset_camera=False, magnification=2) +window.record( + showm.scene, + size=(560, 200), + out_path="tensor_comparison.png", + reset_camera=False, + magnification=2, +) showm.scene.clear() @@ -258,12 +285,12 @@ 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(evals=roi_evals, evecs=roi_evecs, - sphere=sphere100, scale=.3) +tensor_roi = actor.tensor_slicer( + evals=roi_evals, evecs=roi_evecs, sphere=sphere100, scale=0.3 +) data_shape = roi_evals.shape[:3] -tensor_roi.display_extent( - 0, data_shape[0], 0, data_shape[1], 0, data_shape[2]) +tensor_roi.display_extent(0, data_shape[0], 0, data_shape[1], 0, data_shape[2]) showm.size = (600, 600) showm.scene.background([0, 0, 0]) @@ -273,7 +300,7 @@ def get_params(evecs, evals): if interactive: showm.start() -window.record(showm.scene, size=(600, 600), out_path='tensor_roi_100.png') +window.record(showm.scene, size=(600, 600), out_path="tensor_roi_100.png") showm.scene.clear() @@ -285,14 +312,15 @@ def get_params(evecs, evals): centers, evecs, evals, colors = get_params(roi_evecs, roi_evals) -tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs, - lengths=evals, scales=.6) +tensors = actor.ellipsoid( + centers=centers, colors=colors, axes=evecs, lengths=evals, scales=0.6 +) showm.scene.add(tensors) if interactive: showm.start() -window.record(showm.scene, size=(600, 600), out_path='tensor_roi_sdf.png') +window.record(showm.scene, size=(600, 600), out_path="tensor_roi_sdf.png") showm.scene.clear() @@ -301,8 +329,7 @@ def get_params(evecs, evals): # the whole brain, which contains a much larger amount of data, to be exact # 184512 tensor ellipsoids are displayed at the same time. -centers, evecs, evals, colors = get_params(whole_brain_evecs, - whole_brain_evals) +centers, evecs, evals, colors = get_params(whole_brain_evecs, whole_brain_evals) # We remove all the noise around the brain to have a better visualization. fil = [len(set(elem)) != 1 for elem in evals] @@ -311,8 +338,9 @@ def get_params(evecs, evals): evecs = np.array(list(itertools.compress(evecs, fil))) evals = np.array(list(itertools.compress(evals, fil))) -tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs, - lengths=evals, scales=.6) +tensors = actor.ellipsoid( + centers=centers, colors=colors, axes=evecs, lengths=evals, scales=0.6 +) scene = window.Scene() scene.add(tensors) @@ -322,7 +350,11 @@ def get_params(evecs, evals): if interactive: showm.start() -window.record(showm.scene, size=(600, 600), reset_camera=False, - out_path='tensor_whole_brain_sdf.png') +window.record( + showm.scene, + size=(600, 600), + reset_camera=False, + out_path="tensor_whole_brain_sdf.png", +) showm.scene.clear() diff --git a/docs/examples/viz_earth_animation.py b/docs/examples/viz_earth_animation.py index 38cd7f286..ff430a31b 100644 --- a/docs/examples/viz_earth_animation.py +++ b/docs/examples/viz_earth_animation.py @@ -30,7 +30,7 @@ # image. fetch_viz_textures() -earth_filename = read_viz_textures('1_earth_8k.jpg') +earth_filename = read_viz_textures("1_earth_8k.jpg") earth_image = io.load_image(earth_filename) ############################################################################## @@ -42,7 +42,7 @@ ############################################################################## # Then, do the same for the moon. -moon_filename = read_viz_textures('moon-8k.jpg') +moon_filename = read_viz_textures("moon-8k.jpg") moon_image = io.load_image(moon_filename) moon_actor = actor.texture_on_sphere(moon_image) @@ -100,7 +100,7 @@ # 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 + "Bloomington, Indiana", (-0.42, 0.31, 0.03), window.colors.white, 0.004 ) utils.rotate(text_actor, (-90, 0, 1, 0)) @@ -108,7 +108,7 @@ # 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_filename = read_viz_models("satellite_obj.obj") satellite = io.load_polydata(satellite_filename) satellite_actor = utils.get_actor_from_polydata(satellite) @@ -172,4 +172,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') +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 48232a3c0..3c3c10eec 100644 --- a/docs/examples/viz_earth_coordinates.py +++ b/docs/examples/viz_earth_coordinates.py @@ -23,7 +23,7 @@ scene = window.Scene() fetch_viz_textures() -earth_file = read_viz_textures('1_earth_16k.jpg') +earth_file = read_viz_textures("1_earth_16k.jpg") earth_image = io.load_image(earth_file) earth_actor = actor.texture_on_sphere(earth_image) scene.add(earth_actor) @@ -81,19 +81,19 @@ def latlong_coordinates(lat, lon): # geographical coordinates. nyc_actor = actor.text_3d( - 'New York City, New York\n40.7128° N, 74.0060° W', + "New York City, New York\n40.7128° N, 74.0060° W", (locationone[0] - 0.04, locationone[1], locationone[2] + 0.07), window.colors.white, 0.01, ) paris_actor = actor.text_3d( - 'Paris, France\n48.8566° N, 2.3522° E', + "Paris, France\n48.8566° N, 2.3522° E", (locationthree[0] - 0.04, locationthree[1], locationthree[2] - 0.07), window.colors.white, 0.01, ) beijing_actor = actor.text_3d( - 'Beijing, China\n39.9042° N, 116.4074° E', + "Beijing, China\n39.9042° N, 116.4074° E", (locationtwo[0] - 0.06, locationtwo[1], locationtwo[2] - 0.07), window.colors.white, 0.01, @@ -157,4 +157,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') +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 52beb9735..bfa29b6f3 100644 --- a/docs/examples/viz_emwave_animation.py +++ b/docs/examples/viz_emwave_animation.py @@ -94,14 +94,14 @@ def update_coordinates(wavenumber, ang_frq, time, phase_angle): y = np.sin(wavenumber * x - angular_frq * time + phase_angle) z = np.array([0 for i in range(npoints)]) -pts = np.array([(a, b, c) for (a, b, c) in zip(x, y, z)]) +pts = np.array(list(zip(x, y, z, strict=False))) pts = [pts] colors = window.colors.red wave_actor1 = 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') +vcolors = 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) @@ -113,14 +113,14 @@ def update_coordinates(wavenumber, ang_frq, time, phase_angle): yy = np.array([0 for i in range(npoints)]) zz = np.sin(wavenumber * xx - angular_frq * time + phase_angle) -pts2 = np.array([(a, b, c) for (a, b, c) in zip(xx, yy, zz)]) +pts2 = np.array(list(zip(xx, yy, zz, strict=False))) pts2 = [pts2] colors2 = window.colors.blue wave_actor2 = 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') +vcolors2 = 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) @@ -129,7 +129,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.message = 'Electromagnetic Wave' +tb.message = "Electromagnetic Wave" scene.add(tb) ############################################################################### @@ -154,12 +154,12 @@ def timer_callback(_obj, _event): cnt = next(counter) x, y, z = update_coordinates(wavenumber, angular_frq, phase_angle, time) - pts = np.array([(a, b, c) for (a, b, c) in zip(x, y, z)]) + pts = np.array(list(zip(x, y, z, strict=False))) vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0) utils.update_actor(wave_actor1) xx, zz, yy = update_coordinates(wavenumber, angular_frq, phase_angle, time) - pts2 = np.array([(a, b, c) for (a, b, c) in zip(xx, yy, zz)]) + pts2 = np.array(list(zip(xx, yy, zz, strict=False))) vertices2[:] = initial_vertices2 + np.repeat(pts2, no_vertices_per_point2, axis=0) utils.update_actor(wave_actor2) @@ -178,4 +178,4 @@ def timer_callback(_obj, _event): interactive = False if interactive: showm.start() -window.record(showm.scene, size=(800, 600), out_path='viz_emwave.png') +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 de1470234..ac327aa7f 100644 --- a/docs/examples/viz_fiber_odf.py +++ b/docs/examples/viz_fiber_odf.py @@ -24,7 +24,7 @@ fetch_viz_dmri() fetch_viz_icons() -fodf_img = nib.load(read_viz_dmri('fodf.nii.gz')) +fodf_img = nib.load(read_viz_dmri("fodf.nii.gz")) sh = fodf_img.get_fdata() affine = fodf_img.affine grid_shape = sh.shape[:-1] @@ -33,7 +33,7 @@ # We then define a low resolution sphere used to visualize SH coefficients # as spherical functions (SF) as well as a matrix `B_low` to project SH # onto the sphere. -sphere_low = get_sphere('repulsion100') +sphere_low = get_sphere("repulsion100") B_low = sh_to_sf_matrix(sphere_low, 8, return_inv=False) ############################################################################### @@ -111,7 +111,7 @@ min_value=0, max_value=grid_shape[2] - 1, initial_value=grid_shape[2] / 2, - text_template='{value:.0f}', + text_template="{value:.0f}", length=140, ) @@ -119,7 +119,7 @@ min_value=0, max_value=grid_shape[1] - 1, initial_value=grid_shape[1] / 2, - text_template='{value:.0f}', + text_template="{value:.0f}", length=140, ) @@ -127,14 +127,14 @@ min_value=0, max_value=grid_shape[0] - 1, initial_value=grid_shape[0] / 2, - text_template='{value:.0f}', + text_template="{value:.0f}", length=140, ) ############################################################################### # We also define a high resolution sphere to demonstrate the capability to # dynamically change the sphere used for SH to SF projection. -sphere_high = get_sphere('symmetric362') +sphere_high = get_sphere("symmetric362") # 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. @@ -144,8 +144,8 @@ ############################################################################### # We add a combobox for choosing the sphere resolution during execution. sphere_dict = { - 'Low resolution': (sphere_low, B_low), - 'High resolution': (sphere_high, B_high), + "Low resolution": (sphere_low, B_low), + "High resolution": (sphere_high, B_high), } combobox = ui.ComboBox2D(items=list(sphere_dict)) scene.add(combobox) @@ -161,12 +161,12 @@ def change_slice_z(slider): def change_slice_y(slider): i = int(np.round(slider.value)) - odf_actor_y.slice_along_axis(i, 'yaxis') + odf_actor_y.slice_along_axis(i, "yaxis") def change_slice_x(slider): i = int(np.round(slider.value)) - odf_actor_x.slice_along_axis(i, 'xaxis') + odf_actor_x.slice_along_axis(i, "xaxis") def change_sphere(combobox): @@ -189,8 +189,8 @@ def build_label(text): label = ui.TextBlock2D() label.message = text label.font_size = 18 - label.font_family = 'Arial' - label.justification = 'left' + label.font_family = "Arial" + label.justification = "left" label.bold = False label.italic = False label.shadow = False @@ -200,11 +200,11 @@ def build_label(text): return label -line_slider_label_z = build_label(text='Z Slice') -line_slider_label_y = build_label(text='Y Slice') -line_slider_label_x = build_label(text='X Slice') +line_slider_label_z = build_label(text="Z Slice") +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 = 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)) @@ -246,7 +246,7 @@ def win_callback(obj, _event): show_m.start() else: window.record( - scene, out_path='odf_slicer_3D.png', size=(1200, 900), reset_camera=False + scene, out_path="odf_slicer_3D.png", size=(1200, 900), reset_camera=False ) del show_m diff --git a/docs/examples/viz_fine_tuning_gl_context.py b/docs/examples/viz_fine_tuning_gl_context.py index 8b3dec517..2f11ee588 100644 --- a/docs/examples/viz_fine_tuning_gl_context.py +++ b/docs/examples/viz_fine_tuning_gl_context.py @@ -29,21 +29,21 @@ actor_no_depth_test = actor.markers( centers, - marker='s', + marker="s", colors=colors, marker_opacity=0.5, scales=0.2, ) actor_normal_blending = actor.markers( centers - np.array([[0, -0.5, 0]]), - marker='s', + marker="s", colors=colors, marker_opacity=0.5, scales=0.2, ) actor_add_blending = actor.markers( centers - np.array([[0, -1, 0]]), - marker='s', + marker="s", colors=colors, marker_opacity=0.5, scales=0.2, @@ -51,14 +51,14 @@ actor_sub_blending = actor.markers( centers - np.array([[0, -1.5, 0]]), - marker='s', + marker="s", colors=colors, marker_opacity=0.5, scales=0.2, ) actor_mul_blending = actor.markers( centers - np.array([[0, -2, 0]]), - marker='s', + marker="s", colors=colors, marker_opacity=0.5, scales=0.2, @@ -150,4 +150,4 @@ def timer_callback(obj, event): if interactive: showm.start() -window.record(scene, out_path='viz_fine_tuning_gl_context.png', size=(600, 600)) +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 4c5c40113..acbd3061e 100644 --- a/docs/examples/viz_fractals.py +++ b/docs/examples/viz_fractals.py @@ -221,7 +221,7 @@ def gen_centers(depth, pos, center, side): # the Scene and ShowManager. scene = window.Scene() -showmgr = window.ShowManager(scene, 'Fractals', (800, 800), reset_camera=True) +showmgr = window.ShowManager(scene, "Fractals", (800, 800), reset_camera=True) ############################################################################### # These values are what work nicely on my machine without lagging. If you have @@ -235,16 +235,16 @@ def gen_centers(depth, pos, center, side): # fractals and add the selected one. This also resets the camera. options = { - 'Tetrix': 0, - 'Sponge': 1, - 'Snowflake': 2, + "Tetrix": 0, + "Sponge": 1, + "Snowflake": 2, } shape_chooser = ui.RadioButton( options.keys(), padding=10, font_size=16, - checked_labels=['Tetrix'], + checked_labels=["Tetrix"], position=(10, 10), ) @@ -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)) + 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 fd64cacad..8d1c50ca4 100644 --- a/docs/examples/viz_gltf.py +++ b/docs/examples/viz_gltf.py @@ -17,8 +17,8 @@ ############################################################################## # Retrieving the gltf model. -fetch_gltf('Duck', 'glTF') -filename = read_viz_gltf('Duck') +fetch_gltf("Duck", "glTF") +filename = read_viz_gltf("Duck") ############################################################################## # Initialize the glTF object and get actors using `actors` method. @@ -46,4 +46,4 @@ if interactive: window.show(scene, size=(1280, 720)) -window.record(scene, out_path='viz_gltf.png', size=(1280, 720)) +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 18fdc8b41..a7bf84ced 100644 --- a/docs/examples/viz_gltf_animated.py +++ b/docs/examples/viz_gltf_animated.py @@ -23,8 +23,8 @@ ############################################################################## # Retrieving the gltf model. -fetch_gltf('InterpolationTest', 'glTF') -filename = read_viz_gltf('InterpolationTest') +fetch_gltf("InterpolationTest", "glTF") +filename = read_viz_gltf("InterpolationTest") ############################################################################## # Initialize the glTF object and get actors using `actors` method. @@ -54,4 +54,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, out_path='viz_gltf_animated.png', size=(900, 768)) +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 6595c91cf..9d54a2f8a 100644 --- a/docs/examples/viz_gltf_export.py +++ b/docs/examples/viz_gltf_export.py @@ -4,6 +4,7 @@ ============================== In this tutorial, we will show how to create a glTF file for a scene. """ + import numpy as np from fury import actor, gltf, window @@ -30,8 +31,8 @@ sphere = actor.sphere(np.add(centers, np.array([0, 2, 0])), colors=colors) scene.add(sphere) -fetch_gltf('BoxTextured', 'glTF') -filename = read_viz_gltf('BoxTextured') +fetch_gltf("BoxTextured", "glTF") +filename = read_viz_gltf("BoxTextured") gltf_obj = gltf.glTF(filename) box_actor = gltf_obj.actors() scene.add(box_actor[0]) @@ -46,12 +47,12 @@ ############################################################################## # Exporting scene as a glTF file -gltf.export_scene(scene, filename='viz_gltf_export.gltf') +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 = gltf.glTF("viz_gltf_export.gltf") actors = gltf_obj.actors() ############################################################################## @@ -64,4 +65,4 @@ if interactive: window.show(scene, size=(1280, 720)) -window.record(scene, out_path='viz_gltf_export.png', size=(1280, 720)) +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 891bffeb0..b17f319ff 100644 --- a/docs/examples/viz_helical_motion.py +++ b/docs/examples/viz_helical_motion.py @@ -96,7 +96,7 @@ scene.add(charge_actor) vertices = utils.vertices_from_actor(charge_actor) -vcolors = utils.colors_from_actor(charge_actor, 'colors') +vcolors = 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) @@ -105,8 +105,8 @@ # Initializing text box to display the name of the animation tb = ui.TextBlock2D(bold=True, position=(100, 90)) -m1 = 'Motion of a charged particle in a ' -m2 = 'combined electric and magnetic field' +m1 = "Motion of a charged particle in a " +m2 = "combined electric and magnetic field" tb.message = m1 + m2 scene.add(tb) @@ -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') +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 35c9b454d..8b727e708 100644 --- a/docs/examples/viz_hierarchical_animation.py +++ b/docs/examples/viz_hierarchical_animation.py @@ -5,6 +5,7 @@ Creating hierarchical keyframes animation in fury """ + import numpy as np from fury import actor, window @@ -140,5 +141,5 @@ showm.start() window.record( - scene, out_path='viz_keyframe_hierarchical_animation.png', size=(900, 768) + 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 4775626cd..7becb5964 100644 --- a/docs/examples/viz_interaction.py +++ b/docs/examples/viz_interaction.py @@ -44,7 +44,7 @@ # multiprocessing.set_start_method('spawn') from fury.stream.server.main import WEBRTC_AVAILABLE, web_server, web_server_raw_array -if __name__ == '__main__': +if __name__ == "__main__": interactive = False # `use_raw_array` is a flag to tell the server to use python RawArray # instead of SharedMemory which is a new feature in python 3.8 @@ -100,7 +100,7 @@ stream_interaction.circular_queue.head_tail_buffer, stream_interaction.circular_queue.buffer._buffer, 8000, - 'localhost', + "localhost", True, WEBRTC_AVAILABLE, ), @@ -115,7 +115,7 @@ stream_interaction.circular_queue.head_tail_buffer_name, stream_interaction.circular_queue.buffer.buffer_name, 8000, - 'localhost', + "localhost", True, WEBRTC_AVAILABLE, ), @@ -143,4 +143,4 @@ stream.cleanup() stream_interaction.cleanup() - window.record(showm.scene, size=window_size, out_path='viz_interaction.png') + 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 6a63c112b..d6793bb18 100644 --- a/docs/examples/viz_interpolators.py +++ b/docs/examples/viz_interpolators.py @@ -20,10 +20,10 @@ from fury.animation.interpolator import cubic_spline_interpolator keyframes = { - 1.0: {'value': np.array([0, 0, 0])}, - 2.0: {'value': np.array([-4, 1, 0])}, - 5.0: {'value': np.array([0, 0, 12])}, - 6.0: {'value': np.array([25, 0, 12])}, + 1.0: {"value": np.array([0, 0, 0])}, + 2.0: {"value": np.array([-4, 1, 0])}, + 5.0: {"value": np.array([0, 0, 12])}, + 6.0: {"value": np.array([25, 0, 12])}, } ############################################################################### @@ -133,4 +133,4 @@ if interactive: showm.start() -window.record(scene, out_path='viz_keyframe_interpolator.png', size=(900, 768)) +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 86b5fa3d4..f3b2673bf 100644 --- a/docs/examples/viz_introduction.py +++ b/docs/examples/viz_introduction.py @@ -55,7 +55,6 @@ # For this tutorial, we are going to use the FURY animation module to translate # FURY sphere actor. - import numpy as np from fury import actor, window @@ -114,5 +113,5 @@ showm.start() window.record( - scene, out_path='viz_keyframe_animation_introduction.png', size=(900, 768) + 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 98270c66e..c7fd19e92 100644 --- a/docs/examples/viz_layout.py +++ b/docs/examples/viz_layout.py @@ -24,22 +24,22 @@ ############################################################################### # Now we create two listboxes -listbox_1 = ui.ListBox2D(size=(150, 150), values=['First', 'Second', 'Third']) +listbox_1 = ui.ListBox2D(size=(150, 150), values=["First", "Second", "Third"]) -listbox_2 = ui.ListBox2D(size=(250, 250), values=['First', 'Second', 'Third']) +listbox_2 = 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']) +listbox = 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)) +square_grid = GridLayout(cell_shape="square", position_offset=(0, 300, 0)) +diagonal_grid = GridLayout(cell_shape="diagonal", position_offset=(0, 600, 0)) ############################################################################### @@ -50,7 +50,7 @@ diagonal_grid.apply([slider, listbox]) current_size = (1500, 1500) -show_manager = window.ShowManager(size=current_size, title='FURY UI Layout') +show_manager = 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 +60,4 @@ if interactive: show_manager.start() -window.record(show_manager.scene, out_path='ui_layout.png', size=(400, 400)) +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 6f2849569..600296c2d 100644 --- a/docs/examples/viz_markers.py +++ b/docs/examples/viz_markers.py @@ -5,6 +5,7 @@ This example shows how to use the marker actor. """ + import numpy as np from fury import actor, window @@ -15,7 +16,7 @@ # There are nine types 2d markers: circle, square, diamond, triangle, pentagon, # hexagon, heptagon, cross and plus. -marker_symbols = ['o', 's', 'd', '^', 'p', 'h', 's6', 'x', '+'] +marker_symbols = ["o", "s", "d", "^", "p", "h", "s6", "x", "+"] markers = [np.random.choice(marker_symbols) for i in range(n)] centers = np.random.normal(size=(n, 3), scale=10) @@ -39,7 +40,7 @@ nodes_3d_actor = actor.markers( centers + np.ones_like(centers) * 25, - marker='3d', + marker="3d", colors=colors, scales=0.5, ) @@ -54,4 +55,4 @@ if interactive: window.show(scene, size=(600, 600)) -window.record(scene, out_path='viz_markers.png', size=(600, 600)) +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 02f4e931f..9bf996759 100644 --- a/docs/examples/viz_morphing.py +++ b/docs/examples/viz_morphing.py @@ -13,8 +13,8 @@ # 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') +fetch_gltf("MorphStressTest", "glTF") +filename = read_viz_gltf("MorphStressTest") ############################################################################## # Initializing the glTF object, You can additionally set `apply_normals=True`. @@ -27,7 +27,7 @@ # name you want to visualize. # Note: If there's no name for animation, It's stored as `anim_0`, `anim_1` etc -animation = gltf_obj.morph_animation()['TheWave'] +animation = gltf_obj.morph_animation()["TheWave"] ############################################################################## # Call the `update_morph` method once, This moves initialise the morphing at @@ -71,4 +71,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, out_path='viz_morphing.png', size=(900, 768)) +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 33f0bf8c0..33060f75f 100644 --- a/docs/examples/viz_multithread.py +++ b/docs/examples/viz_multithread.py @@ -44,16 +44,16 @@ # Create a function to print a counter to the console def print_counter(): - print('') + print("") for i in range(100): - print('\rCounter: %d' % i, end='') + print("\rCounter: %d" % i, end="") message = "Let's count up to 100 and exit :" + str(i + 1) tb.message = message time.sleep(0.05) if showm.is_done(): break showm.exit() - print('') + print("") # Create a function to rotate the camera diff --git a/docs/examples/viz_network.py b/docs/examples/viz_network.py index 38dbdca64..13140a96f 100644 --- a/docs/examples/viz_network.py +++ b/docs/examples/viz_network.py @@ -100,7 +100,7 @@ if interactive: window.show(scene, size=(600, 600)) -window.record(scene, out_path='journal_networks.png', size=(600, 600)) +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 ffcb5c7bd..d68a19e4c 100644 --- a/docs/examples/viz_network_animated.py +++ b/docs/examples/viz_network_animated.py @@ -255,4 +255,4 @@ def _timer(_obj, _event): showm.start() -window.record(showm.scene, size=(900, 768), out_path='viz_animated_networks.png') +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 ae51e9f49..d68b70076 100644 --- a/docs/examples/viz_no_interaction.py +++ b/docs/examples/viz_no_interaction.py @@ -17,8 +17,7 @@ from fury.stream.client import FuryStreamClient from fury.stream.server.main import web_server_raw_array -if __name__ == '__main__': - +if __name__ == "__main__": interactive = False ########################################################################### # First we will set the resolution which it'll be used by the streamer @@ -53,7 +52,7 @@ sphere_actor = actor.sdf( centers=positions, colors=colors, - primitives='sphere', + primitives="sphere", scales=radii * 0.5, ) @@ -101,4 +100,4 @@ stream.stop() stream.cleanup() - window.record(showm.scene, size=window_size, out_path='viz_no_interaction.png') + 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 2bee8e0e7..3238e8ac5 100644 --- a/docs/examples/viz_pbr_interactive.py +++ b/docs/examples/viz_pbr_interactive.py @@ -106,7 +106,7 @@ def win_callback(obj, event): # The following function returns the full path of the 6 images composing the # skybox. -textures = read_viz_cubemap('skybox') +textures = read_viz_cubemap("skybox") ############################################################################### # Now that we have the location of the textures, let's load them and create a @@ -166,32 +166,32 @@ def win_callback(obj, event): # We will create one single panel with all of our labels and sliders. control_panel = ui.Panel2D( - (400, 500), position=(5, 5), color=(0.25, 0.25, 0.25), opacity=0.75, align='right' + (400, 500), position=(5, 5), color=(0.25, 0.25, 0.25), opacity=0.75, align="right" ) ############################################################################### # 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_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( - text='Anisotropy Rotation', font_size=16 + text="Anisotropy Rotation", font_size=16 ) slider_label_anisotropy_direction_x = ui.TextBlock2D( - text='Anisotropy Direction X', font_size=16 + text="Anisotropy Direction X", font_size=16 ) slider_label_anisotropy_direction_y = ui.TextBlock2D( - text='Anisotropy Direction Y', font_size=16 + text="Anisotropy Direction Y", font_size=16 ) slider_label_anisotropy_direction_z = ui.TextBlock2D( - text='Anisotropy Direction Z', font_size=16 + 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 = 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) control_panel.add_element(slider_label_metallic, (0.01, 0.95)) control_panel.add_element(slider_label_roughness, (0.01, 0.86)) @@ -212,37 +212,37 @@ def win_callback(obj, event): initial_value=pbr_params.metallic, max_value=1, length=195, - text_template='{value:.1f}', + text_template="{value:.1f}", ) slider_slice_roughness = ui.LineSlider2D( initial_value=pbr_params.roughness, max_value=1, length=195, - text_template='{value:.1f}', + text_template="{value:.1f}", ) slider_slice_anisotropy = ui.LineSlider2D( initial_value=pbr_params.anisotropy, max_value=1, length=195, - text_template='{value:.1f}', + text_template="{value:.1f}", ) slider_slice_anisotropy_rotation = ui.LineSlider2D( initial_value=pbr_params.anisotropy_rotation, max_value=1, length=195, - text_template='{value:.1f}', + text_template="{value:.1f}", ) slider_slice_coat_strength = ui.LineSlider2D( initial_value=pbr_params.coat_strength, max_value=1, length=195, - text_template='{value:.1f}', + text_template="{value:.1f}", ) slider_slice_coat_roughness = ui.LineSlider2D( initial_value=pbr_params.coat_roughness, max_value=1, length=195, - text_template='{value:.1f}', + text_template="{value:.1f}", ) ############################################################################### @@ -255,21 +255,21 @@ def win_callback(obj, event): min_value=-1, max_value=1, length=195, - text_template='{value:.1f}', + text_template="{value:.1f}", ) slider_slice_anisotropy_direction_y = ui.LineSlider2D( initial_value=doa[1], min_value=-1, max_value=1, length=195, - text_template='{value:.1f}', + text_template="{value:.1f}", ) slider_slice_anisotropy_direction_z = ui.LineSlider2D( initial_value=doa[2], min_value=-1, max_value=1, length=195, - text_template='{value:.1f}', + text_template="{value:.1f}", ) ############################################################################### @@ -282,14 +282,14 @@ def win_callback(obj, event): min_value=1, max_value=2.3, length=195, - text_template='{value:.02f}', + text_template="{value:.02f}", ) slider_slice_coat_ior = ui.LineSlider2D( initial_value=pbr_params.coat_ior, min_value=1, max_value=2.3, length=195, - text_template='{value:.02f}', + text_template="{value:.02f}", ) ############################################################################### @@ -343,4 +343,4 @@ def win_callback(obj, event): if interactive: show_m.start() -window.record(scene, size=(1920, 1080), out_path='viz_pbr_interactive.png') +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 05f401b03..318fcc51e 100644 --- a/docs/examples/viz_pbr_spheres.py +++ b/docs/examples/viz_pbr_spheres.py @@ -35,15 +35,15 @@ # These subset of parameters have their values constrained in the 0 to 1 range. material_params = [ - [[1, 1, 0], {'metallic': 0, 'roughness': 0}], - [(0, 0, 1), {'roughness': 0}], - [(1, 0, 1), {'anisotropy': 0, 'metallic': 0.25, 'roughness': 0.5}], + [[1, 1, 0], {"metallic": 0, "roughness": 0}], + [(0, 0, 1), {"roughness": 0}], + [(1, 0, 1), {"anisotropy": 0, "metallic": 0.25, "roughness": 0.5}], [ (1, 0, 1), - {'anisotropy_rotation': 0, 'anisotropy': 1, 'metallic': 0.25, 'roughness': 0.5}, + {"anisotropy_rotation": 0, "anisotropy": 1, "metallic": 0.25, "roughness": 0.5}, ], - [(0, 1, 1), {'coat_strength': 0, 'roughness': 0}], - [(0, 1, 1), {'coat_roughness': 0, 'coat_strength': 1, 'roughness': 0}], + [(0, 1, 1), {"coat_strength": 0, "roughness": 0}], + [(0, 1, 1), {"coat_roughness": 0, "coat_strength": 1, "roughness": 0}], ] ############################################################################### @@ -73,17 +73,17 @@ # visualization. labels = [ - 'Metallic', - 'Roughness', - 'Anisotropy', - 'Anisotropy Rotation', - 'Coat Strength', - 'Coat Roughness', + "Metallic", + "Roughness", + "Anisotropy", + "Anisotropy Rotation", + "Coat Strength", + "Coat Roughness", ] -for i, l in enumerate(labels): +for i, name in enumerate(labels): pos = [-40, -5 * i, 0] - label = actor.vector_text(l, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)) + label = 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): @@ -105,14 +105,14 @@ iors = np.round(np.linspace(1, 2.3, num=num_values), decimals=2) ior_params = [ - [(0, 1, 1), {'base_ior': iors[0], 'roughness': 0}], + [(0, 1, 1), {"base_ior": iors[0], "roughness": 0}], [ (0, 1, 1), { - 'coat_ior': iors[0], - 'coat_roughness': 0.1, - 'coat_strength': 1, - 'roughness': 0, + "coat_ior": iors[0], + "coat_roughness": 0.1, + "coat_strength": 1, + "roughness": 0, }, ], ] @@ -132,17 +132,17 @@ ############################################################################### # Let's add the respective labels to the scene. -labels = ['Base IoR', 'Coat IoR'] +labels = ["Base IoR", "Coat IoR"] -for i, l in enumerate(labels): +for i, name in enumerate(labels): pos = [-40, -35 - (5 * i), 0] - label = actor.vector_text(l, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)) + label = 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( - '{:.02f}'.format(iors[j]), pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0) + "{:.02f}".format(iors[j]), pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0) ) scene.add(label) @@ -153,4 +153,4 @@ if interactive: window.show(scene) -window.record(scene, size=(600, 600), out_path='viz_pbr_spheres.png') +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 00b14c5f8..772ca79d5 100644 --- a/docs/examples/viz_picking.py +++ b/docs/examples/viz_picking.py @@ -24,10 +24,10 @@ ############################################################################### # 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 = 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 = ui.TextBlock2D(text="Left click on object \n") panel.add_element(text_block, (0.3, 0.3)) ############################################################################### @@ -35,7 +35,7 @@ scene = window.Scene() -label_actor = actor.vector_text(text='Test') +label_actor = actor.vector_text(text="Test") ############################################################################### # This actor is made with 3 cubes of different orientation @@ -59,7 +59,7 @@ ############################################################################### # Access the memory of the colors of all the cubes -vcolors = utils.colors_from_actor(fury_actor, 'colors') +vcolors = utils.colors_from_actor(fury_actor, "colors") ############################################################################### # Adding an actor showing the axes of the world coordinates @@ -80,13 +80,12 @@ def left_click_callback(obj, event): - # Get the event position on display and pick event_pos = pickm.event_position(showm.iren) picked_info = pickm.pick(event_pos, showm.scene) - vertex_index = picked_info['vertex'] + vertex_index = picked_info["vertex"] # Calculate the objects index @@ -97,11 +96,11 @@ def left_click_callback(obj, event): if not selected[object_index]: scale = 6 / 5 - color_add = np.array([30, 30, 30], dtype='uint8') + color_add = np.array([30, 30, 30], dtype="uint8") selected[object_index] = True else: scale = 5 / 6 - color_add = np.array([-30, -30, -30], dtype='uint8') + color_add = np.array([-30, -30, -30], dtype="uint8") selected[object_index] = False # Update vertices positions @@ -120,14 +119,14 @@ def left_click_callback(obj, event): # Tell actor that memory is modified utils.update_actor(fury_actor) - face_index = picked_info['face'] + face_index = picked_info["face"] # Show some info - text = 'Object ' + str(object_index) + '\n' - text += 'Vertex ID ' + str(vertex_index) + '\n' - text += 'Face ID ' + str(face_index) + '\n' - text += 'World pos ' + str(np.round(picked_info['xyz'], 2)) + '\n' - text += 'Actor ID ' + str(id(picked_info['actor'])) + text = "Object " + str(object_index) + "\n" + text += "Vertex ID " + str(vertex_index) + "\n" + text += "Face ID " + str(face_index) + "\n" + text += "World pos " + str(np.round(picked_info["xyz"], 2)) + "\n" + text += "Actor ID " + str(id(picked_info["actor"])) text_block.message = text showm.render() @@ -135,7 +134,7 @@ def left_click_callback(obj, event): ############################################################################### # Bind the callback to the actor -fury_actor.AddObserver('LeftButtonPressEvent', left_click_callback, 1) +fury_actor.AddObserver("LeftButtonPressEvent", left_click_callback, 1) ############################################################################### # Make the window appear @@ -150,11 +149,10 @@ def left_click_callback(obj, event): interactive = False if interactive: - showm.start() ############################################################################### # Save the current framebuffer in a PNG file -window.record(showm.scene, size=(1024, 768), out_path='viz_picking.png') +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 7437d0582..920d2b1a7 100644 --- a/docs/examples/viz_play_video.py +++ b/docs/examples/viz_play_video.py @@ -85,9 +85,9 @@ def run(self): # Create VideoPlayer Object and run it video_url = ( - 'http://commondatastorage.googleapis.com/' - + 'gtv-videos-bucket/sample/BigBuckBunny.mp4' + "http://commondatastorage.googleapis.com/" + + "gtv-videos-bucket/sample/BigBuckBunny.mp4" ) vp = VideoPlayer(video_url) vp.run() -window.record(vp.show_manager.scene, out_path='viz_play_video.png', size=(600, 600)) +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 6408bfa62..018672433 100644 --- a/docs/examples/viz_principled_spheres.py +++ b/docs/examples/viz_principled_spheres.py @@ -36,16 +36,16 @@ # values between the range 0 to 1. material_params = [ - [(1, 1, 1), {'subsurface': 0}], - [[1, 1, 0], {'metallic': 0}], - [(1, 0, 0), {'specular': 0}], - [(1, 0, 0), {'specular_tint': 0, 'specular': 1}], - [(0, 0, 1), {'roughness': 0}], - [(1, 0, 1), {'anisotropic': 0, 'metallic': 0.25, 'roughness': 0.5}], - [[0, 1, 0.5], {'sheen': 0}], - [(0, 1, 0.5), {'sheen_tint': 0, 'sheen': 1}], - [(0, 1, 1), {'clearcoat': 0}], - [(0, 1, 1), {'clearcoat_gloss': 0, 'clearcoat': 1}], + [(1, 1, 1), {"subsurface": 0}], + [[1, 1, 0], {"metallic": 0}], + [(1, 0, 0), {"specular": 0}], + [(1, 0, 0), {"specular_tint": 0, "specular": 1}], + [(0, 0, 1), {"roughness": 0}], + [(1, 0, 1), {"anisotropic": 0, "metallic": 0.25, "roughness": 0.5}], + [[0, 1, 0.5], {"sheen": 0}], + [(0, 1, 0.5), {"sheen_tint": 0, "sheen": 1}], + [(0, 1, 1), {"clearcoat": 0}], + [(0, 1, 1), {"clearcoat_gloss": 0, "clearcoat": 1}], ] ############################################################################### @@ -68,16 +68,16 @@ # Finally, let's add some labels to guide us through our visualization. labels = [ - 'Subsurface', - 'Metallic', - 'Specular', - 'Specular Tint', - 'Roughness', - 'Anisotropic', - 'Sheen', - 'Sheen Tint', - 'Clearcoat', - 'Clearcoat Gloss', + "Subsurface", + "Metallic", + "Specular", + "Specular Tint", + "Roughness", + "Anisotropic", + "Sheen", + "Sheen Tint", + "Clearcoat", + "Clearcoat Gloss", ] for i in range(10): @@ -104,4 +104,4 @@ if interactive: window.show(scene) -window.record(scene, size=(600, 600), out_path='viz_principled_spheres.png') +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 8cec217b0..71dd1c6fe 100644 --- a/docs/examples/viz_radio_buttons.py +++ b/docs/examples/viz_radio_buttons.py @@ -34,14 +34,14 @@ ) # 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)} +options = {"Blue": (0, 0, 255), "Red": (255, 0, 0), "Green": (0, 255, 0)} color_toggler = ui.RadioButton( list(options), - checked_labels=['Blue'], + checked_labels=["Blue"], padding=1, font_size=16, - font_family='Arial', + font_family="Arial", position=(200, 200), ) @@ -65,7 +65,7 @@ def toggle_color(radio): # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title='FURY Sphere Example') +show_manager = window.ShowManager(size=current_size, title="FURY Sphere Example") show_manager.scene.add(sphere) show_manager.scene.add(color_toggler) @@ -82,4 +82,4 @@ def toggle_color(radio): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path='viz_radio_buttons.png') +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 24dc53700..1e9485d02 100644 --- a/docs/examples/viz_robot_arm_animation.py +++ b/docs/examples/viz_robot_arm_animation.py @@ -5,6 +5,7 @@ Tutorial on making a robot arm animation in FURY. """ + import numpy as np from fury import actor, window @@ -118,4 +119,4 @@ def rot_drill(t): if interactive: showm.start() -window.record(scene, out_path='viz_robot_arm.png', size=(900, 768)) +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 bc9fcc84d..17590a3df 100644 --- a/docs/examples/viz_roi_contour.py +++ b/docs/examples/viz_roi_contour.py @@ -97,4 +97,4 @@ # scene.zoom(1.5) # scene.reset_clipping_range() -window.record(scene, out_path='contour_from_roi_tutorial.png', size=(600, 600)) +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 b694e02bc..bebeb4f30 100644 --- a/docs/examples/viz_sdf_cylinder.py +++ b/docs/examples/viz_sdf_cylinder.py @@ -129,7 +129,7 @@ if interactive: window.show(scene) -window.record(scene, size=(600, 600), out_path='viz_poly_cylinder.png') +window.record(scene, size=(600, 600), out_path="viz_poly_cylinder.png") ############################################################################### # Visualize the surface geometry representation for the object. @@ -141,7 +141,7 @@ if interactive: window.show(scene) -window.record(scene, size=(600, 600), out_path='viz_poly_cylinder_geom.png') +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 @@ -187,10 +187,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') +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") ############################################################################### # Then we have the shader code implementation corresponding to vertex and @@ -225,7 +225,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) +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, @@ -253,13 +253,13 @@ # cylinder with respect to the box. vec_to_vec_rot_mat = import_fury_shader( - os.path.join('utils', 'vec_to_vec_rot_mat.glsl') + 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 = import_fury_shader(os.path.join("sdf", "sd_cylinder.frag")) ############################################################################### # This is used on calculations for surface normals of the cylinder. @@ -283,18 +283,18 @@ ############################################################################### # 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 = 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 = 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( - os.path.join('lighting', 'blinn_phong_model.frag') + os.path.join("lighting", "blinn_phong_model.frag") ) ############################################################################### @@ -312,7 +312,7 @@ ] ) -shader_to_actor(box_actor, 'fragment', decl_code=fs_dec) +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 +350,7 @@ } """ -shader_to_actor(box_actor, 'fragment', impl_code=sdf_cylinder_frag_impl, block='light') +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. @@ -360,7 +360,7 @@ if interactive: window.show(scene) -window.record(scene, size=(600, 600), out_path='viz_sdf_cylinder.png') +window.record(scene, size=(600, 600), out_path="viz_sdf_cylinder.png") ############################################################################### # References diff --git a/docs/examples/viz_sdfactor.py b/docs/examples/viz_sdfactor.py index 748d02ea1..1223d38aa 100644 --- a/docs/examples/viz_sdfactor.py +++ b/docs/examples/viz_sdfactor.py @@ -34,7 +34,7 @@ centers=centers, directions=dirs, colors=colors, - primitives=['sphere', 'torus', 'ellipsoid', 'capsule'], + primitives=["sphere", "torus", "ellipsoid", "capsule"], scales=scales, ) @@ -53,11 +53,11 @@ # manager. current_size = (1024, 720) -showm = window.ShowManager(scene, size=current_size, title='Visualize SDF Actor') +showm = 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) +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 968d5f315..6c0a4c485 100644 --- a/docs/examples/viz_selection.py +++ b/docs/examples/viz_selection.py @@ -61,7 +61,7 @@ ############################################################################### # Access the memory of the colors of all the cubes -vcolors = utils.colors_from_actor(cube_actor, 'colors') +vcolors = utils.colors_from_actor(cube_actor, "colors") ############################################################################### # Create a rectangular 2d box as a texture @@ -78,7 +78,7 @@ ############################################################################### # Create the Selection Manager -selm = pick.SelectionManager(select='faces') +selm = pick.SelectionManager(select="faces") ############################################################################### # Tell Selection Manager to avoid selecting specific actors @@ -98,17 +98,17 @@ def hover_callback(_obj, _event): # defines selection region and returns information from selected objects info = selm.select(event_pos, showm.scene, (200 // 2, 100 // 2)) for node in info.keys(): - if info[node]['face'] is not None: - if info[node]['actor'] is cube_actor: - for face_index in info[node]['face']: + if info[node]["face"] is not None: + if info[node]["actor"] is cube_actor: + for face_index in info[node]["face"]: # generates an object_index to help with coloring # by dividing by the number of faces of each cube (6 * 2) object_index = face_index // 12 sec = int(num_vertices / num_objects) - color_change = np.array([150, 0, 0, 255], dtype='uint8') - vcolors[ - object_index * sec : object_index * sec + sec - ] = color_change + color_change = np.array([150, 0, 0, 255], dtype="uint8") + vcolors[object_index * sec : object_index * sec + sec] = ( + color_change + ) utils.update_actor(cube_actor) showm.render() @@ -132,11 +132,10 @@ def hover_callback(_obj, _event): interactive = False if interactive: - showm.start() ############################################################################### # Save the current framebuffer in a PNG file -window.record(showm.scene, size=(1024, 768), out_path='viz_selection.png') +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 2c7feab13..19b1a36ba 100644 --- a/docs/examples/viz_shader.py +++ b/docs/examples/viz_shader.py @@ -19,7 +19,7 @@ fetch_viz_models() -model = read_viz_models('utah.obj') +model = read_viz_models("utah.obj") ############################################################################### @@ -59,10 +59,10 @@ """ shader_to_actor( - utah, 'vertex', impl_code=vertex_shader_code_impl, decl_code=vertex_shader_code_decl + 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') +shader_to_actor(utah, "fragment", decl_code=fragment_shader_code_decl) +shader_to_actor(utah, "fragment", impl_code=fragment_shader_code_impl, block="light") ############################################################################### # Let's create a scene. @@ -93,7 +93,7 @@ def shader_callback(_caller, _event, calldata=None): global timer if program is not None: try: - program.SetUniformf('time', timer) + program.SetUniformf("time", timer) except ValueError: pass @@ -103,7 +103,7 @@ def shader_callback(_caller, _event, calldata=None): # Let's add a textblock to the scene with a custom message tb = ui.TextBlock2D() -tb.message = 'Hello Shaders' +tb.message = "Hello Shaders" ############################################################################### # Show Manager @@ -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') +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 130fadbcd..e7e64361c 100644 --- a/docs/examples/viz_shapes.py +++ b/docs/examples/viz_shapes.py @@ -39,7 +39,7 @@ # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title='FURY Shapes Example') +show_manager = window.ShowManager(size=current_size, title="FURY Shapes Example") show_manager.scene.add(rect) show_manager.scene.add(disk) @@ -50,4 +50,4 @@ if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path='viz_shapes.png') +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 5a83ab54f..0657e0b1d 100644 --- a/docs/examples/viz_skinning.py +++ b/docs/examples/viz_skinning.py @@ -14,8 +14,8 @@ # Retrieving the model with skeletal animations. # We're choosing the `RiggedFigure` model here. -fetch_gltf('RiggedFigure', 'glTF') -filename = read_viz_gltf('RiggedFigure') +fetch_gltf("RiggedFigure", "glTF") +filename = read_viz_gltf("RiggedFigure") ############################################################################## # Initializing the glTF object, You can additionally set `apply_normals=True`. @@ -28,7 +28,7 @@ # name you want to visualize. # Note: If there's no name for animation, It's stored as `anim_0`, `anim_1` etc -animation = gltf_obj.skin_animation()['anim_0'] +animation = gltf_obj.skin_animation()["anim_0"] # After we get the timeline object, We want to initialise the skinning process. # You can set `bones=true` to visualize each bone transformation. Additionally, @@ -73,4 +73,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, out_path='viz_skinning.png', size=(900, 768)) +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 5a12553a7..0a8c01303 100644 --- a/docs/examples/viz_slice.py +++ b/docs/examples/viz_slice.py @@ -19,12 +19,12 @@ fetch_bundles_2_subjects() fname_t1 = os.path.join( - os.path.expanduser('~'), - '.dipy', - 'exp_bundles_and_maps', - 'bundles_2_subjects', - 'subj_1', - 't1_warped.nii.gz', + os.path.expanduser("~"), + ".dipy", + "exp_bundles_and_maps", + "bundles_2_subjects", + "subj_1", + "t1_warped.nii.gz", ) @@ -86,7 +86,7 @@ ############################################################################### # Otherwise, you can save a screenshot using the following command. -window.record(scene, out_path='slices.png', size=(600, 600), reset_camera=False) +window.record(scene, out_path="slices.png", size=(600, 600), reset_camera=False) ############################################################################### # Render slices from FA with your colormap @@ -97,12 +97,12 @@ # colormap. fname_fa = os.path.join( - os.path.expanduser('~'), - '.dipy', - 'exp_bundles_and_maps', - 'bundles_2_subjects', - 'subj_1', - 'fa_1x1x1.nii.gz', + os.path.expanduser("~"), + ".dipy", + "exp_bundles_and_maps", + "bundles_2_subjects", + "subj_1", + "fa_1x1x1.nii.gz", ) img = nib.load(fname_fa) @@ -132,7 +132,7 @@ # window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='slices_lut.png', size=(600, 600), reset_camera=False) +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 @@ -148,14 +148,14 @@ ############################################################################### # 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 = ui.TextBlock2D(text="Position:") +label_value = ui.TextBlock2D(text="Value:") -result_position = ui.TextBlock2D(text='') -result_value = ui.TextBlock2D(text='') +result_position = ui.TextBlock2D(text="") +result_value = ui.TextBlock2D(text="") panel_picking = ui.Panel2D( - size=(250, 125), position=(20, 20), color=(0, 0, 0), opacity=0.75, align='left' + size=(250, 125), position=(20, 20), color=(0, 0, 0), opacity=0.75, align="left" ) panel_picking.add_element(label_position, (0.1, 0.55)) @@ -178,12 +178,12 @@ def left_click_callback(obj, _ev): obj.picker.Pick(event_pos[0], event_pos[1], 0, show_m.scene) i, j, k = obj.picker.GetPointIJK() - result_position.message = '({}, {}, {})'.format(str(i), str(j), str(k)) - result_value.message = '%.8f' % data[i, j, k] + result_position.message = "({}, {}, {})".format(str(i), str(j), str(k)) + result_value.message = "%.8f" % data[i, j, k] fa_actor.SetInterpolate(False) -fa_actor.AddObserver('LeftButtonPressEvent', left_click_callback, 1.0) +fa_actor.AddObserver("LeftButtonPressEvent", left_click_callback, 1.0) # show_m.start() @@ -198,10 +198,10 @@ def left_click_callback(obj, _ev): # parallel. We'll also need a new show manager and an associated callback. scene.clear() -scene.projection('parallel') +scene.projection("parallel") -result_position.message = '' -result_value.message = '' +result_position.message = "" +result_value.message = "" show_m_mosaic = window.ShowManager(scene, size=(1200, 900)) @@ -213,8 +213,8 @@ def left_click_callback_mosaic(obj, _ev): obj.picker.Pick(event_pos[0], event_pos[1], 0, show_m_mosaic.scene) i, j, k = obj.picker.GetPointIJK() - result_position.message = '({}, {}, {})'.format(str(i), str(j), str(k)) - result_value.message = '%.8f' % data[i, j, k] + result_position.message = "({}, {}, {})".format(str(i), str(j), str(k)) + result_value.message = "%.8f" % data[i, j, k] ############################################################################### @@ -239,7 +239,7 @@ def left_click_callback_mosaic(obj, _ev): ) slice_mosaic.SetInterpolate(False) slice_mosaic.AddObserver( - 'LeftButtonPressEvent', left_click_callback_mosaic, 1.0 + "LeftButtonPressEvent", left_click_callback_mosaic, 1.0 ) scene.add(slice_mosaic) cnt += 1 @@ -260,4 +260,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) +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 185b044a3..734d7243e 100644 --- a/docs/examples/viz_solar_system.py +++ b/docs/examples/viz_solar_system.py @@ -23,11 +23,11 @@ # Create a panel and the start/pause buttons -panel = ui.Panel2D(size=(300, 100), color=(1, 1, 1), align='right') +panel = 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 = ui.Button2D(icon_fnames=[("square", read_viz_icons(fname="pause2.png"))]) +start_button = ui.Button2D(icon_fnames=[("square", read_viz_icons(fname="play3.png"))]) # Add the buttons on the panel @@ -41,55 +41,55 @@ planets_data = [ { - 'filename': '8k_mercury.jpg', - 'position': 7, - 'earth_days': 58, - 'scale': (0.4, 0.4, 0.4), + "filename": "8k_mercury.jpg", + "position": 7, + "earth_days": 58, + "scale": (0.4, 0.4, 0.4), }, { - 'filename': '8k_venus_surface.jpg', - 'position': 9, - 'earth_days': 243, - 'scale': (0.6, 0.6, 0.6), + "filename": "8k_venus_surface.jpg", + "position": 9, + "earth_days": 243, + "scale": (0.6, 0.6, 0.6), }, { - 'filename': '1_earth_8k.jpg', - 'position': 11, - 'earth_days': 1, - 'scale': (0.4, 0.4, 0.4), + "filename": "1_earth_8k.jpg", + "position": 11, + "earth_days": 1, + "scale": (0.4, 0.4, 0.4), }, { - 'filename': '8k_mars.jpg', - 'position': 13, - 'earth_days': 1, - 'scale': (0.8, 0.8, 0.8), + "filename": "8k_mars.jpg", + "position": 13, + "earth_days": 1, + "scale": (0.8, 0.8, 0.8), }, - {'filename': 'jupiter.jpg', 'position': 16, 'earth_days': 0.41, 'scale': (2, 2, 2)}, + {"filename": "jupiter.jpg", "position": 16, "earth_days": 0.41, "scale": (2, 2, 2)}, { - 'filename': '8k_saturn.jpg', - 'position': 19, - 'earth_days': 0.45, - 'scale': (2, 2, 2), + "filename": "8k_saturn.jpg", + "position": 19, + "earth_days": 0.45, + "scale": (2, 2, 2), }, { - 'filename': '8k_saturn_ring_alpha.png', - 'position': 19, - 'earth_days': 0.45, - 'scale': (3, 0.5, 3), + "filename": "8k_saturn_ring_alpha.png", + "position": 19, + "earth_days": 0.45, + "scale": (3, 0.5, 3), }, { - 'filename': '2k_uranus.jpg', - 'position': 22, - 'earth_days': 0.70, - 'scale': (1, 1, 1), + "filename": "2k_uranus.jpg", + "position": 22, + "earth_days": 0.70, + "scale": (1, 1, 1), }, { - 'filename': '2k_neptune.jpg', - 'position': 25, - 'earth_days': 0.70, - 'scale': (1, 1, 1), + "filename": "2k_neptune.jpg", + "position": 25, + "earth_days": 0.70, + "scale": (1, 1, 1), }, - {'filename': '8k_sun.jpg', 'position': 0, 'earth_days': 27, 'scale': (5, 5, 5)}, + {"filename": "8k_sun.jpg", "position": 0, "earth_days": 27, "scale": (5, 5, 5)}, ] fetch_viz_textures() @@ -114,13 +114,13 @@ def init_planet(planet_data): planet_actor: actor The corresponding sphere actor with texture applied. """ - planet_file = read_viz_textures(planet_data['filename']) + planet_file = read_viz_textures(planet_data["filename"]) planet_image = io.load_image(planet_file) planet_actor = actor.texture_on_sphere(planet_image) - planet_actor.SetPosition(planet_data['position'], 0, 0) - if planet_data['filename'] != '8k_saturn_ring_alpha.png': + 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)) - planet_actor.SetScale(planet_data['scale']) + planet_actor.SetScale(planet_data["scale"]) scene.add(planet_actor) return planet_actor @@ -153,7 +153,7 @@ def init_planet(planet_data): g_exponent = np.float_power(10, -11) g_constant = 6.673 * g_exponent -m_exponent = 1073741824 # np.power(10, 30) +m_exponent = 1073741824 # np.power(10, 30) m_constant = 1.989 * m_exponent miu = m_constant * g_constant @@ -242,10 +242,10 @@ def calculate_path(r_planet, c): # around itself. r_planets = [ - p_data['position'] + p_data["position"] for p_data in planets_data - if 'sun' not in p_data['filename'] - if 'saturn_ring' not in p_data['filename'] + if "sun" not in p_data["filename"] + if "saturn_ring" not in p_data["filename"] ] planet_actors = [ @@ -261,12 +261,12 @@ def calculate_path(r_planet, c): sun_data = { - 'actor': sun_actor, - 'position': planets_data[9]['position'], - 'earth_days': planets_data[9]['earth_days'], + "actor": sun_actor, + "position": planets_data[9]["position"], + "earth_days": planets_data[9]["earth_days"], } -r_times = [p_data['earth_days'] for p_data in planets_data] +r_times = [p_data["earth_days"] for p_data in planets_data] ############################################################################## # Here we are calculating and updating the path/orbit before animation starts. @@ -292,9 +292,11 @@ def timer_callback(_obj, _event): showm.render() # Rotating the sun actor - rotate_axial(sun_actor, sun_data['earth_days'], 1) + rotate_axial(sun_actor, sun_data["earth_days"], 1) - for r_planet, p_actor, r_time in zip(r_planets, planet_actors, r_times): + for r_planet, p_actor, r_time in zip( + r_planets, planet_actors, r_times, strict=False + ): # if the planet is saturn then we also need to update the position # of its rings. if p_actor == saturn_actor: @@ -331,4 +333,4 @@ 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') +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 45b9489da..92df3c73c 100644 --- a/docs/examples/viz_sphere.py +++ b/docs/examples/viz_sphere.py @@ -41,4 +41,4 @@ if interactive: window.show(scene, size=(600, 600)) -window.record(scene, out_path='viz_sphere.png', size=(600, 600)) +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 0cf3ffcd5..3ab10c87c 100644 --- a/docs/examples/viz_spiky.py +++ b/docs/examples/viz_spiky.py @@ -24,7 +24,7 @@ # 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 = primitive.prim_sphere(name="symmetric362", gen_faces=False) ############################################################################## # To be able to visualize the vertices, let's define a point actor with @@ -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') +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 756d198f4..1fbe02f97 100644 --- a/docs/examples/viz_spinbox.py +++ b/docs/examples/viz_spinbox.py @@ -9,6 +9,7 @@ First, some imports. """ + import numpy as np from fury import actor, ui, utils, window @@ -22,23 +23,31 @@ ############################################################################### # Let's create a Cone. -cone = actor.cone(centers=np.random.rand(1, 3), - directions=np.random.rand(1, 3), - colors=(1, 1, 1), heights=np.random.rand(1)) +cone = actor.cone( + centers=np.random.rand(1, 3), + directions=np.random.rand(1, 3), + colors=(1, 1, 1), + heights=np.random.rand(1), +) ############################################################################### # Creating the SpinBox UI. -spinbox = ui.SpinBox(position=(200, 100), size=(300, 100), min_val=0, - max_val=360, initial_val=180, step=10) +spinbox = ui.SpinBox( + position=(200, 100), + size=(300, 100), + min_val=0, + max_val=360, + initial_val=180, + step=10, +) ############################################################################### # Now that all the elements have been initialised, we add them to the show # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, - title="FURY SpinBox Example") +show_manager = window.ShowManager(size=current_size, title="FURY SpinBox Example") show_manager.scene.add(cone) show_manager.scene.add(spinbox) @@ -67,5 +76,4 @@ def rotate_cone(spinbox): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, - out_path="viz_spinbox.png") +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 2023647b0..c5ca86344 100644 --- a/docs/examples/viz_spline_interpolator.py +++ b/docs/examples/viz_spline_interpolator.py @@ -94,4 +94,4 @@ if interactive: showm.start() -window.record(scene, out_path='viz_keyframe_animation_spline.png', size=(900, 768)) +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 6dbc9e124..6cc62c551 100644 --- a/docs/examples/viz_surfaces.py +++ b/docs/examples/viz_surfaces.py @@ -58,7 +58,7 @@ [1, 5, 7], [1, 7, 3], ], - dtype='i8', + dtype="i8", ) @@ -71,9 +71,9 @@ ############################################################################### # Save the ``PolyData`` -file_name = 'my_cube.vtk' +file_name = "my_cube.vtk" save_polydata(my_polydata, file_name) -print('Surface saved in ' + file_name) +print("Surface saved in " + file_name) ############################################################################### # Load the ``PolyData`` @@ -87,7 +87,7 @@ colors = cube_vertices * 255 utils.set_polydata_colors(cube_polydata, colors) -print('new surface colors') +print("new surface colors") print(utils.get_polydata_colors(cube_polydata)) ############################################################################### @@ -104,4 +104,4 @@ # display # window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, out_path='cube.png', size=(600, 600)) +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 6cabf95b9..da6f542c1 100644 --- a/docs/examples/viz_tab.py +++ b/docs/examples/viz_tab.py @@ -12,6 +12,7 @@ First, some imports. """ + import numpy as np from fury import actor, ui, window @@ -31,7 +32,7 @@ # We can also define the position of the Tab Bar. # By default the Tab Bar is positioned at top -tab_ui.tab_bar_pos = 'bottom' +tab_ui.tab_bar_pos = "bottom" ############################################################################### # Slider Controls for a Cube for Tab Index 0 @@ -39,22 +40,22 @@ # # Now we prepare content for the first tab. -ring_slider = ui.RingSlider2D(initial_value=0, text_template='{angle:5.1f}°') +ring_slider = ui.RingSlider2D(initial_value=0, text_template="{angle:5.1f}°") line_slider_x = ui.LineSlider2D( initial_value=0, min_value=-10, max_value=10, - orientation='horizontal', - text_alignment='Top', + orientation="horizontal", + text_alignment="Top", ) line_slider_y = ui.LineSlider2D( initial_value=0, min_value=-10, max_value=10, - orientation='vertical', - text_alignment='Right', + orientation="vertical", + text_alignment="Right", ) cube = actor.box( @@ -93,7 +94,7 @@ def translate_cube_y(slider): ############################################################################### # After defining content, we define properties for the tab. -tab_ui.tabs[0].title = 'Sliders' +tab_ui.tabs[0].title = "Sliders" tab_ui.add_element(0, ring_slider, (0.3, 0.3)) tab_ui.add_element(0, line_slider_x, (0.0, 0.0)) tab_ui.add_element(0, line_slider_y, (0.0, 0.1)) @@ -113,8 +114,8 @@ def translate_cube_y(slider): sphere = actor.sphere(centers=np.array([[5, 0, 0]]), colors=(1, 1, 0)) -figure_dict = {'cylinder': cylinder, 'sphere': sphere} -checkbox = ui.Checkbox(labels=['cylinder', 'sphere']) +figure_dict = {"cylinder": cylinder, "sphere": sphere} +checkbox = ui.Checkbox(labels=["cylinder", "sphere"]) # Get difference between two lists. @@ -139,7 +140,7 @@ def set_figure_visiblity(checkboxes): ############################################################################### # After defining content, we define properties for the tab. -tab_ui.tabs[1].title = 'Checkbox' +tab_ui.tabs[1].title = "Checkbox" tab_ui.add_element(1, checkbox, (0.2, 0.2)) ############################################################################### @@ -152,24 +153,24 @@ def set_figure_visiblity(checkboxes): position=(600, 300), font_size=40, color=(1, 0.5, 0), - justification='center', - vertical_justification='top', - text='FURY rocks!!!', + justification="center", + vertical_justification="top", + text="FURY rocks!!!", ) colors = { - 'Violet': (0.6, 0, 0.8), - 'Indigo': (0.3, 0, 0.5), - 'Blue': (0, 0, 1), - 'Green': (0, 1, 0), - 'Yellow': (1, 1, 0), - 'Orange': (1, 0.5, 0), - 'Red': (1, 0, 0), + "Violet": (0.6, 0, 0.8), + "Indigo": (0.3, 0, 0.5), + "Blue": (0, 0, 1), + "Green": (0, 1, 0), + "Yellow": (1, 1, 0), + "Orange": (1, 0.5, 0), + "Red": (1, 0, 0), } color_combobox = ui.ComboBox2D( items=list(colors.keys()), - placeholder='Choose Text Color', + placeholder="Choose Text Color", size=(250, 150), draggable=True, ) @@ -184,7 +185,7 @@ def change_color(combobox): ############################################################################### # After defining content, we define properties for the tab. -tab_ui.tabs[2].title = 'Colors' +tab_ui.tabs[2].title = "Colors" tab_ui.add_element(2, color_combobox, (0.1, 0.3)) ############################################################################### @@ -194,13 +195,13 @@ def change_color(combobox): def hide_actors(tab_ui): - if tab_ui.tabs[tab_ui.active_tab_idx].title == 'Sliders': + if tab_ui.tabs[tab_ui.active_tab_idx].title == "Sliders": cube.SetVisibility(True) cylinder.SetVisibility(False) sphere.SetVisibility(False) label.set_visibility(False) - elif tab_ui.tabs[tab_ui.active_tab_idx].title == 'Checkbox': + elif tab_ui.tabs[tab_ui.active_tab_idx].title == "Checkbox": cube.SetVisibility(False) set_figure_visiblity(checkbox) label.set_visibility(False) @@ -227,7 +228,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 = 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 @@ -236,4 +237,4 @@ def collapse(tab_ui): if interactive: sm.start() -window.record(sm.scene, size=(500, 500), out_path='viz_tab.png') +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 64ea04702..f037c9026 100644 --- a/docs/examples/viz_tesseract.py +++ b/docs/examples/viz_tesseract.py @@ -150,7 +150,7 @@ def connect_points(verts3D): ############################################################################### # Initializing text box to display the name -tb = TextBlock2D(text='Tesseract', position=(900, 950), font_size=20) +tb = TextBlock2D(text="Tesseract", position=(900, 950), font_size=20) showm.scene.add(tb) ############################################################################### @@ -186,4 +186,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') +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 69b7426bc..31043b706 100644 --- a/docs/examples/viz_texture.py +++ b/docs/examples/viz_texture.py @@ -20,7 +20,7 @@ # to download the available textures. fetch_viz_textures() -filename = read_viz_textures('1_earth_8k.jpg') +filename = read_viz_textures("1_earth_8k.jpg") image = io.load_image(filename) ############################################################################## @@ -38,4 +38,4 @@ interactive = False if interactive: window.show(scene, size=(600, 600), reset_camera=False) -window.record(scene, size=(900, 768), out_path='viz_texture.png') +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 65c65e949..45218aacc 100644 --- a/docs/examples/viz_timeline.py +++ b/docs/examples/viz_timeline.py @@ -16,7 +16,6 @@ # ``Timeline`` has playback methods such as ``play``, ``pause``, ``stop``, ... # which can be used to control the animation. - import numpy as np from fury import actor, window @@ -89,4 +88,4 @@ if interactive: showm.start() -window.record(scene, out_path='viz_keyframe_animation_timeline.png', size=(900, 768)) +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 c529a5768..4618cee44 100644 --- a/docs/examples/viz_timers.py +++ b/docs/examples/viz_timers.py @@ -13,7 +13,6 @@ application will exit after the callback has been called 100 times. """ - import itertools import numpy as np @@ -67,4 +66,4 @@ def timer_callback(_obj, _event): showm.start() -window.record(showm.scene, size=(900, 768), out_path='viz_timer.png') +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 253cbd662..31eecdc0b 100644 --- a/docs/examples/viz_ui.py +++ b/docs/examples/viz_ui.py @@ -46,7 +46,7 @@ # Now we can create an image container. img = ui.ImageContainer2D( - img_path=read_viz_icons(fname='home3.png'), position=(450, 350) + img_path=read_viz_icons(fname="home3.png"), position=(450, 350) ) ############################################################################### @@ -56,15 +56,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 = 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 = ui.TextBlock2D(text="Click me") +text2 = ui.TextBlock2D(text="Me too") panel.add_element(text, (50, 100)) panel.add_element(text2, (180, 100)) @@ -76,14 +76,14 @@ button_example = ui.Button2D( - icon_fnames=[('square', read_viz_icons(fname='stop2.png'))] + icon_fnames=[("square", 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", 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"))) second_button_example = ui.Button2D(icon_fnames=icon_files) @@ -95,7 +95,7 @@ def change_text_callback(i_ren, _obj, _button): - text.message = 'Clicked!' + text.message = "Clicked!" i_ren.force_render() @@ -125,7 +125,7 @@ def change_icon_callback(i_ren, _obj, _button): # Now we'll add three sliders: one circular and two linear. ring_slider = ui.RingSlider2D( - center=(740, 400), initial_value=0, text_template='{angle:5.1f}°' + center=(740, 400), initial_value=0, text_template="{angle:5.1f}°" ) line_slider_x = ui.LineSlider2D( @@ -133,7 +133,7 @@ def change_icon_callback(i_ren, _obj, _button): initial_value=0, min_value=-10, max_value=10, - orientation='horizontal', + orientation="horizontal", ) line_slider_y = ui.LineSlider2D( @@ -141,7 +141,7 @@ def change_icon_callback(i_ren, _obj, _button): initial_value=0, min_value=-10, max_value=10, - orientation='vertical', + orientation="vertical", ) ############################################################################### @@ -198,7 +198,7 @@ def translate_cube_y(slider): font_size=18, range_precision=2, value_precision=4, - shape='square', + shape="square", ) range_slider_y = ui.RangeSlider( @@ -212,8 +212,8 @@ def translate_cube_y(slider): font_size=18, range_precision=2, value_precision=4, - orientation='vertical', - shape='square', + orientation="vertical", + shape="square", ) ############################################################################### # Select menu @@ -252,12 +252,12 @@ def hide_all_examples(): # correspond with the examples. values = [ - 'Rectangle', - 'Disks', - 'Image', - 'Button Panel', - 'Line & Ring Slider', - 'Range Slider', + "Rectangle", + "Disks", + "Image", + "Button Panel", + "Line & Ring Slider", + "Range Slider", ] ############################################################################### @@ -291,7 +291,7 @@ def display_element(): # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title='FURY UI Example') +show_manager = window.ShowManager(size=current_size, title="FURY UI Example") show_manager.scene.add(listbox) for example in examples: @@ -309,4 +309,4 @@ def display_element(): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path='viz_ui.png') +window.record(show_manager.scene, size=current_size, out_path="viz_ui.png") diff --git a/docs/examples/viz_ui_listbox.py b/docs/examples/viz_ui_listbox.py index 118a00e8a..c89335662 100644 --- a/docs/examples/viz_ui_listbox.py +++ b/docs/examples/viz_ui_listbox.py @@ -9,6 +9,7 @@ First, a bunch of imports. """ + from fury import ui, window from fury.data import fetch_viz_icons @@ -21,9 +22,9 @@ # 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 = 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)) example = [welcome_text, bye_text, fury_text] @@ -41,7 +42,7 @@ def hide_all_examples(): ############################################################################### # Create ListBox with the values as parameter. -values = ['Welcome', 'Bye', 'Fury'] +values = ["Welcome", "Bye", "Fury"] listbox = ui.ListBox2D( values=values, position=(10, 300), size=(200, 200), multiselection=False ) @@ -63,7 +64,7 @@ def display_element(): # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title='FURY UI ListBox_Example') +show_manager = window.ShowManager(size=current_size, title="FURY UI ListBox_Example") show_manager.scene.add(listbox) show_manager.scene.add(welcome_text) @@ -74,4 +75,4 @@ def display_element(): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path='viz_listbox.png') +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 648d45dde..034761fc3 100644 --- a/docs/examples/viz_ui_slider.py +++ b/docs/examples/viz_ui_slider.py @@ -9,6 +9,7 @@ First, some imports. """ + import numpy as np from fury import actor, ui, window @@ -37,43 +38,43 @@ # By default the alignments are 'bottom' for horizontal and 'top' for vertical. ring_slider = ui.RingSlider2D( - center=(630, 400), initial_value=0, text_template='{angle:5.1f}°' + center=(630, 400), initial_value=0, text_template="{angle:5.1f}°" ) hor_line_slider_text_top = ui.LineSlider2D( center=(400, 230), initial_value=0, - orientation='horizontal', + orientation="horizontal", min_value=-10, max_value=10, - text_alignment='top', + text_alignment="top", ) hor_line_slider_text_bottom = ui.LineSlider2D( center=(400, 200), initial_value=0, - orientation='horizontal', + orientation="horizontal", min_value=-10, max_value=10, - text_alignment='bottom', + text_alignment="bottom", ) ver_line_slider_text_left = ui.LineSlider2D( center=(100, 400), initial_value=0, - orientation='vertical', + orientation="vertical", min_value=-10, max_value=10, - text_alignment='left', + text_alignment="left", ) ver_line_slider_text_right = ui.LineSlider2D( center=(150, 400), initial_value=0, - orientation='vertical', + orientation="vertical", min_value=-10, max_value=10, - text_alignment='right', + text_alignment="right", ) @@ -117,7 +118,7 @@ def translate_cube_hor(slider): # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title='FURY Cube Example') +show_manager = window.ShowManager(size=current_size, title="FURY Cube Example") show_manager.scene.add(cube) show_manager.scene.add(ring_slider) @@ -149,4 +150,4 @@ def translate_cube_hor(slider): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path='viz_slider.png') +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 da8a5c2a7..baf680b2c 100644 --- a/docs/examples/viz_using_time_equations.py +++ b/docs/examples/viz_using_time_equations.py @@ -5,6 +5,7 @@ Tutorial on making keyframe-based animation in FURY using custom functions. """ + import numpy as np from fury import actor, window @@ -60,7 +61,7 @@ def scale_eval(t): anim.set_position_interpolator(pos_eval, is_evaluator=True) anim.set_rotation_interpolator(rotation_eval, is_evaluator=True) anim.set_color_interpolator(color_eval, is_evaluator=True) -anim.set_interpolator('scale', scale_eval, is_evaluator=True) +anim.set_interpolator("scale", scale_eval, is_evaluator=True) ############################################################################### # changing camera position to observe the animation better. @@ -76,4 +77,4 @@ def scale_eval(t): if interactive: showm.start() -window.record(scene, out_path='viz_keyframe_animation_evaluators.png', size=(900, 768)) +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 5a500803a..6768a843e 100644 --- a/docs/examples/viz_widget.py +++ b/docs/examples/viz_widget.py @@ -70,7 +70,7 @@ # If you want to use the widget in a Windows environment without the WSL # you need to use the asyncio version of the widget. # -if platform.system() == 'Windows': +if platform.system() == "Windows": async def main(): widget.start() @@ -86,4 +86,4 @@ async def main(): time.sleep(time_sleep) widget.stop() -window.record(showm.scene, size=window_size, out_path='viz_widget.png') +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 1c3eb02d9..1e574ccc3 100644 --- a/docs/examples/viz_wrecking_ball.py +++ b/docs/examples/viz_wrecking_ball.py @@ -9,6 +9,7 @@ First some imports. """ + import itertools import numpy as np @@ -263,6 +264,7 @@ ############################################################################### # We define methods to sync bricks and wrecking ball. + # Function for syncing actors with multibodies. def sync_brick(object_index, multibody): pos, orn = p.getBasePositionAndOrientation(multibody) @@ -315,7 +317,7 @@ def sync_chain(actor_list, multibody): counter = itertools.count() fpss = np.array([]) tb = ui.TextBlock2D( - position=(0, 680), font_size=30, color=(1, 0.5, 0), text='Avg. FPS: \nSim Steps: ' + position=(0, 680), font_size=30, color=(1, 0.5, 0), text="Avg. FPS: \nSim Steps: " ) scene.add(tb) @@ -335,7 +337,7 @@ def timer_callback(_obj, _event): fps = showm.frame_rate fpss = np.append(fpss, fps) tb.message = ( - 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + "Avg. FPS: " + str(np.round(np.mean(fpss), 0)) + "\nSim Steps: " + str(cnt) ) # Updating the position and orientation of each individual brick. @@ -373,4 +375,4 @@ def timer_callback(_obj, _event): if interactive: showm.start() -window.record(scene, size=(900, 768), out_path='viz_wrecking_ball.png') +window.record(scene, size=(900, 768), out_path="viz_wrecking_ball.png") diff --git a/docs/source/conf.py b/docs/source/conf.py index 2ca85bd6c..6af7ae93f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -23,40 +23,40 @@ import sys # Add current path -sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(".")) # Add doc in path for finding tutorial and examples -sys.path.insert(0, os.path.abspath('../..')) +sys.path.insert(0, os.path.abspath("../..")) # Add custom extensions -sys.path.insert(0, os.path.abspath('./ext')) +sys.path.insert(0, os.path.abspath("./ext")) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # -needs_sphinx = '4.3' +needs_sphinx = "4.3" # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - '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', - 'sphinx_copybutton', - 'ext.prepare_gallery', - 'sphinx_gallery.gen_gallery', - 'ext.build_modref_templates', - 'ext.github', - 'ext.github_tools', - 'ext.rstjinja', - 'ablog', + "sphinx.ext.autodoc", + "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", + "sphinx_copybutton", + "ext.prepare_gallery", + "sphinx_gallery.gen_gallery", + "ext.build_modref_templates", + "ext.github", + "ext.github_tools", + "ext.rstjinja", + "ablog", ] # Configuration options for plot_directive. See: @@ -72,7 +72,7 @@ # import ablog templates_path = [ - '_templates', + "_templates", # ablog.get_html_templates_path(), ] @@ -80,15 +80,15 @@ # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'FURY' -copyright = '2018-{0}, FURY'.format(datetime.now().year) -author = 'FURY' +project = "FURY" +copyright = "2018-{0}, FURY".format(datetime.now().year) +author = "FURY" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -106,7 +106,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = 'en' +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -114,7 +114,7 @@ exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -158,21 +158,20 @@ # "version_dropdown": True, # "version_json": "_static/versions.json", # } -import pydata_sphinx_theme -html_theme = 'pydata_sphinx_theme' +html_theme = "pydata_sphinx_theme" # Define the json_url for our version switcher. -json_url = 'https://fury.gl/latest/_static/versions_switcher.json' +json_url = "https://fury.gl/latest/_static/versions_switcher.json" -if 'dev' in release: - version_match = 'latest' +if "dev" in release: + version_match = "latest" # We want to keep the relative reference if we are in dev mode # but we want the whole url if we are effectively in a released version - json_url = '/_static/versions_switcher.json' + json_url = "/_static/versions_switcher.json" else: - version_match = 'v' + release + version_match = "v" + release # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. @@ -181,34 +180,34 @@ # Log:3/3/24 ~ footer_items is deprecated, using new keys for footer. html_theme_options = { - 'navigation_depth': 1, - 'navigation_with_keys': True, + "navigation_depth": 1, + "navigation_with_keys": True, # "logo_link": 'index.html', - 'navbar_start': ['custom-title.html'], - 'navbar_center': ['custom-navbar.html'], - 'footer_start': ['custom-footer.html'], - 'footer_center': '', - 'footer_end': '', - 'switcher': { - 'json_url': json_url, - 'version_match': version_match, + "navbar_start": ["custom-title.html"], + "navbar_center": ["custom-navbar.html"], + "footer_start": ["custom-footer.html"], + "footer_center": "", + "footer_end": "", + "switcher": { + "json_url": json_url, + "version_match": version_match, }, } -html_additional_pages = {'video': 'home-video-page.html', 'index': 'home.html'} +html_additional_pages = {"video": "home-video-page.html", "index": "home.html"} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] -html_css_files = ['css/custom.css', 'vendor/fonts.css'] +html_css_files = ["css/custom.css", "vendor/fonts.css"] # html_baseurl = os.environ.get("SPHINX_HTML_BASE_URL", "http://127.0.0.1:8000/") -html_logo = '_static/images/logo.svg' +html_logo = "_static/images/logo.svg" -html_favicon = '_static/images/logo.ico' +html_favicon = "_static/images/logo.ico" # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -229,41 +228,66 @@ html_sidebars = { # "**": ["search-field", 'globaltoc.html',"sidebar-nav-bs"] # '**': ['search-field', 'globaltoc.html'] - '**': ['globaltoc.html'] + "**": ["globaltoc.html"] } # html_sidebars = { # "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"], # } # html_sidebars = { -# "introduction/**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"], -# "getting_started": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"], -# "auto_examples/**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"], -# "auto_tutorials/**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"], -# "references/**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"], +# "introduction/**": [ +# "logo-text.html", +# "globaltoc.html", +# "localtoc.html", +# "searchbox.html", +# ], +# "getting_started": [ +# "logo-text.html", +# "globaltoc.html", +# "localtoc.html", +# "searchbox.html", +# ], +# "auto_examples/**": [ +# "logo-text.html", +# "globaltoc.html", +# "localtoc.html", +# "searchbox.html", +# ], +# "auto_tutorials/**": [ +# "logo-text.html", +# "globaltoc.html", +# "localtoc.html", +# "searchbox.html", +# ], +# "references/**": [ +# "logo-text.html", +# "globaltoc.html", +# "localtoc.html", +# "searchbox.html", +# ], # "blog": ["categories.html", "archives.html"], # "blog/**": ["categories.html", "archives.html"], # "posts/**": ["postcard.html"], # } # ghissue config -github_project_url = 'https://github.com/fury-gl/fury' +github_project_url = "https://github.com/fury-gl/fury" import github_tools as ght -all_versions = ght.get_all_versions(ignore='micro') +all_versions = ght.get_all_versions(ignore="micro") html_context = { - 'all_versions': all_versions, - 'versions_list': ['dev', 'latest'] + all_versions, - 'basic_stats': ght.fetch_basic_stats(), - 'contributors': ght.fetch_contributor_stats(), - 'default_mode': 'light', + "all_versions": all_versions, + "versions_list": ["dev", "latest"] + all_versions, + "basic_stats": ght.fetch_basic_stats(), + "contributors": ght.fetch_contributor_stats(), + "default_mode": "light", } # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. -htmlhelp_basename = 'fury' +htmlhelp_basename = "fury" # -- Options for LaTeX output --------------------------------------------- @@ -287,7 +311,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'fury.tex', 'FURY Documentation', 'Contributors', 'manual'), + (master_doc, "fury.tex", "FURY Documentation", "Contributors", "manual"), ] @@ -295,7 +319,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, 'fury', 'FURY Documentation', [author], 1)] +man_pages = [(master_doc, "fury", "FURY Documentation", [author], 1)] # -- Options for sphinx gallery ------------------------------------------- from scrap import ImageFileScraper @@ -303,28 +327,28 @@ sc = ImageFileScraper() sphinx_gallery_conf = { - 'doc_module': ('fury',), + "doc_module": ("fury",), # path to your examples scripts - 'examples_dirs': ['../examples_revamped'], + "examples_dirs": ["../examples_revamped"], # path where to save gallery generated examples - 'gallery_dirs': ['auto_examples'], - 'image_scrapers': (sc), - 'backreferences_dir': 'api', - 'reference_url': { - 'fury': None, + "gallery_dirs": ["auto_examples"], + "image_scrapers": (sc), + "backreferences_dir": "api", + "reference_url": { + "fury": None, }, - 'filename_pattern': re.escape(os.sep), - 'plot_gallery': "'True'", + "filename_pattern": re.escape(os.sep), + "plot_gallery": "'True'", } # -- Options for Blog ------------------------------------------- -blog_baseurl = 'https://fury.gl/' +blog_baseurl = "https://fury.gl/" blog_feed_fulltext = True blog_feed_length = 10 blog_feed_archives = True blog_authors = { - 'skoudoro': ('Serge Koudoro', 'https://github.com/skoudoro'), + "skoudoro": ("Serge Koudoro", "https://github.com/skoudoro"), } # -- Options for Texinfo output ------------------------------------------- @@ -335,22 +359,22 @@ texinfo_documents = [ ( master_doc, - 'fury', - 'FURY Documentation', + "fury", + "FURY Documentation", author, - 'fury', - 'Free Unified Rendering in Python', - 'Miscellaneous', + "fury", + "Free Unified Rendering in Python", + "Miscellaneous", ), ] # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - 'python': ('https://docs.python.org/3/', None), - 'numpy': ('https://numpy.org/doc/stable/', None), - 'scipy': ('https://docs.scipy.org/doc/scipy/', None), - 'pandas': ('https://pandas.pydata.org/docs/', None), - 'matplotlib': ('https://matplotlib.org/stable/', None), - 'dipy': ('https://docs.dipy.org/stable', None), - 'scikit-learn': ('https://scikit-learn.org/stable/', None), + "python": ("https://docs.python.org/3/", None), + "numpy": ("https://numpy.org/doc/stable/", None), + "scipy": ("https://docs.scipy.org/doc/scipy/", None), + "pandas": ("https://pandas.pydata.org/docs/", None), + "matplotlib": ("https://matplotlib.org/stable/", None), + "dipy": ("https://docs.dipy.org/stable", None), + "scikit-learn": ("https://scikit-learn.org/stable/", None), } diff --git a/docs/source/ext/apigen.py b/docs/source/ext/apigen.py index 8c575c095..c1696ea18 100644 --- a/docs/source/ext/apigen.py +++ b/docs/source/ext/apigen.py @@ -33,12 +33,12 @@ class ApiDocWriter: """ # only separating first two levels - rst_section_levels = ['*', '=', '-', '~', '^'] + rst_section_levels = ["*", "=", "-", "~", "^"] def __init__( self, package_name, - rst_extension='.txt', + rst_extension=".txt", package_skip_patterns=None, module_skip_patterns=None, object_skip_patterns=None, @@ -77,13 +77,13 @@ def __init__( """ if package_skip_patterns is None: - package_skip_patterns = ['\\.tests$'] + package_skip_patterns = ["\\.tests$"] if module_skip_patterns is None: - module_skip_patterns = ['\\.setup$', '\\._'] + module_skip_patterns = ["\\.setup$", "\\._"] if object_skip_patterns is None: object_skip_patterns = [] - self.root_path = '' + self.root_path = "" self.written_modules = None self._package_name = None self.package_name = package_name @@ -116,14 +116,14 @@ def set_package_name(self, package_name): self.written_modules = None package_name = property( - get_package_name, set_package_name, None, 'get/set package_name' + get_package_name, set_package_name, None, "get/set package_name" ) @staticmethod def _import(name): """Import namespace package.""" mod = __import__(name) - components = name.split('.') + components = name.split(".") for comp in components[1:]: mod = getattr(mod, comp) return mod @@ -141,10 +141,10 @@ def _get_object_name(line): 'Klass' """ - name = line.split()[1].split('(')[0].strip() + name = line.split()[1].split("(")[0].strip() # in case we have classes which are not derived from object # ie. old style classes - return name.rstrip(':') + return name.rstrip(":") def _uri2path(self, uri): """Convert uri to absolute filepath. @@ -175,36 +175,36 @@ def _uri2path(self, uri): """ if uri == self.package_name: - return os.path.join(self.root_path, '__init__.py') - path = uri.replace(self.package_name + '.', '') - path = path.replace('.', os.path.sep) + return os.path.join(self.root_path, "__init__.py") + path = uri.replace(self.package_name + ".", "") + path = path.replace(".", os.path.sep) path = os.path.join(self.root_path, path) # XXX maybe check for extensions as well? - if os.path.exists(path + '.py'): # file - path += '.py' - elif os.path.exists(os.path.join(path, '__init__.py')): - path = os.path.join(path, '__init__.py') + if os.path.exists(path + ".py"): # file + path += ".py" + elif os.path.exists(os.path.join(path, "__init__.py")): + path = os.path.join(path, "__init__.py") else: return None return path def _path2uri(self, dirpath): """Convert directory path to uri.""" - package_dir = self.package_name.replace('.', os.path.sep) + package_dir = self.package_name.replace(".", os.path.sep) relpath = dirpath.replace(self.root_path, package_dir) if relpath.startswith(os.path.sep): relpath = relpath[1:] - return relpath.replace(os.path.sep, '.') + return relpath.replace(os.path.sep, ".") def _parse_module(self, uri): """Parse module defined in *uri*.""" filename = self._uri2path(uri) if filename is None: - print(filename, 'erk') + print(filename, "erk") # nothing that we could handle here. return ([], []) - f = open(filename, 'rt') + f = open(filename, "rt") functions, classes = self._parse_lines(f) f.close() return functions, classes @@ -227,7 +227,7 @@ def _parse_module_with_import(self, uri): """ mod = import_module(uri) - patterns = '(?:{0})'.format('|'.join(self.object_skip_patterns)) + patterns = "(?:{0})".format("|".join(self.object_skip_patterns)) pat = re.compile(patterns) with open(mod.__file__) as fi: @@ -236,17 +236,16 @@ def _parse_module_with_import(self, uri): functions = [] classes = [] for n in node.body: - - if not hasattr(n, 'name'): + if not hasattr(n, "name"): if not isinstance(n, ast.Assign): continue if isinstance(n, ast.ClassDef): - if n.name.startswith('_') or pat.search(n.name): + if n.name.startswith("_") or pat.search(n.name): continue classes.append(n.name) elif isinstance(n, ast.FunctionDef): - if n.name.startswith('_') or pat.search(n.name): + if n.name.startswith("_") or pat.search(n.name): continue functions.append(n.name) # Specific condition for vtk and fury @@ -256,7 +255,7 @@ def _parse_module_with_import(self, uri): if isinstance(n.targets[0], ast.Tuple): continue functions.append(n.targets[0].id) - elif hasattr(n.value, 'attr') and n.value.attr.startswith('vtk'): + elif hasattr(n.value, "attr") and n.value.attr.startswith("vtk"): classes.append(n.targets[0].id) except Exception: print(mod.__file__) @@ -270,15 +269,15 @@ def _parse_lines(self, linesource): functions = [] classes = [] for line in linesource: - if line.startswith('def ') and line.count('('): + if line.startswith("def ") and line.count("("): # exclude private stuff name = self._get_object_name(line) - if not name.startswith('_'): + if not name.startswith("_"): functions.append(name) - elif line.startswith('class '): + elif line.startswith("class "): # exclude private stuff name = self._get_object_name(line) - if not name.startswith('_'): + if not name.startswith("_"): classes.append(name) else: pass @@ -305,54 +304,54 @@ def generate_api_doc(self, uri): # get the names of all classes and functions functions, classes = self._parse_module_with_import(uri) if not len(functions) and not len(classes) and DEBUG: - print('WARNING: Empty -', uri) # dbg + print("WARNING: Empty -", uri) # dbg # Make a shorter version of the uri that omits the package name for # titles - uri_short = re.sub(r'^%s\.' % self.package_name, '', uri) + uri_short = re.sub(r"^%s\." % self.package_name, "", uri) - head = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n' - body = '' + head = ".. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n" + body = "" # Set the chapter title to read 'module' for all modules except for the # main packages - if '.' in uri_short: - title = 'Module: :mod:`' + uri_short + '`' - head += title + '\n' + self.rst_section_levels[2] * len(title) + if "." in uri_short: + title = "Module: :mod:`" + uri_short + "`" + head += title + "\n" + self.rst_section_levels[2] * len(title) else: - title = ':mod:`' + uri_short + '`' - head += title + '\n' + self.rst_section_levels[1] * len(title) + title = ":mod:`" + uri_short + "`" + 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' + head += "\n.. automodule:: " + uri + "\n" + head += "\n.. currentmodule:: " + uri + "\n" + body += "\n.. currentmodule:: " + uri + "\n\n" for c in classes: body += ( - '\n:class:`' + "\n:class:`" + c - + '`\n' + + "`\n" + self.rst_section_levels[3] * (len(c) + 9) - + '\n\n' + + "\n\n" ) - body += '\n.. autoclass:: ' + c + '\n' + 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' + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n" + "\n" + " .. automethod:: __init__\n\n" ) - head += '.. autosummary::\n\n' + head += ".. autosummary::\n\n" for f in classes + functions: - head += ' ' + f + '\n' - head += '\n' + head += " " + f + "\n" + head += "\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 += f + "\n" + body += self.rst_section_levels[3] * len(f) + "\n" + body += "\n.. autofunction:: " + f + "\n\n" return head, body @@ -378,9 +377,9 @@ def _survives_exclude(self, matchstr, match_type): False """ - if match_type == 'module': + if match_type == "module": patterns = self.module_skip_patterns - elif match_type == 'package': + elif match_type == "package": patterns = self.package_skip_patterns else: raise ValueError('Cannot interpret match type "%s"' % match_type) @@ -390,7 +389,7 @@ def _survives_exclude(self, matchstr, match_type): matchstr = matchstr[L:] for pat in patterns: try: - pat.search + _ = pat.search except AttributeError: pat = re.compile(pat) if pat.search(matchstr): @@ -433,13 +432,13 @@ def discover_modules(self): filenames = [ f[:-3] for f in filenames - if f.endswith('.py') and not f.startswith('__init__') + if f.endswith(".py") and not f.startswith("__init__") ] for subpkg_name in dirnames + filenames: - package_uri = '.'.join((root_uri, subpkg_name)) + package_uri = ".".join((root_uri, subpkg_name)) package_path = self._uri2path(package_uri) - if package_path and self._survives_exclude(package_uri, 'package'): + if package_path and self._survives_exclude(package_uri, "package"): modules.append(package_uri) return sorted(modules) @@ -447,7 +446,7 @@ def discover_modules(self): def write_modules_api(self, modules, outdir): # upper-level modules ulms = [ - '.'.join(m.split('.')[:2]) if m.count('.') >= 1 else m.split('.')[0] + ".".join(m.split(".")[:2]) if m.count(".") >= 1 else m.split(".")[0] for m in modules ] @@ -455,7 +454,7 @@ def write_modules_api(self, modules, outdir): module_by_ulm = OrderedDict() - for v, k in zip(modules, ulms): + for v, k in zip(modules, ulms, strict=False): if k in module_by_ulm: module_by_ulm[k].append(v) else: @@ -464,12 +463,12 @@ def write_modules_api(self, modules, outdir): written_modules = [] for ulm, mods in module_by_ulm.items(): - print('Generating docs for %s:' % ulm) + print("Generating docs for %s:" % ulm) document_head = [] document_body = [] for m in mods: - print(' -> ' + m) + print(" -> " + m) head, body = self.generate_api_doc(m) document_head.append(head) @@ -477,7 +476,7 @@ def write_modules_api(self, modules, outdir): out_module = ulm + self.rst_extension outfile = os.path.join(outdir, out_module) - fileobj = open(outfile, 'wt') + fileobj = open(outfile, "wt") fileobj.writelines(document_head + document_body) fileobj.close() @@ -509,7 +508,7 @@ def write_api_docs(self, outdir): modules = self.discover_modules() self.write_modules_api(modules, outdir) - def write_index(self, outdir, froot='gen', relative_to=None): + def write_index(self, outdir, froot="gen", relative_to=None): """Make a reST API index file from written files. Parameters @@ -529,22 +528,22 @@ def write_index(self, outdir, froot='gen', relative_to=None): """ if self.written_modules is None: - raise ValueError('No modules written') + raise ValueError("No modules written") # Get full filename path path = os.path.join(outdir, froot + self.rst_extension) # Path written into index is relative to rootpath if relative_to is not None: - relpath = (outdir + os.path.sep).replace(relative_to + os.path.sep, '') + relpath = (outdir + os.path.sep).replace(relative_to + os.path.sep, "") else: relpath = outdir - idx = open(path, 'wt') + idx = open(path, "wt") w = idx.write - w('.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n') + w(".. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n") - title = 'API Reference' - w(title + '\n') - w('=' * len(title) + '\n\n') - w('.. toctree::\n\n') + title = "API Reference" + w(title + "\n") + w("=" * len(title) + "\n\n") + w(".. toctree::\n\n") for f in self.written_modules: - w(' %s\n' % os.path.join(relpath, f)) + w(" %s\n" % os.path.join(relpath, f)) idx.close() diff --git a/docs/source/ext/build_modref_templates.py b/docs/source/ext/build_modref_templates.py index 1acea334f..2cba24f93 100755 --- a/docs/source/ext/build_modref_templates.py +++ b/docs/source/ext/build_modref_templates.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -"""Script to auto-generate our API docs. -""" +"""Script to auto-generate our API docs.""" + # stdlib imports from os.path import join as pjoin import sys @@ -15,54 +15,54 @@ def abort(error): - print('*WARNING* API documentation not generated: %s' % error) + print("*WARNING* API documentation not generated: %s" % error) exit() def generate_api_reference_rst( - app=None, package='fury', outdir='reference', defines=True + app=None, package="fury", outdir="reference", defines=True ): try: __import__(package) except ImportError: - abort('Can not import ' + package) + abort("Can not import " + package) module = sys.modules[package] installed_version = parse(module.__version__) - print('Generation API for {} v{}'.format(package, installed_version)) + print("Generation API for {} v{}".format(package, installed_version)) - docwriter = ApiDocWriter(package, rst_extension='.rst', other_defines=defines) + docwriter = ApiDocWriter(package, rst_extension=".rst", other_defines=defines) docwriter.package_skip_patterns += [ - r'.*test.*$', + r".*test.*$", # r'^\.utils.*', - r'\._version.*$', - r'\.interactor.*$', - r'\.optpkg.*$', + r"\._version.*$", + r"\.interactor.*$", + r"\.optpkg.*$", ] docwriter.object_skip_patterns += [ - r'.*FetcherError.*$', - r'.*urlopen.*', - r'.*add_callback.*', + r".*FetcherError.*$", + r".*urlopen.*", + r".*add_callback.*", ] if app is not None: outdir = pjoin(app.builder.srcdir, outdir) docwriter.write_api_docs(outdir) - docwriter.write_index(outdir, 'index', relative_to=outdir) - print('%d files written' % len(docwriter.written_modules)) + docwriter.write_index(outdir, "index", relative_to=outdir) + print("%d files written" % len(docwriter.written_modules)) def setup(app): """Setup sphinx extension for API reference generation.""" - app.connect('builder-inited', generate_api_reference_rst) + app.connect("builder-inited", generate_api_reference_rst) # app.connect('build-finished', summarize_failing_examples) - metadata = {'parallel_read_safe': True, 'version': app.config.version} + metadata = {"parallel_read_safe": True, "version": app.config.version} return metadata -if __name__ == '__main__': +if __name__ == "__main__": package = sys.argv[1] outdir = sys.argv[2] try: @@ -70,7 +70,7 @@ def setup(app): except IndexError: other_defines = True else: - other_defines = other_defines in ('True', 'true', '1') + other_defines = other_defines in ("True", "true", "1") generate_api_reference_rst( app=None, package=package, outdir=outdir, defines=other_defines diff --git a/docs/source/ext/github.py b/docs/source/ext/github.py index 99bea76e3..374c840c4 100644 --- a/docs/source/ext/github.py +++ b/docs/source/ext/github.py @@ -34,25 +34,25 @@ def make_link_node(rawtext, app, type, slug, options): base = app.config.github_project_url if not base: raise AttributeError - if not base.endswith('/'): - base += '/' + if not base.endswith("/"): + base += "/" except AttributeError as err: raise ValueError( - 'github_project_url configuration value is not set (%s)' % str(err) - ) + "github_project_url configuration value is not set (%s)" % str(err) + ) from err - ref = base + type + '/' + slug + '/' + ref = base + type + "/" + slug + "/" set_classes(options) - prefix = '#' - if type == 'pull': - prefix = 'PR ' + prefix + prefix = "#" + if type == "pull": + prefix = "PR " + prefix node = nodes.reference( rawtext, prefix + utils.unescape(slug), refuri=ref, **options ) return node -def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): +def ghissue_role(name, rawtext, text, lineno, inliner, options=None, content=None): """Link to a GitHub issue. Returns 2 part tuple containing list of nodes to insert into the @@ -67,13 +67,18 @@ def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): :param options: Directive options for customization. :param content: The directive content for customization. """ + if options is None: + options = {} + + _ = content + try: issue_num = int(text) if issue_num <= 0: raise ValueError except ValueError: msg = inliner.reporter.error( - 'GitHub issue number must be a number greater than or equal to 1; ' + "GitHub issue number must be a number greater than or equal to 1; " '"%s" is invalid.' % text, line=lineno, ) @@ -81,10 +86,10 @@ def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): return [prb], [msg] app = inliner.document.settings.env.app # app.info('issue %r' % text) - if 'pull' in name.lower(): - category = 'pull' - elif 'issue' in name.lower(): - category = 'issues' + if "pull" in name.lower(): + category = "pull" + elif "issue" in name.lower(): + category = "issues" else: msg = inliner.reporter.error( 'GitHub roles include "ghpull" and "ghissue", ' '"%s" is invalid.' % name, @@ -96,7 +101,7 @@ def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): return [node], [] -def ghuser_role(name, rawtext, text, lineno, inliner, options={}, content=[]): +def ghuser_role(name, rawtext, text, lineno, inliner, options=None, content=None): """Link to a GitHub user. Returns 2 part tuple containing list of nodes to insert into the @@ -111,14 +116,20 @@ def ghuser_role(name, rawtext, text, lineno, inliner, options={}, content=[]): :param options: Directive options for customization. :param content: The directive content for customization. """ + if options is None: + options = {} + + _ = name + _ = lineno + _ = content _ = inliner.document.settings.env.app # app.info('user link %r' % text) - ref = 'https://www.github.com/' + text + ref = "https://www.github.com/" + text node = nodes.reference(rawtext, text, refuri=ref, **options) return [node], [] -def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): +def ghcommit_role(name, rawtext, text, lineno, inliner, options=None, content=None): """Link to a GitHub commit. Returns 2 part tuple containing list of nodes to insert into the @@ -133,18 +144,24 @@ def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): :param options: Directive options for customization. :param content: The directive content for customization. """ + if options is None: + options = {} + + _ = name + _ = lineno + _ = content app = inliner.document.settings.env.app # app.info('user link %r' % text) try: base = app.config.github_project_url if not base: raise AttributeError - if not base.endswith('/'): - base += '/' + if not base.endswith("/"): + base += "/" except AttributeError as err: raise ValueError( - 'github_project_url configuration value is not set (%s)' % str(err) - ) + "github_project_url configuration value is not set (%s)" % str(err) + ) from err ref = base + text node = nodes.reference(rawtext, text[:6], refuri=ref, **options) @@ -159,11 +176,11 @@ def setup(app): from sphinx.util import logging logger = logging.getLogger(__name__) - logger.info('Initializing GitHub plugin') + logger.info("Initializing GitHub plugin") # app.info('Initializing GitHub plugin') - app.add_role('ghissue', ghissue_role) - app.add_role('ghpull', ghissue_role) - app.add_role('ghuser', ghuser_role) - app.add_role('ghcommit', ghcommit_role) - app.add_config_value('github_project_url', None, 'env') + app.add_role("ghissue", ghissue_role) + app.add_role("ghpull", ghissue_role) + app.add_role("ghuser", ghuser_role) + app.add_role("ghcommit", ghcommit_role) + app.add_config_value("github_project_url", None, "env") return diff --git a/docs/source/ext/github_tools.py b/docs/source/ext/github_tools.py index 2f56286df..fe812d58e 100644 --- a/docs/source/ext/github_tools.py +++ b/docs/source/ext/github_tools.py @@ -3,6 +3,7 @@ Taken from ipython """ + import argparse from datetime import datetime, timedelta import json @@ -22,15 +23,15 @@ # Globals # ---------------------------------------------------------------------------- -ISO8601 = '%Y-%m-%dT%H:%M:%SZ' +ISO8601 = "%Y-%m-%dT%H:%M:%SZ" PER_PAGE = 100 -element_pat = re.compile(r'<(.+?)>') +element_pat = re.compile(r"<(.+?)>") rel_pat = re.compile(r'rel=[\'"](\w+)[\'"]') LAST_RELEASE = datetime(2015, 3, 18) -CONTRIBUTORS_FILE = 'contributors.json' -GH_TOKEN = os.environ.get('GH_TOKEN', '') +CONTRIBUTORS_FILE = "contributors.json" +GH_TOKEN = os.environ.get("GH_TOKEN", "") # ---------------------------------------------------------------------------- @@ -49,30 +50,30 @@ def fetch_url(url): """ req = Request(url) if GH_TOKEN: - req.add_header('Authorization', 'token {0}'.format(GH_TOKEN)) + req.add_header("Authorization", "token {0}".format(GH_TOKEN)) try: - print('fetching %s' % url, file=sys.stderr) + print("fetching %s" % url, file=sys.stderr) # url = Request(url, # headers={'Accept': 'application/vnd.github.v3+json', # 'User-agent': 'Defined'}) - if not url.lower().startswith('http'): - msg = 'Please make sure you use http/https connection' + if not url.lower().startswith("http"): + msg = "Please make sure you use http/https connection" raise ValueError(msg) f = urlopen(req) except Exception as e: print(e) - print('return Empty data', file=sys.stderr) + print("return Empty data", file=sys.stderr) return {} return f def parse_link_header(headers): - link_s = headers.get('link', '') + link_s = headers.get("link", "") urls = element_pat.findall(link_s) rels = rel_pat.findall(link_s) d = {} - for rel, url in zip(rels, urls): + for rel, url in zip(rels, urls, strict=False): d[rel] = url return d @@ -97,14 +98,14 @@ def get_paged_request(url): continue results.extend(json.load(f)) links = parse_link_header(f.headers) - url = links.get('next') + url = links.get("next") return results -def get_issues(project='fury-gl/fury', state='closed', pulls=False): +def get_issues(project="fury-gl/fury", state="closed", pulls=False): """Get a list of the issues from the Github API.""" - which = 'pulls' if pulls else 'issues' - url = 'https://api.github.com/repos/%s/%s?state=%s&per_page=%i' % ( + which = "pulls" if pulls else "issues" + url = "https://api.github.com/repos/%s/%s?state=%s&per_page=%i" % ( project, which, state, @@ -113,13 +114,13 @@ def get_issues(project='fury-gl/fury', state='closed', pulls=False): return get_paged_request(url) -def get_tags(project='fury-gl/fury'): +def get_tags(project="fury-gl/fury"): """Get a list of the tags from the Github API.""" - url = 'https://api.github.com/repos/{0}/tags'.format(project) + url = "https://api.github.com/repos/{0}/tags".format(project) return get_paged_request(url) -def fetch_basic_stats(project='fury-gl/fury'): +def fetch_basic_stats(project="fury-gl/fury"): """Fetch the basic stats. Returns @@ -137,24 +138,24 @@ def fetch_basic_stats(project='fury-gl/fury'): """ desired_keys = [ - 'stargazers_count', - 'stargazers_url', - 'watchers_count', - 'watchers_url', - 'forks_count', - 'forks_url', - 'open_issues', - 'issues_url', - 'subscribers_count', - 'subscribers_url', + "stargazers_count", + "stargazers_url", + "watchers_count", + "watchers_url", + "forks_count", + "forks_url", + "open_issues", + "issues_url", + "subscribers_count", + "subscribers_url", ] - url = 'https://api.github.com/repos/{0}'.format(project) + url = "https://api.github.com/repos/{0}".format(project) r_json = get_json_from_url(url) - basic_stats = dict((k, r_json[k]) for k in desired_keys if k in r_json) + basic_stats = {k: r_json[k] for k in desired_keys if k in r_json} return basic_stats -def fetch_contributor_stats(project='fury-gl/fury'): +def fetch_contributor_stats(project="fury-gl/fury"): """Fetch stats of contributors. Returns @@ -183,67 +184,69 @@ def fetch_contributor_stats(project='fury-gl/fury'): } """ - url = 'https://api.github.com/repos/{0}/stats/contributors'.format(project) + url = "https://api.github.com/repos/{0}/stats/contributors".format(project) r_json = get_json_from_url(url) contributor_stats = {} - contributor_stats['total_contributors'] = len(r_json) - contributor_stats['contributors'] = [] + contributor_stats["total_contributors"] = len(r_json) + contributor_stats["contributors"] = [] cumulative_commits = 0 - desired_keys = ['login', 'avatar_url', 'html_url'] - with open(os.path.join(os.path.dirname(__file__), '..', CONTRIBUTORS_FILE)) as f: + desired_keys = ["login", "avatar_url", "html_url"] + with open(os.path.join(os.path.dirname(__file__), "..", CONTRIBUTORS_FILE)) as f: extra_info = json.load(f) - extra_info = extra_info['team'] + extra_info['core_team'] + extra_info = extra_info["team"] + extra_info["core_team"] for contributor in r_json: contributor_dict = dict( - (k, contributor['author'][k]) - for k in desired_keys - if k in contributor['author'] + { + (k, contributor["author"][k]) + for k in desired_keys + if k in contributor["author"] + } ) # check if "author" is null - if not contributor_dict['login']: + if not contributor_dict["login"]: continue # Replace key name - contributor_dict['username'] = usrname = contributor_dict.pop('login') - contributor_dict['nb_commits'] = contributor['total'] + contributor_dict["username"] = usrname = contributor_dict.pop("login") + contributor_dict["nb_commits"] = contributor["total"] # Add extra information like fullname and affiliation l_extra_info = [ - e for e in extra_info if e['username'].lower() == usrname.lower() + e for e in extra_info if e["username"].lower() == usrname.lower() ] l_extra_info = l_extra_info[0] if l_extra_info else {} contributor_dict.update(l_extra_info) # Update total commits - cumulative_commits += contributor_dict['nb_commits'] + cumulative_commits += contributor_dict["nb_commits"] total_additions = 0 total_deletions = 0 - for week in contributor['weeks']: - total_additions += week['a'] - total_deletions += week['d'] + for week in contributor["weeks"]: + total_additions += week["a"] + total_deletions += week["d"] - contributor_dict['total_additions'] = total_additions - contributor_dict['total_deletions'] = total_deletions + contributor_dict["total_additions"] = total_additions + contributor_dict["total_deletions"] = total_deletions # contributor_dict["weekly_commits"] = contributor["weeks"] - contributor_stats['contributors'].insert(0, contributor_dict) + contributor_stats["contributors"].insert(0, contributor_dict) - contributor_stats['contributors'] = sorted( - contributor_stats['contributors'], - key=lambda x: x.get('nb_commits'), + contributor_stats["contributors"] = sorted( + contributor_stats["contributors"], + key=lambda x: x.get("nb_commits"), reverse=True, ) - contributor_stats['total_commits'] = cumulative_commits + contributor_stats["total_commits"] = cumulative_commits return contributor_stats -def cumulative_contributors(project='fury-gl/fury', show=True): +def cumulative_contributors(project="fury-gl/fury", show=True): """Calculate total contributors as new contributors join with time. Parameters @@ -260,14 +263,14 @@ def cumulative_contributors(project='fury-gl/fury', show=True): ] """ - url = 'https://api.github.com/repos/{0}/stats/contributors'.format(project) + url = "https://api.github.com/repos/{0}/stats/contributors".format(project) r_json = get_json_from_url(url) contributors_join_date = {} for contributor in r_json: - for week in contributor['weeks']: - if week['c'] > 0: - join_date = week['w'] + for week in contributor["weeks"]: + if week["c"] > 0: + join_date = week["w"] if join_date not in contributors_join_date: contributors_join_date[join_date] = 0 contributors_join_date[join_date] += 1 @@ -288,35 +291,35 @@ def cumulative_contributors(project='fury-gl/fury', show=True): import matplotlib.pyplot as plt import numpy as np - years, c_cum = zip(*cumulative_list) + years, c_cum = zip(*cumulative_list, strict=False) years_ticks = np.linspace(min(years), max(years), 15) years_labels = [] for y in years_ticks: date = datetime.utcfromtimestamp(int(y)) - date_str = 'Q{} - '.format((date.month - 1) // 3 + 1) - date_str += date.strftime('%Y') + date_str = "Q{} - ".format((date.month - 1) // 3 + 1) + date_str += date.strftime("%Y") years_labels.append(date_str) - plt.fill_between(years, c_cum, color='skyblue', alpha=0.4) - plt.plot(years, c_cum, color='Slateblue', alpha=0.6, linewidth=2) + plt.fill_between(years, c_cum, color="skyblue", alpha=0.4) + plt.plot(years, c_cum, color="Slateblue", alpha=0.6, linewidth=2) plt.tick_params(labelsize=12) plt.xticks(years_ticks, years_labels, rotation=45, fontsize=8) plt.yticks(fontsize=8) - plt.xlabel('Date', size=12) - plt.ylabel('Contributors', size=12) + plt.xlabel("Date", size=12) + plt.ylabel("Contributors", size=12) plt.ylim(bottom=0) plt.grid(True) plt.legend( [ - mpatches.Patch(color='skyblue'), + mpatches.Patch(color="skyblue"), ], [ - 'Contributors', + "Contributors", ], bbox_to_anchor=(0.5, 1.1), - loc='upper center', + loc="upper center", ) - plt.savefig('fury_cumulative_contributors.png', dpi=150) + plt.savefig("fury_cumulative_contributors.png", dpi=150) plt.show() return cumulative_list @@ -334,43 +337,43 @@ def issues2dict(issues): """Convert a list of issues to a dict, keyed by issue number.""" idict = {} for i in issues: - idict[i['number']] = i + idict[i["number"]] = i return idict def is_pull_request(issue): """Return True if the given issue is a pull request.""" - return 'pull_request_url' in issue + return "pull_request_url" in issue -def issues_closed_since(period=LAST_RELEASE, project='fury-gl/fury', pulls=False): +def issues_closed_since(period=LAST_RELEASE, project="fury-gl/fury", pulls=False): """Get all issues closed since a particular point in time. period can either be a datetime object, or a timedelta object. In the latter case, it is used as a time before the present. """ - which = 'pulls' if pulls else 'issues' + which = "pulls" if pulls else "issues" if isinstance(period, timedelta): period = datetime.now() - period url = ( - 'https://api.github.com/repos/%s/%s?state=closed&sort=updated&' - 'since=%s&per_page=%i' + "https://api.github.com/repos/%s/%s?state=closed&sort=updated&" + "since=%s&per_page=%i" ) % (project, which, period.strftime(ISO8601), PER_PAGE) allclosed = get_paged_request(url) # allclosed = get_issues(project=project, state='closed', pulls=pulls, # since=period) - filtered = [i for i in allclosed if _parse_datetime(i['closed_at']) > period] + filtered = [i for i in allclosed if _parse_datetime(i["closed_at"]) > period] # exclude rejected PRs if pulls: - filtered = [pr for pr in filtered if pr['merged_at']] + filtered = [pr for pr in filtered if pr["merged_at"]] return filtered -def sorted_by_field(issues, field='closed_at', reverse=False): +def sorted_by_field(issues, field="closed_at", reverse=False): """Return a list of issues sorted by closing date date.""" return sorted(issues, key=lambda i: i[field], reverse=reverse) @@ -380,14 +383,14 @@ def report(issues, show_urls=False): # titles may have unicode in them, so we must encode everything below if show_urls: for i in issues: - role = 'ghpull' if 'merged_at' in i else 'ghissue' - print('* :%s:`%d`: %s' % (role, i['number'], i['title'])) + role = "ghpull" if "merged_at" in i else "ghissue" + print("* :%s:`%d`: %s" % (role, i["number"], i["title"])) else: for i in issues: - print('* %d: %s' % (i['number'], i['title'])) + print("* %d: %s" % (i["number"], i["title"])) -def get_all_versions(ignore='', project='fury-gl/fury'): +def get_all_versions(ignore="", project="fury-gl/fury"): """Return all releases version. Parameters @@ -406,47 +409,47 @@ def get_all_versions(ignore='', project='fury-gl/fury'): """ tags = get_tags(project=project) - l_version = [t['name'] for t in tags] + l_version = [t["name"] for t in tags] - if ignore.lower() in ['micro', 'minor']: - l_version = list(set([re.sub(r'(\d+)$', 'x', v) for v in l_version])) + if ignore.lower() in ["micro", "minor"]: + l_version = list({re.sub(r"(\d+)$", "x", v) for v in l_version}) - if ignore.lower() == 'minor': - l_version = list(set([re.sub(r'\.(\d+)\.', '.x.', v) for v in l_version])) + if ignore.lower() == "minor": + l_version = list({re.sub(r"\.(\d+)\.", ".x.", v) for v in l_version}) return l_version -def version_compare(current_version, version_number, op='eq', all_versions=None): +def version_compare(current_version, version_number, op="eq", all_versions=None): """Compare doc version. This is afilter for sphinx template.""" - p = re.compile(r'(\d+)\.(\d+)') + p = re.compile(r"(\d+)\.(\d+)") d_operator = { - '<': operator.lt, - 'lt': operator.lt, - '<=': operator.le, - 'le': operator.le, - '>': operator.gt, - 'gt': operator.gt, - '>=': operator.ge, - 'ge': operator.ge, - '==': operator.eq, - '=': operator.eq, - 'eq': operator.eq, - '!=': operator.ne, + "<": operator.lt, + "lt": operator.lt, + "<=": operator.le, + "le": operator.le, + ">": operator.gt, + "gt": operator.gt, + ">=": operator.ge, + "ge": operator.ge, + "==": operator.eq, + "=": operator.eq, + "eq": operator.eq, + "!=": operator.ne, } # Setup default value to op if op not in d_operator.keys(): - op = 'eq' + op = "eq" # check dev page - if current_version.lower() == 'dev': - return 'post' in version_number + if current_version.lower() == "dev": + return "post" in version_number # major and minor extraction current = p.search(current_version) ref = p.search(version_number) - if current_version.lower() == 'latest': + if current_version.lower() == "latest": # Check if it is the latest release all_versions = all_versions or get_all_versions() if not all_versions: @@ -455,28 +458,27 @@ def version_compare(current_version, version_number, op='eq', all_versions=None) last_version = p.search(last_version) if ( parse(last_version.group()) == parse(ref.group()) - and 'post' not in version_number + and "post" not in version_number ): return True return False - if 'post' in version_number: + if "post" in version_number: return False return d_operator[op](parse(current.group()), parse(ref.group())) def username_to_fullname(all_authors): - with open(os.path.join(os.path.dirname(__file__), '..', CONTRIBUTORS_FILE)) as f: - + with open(os.path.join(os.path.dirname(__file__), "..", CONTRIBUTORS_FILE)) as f: extra_info = json.load(f) - extra_info = extra_info['team'] + extra_info['core_team'] - extra_info = {i['username']: i['fullname'] for i in extra_info} + extra_info = extra_info["team"] + extra_info["core_team"] + extra_info = {i["username"]: i["fullname"] for i in extra_info} curent_authors = all_authors for i, author in enumerate(all_authors): if author[2:] in extra_info.keys(): - curent_authors[i] = '* ' + extra_info[author[2:]] + curent_authors[i] = "* " + extra_info[author[2:]] return curent_authors @@ -485,26 +487,26 @@ def github_stats(**kwargs): """Get release github stats.""" # Whether to add reST urls for all issues in printout. show_urls = True - save = kwargs.get('save', None) + save = kwargs.get("save", None) if save: - version = kwargs.get('version', 'vx.x.x') - fname = 'releasev' + version + '.rst' - fpath = os.path.join(os.path.dirname(__file__), '..', 'release_notes', fname) - f = open(fpath, 'w') + version = kwargs.get("version", "vx.x.x") + fname = "releasev" + version + ".rst" + fpath = os.path.join(os.path.dirname(__file__), "..", "release_notes", fname) + f = open(fpath, "w") orig_stdout = sys.stdout sys.stdout = f - print('.. _{}'.format(fname.replace('.rst', ':'))) + print(".. _{}".format(fname.replace(".rst", ":"))) print() print( ( - '==============================\n' - ' Release notes v{}\n ()' - '==============================' + "==============================\n" + " Release notes v{}\n ()" + "==============================" ).format(version) ) # By default, search one month back - tag = kwargs.get('tag', None) + tag = kwargs.get("tag", None) if tag is None: if len(sys.argv) > 1: try: @@ -513,17 +515,17 @@ def github_stats(**kwargs): tag = sys.argv[1] else: tag = check_output( - ['git', 'describe', '--abbrev=0'], universal_newlines=True + ["git", "describe", "--abbrev=0"], universal_newlines=True ).strip() if tag: - cmd = ['git', 'log', '-1', '--format=%ai', tag] - tagday, _ = check_output(cmd, universal_newlines=True).strip().rsplit(' ', 1) - since = datetime.strptime(tagday, '%Y-%m-%d %H:%M:%S') + cmd = ["git", "log", "-1", "--format=%ai", tag] + tagday, _ = check_output(cmd, universal_newlines=True).strip().rsplit(" ", 1) + since = datetime.strptime(tagday, "%Y-%m-%d %H:%M:%S") else: since = datetime.now() - timedelta(days=days) - print('fetching GitHub stats since %s (tag: %s)' % (since, tag), file=sys.stderr) + print("fetching GitHub stats since %s (tag: %s)" % (since, tag), file=sys.stderr) # turn off to play interactively without redownloading, use %run -i if 1: issues = issues_closed_since(since, pulls=False) @@ -539,51 +541,51 @@ def github_stats(**kwargs): # Print summary report we can directly include into release notes. print() - since_day = since.strftime('%Y/%m/%d') - today = datetime.today().strftime('%Y/%m/%d') - print('GitHub stats for %s - %s (tag: %s)' % (since_day, today, tag)) + since_day = since.strftime("%Y/%m/%d") + today = datetime.today().strftime("%Y/%m/%d") + print("GitHub stats for %s - %s (tag: %s)" % (since_day, today, tag)) print() print( - 'These lists are automatically generated, and may be incomplete or' - ' contain duplicates.' + "These lists are automatically generated, and may be incomplete or" + " contain duplicates." ) print() if tag: # print git info, in addition to GitHub info: - since_tag = tag + '..' - cmd = ['git', 'log', '--oneline', since_tag] + since_tag = tag + ".." + cmd = ["git", "log", "--oneline", since_tag] ncommits = check_output(cmd, universal_newlines=True).splitlines() ncommits = len(ncommits) - author_cmd = ['git', 'log', '--format=* %aN', since_tag] + author_cmd = ["git", "log", "--format=* %aN", since_tag] all_authors = check_output(author_cmd, universal_newlines=True).splitlines() # Replace username by author name all_authors = username_to_fullname(all_authors) unique_authors = sorted(set(all_authors)) if len(unique_authors) == 0: - print('No commits during this period.') + print("No commits during this period.") else: print( - 'The following %i authors contributed %i commits.' + "The following %i authors contributed %i commits." % (len(unique_authors), ncommits) ) print() - print('\n'.join(unique_authors)) + print("\n".join(unique_authors)) print() print() print( - 'We closed a total of %d issues, %d pull requests and %d' - ' regular issues;\nthis is the full list (generated with' - ' the script \n:file:`tools/github_stats.py`):' + "We closed a total of %d issues, %d pull requests and %d" + " regular issues;\nthis is the full list (generated with" + " the script \n:file:`tools/github_stats.py`):" % (n_total, n_pulls, n_issues) ) print() - print('Pull Requests (%d):\n' % n_pulls) + print("Pull Requests (%d):\n" % n_pulls) report(pulls, show_urls) print() - print('Issues (%d):\n' % n_issues) + print("Issues (%d):\n" % n_issues) report(issues, show_urls) if save: @@ -595,7 +597,7 @@ def github_stats(**kwargs): # Sphinx connection # ---------------------------------------------------------------------------- def add_jinja_filters(app): - app.builder.templates.environment.filters['version_compare'] = version_compare + app.builder.templates.environment.filters["version_compare"] = version_compare def setup(app): @@ -604,8 +606,8 @@ def setup(app): - Collect and clean authors - Adds extra jinja filters. """ - app.connect('builder-inited', add_jinja_filters) - app.add_css_file('css/custom_github.css') + app.connect("builder-inited", add_jinja_filters) + app.add_css_file("css/custom_github.css") # ---------------------------------------------------------------------------- @@ -613,24 +615,24 @@ def setup(app): # ---------------------------------------------------------------------------- -if __name__ == '__main__': +if __name__ == "__main__": # e.g github_tools.py --tag=v0.1.3 --save --version=0.1.4 parser = argparse.ArgumentParser() parser.add_argument( - '--tag', + "--tag", type=str, default=None, - help='from which tag version to get information', + help="from which tag version to get information", ) parser.add_argument( - '--version', type=str, default='', help='current release version' + "--version", type=str, default="", help="current release version" ) parser.add_argument( - '--save', - dest='save', - action='store_true', + "--save", + dest="save", + action="store_true", default=False, - help=('Save in the release folder' 'and add rst header'), + help=("Save in the release folder" "and add rst header"), ) args = parser.parse_args() diff --git a/docs/source/ext/prepare_gallery.py b/docs/source/ext/prepare_gallery.py index e328429f7..10f0cae7e 100644 --- a/docs/source/ext/prepare_gallery.py +++ b/docs/source/ext/prepare_gallery.py @@ -3,6 +3,7 @@ import os from pathlib import Path import shutil +import sys from sphinx.util import logging @@ -28,31 +29,31 @@ def __post_init__(self): def abort(error): - print(f'*WARNING* Examples Revamp not generated: \n\n{error}') + print(f"*WARNING* Examples Revamp not generated: \n\n{error}") exit() def prepare_gallery(app=None): - examples_dir = os.path.join(app.srcdir, '..', 'examples') - examples_revamp_dir = os.path.join(app.srcdir, '..', 'examples_revamped') + examples_dir = os.path.join(app.srcdir, "..", "examples") + examples_revamp_dir = os.path.join(app.srcdir, "..", "examples_revamped") os.makedirs(examples_revamp_dir, exist_ok=True) - f_example_desc = Path(examples_dir, '_valid_examples.toml') + f_example_desc = Path(examples_dir, "_valid_examples.toml") if not f_example_desc.exists(): - msg = 'No valid examples description file found ' + msg = "No valid examples description file found " msg += "(e.g '_valid_examples.toml')" abort(msg) - with open(f_example_desc, 'rb') as fobj: + with open(f_example_desc, "rb") as fobj: try: desc_examples = tomllib.load(fobj) except Exception as e: - msg = f'Error Loading examples description file: {e}.\n\n' - msg += 'Please check the file format.' + msg = f"Error Loading examples description file: {e}.\n\n" + msg += "Please check the file format." abort(msg) - if 'main' not in desc_examples.keys(): - msg = 'No main section found in examples description file' + if "main" not in desc_examples.keys(): + msg = "No main section found in examples description file" abort(msg) try: @@ -60,18 +61,18 @@ def prepare_gallery(app=None): [examplesConfig(folder_name=k, **v) for k, v in desc_examples.items()] ) except Exception as e: - msg = f'Error parsing examples description file: {e}.\n\n' - msg += 'Please check the file format.' + msg = f"Error parsing examples description file: {e}.\n\n" + msg += "Please check the file format." abort(msg) if examples_config[0].position != 0: - msg = 'Main section must be first in examples description file with position=0' + msg = "Main section must be first in examples description file with position=0" abort(msg) - elif examples_config[0].folder_name != 'main': + elif examples_config[0].folder_name != "main": msg = "Main section must be named 'main' in examples description file" abort(msg) elif examples_config[0].enable is False: - msg = 'Main section must be enabled in examples description file' + msg = "Main section must be enabled in examples description file" abort(msg) disable_examples_section = [] @@ -84,7 +85,7 @@ def prepare_gallery(app=None): # Create folder for each example if example.position != 0: folder = Path( - examples_revamp_dir, f'{example.position:02d}_{example.folder_name}' + examples_revamp_dir, f"{example.position:02d}_{example.folder_name}" ) else: folder = Path(examples_revamp_dir) @@ -93,11 +94,11 @@ def prepare_gallery(app=None): os.makedirs(folder) # Create readme file - if example.readme.startswith('file:'): - filename = example.readme.split('file:')[1].strip() - shutil.copy(Path(examples_dir, filename), Path(folder, 'README.rst')) + if example.readme.startswith("file:"): + filename = example.readme.split("file:")[1].strip() + shutil.copy(Path(examples_dir, filename), Path(folder, "README.rst")) else: - with open(Path(folder, 'README.rst'), 'w') as fi: + with open(Path(folder, "README.rst"), "w") as fi: fi.write(example.readme) # Copy files to folder @@ -106,19 +107,19 @@ def prepare_gallery(app=None): for fi in example.files: if not Path(examples_dir, fi).exists(): - msg = f'\tFile {fi} not found in examples folder: {examples_dir}.\n\n' - msg += '\tPlease, Add the file or remove it from the description file.' + msg = f"\tFile {fi} not found in examples folder: {examples_dir}.\n\n" + msg += "\tPlease, Add the file or remove it from the description file." logger.info(msg) continue shutil.copy(Path(examples_dir, fi), Path(folder, fi)) # Check if all python examples are in the description file files_in_config = [fi for ex in examples_config for fi in ex.files] - all_examples = fnmatch.filter(os.listdir(examples_dir), '*.py') + all_examples = fnmatch.filter(os.listdir(examples_dir), "*.py") for all_ex in all_examples: if all_ex in files_in_config: continue - msg = f'File {all_ex} not found in examples description file: {f_example_desc}' + msg = f"File {all_ex} not found in examples description file: {f_example_desc}" logger.info(msg) @@ -130,18 +131,18 @@ def setup(app): app: Sphinx application context. """ - logger.info('Initializing Examples folder revamp plugin...') + logger.info("Initializing Examples folder revamp plugin...") - app.connect('builder-inited', prepare_gallery) + app.connect("builder-inited", prepare_gallery) # app.connect('build-finished', summarize_failing_examples) - metadata = {'parallel_read_safe': True, 'version': app.config.version} + metadata = {"parallel_read_safe": True, "version": app.config.version} return metadata -if __name__ == '__main__': +if __name__ == "__main__": gallery_name = sys.argv[1] outdir = sys.argv[2] - prepare_gallery(app=None, package=package, outdir=outdir) + prepare_gallery(app=None) diff --git a/docs/source/ext/rstjinja.py b/docs/source/ext/rstjinja.py index b5546583b..3c6a4b39b 100644 --- a/docs/source/ext/rstjinja.py +++ b/docs/source/ext/rstjinja.py @@ -4,7 +4,7 @@ def rstjinja(app, _docname, source): """Render our pages as a jinja template for fancy templating goodness.""" # Make sure we're outputting HTML - if app.builder.format != 'html': + if app.builder.format != "html": return src = source[0] rendered = app.builder.templates.render_string(src, app.config.html_context) @@ -12,4 +12,4 @@ def rstjinja(app, _docname, source): def setup(app): - app.connect('source-read', rstjinja) + app.connect("source-read", rstjinja) diff --git a/docs/source/ext/scrap.py b/docs/source/ext/scrap.py index f7004d418..73ae432a9 100644 --- a/docs/source/ext/scrap.py +++ b/docs/source/ext/scrap.py @@ -14,11 +14,11 @@ def __init__(self): def __call__(self, block, block_vars, gallery_conf): # Find all image files in the current directory. - path_example = os.path.dirname(block_vars['src_file']) + path_example = os.path.dirname(block_vars["src_file"]) image_files = _find_images(path_example) # Iterate through files, copy them to the SG output directory image_names = [] - image_path_iterator = block_vars['image_path_iterator'] + image_path_iterator = block_vars["image_path_iterator"] for path_orig in image_files: # If we already know about this image and it hasn't been modified # since starting, then skip it @@ -37,15 +37,18 @@ def __call__(self, block, block_vars, gallery_conf): shutil.copyfile(path_orig, path_new) if not image_names: - return '' + return "" - return figure_rst(image_names, gallery_conf['src_dir']) + return figure_rst(image_names, gallery_conf["src_dir"]) -def _find_images(path, image_extensions=['jpg', 'jpeg', 'png', 'gif']): +def _find_images(path, image_extensions=None): """Find all unique image paths for a set of extensions.""" + if image_extensions is None: + image_extensions = ["jpg", "jpeg", "png", "gif"] + image_files = set() for ext in image_extensions: - this_ext_files = set(glob.glob(os.path.join(path, '*.' + ext))) + this_ext_files = set(glob.glob(os.path.join(path, "*." + ext))) image_files = image_files.union(this_ext_files) return image_files diff --git a/docs/upload_to_gh-pages.py b/docs/upload_to_gh-pages.py index 4a71d0f11..a506c4cc3 100644 --- a/docs/upload_to_gh-pages.py +++ b/docs/upload_to_gh-pages.py @@ -18,7 +18,7 @@ import sys if sys.version_info < (3, 4): - raise RuntimeError('Python 3.4 and above is required' ' for running this script') + raise RuntimeError("Python 3.4 and above is required" " for running this script") else: from pathlib import Path @@ -27,12 +27,12 @@ ############################################################################### docs_dir = os.path.realpath(os.path.dirname(os.path.realpath(__file__))) -pkg_name = 'fury' -pkg_path = os.path.realpath(pjoin(docs_dir, '..')) -pages_dir = os.path.realpath(pjoin(docs_dir, 'gh-pages')) -html_dir = os.path.realpath(pjoin(docs_dir, 'build', 'html')) -pdf_dir = os.path.realpath(pjoin(docs_dir, 'build', 'latex')) -pages_repo = 'https://github.com/fury-gl/fury-website.git' +pkg_name = "fury" +pkg_path = os.path.realpath(pjoin(docs_dir, "..")) +pages_dir = os.path.realpath(pjoin(docs_dir, "gh-pages")) +html_dir = os.path.realpath(pjoin(docs_dir, "build", "html")) +pdf_dir = os.path.realpath(pjoin(docs_dir, "build", "latex")) +pages_repo = "https://github.com/fury-gl/fury-website.git" ############################################################################### @@ -75,7 +75,7 @@ def sh3(cmd): ############################################################################### # Script starts ############################################################################### -if __name__ == '__main__': +if __name__ == "__main__": # Get starting folder current_dir = os.getcwd() @@ -84,16 +84,15 @@ def sh3(cmd): mod = __import__(pkg_name) if pjoin(pkg_path, pkg_name).lower() != os.path.dirname(mod.__file__).lower(): - print(pjoin(pkg_path, pkg_name)) print(mod.__file__) raise RuntimeError( - 'You should work with the source and not the ' 'installed package' + "You should work with the source and not the " "installed package" ) # find the version number - tag = 'dev' - if any(t in mod.__version__.lower() for t in ['dev', 'post']): + tag = "dev" + if any(t in mod.__version__.lower() for t in ["dev", "post"]): tag = mod.__version__ if len(sys.argv) == 2: @@ -104,45 +103,43 @@ def sh3(cmd): # Documentation version {} # # using tag '{}' -##############################################""".format( - mod.__version__, tag - ) +##############################################""".format(mod.__version__, tag) print(intro_msg) if not os.path.exists(html_dir): raise RuntimeError( - 'Documentation build folder not found! You should ' - 'generate the documentation first via this ' + "Documentation build folder not found! You should " + "generate the documentation first via this " "command: 'make -C docs html')" ) if not os.path.exists(pages_dir): # clone the gh-pages repo if we haven't already. - sh('git clone {0} {1}'.format(pages_repo, pages_dir)) + sh("git clone {0} {1}".format(pages_repo, pages_dir)) # ensure up-to-date before operating cd(pages_dir) try: - sh('git checkout gh-pages') - sh('git pull') + sh("git checkout gh-pages") + sh("git pull") except BaseException: - print('\nLooks like gh-pages branch does not exist!') - print('Do you want to create a new one? (y/n)') + print("\nLooks like gh-pages branch does not exist!") + print("Do you want to create a new one? (y/n)") while 1: choice = str(input()).lower() - if choice == 'y': - sh('git checkout -b gh-pages') - sh('rm -rf *') - sh('git add .') + if choice == "y": + sh("git checkout -b gh-pages") + sh("rm -rf *") + sh("git add .") sh("git commit -m 'cleaning gh-pages branch'") - sh('git push origin gh-pages') + sh("git push origin gh-pages") break - elif choice == 'n': - print('Please manually create a new gh-pages branch' ' and try again.') + elif choice == "n": + print("Please manually create a new gh-pages branch" " and try again.") sys.exit(0) else: - print('Please enter valid choice ..') + print("Please enter valid choice ..") # delete tag version and copy the doc dest = os.path.join(pages_dir, tag) @@ -151,28 +148,28 @@ def sh3(cmd): try: cd(pages_dir) - status = sh2('LANG=en_US git status | head -1') - branch = re.match(b'On branch (.*)$', status).group(1) - if branch != b'gh-pages': + status = sh2("LANG=en_US git status | head -1") + branch = re.match(b"On branch (.*)$", status).group(1) + if branch != b"gh-pages": e = 'On %r, git branch is %r, MUST be "gh-pages"' % (pages_dir, branch) raise RuntimeError(e) # Add no jekyll file - if os.path.exists(pjoin(pages_dir, '.nojekyll')): - Path('.nojekyll').touch() - sh('git add .nojekyll') + if os.path.exists(pjoin(pages_dir, ".nojekyll")): + Path(".nojekyll").touch() + sh("git add .nojekyll") - sh('git add --all {}'.format(tag)) + sh("git add --all {}".format(tag)) - status = sh2('LANG=en_US git status | tail -1') - if not re.match(b'nothing to commit', status): + status = sh2("LANG=en_US git status | tail -1") + if not re.match(b"nothing to commit", status): sh2('git commit -m "Updated doc release: {}"'.format(tag)) else: - print('\n! Note: no changes to commit\n') + print("\n! Note: no changes to commit\n") - print('Most recent commit:') + print("Most recent commit:") sys.stdout.flush() - sh('git --no-pager log --oneline HEAD~1..') + sh("git --no-pager log --oneline HEAD~1..") # update stable symlink # latest_tag = sh2('git describe --exact-match --abbrev=0') # os.symlink() @@ -180,6 +177,6 @@ def sh3(cmd): finally: cd(current_dir) - print('') - print('Now verify the build in: %r' % dest) + print("") + print("Now verify the build in: %r" % dest) print("If everything looks good, run 'git push' inside doc/gh-pages.") diff --git a/fury/__init__.py b/fury/__init__.py index 5c4ee0347..1447797f9 100644 --- a/fury/__init__.py +++ b/fury/__init__.py @@ -1,4 +1,5 @@ """Init file for visualization package.""" + import warnings from fury.pkg_info import __version__, pkg_commit_hash @@ -27,31 +28,31 @@ def get_info(verbose=False): from fury.optpkg import optional_package - mpl, have_mpl, _ = optional_package('matplotlib') - dipy, have_dipy, _ = optional_package('dipy') + mpl, have_mpl, _ = optional_package("matplotlib") + dipy, have_dipy, _ = optional_package("dipy") install_type, commit_hash = pkg_commit_hash(dirname(__file__)) - info = dict( - fury_version=__version__, - pkg_path=dirname(__file__), - commit_hash=commit_hash, - sys_version=sys.version, - sys_executable=sys.executable, - sys_platform=sys.platform, - numpy_version=numpy.__version__, - scipy_version=scipy.__version__, - vtk_version=ccvtk.vtkVersion.GetVTKVersion(), - ) - - d_mpl = dict(matplotlib_version=mpl.__version__) if have_mpl else {} - d_dipy = dict(dipy_version=dipy.__version__) if have_dipy else {} + info = { + "fury_version": __version__, + "pkg_path": dirname(__file__), + "commit_hash": commit_hash, + "sys_version": sys.version, + "sys_executable": sys.executable, + "sys_platform": sys.platform, + "numpy_version": numpy.__version__, + "scipy_version": scipy.__version__, + "vtk_version": ccvtk.vtkVersion.GetVTKVersion(), + } + + d_mpl = {"matplotlib_version": mpl.__version__} if have_mpl else {} + d_dipy = {"dipy_version": dipy.__version__} if have_dipy else {} info.update(d_mpl) info.update(d_dipy) if verbose: - print('\n'.join(['{0}: {1}'.format(k, v) for k, v in info.items()])) + print("\n".join(["{0}: {1}".format(k, v) for k, v in info.items()])) return info @@ -65,9 +66,9 @@ def enable_warnings(warnings_origin=None): list origin ['all', 'fury', 'vtk', 'matplotlib', ...] """ - warnings_origin = warnings_origin or ('all',) + warnings_origin = warnings_origin or ("all",) - if 'all' in warnings_origin or 'vtk' in warnings_origin: + if "all" in warnings_origin or "vtk" in warnings_origin: import vtkmodules.vtkCommonCore as ccvtk ccvtk.vtkObject.GlobalWarningDisplayOn() @@ -82,16 +83,16 @@ def disable_warnings(warnings_origin=None): list origin ['all', 'fury', 'vtk', 'matplotlib', ...] """ - warnings_origin = warnings_origin or ('all',) + warnings_origin = warnings_origin or ("all",) - if 'all' in warnings_origin or 'vtk' in warnings_origin: + if "all" in warnings_origin or "vtk" in warnings_origin: import vtkmodules.vtkCommonCore as ccvtk ccvtk.vtkObject.GlobalWarningDisplayOff() # We switch off the warning display during the release -if not ('post' in __version__) and not ('dev' in __version__): +if "post" not in __version__ and "dev" not in __version__: disable_warnings() # Ignore this specific warning below from vtk < 8.2. @@ -100,9 +101,9 @@ def disable_warnings(warnings_origin=None): # treated as `np.complex128 == np.dtype(complex).type`. # assert not numpy.issubdtype(z.dtype, complex), \ warnings.filterwarnings( - 'ignore', - message='Conversion of the second argument of' - ' issubdtype from `complex` to' - ' `np.complexfloating` is deprecated.*', + "ignore", + message="Conversion of the second argument of" + " issubdtype from `complex` to" + " `np.complexfloating` is deprecated.*", category=FutureWarning, ) diff --git a/fury/actor.py b/fury/actor.py index c42b4c800..01beaca75 100644 --- a/fury/actor.py +++ b/fury/actor.py @@ -6,14 +6,14 @@ import numpy as np -from fury import layout +from fury import layout as lyt from fury.actors.odf_slicer import OdfSlicerActor from fury.actors.peak import PeakActor from fury.actors.tensor import ( double_cone, main_dir_uncertainty, tensor_ellipsoid, - ) +) from fury.colormap import colormap_lookup_table from fury.deprecator import deprecate_with_version, deprecated_params from fury.io import load_image @@ -94,7 +94,7 @@ def slicer( value_range=None, opacity=1.0, lookup_colormap=None, - interpolation='linear', + interpolation="linear", picking_tol=0.025, ): """Cut 3D scalar or rgb volumes into 2D images. @@ -138,19 +138,19 @@ def slicer( if data.ndim != 3: if data.ndim == 4: if data.shape[3] != 3: - raise ValueError('Only RGB 3D arrays are currently supported.') + raise ValueError("Only RGB 3D arrays are currently supported.") else: nb_components = 3 else: - raise ValueError('Only 3D arrays are currently supported.') + raise ValueError("Only 3D arrays are currently supported.") else: nb_components = 1 vol = data im = ImageData() - I, J, K = vol.shape[:3] - im.SetDimensions(I, J, K) + i, j, k = vol.shape[:3] + im.SetDimensions(i, j, k) # for now setting up for 1x1x1 but transformation comes later. voxsz = (1.0, 1.0, 1.0) # im.SetOrigin(0,0,0) @@ -225,9 +225,7 @@ def slicer( ex1, ex2, ey1, ey2, ez1, ez2 = vtk_resliced_data.GetExtent() - resliced = numpy_support.vtk_to_numpy( - vtk_resliced_data.GetPointData().GetScalars() - ) + resliced = numpy_support.vtk_to_numpy(vtk_resliced_data.GetPointData().GetScalars()) # swap axes here if data.ndim == 4: @@ -244,7 +242,6 @@ def __init__(self): self.outline_actor = None def input_connection(self, output): - # outline only outline = OutlineFilter() outline.SetInputData(vtk_resliced_data) @@ -306,7 +303,7 @@ def copy(self): im_actor.SetDisplayExtent(*self.GetDisplayExtent()) im_actor.opacity(self.GetOpacity()) im_actor.tolerance(self.picker.GetTolerance()) - if interpolation == 'nearest': + if interpolation == "nearest": im_actor.SetInterpolate(False) else: im_actor.SetInterpolate(True) @@ -338,7 +335,7 @@ def shallow_copy(self): image_actor.opacity(opacity) image_actor.tolerance(picking_tol) - if interpolation == 'nearest': + if interpolation == "nearest": image_actor.SetInterpolate(False) else: image_actor.SetInterpolate(True) @@ -390,13 +387,11 @@ def surface(vertices, faces=None, colors=None, smooth=None, subdivision=3): triangle_poly_data.SetPoints(points) if colors is not None: - triangle_poly_data.GetPointData().SetScalars( - numpy_to_vtk_colors(255 * colors) - ) + triangle_poly_data.GetPointData().SetScalars(numpy_to_vtk_colors(255 * colors)) if faces is None: tri = Delaunay(vertices[:, [0, 1]]) - faces = np.array(tri.simplices, dtype='i8') + faces = np.array(tri.simplices, dtype="i8") set_polydata_triangles(triangle_poly_data, faces) @@ -410,14 +405,14 @@ def surface(vertices, faces=None, colors=None, smooth=None, subdivision=3): mapper.SetInputData(triangle_poly_data) surface_actor.SetMapper(mapper) - elif smooth == 'loop': + elif smooth == "loop": smooth_loop = LoopSubdivisionFilter() smooth_loop.SetNumberOfSubdivisions(subdivision) smooth_loop.SetInputConnection(clean_poly_data.GetOutputPort()) mapper.SetInputConnection(smooth_loop.GetOutputPort()) surface_actor.SetMapper(mapper) - elif smooth == 'butterfly': + elif smooth == "butterfly": smooth_butterfly = ButterflySubdivisionFilter() smooth_butterfly.SetNumberOfSubdivisions(subdivision) smooth_butterfly.SetInputConnection(clean_poly_data.GetOutputPort()) @@ -427,7 +422,7 @@ def surface(vertices, faces=None, colors=None, smooth=None, subdivision=3): return surface_actor -def contour_from_roi(data, affine=None, color=np.array([1, 0, 0]), opacity=1): +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. @@ -452,13 +447,16 @@ def contour_from_roi(data, affine=None, color=np.array([1, 0, 0]), opacity=1): """ if data.ndim != 3: - raise ValueError('Only 3D arrays are currently supported.') + raise ValueError("Only 3D arrays are currently supported.") + + if color is None: + color = np.array([1, 0, 0]) nb_components = 1 data = (data > 0) * 1 vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) - vol = vol.astype('uint8') + vol = vol.astype("uint8") im = ImageData() di, dj, dk = vol.shape[:3] @@ -577,7 +575,7 @@ def contour_from_label(data, affine=None, color=None): if color is None: color = np.random.rand(nb_surfaces, 3) elif color.shape != (nb_surfaces, 3) and color.shape != (nb_surfaces, 4): - raise ValueError('Incorrect color array shape') + raise ValueError("Incorrect color array shape") if color.shape == (nb_surfaces, 4): opacity = color[:, -1] @@ -606,7 +604,7 @@ def streamtube( lod_points_size=3, spline_subdiv=None, lookup_colormap=None, - replace_strips=False + replace_strips=False, ): """Use streamtubes to visualize polylines. @@ -728,16 +726,13 @@ def streamtube( poly_mapper = set_input(PolyDataMapper(), next_input) if replace_strips: triangle_filter = set_input(TriangleFilter(), next_input) - poly_mapper = set_input( - PolyDataMapper(), - triangle_filter.GetOutputPort() - ) + poly_mapper = set_input(PolyDataMapper(), triangle_filter.GetOutputPort()) else: poly_mapper = set_input(PolyDataMapper(), next_input) poly_mapper.ScalarVisibilityOn() poly_mapper.SetScalarModeToUsePointFieldData() - poly_mapper.SelectColorArray('colors') + poly_mapper.SelectColorArray("colors") poly_mapper.Update() # Color Scale with a lookup table @@ -861,7 +856,7 @@ def line( poly_mapper = set_input(PolyDataMapper(), next_input) poly_mapper.ScalarVisibilityOn() poly_mapper.SetScalarModeToUsePointFieldData() - poly_mapper.SelectColorArray('colors') + poly_mapper.SelectColorArray("colors") poly_mapper.Update() # Color Scale with a lookup table @@ -890,13 +885,9 @@ def line( def callback(_caller, _event, calldata=None): program = calldata if program is not None: - program.SetUniformf('linewidth', linewidth) + program.SetUniformf("linewidth", linewidth) - replace_shader_in_actor( - actor, - 'geometry', - import_fury_shader('line.geom') - ) + replace_shader_in_actor(actor, "geometry", import_fury_shader("line.geom")) add_shader_callback(actor, callback) if fake_tube: @@ -905,7 +896,7 @@ def callback(_caller, _event, calldata=None): return actor -def scalar_bar(lookup_table=None, title=' '): +def scalar_bar(lookup_table=None, title=" "): """Default scalar bar actor for a given colormap (colorbar). Parameters @@ -937,11 +928,7 @@ def scalar_bar(lookup_table=None, title=' '): 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. @@ -966,11 +953,7 @@ def axes( """ centers = np.zeros((3, 3)) dirs = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) - colors = np.array( - [colorx + (opacity,), - colory + (opacity,), - colorz + (opacity,)] - ) + colors = np.array([colorx + (opacity,), colory + (opacity,), colorz + (opacity,)]) scales = np.asarray(scale) arrow_actor = arrow(centers, dirs, colors, scales, repeat_primitive=False) @@ -1036,8 +1019,8 @@ def odf_slicer( n_dims = len(odfs.shape) if n_dims != 4: raise ValueError( - 'Invalid number of dimensions for odfs. Expected 4 ' - 'dimensions, got {0} dimensions.'.format(n_dims) + "Invalid number of dimensions for odfs. Expected 4 " + "dimensions, got {0} dimensions.".format(n_dims) ) # we generate indices for all nonzero voxels @@ -1049,7 +1032,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("repulsion100") else: vertices = sphere.vertices faces = fix_winding_order(vertices, sphere.faces, clockwise=True) @@ -1057,17 +1040,16 @@ def odf_slicer( if B_matrix is None: if len(vertices) != odfs.shape[-1]: raise ValueError( - 'Invalid number of SF coefficients. ' - 'Expected {0}, got {1}.'.format(len(vertices), odfs.shape[-1]) + "Invalid number of SF coefficients. " "Expected {0}, got {1}.".format( + len(vertices), odfs.shape[-1] + ) ) else: if len(vertices) != B_matrix.shape[1]: raise ValueError( - 'Invalid number of SH coefficients. ' - 'Expected {0}, got {1}.'.format( - len(vertices), - B_matrix.shape[1] - ) + "Invalid number of SH coefficients. " "Expected {0}, got {1}.".format( + len(vertices), B_matrix.shape[1] + ) ) # create and return an instance of OdfSlicerActor @@ -1117,7 +1099,7 @@ def _roll_evals(evals, axis=-1): """ if evals.shape[-1] != 3: - msg = 'Expecting 3 eigenvalues, got {}'.format(evals.shape[-1]) + msg = "Expecting 3 eigenvalues, got {}".format(evals.shape[-1]) raise ValueError(msg) evals = np.rollaxis(evals, axis) @@ -1191,7 +1173,7 @@ def _color_fa(fa, evecs): """ if (fa.shape != evecs[..., 0, 0].shape) or ((3, 3) != evecs.shape[-2:]): - raise ValueError('Wrong number of dimensions for evecs') + raise ValueError("Wrong number of dimensions for evecs") return np.abs(evecs[..., 0]) * np.clip(fa, 0, 1)[..., None] @@ -1240,8 +1222,8 @@ def tensor_slicer( if not evals.shape == evecs.shape[:-1]: raise RuntimeError( "Eigenvalues shape {} is incompatible with eigenvectors' {}." - ' Please provide eigenvalue and' - ' eigenvector arrays that have compatible dimensions.'.format( + " Please provide eigenvalue and" + " eigenvector arrays that have compatible dimensions.".format( evals.shape, evecs.shape ) ) @@ -1259,7 +1241,7 @@ def __init__(self): def display_extent(self, x1, x2, y1, y2, z1, z2): tmp_mask = np.zeros(evals.shape[:3], dtype=bool) - tmp_mask[x1: x2 + 1, y1: y2 + 1, z1: z2 + 1] = True + tmp_mask[x1 : x2 + 1, y1 : y2 + 1, z1 : z2 + 1] = True tmp_mask = np.bitwise_and(tmp_mask, mask) self.mapper = _tensor_slicer_mapper( @@ -1357,11 +1339,11 @@ def _tensor_slicer_mapper( else: cfa = _makeNd(scalar_colors, 4) - cols = np.zeros((ijk.shape[0],) + sphere.vertices.shape, dtype='f4') + cols = np.zeros((ijk.shape[0],) + sphere.vertices.shape, dtype="f4") all_xyz = [] all_faces = [] - for (k, center) in enumerate(ijk): + for k, center in enumerate(ijk): ea = evals[tuple(center.astype(int))] if norm: ea /= ea.max() @@ -1376,7 +1358,7 @@ def _tensor_slicer_mapper( cols[k, ...] = np.interp( cfa[tuple(center.astype(int))], [0, 1], [0, 255] - ).astype('ubyte') + ).astype("ubyte") all_xyz = np.ascontiguousarray(np.concatenate(all_xyz)) all_xyz_vtk = numpy_support.numpy_to_vtk(all_xyz, deep=True) @@ -1387,17 +1369,14 @@ def _tensor_slicer_mapper( all_faces = np.concatenate(all_faces) cols = np.ascontiguousarray( - np.reshape( - cols, - (cols.shape[0] * cols.shape[1], - cols.shape[2])), dtype='f4' + np.reshape(cols, (cols.shape[0] * cols.shape[1], cols.shape[2])), dtype="f4" ) vtk_colors = numpy_support.numpy_to_vtk( cols, deep=True, array_type=VTK_UNSIGNED_CHAR ) - vtk_colors.SetName('colors') + vtk_colors.SetName("colors") polydata = PolyData() polydata.SetPoints(points) @@ -1468,7 +1447,7 @@ def peak_slicer( """ peaks_dirs = np.asarray(peaks_dirs) if peaks_dirs.ndim > 5: - raise ValueError('Wrong shape') + raise ValueError("Wrong shape") peaks_dirs = _makeNd(peaks_dirs, 5) if peaks_values is not None: @@ -1484,9 +1463,8 @@ def __init__(self): self.line = None def display_extent(self, x1, x2, y1, y2, z1, z2): - tmp_mask = np.zeros(grid_shape, dtype=bool) - tmp_mask[x1: x2 + 1, y1: y2 + 1, z1: z2 + 1] = True + tmp_mask[x1 : x2 + 1, y1 : y2 + 1, z1 : z2 + 1] = True tmp_mask = np.bitwise_and(tmp_mask, mask) ijk = np.ascontiguousarray(np.array(np.nonzero(tmp_mask)).T) @@ -1504,7 +1482,6 @@ def display_extent(self, x1, x2, y1, y2, z1, z2): xyz = ijk_trans[index][:, None] xyz = xyz.T for i in range(peaks_dirs[tuple(center)].shape[-2]): - if peaks_values is not None: pv = peaks_values[tuple(center)][i] else: @@ -1517,10 +1494,7 @@ def display_extent(self, x1, x2, y1, y2, z1, z2): ) ) else: - dirs = np.vstack(( - xyz, - peaks_dirs[tuple(center)][i] * pv + xyz) - ) + dirs = np.vstack((xyz, peaks_dirs[tuple(center)][i] * pv + xyz)) list_dirs.append(dirs) self.line = line( @@ -1617,15 +1591,15 @@ def peak( """ if peaks_dirs.ndim != 5: raise ValueError( - 'Invalid peak directions. The shape of the structure ' - 'must be (XxYxZxDx3). Your data has {} dimensions.' - ''.format(peaks_dirs.ndim) + "Invalid peak directions. The shape of the structure " + "must be (XxYxZxDx3). Your data has {} dimensions." + "".format(peaks_dirs.ndim) ) if peaks_dirs.shape[4] != 3: raise ValueError( - 'Invalid peak directions. The shape of the last ' - 'dimension must be 3. Your data has a last dimension ' - 'of {}.'.format(peaks_dirs.shape[4]) + "Invalid peak directions. The shape of the last " + "dimension must be 3. Your data has a last dimension " + "of {}.".format(peaks_dirs.shape[4]) ) dirs_shape = peaks_dirs.shape @@ -1633,32 +1607,34 @@ def peak( if peaks_values is not None: if peaks_values.ndim != 4: raise ValueError( - 'Invalid peak values. The shape of the structure ' - 'must be (XxYxZxD). Your data has {} dimensions.' - ''.format(peaks_values.ndim) + "Invalid peak values. The shape of the structure " + "must be (XxYxZxD). Your data has {} dimensions." + "".format(peaks_values.ndim) ) vals_shape = peaks_values.shape if vals_shape != dirs_shape[:4]: raise ValueError( - 'Invalid peak values. The shape of the values ' - 'must coincide with the shape of the directions.' + "Invalid peak values. The shape of the values " + "must coincide with the shape of the directions." ) valid_mask = np.abs(peaks_dirs).max(axis=(-2, -1)) > 0 if mask is not None: if mask.ndim != 3: warnings.warn( - 'Invalid mask. The mask must be a 3D array. The ' - 'passed mask has {} dimensions. Ignoring passed ' - 'mask.'.format(mask.ndim), + "Invalid mask. The mask must be a 3D array. The " + "passed mask has {} dimensions. Ignoring passed " + "mask.".format(mask.ndim), UserWarning, + stacklevel=2, ) elif mask.shape != dirs_shape[:3]: warnings.warn( - 'Invalid mask. The shape of the mask must coincide ' - 'with the shape of the directions. Ignoring passed ' - 'mask.', + "Invalid mask. The shape of the mask must coincide " + "with the shape of the directions. Ignoring passed " + "mask.", UserWarning, + stacklevel=2, ) else: valid_mask = np.logical_and(valid_mask, mask) @@ -1703,16 +1679,14 @@ def dot(points, colors=None, opacity=None, dot_size=5): """ if points.ndim != 2: raise ValueError( - 'Invalid points. The shape of the structure must be ' - '(Nx3). Your data has {} dimensions.'.format(points.ndim) + "Invalid points. The shape of the structure must be " + "(Nx3). Your data has {} dimensions.".format(points.ndim) ) if points.shape[1] != 3: raise ValueError( - 'Invalid points. The shape of the last dimension ' - 'must be 3. Your data has a last dimension of {}.'.format( - points.shape[1] - ) + "Invalid points. The shape of the last dimension " + "must be 3. Your data has a last dimension of {}.".format(points.shape[1]) ) vtk_vertices = Points() @@ -1756,7 +1730,7 @@ def dot(points, colors=None, opacity=None, dot_size=5): dots = deprecate_with_version( - message='dots function has been renamed dot', since='0.8.1', until='0.9.0' + message="dots function has been renamed dot", since="0.8.1", until="0.9.0" )(dot) @@ -1953,10 +1927,9 @@ def cylinder( """ if repeat_primitive: - if resolution < 8: # Sectors parameter should be greater than 7 in fp.prim_cylinder() - raise ValueError('resolution parameter should be greater than 7') + raise ValueError("resolution parameter should be greater than 7") verts, faces = fp.prim_cylinder( radius=radius, @@ -1984,13 +1957,7 @@ def cylinder( src.SetCapping(capped) src.SetResolution(resolution) src.SetRadius(radius) - rotate = np.array( - [[0, 1, 0, 0], - [-1, 0, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, 1] - ] - ) + rotate = np.array([[0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) else: src = None rotate = None @@ -2068,13 +2035,7 @@ def disk( src.SetRadialResolution(rresolution) src.SetInnerRadius(rinner) src.SetOuterRadius(router) - rotate = np.array( - [[0, 0, -1, 0], - [0, 1, 0, 0], - [1, 0, 0, 0], - [0, 0, 0, 1] - ] - ) + rotate = np.array([[0, 0, -1, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]]) else: src = None rotate = None @@ -2140,11 +2101,7 @@ def square(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): return sq_actor -def rectangle( - centers, - directions=(1, 0, 0), - colors=(1, 0, 0), - scales=(1, 2, 0)): +def rectangle(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 0)): """Visualize one or many rectangles with different features. Parameters @@ -2177,18 +2134,10 @@ def rectangle( >>> # window.show(scene) """ - return square( - centers=centers, - directions=directions, - colors=colors, - scales=scales) + return square(centers=centers, directions=directions, colors=colors, scales=scales) -@deprecated_params( - ['size', 'heights'], - ['scales', 'scales'], - since='0.6', - until='0.8') +@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)): """Visualize one or many boxes with different features. @@ -2236,7 +2185,7 @@ def box(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 3)): return box_actor -@deprecated_params('heights', 'scales', since='0.6', until='0.8') +@deprecated_params("heights", "scales", since="0.6", until="0.8") def cube(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): """Visualize one or many cubes with different features. @@ -2266,10 +2215,7 @@ def cube(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): >>> # window.show(scene) """ - return box(centers=centers, - directions=directions, - colors=colors, - scales=scales) + return box(centers=centers, directions=directions, colors=colors, scales=scales) def arrow( @@ -2437,12 +2383,7 @@ def cone( vertices, faces = fp.prim_cone(sectors=resolution) res = fp.repeat_primitive( - vertices, - faces, - centers, - directions=directions, - colors=colors, - scales=heights + vertices, faces, centers, directions=directions, colors=colors, scales=heights ) big_verts, big_faces, big_colors, _ = res @@ -2502,10 +2443,7 @@ def triangularprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): return tprism_actor -def rhombicuboctahedron(centers, - directions=(1, 0, 0), - colors=(1, 0, 0), - scales=1): +def rhombicuboctahedron(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): """Visualize one or many rhombicuboctahedron with different features. Parameters @@ -2739,6 +2677,7 @@ def superquadric( >>> # window.show(scene) """ + def have_2_dimensions(arr): return all(isinstance(i, (list, tuple, np.ndarray)) for i in arr) @@ -2780,7 +2719,7 @@ def billboard( gs_prog=None, fs_dec=None, fs_impl=None, - bb_type='spherical' + bb_type="spherical", ): """Create a billboard actor. - @@ -2831,116 +2770,97 @@ def billboard( ) bb_actor.GetMapper().SetVBOShiftScaleMethod(False) bb_actor.GetProperty().BackfaceCullingOff() - attribute_to_actor(bb_actor, big_centers, 'center') + attribute_to_actor(bb_actor, big_centers, "center") - bb_norm = import_fury_shader(os.path.join('utils', - 'billboard_normalization.glsl')) + bb_norm = import_fury_shader(os.path.join("utils", "billboard_normalization.glsl")) - if bb_type.lower() == 'cylindrical_x': - bb_type_sd = import_fury_shader(os.path.join('billboard', - 'cylindrical_x.glsl') - ) - v_pos_mc = \ - """ + if bb_type.lower() == "cylindrical_x": + bb_type_sd = import_fury_shader(os.path.join("billboard", "cylindrical_x.glsl")) + v_pos_mc = """ vec3 vertexPositionMC = cylindricalXVertexPos(center, MCVCMatrix, normalizedVertexMCVSOutput, shape); """ - elif bb_type.lower() == 'cylindrical_y': - bb_type_sd = import_fury_shader(os.path.join('billboard', - 'cylindrical_y.glsl') - ) - v_pos_mc = \ - """ + elif bb_type.lower() == "cylindrical_y": + bb_type_sd = import_fury_shader(os.path.join("billboard", "cylindrical_y.glsl")) + v_pos_mc = """ vec3 vertexPositionMC = cylindricalYVertexPos(center,MCVCMatrix, normalizedVertexMCVSOutput, shape); """ - elif bb_type.lower() == 'spherical': - bb_type_sd = import_fury_shader(os.path.join('billboard', - 'spherical.glsl')) - v_pos_mc = \ - """ + elif bb_type.lower() == "spherical": + bb_type_sd = import_fury_shader(os.path.join("billboard", "spherical.glsl")) + v_pos_mc = """ vec3 vertexPositionMC = sphericalVertexPos(center, MCVCMatrix, normalizedVertexMCVSOutput, shape); """ else: - bb_type_sd = import_fury_shader(os.path.join('billboard', - 'spherical.glsl')) - v_pos_mc = \ - """ + bb_type_sd = import_fury_shader(os.path.join("billboard", "spherical.glsl")) + v_pos_mc = """ vec3 vertexPositionMC = sphericalVertexPos(center, MCVCMatrix, normalizedVertexMCVSOutput, shape); """ - warnings.warn('Invalid option. The billboard will be generated ' - 'with the default spherical option. ', UserWarning) + warnings.warn( + "Invalid option. The billboard will be generated " + "with the default spherical option. ", + UserWarning, + stacklevel=2, + ) - gl_position = \ - ''' + gl_position = """ gl_Position = MCDCMatrix * vec4(vertexPositionMC, 1.); - ''' + """ - billboard_dec_vert = \ - ''' + billboard_dec_vert = """ /* Billboard vertex shader declaration */ in vec3 center; out vec3 centerVertexMCVSOutput; out vec3 normalizedVertexMCVSOutput; - ''' + """ - billboard_impl_vert = \ - ''' + billboard_impl_vert = """ /* Billboard vertex shader implementation */ centerVertexMCVSOutput = center; normalizedVertexMCVSOutput = bbNorm(vertexMC.xyz, center); float scalingFactor = 1. / abs(normalizedVertexMCVSOutput.x); float size = abs((vertexMC.xyz - center).x) * 2; vec2 shape = vec2(size, size); // Fixes the scaling issue - ''' + """ - billboard_dec_frag = \ - ''' + billboard_dec_frag = """ /* Billboard fragment shader declaration */ in vec3 centerVertexMCVSOutput; in vec3 normalizedVertexMCVSOutput; - ''' + """ - billboard_impl_frag = \ - ''' + billboard_impl_frag = """ /* Billboard Fragment shader implementation */ // Renaming variables passed from the Vertex Shader vec3 color = vertexColorVSOutput.rgb; vec3 point = normalizedVertexMCVSOutput; fragOutput0 = vec4(color, 1.); - ''' + """ - billboard_vert_impl = compose_shader( - [billboard_impl_vert, v_pos_mc, gl_position]) + billboard_vert_impl = compose_shader([billboard_impl_vert, v_pos_mc, gl_position]) vs_dec_code = compose_shader( - [billboard_dec_vert, compose_shader(vs_dec), bb_norm, bb_type_sd]) - vs_impl_code = compose_shader( - [compose_shader(vs_impl), billboard_vert_impl]) + [billboard_dec_vert, compose_shader(vs_dec), bb_norm, bb_type_sd] + ) + vs_impl_code = compose_shader([compose_shader(vs_impl), billboard_vert_impl]) gs_code = compose_shader(gs_prog) - fs_dec_code = compose_shader( - [billboard_dec_frag, compose_shader(fs_dec)] - ) - fs_impl_code = compose_shader( - [billboard_impl_frag, compose_shader(fs_impl)] - ) + fs_dec_code = compose_shader([billboard_dec_frag, compose_shader(fs_dec)]) + fs_impl_code = compose_shader([billboard_impl_frag, compose_shader(fs_impl)]) - shader_to_actor(bb_actor, 'vertex', impl_code=vs_impl_code, - decl_code=vs_dec_code) - replace_shader_in_actor(bb_actor, 'geometry', gs_code) - shader_to_actor(bb_actor, 'fragment', decl_code=fs_dec_code) - shader_to_actor(bb_actor, 'fragment', impl_code=fs_impl_code, - block='light') + shader_to_actor(bb_actor, "vertex", impl_code=vs_impl_code, decl_code=vs_dec_code) + replace_shader_in_actor(bb_actor, "geometry", gs_code) + shader_to_actor(bb_actor, "fragment", decl_code=fs_dec_code) + shader_to_actor(bb_actor, "fragment", impl_code=fs_impl_code, block="light") return bb_actor def vector_text( - text='Origin', + text="Origin", pos=(0, 0, 0), scale=(0.2, 0.2, 0.2), color=(1, 1, 1), @@ -3039,9 +2959,9 @@ def add_to_scene(scene): label = deprecate_with_version( - message='Label function has been renamed' ' vector_text', - since='0.7.1', - until='0.9.0', + message="Label function has been renamed" " vector_text", + since="0.7.1", + until="0.9.0", )(vector_text) @@ -3050,9 +2970,9 @@ def text_3d( position=(0, 0, 0), color=(1, 1, 1), font_size=12, - font_family='Arial', - justification='left', - vertical_justification='bottom', + font_family="Arial", + justification="left", + vertical_justification="bottom", bold=False, italic=False, shadow=False, @@ -3079,6 +2999,7 @@ def text_3d( Text3D """ + class Text3D(TextActor3D): def message(self, text): self.set_message(text) @@ -3093,35 +3014,31 @@ def font_size(self, size): self.GetTextProperty().SetFontSize(24) text_actor.SetScale((1.0 / 24.0 * size,) * 3) - def font_family(self, _family='Arial'): + def font_family(self, _family="Arial"): self.GetTextProperty().SetFontFamilyToArial() def justification(self, justification): tprop = self.GetTextProperty() - if justification == 'left': + if justification == "left": tprop.SetJustificationToLeft() - elif justification == 'center': + elif justification == "center": tprop.SetJustificationToCentered() - elif justification == 'right': + elif justification == "right": tprop.SetJustificationToRight() else: - raise ValueError( - "Unknown justification: '{}'".format(justification) - ) + raise ValueError("Unknown justification: '{}'".format(justification)) def vertical_justification(self, justification): tprop = self.GetTextProperty() - if justification == 'top': + if justification == "top": tprop.SetVerticalJustificationToTop() - elif justification == 'middle': + elif justification == "middle": tprop.SetVerticalJustificationToCentered() - elif justification == 'bottom': + elif justification == "bottom": tprop.SetVerticalJustificationToBottom() else: raise ValueError( - "Unknown vertical justification: '{}'".format( - justification - ) + "Unknown vertical justification: '{}'".format(justification) ) def font_style(self, bold=False, italic=False, shadow=False): @@ -3179,13 +3096,16 @@ class Container: """ - def __init__(self, layout=layout.Layout()): + def __init__(self, layout=None): """Parameters ---------- layout : ``fury.layout.Layout`` object Items of this container will be arranged according to `layout`. """ + if layout is None: + layout = lyt.Layout() + self.layout = layout self._items = [] self._need_update = True @@ -3217,7 +3137,7 @@ def add(self, *items, **kwargs): self._need_update = True for item in items: - if not kwargs.get('borrow', True): + if not kwargs.get("borrow", True): item = shallow_copy(item) self._items.append(item) @@ -3250,8 +3170,8 @@ def remove_from_scene(self, scene): def GetBounds(self): """Get the bounds of the container.""" - bounds = np.zeros(6) # x1, x2, y1, y2, z1, z2 - bounds[::2] = np.inf # x1, y1, z1 + bounds = np.zeros(6) # x1, x2, y1, y2, z1, z2 + bounds[::2] = np.inf # x1, y1, z1 bounds[1::2] = -np.inf # x2, y2, z2 for item in self.items: @@ -3314,7 +3234,7 @@ def grid( captions=None, caption_offset=(0, -100, 0), cell_padding=0, - cell_shape='rect', + cell_shape="rect", aspect_ratio=16 / 9.0, dim=None, ): @@ -3355,7 +3275,7 @@ def grid( captions, if any. """ - grid_layout = layout.GridLayout( + grid_layout = lyt.GridLayout( cell_padding=cell_padding, cell_shape=cell_shape, aspect_ratio=aspect_ratio, @@ -3365,14 +3285,13 @@ def grid( if captions is not None: actors_with_caption = [] - for actor, caption in zip(actors, captions): - + for actor, caption in zip(actors, captions, strict=False): actor_center = np.array(actor.GetCenter()) # Offset accordingly the caption w.r.t. # the center of the associated actor. if isinstance(caption, str): - caption = text_3d(caption, justification='center') + caption = text_3d(caption, justification="center") else: caption = shallow_copy(caption) caption.SetPosition(actor_center + caption_offset) @@ -3383,9 +3302,7 @@ def grid( # We change the anchor of the container so # the actor will be centered in the # grid cell. - actor_with_caption.anchor = ( - actor_center - actor_with_caption.GetCenter() - ) + actor_with_caption.anchor = actor_center - actor_with_caption.GetCenter() actors_with_caption.append(actor_with_caption) actors = actors_with_caption @@ -3394,7 +3311,7 @@ def grid( return grid -def figure(pic, interpolation='nearest'): +def figure(pic, interpolation="nearest"): """Return a figure as an image actor. Parameters @@ -3411,20 +3328,13 @@ def figure(pic, interpolation='nearest'): if isinstance(pic, str): vtk_image_data = load_image(pic, True) else: - if pic.ndim == 3 and pic.shape[2] == 4: - vtk_image_data = ImageData() vtk_image_data.AllocateScalars(VTK_UNSIGNED_CHAR, 4) # width, height vtk_image_data.SetDimensions(pic.shape[1], pic.shape[0], 1) - vtk_image_data.SetExtent(0, - pic.shape[1] - 1, - 0, - pic.shape[0] - 1, - 0, - 0) + vtk_image_data.SetExtent(0, pic.shape[1] - 1, 0, pic.shape[0] - 1, 0, 0) pic_tmp = np.swapaxes(pic, 0, 1) pic_tmp = pic.reshape(pic.shape[1] * pic.shape[0], 4) pic_tmp = np.ascontiguousarray(pic_tmp) @@ -3434,13 +3344,13 @@ def figure(pic, interpolation='nearest'): image_actor = ImageActor() image_actor.SetInputData(vtk_image_data) - if interpolation == 'nearest': + if interpolation == "nearest": image_actor.GetProperty().SetInterpolationTypeToNearest() - if interpolation == 'linear': + if interpolation == "linear": image_actor.GetProperty().SetInterpolationTypeToLinear() - if interpolation == 'cubic': + if interpolation == "cubic": image_actor.GetProperty().SetInterpolationTypeToCubic() image_actor.Update() @@ -3521,8 +3431,7 @@ def texture_update(texture_actor, arr): """ grid = texture_actor.GetTexture().GetInput() dim = arr.shape[-1] - img_data = np.flip(arr.swapaxes(0, 1), - axis=1).reshape((-1, dim), order='F') + img_data = np.flip(arr.swapaxes(0, 1), axis=1).reshape((-1, dim), order="F") vtkarr = numpy_support.numpy_to_vtk(img_data, deep=False) grid.GetPointData().SetScalars(vtkarr) @@ -3651,11 +3560,7 @@ def texture_2d(rgb, interp=False): return act -def sdf(centers, - directions=(1, 0, 0), - colors=(1, 0, 0), - primitives='torus', - scales=1): +def sdf(centers, directions=(1, 0, 0), colors=(1, 0, 0), primitives="torus", scales=1): """Create a SDF primitive based actor. Parameters @@ -3677,7 +3582,7 @@ def sdf(centers, box_actor: Actor """ - prims = {'sphere': 1, 'torus': 2, 'ellipsoid': 3, 'capsule': 4} + prims = {"sphere": 1, "torus": 2, "ellipsoid": 3, "capsule": 4} verts, faces = fp.prim_box() repeated = fp.repeat_primitive( @@ -3701,9 +3606,10 @@ def sdf(centers, if len(primitives) < len(centers): primlist = primlist + [2] * (len(centers) - len(primitives)) warnings.warn( - 'Not enough primitives provided,\ - defaulting to torus', + "Not enough primitives provided,\ + defaulting to torus", category=UserWarning, + stacklevel=2, ) rep_prims = np.repeat(primlist, verts.shape[0]) else: @@ -3714,31 +3620,24 @@ def sdf(centers, else: rep_scales = np.repeat(scales, rep_centers.shape[0], axis=0) - if isinstance(directions, - (list, tuple, np.ndarray)) and len(directions) == 3: + if isinstance(directions, (list, tuple, np.ndarray)) and len(directions) == 3: rep_directions = np.repeat(directions, rep_centers.shape[0], axis=0) else: rep_directions = np.repeat(directions, verts.shape[0], axis=0) - attribute_to_actor(box_actor, rep_centers, 'center') - attribute_to_actor(box_actor, rep_prims, 'primitive') - attribute_to_actor(box_actor, rep_scales, 'scale') - attribute_to_actor(box_actor, rep_directions, 'direction') - - vs_dec_code = import_fury_shader('sdf_dec.vert') - vs_impl_code = import_fury_shader('sdf_impl.vert') - fs_dec_code = import_fury_shader('sdf_dec.frag') - fs_impl_code = import_fury_shader('sdf_impl.frag') - - shader_to_actor(box_actor, - 'vertex', - impl_code=vs_impl_code, - decl_code=vs_dec_code) - shader_to_actor(box_actor, 'fragment', decl_code=fs_dec_code) - shader_to_actor(box_actor, - 'fragment', - impl_code=fs_impl_code, - block='light') + attribute_to_actor(box_actor, rep_centers, "center") + attribute_to_actor(box_actor, rep_prims, "primitive") + attribute_to_actor(box_actor, rep_scales, "scale") + attribute_to_actor(box_actor, rep_directions, "direction") + + vs_dec_code = import_fury_shader("sdf_dec.vert") + vs_impl_code = import_fury_shader("sdf_impl.vert") + fs_dec_code = import_fury_shader("sdf_dec.frag") + fs_impl_code = import_fury_shader("sdf_impl.frag") + + shader_to_actor(box_actor, "vertex", impl_code=vs_impl_code, decl_code=vs_dec_code) + shader_to_actor(box_actor, "fragment", decl_code=fs_dec_code) + shader_to_actor(box_actor, "fragment", impl_code=fs_impl_code, block="light") return box_actor @@ -3746,7 +3645,7 @@ def markers( centers, colors=(0, 1, 0), scales=1, - marker='3d', + marker="3d", marker_opacity=0.8, edge_width=0.0, edge_color=(255, 255, 255), @@ -3813,68 +3712,62 @@ def markers( sq_actor.GetMapper().SetVBOShiftScaleMethod(False) sq_actor.GetProperty().BackfaceCullingOff() - attribute_to_actor(sq_actor, big_centers, 'center') + attribute_to_actor(sq_actor, big_centers, "center") marker2id = { - 'o': 0, - 's': 1, - 'd': 2, - '^': 3, - 'p': 4, - 'h': 5, - 's6': 6, - 'x': 7, - '+': 8, - '3d': 0, + "o": 0, + "s": 1, + "d": 2, + "^": 3, + "p": 4, + "h": 5, + "s6": 6, + "x": 7, + "+": 8, + "3d": 0, } - bb_impl = \ - """ + bb_impl = """ vec3 vertexPositionMC = sphericalVertexPos(center, MCVCMatrix, normalizedVertexMCVSOutput, shape); gl_Position = MCDCMatrix * vec4(vertexPositionMC, 1.); """ - vs_dec_code = \ - ''' + vs_dec_code = """ /* Billboard vertex shader declaration */ in vec3 center; out vec3 centerVertexMCVSOutput; out vec3 normalizedVertexMCVSOutput; - ''' - vs_dec_code += \ - f'\n{import_fury_shader("utils/billboard_normalization.glsl")}' + """ + vs_dec_code += f'\n{import_fury_shader("utils/billboard_normalization.glsl")}' vs_dec_code += f'\n{import_fury_shader("billboard/spherical.glsl")}' vs_dec_code += f'\n{import_fury_shader("marker_billboard_dec.vert")}' - vs_impl_code = \ - ''' + vs_impl_code = """ /* Billboard vertex shader implementation */ centerVertexMCVSOutput = center; normalizedVertexMCVSOutput = bbNorm(vertexMC.xyz, center); float scalingFactor = 1. / abs(normalizedVertexMCVSOutput.x); float size = abs((vertexMC.xyz - center).x) * 2; vec2 shape = vec2(size, size); // Fixes the scaling issue - ''' - vs_impl_code += f'\n{compose_shader(bb_impl)}' + """ + vs_impl_code += f"\n{compose_shader(bb_impl)}" vs_impl_code += f'\n{import_fury_shader("marker_billboard_impl.vert")}' - fs_dec_code = \ - ''' + fs_dec_code = """ /* Billboard fragment shader declaration */ in vec3 centerVertexMCVSOutput; in vec3 normalizedVertexMCVSOutput; - ''' + """ fs_dec_code += f'\n{import_fury_shader("marker_billboard_dec.frag")}' - fs_impl_code = \ - ''' + fs_impl_code = """ /* Billboard Fragment shader implementation */ // Renaming variables passed from the Vertex Shader vec3 color = vertexColorVSOutput.rgb; vec3 point = normalizedVertexMCVSOutput; fragOutput0 = vec4(color, 1.); - ''' + """ - if marker == '3d': + if marker == "3d": fs_impl_code += f'{import_fury_shader("billboard_spheres_impl.frag")}' else: fs_impl_code += f'{import_fury_shader("marker_billboard_impl.frag")}' @@ -3883,79 +3776,50 @@ def markers( else: list_of_markers = [marker2id[i] for i in marker] - list_of_markers = np.repeat(list_of_markers, 4).astype('float') - attribute_to_actor(sq_actor, list_of_markers, 'marker') + list_of_markers = np.repeat(list_of_markers, 4).astype("float") + 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: - program.__getattribute__( - f'SetUniform{uniform_type}' - )(uniform_name, value) + program.__getattribute__(f"SetUniform{uniform_type}")(uniform_name, value) add_shader_callback( sq_actor, - partial(callback, - uniform_type='f', - uniform_name='edgeWidth', - value=edge_width), + partial(callback, uniform_type="f", uniform_name="edgeWidth", value=edge_width), ) add_shader_callback( sq_actor, partial( callback, - uniform_type='f', - uniform_name='markerOpacity', + uniform_type="f", + uniform_name="markerOpacity", value=marker_opacity, ), ) add_shader_callback( sq_actor, partial( - callback, - uniform_type='f', - uniform_name='edgeOpacity', - value=edge_opacity + callback, uniform_type="f", uniform_name="edgeOpacity", value=edge_opacity ), ) add_shader_callback( sq_actor, partial( - callback, - uniform_type='3f', - uniform_name='edgeColor', - value=edge_color + callback, uniform_type="3f", uniform_name="edgeColor", value=edge_color ), ) - shader_to_actor(sq_actor, - 'vertex', - impl_code=vs_impl_code, - decl_code=vs_dec_code) - shader_to_actor(sq_actor, 'fragment', decl_code=fs_dec_code) - shader_to_actor(sq_actor, - 'fragment', - impl_code=fs_impl_code, - block='light') + shader_to_actor(sq_actor, "vertex", impl_code=vs_impl_code, decl_code=vs_dec_code) + shader_to_actor(sq_actor, "fragment", decl_code=fs_dec_code) + shader_to_actor(sq_actor, "fragment", impl_code=fs_impl_code, block="light") return sq_actor -def ellipsoid( - centers, - axes, - lengths, - colors=(1, 0, 0), - scales=1.0, - opacity=1.0 -): +def ellipsoid(centers, axes, lengths, colors=(1, 0, 0), scales=1.0, opacity=1.0): """VTK actor for visualizing ellipsoids. Parameters @@ -3988,16 +3852,18 @@ def ellipsoid( if axes.ndim == 2: axes = np.array([axes]) if axes.shape[0] != centers.shape[0]: - raise ValueError('number of axes defined does not match with number of' - 'centers') + raise ValueError( + "number of axes defined does not match with number of" "centers" + ) if not isinstance(lengths, np.ndarray): lengths = np.array(lengths) if lengths.ndim == 1: lengths = np.array([lengths]) if lengths.shape[0] != centers.shape[0]: - raise ValueError('number of lengths defined does not match with number' - 'of centers') + raise ValueError( + "number of lengths defined does not match with number" "of centers" + ) if not isinstance(scales, np.ndarray): scales = np.array(scales) @@ -4005,7 +3871,8 @@ def ellipsoid( 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) + (scales, np.ones(centers.shape[0] - scales.shape[0])), axis=None + ) if isinstance(colors, tuple): colors = np.array([colors]) @@ -4017,15 +3884,7 @@ def ellipsoid( return tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity) -def uncertainty_cone( - evals, - evecs, - signal, - sigma, - b_matrix, - scales=.6, - opacity=1.0 -): +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. diff --git a/fury/actors/odf_slicer.py b/fury/actors/odf_slicer.py index f4e570ec4..8b75d200a 100644 --- a/fury/actors/odf_slicer.py +++ b/fury/actors/odf_slicer.py @@ -108,8 +108,7 @@ def __init__( self.set_opacity(opacity) def set_opacity(self, opacity): - """Set opacity value of ODFs to display. - """ + """Set opacity value of ODFs to display.""" self.GetProperty().SetOpacity(opacity) def display_extent(self, x1, x2, y1, y2, z1, z2): @@ -118,16 +117,16 @@ def display_extent(self, x1, x2, y1, y2, z1, z2): (inclusive). """ mask = np.zeros(self.grid_shape, dtype=bool) - mask[x1: x2 + 1, y1: y2 + 1, z1: z2 + 1] = True + mask[x1 : x2 + 1, y1 : y2 + 1, z1 : z2 + 1] = True self.mask = mask self._update_mapper() - def slice_along_axis(self, slice_index, axis='zaxis'): + def slice_along_axis(self, slice_index, axis="zaxis"): """Slice ODF field at given `slice_index` along axis in ['xaxis', 'yaxis', zaxis']. """ - if axis == 'xaxis': + if axis == "xaxis": self.display_extent( slice_index, slice_index, @@ -136,7 +135,7 @@ def slice_along_axis(self, slice_index, axis='zaxis'): 0, self.grid_shape[2] - 1, ) - elif axis == 'yaxis': + elif axis == "yaxis": self.display_extent( 0, self.grid_shape[0] - 1, @@ -145,7 +144,7 @@ def slice_along_axis(self, slice_index, axis='zaxis'): 0, self.grid_shape[2] - 1, ) - elif axis == 'zaxis': + elif axis == "zaxis": self.display_extent( 0, self.grid_shape[0] - 1, @@ -155,28 +154,23 @@ def slice_along_axis(self, slice_index, axis='zaxis'): slice_index, ) else: - raise ValueError('Invalid axis name {0}.'.format(axis)) + raise ValueError("Invalid axis name {0}.".format(axis)) def display(self, x=None, y=None, z=None): - """Display a slice along x, y, or z axis. - """ + """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, "xaxis") elif y is not None: - self.slice_along_axis(y, 'yaxis') + self.slice_along_axis(y, "yaxis") elif z is not None: - self.slice_along_axis(z, 'zaxis') + self.slice_along_axis(z, "zaxis") def update_sphere(self, vertices, faces, B): - """Dynamically change the sphere used for SH to SF projection. - """ + """Dynamically change the sphere used for SH to SF projection.""" if self.B is None: - raise ValueError( - "Can't update sphere when using " - 'SF coefficients.' - ) + raise ValueError("Can't update sphere when using " "SF coefficients.") self.vertices = vertices if self.affine is not None: self.w_verts = self.vertices.dot(self.affine[:3, :3]) @@ -187,8 +181,7 @@ def update_sphere(self, vertices, faces, B): self._update_mapper() def _update_mapper(self): - """Map vtkPolyData to the actor. - """ + """Map vtkPolyData to the actor.""" polydata = PolyData() offsets = self._get_odf_offsets(self.mask) @@ -212,22 +205,19 @@ def _update_mapper(self): self.mapper.SetInputData(polydata) def _get_odf_offsets(self, mask): - """Get the position of non-zero voxels inside `mask`. - """ + """Get the position of non-zero voxels inside `mask`.""" if self.affine is not None: return self.w_pos[mask[self.indices]] return np.asarray(self.indices).T[mask[self.indices]] def _get_sphere_directions(self): - """Get the sphere directions onto which is projected the signal. - """ + """Get the sphere directions onto which is projected the signal.""" if self.affine is not None: return self.w_verts return self.vertices def _get_sf(self, mask): - """Get SF coefficients inside `mask`. - """ + """Get SF coefficients inside `mask`.""" # when odfs are expressed in SH coefficients if self.B is not None: sf = self.odfs[mask[self.indices]].dot(self.B) @@ -240,14 +230,12 @@ def _get_sf(self, mask): return self.odfs[mask[self.indices]] def _get_all_vertices(self, offsets, sph_dirs, sf): - """Get array of all the vertices of the ODFs to display. - """ + """Get array of all the vertices of the ODFs to display.""" if self.radial_scale: # apply SF amplitudes to all sphere # directions and offset each voxel - return ( - np.tile(sph_dirs, (len(offsets), 1)) * sf.reshape(-1, 1) - + np.repeat(offsets, len(sph_dirs), axis=0) + return np.tile(sph_dirs, (len(offsets), 1)) * sf.reshape(-1, 1) + np.repeat( + offsets, len(sph_dirs), axis=0 ) # return scaled spheres offsetted by `offsets` return np.tile(sph_dirs, (len(offsets), 1)) * self.scale + np.repeat( @@ -255,18 +243,16 @@ def _get_all_vertices(self, offsets, sph_dirs, sf): ) def _get_all_faces(self, nb_odfs, nb_dirs): - """Get array of all the faces of the ODFs to display. - """ + """Get array of all the faces of the ODFs to display.""" return np.tile(self.faces, (nb_odfs, 1)) + np.repeat( np.arange(nb_odfs) * nb_dirs, len(self.faces) ).reshape(-1, 1) def _generate_color_for_vertices(self, sf): - """Get array of all vertices colors. - """ + """Get array of all vertices colors.""" if self.global_cm: if self.colormap is None: - raise IOError('if global_cm=True, colormap must be defined.') + raise IOError("if global_cm=True, colormap must be defined.") else: all_colors = create_colormap(sf.ravel(), self.colormap) * 255 elif self.colormap is not None: @@ -275,8 +261,7 @@ def _generate_color_for_vertices(self, sf): 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(), 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 0e6d6070a..571cd3fc0 100644 --- a/fury/actors/peak.py +++ b/fury/actors/peak.py @@ -86,14 +86,16 @@ def __init__( centers_array = np.empty_like(points_array, dtype=int) diffs_array = np.empty_like(points_array) line_count = 0 - for idx, center in enumerate(zip(indices[0], indices[1], indices[2])): + for idx, center in enumerate( + zip(indices[0], indices[1], indices[2], strict=False) + ): if affine is None: xyz = np.asarray(center) else: xyz = w_pos[idx, :] - valid_peaks = np.nonzero( - np.abs(valid_dirs[idx, :, :]).max(axis=-1) > 0.0 - )[0] + valid_peaks = np.nonzero(np.abs(valid_dirs[idx, :, :]).max(axis=-1) > 0.0)[ + 0 + ] for direction in valid_peaks: if values is not None: pv = values[center][direction] @@ -132,13 +134,13 @@ def __init__( self.__mapper.SetInputData(poly_data) self.__mapper.ScalarVisibilityOn() self.__mapper.SetScalarModeToUsePointFieldData() - self.__mapper.SelectColorArray('colors') + self.__mapper.SelectColorArray("colors") self.__mapper.Update() self.SetMapper(self.__mapper) - attribute_to_actor(self, centers_array, 'center') - attribute_to_actor(self, diffs_array, 'diff') + attribute_to_actor(self, centers_array, "center") + attribute_to_actor(self, diffs_array, "diff") vs_var_dec = """ in vec3 center; @@ -152,20 +154,14 @@ def __init__( uniform vec3 lowRanges; uniform vec3 highRanges; """ - orient_to_rgb = import_fury_shader( - pjoin('utils', 'orient_to_rgb.glsl') - ) + orient_to_rgb = import_fury_shader(pjoin("utils", "orient_to_rgb.glsl")) visible_cross_section = import_fury_shader( - pjoin('interaction', 'visible_cross_section.glsl') + pjoin("interaction", "visible_cross_section.glsl") ) - visible_range = import_fury_shader( - pjoin('interaction', 'visible_range.glsl') - ) + visible_range = import_fury_shader(pjoin("interaction", "visible_range.glsl")) vs_dec = compose_shader([vs_var_dec, orient_to_rgb]) - fs_dec = compose_shader( - [fs_var_dec, visible_cross_section, visible_range] - ) + fs_dec = compose_shader([fs_var_dec, visible_cross_section, visible_range]) vs_impl = """ centerVertexMCVSOutput = center; @@ -188,9 +184,9 @@ def __init__( } """ - shader_to_actor(self, 'vertex', decl_code=vs_dec, impl_code=vs_impl) - shader_to_actor(self, 'fragment', decl_code=fs_dec) - shader_to_actor(self, 'fragment', impl_code=fs_impl, block='light') + shader_to_actor(self, "vertex", decl_code=vs_dec, impl_code=vs_impl) + shader_to_actor(self, "fragment", decl_code=fs_dec) + shader_to_actor(self, "fragment", impl_code=fs_impl, block="light") # Color scale with a lookup table if colors_are_scalars: @@ -222,10 +218,10 @@ def __init__( @calldata_type(VTK_OBJECT) 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) - calldata.SetUniform3f('lowRanges', self.__low_ranges) - calldata.SetUniform3f('crossSection', self.__cross_section) + calldata.SetUniformi("isRange", self.__is_range) + calldata.SetUniform3f("highRanges", self.__high_ranges) + calldata.SetUniform3f("lowRanges", self.__low_ranges) + calldata.SetUniform3f("crossSection", self.__cross_section) def display_cross_section(self, x, y, z): if self.__is_range: @@ -281,7 +277,7 @@ def min_centers(self): return self.__min_centers -def _orientation_colors(points, cmap='rgb_standard'): +def _orientation_colors(points, cmap="rgb_standard"): """ Parameters ---------- @@ -296,19 +292,17 @@ def _orientation_colors(points, cmap='rgb_standard'): list of Kx3 colors. Where K is the number of lines. """ - if cmap.lower() == 'rgb_standard': + if cmap.lower() == "rgb_standard": col_list = [ - orient2rgb(points[i + 1] - points[i]) - for i in range(0, len(points), 2) + orient2rgb(points[i + 1] - points[i]) for i in range(0, len(points), 2) ] - elif cmap.lower() == 'boys_standard': + elif cmap.lower() == "boys_standard": col_list = [ - boys2rgb(points[i + 1] - points[i]) - for i in range(0, len(points), 2) + boys2rgb(points[i + 1] - points[i]) for i in range(0, len(points), 2) ] else: raise ValueError( - 'Invalid colormap. The only available options are ' + "Invalid colormap. The only available options are " "'rgb_standard' and 'boys_standard'." ) return np.asarray(col_list) @@ -354,7 +348,7 @@ def _peaks_colors_from_points(points, colors=None, points_per_line=2): num_lines = num_pnts // points_per_line colors_are_scalars = False global_opacity = 1 - if colors is None or colors == 'rgb_standard': + if colors is None or colors == "rgb_standard": # Automatic RGB colors colors = np.asarray((0, 0, 0)) color_array = numpy_to_vtk_colors(np.tile(255 * colors, (num_pnts, 1))) @@ -367,8 +361,7 @@ def _peaks_colors_from_points(points, colors=None, points_per_line=2): if len(colors) == num_lines: pnts_colors = np.repeat(colors, points_per_line, axis=0) if colors.ndim == 1: # Scalar per line - color_array = \ - numpy_support.numpy_to_vtk(pnts_colors, deep=True) + color_array = numpy_support.numpy_to_vtk(pnts_colors, deep=True) colors_are_scalars = True elif colors.ndim == 2: # RGB(A) color per line global_opacity = 1 if colors.shape[1] == 3 else -1 @@ -381,7 +374,7 @@ def _peaks_colors_from_points(points, colors=None, points_per_line=2): global_opacity = 1 if colors.shape[1] == 3 else -1 color_array = numpy_to_vtk_colors(255 * colors) - color_array.SetName('colors') + color_array.SetName("colors") return color_array, colors_are_scalars, global_opacity @@ -418,18 +411,12 @@ def _points_to_vtk_cells(points, points_per_line=2): this actor the creation of this array requires a 2 points padding between indices. """ - offset = np.asarray( - list(range(0, num_pnts + 1, points_per_line)), dtype=int - ) + offset = np.asarray(list(range(0, num_pnts + 1, points_per_line)), dtype=int) vtk_array_type = numpy_support.get_vtk_array_type(connectivity.dtype) cell_array.SetData( - numpy_support.numpy_to_vtk( - offset, deep=True, array_type=vtk_array_type - ), - numpy_support.numpy_to_vtk( - connectivity, deep=True, array_type=vtk_array_type - ), + numpy_support.numpy_to_vtk(offset, deep=True, array_type=vtk_array_type), + numpy_support.numpy_to_vtk(connectivity, deep=True, array_type=vtk_array_type), ) cell_array.SetNumberOfCells(num_cells) diff --git a/fury/actors/tensor.py b/fury/actors/tensor.py index 1270c23a0..5bb701b9e 100644 --- a/fury/actors/tensor.py +++ b/fury/actors/tensor.py @@ -42,29 +42,28 @@ def tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity): n_verts = 8 big_centers = np.repeat(centers, n_verts, axis=0) - attribute_to_actor(box_actor, big_centers, 'center') + attribute_to_actor(box_actor, big_centers, "center") big_scales = np.repeat(scales, n_verts, axis=0) - attribute_to_actor(box_actor, big_scales, 'scale') + attribute_to_actor(box_actor, big_scales, "scale") big_values = np.repeat(np.array(lengths, dtype=float), n_verts, axis=0) - attribute_to_actor(box_actor, big_values, 'evals') + attribute_to_actor(box_actor, big_values, "evals") evec1 = np.array([item[0] for item in axes]) evec2 = np.array([item[1] for item in axes]) evec3 = np.array([item[2] for item in axes]) big_vectors_1 = np.repeat(evec1, n_verts, axis=0) - attribute_to_actor(box_actor, big_vectors_1, 'evec1') + attribute_to_actor(box_actor, big_vectors_1, "evec1") big_vectors_2 = np.repeat(evec2, n_verts, axis=0) - attribute_to_actor(box_actor, big_vectors_2, 'evec2') + attribute_to_actor(box_actor, big_vectors_2, "evec2") big_vectors_3 = np.repeat(evec3, n_verts, axis=0) - attribute_to_actor(box_actor, big_vectors_3, 'evec3') + attribute_to_actor(box_actor, big_vectors_3, "evec3") # Start of shader implementation - vs_dec = \ - """ + vs_dec = """ in vec3 center; in float scale; in vec3 evals; @@ -80,8 +79,7 @@ def tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity): """ # Variables assignment - v_assign = \ - """ + v_assign = """ vertexMCVSOutput = vertexMC; centerMCVSOutput = center; scaleVSOutput = scale; @@ -94,8 +92,7 @@ def tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity): evals = "evalsVSOutput = clamp(evalsVSOutput,0.05,1);" # Scaling matrix - sc_matrix = \ - """ + sc_matrix = """ mat3 S = mat3(1/evalsVSOutput.x, 0.0, 0.0, 0.0, 1/evalsVSOutput.y, 0.0, 0.0, 0.0, 1/evalsVSOutput.z); @@ -107,14 +104,14 @@ def tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity): # Tensor matrix t_matrix = "tensorMatrix = inverse(R) * S * R;" - vs_impl = compose_shader([v_assign, n_evals, evals, sc_matrix, rot_matrix, - t_matrix]) + vs_impl = compose_shader( + [v_assign, n_evals, evals, sc_matrix, rot_matrix, t_matrix] + ) # Adding shader implementation to actor - shader_to_actor(box_actor, 'vertex', decl_code=vs_dec, impl_code=vs_impl) + shader_to_actor(box_actor, "vertex", decl_code=vs_dec, impl_code=vs_impl) - fs_vars_dec = \ - """ + fs_vars_dec = """ in vec4 vertexMCVSOutput; in vec3 centerMCVSOutput; in float scaleVSOutput; @@ -125,11 +122,10 @@ def tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity): """ # Importing the sphere SDF - sd_sphere = import_fury_shader(os.path.join('sdf', 'sd_sphere.frag')) + sd_sphere = import_fury_shader(os.path.join("sdf", "sd_sphere.frag")) # SDF definition - sdf_map = \ - """ + sdf_map = """ float map(in vec3 position) { /* @@ -152,38 +148,42 @@ def tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity): """ # Importing central differences function for computing surface normals - central_diffs_normal = import_fury_shader(os.path.join( - 'sdf', 'central_diffs.frag')) + central_diffs_normal = import_fury_shader(os.path.join("sdf", "central_diffs.frag")) # Importing raymarching function - cast_ray = import_fury_shader(os.path.join( - 'ray_marching', 'cast_ray.frag')) + cast_ray = import_fury_shader(os.path.join("ray_marching", "cast_ray.frag")) # Importing the function that generates the ray components - ray_generation = import_fury_shader(os.path.join( - 'ray_marching', 'gen_ray.frag')) + ray_generation = import_fury_shader(os.path.join("ray_marching", "gen_ray.frag")) # Importing Blinn-Phong model for lighting - blinn_phong_model = import_fury_shader(os.path.join( - 'lighting', 'blinn_phong_model.frag')) + blinn_phong_model = import_fury_shader( + os.path.join("lighting", "blinn_phong_model.frag") + ) # Full fragment shader declaration - fs_dec = compose_shader([fs_vars_dec, sd_sphere, sdf_map, - central_diffs_normal, cast_ray, ray_generation, - blinn_phong_model]) - - shader_to_actor(box_actor, 'fragment', decl_code=fs_dec) - - ray_components = \ - """ + fs_dec = compose_shader( + [ + fs_vars_dec, + sd_sphere, + sdf_map, + central_diffs_normal, + cast_ray, + ray_generation, + blinn_phong_model, + ] + ) + + shader_to_actor(box_actor, "fragment", decl_code=fs_dec) + + ray_components = """ vec3 ro; vec3 rd; float t; gen_ray(ro, rd, t); """ # Fragment shader output definition # If surface is detected, color is assigned, otherwise, nothing is painted - frag_output_def = \ - """ + frag_output_def = """ if(t < 20) { vec3 pos = ro + t * rd; @@ -205,8 +205,7 @@ def tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity): # Full fragment shader implementation sdf_frag_impl = compose_shader([ray_components, frag_output_def]) - shader_to_actor(box_actor, 'fragment', impl_code=sdf_frag_impl, - block='light') + shader_to_actor(box_actor, "fragment", impl_code=sdf_frag_impl, block="light") return box_actor @@ -242,29 +241,28 @@ def double_cone(centers, axes, angles, colors, scales, opacity): n_verts = 8 big_centers = np.repeat(centers, n_verts, axis=0) - attribute_to_actor(box_actor, big_centers, 'center') + attribute_to_actor(box_actor, big_centers, "center") big_scales = np.repeat(scales, n_verts, axis=0) - attribute_to_actor(box_actor, big_scales, 'scale') + attribute_to_actor(box_actor, big_scales, "scale") evec1 = np.array([item[0] for item in axes]) evec2 = np.array([item[1] for item in axes]) evec3 = np.array([item[2] for item in axes]) big_vectors_1 = np.repeat(evec1, n_verts, axis=0) - attribute_to_actor(box_actor, big_vectors_1, 'evec1') + attribute_to_actor(box_actor, big_vectors_1, "evec1") big_vectors_2 = np.repeat(evec2, n_verts, axis=0) - attribute_to_actor(box_actor, big_vectors_2, 'evec2') + attribute_to_actor(box_actor, big_vectors_2, "evec2") big_vectors_3 = np.repeat(evec3, n_verts, axis=0) - attribute_to_actor(box_actor, big_vectors_3, 'evec3') + attribute_to_actor(box_actor, big_vectors_3, "evec3") big_angles = np.repeat(np.array(angles, dtype=float), n_verts, axis=0) - attribute_to_actor(box_actor, big_angles, 'angle') + attribute_to_actor(box_actor, big_angles, "angle") # Start of shader implementation - vs_dec = \ - """ + vs_dec = """ in vec3 center; in float scale; in vec3 evec1; @@ -280,8 +278,7 @@ def double_cone(centers, axes, angles, colors, scales, opacity): """ # Variables assignment - v_assign = \ - """ + v_assign = """ vertexMCVSOutput = vertexMC; centerMCVSOutput = center; scaleVSOutput = scale; @@ -289,8 +286,7 @@ def double_cone(centers, axes, angles, colors, scales, opacity): """ # Rotation matrix - rot_matrix = \ - """ + rot_matrix = """ mat3 R = mat3(normalize(evec1), normalize(evec2), normalize(evec3)); float a = radians(90); mat3 rot = mat3(cos(a),-sin(a), 0, @@ -301,11 +297,9 @@ def double_cone(centers, axes, angles, colors, scales, opacity): vs_impl = compose_shader([v_assign, rot_matrix]) - shader_to_actor(box_actor, 'vertex', decl_code=vs_dec, - impl_code=vs_impl) + shader_to_actor(box_actor, "vertex", decl_code=vs_dec, impl_code=vs_impl) - fs_vars_dec = \ - """ + fs_vars_dec = """ in vec4 vertexMCVSOutput; in vec3 centerMCVSOutput; in float scaleVSOutput; @@ -316,14 +310,13 @@ def double_cone(centers, axes, angles, colors, scales, opacity): """ # Importing the cone SDF - sd_cone = import_fury_shader(os.path.join('sdf', 'sd_cone.frag')) + sd_cone = import_fury_shader(os.path.join("sdf", "sd_cone.frag")) # Importing the union operation SDF - sd_union = import_fury_shader(os.path.join('sdf', 'sd_union.frag')) + sd_union = import_fury_shader(os.path.join("sdf", "sd_union.frag")) # SDF definition - sdf_map = \ - """ + sdf_map = """ float map(in vec3 position) { vec3 p = (position - centerMCVSOutput)/scaleVSOutput @@ -336,38 +329,43 @@ def double_cone(centers, axes, angles, colors, scales, opacity): """ # Importing central differences function for computing surface normals - central_diffs_normal = import_fury_shader(os.path.join( - 'sdf', 'central_diffs.frag')) + central_diffs_normal = import_fury_shader(os.path.join("sdf", "central_diffs.frag")) # Importing raymarching function - cast_ray = import_fury_shader(os.path.join( - 'ray_marching', 'cast_ray.frag')) + cast_ray = import_fury_shader(os.path.join("ray_marching", "cast_ray.frag")) # Importing the function that generates the ray components - ray_generation = import_fury_shader(os.path.join( - 'ray_marching', 'gen_ray.frag')) + ray_generation = import_fury_shader(os.path.join("ray_marching", "gen_ray.frag")) # Importing Blinn-Phong model for lighting - blinn_phong_model = import_fury_shader(os.path.join( - 'lighting', 'blinn_phong_model.frag')) + blinn_phong_model = import_fury_shader( + os.path.join("lighting", "blinn_phong_model.frag") + ) # Full fragment shader declaration - fs_dec = compose_shader([fs_vars_dec, sd_cone, sd_union, sdf_map, - central_diffs_normal, cast_ray, ray_generation, - blinn_phong_model]) - - shader_to_actor(box_actor, 'fragment', decl_code=fs_dec) - - ray_components = \ - """ + fs_dec = compose_shader( + [ + fs_vars_dec, + sd_cone, + sd_union, + sdf_map, + central_diffs_normal, + cast_ray, + ray_generation, + blinn_phong_model, + ] + ) + + shader_to_actor(box_actor, "fragment", decl_code=fs_dec) + + ray_components = """ vec3 ro; vec3 rd; float t; gen_ray(ro, rd, t); """ # Fragment shader output definition # If surface is detected, color is assigned, otherwise, nothing is painted - frag_output_def = \ - """ + frag_output_def = """ if(t < 20) { vec3 pos = ro + t * rd; @@ -389,8 +387,7 @@ def double_cone(centers, axes, angles, colors, scales, opacity): # Full fragment shader implementation sdf_frag_impl = compose_shader([ray_components, frag_output_def]) - shader_to_actor(box_actor, 'fragment', impl_code=sdf_frag_impl, - block='light') + shader_to_actor(box_actor, "fragment", impl_code=sdf_frag_impl, block="light") return box_actor @@ -449,14 +446,14 @@ def main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix): """ angles = np.ones(evecs.shape[0]) for i in range(evecs.shape[0]): - sigma_e = np.diag(signal[i] / sigma ** 2) + sigma_e = np.diag(signal[i] / sigma**2) k = np.dot(np.transpose(b_matrix), sigma_e) sigma_ = np.dot(k, b_matrix) dd = np.diag(sigma_) - delta_DD = np.array([[dd[0], dd[3], dd[4]], - [dd[3], dd[1], dd[5]], - [dd[4], dd[5], dd[2]]]) + delta_DD = np.array( + [[dd[0], dd[3], dd[4]], [dd[3], dd[1], dd[5]], [dd[4], dd[5], dd[2]]] + ) # perturbation matrix of tensor D try: @@ -467,17 +464,20 @@ def main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix): D_ = evecs eigen_vals = evals[i] - e1, e2, e3 = np.array(D_[i, :, 0]), np.array(D_[i, :, 1]), \ - np.array(D_[i, :, 2]) + e1, e2, e3 = np.array(D_[i, :, 0]), np.array(D_[i, :, 1]), np.array(D_[i, :, 2]) lambda1, lambda2, lambda3 = eigen_vals[0], eigen_vals[1], eigen_vals[2] if lambda1 > lambda2 and lambda1 > lambda3: # The perturbation of the eigenvector associated with the largest # eigenvalue is given by - a = np.dot(np.outer(np.dot(e1, delta_D), np.transpose(e2)) / - (lambda1 - lambda2), e2) - b = np.dot(np.outer(np.dot(e1, delta_D), np.transpose(e3)) / - (lambda1 - lambda3), e3) + a = np.dot( + np.outer(np.dot(e1, delta_D), np.transpose(e2)) / (lambda1 - lambda2), + e2, + ) + b = np.dot( + np.outer(np.dot(e1, delta_D), np.transpose(e3)) / (lambda1 - lambda3), + e3, + ) delta_e1 = a + b # The angle \theta between the perturbed principal eigenvector of D diff --git a/fury/actors/tests/test_peak.py b/fury/actors/tests/test_peak.py index fbb688f33..13ea18742 100644 --- a/fury/actors/tests/test_peak.py +++ b/fury/actors/tests/test_peak.py @@ -42,11 +42,11 @@ def test__orientation_colors(): [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]] ) - colors = _orientation_colors(points, cmap='rgb_standard') + colors = _orientation_colors(points, cmap="rgb_standard") expected = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] npt.assert_array_equal(colors, expected) - npt.assert_raises(ValueError, _orientation_colors, points, cmap='test') + npt.assert_raises(ValueError, _orientation_colors, points, cmap="test") def test__peaks_colors_from_points(): @@ -61,7 +61,7 @@ def test__peaks_colors_from_points(): npt.assert_equal(colors_are_scalars, False) npt.assert_equal(global_opacity, 1) - colors_tuple = _peaks_colors_from_points(points, colors='rgb_standard') + colors_tuple = _peaks_colors_from_points(points, colors="rgb_standard") vtk_colors, colors_are_scalars, global_opacity = colors_tuple desired = [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] npt.assert_array_equal(numpy_support.vtk_to_numpy(vtk_colors), desired) diff --git a/fury/animation/__init__.py b/fury/animation/__init__.py index 33129d5b4..10cd5a103 100644 --- a/fury/animation/__init__.py +++ b/fury/animation/__init__.py @@ -1,2 +1,8 @@ from fury.animation.animation import Animation, CameraAnimation from fury.animation.timeline import Timeline + +__all__ = [ + "Animation", + "CameraAnimation", + "Timeline", +] diff --git a/fury/animation/animation.py b/fury/animation/animation.py index 8e2d78b63..f2fa56bb9 100644 --- a/fury/animation/animation.py +++ b/fury/animation/animation.py @@ -42,11 +42,7 @@ class Animation: """ - def __init__(self, actors=None, - length=None, - loop=True, - motion_path_res=None): - + def __init__(self, actors=None, length=None, loop=True, motion_path_res=None): super().__init__() self._data = defaultdict(dict) self._animations = [] @@ -84,8 +80,7 @@ def update_duration(self): else: self._duration = max( self._max_timestamp, - max([0] + [anim.update_duration() - for anim in self.child_animations]), + max([0] + [anim.update_duration() for anim in self.child_animations]), ) return self.duration @@ -132,10 +127,10 @@ def update_motion_path(self): lines = [] colors = [] - if self.is_interpolatable('position'): + if self.is_interpolatable("position"): ts = np.linspace(0, self.duration, res) [lines.append(self.get_position(t).tolist()) for t in ts] - if self.is_interpolatable('color'): + if self.is_interpolatable("color"): [colors.append(self.get_color(t)) for t in ts] elif len(self._actors) >= 1: colors = sum([i.vcolors[0] / 255 for i in self._actors]) / len( @@ -186,14 +181,13 @@ def _get_attribute_data(self, attrib): if attrib not in data: data[attrib] = { - 'keyframes': defaultdict(dict), - 'interpolator': { - 'base': (linear_interpolator - if attrib != 'rotation' else slerp), - 'func': None, - 'args': defaultdict(), + "keyframes": defaultdict(dict), + "interpolator": { + "base": (linear_interpolator if attrib != "rotation" else slerp), + "func": None, + "args": defaultdict(), }, - 'callbacks': [], + "callbacks": [], } return data.get(attrib) @@ -211,10 +205,9 @@ def get_keyframes(self, attrib=None): if attrib is None: attribs = data.keys() return { - attrib: data.get(attrib, - {}).get('keyframes', {}) for attrib in attribs + attrib: data.get(attrib, {}).get("keyframes", {}) for attrib in attribs } - return data.get(attrib, {}).get('keyframes', {}) + return data.get(attrib, {}).get("keyframes", {}) def set_keyframe( self, attrib, timestamp, value, update_interpolator=True, **kwargs @@ -245,10 +238,10 @@ def set_keyframe( """ attrib_data = self._get_attribute_data(attrib) - keyframes = attrib_data.get('keyframes') + keyframes = attrib_data.get("keyframes") keyframes[timestamp] = { - 'value': np.array(value).astype(float), + "value": np.array(value).astype(float), **{ par: np.array(val).astype(float) for par, val in kwargs.items() @@ -257,11 +250,11 @@ def set_keyframe( } if update_interpolator: - interp = attrib_data.get('interpolator') + interp = attrib_data.get("interpolator") interp_base = interp.get( - 'base', linear_interpolator if attrib != 'rotation' else slerp + "base", linear_interpolator if attrib != "rotation" else slerp ) - args = interp.get('args', {}) + args = interp.get("args", {}) self.set_interpolator(attrib, interp_base, **args) if timestamp > self._max_timestamp: @@ -320,9 +313,8 @@ def is_inside_scene_at(self, timestamp): if parent is not None: parent_in_scene = parent._added_to_scene - if self.is_interpolatable('in_scene'): - in_scene = parent_in_scene and self.get_value('in_scene', - timestamp) + if self.is_interpolatable("in_scene"): + in_scene = parent_in_scene and self.get_value("in_scene", timestamp) else: in_scene = parent_in_scene return in_scene @@ -336,11 +328,11 @@ def add_to_scene_at(self, timestamp): Timestamp of the event. """ - if not self.is_interpolatable('in_scene'): - self.set_keyframe('in_scene', timestamp, True) - self.set_interpolator('in_scene', step_interpolator) + if not self.is_interpolatable("in_scene"): + self.set_keyframe("in_scene", timestamp, True) + self.set_interpolator("in_scene", step_interpolator) else: - self.set_keyframe('in_scene', timestamp, True) + self.set_keyframe("in_scene", timestamp, True) def remove_from_scene_at(self, timestamp): """Set timestamp for removing Animation to scene event. @@ -351,11 +343,11 @@ def remove_from_scene_at(self, timestamp): Timestamp of the event. """ - if not self.is_interpolatable('in_scene'): - self.set_keyframe('in_scene', timestamp, False) - self.set_interpolator('in_scene', step_interpolator) + if not self.is_interpolatable("in_scene"): + self.set_keyframe("in_scene", timestamp, False) + self.set_interpolator("in_scene", step_interpolator) else: - self.set_keyframe('in_scene', timestamp, False) + self.set_keyframe("in_scene", timestamp, False) def _handle_scene_event(self, timestamp): should_be_in_scene = self.is_inside_scene_at(timestamp) @@ -367,8 +359,7 @@ 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): + def set_interpolator(self, attrib, interpolator, is_evaluator=False, **kwargs): """Set keyframes interpolator for a certain property Parameters @@ -406,19 +397,19 @@ def set_interpolator(self, attrib, interpolator, """ attrib_data = self._get_attribute_data(attrib) - keyframes = attrib_data.get('keyframes', {}) - interp_data = attrib_data.get('interpolator', {}) + keyframes = attrib_data.get("keyframes", {}) + interp_data = attrib_data.get("interpolator", {}) if is_evaluator: - interp_data['base'] = None - interp_data['func'] = interpolator + interp_data["base"] = None + interp_data["func"] = interpolator else: - interp_data['base'] = interpolator - interp_data['args'] = kwargs + interp_data["base"] = interpolator + interp_data["args"] = kwargs # Maintain interpolator base in case new keyframes are added. if len(keyframes) == 0: return new_interp = interpolator(keyframes, **kwargs) - interp_data['func'] = new_interp + interp_data["func"] = new_interp # update motion path self.update_duration() @@ -444,10 +435,9 @@ def is_interpolatable(self, attrib): """ data = self._data - return bool(data.get(attrib, {}).get('interpolator', {}).get('func')) + return bool(data.get(attrib, {}).get("interpolator", {}).get("func")) - def set_position_interpolator(self, interpolator, - is_evaluator=False, **kwargs): + def set_position_interpolator(self, interpolator, is_evaluator=False, **kwargs): """Set the position interpolator. Parameters @@ -471,7 +461,7 @@ def set_position_interpolator(self, interpolator, """ self.set_interpolator( - 'position', interpolator, is_evaluator=is_evaluator, **kwargs + "position", interpolator, is_evaluator=is_evaluator, **kwargs ) def set_scale_interpolator(self, interpolator, is_evaluator=False): @@ -491,7 +481,7 @@ def set_scale_interpolator(self, interpolator, is_evaluator=False): >>> Animation.set_scale_interpolator(step_interpolator) """ - self.set_interpolator('scale', interpolator, is_evaluator=is_evaluator) + self.set_interpolator("scale", interpolator, is_evaluator=is_evaluator) def set_rotation_interpolator(self, interpolator, is_evaluator=False): """Set the rotation interpolator . @@ -510,8 +500,7 @@ def set_rotation_interpolator(self, interpolator, is_evaluator=False): >>> Animation.set_rotation_interpolator(slerp) """ - self.set_interpolator('rotation', interpolator, - is_evaluator=is_evaluator) + self.set_interpolator("rotation", interpolator, is_evaluator=is_evaluator) def set_color_interpolator(self, interpolator, is_evaluator=False): """Set the color interpolator. @@ -530,7 +519,7 @@ def set_color_interpolator(self, interpolator, is_evaluator=False): >>> Animation.set_color_interpolator(lab_color_interpolator) """ - self.set_interpolator('color', interpolator, is_evaluator=is_evaluator) + self.set_interpolator("color", interpolator, is_evaluator=is_evaluator) def set_opacity_interpolator(self, interpolator, is_evaluator=False): """Set the opacity interpolator. @@ -549,9 +538,7 @@ def set_opacity_interpolator(self, interpolator, is_evaluator=False): >>> Animation.set_opacity_interpolator(step_interpolator) """ - self.set_interpolator('opacity', - interpolator, - is_evaluator=is_evaluator) + self.set_interpolator("opacity", interpolator, is_evaluator=is_evaluator) def get_value(self, attrib, timestamp): """Return the value of an attribute at any given timestamp. @@ -565,8 +552,7 @@ def get_value(self, attrib, timestamp): """ value = ( - self._data.get(attrib, - {}).get('interpolator', {}).get('func')(timestamp) + self._data.get(attrib, {}).get("interpolator", {}).get("func")(timestamp) ) return value @@ -581,8 +567,8 @@ def get_current_value(self, attrib): """ return ( self._data.get(attrib) - .get('interpolator') - .get('func')(self._timeline.current_timestamp) + .get("interpolator") + .get("func")(self._timeline.current_timestamp) ) def set_position(self, timestamp, position, **kwargs): @@ -614,7 +600,7 @@ def set_position(self, timestamp, position, **kwargs): interpolation method. """ - self.set_keyframe('position', timestamp, position, **kwargs) + self.set_keyframe("position", timestamp, position, **kwargs) def set_position_keyframes(self, keyframes): """Set a dict of position keyframes at once. @@ -632,7 +618,7 @@ def set_position_keyframes(self, keyframes): >>> Animation.set_position_keyframes(pos_keyframes) """ - self.set_keyframes('position', keyframes) + self.set_keyframes("position", keyframes) def set_rotation(self, timestamp, rotation, **kwargs): """Set a rotation keyframe at a specific timestamp. @@ -653,19 +639,20 @@ def set_rotation(self, timestamp, rotation, **kwargs): """ no_components = len(np.array(rotation).flatten()) if no_components == 4: - self.set_keyframe('rotation', timestamp, rotation, **kwargs) + self.set_keyframe("rotation", timestamp, rotation, **kwargs) elif no_components == 3: # user is expected to set rotation order by default as setting # orientation of a `vtkActor` ordered as z->x->y. rotation = np.asarray(rotation, dtype=float) rotation = transform.Rotation.from_euler( - 'zxy', rotation[[2, 0, 1]], degrees=True + "zxy", rotation[[2, 0, 1]], degrees=True ).as_quat() - self.set_keyframe('rotation', timestamp, rotation, **kwargs) + self.set_keyframe("rotation", timestamp, rotation, **kwargs) else: warn( - f'Keyframe with {no_components} components is not a ' - f'valid rotation data. Skipped!' + f"Keyframe with {no_components} components is not a " + f"valid rotation data. Skipped!", + stacklevel=2, ) def set_rotation_as_vector(self, timestamp, vector, **kwargs): @@ -680,7 +667,7 @@ def set_rotation_as_vector(self, timestamp, vector, **kwargs): """ quat = transform.Rotation.from_rotvec(vector).as_quat() - self.set_keyframe('rotation', timestamp, quat, **kwargs) + self.set_keyframe("rotation", timestamp, quat, **kwargs) def set_scale(self, timestamp, scalar, **kwargs): """Set a scale keyframe at a specific timestamp. @@ -693,7 +680,7 @@ def set_scale(self, timestamp, scalar, **kwargs): Scale keyframe value associated with the timestamp. """ - self.set_keyframe('scale', timestamp, scalar, **kwargs) + self.set_keyframe("scale", timestamp, scalar, **kwargs) def set_scale_keyframes(self, keyframes): """Set a dict of scale keyframes at once. @@ -711,7 +698,7 @@ def set_scale_keyframes(self, keyframes): >>> Animation.set_scale_keyframes(scale_keyframes) """ - self.set_keyframes('scale', keyframes) + self.set_keyframes("scale", keyframes) def set_color(self, timestamp, color, **kwargs): """Set color keyframe at a specific timestamp. @@ -724,7 +711,7 @@ def set_color(self, timestamp, color, **kwargs): Color keyframe value associated with the timestamp. """ - self.set_keyframe('color', timestamp, color, **kwargs) + self.set_keyframe("color", timestamp, color, **kwargs) def set_color_keyframes(self, keyframes): """Set a dict of color keyframes at once. @@ -742,7 +729,7 @@ def set_color_keyframes(self, keyframes): >>> Animation.set_color_keyframes(color_keyframes) """ - self.set_keyframes('color', keyframes) + self.set_keyframes("color", keyframes) def set_opacity(self, timestamp, opacity, **kwargs): """Set opacity keyframe at a specific timestamp. @@ -755,7 +742,7 @@ def set_opacity(self, timestamp, opacity, **kwargs): Opacity keyframe value associated with the timestamp. """ - self.set_keyframe('opacity', timestamp, opacity, **kwargs) + self.set_keyframe("opacity", timestamp, opacity, **kwargs) def set_opacity_keyframes(self, keyframes): """Set a dict of opacity keyframes at once. @@ -777,7 +764,7 @@ def set_opacity_keyframes(self, keyframes): >>> Animation.set_scale_keyframes(opacity) """ - self.set_keyframes('opacity', keyframes) + self.set_keyframes("opacity", keyframes) def get_position(self, t): """Return the interpolated position. @@ -793,7 +780,7 @@ def get_position(self, t): The interpolated position. """ - return self.get_value('position', t) + return self.get_value("position", t) def get_rotation(self, t, as_quat=False): """Return the interpolated rotation. @@ -811,17 +798,17 @@ def get_rotation(self, t, as_quat=False): The interpolated rotation as Euler degrees by default. """ - rot = self.get_value('rotation', t) + rot = self.get_value("rotation", t) if len(rot) == 4: if as_quat: return rot r = transform.Rotation.from_quat(rot) - degrees = r.as_euler('zxy', degrees=True)[[1, 2, 0]] + degrees = r.as_euler("zxy", degrees=True)[[1, 2, 0]] return degrees elif not as_quat: return rot return transform.Rotation.from_euler( - 'zxy', rot[[2, 0, 1]], degrees=True + "zxy", rot[[2, 0, 1]], degrees=True ).as_quat() def get_scale(self, t): @@ -838,7 +825,7 @@ def get_scale(self, t): The interpolated scale. """ - return self.get_value('scale', t) + return self.get_value("scale", t) def get_color(self, t): """Return the interpolated color. @@ -854,7 +841,7 @@ def get_color(self, t): The interpolated color. """ - return self.get_value('color', t) + return self.get_value("color", t) def get_opacity(self, t): """Return the opacity value. @@ -870,7 +857,7 @@ def get_opacity(self, t): The interpolated opacity. """ - return self.get_value('opacity', t) + return self.get_value("opacity", t) def add(self, item): """Add an item to the Animation. @@ -1002,7 +989,7 @@ def actors(self): return self._actors @property - def child_animations(self) -> 'list[Animation]': + def child_animations(self) -> "list[Animation]": """Return a list of child Animations. Returns @@ -1105,7 +1092,7 @@ def add_update_callback(self, callback, prop=None): self._general_callbacks.append(callback) return attrib = self._get_attribute_data(prop) - attrib.get('callbacks', []).append(callback) + attrib.get("callbacks", []).append(callback) def update_animation(self, time=None): """Update the animation. @@ -1143,26 +1130,26 @@ def update_animation(self, time=None): # actors properties if in_scene: - if self.is_interpolatable('position'): + if self.is_interpolatable("position"): position = self.get_position(time) self._transform.Translate(*position) - if self.is_interpolatable('opacity'): + if self.is_interpolatable("opacity"): opacity = self.get_opacity(time) [act.GetProperty().SetOpacity(opacity) for act in self.actors] - if self.is_interpolatable('rotation'): + if self.is_interpolatable("rotation"): x, y, z = self.get_rotation(time) # Rotate in the same order as VTK defaults. self._transform.RotateZ(z) self._transform.RotateX(x) self._transform.RotateY(y) - if self.is_interpolatable('scale'): + if self.is_interpolatable("scale"): scale = self.get_scale(time) self._transform.Scale(*scale) - if self.is_interpolatable('color'): + if self.is_interpolatable("color"): color = self.get_color(time) for act in self.actors: act.vcolors[:] = color * 255 @@ -1172,7 +1159,7 @@ def update_animation(self, time=None): [act.SetUserTransform(self._transform) for act in self.actors] for attrib in self._data: - callbacks = self._data.get(attrib, {}).get('callbacks', []) + callbacks = self._data.get(attrib, {}).get("callbacks", []) if callbacks != [] and self.is_interpolatable(attrib): value = self.get_value(attrib, time) [cbk(value) for cbk in callbacks] @@ -1230,11 +1217,7 @@ class CameraAnimation(Animation): """ - def __init__(self, - camera=None, - length=None, - loop=True, - motion_path_res=None): + 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 ) @@ -1275,7 +1258,7 @@ def set_focal(self, timestamp, position, **kwargs): The camera position """ - self.set_keyframe('focal', timestamp, position, **kwargs) + self.set_keyframe("focal", timestamp, position, **kwargs) def set_view_up(self, timestamp, direction, **kwargs): """Set the camera view-up direction keyframe. @@ -1288,7 +1271,7 @@ def set_view_up(self, timestamp, direction, **kwargs): The camera view-up direction """ - self.set_keyframe('view_up', timestamp, direction, **kwargs) + self.set_keyframe("view_up", timestamp, direction, **kwargs) def set_focal_keyframes(self, keyframes): """Set multiple camera focal position keyframes at once. @@ -1307,7 +1290,7 @@ def set_focal_keyframes(self, keyframes): >>> CameraAnimation.set_focal_keyframes(focal_pos) """ - self.set_keyframes('focal', keyframes) + self.set_keyframes("focal", keyframes) def set_view_up_keyframes(self, keyframes): """Set multiple camera view up direction keyframes. @@ -1326,7 +1309,7 @@ def set_view_up_keyframes(self, keyframes): >>> CameraAnimation.set_view_up_keyframes(view_ups) """ - self.set_keyframes('view_up', keyframes) + self.set_keyframes("view_up", keyframes) def get_focal(self, t): """Return the interpolated camera's focal position. @@ -1347,7 +1330,7 @@ def get_focal(self, t): camera's focal position, but the expected one. """ - return self.get_value('focal', t) + return self.get_value("focal", t) def get_view_up(self, t): """Return the interpolated camera's view-up directional vector. @@ -1368,7 +1351,7 @@ def get_view_up(self, t): camera view up directional vector, but the expected one. """ - return self.get_value('view_up', t) + return self.get_value("view_up", t) def set_focal_interpolator(self, interpolator, is_evaluator=False): """Set the camera focal position interpolator. @@ -1383,7 +1366,7 @@ def set_focal_interpolator(self, interpolator, is_evaluator=False): function that does not depend on keyframes. """ - self.set_interpolator('focal', interpolator, is_evaluator=is_evaluator) + self.set_interpolator("focal", interpolator, is_evaluator=is_evaluator) def set_view_up_interpolator(self, interpolator, is_evaluator=False): """Set the camera up-view vector animation interpolator. @@ -1398,8 +1381,7 @@ def set_view_up_interpolator(self, interpolator, is_evaluator=False): function that does not depend on keyframes. """ - self.set_interpolator('view_up', interpolator, - is_evaluator=is_evaluator) + self.set_interpolator("view_up", interpolator, is_evaluator=is_evaluator) def update_animation(self, time=None): """Update the camera animation. @@ -1417,32 +1399,29 @@ def update_animation(self, time=None): self.update_animation(time) return else: - if self.is_interpolatable('rotation'): + if self.is_interpolatable("rotation"): pos = self._camera.GetPosition() translation = np.identity(4) translation[:3, 3] = pos # camera axis is reverted rot = -self.get_rotation(time, as_quat=True) rot = transform.Rotation.from_quat(rot).as_matrix() - rot = np.array([[*rot[0], 0], - [*rot[1], 0], - [*rot[2], 0], - [0, 0, 0, 1]]) + rot = np.array([[*rot[0], 0], [*rot[1], 0], [*rot[2], 0], [0, 0, 0, 1]]) rot = translation @ rot @ np.linalg.inv(translation) self._camera.SetModelTransformMatrix(rot.flatten()) - if self.is_interpolatable('position'): + if self.is_interpolatable("position"): cam_pos = self.get_position(time) self._camera.SetPosition(cam_pos) - if self.is_interpolatable('focal'): + if self.is_interpolatable("focal"): cam_foc = self.get_focal(time) self._camera.SetFocalPoint(cam_foc) - if self.is_interpolatable('view_up'): + if self.is_interpolatable("view_up"): cam_up = self.get_view_up(time) self._camera.SetViewUp(cam_up) - elif not self.is_interpolatable('view_up'): + elif not self.is_interpolatable("view_up"): # to preserve up-view as default after user interaction self._camera.SetViewUp(0, 1, 0) if self._scene: diff --git a/fury/animation/helpers.py b/fury/animation/helpers.py index eb4d01f25..f1753a8e9 100644 --- a/fury/animation/helpers.py +++ b/fury/animation/helpers.py @@ -83,8 +83,7 @@ def get_values_from_keyframes(keyframes): """ return np.asarray( - [keyframes.get(t, {}).get('value', None) - for t in sorted(keyframes.keys())] + [keyframes.get(t, {}).get("value", None) for t in sorted(keyframes.keys())] ) @@ -152,4 +151,4 @@ def euclidean_distances(points): A List of euclidean distance between each consecutive points or values. """ - return [np.linalg.norm(x - y) for x, y in zip(points, points[1:])] + return [np.linalg.norm(x - y) for x, y in zip(points, points[1:], strict=False)] diff --git a/fury/animation/interpolator.py b/fury/animation/interpolator.py index 97260acea..a7228a7dd 100644 --- a/fury/animation/interpolator.py +++ b/fury/animation/interpolator.py @@ -36,9 +36,9 @@ def spline_interpolator(keyframes, degree): """ if len(keyframes) < (degree + 1): raise ValueError( - f'Minimum {degree + 1} ' - f'keyframes must be set in order to use ' - f'{degree}-degree spline' + f"Minimum {degree + 1} " + f"keyframes must be set in order to use " + f"{degree}-degree spline" ) timestamps = get_timestamps_from_keyframes(keyframes) @@ -108,7 +108,7 @@ def step_interpolator(keyframes): def interpolate(t): previous_t = get_previous_timestamp(timestamps, t, include_last=True) - return keyframes.get(previous_t).get('value') + return keyframes.get(previous_t).get("value") return interpolate @@ -137,11 +137,11 @@ def linear_interpolator(keyframes): def interpolate(t): if is_single: t = timestamps[0] - return keyframes.get(t).get('value') + return keyframes.get(t).get("value") t0 = get_previous_timestamp(timestamps, t) t1 = get_next_timestamp(timestamps, t) - p0 = keyframes.get(t0).get('value') - p1 = keyframes.get(t1).get('value') + p0 = keyframes.get(t0).get("value") + p1 = keyframes.get(t1).get("value") return lerp(p0, p1, t0, t1, t) return interpolate @@ -175,21 +175,21 @@ def cubic_bezier_interpolator(keyframes): for ts in timestamps: # keyframe at timestamp kf_ts = keyframes.get(ts) - if kf_ts.get('in_cp') is None: - kf_ts['in_cp'] = kf_ts.get('value') + if kf_ts.get("in_cp") is None: + kf_ts["in_cp"] = kf_ts.get("value") - if kf_ts.get('out_cp') is None: - kf_ts['out_cp'] = kf_ts.get('value') + if kf_ts.get("out_cp") is None: + kf_ts["out_cp"] = kf_ts.get("value") def interpolate(t): t0 = get_previous_timestamp(timestamps, t) t1 = get_next_timestamp(timestamps, t) k0 = keyframes.get(t0) k1 = keyframes.get(t1) - p0 = k0.get('value') - p1 = k0.get('out_cp') - p2 = k1.get('in_cp') - p3 = k1.get('value') + p0 = k0.get("value") + p1 = k0.get("out_cp") + p2 = k1.get("in_cp") + p3 = k1.get("value") dt = get_time_tau(t, t0, t1) val = ( (1 - dt) ** 3 * p0 @@ -227,7 +227,7 @@ def slerp(keyframes): quat_rots = [] for ts in timestamps: - quat_rots.append(keyframes.get(ts).get('value')) + quat_rots.append(keyframes.get(ts).get("value")) rotations = transform.Rotation.from_quat(quat_rots) # if only one keyframe specified, linear interpolator is used. if len(timestamps) == 1: @@ -272,12 +272,12 @@ def color_interpolator(keyframes, rgb2space, space2rgb): space_keyframes = {} is_single = len(keyframes) == 1 for ts, keyframe in keyframes.items(): - space_keyframes[ts] = rgb2space(keyframe.get('value')) + space_keyframes[ts] = rgb2space(keyframe.get("value")) def interpolate(t): if is_single: t = timestamps[0] - return keyframes.get(t).get('value') + return keyframes.get(t).get("value") t0 = get_previous_timestamp(timestamps, t) t1 = get_next_timestamp(timestamps, t) c0 = space_keyframes.get(t0) @@ -342,11 +342,11 @@ def tan_cubic_spline_interpolator(keyframes): timestamps = get_timestamps_from_keyframes(keyframes) for time in keyframes: data = keyframes.get(time) - value = data.get('value') - if data.get('in_tangent') is None: - data['in_tangent'] = np.zeros_like(value) - if data.get('in_tangent') is None: - data['in_tangent'] = np.zeros_like(value) + value = data.get("value") + if data.get("in_tangent") is None: + data["in_tangent"] = np.zeros_like(value) + if data.get("in_tangent") is None: + data["in_tangent"] = np.zeros_like(value) def interpolate(t): t0 = get_previous_timestamp(timestamps, t) @@ -356,10 +356,10 @@ def interpolate(t): time_delta = t1 - t0 - p0 = keyframes.get(t0).get('value') - tan_0 = keyframes.get(t0).get('out_tangent') * time_delta - p1 = keyframes.get(t1).get('value') - tan_1 = keyframes.get(t1).get('in_tangent') * time_delta + p0 = keyframes.get(t0).get("value") + tan_0 = keyframes.get(t0).get("out_tangent") * time_delta + p1 = keyframes.get(t1).get("value") + tan_1 = keyframes.get(t1).get("in_tangent") * time_delta # cubic spline equation using tangents t2 = dt * dt t3 = t2 * dt diff --git a/fury/animation/tests/test_helpers.py b/fury/animation/tests/test_helpers.py index 222775e40..3b5daf4f2 100644 --- a/fury/animation/tests/test_helpers.py +++ b/fury/animation/tests/test_helpers.py @@ -7,9 +7,9 @@ def test_get_timestamps_from_keyframes(): keyframes = { - 0: {'value': np.array([0, 0, 0])}, - 1: {'value': np.array([1, 0, 0])}, - 2: {'value': np.array([2, 0, 0])}, + 0: {"value": np.array([0, 0, 0])}, + 1: {"value": np.array([1, 0, 0])}, + 2: {"value": np.array([2, 0, 0])}, } # Test `get_timestamps_from_keyframes` timestamps = helpers.get_timestamps_from_keyframes(keyframes) @@ -35,12 +35,12 @@ def test_lerp(): def test_get_values_from_keyframes(): keyframes = { - 0: {'value': np.array([0, 0, 0])}, - 1: {'value': np.array([1, 0, 0])}, - 2: {'value': np.array([2, 0, 0])}, + 0: {"value": np.array([0, 0, 0])}, + 1: {"value": np.array([1, 0, 0])}, + 2: {"value": np.array([2, 0, 0])}, } values = helpers.get_values_from_keyframes(keyframes) - npt.assert_array_equal(values, np.array([i['value'] for i in keyframes.values()])) + npt.assert_array_equal(values, np.array([i["value"] for i in keyframes.values()])) values = helpers.get_values_from_keyframes({}) npt.assert_array_equal(values, np.array([])) @@ -54,11 +54,11 @@ def test_get_next_timestamp(): for t in range(-100, 100, 1): t /= 10 next_ts = helpers.get_next_timestamp(timestamps, t) - npt.assert_(next_ts in timestamps, 'Timestamp is not valid') + npt.assert_(next_ts in timestamps, "Timestamp is not valid") ft.assert_greater_equal(next_ts, min(max(timestamps), t)) next_ts_2 = helpers.get_next_timestamp(timestamps, t, include_first=True) ft.assert_less_equal(next_ts_2, next_ts) - npt.assert_(next_ts_2 in timestamps, 'Timestamp is not valid') + npt.assert_(next_ts_2 in timestamps, "Timestamp is not valid") ts = helpers.get_next_timestamp(timestamps, 0.5, include_first=False) ft.assert_equal(ts, 2) @@ -71,11 +71,11 @@ def test_get_previous_timestamp(): for t in range(-100, 100, 1): t /= 10 previous_ts = helpers.get_previous_timestamp(timestamps, t) - npt.assert_(previous_ts in timestamps, 'Timestamp is not valid') + npt.assert_(previous_ts in timestamps, "Timestamp is not valid") ft.assert_less_equal(previous_ts, max(min(timestamps), t)) previous_ts_2 = helpers.get_previous_timestamp(timestamps, t, include_last=True) ft.assert_greater_equal(previous_ts_2, previous_ts) - npt.assert_(previous_ts_2 in timestamps, 'Timestamp is not valid') + npt.assert_(previous_ts_2 in timestamps, "Timestamp is not valid") ts = helpers.get_previous_timestamp(timestamps, 5.5, include_last=False) ft.assert_equal(ts, 5) diff --git a/fury/animation/tests/test_interpolators.py b/fury/animation/tests/test_interpolators.py index 80389d0a5..5856676d2 100644 --- a/fury/animation/tests/test_interpolators.py +++ b/fury/animation/tests/test_interpolators.py @@ -22,9 +22,9 @@ def assert_not_equal(x, y): def test_step_interpolator(): data = { - 1: {'value': np.array([1, 2, 3])}, - 2: {'value': np.array([0, 0, 0])}, - 3: {'value': np.array([5, 5, 5])}, + 1: {"value": np.array([1, 2, 3])}, + 2: {"value": np.array([0, 0, 0])}, + 3: {"value": np.array([5, 5, 5])}, } interpolator = step_interpolator(data) @@ -44,33 +44,33 @@ def test_step_interpolator(): npt.assert_equal(interpolator(999), pos_final) for t in range(-10, 40, 1): - npt.assert_equal(interpolator(t / 10).shape, data.get(1).get('value').shape) + npt.assert_equal(interpolator(t / 10).shape, data.get(1).get("value").shape) - for ts, pos in data.items(): - npt.assert_equal(interpolator(ts), data.get(ts).get('value')) + for ts in data.keys(): + npt.assert_equal(interpolator(ts), data.get(ts).get("value")) interp = step_interpolator({}) try: interp(1) - raise "This shouldn't work since no keyframes were provided!" + raise Exception("This shouldn't work since no keyframes were provided!") except IndexError: ... - data = {1: {'value': np.array([1, 2, 3])}} + data = {1: {"value": np.array([1, 2, 3])}} interp = step_interpolator(data) npt.assert_equal(interp(-100), np.array([1, 2, 3])) npt.assert_equal(interp(100), np.array([1, 2, 3])) - data = {1: {'value': None}} + data = {1: {"value": None}} interp = step_interpolator(data) npt.assert_equal(interp(-100), None) def test_linear_interpolator(): data = { - 1: {'value': np.array([1, 2, 3])}, - 2: {'value': np.array([0, 0, 0])}, - 3: {'value': np.array([5, 5, 5])}, + 1: {"value": np.array([1, 2, 3])}, + 2: {"value": np.array([0, 0, 0])}, + 3: {"value": np.array([5, 5, 5])}, } interpolator = linear_interpolator(data) @@ -79,13 +79,13 @@ def test_linear_interpolator(): pos2 = interpolator(2.1) assert_not_equal(pos1, pos2) - npt.assert_equal(pos1, data.get(2).get('value')) + npt.assert_equal(pos1, data.get(2).get("value")) - for ts, pos in data.items(): - npt.assert_equal(interpolator(ts), data.get(ts).get('value')) + for ts in data.keys(): + npt.assert_equal(interpolator(ts), data.get(ts).get("value")) for t in range(-10, 40, 1): - npt.assert_equal(interpolator(t / 10).shape, data.get(1).get('value').shape) + npt.assert_equal(interpolator(t / 10).shape, data.get(1).get("value").shape) pos_initial = interpolator(1) pos_final = interpolator(3) @@ -97,43 +97,43 @@ def test_linear_interpolator(): interp = linear_interpolator({}) try: interp(1) - raise "This shouldn't work since no keyframes were provided!" + raise Exception("This shouldn't work since no keyframes were provided!") except IndexError: ... - data = {1: {'value': np.array([1, 2, 3])}} + data = {1: {"value": np.array([1, 2, 3])}} interp = linear_interpolator(data) npt.assert_equal(interp(-100), np.array([1, 2, 3])) npt.assert_equal(interp(100), np.array([1, 2, 3])) - data = {1: {'value': None}, 2: {'value': np.array([1, 1, 1])}} + data = {1: {"value": None}, 2: {"value": np.array([1, 1, 1])}} interp = linear_interpolator(data) try: interp(1) - raise "This shouldn't work since invalid keyframes were provided!" + raise Exception("This shouldn't work since invalid keyframes were provided!") except TypeError: ... def test_cubic_spline_interpolator(): data = { - 1: {'value': np.array([1, 2, 3])}, - 2: {'value': np.array([0, 0, 0])}, - 3: {'value': np.array([5, 5, 5])}, - 4: {'value': np.array([7, 7, 7])}, + 1: {"value": np.array([1, 2, 3])}, + 2: {"value": np.array([0, 0, 0])}, + 3: {"value": np.array([5, 5, 5])}, + 4: {"value": np.array([7, 7, 7])}, } interpolator = cubic_spline_interpolator(data) pos1 = interpolator(2) - npt.assert_almost_equal(pos1, data.get(2).get('value')) + npt.assert_almost_equal(pos1, data.get(2).get("value")) - for ts, pos in data.items(): - npt.assert_almost_equal(interpolator(ts), data.get(ts).get('value')) + for ts in data.keys(): + npt.assert_almost_equal(interpolator(ts), data.get(ts).get("value")) for t in range(-10, 40, 1): npt.assert_almost_equal( - interpolator(t / 10).shape, data.get(1).get('value').shape + interpolator(t / 10).shape, data.get(1).get("value").shape ) pos_initial = interpolator(1) @@ -145,15 +145,15 @@ def test_cubic_spline_interpolator(): try: cubic_spline_interpolator({}) - raise 'At least 4 keyframes must be provided!' + raise Exception("At least 4 keyframes must be provided!") except ValueError: ... data = { - 1: {'value': None}, - 2: {'value': np.array([1, 1, 1])}, - 3: {'value': None}, - 4: {'value': None}, + 1: {"value": None}, + 2: {"value": np.array([1, 1, 1])}, + 3: {"value": None}, + 4: {"value": None}, } # Interpolator should not work with invalid data! @@ -162,11 +162,11 @@ def test_cubic_spline_interpolator(): def test_cubic_bezier_interpolator(): - data_1 = {1: {'value': np.array([-2, 0, 0])}, 2: {'value': np.array([18, 0, 0])}} + data_1 = {1: {"value": np.array([-2, 0, 0])}, 2: {"value": np.array([18, 0, 0])}} data_2 = { - 1: {'value': np.array([-2, 0, 0]), 'out_cp': np.array([-15, 6, 0])}, - 2: {'value': np.array([18, 0, 0]), 'in_cp': np.array([27, 18, 0])}, + 1: {"value": np.array([-2, 0, 0]), "out_cp": np.array([-15, 6, 0])}, + 2: {"value": np.array([18, 0, 0]), "in_cp": np.array([27, 18, 0])}, } # with control points @@ -186,14 +186,14 @@ def test_cubic_bezier_interpolator(): npt.assert_equal(interp_1(1), interp_2(1)) npt.assert_equal(interp_1(2), interp_2(2)) - for ts, pos in data_1.items(): - expected = data_1.get(ts).get('value') + for ts in data_1.keys(): + expected = data_1.get(ts).get("value") npt.assert_almost_equal(interp_1(ts), expected) npt.assert_almost_equal(interp_2(ts), expected) for t in range(-10, 40, 1): npt.assert_almost_equal( - interp_1(t / 10).shape, data_1.get(1).get('value').shape + interp_1(t / 10).shape, data_1.get(1).get("value").shape ) pos_initial = interp_1(1) @@ -210,26 +210,26 @@ def test_cubic_bezier_interpolator(): try: interp(1) - raise "This shouldn't work since no keyframes were provided!" + raise Exception("This shouldn't work since no keyframes were provided!") except IndexError: ... - data = {1: {'value': np.array([1, 2, 3])}} + data = {1: {"value": np.array([1, 2, 3])}} interp = cubic_bezier_interpolator(data) npt.assert_equal(interp(-10), np.array([1, 2, 3])) npt.assert_equal(interp(100), np.array([1, 2, 3])) - data = {1: {'value': None}, 2: {'value': np.array([1, 1, 1])}} + data = {1: {"value": None}, 2: {"value": np.array([1, 1, 1])}} interp = cubic_bezier_interpolator(data) try: interp(1) - raise "This shouldn't work since no keyframes were provided!" + raise Exception("This shouldn't work since no keyframes were provided!") except TypeError: ... def test_n_spline_interpolator(): - data = {i: {'value': np.random.random(3) * 10} for i in range(10)} + data = {i: {"value": np.random.random(3) * 10} for i in range(10)} interps = [spline_interpolator(data, degree=i) for i in range(1, 6)] @@ -237,20 +237,20 @@ def test_n_spline_interpolator(): npt.assert_equal(i(-999), i(0)) npt.assert_equal(i(999), i(10)) for t in range(10): - npt.assert_almost_equal(i(t), data.get(t).get('value')) + npt.assert_almost_equal(i(t), data.get(t).get("value")) for t in range(-100, 100, 1): i(t / 10) try: spline_interpolator({}, 5) - raise 'At least 6 keyframes must be provided!' + raise Exception("At least 6 keyframes must be provided!") except ValueError: ... data = { - 1: {'value': None}, - 2: {'value': np.array([1, 1, 1])}, - 3: {'value': None}, - 4: {'value': None}, + 1: {"value": None}, + 2: {"value": np.array([1, 1, 1])}, + 3: {"value": None}, + 4: {"value": None}, } # Interpolator should not work with invalid data! @@ -259,7 +259,7 @@ def test_n_spline_interpolator(): def test_color_interpolators(): - data = {1: {'value': np.array([1, 0.5, 0])}, 2: {'value': np.array([0.5, 0, 1])}} + data = {1: {"value": np.array([1, 0.5, 0])}, 2: {"value": np.array([0.5, 0, 1])}} color_interps = [ hsv_color_interpolator(data), @@ -289,22 +289,22 @@ def test_color_interpolators(): interp = interpolator({}) try: interp(1) - raise "This shouldn't work since no keyframes were provided!" + raise Exception("This shouldn't work since no keyframes were provided!") except IndexError: ... - data = {1: {'value': np.array([1, 2, 3])}} + data = {1: {"value": np.array([1, 2, 3])}} interp = interpolator(data) npt.assert_equal(interp(-10), np.array([1, 2, 3])) npt.assert_equal(interp(10), np.array([1, 2, 3])) - data = {1: {'value': None}, 2: {'value': np.array([1, 1, 1])}} + data = {1: {"value": None}, 2: {"value": np.array([1, 1, 1])}} try: interpolator(data) - msg = "This shouldn't work since invalid keyframes " + msg = "This shouldn't work since invalid keyframes " msg += "were provided! and hence can't be converted to" msg += "targeted color space." - raise msg + raise msg except ( TypeError, AttributeError, @@ -314,8 +314,8 @@ def test_color_interpolators(): def test_slerp(): data = { - 1: {'value': np.array([0, 0, 0, 1])}, - 2: {'value': np.array([0, 0.7071068, 0, 0.7071068])}, + 1: {"value": np.array([0, 0, 0, 1])}, + 2: {"value": np.array([0, 0.7071068, 0, 0.7071068])}, } interp_slerp = slerp(data) @@ -335,19 +335,19 @@ def test_slerp(): try: interp = slerp({}) interp(1) - raise "This shouldn't work since no keyframes were provided!" + raise Exception("This shouldn't work since no keyframes were provided!") except ValueError: ... - data = {1: {'value': np.array([1, 2, 3, 1])}} + data = {1: {"value": np.array([1, 2, 3, 1])}} interp = slerp(data) npt.assert_equal(interp(-100), np.array([1, 2, 3, 1])) npt.assert_equal(interp(100), np.array([1, 2, 3, 1])) - data = {1: {'value': None}, 2: {'value': np.array([1, 1, 1])}} + data = {1: {"value": None}, 2: {"value": np.array([1, 1, 1])}} try: interp = slerp(data) interp(1) - raise "This shouldn't work since invalid keyframes were provided!" + raise Exception("This shouldn't work since invalid keyframes were provided!") except ValueError: ... diff --git a/fury/animation/tests/test_timeline.py b/fury/animation/tests/test_timeline.py index 8897ad0fe..79a3301be 100644 --- a/fury/animation/tests/test_timeline.py +++ b/fury/animation/tests/test_timeline.py @@ -6,7 +6,6 @@ from fury.animation import Animation, Timeline import fury.testing as ft from fury.ui import PlaybackPanel -from fury.window import Scene, ShowManager def assert_not_equal(x, y): diff --git a/fury/animation/timeline.py b/fury/animation/timeline.py index f90e0b8c7..7156a809d 100644 --- a/fury/animation/timeline.py +++ b/fury/animation/timeline.py @@ -33,10 +33,7 @@ class Timeline: """ - def __init__(self, animations=None, - playback_panel=False, - loop=True, length=None): - + def __init__(self, animations=None, playback_panel=False, loop=True, length=None): self._scene = None self.playback_panel = None self._current_timestamp = 0 @@ -287,9 +284,17 @@ def has_playback_panel(self): """ return self.playback_panel is not None - def record(self, fname=None, fps=30, speed=1.0, size=(900, 768), - order_transparent=True, multi_samples=8, - max_peels=4, show_panel=False): + def record( + self, + fname=None, + fps=30, + speed=1.0, + size=(900, 768), + order_transparent=True, + multi_samples=8, + max_peels=4, + show_panel=False, + ): """Record the animation Parameters @@ -328,15 +333,16 @@ def record(self, fname=None, fps=30, speed=1.0, size=(900, 768), """ ext = os.path.splitext(fname)[-1] - mp4 = ext == '.mp4' + mp4 = ext == ".mp4" if mp4: try: import cv2 - except ImportError: - raise ImportError('OpenCV must be installed in order to ' - 'save as MP4 video.') - fourcc = cv2.VideoWriter.fourcc(*'mp4v') + except ImportError as err: + raise ImportError( + "OpenCV must be installed in order to " "save as MP4 video." + ) from err + fourcc = cv2.VideoWriter.fourcc(*"mp4v") out = cv2.VideoWriter(fname, fourcc, fps, size) duration = self.duration @@ -358,8 +364,7 @@ def record(self, fname=None, fps=30, speed=1.0, size=(900, 768), render_window.SetSize(*size) if order_transparent: - window.antialiasing(scene, render_window, multi_samples, max_peels, - 0) + window.antialiasing(scene, render_window, multi_samples, max_peels, 0) render_window = RenderWindow() render_window.SetOffScreenRendering(1) @@ -367,15 +372,11 @@ def record(self, fname=None, fps=30, speed=1.0, size=(900, 768), render_window.SetSize(*size) if order_transparent: - window.antialiasing(scene, - render_window, - multi_samples, - max_peels, - 0) + window.antialiasing(scene, render_window, multi_samples, max_peels, 0) window_to_image_filter = WindowToImageFilter() - print('Recording...') + print("Recording...") while t < duration: self.seek(t) render_window.Render() @@ -386,8 +387,7 @@ def record(self, fname=None, fps=30, speed=1.0, size=(900, 768), h, w, _ = vtk_image.GetDimensions() vtk_array = vtk_image.GetPointData().GetScalars() components = vtk_array.GetNumberOfComponents() - snap = numpy_support.vtk_to_numpy(vtk_array).reshape(w, h, - components) + snap = numpy_support.vtk_to_numpy(vtk_array).reshape(w, h, components) corrected_snap = np.flipud(snap) if mp4: @@ -399,7 +399,7 @@ def record(self, fname=None, fps=30, speed=1.0, size=(900, 768), t += step - print('Saving...') + print("Saving...") if fname is None: return frames @@ -407,8 +407,13 @@ def record(self, fname=None, fps=30, speed=1.0, size=(900, 768), if mp4: out.release() else: - frames[0].save(fname, append_images=frames[1:], loop=0, - duration=1000 / fps, save_all=True) + frames[0].save( + fname, + append_images=frames[1:], + loop=0, + duration=1000 / fps, + save_all=True, + ) if _hide_panel: self.playback_panel.show() @@ -431,10 +436,10 @@ def add_animation(self, animation): self._animations.append(animation) self.update_duration() else: - raise TypeError('Expected an Animation, a list or a tuple.') + raise TypeError("Expected an Animation, a list or a tuple.") @property - def animations(self) -> 'list[Animation]': + def animations(self) -> "list[Animation]": """Return a list of Animations. Returns diff --git a/fury/colormap.py b/fury/colormap.py index 922f97eec..0d836707f 100644 --- a/fury/colormap.py +++ b/fury/colormap.py @@ -11,7 +11,7 @@ # Allow import, but disable doctests if we don't have matplotlib from fury.optpkg import optional_package -cm, have_matplotlib, _ = optional_package('matplotlib.cm') +cm, have_matplotlib, _ = optional_package("matplotlib.cm") def colormap_lookup_table( @@ -193,7 +193,6 @@ def boys2rgb(v): trl_z = -2.1899 if v.ndim == 2: - N = len(x) C = np.zeros((N, 3)) @@ -202,7 +201,6 @@ def boys2rgb(v): C[:, 2] = 0.9 * np.abs(((Z - trl_z) / w_z)) + 0.05 if v.ndim == 1: - C = np.zeros((3,)) C[0] = 0.9 * np.abs(((X - trl_x) / w_x)) + 0.05 C[1] = 0.9 * np.abs(((Y - trl_y) / w_y)) + 0.05 @@ -238,14 +236,13 @@ def orient2rgb(v): orient = np.abs(np.divide(v, orientn, where=orientn != 0)) else: raise IOError( - 'Wrong vector dimension, It should be an array' - ' with a shape (N, 3)' + "Wrong vector dimension, It should be an array" " with a shape (N, 3)" ) return orient -def line_colors(streamlines, cmap='rgb_standard'): +def line_colors(streamlines, cmap="rgb_standard"): """Create colors for streamlines to be used in actor.line. Parameters @@ -258,38 +255,37 @@ def line_colors(streamlines, cmap='rgb_standard'): colors : ndarray """ - if cmap == 'rgb_standard': + if cmap == "rgb_standard": col_list = [ - orient2rgb(streamline[-1] - streamline[0]) - for streamline in streamlines + orient2rgb(streamline[-1] - streamline[0]) for streamline in streamlines ] - if cmap == 'boys_standard': + if cmap == "boys_standard": col_list = [ - boys2rgb(streamline[-1] - streamline[0]) - for streamline in streamlines + boys2rgb(streamline[-1] - streamline[0]) for streamline in streamlines ] return np.vstack(col_list) -lowercase_cm_name = {'blues': 'Blues', 'accent': 'Accent'} +lowercase_cm_name = {"blues": "Blues", "accent": "Accent"} dipy_cmaps = None def get_cmap(name): """Make a callable, similar to maptlotlib.pyplot.get_cmap.""" - if name.lower() == 'accent': + if name.lower() == "accent": warn( - 'The `Accent` colormap is deprecated as of version' - + ' 0.2 of Fury and will be removed in a future ' - + 'version. Please use another colormap', + "The `Accent` colormap is deprecated as of version" + + " 0.2 of Fury and will be removed in a future " + + "version. Please use another colormap", PendingDeprecationWarning, + stacklevel=2, ) global dipy_cmaps if dipy_cmaps is None: - filename = pjoin(DATA_DIR, 'dipy_colormaps.json') + filename = pjoin(DATA_DIR, "dipy_colormaps.json") with open(filename) as f: dipy_cmaps = json.load(f) @@ -300,8 +296,8 @@ def get_cmap(name): def simple_cmap(v): """Emulate matplotlib colormap callable.""" rgba = np.ones((len(v), 4)) - for i, color in enumerate(('red', 'green', 'blue')): - x, y0, _ = zip(*desc[color]) + for i, color in enumerate(("red", "green", "blue")): + x, y0, _ = zip(*desc[color], strict=False) # Matplotlib allows more complex colormaps, but for users who do # not have Matplotlib fury makes a few simple colormaps available. # These colormaps are simple because y0 == y1, and therefore we @@ -312,7 +308,7 @@ def simple_cmap(v): return simple_cmap -def create_colormap(v, name='plasma', auto=True): +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. @@ -338,17 +334,17 @@ def create_colormap(v, name='plasma', auto=True): """ if not have_matplotlib: - msg = 'You do not have Matplotlib installed. Some colormaps' - msg += ' might not work for you. Consider downloading Matplotlib.' - warn(msg) + msg = "You do not have Matplotlib installed. Some colormaps" + msg += " might not work for you. Consider downloading Matplotlib." + warn(msg, stacklevel=2) - if name.lower() == 'jet': - msg = 'Jet is a popular colormap but can often be misleading' - msg += 'Use instead plasma, viridis, hot or inferno.' - warn(msg, PendingDeprecationWarning) + if name.lower() == "jet": + msg = "Jet is a popular colormap but can often be misleading" + msg += "Use instead plasma, viridis, hot or inferno." + warn(msg, PendingDeprecationWarning, stacklevel=2) if v.ndim > 1: - msg = 'This function works only with 1d arrays. Use ravel()' + msg = "This function works only with 1d arrays. Use ravel()" raise ValueError(msg) if auto: @@ -361,7 +357,7 @@ def create_colormap(v, name='plasma', auto=True): colormap = getattr(cm, newname) if have_matplotlib else get_cmap(newname) if colormap is None: - e_s = 'Colormap {} is not yet implemented '.format(name) + e_s = "Colormap {} is not yet implemented ".format(name) raise ValueError(e_s) rgba = colormap(v) @@ -515,7 +511,7 @@ def _lab2rgb(lab): return _xyz2rgb(tmp) -def distinguishable_colormap(bg=(0, 0, 0), exclude=[], nb_colors=None): +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 @@ -566,6 +562,9 @@ def distinguishable_colormap(bg=(0, 0, 0), exclude=[], nb_colors=None): original implementation (v1.2), 14 Dec 2010 (Updated 07 Feb 2011). """ + if exclude is None: + exclude = [] + NB_DIVISIONS = 30 # This constant come from the original code. # Generate a sizable number of RGB triples. This represents our space of @@ -601,7 +600,9 @@ def _generate_next_color(): lastlab = lab[idx] if nb_colors is not None: - return [c for i, c in zip(range(nb_colors), _generate_next_color())] + return [ + c for i, c in zip(range(nb_colors), _generate_next_color(), strict=False) + ] return _generate_next_color() @@ -628,12 +629,12 @@ def hex_to_rgb(color): >>> c = colormap.hex_to_rgb(color) """ - if color[0] == '#': + if color[0] == "#": color = color[1:] - r = int('0x' + color[0:2], 0) / 255 - g = int('0x' + color[2:4], 0) / 255 - b = int('0x' + color[4:6], 0) / 255 + r = int("0x" + color[0:2], 0) / 255 + g = int("0x" + color[2:4], 0) / 255 + b = int("0x" + color[4:6], 0) / 255 return np.array([r, g, b]) @@ -672,7 +673,7 @@ def rgb2hsv(rgb): # -- S channel delta = rgb.ptp(-1) # Ignore warning for zero divided by zero - old_settings = np.seterr(invalid='ignore') + old_settings = np.seterr(invalid="ignore") out_s = delta / out_v out_s[delta == 0.0] = 0.0 @@ -829,42 +830,42 @@ def rgb2xyz(rgb): # it can be found at: # https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py illuminants = { - 'A': { - '2': (1.098466069456375, 1, 0.3558228003436005), - '10': (1.111420406956693, 1, 0.3519978321919493), - 'R': (1.098466069456375, 1, 0.3558228003436005), + "A": { + "2": (1.098466069456375, 1, 0.3558228003436005), + "10": (1.111420406956693, 1, 0.3519978321919493), + "R": (1.098466069456375, 1, 0.3558228003436005), }, - 'B': { - '2': (0.9909274480248003, 1, 0.8531327322886154), - '10': (0.9917777147717607, 1, 0.8434930535866175), - 'R': (0.9909274480248003, 1, 0.8531327322886154), + "B": { + "2": (0.9909274480248003, 1, 0.8531327322886154), + "10": (0.9917777147717607, 1, 0.8434930535866175), + "R": (0.9909274480248003, 1, 0.8531327322886154), }, - 'C': { - '2': (0.980705971659919, 1, 1.1822494939271255), - '10': (0.9728569189782166, 1, 1.1614480488951577), - 'R': (0.980705971659919, 1, 1.1822494939271255), + "C": { + "2": (0.980705971659919, 1, 1.1822494939271255), + "10": (0.9728569189782166, 1, 1.1614480488951577), + "R": (0.980705971659919, 1, 1.1822494939271255), }, - 'D50': { - '2': (0.9642119944211994, 1, 0.8251882845188288), - '10': (0.9672062750333777, 1, 0.8142801513128616), - 'R': (0.9639501491621826, 1, 0.8241280285499208), + "D50": { + "2": (0.9642119944211994, 1, 0.8251882845188288), + "10": (0.9672062750333777, 1, 0.8142801513128616), + "R": (0.9639501491621826, 1, 0.8241280285499208), }, - 'D55': { - '2': (0.956797052643698, 1, 0.9214805860173273), - '10': (0.9579665682254781, 1, 0.9092525159847462), - 'R': (0.9565317453467969, 1, 0.9202554587037198), + "D55": { + "2": (0.956797052643698, 1, 0.9214805860173273), + "10": (0.9579665682254781, 1, 0.9092525159847462), + "R": (0.9565317453467969, 1, 0.9202554587037198), }, - 'D65': { - '2': (0.95047, 1.0, 1.08883), - '10': (0.94809667673716, 1, 1.0730513595166162), - 'R': (0.9532057125493769, 1, 1.0853843816469158), + "D65": { + "2": (0.95047, 1.0, 1.08883), + "10": (0.94809667673716, 1, 1.0730513595166162), + "R": (0.9532057125493769, 1, 1.0853843816469158), }, - 'D75': { - '2': (0.9497220898840717, 1, 1.226393520724154), - '10': (0.9441713925645873, 1, 1.2064272211720228), - 'R': (0.9497220898840717, 1, 1.226393520724154), + "D75": { + "2": (0.9497220898840717, 1, 1.226393520724154), + "10": (0.9441713925645873, 1, 1.2064272211720228), + "R": (0.9497220898840717, 1, 1.226393520724154), }, - 'E': {'2': (1.0, 1.0, 1.0), '10': (1.0, 1.0, 1.0), 'R': (1.0, 1.0, 1.0)}, + "E": {"2": (1.0, 1.0, 1.0), "10": (1.0, 1.0, 1.0), "R": (1.0, 1.0, 1.0)}, } @@ -897,14 +898,14 @@ def get_xyz_coords(illuminant, observer): observer = observer.upper() try: return np.asarray(illuminants[illuminant][observer], dtype=float) - except KeyError: + except KeyError as err: raise ValueError( - f'Unknown illuminant/observer combination ' - f'(`{illuminant}`, `{observer}`)' - ) + f"Unknown illuminant/observer combination " + f"(`{illuminant}`, `{observer}`)" + ) from err -def xyz2lab(xyz, illuminant='D65', observer='2'): +def xyz2lab(xyz, illuminant="D65", observer="2"): """XYZ to CIE-LAB color space conversion. Parameters @@ -951,7 +952,7 @@ 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'): +def lab2xyz(lab, illuminant="D65", observer="2"): """CIE-LAB to XYZcolor space conversion. Parameters @@ -985,7 +986,7 @@ def lab2xyz(lab, illuminant='D65', observer='2'): if np.any(z < 0): invalid = np.nonzero(z < 0) warn( - 'Color data out of range: Z < 0 in %s pixels' % invalid[0].size, + "Color data out of range: Z < 0 in %s pixels" % invalid[0].size, stacklevel=2, ) z[invalid] = 0 @@ -1002,7 +1003,7 @@ def lab2xyz(lab, illuminant='D65', observer='2'): return out -def rgb2lab(rgb, illuminant='D65', observer='2'): +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. @@ -1032,7 +1033,7 @@ def rgb2lab(rgb, illuminant='D65', observer='2'): return xyz2lab(rgb2xyz(rgb), illuminant, observer) -def lab2rgb(lab, illuminant='D65', observer='2'): +def lab2rgb(lab, illuminant="D65", observer="2"): """Lab to RGB color space conversion. Parameters diff --git a/fury/convert.py b/fury/convert.py index 8d04a2a27..25ad4d1a8 100644 --- a/fury/convert.py +++ b/fury/convert.py @@ -43,22 +43,18 @@ def matplotlib_figure_to_numpy( """ if fname is None: with TemporaryDirectory() as tmpdir: - fname = os.path.join(tmpdir, 'tmp.png') + fname = os.path.join(tmpdir, "tmp.png") fig.savefig( fname, dpi=dpi, transparent=transparent, - bbox_inches='tight', + bbox_inches="tight", pad_inches=0, ) 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 27af60fcf..bea342c0e 100644 --- a/fury/data/__init__.py +++ b/fury/data/__init__.py @@ -20,13 +20,23 @@ read_viz_textures, ) -DATA_DIR = pjoin(dirname(__file__), 'files') +DATA_DIR = pjoin(dirname(__file__), "files") -__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__ = [ + "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", +] diff --git a/fury/data/fetcher.py b/fury/data/fetcher.py index 326d5f2ca..d73081866 100644 --- a/fury/data/fetcher.py +++ b/fury/data/fetcher.py @@ -17,37 +17,35 @@ import aiohttp # Set a user-writeable file-system location to put files: -if 'FURY_HOME' in os.environ: - fury_home = os.environ['FURY_HOME'] +if "FURY_HOME" in os.environ: + fury_home = os.environ["FURY_HOME"] else: - fury_home = pjoin(os.path.expanduser('~'), '.fury') + fury_home = pjoin(os.path.expanduser("~"), ".fury") # The URL to the University of Washington Researchworks repository: -UW_RW_URL = \ - "https://digital.lib.washington.edu/researchworks/bitstream/handle/" +UW_RW_URL = "https://digital.lib.washington.edu/researchworks/bitstream/handle/" NEW_ICONS_DATA_URL = ( - "https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/" - "new_icons/" + "https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/" "new_icons/" ) -CUBEMAP_DATA_URL = \ +CUBEMAP_DATA_URL = ( "https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/" +) -FURY_DATA_URL = \ - "https://raw.githubusercontent.com/fury-gl/fury-data/master/examples/" +FURY_DATA_URL = "https://raw.githubusercontent.com/fury-gl/fury-data/master/examples/" -MODEL_DATA_URL = \ - "https://raw.githubusercontent.com/fury-gl/fury-data/master/models/" +MODEL_DATA_URL = "https://raw.githubusercontent.com/fury-gl/fury-data/master/models/" -TEXTURE_DATA_URL = \ +TEXTURE_DATA_URL = ( "https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/" +) -DMRI_DATA_URL = \ - "https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/" +DMRI_DATA_URL = "https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/" -GLTF_DATA_URL = \ +GLTF_DATA_URL = ( "https://api.github.com/repos/KhronosGroup/glTF-Sample-Models/contents/2.0/" # noqa +) class FetcherError(Exception): @@ -61,10 +59,10 @@ def update_progressbar(progress, total_length): """ # Try to set the bar_length according to the console size try: - if os.name == 'nt': + if os.name == "nt": bar_length = 20 else: - columns = os.popen('tput cols', 'r').read() + columns = os.popen("tput cols", "r").read() bar_length = int(columns) - 46 if bar_length < 1: bar_length = 20 @@ -74,7 +72,8 @@ def update_progressbar(progress, total_length): block = int(round(bar_length * progress)) size_string = "{0:.2f} MB".format(float(total_length) / (1024 * 1024)) text = "\rDownload Progress: [{0}] {1:.2f}% of {2}\n".format( - "#" * block + "-" * (bar_length - block), progress * 100, size_string) + "#" * block + "-" * (bar_length - block), progress * 100, size_string + ) sys.stdout.write(text) sys.stdout.flush() @@ -93,8 +92,8 @@ def copyfileobj_withprogress(fsrc, fdst, total_length, length=16 * 1024): def _already_there_msg(folder): """Print a message indicating that dataset is already in place.""" - msg = 'Dataset is already in place. If you want to fetch it again ' - msg += 'please first remove the folder %s ' % folder + msg = "Dataset is already in place. If you want to fetch it again " + msg += "please first remove the folder %s " % folder print(msg) @@ -113,8 +112,8 @@ def _get_file_sha(filename): """ sha256_data = sha256() - with open(filename, 'rb') as f: - for chunk in iter(lambda: f.read(256*sha256_data.block_size), b''): + with open(filename, "rb") as f: + for chunk in iter(lambda: f.read(256 * sha256_data.block_size), b""): sha256_data.update(chunk) return sha256_data.hexdigest() @@ -150,11 +149,11 @@ def check_sha(filename, stored_sha256=None): def _get_file_data(fname, url): with contextlib.closing(urlopen(url)) as opener: try: - response_size = opener.headers['content-length'] + response_size = opener.headers["content-length"] except KeyError: response_size = None - with open(fname, 'wb') as data: + with open(fname, "wb") as data: if response_size is None: copyfileobj(opener, data) else: @@ -190,14 +189,13 @@ def fetch_data(files, folder, data_size=None): os.makedirs(folder) if data_size is not None: - print('Data size is approximately %s' % data_size) + print("Data size is approximately %s" % data_size) all_skip = True for f in files: url, sha = files[f] fullpath = pjoin(folder, f) - if os.path.exists(fullpath) and \ - (_get_file_sha(fullpath) == sha.lower()): + if os.path.exists(fullpath) and (_get_file_sha(fullpath) == sha.lower()): continue all_skip = False print('Downloading "%s" to %s' % (f, folder)) @@ -209,9 +207,18 @@ def fetch_data(files, folder, data_size=None): print("Files successfully downloaded to %s" % (folder)) -def _make_fetcher(name, folder, baseurl, remote_fnames, local_fnames, - sha_list=None, doc="", data_size=None, msg=None, - unzip=False): +def _make_fetcher( + name, + folder, + baseurl, + remote_fnames, + local_fnames, + sha_list=None, + doc="", + data_size=None, + msg=None, + unzip=False, +): """Create a new fetcher. Parameters @@ -249,11 +256,14 @@ def _make_fetcher(name, folder, baseurl, remote_fnames, local_fnames, inputs """ + 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) + for ( + i, + (f, n), + ) in enumerate(zip(remote_fnames, local_fnames, strict=False)): + files[n] = (baseurl + f, sha_list[i] if sha_list is not None else None) fetch_data(files, folder, data_size) if msg is not None: @@ -261,19 +271,19 @@ def fetcher(): if unzip: for f in local_fnames: split_ext = os.path.splitext(f) - if split_ext[-1] == '.gz' or split_ext[-1] == '.bz2': - if os.path.splitext(split_ext[0])[-1] == '.tar': + if split_ext[-1] == ".gz" or split_ext[-1] == ".bz2": + if os.path.splitext(split_ext[0])[-1] == ".tar": ar = tarfile.open(pjoin(folder, f)) ar.extractall(path=folder) ar.close() else: - raise ValueError('File extension is not recognized') - elif split_ext[-1] == '.zip': - z = zipfile.ZipFile(pjoin(folder, f), 'r') + raise ValueError("File extension is not recognized") + elif split_ext[-1] == ".zip": + z = zipfile.ZipFile(pjoin(folder, f), "r") z.extractall(folder) z.close() else: - raise ValueError('File extension is not recognized') + raise ValueError("File extension is not recognized") return files, folder @@ -320,16 +330,16 @@ async def _download(session, url, filename, size=None): Length of the content in bytes """ if not os.path.exists(filename): - print(f'Downloading: {filename}') + print(f"Downloading: {filename}") async with session.get(url) as response: size = response.content_length if not size else size block = size copied = 0 - with open(filename, mode='wb') as f: + with open(filename, mode="wb") as f: async for chunk in response.content.iter_chunked(block): f.write(chunk) copied += len(chunk) - progress = float(copied)/float(size) + progress = float(copied) / float(size) update_progressbar(progress, size) @@ -354,7 +364,7 @@ async def _fetch_gltf(name, mode): """ if name is None: - name = ['BoxTextured', 'Duck', 'CesiumMilkTruck', 'CesiumMan'] + name = ["BoxTextured", "Duck", "CesiumMilkTruck", "CesiumMan"] if isinstance(name, list): f_names = await asyncio.gather( @@ -362,28 +372,27 @@ async def _fetch_gltf(name, mode): ) return f_names else: - path = f'{name}/{mode}' - DATA_DIR = pjoin(dirname(__file__), 'files') - with open(pjoin(DATA_DIR, 'KhronosGltfSamples.json'), 'r') as f: + path = f"{name}/{mode}" + DATA_DIR = pjoin(dirname(__file__), "files") + with open(pjoin(DATA_DIR, "KhronosGltfSamples.json"), "r") as f: models = json.loads(f.read()) urls = models.get(path, None) if urls is None: - raise ValueError( - "Model name and mode combination doesn't exist") + raise ValueError("Model name and mode combination doesn't exist") path = pjoin(name, mode) - path = pjoin('glTF', path) + path = pjoin("glTF", path) folder = pjoin(fury_home, path) if not os.path.exists(folder): os.makedirs(folder) - d_urls = [file['download_url'] for file in urls] - sizes = [file['size'] for file in urls] - f_names = [url.split('/')[-1] for url in d_urls] + d_urls = [file["download_url"] for file in urls] + sizes = [file["size"] for file in urls] + f_names = [url.split("/")[-1] for url in d_urls] f_paths = [pjoin(folder, name) for name in f_names] - zip_url = zip(d_urls, f_paths, sizes) + zip_url = zip(d_urls, f_paths, sizes, strict=False) async with aiohttp.ClientSession() as session: await asyncio.gather( @@ -393,7 +402,7 @@ async def _fetch_gltf(name, mode): return f_names, folder -def fetch_gltf(name=None, mode='glTF'): +def fetch_gltf(name=None, mode="glTF"): """Download glTF samples from Khronos Group Github. Parameters @@ -425,161 +434,241 @@ def fetch_gltf(name=None, mode='glTF'): "fetch_viz_cubemaps", pjoin(fury_home, "cubemaps"), CUBEMAP_DATA_URL, - ['skybox-nx.jpg', 'skybox-ny.jpg', 'skybox-nz.jpg', 'skybox-px.jpg', - 'skybox-py.jpg', 'skybox-pz.jpg'], - ['skybox-nx.jpg', 'skybox-ny.jpg', 'skybox-nz.jpg', 'skybox-px.jpg', - 'skybox-py.jpg', 'skybox-pz.jpg'], - ['12B1CE6C91AA3AAF258A8A5944DF739A6C1CC76E89D4D7119D1F795A30FC1BF2', - 'E18FE2206B63D3DF2C879F5E0B9937A61D99734B6C43AC288226C58D2418D23E', - '00DDDD1B715D5877AF2A74C014FF6E47891F07435B471D213CD0673A8C47F2B2', - 'BF20ACD6817C9E7073E485BBE2D2CE56DACFF73C021C2B613BA072BA2DF2B754', - '16F0D692AF0B80E46929D8D8A7E596123C76729CC5EB7DFD1C9184B115DD143A', - 'B850B5E882889DF26BE9289D7C25BA30524B37E56BC2075B968A83197AD977F3'], - doc="Download cube map textures for fury" + [ + "skybox-nx.jpg", + "skybox-ny.jpg", + "skybox-nz.jpg", + "skybox-px.jpg", + "skybox-py.jpg", + "skybox-pz.jpg", + ], + [ + "skybox-nx.jpg", + "skybox-ny.jpg", + "skybox-nz.jpg", + "skybox-px.jpg", + "skybox-py.jpg", + "skybox-pz.jpg", + ], + [ + "12B1CE6C91AA3AAF258A8A5944DF739A6C1CC76E89D4D7119D1F795A30FC1BF2", + "E18FE2206B63D3DF2C879F5E0B9937A61D99734B6C43AC288226C58D2418D23E", + "00DDDD1B715D5877AF2A74C014FF6E47891F07435B471D213CD0673A8C47F2B2", + "BF20ACD6817C9E7073E485BBE2D2CE56DACFF73C021C2B613BA072BA2DF2B754", + "16F0D692AF0B80E46929D8D8A7E596123C76729CC5EB7DFD1C9184B115DD143A", + "B850B5E882889DF26BE9289D7C25BA30524B37E56BC2075B968A83197AD977F3", + ], + doc="Download cube map textures for fury", ) fetch_viz_icons = _make_fetcher( "fetch_viz_icons", pjoin(fury_home, "icons"), UW_RW_URL + "1773/38478/", - ['icomoon.tar.gz'], - ['icomoon.tar.gz'], - ['BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735'], + ["icomoon.tar.gz"], + ["icomoon.tar.gz"], + ["BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735"], data_size="12KB", doc="Download icons for fury", - unzip=True - ) + unzip=True, +) fetch_viz_new_icons = _make_fetcher( "fetch_viz_new_icons", pjoin(fury_home, "icons", "new_icons"), NEW_ICONS_DATA_URL, - ["circle-pressed.png", "circle.png", "delete-pressed.png", "delete.png", - "drawing-pressed.png", "drawing.png", "line-pressed.png", "line.png", - "polyline-pressed.png", "polyline.png", "quad-pressed.png", "quad.png", - "resize-pressed.png", "resize.png", "selection-pressed.png", - "selection.png"], - ["circle-pressed.png", "circle.png", "delete-pressed.png", "delete.png", - "drawing-pressed.png", "drawing.png", "line-pressed.png", "line.png", - "polyline-pressed.png", "polyline.png", "quad-pressed.png", "quad.png", - "resize-pressed.png", "resize.png", "selection-pressed.png", - "selection.png"], - ["CD859F244DF1BA719C65C869C3FAF6B8563ABF82F457730ADBFBD7CA72DDB7BC", - "5896BDC9FF9B3D1054134D7D9A854677CE9FA4E64F494F156BB2E3F0E863F207", - "937C46C25BC38B62021B01C97A4EE3CDE5F7C8C4A6D0DB75BF4E4CACE2AF1226", - "476E00A0A5373E1CCDA4AF8E7C9158E0AC9B46B540CE410C6EA47D97F364A0CD", - "08A914C5DC7997CB944B8C5FBB958951F80B715CFE04FF4F47A73F9D08C4B14B", - "FB2210B0393ECA8A5DD2B8F034DAE386BBB47EB95BB1CAC2A97DE807EE195ADF", - "8D1AC2BB7C5BAA34E68578DAAD85F64EF824BE7BCB828CAC18E52833D4CBF4C9", - "E6D833B6D958129E12FF0F6087282CE92CD43C6DAFCE03F185746ECCA89E42A9", - "CFF12B8DE48FC19DA5D5F0EA7FF2D23DD942D05468E19522E7C7BEB72F0FF66E", - "7AFE65EBAE0C0D0556393B979148AE15FC3E037D126CD1DA4A296F4E25F5B4AA", - "5FD43F1C2D37BF9AF05D9FC591172684AC51BA236980CD1B0795B0225B9247E2", - "A2DA0CB963401C174919E1D8028AA6F0CB260A736FD26421DB5AB08E9F3C4FDF", - "FF49DDF9DF24729F4F6345C30C88DE0A11E5B12B2F2FF28375EF9762FE5F8995", - "A2D850CDBA8F332DA9CD7B7C9459CBDA587C18AF0D3C12CA68D6E6A864EF54BB", - "54618FDC4589F0A039D531C07A110ED9BC57A256BB15A3B5429CF60E950887C3", - "CD573F5E4BF4A91A3B21F6124A95FFB3C036F926F8FEC1FD0180F5D27D8F48C0"], - doc="Download the new icons for DrawPanel" - ) + [ + "circle-pressed.png", + "circle.png", + "delete-pressed.png", + "delete.png", + "drawing-pressed.png", + "drawing.png", + "line-pressed.png", + "line.png", + "polyline-pressed.png", + "polyline.png", + "quad-pressed.png", + "quad.png", + "resize-pressed.png", + "resize.png", + "selection-pressed.png", + "selection.png", + ], + [ + "circle-pressed.png", + "circle.png", + "delete-pressed.png", + "delete.png", + "drawing-pressed.png", + "drawing.png", + "line-pressed.png", + "line.png", + "polyline-pressed.png", + "polyline.png", + "quad-pressed.png", + "quad.png", + "resize-pressed.png", + "resize.png", + "selection-pressed.png", + "selection.png", + ], + [ + "CD859F244DF1BA719C65C869C3FAF6B8563ABF82F457730ADBFBD7CA72DDB7BC", + "5896BDC9FF9B3D1054134D7D9A854677CE9FA4E64F494F156BB2E3F0E863F207", + "937C46C25BC38B62021B01C97A4EE3CDE5F7C8C4A6D0DB75BF4E4CACE2AF1226", + "476E00A0A5373E1CCDA4AF8E7C9158E0AC9B46B540CE410C6EA47D97F364A0CD", + "08A914C5DC7997CB944B8C5FBB958951F80B715CFE04FF4F47A73F9D08C4B14B", + "FB2210B0393ECA8A5DD2B8F034DAE386BBB47EB95BB1CAC2A97DE807EE195ADF", + "8D1AC2BB7C5BAA34E68578DAAD85F64EF824BE7BCB828CAC18E52833D4CBF4C9", + "E6D833B6D958129E12FF0F6087282CE92CD43C6DAFCE03F185746ECCA89E42A9", + "CFF12B8DE48FC19DA5D5F0EA7FF2D23DD942D05468E19522E7C7BEB72F0FF66E", + "7AFE65EBAE0C0D0556393B979148AE15FC3E037D126CD1DA4A296F4E25F5B4AA", + "5FD43F1C2D37BF9AF05D9FC591172684AC51BA236980CD1B0795B0225B9247E2", + "A2DA0CB963401C174919E1D8028AA6F0CB260A736FD26421DB5AB08E9F3C4FDF", + "FF49DDF9DF24729F4F6345C30C88DE0A11E5B12B2F2FF28375EF9762FE5F8995", + "A2D850CDBA8F332DA9CD7B7C9459CBDA587C18AF0D3C12CA68D6E6A864EF54BB", + "54618FDC4589F0A039D531C07A110ED9BC57A256BB15A3B5429CF60E950887C3", + "CD573F5E4BF4A91A3B21F6124A95FFB3C036F926F8FEC1FD0180F5D27D8F48C0", + ], + doc="Download the new icons for DrawPanel", +) fetch_viz_wiki_nw = _make_fetcher( "fetch_viz_wiki_nw", pjoin(fury_home, "examples", "wiki_nw"), FURY_DATA_URL, - ['wiki_categories.txt', 'wiki_edges.txt', - 'wiki_positions.txt'], - ['wiki_categories.txt', 'wiki_edges.txt', - 'wiki_positions.txt'], - ['1679241B13D2FD01209160F0C186E14AB55855478300B713D5369C12854CFF82', - '702EE8713994243C8619A29C9ECE32F95305737F583B747C307500F3EC4A6B56', - '044917A8FBD0EB980D93B6C406A577BEA416FA934E897C26C87E91C218EF4432'], + ["wiki_categories.txt", "wiki_edges.txt", "wiki_positions.txt"], + ["wiki_categories.txt", "wiki_edges.txt", "wiki_positions.txt"], + [ + "1679241B13D2FD01209160F0C186E14AB55855478300B713D5369C12854CFF82", + "702EE8713994243C8619A29C9ECE32F95305737F583B747C307500F3EC4A6B56", + "044917A8FBD0EB980D93B6C406A577BEA416FA934E897C26C87E91C218EF4432", + ], doc="Download the following wiki information" - "Interdisciplinary map of the journals", - msg=("More information about complex " - "networks can be found in this papers:" - " https://arxiv.org/abs/0711.3199") - ) + "Interdisciplinary map of the journals", + msg=( + "More information about complex " + "networks can be found in this papers:" + " https://arxiv.org/abs/0711.3199" + ), +) fetch_viz_models = _make_fetcher( "fetch_viz_models", pjoin(fury_home, "models"), MODEL_DATA_URL, - ['utah.obj', 'suzanne.obj', 'satellite_obj.obj', 'dragon.obj'], - ['utah.obj', 'suzanne.obj', 'satellite_obj.obj', 'dragon.obj'], - ['0B50F12CEDCDC27377AC702B1EE331223BECEC59593B3F00A9E06B57A9C1B7C3', - 'BB4FF4E65D65D71D53000E06D2DC7BF89B702223657C1F64748811A3A6C8D621', - '90213FAC81D89BBB59FA541643304E0D95C2D446157ACE044D46F259454C0E74', - 'A775D6160D04EAB9A4E90180104F148927CEFCCAF9F0BCD748265CB8EE86F41B'], - doc=" Download the models for shader tutorial" - ) + ["utah.obj", "suzanne.obj", "satellite_obj.obj", "dragon.obj"], + ["utah.obj", "suzanne.obj", "satellite_obj.obj", "dragon.obj"], + [ + "0B50F12CEDCDC27377AC702B1EE331223BECEC59593B3F00A9E06B57A9C1B7C3", + "BB4FF4E65D65D71D53000E06D2DC7BF89B702223657C1F64748811A3A6C8D621", + "90213FAC81D89BBB59FA541643304E0D95C2D446157ACE044D46F259454C0E74", + "A775D6160D04EAB9A4E90180104F148927CEFCCAF9F0BCD748265CB8EE86F41B", + ], + doc=" Download the models for shader tutorial", +) fetch_viz_dmri = _make_fetcher( "fetch_viz_dmri", pjoin(fury_home, "dmri"), DMRI_DATA_URL, - ['fodf.nii.gz', 'slice_evecs.nii.gz', 'slice_evals.nii.gz', - 'roi_evecs.nii.gz', 'roi_evals.nii.gz', 'whole_brain_evecs.nii.gz', - 'whole_brain_evals.nii.gz'], - ['fodf.nii.gz', 'slice_evecs.nii.gz', 'slice_evals.nii.gz', - 'roi_evecs.nii.gz', 'roi_evals.nii.gz', 'whole_brain_evecs.nii.gz', - 'whole_brain_evals.nii.gz'], - ['767ca3e4cd296e78421d83c32201b30be2d859c332210812140caac1b93d492b', - '8843ECF3224CB8E3315B7251D1E303409A17D7137D3498A8833853C4603C6CC2', - '3096B190B1146DD0EADDFECC0B4FBBD901F4933692ADD46A83F637F28B22122D', - '89E569858A897E72C852A8F05BBCE0B21C1CA726E55508087A2DA5A38C212A17', - 'F53C68CCCABF97F1326E93840A8B5CE2E767D66D692FFD955CA747FFF14EC781', - '8A894F6AB404240E65451FA6D10FB5D74E2D0BDCB2A56AD6BEA38215BF787248', - '47A73BBE68196381ED790F80F48E46AC07B699B506973FFA45A95A33023C7A77'] + [ + "fodf.nii.gz", + "slice_evecs.nii.gz", + "slice_evals.nii.gz", + "roi_evecs.nii.gz", + "roi_evals.nii.gz", + "whole_brain_evecs.nii.gz", + "whole_brain_evals.nii.gz", + ], + [ + "fodf.nii.gz", + "slice_evecs.nii.gz", + "slice_evals.nii.gz", + "roi_evecs.nii.gz", + "roi_evals.nii.gz", + "whole_brain_evecs.nii.gz", + "whole_brain_evals.nii.gz", + ], + [ + "767ca3e4cd296e78421d83c32201b30be2d859c332210812140caac1b93d492b", + "8843ECF3224CB8E3315B7251D1E303409A17D7137D3498A8833853C4603C6CC2", + "3096B190B1146DD0EADDFECC0B4FBBD901F4933692ADD46A83F637F28B22122D", + "89E569858A897E72C852A8F05BBCE0B21C1CA726E55508087A2DA5A38C212A17", + "F53C68CCCABF97F1326E93840A8B5CE2E767D66D692FFD955CA747FFF14EC781", + "8A894F6AB404240E65451FA6D10FB5D74E2D0BDCB2A56AD6BEA38215BF787248", + "47A73BBE68196381ED790F80F48E46AC07B699B506973FFA45A95A33023C7A77", + ], ) fetch_viz_textures = _make_fetcher( "fetch_viz_textures", pjoin(fury_home, "textures"), TEXTURE_DATA_URL, - ['1_earth_8k.jpg', '2_no_clouds_8k.jpg', - '5_night_8k.jpg', 'earth.ppm', - 'jupiter.jpg', 'masonry.bmp', - 'moon_8k.jpg', - '8k_mercury.jpg', '8k_venus_surface.jpg', - '8k_mars.jpg', '8k_saturn.jpg', - '8k_saturn_ring_alpha.png', - '2k_uranus.jpg', '2k_neptune.jpg', - '8k_sun.jpg', '1_earth_16k.jpg', - 'clouds.jpg'], - ['1_earth_8k.jpg', '2_no_clouds_8k.jpg', - '5_night_8k.jpg', 'earth.ppm', - 'jupiter.jpg', 'masonry.bmp', - 'moon-8k.jpg', - '8k_mercury.jpg', '8k_venus_surface.jpg', - '8k_mars.jpg', '8k_saturn.jpg', - '8k_saturn_ring_alpha.png', - '2k_uranus.jpg', '2k_neptune.jpg', - '8k_sun.jpg', '1_earth_16k.jpg', - 'clouds.jpg'], - ['0D66DC62768C43D763D3288CE67128AAED27715B11B0529162DC4117F710E26F', - '5CF740C72287AF7B3ACCF080C3951944ADCB1617083B918537D08CBD9F2C5465', - 'DF443F3E20C7724803690A350D9F6FDB36AD8EBC011B0345FB519A8B321F680A', - '34CE9AD183D7C7B11E2F682D7EBB84C803E661BE09E01ADB887175AE60C58156', - '5DF6A384E407BD0D5F18176B7DB96AAE1EEA3CFCFE570DDCE0D34B4F0E493668', - '045E30B2ABFEAE6318C2CF955040C4A37E6DE595ACE809CE6766D397C0EE205D', - '7397A6C2CE0348E148C66EBEFE078467DDB9D0370FF5E63434D0451477624839', - '5C8BD885AE3571C6BA2CD34B3446B9C6D767E314BF0EE8C1D5C147CADD388FC3', - '9BC21A50577ED8AC734CDA91058724C7A741C19427AA276224CE349351432C5B', - '4CC52149924ABC6AE507D63032F994E1D42A55CB82C09E002D1A567FF66C23EE', - '0D39A4A490C87C3EDABE00A3881A29BB3418364178C79C534FE0986E97E09853', - 'F1F826933C9FF87D64ECF0518D6256B8ED990B003722794F67E96E3D2B876AE4', - 'D15239D46F82D3EA13D2B260B5B29B2A382F42F2916DAE0694D0387B1204A09D', - 'CB42EA82709741D28B0AF44D8B283CBC6DBD0C521A7F0E1E1E010ADE00977DF6', - 'F22B1CFB306DDCE72A7E3B628668A0175B745038CE6268557CB2F7F1BDF98B9D', - '7DD1DAC926101B5D7B7F2E952E53ACF209421B5CCE57C03168BCE0AAD675998A', - '85043336E023C4C9394CFD6D48D257A5564B4F895BFCEC01C70E4898CC77F003'], - doc="Download textures for fury" - ) + [ + "1_earth_8k.jpg", + "2_no_clouds_8k.jpg", + "5_night_8k.jpg", + "earth.ppm", + "jupiter.jpg", + "masonry.bmp", + "moon_8k.jpg", + "8k_mercury.jpg", + "8k_venus_surface.jpg", + "8k_mars.jpg", + "8k_saturn.jpg", + "8k_saturn_ring_alpha.png", + "2k_uranus.jpg", + "2k_neptune.jpg", + "8k_sun.jpg", + "1_earth_16k.jpg", + "clouds.jpg", + ], + [ + "1_earth_8k.jpg", + "2_no_clouds_8k.jpg", + "5_night_8k.jpg", + "earth.ppm", + "jupiter.jpg", + "masonry.bmp", + "moon-8k.jpg", + "8k_mercury.jpg", + "8k_venus_surface.jpg", + "8k_mars.jpg", + "8k_saturn.jpg", + "8k_saturn_ring_alpha.png", + "2k_uranus.jpg", + "2k_neptune.jpg", + "8k_sun.jpg", + "1_earth_16k.jpg", + "clouds.jpg", + ], + [ + "0D66DC62768C43D763D3288CE67128AAED27715B11B0529162DC4117F710E26F", + "5CF740C72287AF7B3ACCF080C3951944ADCB1617083B918537D08CBD9F2C5465", + "DF443F3E20C7724803690A350D9F6FDB36AD8EBC011B0345FB519A8B321F680A", + "34CE9AD183D7C7B11E2F682D7EBB84C803E661BE09E01ADB887175AE60C58156", + "5DF6A384E407BD0D5F18176B7DB96AAE1EEA3CFCFE570DDCE0D34B4F0E493668", + "045E30B2ABFEAE6318C2CF955040C4A37E6DE595ACE809CE6766D397C0EE205D", + "7397A6C2CE0348E148C66EBEFE078467DDB9D0370FF5E63434D0451477624839", + "5C8BD885AE3571C6BA2CD34B3446B9C6D767E314BF0EE8C1D5C147CADD388FC3", + "9BC21A50577ED8AC734CDA91058724C7A741C19427AA276224CE349351432C5B", + "4CC52149924ABC6AE507D63032F994E1D42A55CB82C09E002D1A567FF66C23EE", + "0D39A4A490C87C3EDABE00A3881A29BB3418364178C79C534FE0986E97E09853", + "F1F826933C9FF87D64ECF0518D6256B8ED990B003722794F67E96E3D2B876AE4", + "D15239D46F82D3EA13D2B260B5B29B2A382F42F2916DAE0694D0387B1204A09D", + "CB42EA82709741D28B0AF44D8B283CBC6DBD0C521A7F0E1E1E010ADE00977DF6", + "F22B1CFB306DDCE72A7E3B628668A0175B745038CE6268557CB2F7F1BDF98B9D", + "7DD1DAC926101B5D7B7F2E952E53ACF209421B5CCE57C03168BCE0AAD675998A", + "85043336E023C4C9394CFD6D48D257A5564B4F895BFCEC01C70E4898CC77F003", + ], + doc="Download textures for fury", +) -def read_viz_cubemap(name, suffix_type=1, ext='.jpg'): +def read_viz_cubemap(name, suffix_type=1, ext=".jpg"): """Read specific cube map with specific suffix type and extension. Parameters @@ -604,24 +693,24 @@ def read_viz_cubemap(name, suffix_type=1, ext='.jpg'): # indexing number. For a correct creation and display of the skybox, # textures must be read in this order. suffix_types = { - 0: ['0', '1', '2', '3', '4', '5'], - 1: ['-px', '-nx', '-py', '-ny', '-pz', '-nz'], - 2: ['posx', 'negx', 'posy', 'negy', 'posz', 'negz'], - 3: ['right', 'left', 'top', 'bottom', 'front', 'back'] + 0: ["0", "1", "2", "3", "4", "5"], + 1: ["-px", "-nx", "-py", "-ny", "-pz", "-nz"], + 2: ["posx", "negx", "posy", "negy", "posz", "negz"], + 3: ["right", "left", "top", "bottom", "front", "back"], } if suffix_type in suffix_types: conv = suffix_types[suffix_type] else: - warnings.warn('read_viz_cubemap(): Invalid suffix_type.') + warnings.warn("read_viz_cubemap(): Invalid suffix_type.", stacklevel=2) return None cubemap_fnames = [] - folder = pjoin(fury_home, 'cubemaps') + folder = pjoin(fury_home, "cubemaps") for dir_conv in conv: cubemap_fnames.append(pjoin(folder, name + dir_conv + ext)) return cubemap_fnames -def read_viz_icons(style='icomoon', fname='infinity.png'): +def read_viz_icons(style="icomoon", fname="infinity.png"): """Read specific icon from specific style. Parameters @@ -638,12 +727,12 @@ def read_viz_icons(style='icomoon', fname='infinity.png'): Complete path of icon. """ - if not os.path.isdir(pjoin(fury_home, 'icons', style)): + if not os.path.isdir(pjoin(fury_home, "icons", style)): if style == "icomoon": fetch_viz_icons() elif style == "new_icons": fetch_viz_new_icons() - folder = pjoin(fury_home, 'icons', style) + folder = pjoin(fury_home, "icons", style) return pjoin(folder, fname) @@ -662,7 +751,7 @@ def read_viz_models(fname): Complete path of models. """ - folder = pjoin(fury_home, 'models') + folder = pjoin(fury_home, "models") return pjoin(folder, fname) @@ -681,7 +770,7 @@ def read_viz_textures(fname): Complete path of textures. """ - folder = pjoin(fury_home, 'textures') + folder = pjoin(fury_home, "textures") return pjoin(folder, fname) @@ -700,11 +789,11 @@ def read_viz_dmri(fname): Complete path of dMRI image. """ - folder = pjoin(fury_home, 'dmri') + folder = pjoin(fury_home, "dmri") return pjoin(folder, fname) -def read_viz_gltf(fname, mode='glTF'): +def read_viz_gltf(fname, mode="glTF"): """Read specific gltf sample. Parameters @@ -723,16 +812,16 @@ def read_viz_gltf(fname, mode='glTF'): Complete path of models. """ - folder = pjoin(fury_home, 'glTF') + folder = pjoin(fury_home, "glTF") model = pjoin(folder, fname) sample = pjoin(model, mode) if not os.path.exists(sample): - raise ValueError(f'Model {sample} does not exists.') + raise ValueError(f"Model {sample} does not exists.") for filename in os.listdir(sample): - if filename.endswith('.gltf') or filename.endswith('.glb'): + if filename.endswith(".gltf") or filename.endswith(".glb"): return pjoin(sample, filename) @@ -746,11 +835,11 @@ def list_gltf_sample_models(): https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0 """ - DATA_DIR = pjoin(dirname(__file__), 'files') - with open(pjoin(DATA_DIR, 'KhronosGltfSamples.json'), 'r') as f: + DATA_DIR = pjoin(dirname(__file__), "files") + with open(pjoin(DATA_DIR, "KhronosGltfSamples.json"), "r") as f: models = json.loads(f.read()) models = models.keys() - model_modes = [model.split('/')[0] for model in models] + model_modes = [model.split("/")[0] for model in models] model_names = [] for name in model_modes: @@ -758,13 +847,13 @@ def list_gltf_sample_models(): model_names.append(name) model_names = model_names[1:] # removing __comments__ - default_models = ['BoxTextured', 'Duck', 'CesiumMilkTruck', 'CesiumMan'] + default_models = ["BoxTextured", "Duck", "CesiumMilkTruck", "CesiumMan"] if not model_names: - print('Failed to get models list') + print("Failed to get models list") return None result = [model in model_names for model in default_models] for i, exist in enumerate(result): if not exist: - print(f'Default Model: {default_models[i]} not found!') + print(f"Default Model: {default_models[i]} not found!") return model_names diff --git a/fury/data/tests/test_fetcher.py b/fury/data/tests/test_fetcher.py index 10f9a099c..08af70da6 100644 --- a/fury/data/tests/test_fetcher.py +++ b/fury/data/tests/test_fetcher.py @@ -1,26 +1,26 @@ import json import os from os.path import join as pjoin -from urllib.request import urlopen import numpy.testing as npt from fury.data import fetch_gltf, list_gltf_sample_models, read_viz_gltf -if 'FURY_HOME' in os.environ: - fury_home = os.environ['FURY_HOME'] +if "FURY_HOME" in os.environ: + fury_home = os.environ["FURY_HOME"] else: - fury_home = pjoin(os.path.expanduser('~'), '.fury') + fury_home = pjoin(os.path.expanduser("~"), ".fury") -GLTF_DATA_URL = \ +GLTF_DATA_URL = ( "https://api.github.com/repos/KhronosGroup/glTF-Sample-Models/contents/2.0/" # noqa +) def tests_fetch_gltf(): - folder = pjoin(fury_home, 'glTF') - boxtex = pjoin(folder, 'BoxTextured') - boxtex = pjoin(boxtex, 'glTF') - models_list = ['BoxTextured', 'Box'] + folder = pjoin(fury_home, "glTF") + boxtex = pjoin(folder, "BoxTextured") + boxtex = pjoin(boxtex, "glTF") + models_list = ["BoxTextured", "Box"] if os.path.exists(boxtex): for path in os.listdir(boxtex): os.remove(pjoin(boxtex, path)) @@ -31,53 +31,53 @@ def tests_fetch_gltf(): results = [model in list_gltf for model in models_list] npt.assert_equal(results, [True, True]) - npt.assert_raises(ValueError, fetch_gltf, ['duck']) - npt.assert_raises(ValueError, fetch_gltf, ['Duck'], 'GLTF') + npt.assert_raises(ValueError, fetch_gltf, ["duck"]) + npt.assert_raises(ValueError, fetch_gltf, ["Duck"], "GLTF") fetch_gltf() list_gltf = os.listdir(folder) - default_list = ['BoxTextured', 'Duck', 'CesiumMilkTruck', 'CesiumMan'] + default_list = ["BoxTextured", "Duck", "CesiumMilkTruck", "CesiumMan"] results = [model in list_gltf for model in default_list] npt.assert_equal(results, [True, True, True, True]) items = os.listdir(boxtex) npt.assert_array_equal(len(items), 3) - filenames, path = fetch_gltf('Box', 'glTF-Binary') + filenames, path = fetch_gltf("Box", "glTF-Binary") npt.assert_equal(len(filenames), 1) npt.assert_equal(os.listdir(path), filenames) - gltf = pjoin(boxtex, 'BoxTextured.gltf') - with open(gltf, 'r') as f: + gltf = pjoin(boxtex, "BoxTextured.gltf") + with open(gltf, "r") as f: gltf = json.loads(f.read()) - validate_gltf = gltf.get('asset') - npt.assert_equal(validate_gltf['version'], str(2.0)) + validate_gltf = gltf.get("asset") + npt.assert_equal(validate_gltf["version"], str(2.0)) def test_list_gltf_sample_models(): fetch_names = list_gltf_sample_models() - default_list = ['BoxTextured', 'Duck', 'CesiumMilkTruck', 'CesiumMan'] + default_list = ["BoxTextured", "Duck", "CesiumMilkTruck", "CesiumMan"] result = [model in fetch_names for model in default_list] npt.assert_equal(result, [True, True, True, True]) 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') + gltf_dir = pjoin(fury_home, "glTF") + filenames, path = fetch_gltf("Box", "glTF-Binary") + filename = read_viz_gltf("Box", "glTF-Binary") npt.assert_equal(filename, pjoin(path, filenames[0])) - npt.assert_raises(ValueError, read_viz_gltf, 'FURY', 'glTF') + npt.assert_raises(ValueError, read_viz_gltf, "FURY", "glTF") - box_gltf = pjoin(gltf_dir, 'Box') + box_gltf = pjoin(gltf_dir, "Box") for path in os.listdir(box_gltf): mode = pjoin(box_gltf, path) for file in os.listdir(mode): os.remove(pjoin(mode, file)) os.rmdir(mode) - npt.assert_raises(ValueError, read_viz_gltf, 'Box') + npt.assert_raises(ValueError, read_viz_gltf, "Box") - filenames, path = fetch_gltf('Box') - out_path = read_viz_gltf('Box').split(os.sep) + filenames, path = fetch_gltf("Box") + out_path = read_viz_gltf("Box").split(os.sep) mode = out_path[-2:][0] - npt.assert_equal(mode, 'glTF') + npt.assert_equal(mode, "glTF") diff --git a/fury/decorators.py b/fury/decorators.py index a0085dbbb..4cb1ee2cf 100644 --- a/fury/decorators.py +++ b/fury/decorators.py @@ -1,13 +1,14 @@ """Decorators for FURY tests.""" + import platform import re import sys -skip_linux = is_linux = platform.system().lower() == 'linux' -skip_osx = is_osx = platform.system().lower() == 'darwin' -skip_win = is_win = platform.system().lower() == 'windows' +skip_linux = is_linux = platform.system().lower() == "linux" +skip_osx = is_osx = platform.system().lower() == "darwin" +skip_win = is_win = platform.system().lower() == "windows" is_py35 = sys.version_info.major == 3 and sys.version_info.minor == 5 -SKIP_RE = re.compile(r'(\s*>>>.*?)(\s*)#\s*skip\s+if\s+(.*)$') +SKIP_RE = re.compile(r"(\s*>>>.*?)(\s*)#\s*skip\s+if\s+(.*)$") def doctest_skip_parser(func): @@ -29,7 +30,7 @@ def doctest_skip_parser(func): >>> something """ - lines = func.__doc__.split('\n') + lines = func.__doc__.split("\n") new_lines = [] for line in lines: match = SKIP_RE.match(line) @@ -38,7 +39,7 @@ def doctest_skip_parser(func): continue code, space, expr = match.groups() if eval(expr, func.__globals__): - code = code + space + '# doctest: +SKIP' + code = code + space + "# doctest: +SKIP" new_lines.append(code) - func.__doc__ = '\n'.join(new_lines) + func.__doc__ = "\n".join(new_lines) return func diff --git a/fury/deprecator.py b/fury/deprecator.py index d01c6ba33..2ef576766 100644 --- a/fury/deprecator.py +++ b/fury/deprecator.py @@ -19,9 +19,9 @@ # 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') +packaging, have_pkg, _ = optional_package("setuptools.extern.packaging") -_LEADING_WHITE = re.compile(r'^(\s*)') +_LEADING_WHITE = re.compile(r"^(\s*)") class ExpiredDeprecationError(RuntimeError): @@ -50,7 +50,7 @@ def _ensure_cr(text): Ensures that ``text`` always ends with a carriage return """ - return text.rstrip() + '\n' + return text.rstrip() + "\n" def _add_dep_doc(old_doc, dep_doc): @@ -76,7 +76,9 @@ def _add_dep_doc(old_doc, dep_doc): old_doc = _ensure_cr(old_doc) old_lines = old_doc.splitlines() new_lines = [] - for line_no, line in enumerate(old_lines): + line_no = 0 + for line_no in range(len(old_lines)): + line = old_lines[line_no] if line.strip(): new_lines.append(line) else: @@ -84,10 +86,10 @@ def _add_dep_doc(old_doc, dep_doc): next_line = line_no + 1 if next_line >= len(old_lines): # nothing following first paragraph, just append message - return old_doc + '\n' + dep_doc + return old_doc + "\n" + dep_doc indent = _LEADING_WHITE.match(old_lines[next_line]).group() - dep_lines = [indent + L for L in [''] + dep_doc.splitlines() + ['']] - return '\n'.join(new_lines + dep_lines + old_lines[next_line:]) + '\n' + dep_lines = [indent + L for L in [""] + dep_doc.splitlines() + [""]] + return "\n".join(new_lines + dep_lines + old_lines[next_line:]) + "\n" def cmp_pkg_version(version_str, pkg_version_str=__version__): @@ -116,9 +118,8 @@ def cmp_pkg_version(version_str, pkg_version_str=__version__): """ version_cmp = packaging.version.parse if have_pkg else None - 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) + 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) raise ValueError(msg) elif version_cmp(version_str) > version_cmp(pkg_version_str): return 1 @@ -135,8 +136,8 @@ def is_bad_version(version_str, version_comparator=cmp_pkg_version): def deprecate_with_version( message, - since='', - until='', + since="", + until="", version_comparator=cmp_pkg_version, warn_class=DeprecationWarning, error_class=ExpiredDeprecationError, @@ -180,18 +181,17 @@ def deprecate_with_version( """ messages = [message] - if (since, until) != ('', ''): - messages.append('') + if (since, until) != ("", ""): + messages.append("") if since: - messages.append('* deprecated from version: ' + since) + messages.append("* deprecated from version: " + since) if until: messages.append( - '* {0} {1} as of version: {2}'.format( - 'Raises' if is_bad_version(until) - else 'Will raise', error_class, until + "* {0} {1} as of version: {2}".format( + "Raises" if is_bad_version(until) else "Will raise", error_class, until ) ) - message = '\n'.join(messages) + message = "\n".join(messages) def deprecator(func): @functools.wraps(func) @@ -201,8 +201,7 @@ def deprecated_func(*args, **kwargs): warnings.warn(message, warn_class, stacklevel=2) return func(*args, **kwargs) - deprecated_func.__doc__ = _add_dep_doc(deprecated_func.__doc__, - message) + deprecated_func.__doc__ = _add_dep_doc(deprecated_func.__doc__, message) return deprecated_func return deprecator @@ -211,13 +210,13 @@ def deprecated_func(*args, **kwargs): def deprecated_params( old_name, new_name=None, - since='', - until='', + since="", + until="", version_comparator=cmp_pkg_version, arg_in_kwargs=False, warn_class=ArgsDeprecationWarning, error_class=ExpiredDeprecationError, - alternative='', + alternative="", ): """Deprecate a *renamed* or *removed* function argument. @@ -317,19 +316,17 @@ def deprecated_params( if ( len( - set( - [ - len(old_name), - len(new_name), - len(since), - len(until), - len(arg_in_kwargs), - ] - ) + { + len(old_name), + len(new_name), + len(since), + len(until), + len(arg_in_kwargs), + } ) != 1 ): - raise ValueError('All parameters should have the same length') + raise ValueError("All parameters should have the same length") else: # To allow a uniform approach later on, wrap all arguments in lists. old_name = [old_name] @@ -344,7 +341,7 @@ def deprecator(function): positions = [None] * len(old_name) for i, (o_name, n_name, in_keywords) in enumerate( - zip(old_name, new_name, arg_in_kwargs) + zip(old_name, new_name, arg_in_kwargs, strict=False) ): # Determine the position of the argument. if in_keywords: @@ -355,7 +352,7 @@ def deprecator(function): # the only remaining possibility is that it should be caught # by some kind of **kwargs argument. msg = '"{}" was not specified in the function '.format(n_name) - msg += 'signature. If it was meant to be part of ' + msg += "signature. If it was meant to be part of " msg += '"**kwargs" then set "arg_in_kwargs" to "True"' raise TypeError(msg) @@ -372,31 +369,29 @@ def deprecator(function): # positional-only argument, varargs, varkwargs or some # unknown type: msg = 'cannot replace argument "{}" '.format(n_name) - msg += 'of kind {}.'.format(repr(param.kind)) + msg += "of kind {}.".format(repr(param.kind)) raise TypeError(msg) @functools.wraps(function) def wrapper(*args, **kwargs): - for i, (o_name, n_name) in enumerate(zip(old_name, new_name)): + for i, (o_name, n_name) in enumerate(zip(old_name, new_name, strict=False)): messages = [ '"{}" was deprecated'.format(o_name), ] - if (since[i], until[i]) != ('', ''): - messages.append('') + if (since[i], until[i]) != ("", ""): + messages.append("") if since[i]: - messages.append('* deprecated from version: ' + - str(since[i])) + messages.append("* deprecated from version: " + str(since[i])) if until[i]: messages.append( - '* {0} {1} as of version: {2}'.format( - 'Raises' if is_bad_version(until[i]) - else 'Will raise', + "* {0} {1} as of version: {2}".format( + "Raises" if is_bad_version(until[i]) else "Will raise", error_class, until[i], ) ) - messages.append('') - message = '\n'.join(messages) + messages.append("") + message = "\n".join(messages) # The only way to have oldkeyword inside the function is # that it is passed as kwarg because the oldkeyword @@ -411,7 +406,7 @@ def wrapper(*args, **kwargs): if newarg_in_args or newarg_in_kwargs: msg = 'cannot specify both "{}"'.format(o_name) - msg += ' (deprecated parameter) and ' + msg += " (deprecated parameter) and " msg += '"{}" (new parameter name).'.format(n_name) raise TypeError(msg) @@ -421,14 +416,11 @@ def wrapper(*args, **kwargs): kwargs[key] = value if n_name is not None: - message += '* Use argument "{}" instead.'.format( - n_name - ) + message += '* Use argument "{}" instead.'.format(n_name) elif alternative: - message += '* Use {} instead.'.format(alternative) + message += "* Use {} instead.".format(alternative) - if until[i] and is_bad_version(until[i], - version_comparator): + if until[i] and is_bad_version(until[i], version_comparator): raise error_class(message) warnings.warn(message, warn_class, stacklevel=2) @@ -436,9 +428,8 @@ def wrapper(*args, **kwargs): # positional argument. elif not n_name and positions[i] and len(args) > positions[i]: if alternative: - message += '* Use {} instead.'.format(alternative) - if until[i] and is_bad_version(until[i], - version_comparator): + message += "* Use {} instead.".format(alternative) + if until[i] and is_bad_version(until[i], version_comparator): raise error_class(message) warnings.warn(message, warn_class, stacklevel=2) diff --git a/fury/gltf.py b/fury/gltf.py index 569864f7b..844482a0a 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -20,15 +20,15 @@ from fury.lib import Camera, Matrix4x4, Texture, Transform, numpy_support comp_type = { - 5120: {'size': 1, 'dtype': np.byte}, - 5121: {'size': 1, 'dtype': np.ubyte}, - 5122: {'size': 2, 'dtype': np.short}, - 5123: {'size': 2, 'dtype': np.ushort}, - 5125: {'size': 4, 'dtype': np.uint}, - 5126: {'size': 4, 'dtype': np.float32}, + 5120: {"size": 1, "dtype": np.byte}, + 5121: {"size": 1, "dtype": np.ubyte}, + 5122: {"size": 2, "dtype": np.short}, + 5123: {"size": 2, "dtype": np.ushort}, + 5125: {"size": 4, "dtype": np.uint}, + 5126: {"size": 4, "dtype": np.float32}, } -acc_type = {'SCALAR': 1, 'VEC2': 2, 'VEC3': 3, 'VEC4': 4, 'MAT4': 16} +acc_type = {"SCALAR": 1, "VEC2": 2, "VEC3": 3, "VEC4": 4, "MAT4": 16} class glTF: @@ -43,13 +43,13 @@ def __init__(self, filename, apply_normals=False): If `True` applies normals to the mesh. """ - if filename in ['', None]: - raise IOError('Filename cannot be empty or None!') + if filename in ["", None]: + raise IOError("Filename cannot be empty or None!") name, extension = os.path.splitext(filename) - if extension == '.glb': - fname_gltf = f'{name}.gltf' + if extension == ".glb": + fname_gltf = f"{name}.gltf" if not os.path.exists(fname_gltf): glb2gltf(filename) filename = fname_gltf @@ -112,9 +112,9 @@ def actors(self): actor.SetUserTransform(_transform) if self.materials[i] is not None: - base_col_tex = self.materials[i]['baseColorTexture'] + base_col_tex = self.materials[i]["baseColorTexture"] actor.SetTexture(base_col_tex) - base_color = self.materials[i]['baseColor'] + base_color = self.materials[i]["baseColor"] actor.GetProperty().SetColor(tuple(base_color[:3])) self._actors.append(actor) @@ -138,12 +138,7 @@ 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 - ): + def transverse_node(self, nextnode_id, matrix, parent=None, is_joint=False): """Load mesh and generates transformation matrix. Parameters @@ -196,7 +191,7 @@ def transverse_node(self, self.bone_tranforms[nextnode_id] = next_matrix[:] if is_joint: - if not (nextnode_id in self.bone_tranforms): + if nextnode_id not in self.bone_tranforms: self.bone_tranforms[nextnode_id] = next_matrix[:] if node.mesh is not None: @@ -206,14 +201,10 @@ def transverse_node(self, if node.skin is not None: skin_id = node.skin joints, ibms = self.get_skin_data(skin_id) - for bone, ibm in zip(joints, ibms): + for bone, ibm in zip(joints, ibms, strict=False): 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, is_joint=True) if node.camera is not None: camera_id = node.camera @@ -237,7 +228,6 @@ def load_mesh(self, mesh_id, transform_mat, parent): primitives = self.gltf.meshes[mesh_id].primitives for primitive in primitives: - attributes = primitive.attributes vertices = self.get_acc_data(attributes.POSITION) @@ -248,8 +238,7 @@ def load_mesh(self, mesh_id, transform_mat, parent): if attributes.NORMAL is not None and self.apply_normals: normals = self.get_acc_data(attributes.NORMAL) - normals = transform.apply_transformation(normals, - transform_mat) + normals = transform.apply_transformation(normals, transform_mat) utils.set_polydata_normals(polydata, normals) if attributes.TEXCOORD_0 is not None: @@ -307,7 +296,7 @@ def get_acc_data(self, acc_id): acc_byte_offset = accessor.byteOffset count = accessor.count d_type = comp_type.get(accessor.componentType) - d_size = d_type['size'] + d_size = d_type["size"] a_type = acc_type.get(accessor.type) buffview = self.gltf.bufferViews[buffview_id] @@ -321,19 +310,11 @@ def get_acc_data(self, acc_id): total_byte_offset = byte_offset + acc_byte_offset buff_array = self.get_buff_array( - buff_id, d_type['dtype'], - byte_length, - total_byte_offset, - byte_stride + buff_id, d_type["dtype"], byte_length, total_byte_offset, byte_stride ) return buff_array[:, :a_type] - def get_buff_array(self, - buff_id, - d_type, - byte_length, - byte_offset, - byte_stride): + def get_buff_array(self, buff_id, d_type, byte_length, byte_offset, byte_stride): """Extract the mesh data from buffer. Parameters @@ -367,13 +348,14 @@ def get_buff_array(self, byte_stride = int(byte_stride / 4) try: - if (uri.startswith('data:application/octet-stream;base64') or - uri.startswith('data:application/gltf-buffer;base64')): - buff_data = uri.split(',')[1] + if uri.startswith("data:application/octet-stream;base64") or uri.startswith( + "data:application/gltf-buffer;base64" + ): + buff_data = uri.split(",")[1] buff_data = base64.b64decode(buff_data) - elif uri.endswith('.bin'): - with open(os.path.join(self.pwd, uri), 'rb') as f: + elif uri.endswith(".bin"): + with open(os.path.join(self.pwd, uri), "rb") as f: buff_data = f.read(-1) out_arr = np.frombuffer( @@ -384,7 +366,7 @@ def get_buff_array(self, return out_arr except IOError: - print('Failed to read ! Error in opening file:') + print("Failed to read ! Error in opening file:") def get_materials(self, mat_id): """Get the material data. @@ -409,7 +391,7 @@ def get_materials(self, mat_id): bct = pbr.baseColorTexture.index bct = self.get_texture(bct) colors = pbr.baseColorFactor - return {'baseColorTexture': bct, 'baseColor': colors} + return {"baseColorTexture": bct, "baseColor": colors} def get_texture(self, tex_id): """Read and convert image into vtk texture. @@ -433,13 +415,13 @@ def get_texture(self, tex_id): if file is None: mimetype = image.mimeType - if file is not None and file.startswith('data:image'): - buff_data = file.split(',')[1] + if file is not None and file.startswith("data:image"): + buff_data = file.split(",")[1] buff_data = base64.b64decode(buff_data) - extension = '.png' if file.startswith('data:image/png') else '.jpg' - image_path = os.path.join(self.pwd, str('b64texture' + extension)) - with open(image_path, 'wb') as image_file: + extension = ".png" if file.startswith("data:image/png") else ".jpg" + image_path = os.path.join(self.pwd, str("b64texture" + extension)) + with open(image_path, "wb") as image_file: image_file.write(buff_data) elif bv_index is not None: @@ -448,12 +430,12 @@ def get_texture(self, tex_id): bo = bv.byteOffset bl = bv.byteLength uri = self.gltf.buffers[buffer].uri - with open(os.path.join(self.pwd, uri), 'rb') as f: + with open(os.path.join(self.pwd, uri), "rb") as f: f.seek(bo) img_binary = f.read(bl) - extension = '.png' if mimetype == 'images/png' else '.jpg' - image_path = os.path.join(self.pwd, str('bvtexture' + extension)) - with open(image_path, 'wb') as image_file: + extension = ".png" if mimetype == "images/png" else ".jpg" + image_path = os.path.join(self.pwd, str("bvtexture" + extension)) + with open(image_path, "wb") as image_file: image_file.write(img_binary) else: @@ -487,7 +469,7 @@ def load_camera(self, camera_id, transform_mat): new_position = transform.apply_transformation(position, transform_mat) vtk_cam.SetPosition(tuple(new_position[0])) - if camera.type == 'orthographic': + if camera.type == "orthographic": orthographic = camera.orthographic vtk_cam.ParallelProjectionOn() zfar = orthographic.zfar @@ -499,9 +481,7 @@ def load_camera(self, camera_id, transform_mat): zfar = perspective.zfar if perspective.zfar else 1000.0 znear = perspective.znear vtk_cam.SetClippingRange(znear, zfar) - angle = (perspective.yfov * 180 / np.pi - if perspective.yfov else 30.0 - ) + angle = perspective.yfov * 180 / np.pi if perspective.yfov else 30.0 vtk_cam.SetViewAngle(angle) if perspective.aspectRatio: vtk_cam.SetExplicitAspectRatio(perspective.aspectRatio) @@ -521,8 +501,8 @@ def transverse_channels(self, animation: gltflib.Animation, count: int): """ name = animation.name if name is None: - name = str(f'anim_{count}') - anim_channel = dict() # type: Dict[int, np.ndarray] + name = str(f"anim_{count}") + anim_channel = {} # type: Dict[int, np.ndarray] for channel in animation.channels: sampler = animation.samplers[channel.sampler] @@ -536,11 +516,7 @@ def transverse_channels(self, animation: gltflib.Animation, count: int): anim_channel[node_id] = sampler_data self.animation_channels[name] = anim_channel - def get_sampler_data(self, - sampler: gltflib.Sampler, - node_id: int, - transform_type - ): + def get_sampler_data(self, sampler: gltflib.Sampler, node_id: int, transform_type): """Get the animation and transformation data from sampler. Parameters @@ -564,11 +540,11 @@ def get_sampler_data(self, interpolation = sampler.interpolation return { - 'node': node_id, - 'input': time_array, - 'output': transform_array, - 'interpolation': interpolation, - 'property': transform_type, + "node": node_id, + "input": time_array, + "output": transform_array, + "interpolation": interpolation, + "property": transform_type, } def get_matrix_from_sampler( @@ -592,14 +568,14 @@ def get_matrix_from_sampler( time_array = self.get_acc_data(sampler.input) tran_array = self.get_acc_data(sampler.output) - if prop == 'weights': + if prop == "weights": tran_array = tran_array.reshape( -1, ) tran_matrix = [] if node in anim_channel: - prev_arr = anim_channel[node]['matrix'] + prev_arr = anim_channel[node]["matrix"] else: prev_arr = [np.identity(4) for i in range(len(tran_array))] @@ -609,14 +585,14 @@ def get_matrix_from_sampler( tran_matrix.append(np.dot(prev_arr[i], temp)) else: tran_matrix.append(temp) - data = {'timestamps': time_array, 'matrix': tran_matrix} + data = {"timestamps": time_array, "matrix": tran_matrix} self.sampler_matrices[node] = data return data def get_morph_data(self, target, mesh_id): weights_array = self.gltf.meshes[mesh_id].weights - if target.get('POSITION') is not None: - morphed_data = self.get_acc_data(target.get('POSITION')) + if target.get("POSITION") is not None: + morphed_data = self.get_acc_data(target.get("POSITION")) self.morph_weights.append(weights_array) return morphed_data @@ -659,11 +635,11 @@ def generate_tmatrix(self, transf, prop): ransformation matrix of shape (4, 4) with respective transforms. """ - if prop == 'translation': + if prop == "translation": matrix = transform.translate(transf) - elif prop == 'rotation': + elif prop == "rotation": matrix = transform.rotate(transf) - elif prop == 'scale': + elif prop == "scale": matrix = transform.scale(transf) else: matrix = transf @@ -675,7 +651,7 @@ def transverse_animations( bone_id, timestamp, joint_matrices, - parent_bone_deform=np.identity(4), + parent_bone_deform=None, ): """Calculate skinning matrix (Joint Matrices) and transform bone for each animation. @@ -695,7 +671,10 @@ def transverse_animations( (default=np.identity(4)) """ - deform = animation.get_value('transform', timestamp) + if parent_bone_deform is None: + parent_bone_deform = np.identity(4) + + deform = animation.get_value("transform", timestamp) new_deform = np.dot(parent_bone_deform, deform) ibm = self.ibms[bone_id].T @@ -715,7 +694,7 @@ def transverse_animations( if node.children: c_animations = animation.child_animations c_bones = node.children - for c_anim, c_bone in zip(c_animations, c_bones): + for c_anim, c_bone in zip(c_animations, c_bones, strict=False): self.transverse_animations( c_anim, c_bone, timestamp, joint_matrices, new_deform ) @@ -743,16 +722,10 @@ 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_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, i) actor_transf = self.transformations[i] vertex[:] = transform.apply_transformation(vertex, actor_transf) utils.update_actor(self._actors[i]) @@ -816,11 +789,7 @@ def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): return clone - def transverse_bones(self, - bone_id, - channel_name, - parent_animation: Animation - ): + def transverse_bones(self, bone_id, channel_name, parent_animation: Animation): """Loop over the bones and add child bone animation to their parent animation. @@ -843,12 +812,12 @@ def transverse_bones(self, orig_transform = np.identity(4) if bone_id in self.animation_channels[channel_name]: transforms = self.animation_channels[channel_name][bone_id] - timestamps = transforms['timestamps'] - metrices = transforms['matrix'] - for time, matrix in zip(timestamps, metrices): - animation.set_keyframe('transform', time[0], matrix) + timestamps = transforms["timestamps"] + metrices = transforms["matrix"] + for time, matrix in zip(timestamps, metrices, strict=False): + animation.set_keyframe("transform", time[0], matrix) else: - animation.set_keyframe('transform', 0.0, orig_transform) + animation.set_keyframe("transform", 0.0, orig_transform) parent_animation.add(animation) if node.children: @@ -865,8 +834,7 @@ def skin_animation(self): """ root_animations = {} - self._vertices = [utils.vertices_from_actor(act) - for act in self.actors()] + self._vertices = [utils.vertices_from_actor(act) for act in self.actors()] self._vcopy = [np.copy(vert) for vert in self._vertices] for name in self.animation_channels.keys(): root_animation = Animation() @@ -916,12 +884,9 @@ def update_morph(self, animation): animation.update_animation() timestamp = animation.current_timestamp for i, vertex in enumerate(self._vertices): - weights = animation.child_animations[0].get_value('morph', - timestamp) + weights = animation.child_animations[0].get_value("morph", timestamp) vertex[:] = self.apply_morph_vertices(self._vcopy[i], weights, i) - vertex[:] = transform.apply_transformation(vertex, - self.transformations[i] - ) + vertex[:] = transform.apply_transformation(vertex, self.transformations[i]) utils.update_actor(self._actors[i]) utils.compute_bounds(self._actors[i]) @@ -959,8 +924,7 @@ def morph_animation(self): """ animations = {} - self._vertices = [utils.vertices_from_actor(act) - for act in self.actors()] + self._vertices = [utils.vertices_from_actor(act) for act in self.actors()] self._vcopy = [np.copy(vert) for vert in self._vertices] for name, data in self.animation_channels.items(): @@ -969,12 +933,12 @@ def morph_animation(self): for i, transforms in enumerate(data.values()): weights = self.morph_weights[i] animation = Animation() - timestamps = transforms['timestamps'] - metrices = transforms['matrix'] + timestamps = transforms["timestamps"] + metrices = transforms["matrix"] metrices = np.array(metrices).reshape(-1, len(weights)) - for time, weights in zip(timestamps, metrices): - animation.set_keyframe('morph', time[0], weights) + for time, weights in zip(timestamps, metrices, strict=False): + animation.set_keyframe("morph", time[0], weights) root_animation.add(animation) root_animation.add_actor(self._actors) @@ -992,47 +956,45 @@ def get_animations(self): """ actors = self.actors() interpolators = { - 'LINEAR': linear_interpolator, - 'STEP': step_interpolator, - 'CUBICSPLINE': tan_cubic_spline_interpolator, + "LINEAR": linear_interpolator, + "STEP": step_interpolator, + "CUBICSPLINE": tan_cubic_spline_interpolator, } rotation_interpolators = { - 'LINEAR': slerp, - 'STEP': step_interpolator, - 'CUBICSPLINE': tan_cubic_spline_interpolator, + "LINEAR": slerp, + "STEP": step_interpolator, + "CUBICSPLINE": tan_cubic_spline_interpolator, } animations = [] for transforms in self.node_transform: - target_node = transforms['node'] + target_node = transforms["node"] for i, nodes in enumerate(self.nodes): animation = Animation() transform_mat = self.transformations[i] - position, rot, scale = transform.transform_from_matrix( - transform_mat - ) - animation.set_keyframe('position', 0.0, position) + position, rot, scale = transform.transform_from_matrix(transform_mat) + animation.set_keyframe("position", 0.0, position) if target_node in nodes: animation.add_actor(actors[i]) - timestamp = transforms['input'] - node_transform = transforms['output'] - prop = transforms['property'] + timestamp = transforms["input"] + node_transform = transforms["output"] + prop = transforms["property"] - interpolation_type = transforms['interpolation'] + interpolation_type = transforms["interpolation"] interpolator = interpolators.get(interpolation_type) rot_interp = rotation_interpolators.get(interpolation_type) timeshape = timestamp.shape transhape = node_transform.shape - if transforms['interpolation'] == 'CUBICSPLINE': + if transforms["interpolation"] == "CUBICSPLINE": node_transform = node_transform.reshape( (timeshape[0], -1, transhape[1]) ) - for time, trs in zip(timestamp, node_transform): + for time, trs in zip(timestamp, node_transform, strict=False): in_tan, out_tan = None, None if trs.ndim == 2: cubicspline = trs @@ -1040,28 +1002,19 @@ def get_animations(self): trs = cubicspline[1] out_tan = cubicspline[2] - if prop == 'rotation': + if prop == "rotation": animation.set_rotation( - time[0], - trs, - in_tangent=in_tan, - out_tangent=out_tan + time[0], trs, in_tangent=in_tan, out_tangent=out_tan ) animation.set_rotation_interpolator(rot_interp) - if prop == 'translation': + if prop == "translation": animation.set_position( - time[0], - trs, - in_tangent=in_tan, - out_tangent=out_tan + time[0], trs, in_tangent=in_tan, out_tangent=out_tan ) animation.set_position_interpolator(interpolator) - if prop == 'scale': + if prop == "scale": animation.set_scale( - time[0], - trs, - in_tangent=in_tan, - out_tangent=out_tan + time[0], trs, in_tangent=in_tan, out_tangent=out_tan ) animation.set_scale_interpolator(interpolator) else: @@ -1086,7 +1039,7 @@ def main_animation(self): return main_animation -def export_scene(scene, filename='default.gltf'): +def export_scene(scene, filename="default.gltf"): """Generate gltf from FURY scene. Parameters @@ -1100,10 +1053,10 @@ def export_scene(scene, filename='default.gltf'): gltf_obj = gltflib.GLTF2() name, extension = os.path.splitext(filename) - if extension not in ['.gltf', '.glb']: - raise IOError('Filename should be .gltf or .glb') + if extension not in [".gltf", ".glb"]: + raise IOError("Filename should be .gltf or .glb") - buffer_file = open(f'{name}.bin', 'wb') + buffer_file = open(f"{name}.bin", "wb") primitives = [] buffer_size = 0 bview_count = 0 @@ -1118,7 +1071,7 @@ def export_scene(scene, filename='default.gltf'): buffer_file.close() write_mesh(gltf_obj, primitives) - write_buffer(gltf_obj, size, f'{name}.bin') + write_buffer(gltf_obj, size, f"{name}.bin") camera = scene.camera() cam_id = None if camera: @@ -1127,9 +1080,9 @@ def export_scene(scene, filename='default.gltf'): write_node(gltf_obj, mesh_id=0, camera_id=cam_id) write_scene(gltf_obj, [0]) - gltf_obj.save(f'{name}.gltf') - if extension == '.glb': - gltf2glb(f'{name}.gltf', destination=filename) + gltf_obj.save(f"{name}.gltf") + if extension == ".glb": + gltf2glb(f"{name}.gltf", destination=filename) def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): @@ -1194,16 +1147,11 @@ def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): atype = acc_type.get(gltflib.SCALAR) indices = indices.astype(np.ushort) - blength = len(indices) * ctype['size'] + blength = len(indices) * ctype["size"] buff_file.write(indices.tobytes()) write_bufferview(gltf, 0, byteoffset, blength) write_accessor( - gltf, - count, - 0, - gltflib.UNSIGNED_SHORT, - len(indices), - gltflib.SCALAR + gltf, count, 0, gltflib.UNSIGNED_SHORT, len(indices), gltflib.SCALAR ) byteoffset += blength index = count @@ -1216,8 +1164,8 @@ def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): ctype = comp_type.get(gltflib.FLOAT) atype = acc_type.get(gltflib.VEC3) - vertices = vertices.reshape((-1,)).astype(ctype['dtype']) - blength = len(vertices) * ctype['size'] + vertices = vertices.reshape((-1,)).astype(ctype["dtype"]) + blength = len(vertices) * ctype["size"] buff_file.write(vertices.tobytes()) write_bufferview(gltf, 0, byteoffset, blength) write_accessor( @@ -1242,7 +1190,7 @@ def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): atype = acc_type.get(gltflib.VEC3) normals = normals.reshape((-1,)) - blength = len(normals) * ctype['size'] + blength = len(normals) * ctype["size"] buff_file.write(normals.tobytes()) write_bufferview(gltf, 0, byteoffset, blength) write_accessor( @@ -1266,8 +1214,8 @@ def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): ctype = comp_type.get(gltflib.FLOAT) atype = acc_type.get(gltflib.VEC2) - tcoords = tcoords.reshape((-1,)).astype(ctype['dtype']) - blength = len(tcoords) * ctype['size'] + tcoords = tcoords.reshape((-1,)).astype(ctype["dtype"]) + blength = len(tcoords) * ctype["size"] buff_file.write(tcoords.tobytes()) write_bufferview(gltf, 0, byteoffset, blength) write_accessor( @@ -1283,7 +1231,7 @@ def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): np_im = np.reshape(np_im, (rows, cols, -1)) img = Image.fromarray(np_im) - image_path = f'{name}BaseColorTexture.png' + image_path = f"{name}BaseColorTexture.png" img.save(image_path) write_material(gltf, 0, image_path) @@ -1294,8 +1242,8 @@ def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): shape = colors.shape[0] colors = np.concatenate((colors, np.full((shape, 1), 255.0)), axis=1) colors = colors / 255 - colors = colors.reshape((-1,)).astype(ctype['dtype']) - blength = len(colors) * ctype['size'] + colors = colors.reshape((-1,)).astype(ctype["dtype"]) + blength = len(colors) * ctype["size"] buff_file.write(colors.tobytes()) write_bufferview(gltf, 0, byteoffset, blength) write_accessor(gltf, count, 0, gltflib.FLOAT, shape, gltflib.VEC4) @@ -1376,7 +1324,7 @@ def write_camera(gltf, camera): orthographic = camera.GetParallelProjection() cam = gltflib.Camera() if orthographic: - cam.type = 'orthographic' + cam.type = "orthographic" else: clip_range = camera.GetClippingRange() angle = camera.GetViewAngle() @@ -1386,7 +1334,7 @@ def write_camera(gltf, camera): pers.aspectRatio = aspect_ratio pers.znear, pers.zfar = clip_range pers.yfov = angle * np.pi / 180 - cam.type = 'perspective' + cam.type = "perspective" cam.perspective = pers gltf.cameras.append(cam) @@ -1462,14 +1410,7 @@ def write_material(gltf, basecolortexture: int, uri: str): 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. diff --git a/fury/interactor.py b/fury/interactor.py index 26fe64c05..399f44992 100644 --- a/fury/interactor.py +++ b/fury/interactor.py @@ -101,9 +101,9 @@ def __init__(self): self.history = deque(maxlen=10) # Events history. self.selected_props = { - 'left_button': set(), - 'right_button': set(), - 'middle_button': set(), + "left_button": set(), + "right_button": set(), + "middle_button": set(), } def add_active_prop(self, prop): @@ -117,10 +117,7 @@ def get_prop_at_event_position(self): # TODO: return a list of items (i.e. each level of the assembly path). event_pos = self.GetInteractor().GetEventPosition() - self.picker.Pick(event_pos[0], - event_pos[1], - 0, - self.GetCurrentRenderer()) + self.picker.Pick(event_pos[0], event_pos[1], 0, self.GetCurrentRenderer()) path = self.picker.GetPath() if path is None: @@ -144,34 +141,34 @@ def _process_event(self, obj, evt): self.event.update(evt, self.GetInteractor()) self.history.append( { - 'event': evt, - 'pos': self.event.position, + "event": evt, + "pos": self.event.position, } ) - if evt == 'LeftButtonPressEvent': + if evt == "LeftButtonPressEvent": self.on_left_button_down(obj, evt) - elif evt == 'LeftButtonReleaseEvent': + elif evt == "LeftButtonReleaseEvent": self.on_left_button_up(obj, evt) - elif evt == 'RightButtonPressEvent': + elif evt == "RightButtonPressEvent": self.on_right_button_down(obj, evt) - elif evt == 'RightButtonReleaseEvent': + elif evt == "RightButtonReleaseEvent": self.on_right_button_up(obj, evt) - elif evt == 'MiddleButtonPressEvent': + elif evt == "MiddleButtonPressEvent": self.on_middle_button_down(obj, evt) - elif evt == 'MiddleButtonReleaseEvent': + elif evt == "MiddleButtonReleaseEvent": self.on_middle_button_up(obj, evt) - elif evt == 'MouseMoveEvent': + elif evt == "MouseMoveEvent": self.on_mouse_move(obj, evt) - elif evt == 'CharEvent': + elif evt == "CharEvent": self.on_char(obj, evt) - elif evt == 'KeyPressEvent': + elif evt == "KeyPressEvent": self.on_key_press(obj, evt) - elif evt == 'KeyReleaseEvent': + elif evt == "KeyReleaseEvent": self.on_key_release(obj, evt) - elif evt == 'MouseWheelForwardEvent': + elif evt == "MouseWheelForwardEvent": self.on_mouse_wheel_forward(obj, evt) - elif evt == 'MouseWheelBackwardEvent': + elif evt == "MouseWheelBackwardEvent": self.on_mouse_wheel_backward(obj, evt) self.event.reset() # Event fully processed. @@ -180,18 +177,16 @@ def _button_clicked(self, button, last_event=-1, before_last_event=-2): if len(self.history) < abs(before_last_event): return False - if self.history[last_event]['event'] != button + 'ButtonReleaseEvent': + if self.history[last_event]["event"] != button + "ButtonReleaseEvent": return False - if (self.history[before_last_event]['event'] != - button + 'ButtonPressEvent'): + if self.history[before_last_event]["event"] != button + "ButtonPressEvent": return False 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, -3, -4)): return False return True @@ -200,7 +195,7 @@ def on_left_button_down(self, _obj, evt): self.left_button_down = True prop = self.get_prop_at_event_position() if prop is not None: - self.selected_props['left_button'].add(prop) + self.selected_props["left_button"].add(prop) self.propagate_event(evt, prop) if not self.event.abort_flag: @@ -208,21 +203,21 @@ def on_left_button_down(self, _obj, evt): def on_left_button_up(self, _obj, evt): self.left_button_down = False - self.propagate_event(evt, *self.selected_props['left_button']) - self.selected_props['left_button'].clear() + self.propagate_event(evt, *self.selected_props["left_button"]) + self.selected_props["left_button"].clear() self.trackball_camera.OnLeftButtonUp() prop = self.get_prop_at_event_position() - if self._button_double_clicked('Left'): - self.propagate_event('LeftButtonDoubleClickEvent', prop) + if self._button_double_clicked("Left"): + self.propagate_event("LeftButtonDoubleClickEvent", prop) self.history.clear() def on_right_button_down(self, _obj, evt): self.right_button_down = True prop = self.get_prop_at_event_position() if prop is not None: - self.selected_props['right_button'].add(prop) + self.selected_props["right_button"].add(prop) self.propagate_event(evt, prop) if not self.event.abort_flag: @@ -230,20 +225,20 @@ def on_right_button_down(self, _obj, evt): def on_right_button_up(self, _obj, evt): self.right_button_down = False - self.propagate_event(evt, *self.selected_props['right_button']) - self.selected_props['right_button'].clear() + self.propagate_event(evt, *self.selected_props["right_button"]) + self.selected_props["right_button"].clear() self.trackball_camera.OnRightButtonUp() - if self._button_double_clicked('Right'): + if self._button_double_clicked("Right"): prop = self.get_prop_at_event_position() - self.propagate_event('RightButtonDoubleClickEvent', prop) + self.propagate_event("RightButtonDoubleClickEvent", prop) self.history.clear() def on_middle_button_down(self, _obj, evt): self.middle_button_down = True prop = self.get_prop_at_event_position() if prop is not None: - self.selected_props['middle_button'].add(prop) + self.selected_props["middle_button"].add(prop) self.propagate_event(evt, prop) if not self.event.abort_flag: @@ -251,13 +246,13 @@ def on_middle_button_down(self, _obj, evt): def on_middle_button_up(self, _obj, evt): self.middle_button_down = False - self.propagate_event(evt, *self.selected_props['middle_button']) - self.selected_props['middle_button'].clear() + self.propagate_event(evt, *self.selected_props["middle_button"]) + self.selected_props["middle_button"].clear() self.trackball_camera.OnMiddleButtonUp() - if self._button_double_clicked('Middle'): + if self._button_double_clicked("Middle"): prop = self.get_prop_at_event_position() - self.propagate_event('MiddleButtonDoubleClickEvent', prop) + self.propagate_event("MiddleButtonDoubleClickEvent", prop) self.history.clear() def on_mouse_move(self, _obj, evt): @@ -267,9 +262,9 @@ def on_mouse_move(self, _obj, evt): evt, *( self.active_props - | self.selected_props['left_button'] - | self.selected_props['right_button'] - | self.selected_props['middle_button'] + | self.selected_props["left_button"] + | self.selected_props["right_button"] + | self.selected_props["middle_button"] ), ) @@ -330,23 +325,23 @@ def SetInteractor(self, interactor): # # Note: Be sure that no observer has been manually added to the # `interactor` before setting the InteractorStyle. - interactor.RemoveObservers('TimerEvent') - interactor.RemoveObservers('EnterEvent') - interactor.RemoveObservers('LeaveEvent') - interactor.RemoveObservers('ExposeEvent') - interactor.RemoveObservers('ConfigureEvent') - interactor.RemoveObservers('CharEvent') - interactor.RemoveObservers('KeyPressEvent') - interactor.RemoveObservers('KeyReleaseEvent') - interactor.RemoveObservers('MouseMoveEvent') - interactor.RemoveObservers('LeftButtonPressEvent') - interactor.RemoveObservers('RightButtonPressEvent') - interactor.RemoveObservers('MiddleButtonPressEvent') - interactor.RemoveObservers('LeftButtonReleaseEvent') - interactor.RemoveObservers('RightButtonReleaseEvent') - interactor.RemoveObservers('MiddleButtonReleaseEvent') - interactor.RemoveObservers('MouseWheelForwardEvent') - interactor.RemoveObservers('MouseWheelBackwardEvent') + interactor.RemoveObservers("TimerEvent") + interactor.RemoveObservers("EnterEvent") + interactor.RemoveObservers("LeaveEvent") + interactor.RemoveObservers("ExposeEvent") + interactor.RemoveObservers("ConfigureEvent") + interactor.RemoveObservers("CharEvent") + interactor.RemoveObservers("KeyPressEvent") + interactor.RemoveObservers("KeyReleaseEvent") + interactor.RemoveObservers("MouseMoveEvent") + interactor.RemoveObservers("LeftButtonPressEvent") + interactor.RemoveObservers("RightButtonPressEvent") + interactor.RemoveObservers("MiddleButtonPressEvent") + interactor.RemoveObservers("LeftButtonReleaseEvent") + interactor.RemoveObservers("RightButtonReleaseEvent") + interactor.RemoveObservers("MiddleButtonReleaseEvent") + interactor.RemoveObservers("MouseWheelForwardEvent") + interactor.RemoveObservers("MouseWheelBackwardEvent") # This class is a `vtkClass` (instead of `object`), so `super()` # cannot be used. Also the method `SetInteractor` is not overridden in @@ -357,18 +352,18 @@ def SetInteractor(self, interactor): InteractorStyle.SetInteractor(self, interactor) # Keyboard events. - self.AddObserver('CharEvent', self._process_event) - self.AddObserver('KeyPressEvent', self._process_event) - self.AddObserver('KeyReleaseEvent', self._process_event) + self.AddObserver("CharEvent", self._process_event) + self.AddObserver("KeyPressEvent", self._process_event) + self.AddObserver("KeyReleaseEvent", self._process_event) # Mouse events. - self.AddObserver('MouseMoveEvent', self._process_event) - self.AddObserver('LeftButtonPressEvent', self._process_event) - self.AddObserver('LeftButtonReleaseEvent', self._process_event) - self.AddObserver('RightButtonPressEvent', self._process_event) - self.AddObserver('RightButtonReleaseEvent', self._process_event) - self.AddObserver('MiddleButtonPressEvent', self._process_event) - self.AddObserver('MiddleButtonReleaseEvent', self._process_event) + self.AddObserver("MouseMoveEvent", self._process_event) + self.AddObserver("LeftButtonPressEvent", self._process_event) + self.AddObserver("LeftButtonReleaseEvent", self._process_event) + self.AddObserver("RightButtonPressEvent", self._process_event) + self.AddObserver("RightButtonReleaseEvent", self._process_event) + self.AddObserver("MiddleButtonPressEvent", self._process_event) + self.AddObserver("MiddleButtonReleaseEvent", self._process_event) # Windows and special events. # TODO: we ever find them useful we could support them. @@ -381,14 +376,14 @@ def SetInteractor(self, interactor): # These observers need to be added directly to the interactor because # `vtkInteractorStyleUser` does not support wheel events prior 7.1. See # https://github.com/Kitware/VTK/commit/373258ed21f0915c425eddb996ce6ac13404be28 - interactor.AddObserver('MouseWheelForwardEvent', self._process_event) - interactor.AddObserver('MouseWheelBackwardEvent', self._process_event) + interactor.AddObserver("MouseWheelForwardEvent", self._process_event) + interactor.AddObserver("MouseWheelBackwardEvent", self._process_event) def force_render(self): """Causes the scene to refresh.""" self.GetInteractor().GetRenderWindow().Render() - def add_callback(self, prop, event_type, callback, priority=0, args=[]): + 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 @@ -399,6 +394,8 @@ def add_callback(self, prop, event_type, callback, priority=0, args=[]): priority : int """ + if args is None: + args = [] def _callback(_obj, event_name): # Update event information. @@ -406,8 +403,8 @@ def _callback(_obj, event_name): if interactor_ is not None: callback(self, prop, *args) else: - print('interactor is none') - print('event name is', event_name) + print("interactor is none") + print("event name is", event_name) # Dealing with custom events not defined in VTK. # Check whether the Event is predefined or not. @@ -415,10 +412,7 @@ def _callback(_obj, event_name): if event_type not in self.event2id: # If the event type was not previously defined, # then create an extra user defined event. - self.event2id[event_type] = ( - Command.UserEvent + - len(self.event2id) + - 1) + self.event2id[event_type] = Command.UserEvent + len(self.event2id) + 1 event_type = self.event2id[event_type] diff --git a/fury/io.py b/fury/io.py index d4f246757..828002c2d 100644 --- a/fury/io.py +++ b/fury/io.py @@ -51,7 +51,7 @@ def load_cubemap_texture(fnames, interpolate_on=True, mipmap_on=True): """ if len(fnames) != 6: - raise IOError('Expected 6 filenames, got {}'.format(len(fnames))) + raise IOError("Expected 6 filenames, got {}".format(len(fnames))) texture = Texture() texture.CubeMapOn() for idx, fn in enumerate(fnames): @@ -92,53 +92,50 @@ 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: image_name = os.path.basename(filename) - if len(image_name.split('.')) < 2: - raise IOError(f'{filename} is not a valid image URL') + if len(image_name.split(".")) < 2: + raise IOError(f"{filename} is not a valid image URL") urlretrieve(filename, image_name) filename = image_name if use_pillow: with Image.open(filename) as pil_image: - if pil_image.mode in ['P']: - pil_image = pil_image.convert('RGB') + if pil_image.mode in ["P"]: + pil_image = pil_image.convert("RGB") - if pil_image.mode in ['RGBA', 'RGB', 'L']: + if pil_image.mode in ["RGBA", "RGB", "L"]: image = np.asarray(pil_image) - elif pil_image.mode.startswith('I;16'): - raw = pil_image.tobytes('raw', pil_image.mode) - dtype = '>u2' if pil_image.mode.endswith('B') else ' 3: - raise IOError('Image Dimensions should be <=3') + raise IOError("Image Dimensions should be <=3") if isinstance(dpi, (float, int)): dpi = (dpi, dpi) d_writer = { - '.png': PNGWriter, - '.bmp': BMPWriter, - '.jpeg': JPEGWriter, - '.jpg': JPEGWriter, - '.tiff': TIFFWriter, - '.tif': TIFFWriter, + ".png": PNGWriter, + ".bmp": BMPWriter, + ".jpeg": JPEGWriter, + ".jpg": JPEGWriter, + ".tiff": TIFFWriter, + ".tif": TIFFWriter, } extension = os.path.splitext(os.path.basename(filename).lower())[1] if extension.lower() not in d_writer.keys(): raise IOError( - 'Impossible to save the file {0}: Unknown extension {1}'.format( + "Impossible to save the file {0}: Unknown extension {1}".format( filename, extension ) ) @@ -274,15 +271,16 @@ def save_image( im.save(filename, quality=compression_quality, dpi=dpi) else: warnings.warn( - UserWarning('DPI value is ignored while saving images via vtk.') - ) + UserWarning("DPI value is ignored while saving images via vtk."), + stacklevel=2, + ) if arr.ndim == 2: arr = arr[..., None] shape = arr.shape arr = np.flipud(arr) if extension.lower() in [ - '.png', + ".png", ]: arr = arr.astype(np.uint8) arr = arr.reshape((shape[1] * shape[0], shape[2])) @@ -304,16 +302,12 @@ def save_image( writer = d_writer.get(extension)() writer.SetFileName(filename) writer.SetInputData(vtk_data) - if extension.lower() in ['.jpg', '.jpeg']: + if extension.lower() in [".jpg", ".jpeg"]: writer.ProgressiveOn() writer.SetQuality(compression_quality) - if extension.lower() in ['.tif', '.tiff']: - compression_type = compression_type or 'nocompression' - l_compression = ['nocompression', - 'packbits', - 'jpeg', - 'deflate', - 'lzw'] + if extension.lower() in [".tif", ".tiff"]: + compression_type = compression_type or "nocompression" + l_compression = ["nocompression", "packbits", "jpeg", "deflate", "lzw"] if compression_type.lower() in l_compression: comp_id = l_compression.index(compression_type.lower()) @@ -341,20 +335,20 @@ def load_polydata(file_name): if not os.path.isfile(file_name): raise FileNotFoundError(file_name) - file_extension = file_name.split('.')[-1].lower() + file_extension = file_name.split(".")[-1].lower() poly_reader = { - 'vtk': PolyDataReader, - 'vtp': XMLPolyDataReader, - 'fib': PolyDataReader, - 'ply': PLYReader, - 'stl': STLReader, - 'xml': XMLPolyDataReader, + "vtk": PolyDataReader, + "vtp": XMLPolyDataReader, + "fib": PolyDataReader, + "ply": PLYReader, + "stl": STLReader, + "xml": XMLPolyDataReader, } if file_extension in poly_reader.keys(): reader = poly_reader.get(file_extension)() - elif file_extension == 'obj': + elif file_extension == "obj": # Special case, since there is two obj format reader = OBJReader() reader.SetFileName(file_name) @@ -362,7 +356,7 @@ def load_polydata(file_name): if reader.GetOutput().GetNumberOfCells() == 0: reader = MNIObjectReader() else: - raise IOError('.' + file_extension + ' is not supported by FURY') + raise IOError("." + file_extension + " is not supported by FURY") reader.SetFileName(file_name) reader.Update() @@ -383,34 +377,34 @@ def save_polydata(polydata, file_name, binary=False, color_array_name=None): """ # get file extension (type) - file_extension = file_name.split('.')[-1].lower() + file_extension = file_name.split(".")[-1].lower() poly_writer = { - 'vtk': PolyDataWriter, - 'vtp': XMLPolyDataWriter, - 'fib': PolyDataWriter, - 'ply': PLYWriter, - 'stl': STLWriter, - 'xml': XMLPolyDataWriter, + "vtk": PolyDataWriter, + "vtp": XMLPolyDataWriter, + "fib": PolyDataWriter, + "ply": PLYWriter, + "stl": STLWriter, + "xml": XMLPolyDataWriter, } if file_extension in poly_writer.keys(): writer = poly_writer.get(file_extension)() - elif file_extension == 'obj': + elif file_extension == "obj": # Special case, since there is two obj format - find_keyword = file_name.lower().split('.') - if 'mni' in find_keyword or 'mnc' in find_keyword: + find_keyword = file_name.lower().split(".") + if "mni" in find_keyword or "mnc" in find_keyword: writer = MNIObjectWriter() else: raise IOError( - 'Wavefront obj requires a scene \n' + "Wavefront obj requires a scene \n" " for MNI obj, use '.mni.obj' extension" ) else: - raise IOError('.' + file_extension + ' is not supported by FURY') + raise IOError("." + file_extension + " is not supported by FURY") writer.SetFileName(file_name) writer = set_input(writer, polydata) - if color_array_name is not None and file_extension == 'ply': + if color_array_name is not None and file_extension == "ply": writer.SetArrayName(color_array_name) if binary: @@ -456,14 +450,13 @@ 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]] if as_vtktype: with InTemporaryDirectory() as tdir: - tmp_img_path = os.path.join(tdir, f'{row}{col}.png') + 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 753fa380f..4294ead85 100644 --- a/fury/layout.py +++ b/fury/layout.py @@ -12,12 +12,11 @@ def apply(self, actors): """Position the actors according to a certain layout.""" positions = self.compute_positions(actors) - for a, pos in zip(actors, positions): - + for a, pos in zip(actors, positions, strict=False): if is_ui(a): a.position = (pos[0], pos[1]) else: - anchor = np.array(getattr(a, 'anchor', (0, 0, 0))) + anchor = np.array(getattr(a, "anchor", (0, 0, 0))) a.AddPosition(pos - (np.array(a.GetCenter()) + anchor)) def compute_positions(self, _actors): @@ -36,7 +35,7 @@ class GridLayout(Layout): def __init__( self, cell_padding=0, - cell_shape='rect', + cell_shape="rect", aspect_ratio=16 / 9.0, dim=None, position_offset=(0, 0, 0), @@ -88,17 +87,15 @@ def get_cells_shape(self, actors): The 2D shape (on the xy-plane) of every actors. """ - if self.cell_shape == 'rect': - bounding_box_sizes = np.asarray(list(map(self.compute_sizes, - actors))) + if self.cell_shape == "rect": + 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))) + elif self.cell_shape == "square": + 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': + elif self.cell_shape == "diagonal": # Size of every cell corresponds to the diagonal # of the largest bounding box. diagonals = [] @@ -113,9 +110,7 @@ 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 @@ -138,9 +133,7 @@ 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, self.aspect_ratio, self.dim) positions += self.position_offset return positions @@ -168,7 +161,7 @@ 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'): + def __init__(self, cell_padding=0, cell_shape="rect"): """Initialize the Horizontal layout. Parameters @@ -223,7 +216,7 @@ 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'): + def __init__(self, cell_padding=0, cell_shape="rect"): """Initialize the Vertical layout. Parameters @@ -277,7 +270,7 @@ 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'): + def __init__(self, direction="x+", cell_padding=0, cell_shape="rect"): """Initialize the X layout. Parameters @@ -301,11 +294,10 @@ def __init__(self, direction='x+', cell_padding=0, cell_shape='rect'): """ self.direction = direction.lower() - if self.direction not in ['x+', 'x-']: - raise ValueError(f'{direction} is not a valid direction') + 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 @@ -322,7 +314,7 @@ def get_cells_shape(self, actors): The 2D shape (on the xy-plane) of every actors. """ - if self.direction == 'x-': + if self.direction == "x-": actors = actors[::-1] return super().get_cells_shape(actors) @@ -344,14 +336,14 @@ def compute_positions(self, actors): The computed 3D coordinates of every actors. """ - if self.direction == 'x-': + if self.direction == "x-": actors = actors[::-1] return super().compute_positions(actors) def apply(self, actors): """Position the actors according to a certain layout.""" - if self.direction == 'x-': + if self.direction == "x-": actors = actors[::-1] return super().apply(actors) @@ -360,7 +352,7 @@ 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'): + def __init__(self, direction="y+", cell_padding=0, cell_shape="rect"): """Initialize the Y layout. Parameters @@ -384,11 +376,10 @@ def __init__(self, direction='y+', cell_padding=0, cell_shape='rect'): """ self.direction = direction.lower() - if self.direction not in ['y+', 'y-']: - raise ValueError(f'{direction} is not a valid direction') + 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 @@ -405,7 +396,7 @@ def get_cells_shape(self, actors): The 2D shape (on the xy-plane) of every actors. """ - if self.direction == 'y-': + if self.direction == "y-": actors = actors[::-1] return super().get_cells_shape(actors) @@ -427,14 +418,14 @@ def compute_positions(self, actors): The computed 3D coordinates of every actors. """ - if self.direction == 'y-': + if self.direction == "y-": actors = actors[::-1] return super().compute_positions(actors) def apply(self, actors): """Position the actors according to a certain layout.""" - if self.direction == 'y-': + if self.direction == "y-": actors = actors[::-1] return super().apply(actors) @@ -443,7 +434,7 @@ 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'): + def __init__(self, direction="z+", cell_padding=0, cell_shape="rect"): """Initialize the Z layout. Parameters @@ -467,11 +458,10 @@ def __init__(self, direction='z+', cell_padding=0, cell_shape='rect'): """ self.direction = direction.lower() - if self.direction not in ['z+', 'z-']: - raise ValueError(f'{direction} is not a valid direction') + 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 @@ -488,23 +478,20 @@ def get_cells_shape(self, actors): The shape (on the z-plane) of every actors. """ - if self.direction == 'z-': + if self.direction == "z-": 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))) + if self.cell_shape == "rect" or self.cell_shape == "square": + 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': + elif self.cell_shape == "diagonal": # Size of every cell corresponds to the diagonal # of the largest bounding box. 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 @@ -522,7 +509,7 @@ def compute_positions(self, actors): The computed 3D coordinates of every actors. """ - if self.direction == 'z-': + if self.direction == "z-": actors = actors[::-1] positions = [ @@ -540,7 +527,7 @@ def compute_positions(self, actors): def apply(self, actors): """Position the actors according to a certain layout.""" - if self.direction == 'z-': + if self.direction == "z-": actors = actors[::-1] return super().apply(actors) diff --git a/fury/material.py b/fury/material.py index ff317a380..22891395a 100644 --- a/fury/material.py +++ b/fury/material.py @@ -47,15 +47,23 @@ class __PBRParams: """ - def __init__(self, actor_properties, metallic, roughness, - anisotropy, anisotropy_rotation, coat_strength, - coat_roughness, base_ior, coat_ior): + def __init__( + self, + actor_properties, + metallic, + roughness, + anisotropy, + anisotropy_rotation, + coat_strength, + coat_roughness, + base_ior, + coat_ior, + ): self.__actor_properties = actor_properties self.__actor_properties.SetMetallic(metallic) self.__actor_properties.SetRoughness(roughness) self.__actor_properties.SetAnisotropy(anisotropy) - self.__actor_properties.SetAnisotropyRotation( - anisotropy_rotation) + self.__actor_properties.SetAnisotropyRotation(anisotropy_rotation) self.__actor_properties.SetCoatStrength(coat_strength) self.__actor_properties.SetCoatRoughness(coat_roughness) self.__actor_properties.SetBaseIOR(base_ior) @@ -126,9 +134,17 @@ def coat_ior(self, coat_ior): self.__actor_properties.SetCoatIOR(coat_ior) -def manifest_pbr(actor, metallic=0, roughness=.5, anisotropy=0, - anisotropy_rotation=0, coat_strength=0, coat_roughness=0, - base_ior=1.5, coat_ior=2): +def manifest_pbr( + actor, + metallic=0, + roughness=0.5, + anisotropy=0, + anisotropy_rotation=0, + coat_strength=0, + coat_roughness=0, + base_ior=1.5, + coat_ior=2, +): """Apply VTK's Physically Based Rendering properties to the selected actor. Parameters @@ -164,25 +180,48 @@ def manifest_pbr(actor, metallic=0, roughness=.5, anisotropy=0, prop = actor.GetProperty() try: prop.SetInterpolationToPBR() - pbr_params = __PBRParams(prop, metallic, roughness, anisotropy, - anisotropy_rotation, coat_strength, - coat_roughness, base_ior, coat_ior) + pbr_params = __PBRParams( + prop, + metallic, + roughness, + anisotropy, + anisotropy_rotation, + coat_strength, + coat_roughness, + base_ior, + coat_ior, + ) return pbr_params except AttributeError: warnings.warn( - 'PBR interpolation cannot be applied to this actor. The ' - 'material will not be applied.') + "PBR interpolation cannot be applied to this actor. The " + "material will not be applied.", + stacklevel=2, + ) return None except AttributeError: - warnings.warn('Actor does not have the attribute property. This ' - 'material will not be applied.') + warnings.warn( + "Actor does not have the attribute property. This " + "material will not be applied.", + stacklevel=2, + ) return None -def manifest_principled(actor, subsurface=0, metallic=0, specular=0, - specular_tint=0, roughness=0, anisotropic=0, - anisotropic_direction=[0, 1, .5], sheen=0, - sheen_tint=0, clearcoat=0, clearcoat_gloss=0): +def manifest_principled( + actor, + subsurface=0, + metallic=0, + specular=0, + specular_tint=0, + roughness=0, + anisotropic=0, + anisotropic_direction=None, + sheen=0, + sheen_tint=0, + clearcoat=0, + clearcoat_gloss=0, +): """Apply the Principled Shading properties to the selected actor. Parameters @@ -220,16 +259,24 @@ def manifest_principled(actor, subsurface=0, metallic=0, specular=0, Dictionary containing the Principled Shading parameters. """ + if anisotropic_direction is None: + anisotropic_direction = [0, 1, 0.5] + try: prop = actor.GetProperty() principled_params = { - 'subsurface': subsurface, 'metallic': metallic, - 'specular': specular, 'specular_tint': specular_tint, - 'roughness': roughness, 'anisotropic': anisotropic, - 'anisotropic_direction': anisotropic_direction, 'sheen': sheen, - 'sheen_tint': sheen_tint, 'clearcoat': clearcoat, - 'clearcoat_gloss': clearcoat_gloss + "subsurface": subsurface, + "metallic": metallic, + "specular": specular, + "specular_tint": specular_tint, + "roughness": roughness, + "anisotropic": anisotropic, + "anisotropic_direction": anisotropic_direction, + "sheen": sheen, + "sheen_tint": sheen_tint, + "clearcoat": clearcoat, + "clearcoat_gloss": clearcoat_gloss, } prop.SetSpecular(specular) @@ -237,34 +284,28 @@ def manifest_principled(actor, subsurface=0, metallic=0, specular=0, @calldata_type(VTK_OBJECT) def uniforms_callback(_caller, _event, calldata=None): if calldata is not None: + 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("sheen", principled_params["sheen"]) + calldata.SetUniformf("sheenTint", principled_params["sheen_tint"]) + calldata.SetUniformf("clearcoat", principled_params["clearcoat"]) 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('sheen', principled_params['sheen']) - calldata.SetUniformf( - 'sheenTint', principled_params['sheen_tint']) - calldata.SetUniformf( - 'clearcoat', principled_params['clearcoat']) - calldata.SetUniformf( - 'clearcoatGloss', principled_params['clearcoat_gloss']) + "clearcoatGloss", principled_params["clearcoat_gloss"] + ) calldata.SetUniform3f( - 'anisotropicDirection', principled_params[ - 'anisotropic_direction']) + "anisotropicDirection", principled_params["anisotropic_direction"] + ) add_shader_callback(actor, uniforms_callback) # Start of shader implementation # Adding required constants - pi = '#define PI 3.14159265359' + pi = "#define PI 3.14159265359" # Adding uniforms uniforms = """ @@ -284,112 +325,121 @@ def uniforms_callback(_caller, _event, calldata=None): # Importing functions in order # Importing utility functions - square = import_fury_shader(os.path.join('utils', 'square.glsl')) - pow5 = import_fury_shader(os.path.join('utils', 'pow5.glsl')) + square = import_fury_shader(os.path.join("utils", "square.glsl")) + pow5 = import_fury_shader(os.path.join("utils", "pow5.glsl")) # Importing utility function to update the tangent and bitangent # vectors given a direction of anisotropy update_tan_bitan = import_fury_shader( - os.path.join('utils', 'update_tan_bitan.glsl') + os.path.join("utils", "update_tan_bitan.glsl") ) # Importing color conversion gamma to linear space function gamma_to_linear = import_fury_shader( - os.path.join('lighting', 'gamma_to_linear.frag') + os.path.join("lighting", "gamma_to_linear.frag") ) # Importing color conversion linear to gamma space function linear_to_gamma = import_fury_shader( - os.path.join('lighting', 'linear_to_gamma.frag') + os.path.join("lighting", "linear_to_gamma.frag") ) # Importing linear-space CIE luminance tint approximation function cie_color_tint = import_fury_shader( - os.path.join('lighting', 'cie_color_tint.frag') + os.path.join("lighting", "cie_color_tint.frag") ) # Importing Schlick's weight approximation of the Fresnel equation schlick_weight = import_fury_shader( - os.path.join('lighting', 'schlick_weight.frag') + os.path.join("lighting", "schlick_weight.frag") ) # Importing Normal Distribution Function (NDF): Generalized # Trowbridge-Reitz with param gamma=1 (D_{GTR_1}) needed for the Clear # Coat lobe - gtr1 = import_fury_shader( - os.path.join('lighting', 'ndf', 'gtr1.frag') - ) + gtr1 = import_fury_shader(os.path.join("lighting", "ndf", "gtr1.frag")) # Importing Normal Distribution Function (NDF): Generalized # Trowbridge-Reitz with param gamma=2 (D_{GTR_2}) needed for the # Isotropic Specular lobe - gtr2 = import_fury_shader( - os.path.join('lighting', 'ndf', 'gtr2.frag') - ) + gtr2 = import_fury_shader(os.path.join("lighting", "ndf", "gtr2.frag")) # Importing Normal Distribution Function (NDF): Anisotropic form of the # Generalized Trowbridge-Reitz with param gamma=2 # (D_{GTR_2anisotropic}) needed for the respective Specular lobe gtr2_anisotropic = import_fury_shader( - os.path.join('lighting', 'ndf', 'gtr2_anisotropic.frag') + os.path.join("lighting", "ndf", "gtr2_anisotropic.frag") ) # 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 # for the respective Specular lobe smith_ggx_anisotropic = import_fury_shader( - os.path.join('lighting', 'gf', 'smith_ggx_anisotropic.frag') + os.path.join("lighting", "gf", "smith_ggx_anisotropic.frag") ) # Importing Principled components functions diffuse = import_fury_shader( - os.path.join('lighting', 'principled', 'diffuse.frag') + os.path.join("lighting", "principled", "diffuse.frag") ) subsurface = import_fury_shader( - os.path.join('lighting', 'principled', 'subsurface.frag') - ) - sheen = import_fury_shader( - os.path.join('lighting', 'principled', 'sheen.frag') + os.path.join("lighting", "principled", "subsurface.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') + os.path.join("lighting", "principled", "specular_isotropic.frag") ) specular_anisotropic = import_fury_shader( - os.path.join('lighting', 'principled', 'specular_anisotropic.frag') + os.path.join("lighting", "principled", "specular_anisotropic.frag") ) clearcoat = import_fury_shader( - os.path.join('lighting', 'principled', 'clearcoat.frag') + os.path.join("lighting", "principled", "clearcoat.frag") ) # Putting all the functions together before passing them to the actor - fs_dec = compose_shader([ - pi, uniforms, square, pow5, update_tan_bitan, gamma_to_linear, - linear_to_gamma, cie_color_tint, schlick_weight, gtr1, gtr2, - gtr2_anisotropic, smith_ggx, smith_ggx_anisotropic, diffuse, - subsurface, sheen, specular_isotropic, specular_anisotropic, - clearcoat - ]) + fs_dec = compose_shader( + [ + pi, + uniforms, + square, + pow5, + update_tan_bitan, + gamma_to_linear, + linear_to_gamma, + cie_color_tint, + schlick_weight, + gtr1, + gtr2, + gtr2_anisotropic, + smith_ggx, + smith_ggx_anisotropic, + diffuse, + subsurface, + sheen, + specular_isotropic, + specular_anisotropic, + clearcoat, + ] + ) # Adding shader functions to actor - shader_to_actor(actor, 'fragment', decl_code=fs_dec) + shader_to_actor(actor, "fragment", decl_code=fs_dec) # Start of the implementation code start_comment = "//Disney's Principled BRDF" # Preparing vectors and values - normal = 'vec3 normal = normalVCVSOutput;' + normal = "vec3 normal = normalVCVSOutput;" # VTK's default system is retroreflective, which means view = light - view = 'vec3 view = normalize(-vertexVC.xyz);' + view = "vec3 view = normalize(-vertexVC.xyz);" # Since VTK's default setup is retroreflective we only need to # calculate one single dot product - dot_n_v = 'float dotNV = clamp(dot(normal, view), 1e-5, 1);' + dot_n_v = "float dotNV = clamp(dot(normal, view), 1e-5, 1);" dot_n_v_validation = """ if(dotNV < 0) @@ -398,8 +448,8 @@ def uniforms_callback(_caller, _event, calldata=None): # To work with anisotropic distributions is necessary to have a tangent # and bitangent vector per point on the surface - tangent = 'vec3 tangent = vec3(.0);' - bitangent = 'vec3 bitangent = vec3(.0);' + tangent = "vec3 tangent = vec3(.0);" + bitangent = "vec3 bitangent = vec3(.0);" # The shader function updateTanBitan aligns tangents and bitangents # according to a direction of anisotropy update_aniso_vecs = """ @@ -407,18 +457,18 @@ def uniforms_callback(_caller, _event, calldata=None): """ # Calculating dot products with tangent and bitangent - dot_t_v = 'float dotTV = dot(tangent, view);' - dot_b_v = 'float dotBV = dot(bitangent, view);' + dot_t_v = "float dotTV = dot(tangent, view);" + dot_b_v = "float dotBV = dot(bitangent, view);" # Converting color to linear space - linear_color = 'vec3 linColor = gamma2Linear(diffuseColor);' + linear_color = "vec3 linColor = gamma2Linear(diffuseColor);" # Calculating linear-space CIE luminance tint approximation - tint = 'vec3 tint = calculateTint(linColor);' + tint = "vec3 tint = calculateTint(linColor);" # Since VTK's default setup is retroreflective we only need to # calculate one single Schlick's weight - fsw = 'float fsw = schlickWeight(dotNV);' + fsw = "float fsw = schlickWeight(dotNV);" # Calculating the diffuse coefficient diff_coeff = """ @@ -452,55 +502,89 @@ def uniforms_callback(_caller, _event, calldata=None): # Starting to put all together # Initializing the radiance vector - radiance = 'vec3 rad = (1 / PI) * linColor;' + radiance = "vec3 rad = (1 / PI) * linColor;" # Adding mix between the diffuse and the subsurface coefficients # controlled by the subsurface parameter - diff_subsurf_mix = 'rad *= mix(diffCoeff, subsurfCoeff, subsurface);' + diff_subsurf_mix = "rad *= mix(diffCoeff, subsurfCoeff, subsurface);" # Adding sheen radiance - sheen_add = 'rad += sheenRad;' + sheen_add = "rad += sheenRad;" # Balancing energy using metallic - metallic_balance = 'rad *= (1 - metallic);' + metallic_balance = "rad *= (1 - metallic);" # Adding specular radiance - specular_add = 'rad += specRad;' + specular_add = "rad += specRad;" # Adding clear coat coefficient - clearcoat_add = 'rad += coatCoeff;' + clearcoat_add = "rad += coatCoeff;" # Initializing the color vector using the final radiance and VTK's # additional information - color = 'vec3 color = rad * lightColor0;' + color = "vec3 color = rad * lightColor0;" # Converting color back to gamma space - gamma_color = 'color = linear2Gamma(color);' + gamma_color = "color = linear2Gamma(color);" # Clamping color values - color_clamp = 'color = clamp(color, vec3(0), vec3(1));' + color_clamp = "color = clamp(color, vec3(0), vec3(1));" # Fragment shader output - frag_output = 'fragOutput0 = vec4(color, opacity);' + frag_output = "fragOutput0 = vec4(color, opacity);" # Putting all the implementation together before passing it to the # actor - fs_impl = compose_shader([ - start_comment, normal, view, dot_n_v, dot_n_v_validation, tangent, - bitangent, update_aniso_vecs, dot_t_v, dot_b_v, linear_color, tint, - fsw, diff_coeff, subsurf_coeff, sheen_rad, spec_rad, - clear_coat_coef, radiance, diff_subsurf_mix, sheen_add, - metallic_balance, specular_add, clearcoat_add, color, gamma_color, - color_clamp, frag_output - ]) + fs_impl = compose_shader( + [ + start_comment, + normal, + view, + dot_n_v, + dot_n_v_validation, + tangent, + bitangent, + update_aniso_vecs, + dot_t_v, + dot_b_v, + linear_color, + tint, + fsw, + diff_coeff, + subsurf_coeff, + sheen_rad, + spec_rad, + clear_coat_coef, + radiance, + diff_subsurf_mix, + sheen_add, + metallic_balance, + specular_add, + clearcoat_add, + color, + gamma_color, + color_clamp, + frag_output, + ] + ) # Adding shader implementation to actor - shader_to_actor(actor, 'fragment', impl_code=fs_impl, block='light') + shader_to_actor(actor, "fragment", impl_code=fs_impl, block="light") return principled_params except AttributeError: - warnings.warn('Actor does not have the attribute property. This ' - 'material will not be applied.') + warnings.warn( + "Actor does not have the attribute property. This " + "material will not be applied.", + stacklevel=2, + ) return None -def manifest_standard(actor, ambient_level=0, ambient_color=(1, 1, 1), - diffuse_level=1, diffuse_color=(1, 1, 1), - specular_level=0, specular_color=(1, 1, 1), - specular_power=1, interpolation='gouraud'): +def manifest_standard( + actor, + ambient_level=0, + ambient_color=(1, 1, 1), + diffuse_level=1, + diffuse_color=(1, 1, 1), + specular_level=0, + specular_color=(1, 1, 1), + specular_power=1, + interpolation="gouraud", +): """Apply the standard material to the selected actor. Parameters @@ -533,17 +617,19 @@ def manifest_standard(actor, ambient_level=0, ambient_color=(1, 1, 1), interpolation = interpolation.lower() - if interpolation == 'flat': + if interpolation == "flat": prop.SetInterpolationToFlat() - elif interpolation == 'gouraud': + elif interpolation == "gouraud": prop.SetInterpolationToGouraud() - elif interpolation == 'phong': + elif interpolation == "phong": prop.SetInterpolationToPhong() else: - message = 'Unknown interpolation. Ignoring "{}" interpolation ' \ - 'option and using the default ("{}") option.' - message = message.format(interpolation, 'gouraud') - warnings.warn(message) + message = ( + 'Unknown interpolation. Ignoring "{}" interpolation ' + 'option and using the default ("{}") option.' + ) + message = message.format(interpolation, "gouraud") + warnings.warn(message, stacklevel=2) prop.SetAmbient(ambient_level) prop.SetAmbientColor(ambient_color) @@ -553,6 +639,9 @@ def manifest_standard(actor, ambient_level=0, ambient_color=(1, 1, 1), prop.SetSpecularColor(specular_color) prop.SetSpecularPower(specular_power) except AttributeError: - warnings.warn('Actor does not have the attribute property. This ' - 'material will not be applied.') + warnings.warn( + "Actor does not have the attribute property. This " + "material will not be applied.", + stacklevel=2, + ) return diff --git a/fury/molecular.py b/fury/molecular.py index 4633604fa..394591297 100644 --- a/fury/molecular.py +++ b/fury/molecular.py @@ -97,7 +97,7 @@ def __init__( elif not isinstance(atomic_numbers, np.ndarray) or not isinstance( coords, np.ndarray ): - raise ValueError('atom_types and coords must be numpy arrays.') + raise ValueError("atom_types and coords must be numpy arrays.") elif len(atomic_numbers) == len(coords): self.atom_names = atom_names self.model = model @@ -107,9 +107,8 @@ 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.SetName('Atomic Numbers') + atom_nums = nps.numpy_to_vtk(atomic_numbers, array_type=VTK_UNSIGNED_SHORT) + atom_nums.SetName("Atomic Numbers") fieldData = DataSetAttributes() fieldData.AddArray(atom_nums) self.Initialize(coords, fieldData) @@ -117,8 +116,8 @@ def __init__( n1 = len(coords) n2 = len(atomic_numbers) raise ValueError( - 'Mismatch in length of atomic_numbers({0}) and ' - 'length of atomic_coords({1}).'.format(n1, n2) + "Mismatch in length of atomic_numbers({0}) and " + "length of atomic_coords({1}).".format(n1, n2) ) @property @@ -414,7 +413,7 @@ def atomic_number(self, element_name): """ return self.GetAtomicNumber(element_name) - def atomic_radius(self, atomic_number, radius_type='VDW'): + 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. @@ -433,13 +432,13 @@ def atomic_radius(self, atomic_number, radius_type='VDW'): """ radius_type = radius_type.lower() - if radius_type == 'vdw': + if radius_type == "vdw": return self.GetVDWRadius(atomic_number) - elif radius_type == 'covalent': + elif radius_type == "covalent": return self.GetCovalentRadius(atomic_number) else: raise ValueError( - 'Incorrect radius_type specified. Please choose' + "Incorrect radius_type specified. Please choose" ' from "VDW" or "Covalent".' ) @@ -458,7 +457,7 @@ def atom_color(self, atomic_number): return rgb -def sphere_cpk(molecule, colormode='discrete'): +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. @@ -497,13 +496,13 @@ def sphere_cpk(molecule, colormode='discrete'): msp_mapper.SetRenderBonds(False) msp_mapper.SetAtomicRadiusTypeToVDWRadius() msp_mapper.SetAtomicRadiusScaleFactor(1) - if colormode == 'discrete': + if colormode == "discrete": msp_mapper.SetAtomColorMode(1) - elif colormode == 'single': + elif colormode == "single": msp_mapper.SetAtomColorMode(0) else: msp_mapper.SetAtomColorMode(1) - warnings.warn('Incorrect colormode specified! Using discrete.') + warnings.warn("Incorrect colormode specified! Using discrete.", stacklevel=2) # To-Do manipulate shading properties to make it look aesthetic molecule_actor = Actor() @@ -513,7 +512,7 @@ def sphere_cpk(molecule, colormode='discrete'): def ball_stick( molecule, - colormode='discrete', + colormode="discrete", atom_scale_factor=0.3, bond_thickness=0.1, multiple_bonds=True, @@ -564,8 +563,8 @@ def ball_stick( """ if molecule.total_num_bonds == 0: raise ValueError( - 'No bonding data available for the molecule! Ball ' - 'and stick model cannot be made!' + "No bonding data available for the molecule! Ball " + "and stick model cannot be made!" ) colormode = colormode.lower() bs_mapper = OpenGLMoleculeMapper() @@ -579,21 +578,21 @@ def ball_stick( bs_mapper.SetUseMultiCylindersForBonds(1) else: bs_mapper.SetUseMultiCylindersForBonds(0) - if colormode == 'discrete': + if colormode == "discrete": bs_mapper.SetAtomColorMode(1) bs_mapper.SetBondColorMode(1) - elif colormode == 'single': + elif colormode == "single": bs_mapper.SetAtomColorMode(0) bs_mapper.SetBondColorMode(0) else: bs_mapper.SetAtomColorMode(1) - warnings.warn('Incorrect colormode specified! Using discrete.') + 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): +def stick(molecule, colormode="discrete", bond_thickness=0.1): """Create an actor for stick molecular representation. Parameters @@ -624,8 +623,7 @@ 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() @@ -635,15 +633,15 @@ def stick(molecule, colormode='discrete', bond_thickness=0.1): mst_mapper.SetBondRadius(bond_thickness) mst_mapper.SetAtomicRadiusTypeToUnitRadius() mst_mapper.SetAtomicRadiusScaleFactor(bond_thickness) - if colormode == 'discrete': + if colormode == "discrete": mst_mapper.SetAtomColorMode(1) mst_mapper.SetBondColorMode(1) - elif colormode == 'single': + elif colormode == "single": mst_mapper.SetAtomColorMode(0) mst_mapper.SetBondColorMode(0) else: mst_mapper.SetAtomColorMode(1) - warnings.warn('Incorrect colormode specified! Using discrete.') + warnings.warn("Incorrect colormode specified! Using discrete.", stacklevel=2) molecule_actor = Actor() molecule_actor.SetMapper(mst_mapper) return molecule_actor @@ -675,21 +673,19 @@ def ribbon(molecule): num_total_atoms = molecule.total_num_atoms secondary_structures = np.ones(num_total_atoms) for i in range(num_total_atoms): - secondary_structures[i] = ord('c') + secondary_structures[i] = ord("c") 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') + 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') + secondary_structures[i] = ord("h") output = PolyData() @@ -700,7 +696,7 @@ def ribbon(molecule): # setting the array name to atom_type as vtkProteinRibbonFilter requires # the array to be named atom_type - atomic_num_arr.SetName('atom_type') + atomic_num_arr.SetName("atom_type") output.GetPointData().AddArray(atomic_num_arr) @@ -709,7 +705,7 @@ def ribbon(molecule): # setting the array name to atom_types as vtkProteinRibbonFilter requires # the array to be named atom_types - atom_names.SetName('atom_types') + atom_names.SetName("atom_types") atom_names.SetNumberOfTuples(num_total_atoms) for i in range(num_total_atoms): atom_names.SetValue(i, molecule.atom_names[i]) @@ -720,51 +716,47 @@ def ribbon(molecule): residue_seq = nps.numpy_to_vtk( num_array=molecule.residue_seq, deep=True, array_type=VTK_ID_TYPE ) - residue_seq.SetName('residue') + residue_seq.SetName("residue") output.GetPointData().AddArray(residue_seq) # for chain chain = nps.numpy_to_vtk( num_array=molecule.chain, deep=True, array_type=VTK_UNSIGNED_CHAR ) - chain.SetName('chain') + chain.SetName("chain") output.GetPointData().AddArray(chain) # for secondary structures s_s = nps.numpy_to_vtk( num_array=secondary_structures, deep=True, array_type=VTK_UNSIGNED_CHAR ) - s_s.SetName('secondary_structures') + s_s.SetName("secondary_structures") output.GetPointData().AddArray(s_s) # 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.SetName('secondary_structures_begin') + 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.SetName('secondary_structures_end') + 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) # for is_hetatm is_hetatm = nps.numpy_to_vtk( num_array=molecule.is_hetatm, deep=True, array_type=VTK_UNSIGNED_CHAR ) - is_hetatm.SetName('ishetatm') + is_hetatm.SetName("ishetatm") output.GetPointData().AddArray(is_hetatm) # for model model = nps.numpy_to_vtk( num_array=molecule.model, deep=True, array_type=VTK_UNSIGNED_INT ) - model.SetName('model') + model.SetName("model") output.GetPointData().AddArray(model) table = PTable() @@ -774,19 +766,15 @@ 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], "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.SetName('rgb_colors') + Rgb = nps.numpy_to_vtk(num_array=rgb, deep=True, array_type=VTK_UNSIGNED_CHAR) + Rgb.SetName("rgb_colors") output.GetPointData().SetScalars(Rgb) Radii = nps.numpy_to_vtk(num_array=radii, deep=True, array_type=VTK_FLOAT) - Radii.SetName('radius') + Radii.SetName("radius") output.GetPointData().SetVectors(Radii) # setting the coordinates diff --git a/fury/optpkg.py b/fury/optpkg.py index 00f737662..053b62c6b 100644 --- a/fury/optpkg.py +++ b/fury/optpkg.py @@ -26,7 +26,7 @@ def is_tripwire(obj): """ try: - obj.any_attribute + _ = obj.any_attribute except TripWireError: return True except Exception: @@ -45,7 +45,8 @@ class TripWire: ... import silly_module_name ... except ImportError: ... silly_module_name = TripWire('We do not have silly_module_name') - >>> silly_module_name.do_silly_thing('with silly string') #doctest: +IGNORE_EXCEPTION_DETAIL # noqa + >>> msg = 'with silly string' + >>> silly_module_name.do_silly_thing(msg) #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... TripWireError: We do not have silly_module_name @@ -121,13 +122,13 @@ def optional_package(name, trip_msg=None): return pkg, True, lambda: None if trip_msg is None: trip_msg = ( - 'We need package %s for these functions, but ' - '``import %s`` raised an ImportError' % (name, name) + "We need package %s for these functions, but " + "``import %s`` raised an ImportError" % (name, name) ) pkg = TripWire(trip_msg) def setup_module(): if have_pytest: - pytest.mark.skip('No {0} for these tests'.format(name)) + pytest.mark.skip("No {0} for these tests".format(name)) return pkg, False, setup_module diff --git a/fury/pick.py b/fury/pick.py index 7cac4bbbc..6949638c5 100644 --- a/fury/pick.py +++ b/fury/pick.py @@ -16,12 +16,7 @@ class PickingManager: """Picking Manager helps with picking 3D objects.""" - def __init__( - self, - vertices=True, - faces=True, - actors=True, - world_coords=True): + def __init__(self, vertices=True, faces=True, actors=True, world_coords=True): """Initialize Picking Manager. Parameters @@ -38,13 +33,13 @@ def __init__( """ self.pickers = {} if vertices: - self.pickers['vertices'] = PointPicker() + self.pickers["vertices"] = PointPicker() if faces: - self.pickers['faces'] = CellPicker() + self.pickers["faces"] = CellPicker() if actors: - self.pickers['actors'] = PropPicker() + self.pickers["actors"] = PropPicker() if world_coords: - self.pickers['world_coords'] = WorldPointPicker() + self.pickers["world_coords"] = WorldPointPicker() def pick(self, disp_xy, sc): """Pick on display coordinates. @@ -59,25 +54,25 @@ def pick(self, disp_xy, sc): """ x, y = disp_xy z = 0 - info = {'vertex': None, 'face': None, 'actor': None, 'xyz': None} + info = {"vertex": None, "face": None, "actor": None, "xyz": None} keys = self.pickers.keys() - if 'vertices' in keys: - self.pickers['vertices'].Pick(x, y, z, sc) - info['vertex'] = self.pickers['vertices'].GetPointId() + if "vertices" in keys: + self.pickers["vertices"].Pick(x, y, z, sc) + info["vertex"] = self.pickers["vertices"].GetPointId() - if 'faces' in keys: - self.pickers['faces'].Pick(x, y, z, sc) - info['vertex'] = self.pickers['faces'].GetPointId() - info['face'] = self.pickers['faces'].GetCellId() + if "faces" in keys: + self.pickers["faces"].Pick(x, y, z, sc) + info["vertex"] = self.pickers["faces"].GetPointId() + info["face"] = self.pickers["faces"].GetCellId() - if 'actors' in keys: - self.pickers['actors'].Pick(x, y, z, sc) - info['actor'] = self.pickers['actors'].GetViewProp() + if "actors" in keys: + self.pickers["actors"].Pick(x, y, z, sc) + info["actor"] = self.pickers["actors"].GetViewProp() - if 'world_coords' in keys: - self.pickers['world_coords'].Pick(x, y, z, sc) - info['xyz'] = self.pickers['world_coords'].GetPickPosition() + if "world_coords" in keys: + self.pickers["world_coords"].Pick(x, y, z, sc) + info["xyz"] = self.pickers["world_coords"].GetPickPosition() return info @@ -125,7 +120,7 @@ def pickable_off(self, actors): class SelectionManager: """Selection Manager helps with picking many objects simultaneously.""" - def __init__(self, select='faces'): + def __init__(self, select="faces"): """Initialize Selection Manager. Parameters @@ -154,14 +149,14 @@ def update_selection_type(self, select): """ self.selected_type = select.lower() - if select == 'faces' or select == 'edges': + if select == "faces" or select == "edges": self.hsel.SetFieldAssociation(DataObject.FIELD_ASSOCIATION_CELLS) - elif select == 'points' or select == 'vertices': + elif select == "points" or select == "vertices": self.hsel.SetFieldAssociation(DataObject.FIELD_ASSOCIATION_POINTS) - elif select == 'actors': + elif select == "actors": self.hsel.SetActorPassOnly(True) else: - raise ValueError('Unkown parameter select') + raise ValueError("Unknown parameter select") def pick(self, disp_xy, sc): """Pick on display coordinates returns a single object. @@ -207,52 +202,30 @@ 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() - ) - if self.selected_type == 'faces': - info['face'] = list(selected_nodes) - if self.selected_type == 'vertex': - info['vertex'] = list(selected_nodes) + info["node"] = sel_node + info["actor"] = sel_node.GetProperties().Get(sel_node.PROP()) + if self.selected_type == "faces": + info["face"] = list(selected_nodes) + if self.selected_type == "vertex": + info["vertex"] = list(selected_nodes) info_plus[i] = info return info_plus diff --git a/fury/pkg_info.py b/fury/pkg_info.py index 82e320b78..7bd7da41e 100644 --- a/fury/pkg_info.py +++ b/fury/pkg_info.py @@ -7,9 +7,9 @@ try: from ._version import __version__ except ImportError: - __version__ = '0+unknown' + __version__ = "0+unknown" -COMMIT_HASH = '$Format:%h$' +COMMIT_HASH = "$Format:%h$" def pkg_commit_hash(pkg_path: str | None = None) -> tuple[str, str]: @@ -40,17 +40,17 @@ def pkg_commit_hash(pkg_path: str | None = None) -> tuple[str, str]: short form of hash """ - if not COMMIT_HASH.startswith('$Format'): # it has been substituted - return 'archive substitution', COMMIT_HASH + if not COMMIT_HASH.startswith("$Format"): # it has been substituted + return "archive substitution", COMMIT_HASH ver = Version(__version__) - if ver.local is not None and ver.local.startswith('g'): - return 'installation', ver.local[1:8] + if ver.local is not None and ver.local.startswith("g"): + return "installation", ver.local[1:8] # maybe we are in a repository proc = run( - ('git', 'rev-parse', '--short', 'HEAD'), + ("git", "rev-parse", "--short", "HEAD"), capture_output=True, cwd=pkg_path, ) if proc.stdout: - return 'repository', proc.stdout.decode().strip() - return '(none found)', '' + return "repository", proc.stdout.decode().strip() + return "(none found)", "" diff --git a/fury/primitive.py b/fury/primitive.py index b07ffdafc..768a92626 100644 --- a/fury/primitive.py +++ b/fury/primitive.py @@ -1,4 +1,5 @@ """Module dedicated for basic primitive.""" + import math from os.path import join as pjoin @@ -11,15 +12,15 @@ from fury.transform import cart2sphere, sphere2cart from fury.utils import fix_winding_order -SCIPY_1_4_PLUS = parse(short_version) >= parse('1.4.0') +SCIPY_1_4_PLUS = parse(short_version) >= parse("1.4.0") SPHERE_FILES = { - 'symmetric362': pjoin(DATA_DIR, 'evenly_distributed_sphere_362.npz'), - 'symmetric642': pjoin(DATA_DIR, 'evenly_distributed_sphere_642.npz'), - 'symmetric724': pjoin(DATA_DIR, 'evenly_distributed_sphere_724.npz'), - 'repulsion724': pjoin(DATA_DIR, 'repulsion724.npz'), - 'repulsion100': pjoin(DATA_DIR, 'repulsion100.npz'), - 'repulsion200': pjoin(DATA_DIR, 'repulsion200.npz'), + "symmetric362": pjoin(DATA_DIR, "evenly_distributed_sphere_362.npz"), + "symmetric642": pjoin(DATA_DIR, "evenly_distributed_sphere_642.npz"), + "symmetric724": pjoin(DATA_DIR, "evenly_distributed_sphere_724.npz"), + "repulsion724": pjoin(DATA_DIR, "repulsion724.npz"), + "repulsion100": pjoin(DATA_DIR, "repulsion100.npz"), + "repulsion200": pjoin(DATA_DIR, "repulsion200.npz"), } @@ -37,7 +38,7 @@ def faces_from_sphere_vertices(vertices): Indices into vertices; forms triangular faces. """ - hull = ConvexHull(vertices, qhull_options='Qbb Qc') + hull = ConvexHull(vertices, qhull_options="Qbb Qc") faces = np.ascontiguousarray(hull.simplices) if len(vertices) < 2**16: return np.asarray(faces, np.uint16) @@ -46,12 +47,7 @@ def faces_from_sphere_vertices(vertices): def repeat_primitive_function( - func, - centers, - func_args=[], - 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. @@ -83,14 +79,17 @@ def repeat_primitive_function( Expanded colors applied to all vertices/faces """ + if func_args is None: + func_args = [] + # Get faces _, faces = func() if len(func_args) == 1: func_args = np.squeeze(np.array([func_args] * centers.shape[0])) elif len(func_args) != centers.shape[0]: raise IOError( - 'sq_params should 1 or equal to the numbers \ - of centers' + "sq_params should 1 or equal to the numbers \ + of centers" ) vertices = np.concatenate([func(i)[0] for i in func_args]) @@ -167,15 +166,14 @@ def repeat_primitive( big_vertices *= scales # update triangles - big_triangles = np.array( - np.tile(faces, (centers.shape[0], 1)), dtype=np.int32) + big_triangles = np.array(np.tile(faces, (centers.shape[0], 1)), dtype=np.int32) big_triangles += np.repeat( np.arange(0, centers.shape[0] * unit_verts_size, step=unit_verts_size), unit_triangles_size, axis=0, ).reshape((big_triangles.shape[0], 1)) - def normalize_input(arr, arr_name=''): + def normalize_input(arr, arr_name=""): if ( isinstance(arr, (tuple, list, np.ndarray)) and len(arr) in [3, 4] @@ -187,19 +185,19 @@ def normalize_input(arr, arr_name=''): elif arr is None: return np.array([]) elif len(arr) != len(centers): - msg = '{} size should be 1 or '.format(arr_name) - msg += 'equal to the numbers of centers' + msg = "{} size should be 1 or ".format(arr_name) + msg += "equal to the numbers of centers" raise IOError(msg) else: return np.array(arr) # update colors - colors = normalize_input(colors, 'colors') + colors = normalize_input(colors, "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, "directions") for pts, dirs in enumerate(directions): # Normal vector of the object. dir_abs = np.linalg.norm(dirs) @@ -217,18 +215,17 @@ def normalize_input(arr, arr_name=''): rotation_matrix = -np.eye(3, dtype=np.float64) else: h = 1 / (1 + c) - rotation_matrix = np.eye(3, dtype=np.float64) + \ - Vmat + (Vmat.dot(Vmat) * h) + rotation_matrix = ( + np.eye(3, dtype=np.float64) + Vmat + (Vmat.dot(Vmat) * h) + ) else: rotation_matrix = np.identity(3) - big_vertices[pts * unit_verts_size: (pts + 1) * unit_verts_size] = ( - np.dot(rotation_matrix[:3, :3], - big_vertices[pts * unit_verts_size: ( - pts + 1) * unit_verts_size].T, - ).T - ) + big_vertices[pts * unit_verts_size : (pts + 1) * unit_verts_size] = np.dot( + rotation_matrix[:3, :3], + big_vertices[pts * unit_verts_size : (pts + 1) * unit_verts_size].T, + ).T # apply centers position big_centers = np.repeat(centers, unit_verts_size, axis=0) @@ -249,14 +246,9 @@ def prim_square(): """ vertices = np.array( - [ - [-0.5, -0.5, 0.0], - [-0.5, 0.5, 0.0], - [0.5, 0.5, 0.0], - [0.5, -0.5, 0.0] - ] + [[-0.5, -0.5, 0.0], [-0.5, 0.5, 0.0], [0.5, 0.5, 0.0], [0.5, -0.5, 0.0]] ) - triangles = np.array([[0, 1, 2], [2, 3, 0]], dtype='i8') + triangles = np.array([[0, 1, 2], [2, 3, 0]], dtype="i8") return vertices, triangles @@ -298,12 +290,12 @@ def prim_box(): [1, 5, 7], [1, 7, 3], ], - dtype='i8', + dtype="i8", ) return vertices, triangles -def prim_sphere(name='symmetric362', gen_faces=False, phi=None, theta=None): +def prim_sphere(name="symmetric362", gen_faces=False, phi=None, theta=None): """Provide vertices and triangles of the spheres. Parameters @@ -348,10 +340,9 @@ def prim_sphere(name='symmetric362', gen_faces=False, phi=None, theta=None): raise ValueError('No sphere called "%s"' % name) res = np.load(fname) - verts = res['vertices'].copy() - faces = (faces_from_sphere_vertices(verts) - if gen_faces else res['faces']) - faces = fix_winding_order(res['vertices'], faces, clockwise=True) + verts = res["vertices"].copy() + faces = faces_from_sphere_vertices(verts) if gen_faces else res["faces"] + faces = fix_winding_order(res["vertices"], faces, clockwise=True) return verts, faces else: phi = phi if phi >= 3 else 3 @@ -382,7 +373,7 @@ def prim_sphere(name='symmetric362', gen_faces=False, phi=None, theta=None): return verts, faces -def prim_superquadric(roundness=(1, 1), sphere_name='symmetric362'): +def prim_superquadric(roundness=(1, 1), sphere_name="symmetric362"): """Provide vertices and triangles of a superquadrics. Parameters @@ -450,17 +441,10 @@ def prim_tetrahedron(): """ pyramid_vert = np.array( - [ - [0.5, 0.5, 0.5], - [0.5, -0.5, -0.5], - [-0.5, 0.5, -0.5], - [-0.5, -0.5, 0.5] - ] + [[0.5, 0.5, 0.5], [0.5, -0.5, -0.5], [-0.5, 0.5, -0.5], [-0.5, -0.5, 0.5]] ) - pyramid_triag = np.array( - [[2, 0, 1], [0, 2, 3], [0, 3, 1], [1, 3, 2]], - dtype='i8') + pyramid_triag = np.array([[2, 0, 1], [0, 2, 3], [0, 3, 1], [1, 3, 2]], dtype="i8") return pyramid_vert, pyramid_triag @@ -518,7 +502,7 @@ def prim_icosahedron(): [10, 9, 6], [9, 10, 11], ], - dtype='i8', + dtype="i8", ) return icosahedron_vertices, icosahedron_mesh @@ -613,7 +597,7 @@ def prim_rhombicuboctahedron(): [22, 20, 5], [20, 1, 5], ], - dtype='i8', + dtype="i8", ) triangles = fix_winding_order(vertices, triangles, clockwise=True) @@ -664,7 +648,7 @@ def prim_star(dim=2): [3, 7, 9], [3, 5, 7], ], - dtype='i8', + dtype="i8", ) if dim == 3: @@ -715,7 +699,7 @@ def prim_star(dim=2): [3, 11, 2], [11, 1, 2], ], - dtype='i8', + dtype="i8", ) return vert, triangles @@ -733,7 +717,7 @@ def prim_triangularprism(): """ # Local variable to represent the square root of three rounded # to 7 decimal places - three = float('{:.7f}'.format(math.sqrt(3))) + three = float("{:.7f}".format(math.sqrt(3))) vertices = np.array( [ [0, -1 / three, 1 / 2], @@ -829,7 +813,7 @@ def prim_octagonalprism(): """ # Local variable to represent the square root of two rounded # to 7 decimal places - two = float('{:.7f}'.format(math.sqrt(2))) + two = float("{:.7f}".format(math.sqrt(2))) vertices = np.array( [ @@ -882,7 +866,7 @@ def prim_octagonalprism(): [10, 13, 14], [13, 10, 9], ], - dtype='u8', + dtype="u8", ) vertices /= 4 triangles = fix_winding_order(vertices, triangles, clockwise=True) @@ -927,7 +911,7 @@ def prim_frustum(): [5, 0, 1], [0, 5, 4], ], - dtype='u8', + dtype="u8", ) vertices /= 2 triangles = fix_winding_order(vertices, triangles, clockwise=True) @@ -957,9 +941,9 @@ def prim_cylinder(radius=0.5, height=1, sectors=36, capped=True): """ if not isinstance(sectors, int): - raise TypeError('Only integers are allowed for sectors parameter') + raise TypeError("Only integers are allowed for sectors parameter") if not sectors > 7: - raise ValueError('Sectors parameter should be greater than 7') + raise ValueError("Sectors parameter should be greater than 7") sector_step = 2 * math.pi / sectors unit_circle_vertices = [] @@ -1008,9 +992,7 @@ def prim_cylinder(radius=0.5, height=1, sectors=36, capped=True): k += 3 if capped: - vertices = np.array(vertices).reshape( - 2 * (sectors + 1) + 2 * sectors + 2, 3 - ) + vertices = np.array(vertices).reshape(2 * (sectors + 1) + 2 * sectors + 2, 3) else: vertices = np.array(vertices).reshape(2 * (sectors + 1), 3) @@ -1019,7 +1001,7 @@ def prim_cylinder(radius=0.5, height=1, sectors=36, capped=True): k2 = sectors + 1 # triangles for the side surface - for i in range(sectors): + for _ in range(sectors): triangles.append(k1) triangles.append(k2) triangles.append(k1 + 1) @@ -1064,11 +1046,7 @@ def prim_cylinder(radius=0.5, height=1, sectors=36, capped=True): 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. @@ -1178,7 +1156,7 @@ def prim_cone(radius=0.5, height=1, sectors=10): """ if sectors < 3: - raise ValueError('Sectors parameter should be greater than 2') + raise ValueError("Sectors parameter should be greater than 2") sector_angles = 2 * np.pi / sectors * np.arange(sectors) diff --git a/fury/shaders/__init__.py b/fury/shaders/__init__.py index 8a8f11764..c8a9378d7 100644 --- a/fury/shaders/__init__.py +++ b/fury/shaders/__init__.py @@ -11,13 +11,13 @@ ) __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', + "add_shader_callback", + "attribute_to_actor", + "compose_shader", + "import_fury_shader", + "load_shader", + "load", + "replace_shader_in_actor", + "shader_apply_effects", + "shader_to_actor", ] diff --git a/fury/shaders/base.py b/fury/shaders/base.py index 8308f9efa..34dfe6e55 100644 --- a/fury/shaders/base.py +++ b/fury/shaders/base.py @@ -15,50 +15,58 @@ SHADERS_DIR = os.path.join(os.path.dirname(__file__)) -SHADERS_EXTS = ['.glsl', '.vert', '.tesc', '.tese', '.geom', '.frag', '.comp'] +SHADERS_EXTS = [ + ".glsl", + ".vert", + ".tesc", + ".tese", + ".geom", + ".frag", + ".comp", +] # codespell:ignore SHADERS_TYPE = { - 'vertex': Shader.Vertex, - 'geometry': Shader.Geometry, - 'fragment': Shader.Fragment, + "vertex": Shader.Vertex, + "geometry": Shader.Geometry, + "fragment": Shader.Fragment, } -REPLACEMENT_SHADERS_TYPES = {'vertex': Shader.Vertex, 'fragment': Shader.Fragment} +REPLACEMENT_SHADERS_TYPES = {"vertex": Shader.Vertex, "fragment": Shader.Fragment} SHADERS_BLOCK = { - 'position': '//VTK::PositionVC', # frag position in VC - 'normal': '//VTK::Normal', # optional normal declaration - 'light': '//VTK::Light', # extra lighting parameters - 'tcoord': '//VTK::TCoord', # Texture coordinates - 'color': '//VTK::Color', # material property values - 'clip': '//VTK::Clip', # clipping plane vars - 'camera': '//VTK::Camera', # camera and actor matrix values - 'prim_id': '//VTK::PrimID', # Apple Bug - 'valuepass': '//VTK::ValuePass', # Value raster - 'output': '//VTK::Output', # only for geometry shader - 'coincident': '//VTK::Coincident', # handle coincident offsets - 'zbufer': '//VTK::ZBuffer', - 'depth_peeling': '//VTK::DepthPeeling', # Depth Peeling Support - 'picking': '//VTK::Picking', # picking support + "position": "//VTK::PositionVC", # frag position in VC + "normal": "//VTK::Normal", # optional normal declaration + "light": "//VTK::Light", # extra lighting parameters + "tcoord": "//VTK::TCoord", # Texture coordinates + "color": "//VTK::Color", # material property values + "clip": "//VTK::Clip", # clipping plane vars + "camera": "//VTK::Camera", # camera and actor matrix values + "prim_id": "//VTK::PrimID", # Apple Bug + "valuepass": "//VTK::ValuePass", # Value raster + "output": "//VTK::Output", # only for geometry shader + "coincident": "//VTK::Coincident", # handle coincident offsets + "zbufer": "//VTK::ZBuffer", + "depth_peeling": "//VTK::DepthPeeling", # Depth Peeling Support + "picking": "//VTK::Picking", # picking support } # See [1] for a more extensive list of OpenGL constants # [1] https://docs.factorcode.org/content/vocab-opengl.gl.html GL_NUMBERS = { - 'GL_ONE': 1, - 'GL_ZERO': 0, - 'GL_BLEND': 3042, - 'GL_ONE_MINUS_SRC_ALPHA': 771, - 'GL_SRC_ALPHA': 770, - 'GL_DEPTH_TEST': 2929, - 'GL_DST_COLOR': 774, - 'GL_FUNC_SUBTRACT': 3277, - 'GL_CULL_FACE': 2884, - 'GL_ALPHA_TEST': 3008, - 'GL_CW': 2304, - 'GL_CCW': 2305, - 'GL_ONE_MINUS_SRC_COLOR': 769, - 'GL_SRC_COLOR': 768, + "GL_ONE": 1, + "GL_ZERO": 0, + "GL_BLEND": 3042, + "GL_ONE_MINUS_SRC_ALPHA": 771, + "GL_SRC_ALPHA": 770, + "GL_DEPTH_TEST": 2929, + "GL_DST_COLOR": 774, + "GL_FUNC_SUBTRACT": 3277, + "GL_CULL_FACE": 2884, + "GL_ALPHA_TEST": 3008, + "GL_CW": 2304, + "GL_CCW": 2305, + "GL_ONE_MINUS_SRC_COLOR": 769, + "GL_SRC_COLOR": 768, } @@ -76,17 +84,17 @@ def compose_shader(glsl_code): """ if not glsl_code: - return '' + return "" if not all(isinstance(i, str) for i in glsl_code): - raise IOError('The only supported format are string.') + raise IOError("The only supported format are string.") if isinstance(glsl_code, str): return glsl_code - code = '' + code = "" for content in glsl_code: - code += '\n' + code += "\n" code += content return code @@ -132,15 +140,15 @@ def load_shader(shader_file): if file_ext not in SHADERS_EXTS: raise IOError( 'Shader file "{}" does not have one of the supported ' - 'extensions: {}.'.format(shader_file, SHADERS_EXTS) + "extensions: {}.".format(shader_file, SHADERS_EXTS) ) return load_text(shader_file) @deprecate_with_version( - message='Load function has been reimplemented as import_fury_shader.', - since='0.8.1', - until='0.9.0', + message="Load function has been reimplemented as import_fury_shader.", + since="0.8.1", + until="0.9.0", ) def load(filename): """Load a Fury shader file. @@ -163,9 +171,9 @@ def load(filename): def shader_to_actor( actor, shader_type, - impl_code='', - decl_code='', - block='valuepass', + impl_code="", + decl_code="", + block="valuepass", keep_default=True, replace_first=True, replace_all=False, @@ -209,27 +217,27 @@ def shader_to_actor( shader_type = shader_type.lower() shader_type = REPLACEMENT_SHADERS_TYPES.get(shader_type, None) if shader_type is None: - msg = 'Invalid Shader Type. Please choose between ' - msg += ', '.join(REPLACEMENT_SHADERS_TYPES.keys()) + msg = "Invalid Shader Type. Please choose between " + msg += ", ".join(REPLACEMENT_SHADERS_TYPES.keys()) raise ValueError(msg) block = block.lower() block = SHADERS_BLOCK.get(block, None) if block is None: - msg = 'Invalid Shader Type. Please choose between ' - msg += ', '.join(SHADERS_BLOCK.keys()) + msg = "Invalid Shader Type. Please choose between " + msg += ", ".join(SHADERS_BLOCK.keys()) raise ValueError(msg) - block_dec = block + '::Dec' - block_impl = block + '::Impl' + block_dec = block + "::Dec" + block_impl = block + "::Impl" if keep_default: - decl_code = block_dec + '\n' + decl_code - impl_code = block_impl + '\n' + impl_code + decl_code = block_dec + "\n" + decl_code + impl_code = block_impl + "\n" + impl_code if debug: enable_warnings() - error_msg = '\n\n--- DEBUG: THIS LINE GENERATES AN ERROR ---\n\n' + error_msg = "\n\n--- DEBUG: THIS LINE GENERATES AN ERROR ---\n\n" impl_code += error_msg sp = actor.GetShaderProperty() @@ -256,15 +264,15 @@ def replace_shader_in_actor(actor, shader_type, code): """ function_name = { - 'vertex': 'SetVertexShaderCode', - 'fragment': 'SetFragmentShaderCode', - 'geometry': 'SetGeometryShaderCode', + "vertex": "SetVertexShaderCode", + "fragment": "SetFragmentShaderCode", + "geometry": "SetGeometryShaderCode", } shader_type = shader_type.lower() function = function_name.get(shader_type, None) if function is None: - msg = 'Invalid Shader Type. Please choose between ' - msg += ', '.join(function_name.keys()) + msg = "Invalid Shader Type. Please choose between " + msg += ", ".join(function_name.keys()) raise ValueError(msg) sp = actor.GetShaderProperty() diff --git a/fury/shaders/tests/test_base.py b/fury/shaders/tests/test_base.py index 91c1dbc5b..7fc7f3438 100644 --- a/fury/shaders/tests/test_base.py +++ b/fury/shaders/tests/test_base.py @@ -145,10 +145,10 @@ def generate_cube_with_effect(): cube = actor.cube(np.array([[0, 0, 0]])) shader_to_actor( - cube, 'vertex', impl_code=vertex_impl, decl_code=vertex_dec, block='valuepass' + cube, "vertex", impl_code=vertex_impl, decl_code=vertex_dec, block="valuepass" ) shader_to_actor( - cube, 'fragment', impl_code=frag_impl, decl_code=frag_dec, block='light' + cube, "fragment", impl_code=frag_impl, decl_code=frag_dec, block="light" ) return cube @@ -210,7 +210,7 @@ def my_cbk(_caller, _event, calldata=None): if program is not None: try: - program.SetUniformf('time', timer.idx) + program.SetUniformf("time", timer.idx) except ValueError: pass @@ -234,8 +234,8 @@ def callbackLow(_caller, _event, calldata=None): id_observer = add_shader_callback(cone_actor, callbackLow, 0) - with pytest.raises(Exception): - add_shader_callback(cone_actor, callbackLow, priority='str') + with pytest.raises(Exception): # noqa: B017 + add_shader_callback(cone_actor, callbackLow, priority="str") mapper = cone_actor.GetMapper() mapper.RemoveObserver(id_observer) @@ -243,7 +243,7 @@ def callbackLow(_caller, _event, calldata=None): scene = window.Scene() scene.add(cone_actor) - arr1 = window.snapshot(scene, size=(200, 200)) + window.snapshot(scene, size=(200, 200)) assert len(test_values) == 0 test_values = [] @@ -264,7 +264,7 @@ def callbackMean(_caller, _event, calldata=None): id_mean = add_shader_callback(cone_actor, callbackMean, 500) # check the priority of each call - arr2 = window.snapshot(scene, size=(200, 200)) + window.snapshot(scene, size=(200, 200)) assert ( np.abs([test_values[0] - 999, test_values[1] - 500, test_values[2] - 0]).sum() == 0 @@ -274,7 +274,7 @@ def callbackMean(_caller, _event, calldata=None): mapper.RemoveObserver(id_mean) test_values = [] - arr3 = window.snapshot(scene, size=(200, 200)) + window.snapshot(scene, size=(200, 200)) assert np.abs([test_values[0] - 999, test_values[1] - 0]).sum() == 0 @@ -282,20 +282,20 @@ def test_attribute_to_actor(): cube = generate_cube_with_effect() test_arr = np.arange(24).reshape((8, 3)) - attribute_to_actor(cube, test_arr, 'test_arr') + attribute_to_actor(cube, test_arr, "test_arr") - arr = cube.GetMapper().GetInput().GetPointData().GetArray('test_arr') + arr = cube.GetMapper().GetInput().GetPointData().GetArray("test_arr") npt.assert_array_equal(test_arr, numpy_support.vtk_to_numpy(arr)) def test_compose_shader(): - str_test1 = 'Test1' - str_test2 = 'Test2' + str_test1 = "Test1" + str_test2 = "Test2" list_str1 = [str_test1, None] list_str2 = [str_test1, str_test2] # Test empty parameter code = compose_shader(None) - npt.assert_equal(code, '') + npt.assert_equal(code, "") # Test invalid list npt.assert_raises(IOError, compose_shader, list_str1) # Test str code @@ -303,13 +303,13 @@ def test_compose_shader(): npt.assert_equal(code, str_test1) # Test list of str code code = compose_shader(list_str2) - npt.assert_equal(code, '\n' + '\n'.join(list_str2)) + npt.assert_equal(code, "\n" + "\n".join(list_str2)) def test_import_fury_shader(): - str_test1 = 'Test1' - fname_test1 = 'test1.frag' - fname_test2 = 'test2.txt' + str_test1 = "Test1" + fname_test1 = "test1.frag" + fname_test2 = "test2.txt" pname_test1 = os.path.join(SHADERS_DIR, fname_test1) # Test invalid file extension @@ -319,7 +319,7 @@ def test_import_fury_shader(): npt.assert_raises(IOError, import_fury_shader, pname_test1) # Test valid file - with open(pname_test1, 'w') as f: + with open(pname_test1, "w") as f: f.write(str_test1) code = import_fury_shader(fname_test1) npt.assert_equal(code, str_test1) @@ -328,16 +328,16 @@ def test_import_fury_shader(): def test_load_shader(): - fname_test = 'test.text' + fname_test = "test.text" # Test invalid file extension npt.assert_raises(IOError, load_shader, fname_test) with InTemporaryDirectory() as tdir: - fname_test = 'test.frag' + fname_test = "test.frag" fname_test = os.path.join(tdir, fname_test) - str_test = 'Test1' - test_file = open(fname_test, 'w') + str_test = "Test1" + test_file = open(fname_test, "w") test_file.write(str_test) test_file.close() @@ -345,10 +345,10 @@ def test_load_shader(): def test_load(): - dummy_file_name = 'dummy.txt' - dummy_file_contents = 'This is some dummy text.' + dummy_file_name = "dummy.txt" + dummy_file_contents = "This is some dummy text." - dummy_file = open(os.path.join(SHADERS_DIR, dummy_file_name), 'w') + dummy_file = open(os.path.join(SHADERS_DIR, dummy_file_name), "w") dummy_file.write(dummy_file_contents) dummy_file.close() @@ -370,7 +370,7 @@ def test_replace_shader_in_actor(interactive=False): actual = ss[160, 40, :] npt.assert_array_equal(actual, [0, 0, 0]) scene.clear() - replace_shader_in_actor(test_actor, 'geometry', geometry_code) + replace_shader_in_actor(test_actor, "geometry", geometry_code) scene.add(test_actor) if interactive: window.show(scene) @@ -397,9 +397,9 @@ def test_shader_to_actor(interactive=False): npt.assert_equal(report.objects, 1) # test errors - npt.assert_raises(ValueError, shader_to_actor, cube, 'error', vertex_impl) - npt.assert_raises(ValueError, shader_to_actor, cube, 'geometry', vertex_impl) + npt.assert_raises(ValueError, shader_to_actor, cube, "error", vertex_impl) + npt.assert_raises(ValueError, shader_to_actor, cube, "geometry", vertex_impl) npt.assert_raises( - ValueError, shader_to_actor, cube, 'vertex', vertex_impl, block='error' + ValueError, shader_to_actor, cube, "vertex", vertex_impl, block="error" ) - npt.assert_raises(ValueError, replace_shader_in_actor, cube, 'error', vertex_impl) + npt.assert_raises(ValueError, replace_shader_in_actor, cube, "error", vertex_impl) diff --git a/fury/stream/client.py b/fury/stream/client.py index a6b3b751a..4bd73839b 100644 --- a/fury/stream/client.py +++ b/fury/stream/client.py @@ -35,7 +35,7 @@ def callback_stream_client(stream_client): vtk_array = vtk_image.GetPointData().GetScalars() w, h, _ = vtk_image.GetDimensions() - np_arr = np.frombuffer(vtk_array, dtype='uint8') + np_arr = np.frombuffer(vtk_array, dtype="uint8") if np_arr is None: stream_client.in_request = False return @@ -94,9 +94,7 @@ def __init__( self.max_size = max_window_size[0] * max_window_size[1] self.max_window_size = max_window_size if self.max_size < self.showm.size[0] * self.showm.size[1]: - raise ValueError( - 'max_window_size must be greater than window_size' - ) + raise ValueError("max_window_size must be greater than window_size") if not PY_VERSION_8 and not use_raw_array: raise ValueError( @@ -137,40 +135,30 @@ def start(self, ms=0, use_asyncio=False): """ def callback_for_vtk(caller, event, *args, **kwargs): - callback_stream_client( - **{'stream_client': kwargs['stream_client']} - ) + callback_stream_client(**{"stream_client": kwargs["stream_client"]}) - use_asyncio = platform.system() == 'Windows' or use_asyncio + use_asyncio = platform.system() == "Windows" or use_asyncio if self._started: self.stop() if ms > 0: if self._whithout_iren_start: - - Interval = (IntervalTimer if use_asyncio else - IntervalTimerThreading) + Interval = IntervalTimer if use_asyncio else IntervalTimerThreading self._interval_timer = Interval( - ms / 1000, callback_stream_client, - **{'stream_client': self} + ms / 1000, callback_stream_client, **{"stream_client": self} ) else: self._id_observer = self.showm.iren.AddObserver( - 'TimerEvent', partial( - callback_for_vtk, - **{'stream_client': self}) + "TimerEvent", partial(callback_for_vtk, **{"stream_client": self}) ) self._id_timer = self.showm.iren.CreateRepeatingTimer(ms) else: self._id_observer = self.showm.iren.AddObserver( - 'RenderEvent', partial( - callback_for_vtk, - **{'stream_client': self} - ) + "RenderEvent", partial(callback_for_vtk, **{"stream_client": self}) ) self.showm.window.Render() self.showm.iren.Render() self._started = True - callback_stream_client(**{'stream_client': self}) + callback_stream_client(**{"stream_client": self}) def stop(self): """Stop the stream client.""" @@ -204,17 +192,19 @@ def cleanup(self): self.img_manager.info_buffer.unlink() except FileNotFoundError: print( - f'Shared Memory {self.img_manager.info_buffer_name}\ - (info_buffer) File not found' + f"Shared Memory {self.img_manager.info_buffer_name}\ + (info_buffer) File not found" ) for buffer, name in zip( - self.img_manager.image_buffers, self.img_manager.image_buffer_names + self.img_manager.image_buffers, + self.img_manager.image_buffer_names, + strict=False, ): buffer.close() try: buffer.unlink() except FileNotFoundError: - print(f'Shared Memory {name}(buffer image) File not found') + print(f"Shared Memory {name}(buffer image) File not found") def interaction_callback(circular_queue, showm, iren, render_after): @@ -257,23 +247,12 @@ def interaction_callback(circular_queue, showm, iren, render_after): camera.SetFocalPoint([pos2[i] + delta[i] for i in range(3)]) camera.Zoom(zoomFactor) elif user_event_id == event_ids.mouse_move: - iren.SetEventInformation(newX, - newY, - ctrl_key, - shift_key, - chr(0), 0, None) + iren.SetEventInformation(newX, newY, ctrl_key, shift_key, chr(0), 0, None) iren.MouseMoveEvent() elif event_ids.mouse_ids: - iren.SetEventInformation( - newX, - newY, - ctrl_key, - shift_key, - chr(0), - 0, - None) + iren.SetEventInformation(newX, newY, ctrl_key, shift_key, chr(0), 0, None) mouse_actions = { event_ids.left_btn_press: iren.LeftButtonPressEvent, event_ids.left_btn_release: iren.LeftButtonReleaseEvent, @@ -283,9 +262,7 @@ def interaction_callback(circular_queue, showm, iren, render_after): event_ids.right_btn_release: iren.RightButtonReleaseEvent, } mouse_actions[user_event_id]() - logging.info( - 'Interaction: time to perform event ' + f'{ts-user_timestamp:.2f} ms' - ) + logging.info("Interaction: time to perform event " + f"{ts-user_timestamp:.2f} ms") if render_after: showm.window.Render() showm.iren.Render() @@ -295,11 +272,7 @@ class FuryStreamInteraction: """This obj. is responsible to manage the user interaction""" 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. @@ -346,9 +319,9 @@ def start(self, ms=3, use_asyncio=False): separate thread. """ - use_asyncio = platform.system() == 'Windows' or use_asyncio + use_asyncio = platform.system() == "Windows" or use_asyncio if ms <= 0: - raise ValueError('ms must be greater than zero') + raise ValueError("ms must be greater than zero") if self._started: self.stop() @@ -362,14 +335,9 @@ def start(self, ms=3, use_asyncio=False): else: def callback(caller, event, *args, **kwargs): - interaction_callback( - self.circular_queue, - self.showm, self.iren, - True) + interaction_callback(self.circular_queue, self.showm, self.iren, True) - self._id_observer = self.showm.iren.AddObserver( - 'TimerEvent', - callback) + self._id_observer = self.showm.iren.AddObserver("TimerEvent", callback) self._id_timer = self.showm.iren.CreateRepeatingTimer(ms) self._started = True diff --git a/fury/stream/constants.py b/fury/stream/constants.py index db659e554..edff52b52 100644 --- a/fury/stream/constants.py +++ b/fury/stream/constants.py @@ -16,20 +16,20 @@ # 7 | RightButtonPressEvent # 8 | RightButtonReleaseEvent _event_ids = { - 'mouse_weel': 1, - 'mouse_move': 2, - 'mouse_ids': (3, 4, 5, 6, 7, 8), - 'left_btn_press': 3, - 'left_btn_release': 4, - 'middle_btn_press': 5, - 'middle_btn_release': 6, - 'right_btn_press': 7, - 'right_btn_release': 8, + "mouse_weel": 1, + "mouse_move": 2, + "mouse_ids": (3, 4, 5, 6, 7, 8), + "left_btn_press": 3, + "left_btn_release": 4, + "middle_btn_press": 5, + "middle_btn_release": 6, + "right_btn_press": 7, + "right_btn_release": 8, } # This immutable object it's used to avoid any kind of # mistake in assignment of event ids -_CQUEUE_EVENT_IDs = namedtuple('CQUEUE_EVENT_IDS', list(_event_ids.keys()))( +_CQUEUE_EVENT_IDs = namedtuple("CQUEUE_EVENT_IDS", list(_event_ids.keys()))( **_event_ids ) @@ -45,24 +45,24 @@ # 5 | shift_key state (1 pressed 0 otherwise) # 6 | js event timestamp in mileseconds (ufloat) _index_info = { - 'weel': 1, - 'x': 2, - 'y': 3, - 'ctrl': 4, - 'shift': 5, - 'user_timestamp': 6, + "weel": 1, + "x": 2, + "y": 3, + "ctrl": 4, + "shift": 5, + "user_timestamp": 6, } -_CQUEUE_INDEX_INFO = namedtuple('CQUEUE_INDEX_INFO', list(_index_info.keys()))( +_CQUEUE_INDEX_INFO = namedtuple("CQUEUE_INDEX_INFO", list(_index_info.keys()))( **_index_info ) # dimension it's also a important parameter # A wrong value can cause a silent error or a segmentation fault -_CQUEUE = namedtuple('CQUEUE', ['dimension', 'event_ids', 'index_info'])( +_CQUEUE = namedtuple("CQUEUE", ["dimension", "event_ids", "index_info"])( **{ - 'event_ids': _CQUEUE_EVENT_IDs, - 'index_info': _CQUEUE_INDEX_INFO, - 'dimension': 8, + "event_ids": _CQUEUE_EVENT_IDs, + "index_info": _CQUEUE_INDEX_INFO, + "dimension": 8, } ) diff --git a/fury/stream/server/__init__.py b/fury/stream/server/__init__.py index d606b03e4..af5b0e0ce 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 -__all__ = ['web_server', 'web_server_raw_array'] +__all__ = ["web_server", "web_server_raw_array"] diff --git a/fury/stream/server/async_app.py b/fury/stream/server/async_app.py index 56d57c2d0..eac612818 100644 --- a/fury/stream/server/async_app.py +++ b/fury/stream/server/async_app.py @@ -15,7 +15,7 @@ WEBRTC_AVAILABLE = True except ImportError: WEBRTC_AVAILABLE = False - print('webrtc not available') + print("webrtc not available") import logging import time @@ -27,20 +27,20 @@ async def index(request, **kwargs): - folder = kwargs['folder'] - just_mjpeg = kwargs['just_mjpeg'] - index_file = 'index.html' + folder = kwargs["folder"] + just_mjpeg = kwargs["just_mjpeg"] + index_file = "index.html" if just_mjpeg: - index_file = 'index_mjpeg.html' - content = open(os.path.join(folder, index_file), 'r').read() - return web.Response(content_type='text/html', text=content) + index_file = "index_mjpeg.html" + content = open(os.path.join(folder, index_file), "r").read() + return web.Response(content_type="text/html", text=content) async def javascript(request, **kwargs): - folder = kwargs['folder'] - js = kwargs['js'] - content = open(os.path.join(folder, 'js/%s' % js), 'r').read() - return web.Response(content_type='application/javascript', text=content) + folder = kwargs["folder"] + js = kwargs["js"] + content = open(os.path.join(folder, "js/%s" % js), "r").read() + return web.Response(content_type="application/javascript", text=content) async def mjpeg_handler(request): @@ -52,45 +52,44 @@ async def mjpeg_handler(request): endpoint : /video/mjpeg """ - my_boundary = 'image-boundary' + my_boundary = "image-boundary" response = web.StreamResponse( status=200, - reason='OK', + reason="OK", headers={ - 'Content-Type': 'multipart/x-mixed-replace;boundary={}'.format( - my_boundary) + "Content-Type": "multipart/x-mixed-replace;boundary={}".format(my_boundary) }, ) await response.prepare(request) - image_buffer_manager = request.app['image_buffer_manager'] + image_buffer_manager = request.app["image_buffer_manager"] while True: jpeg_bytes = await image_buffer_manager.async_get_jpeg() - with MultipartWriter('image/jpeg', boundary=my_boundary) as mpwriter: - mpwriter.append(jpeg_bytes, {'Content-Type': 'image/jpeg'}) + with MultipartWriter("image/jpeg", boundary=my_boundary) as mpwriter: + mpwriter.append(jpeg_bytes, {"Content-Type": "image/jpeg"}) try: await mpwriter.write(response, close_boundary=False) except ConnectionResetError: - logging.info('Client connection closed') + logging.info("Client connection closed") break - await response.write(b'\r\n') + await response.write(b"\r\n") async def offer(request, **kwargs): - video = kwargs['video'] - if 'broadcast' in kwargs and kwargs['broadcast']: + video = kwargs["video"] + if "broadcast" in kwargs and kwargs["broadcast"]: video = MediaRelay().subscribe(video) params = await request.json() - offer = RTCSessionDescription(sdp=params['sdp'], type=params['type']) + offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"]) pc = RTCPeerConnection() pcs.add(pc) - @pc.on('connectionstatechange') + @pc.on("connectionstatechange") async def on_connectionstatechange(): - print('Connection state is %s' % pc.connectionState) - if pc.connectionState == 'failed': + print("Connection state is %s" % pc.connectionState) + if pc.connectionState == "failed": await pc.close() pcs.discard(pc) @@ -99,54 +98,48 @@ async def on_connectionstatechange(): await pc.setRemoteDescription(offer) for t in pc.getTransceivers(): - if t.kind == 'audio' and audio: + if t.kind == "audio" and audio: pc.addTrack(audio) - elif t.kind == 'video' and video: + elif t.kind == "video" and video: pc.addTrack(video) answer = await pc.createAnswer() await pc.setLocalDescription(answer) return web.Response( - content_type='application/json', + content_type="application/json", text=json.dumps( - {'sdp': pc.localDescription.sdp, 'type': pc.localDescription.type} + {"sdp": pc.localDescription.sdp, "type": pc.localDescription.type} ), ) def set_weel(data, circular_queue): - deltaY = float(data['deltaY']) - user_envent_ms = float(data['timestampInMs']) + deltaY = float(data["deltaY"]) + user_envent_ms = float(data["timestampInMs"]) ok = circular_queue.enqueue( np.array( [EVENT_IDs.mouse_weel, deltaY, 0, 0, 0, 0, user_envent_ms, 0], - dtype='float64', + dtype="float64", ) ) ts = time.time() * 1000 - logging.info(f'WEEL Time until enqueue {ts-user_envent_ms:.2f} ms') + logging.info(f"WEEL Time until enqueue {ts-user_envent_ms:.2f} ms") return ok def set_mouse(data, circular_queue): - x = float(data['x']) - y = float(data['y']) - ctrl_key = int(data['ctrlKey']) - shift_key = int(data['shiftKey']) + x = float(data["x"]) + y = float(data["y"]) + ctrl_key = int(data["ctrlKey"]) + shift_key = int(data["shiftKey"]) - user_envent_ms = float(data['timestampInMs']) + user_envent_ms = float(data["timestampInMs"]) circular_queue = circular_queue ok = circular_queue.enqueue( np.array( - [EVENT_IDs.mouse_move, - 0, - x, - y, - ctrl_key, - shift_key, - user_envent_ms, 0], - dtype='float64', + [EVENT_IDs.mouse_move, 0, x, y, ctrl_key, shift_key, user_envent_ms, 0], + dtype="float64", ) ) @@ -161,13 +154,13 @@ def set_mouse_click(data, circular_queue): 7 | RightButtonPressEvent 8 | RightButtonReleaseEvent """ - on = 0 if data['on'] == 1 else 1 - ctrl = int(data['ctrlKey']) - shift = int(data['shiftKey']) - user_envent_ms = float(data['timestampInMs']) - x = float(data['x']) - y = float(data['y']) - mouse_button = int(data['mouseButton']) + on = 0 if data["on"] == 1 else 1 + ctrl = int(data["ctrlKey"]) + shift = int(data["shiftKey"]) + user_envent_ms = float(data["timestampInMs"]) + x = float(data["x"]) + y = float(data["y"]) + mouse_button = int(data["mouseButton"]) if mouse_button not in [0, 1, 2]: return False if ctrl not in [0, 1] or shift not in [0, 1]: @@ -175,8 +168,7 @@ def set_mouse_click(data, circular_queue): event_id = (mouse_button + 1) * 2 + on + 1 ok = circular_queue.enqueue( - np.array([event_id, 0, x, y, ctrl, shift, user_envent_ms, 0], - dtype='float64') + np.array([event_id, 0, x, y, ctrl, shift, user_envent_ms, 0], dtype="float64") ) return ok @@ -187,42 +179,38 @@ async def on_shutdown(app): coros = [pc.close() for pc in pcs] await asyncio.gather(*coros) pcs.clear() - for ws in set(app['websockets']): - await ws.close(code=WSCloseCode.GOING_AWAY, message='Server shutdown') + for ws in set(app["websockets"]): + await ws.close(code=WSCloseCode.GOING_AWAY, message="Server shutdown") async def websocket_handler(request, **kwargs): - - circular_queue = kwargs['circular_queue'] + circular_queue = kwargs["circular_queue"] ws = web.WebSocketResponse() await ws.prepare(request) - request.app['websockets'].add(ws) + request.app["websockets"].add(ws) try: async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: - if msg.data == 'close': + if msg.data == "close": await ws.close() else: data = json.loads(msg.data) logging.info(f'\nuser event time {data["timestampInMs"]}') - if data['type'] == 'weel': + if data["type"] == "weel": ts = time.time() * 1000 - interval = ts - data['timestampInMs'] - logging.info('WEEL request time approx ' + - f'{interval:.2f} ms') + interval = ts - data["timestampInMs"] + logging.info("WEEL request time approx " + f"{interval:.2f} ms") set_weel(data, circular_queue) - elif data['type'] == 'mouseMove': + elif data["type"] == "mouseMove": set_mouse(data, circular_queue) - elif data['type'] == 'mouseLeftClick': + elif data["type"] == "mouseLeftClick": set_mouse_click(data, circular_queue) # await ws.send_str(msg.data + '/answer') elif msg.type == aiohttp.WSMsgType.ERROR: - print('ws connection closed with exception {}'.format( - ws.exception()) - ) + print("ws connection closed with exception {}".format(ws.exception())) finally: - request.app['websockets'].discard(ws) + request.app["websockets"].discard(ws) return ws @@ -235,12 +223,11 @@ def get_app( provides_mjpeg=False, broadcast=True, ): - if folder is None: - folder = f'{os.path.dirname(__file__)}/www/' + folder = f"{os.path.dirname(__file__)}/www/" app = web.Application() - app['websockets'] = weakref.WeakSet() + app["websockets"] = weakref.WeakSet() app.on_shutdown.append(on_shutdown) @@ -252,33 +239,30 @@ def get_app( # ) # ) app.router.add_get( - '/', partial(index, folder=folder, just_mjpeg=rtc_server is None) + "/", partial(index, folder=folder, just_mjpeg=rtc_server is None) ) js_files = [ - 'main.js', - 'main_just_mjpeg.js', - 'webrtc.js', - 'constants.js', - 'interaction.js', + "main.js", + "main_just_mjpeg.js", + "webrtc.js", + "constants.js", + "interaction.js", ] for js in js_files: - app.router.add_get('/js/%s' % js, partial(javascript, - folder=folder, - js=js)) + app.router.add_get("/js/%s" % js, partial(javascript, folder=folder, js=js)) - app['image_buffer_manager'] = image_buffer_manager + app["image_buffer_manager"] = image_buffer_manager if provides_mjpeg: - app.router.add_get('/video/mjpeg', mjpeg_handler) + app.router.add_get("/video/mjpeg", mjpeg_handler) if rtc_server is not None: app.router.add_post( - '/offer', partial(offer, video=rtc_server, broadcast=broadcast) + "/offer", partial(offer, video=rtc_server, broadcast=broadcast) ) if circular_queue is not None: app.add_routes( - [web.get('/ws', partial(websocket_handler, - circular_queue=circular_queue))] + [web.get("/ws", partial(websocket_handler, circular_queue=circular_queue))] ) return app diff --git a/fury/stream/server/main.py b/fury/stream/server/main.py index d48a3aecd..1b7656857 100644 --- a/fury/stream/server/main.py +++ b/fury/stream/server/main.py @@ -81,14 +81,14 @@ async def recv(self): or self.frame.planes[0].height != height ): if CYTHON_AVAILABLE: - self.frame = FuryVideoFrame(width, height, 'rgb24') + self.frame = FuryVideoFrame(width, height, "rgb24") self.image = image if not CYTHON_AVAILABLE: # if the buffer it's already flipped # self.frame.planes[0].update(self.image) - self.image = np.frombuffer(self.image, 'uint8')[ - 0: width * height * 3 + self.image = np.frombuffer(self.image, "uint8")[ + 0 : width * height * 3 ].reshape((height, width, 3)) self.image = np.flipud(self.image) self.frame = VideoFrame.from_ndarray(self.image) @@ -117,7 +117,7 @@ def web_server_raw_array( queue_head_tail_buffer=None, queue_buffer=None, port=8000, - host='localhost', + host="localhost", provides_mjpeg=True, provides_webrtc=True, ms_jpeg=16, @@ -207,7 +207,7 @@ def web_server( queue_head_tail_buffer_name=None, queue_buffer_name=None, port=8000, - host='localhost', + host="localhost", provides_mjpeg=True, provides_webrtc=True, avoid_unlink_shared_mem=True, @@ -261,8 +261,7 @@ def web_server( remove_shm_from_resource_tracker() image_buffer_manager = SharedMemImageBufferManager( - image_buffer_names=image_buffer_names, - info_buffer_name=info_buffer_name + image_buffer_names=image_buffer_names, info_buffer_name=info_buffer_name ) rtc_server = None diff --git a/fury/stream/tools.py b/fury/stream/tools.py index 046e0fc1d..12d8eb9eb 100644 --- a/fury/stream/tools.py +++ b/fury/stream/tools.py @@ -42,9 +42,7 @@ def fix_register(name, rtype): if rtype == "shared_memory": return try: - return resource_tracker._resource_tracker.register( - self, name, rtype - ) + return resource_tracker._resource_tracker.register(self, name, rtype) except NameError: return None @@ -54,9 +52,7 @@ def fix_unregister(name, rtype): if rtype == "shared_memory": return try: - return resource_tracker._resource_tracker.unregister( - self, name, rtype - ) + return resource_tracker._resource_tracker.unregister(self, name, rtype) except NameError: return None @@ -211,13 +207,9 @@ def __init__(self, max_size, dimension=4, buffer_name=None): def create_mem_resource(self): self._num_el = self.dimension * (self.max_size + 1) buffer_arr = np.zeros(self._num_el + 2, dtype=_FLOAT_ShM_TYPE) - self._buffer = shared_memory.SharedMemory( - create=True, size=buffer_arr.nbytes - ) + self._buffer = shared_memory.SharedMemory(create=True, size=buffer_arr.nbytes) sizes = np.ndarray( - 2, - dtype=_FLOAT_ShM_TYPE, - buffer=self._buffer.buf[0: _FLOAT_SIZE * 2] + 2, dtype=_FLOAT_ShM_TYPE, buffer=self._buffer.buf[0 : _FLOAT_SIZE * 2] ) sizes[0] = self.max_size sizes[1] = self.dimension @@ -230,9 +222,7 @@ def create_mem_resource(self): def load_mem_resource(self): self._buffer = shared_memory.SharedMemory(self.buffer_name) - sizes = np.ndarray( - 2, dtype="d", buffer=self._buffer.buf[0: _FLOAT_SIZE * 2] - ) + sizes = np.ndarray(2, dtype="d", buffer=self._buffer.buf[0 : _FLOAT_SIZE * 2]) self.max_size = int(sizes[0]) self.dimension = int(sizes[1]) num_el = int((sizes[0] + 1) * sizes[1]) @@ -247,9 +237,7 @@ def _create_repr(self): start = _FLOAT_SIZE * 2 end = (self._num_el + 2) * _FLOAT_SIZE self._buffer_repr = np.ndarray( - self._num_el, - dtype=_FLOAT_ShM_TYPE, - buffer=self._buffer.buf[start:end] + self._num_el, dtype=_FLOAT_ShM_TYPE, buffer=self._buffer.buf[start:end] ) logging.info( [ @@ -327,9 +315,7 @@ def head(self): if self._use_shared_mem: return self.head_tail_buffer_repr[0] else: - return np.frombuffer( - self.head_tail_buffer.get_obj(), _INT_ShM_TYPE - )[0] + return np.frombuffer(self.head_tail_buffer.get_obj(), _INT_ShM_TYPE)[0] @head.setter def head(self, value): @@ -340,9 +326,7 @@ def tail(self): if self._use_shared_mem: return self.head_tail_buffer_repr[1] else: - return np.frombuffer( - self.head_tail_buffer.get_obj(), _INT_ShM_TYPE - )[1] + return np.frombuffer(self.head_tail_buffer.get_obj(), _INT_ShM_TYPE)[1] @tail.setter def tail(self, value): @@ -405,12 +389,7 @@ class ArrayCircularQueue(GenericCircularQueue): Arrays and RawArrays. """ - def __init__( - self, - max_size=10, - dimension=6, - head_tail_buffer=None, - buffer=None): + def __init__(self, max_size=10, dimension=6, head_tail_buffer=None, buffer=None): """Stream system uses that to implement user interactions Parameters @@ -431,11 +410,7 @@ def __init__( RawArray to store the data """ - super().__init__( - max_size, - dimension, - use_shared_mem=False, - buffer=buffer) + super().__init__(max_size, dimension, use_shared_mem=False, buffer=buffer) if head_tail_buffer is None: self.create_mem_resource() @@ -482,11 +457,7 @@ class SharedMemCircularQueue(GenericCircularQueue): """ 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 @@ -520,9 +491,7 @@ def __init__( self._created = False self.head_tail_buffer_repr = np.ndarray( - 3, - dtype=_INT_ShM_TYPE, - buffer=self.head_tail_buffer.buf[0: 3 * _INT_SIZE] + 3, dtype=_INT_ShM_TYPE, buffer=self.head_tail_buffer.buf[0 : 3 * _INT_SIZE] ) logging.info( [ @@ -537,8 +506,7 @@ def __init__( self.set_head_tail(-1, -1, 0) def load_mem_resource(self): - self.head_tail_buffer = shared_memory.SharedMemory( - self.head_tail_buffer_name) + self.head_tail_buffer = shared_memory.SharedMemory(self.head_tail_buffer_name) def create_mem_resource(self): # head_tail_arr[0] int; head position @@ -596,10 +564,7 @@ class GenericImageBufferManager(ABC): the n-buffer technique. """ - def __init__(self, - max_window_size=None, - num_buffers=2, - use_shared_mem=False): + def __init__(self, max_window_size=None, num_buffers=2, use_shared_mem=False): """Initialize the ImageBufferManager. Parameters @@ -633,8 +598,7 @@ def __init__(self, d = ImageDraw.Draw(img) pos_text = (12, size[1] // 2) d.text( - pos_text, "Image size have exceed the Buffer Max Size", - fill=(255, 255, 0) + pos_text, "Image size have exceed the Buffer Max Size", fill=(255, 255, 0) ) img = np.flipud(img) self.img_exceed = np.asarray(img).flatten() @@ -658,8 +622,7 @@ def write_into(self, w, h, np_arr): elif buffer_size < self.max_size: self.image_reprs[next_buffer_index][0:buffer_size] = np_arr else: - self.image_reprs[next_buffer_index][0: self.max_size] = ( - self.img_exceed) + self.image_reprs[next_buffer_index][0 : self.max_size] = self.img_exceed w = self.max_window_size[0] h = self.max_window_size[1] @@ -697,7 +660,7 @@ def get_jpeg(self): if self._use_shared_mem: image = np.frombuffer(image, _BYTE_ShM_TYPE) - image = image[0: width * height * 3].reshape((height, width, 3)) + image = image[0 : width * height * 3].reshape((height, width, 3)) image = np.flipud(image) image_encoded = Image.fromarray(image, mode="RGB") bytes_img_data = io.BytesIO() @@ -767,10 +730,7 @@ def create_mem_resource(self): buffer = multiprocessing.RawArray( _BYTE_ShM_TYPE, np.ctypeslib.as_ctypes( - np.random.randint(0, - 255, - size=self.max_size, - dtype=_BYTE_ShM_TYPE) + np.random.randint(0, 255, size=self.max_size, dtype=_BYTE_ShM_TYPE) ), ) self.image_buffers.append(buffer) @@ -850,14 +810,10 @@ def create_mem_resource(self): self.max_size *= self.num_components self.max_size = int(self.max_size) for _ in range(self.num_buffers): - buffer = shared_memory.SharedMemory( - create=True, - size=self.max_size) + buffer = shared_memory.SharedMemory(create=True, size=self.max_size) self.image_buffers.append(buffer) self.image_reprs.append( - np.ndarray(self.max_size, - dtype=_BYTE_ShM_TYPE, - buffer=buffer.buf) + np.ndarray(self.max_size, dtype=_BYTE_ShM_TYPE, buffer=buffer.buf) ) self.image_buffer_names.append(buffer.name) @@ -871,16 +827,14 @@ def create_mem_resource(self): create=True, size=info_list.nbytes ) sizes = np.ndarray( - 2, - dtype=_UINT_ShM_TYPE, - buffer=self.info_buffer.buf[0: _UINT_SIZE * 2] + 2, dtype=_UINT_ShM_TYPE, buffer=self.info_buffer.buf[0 : _UINT_SIZE * 2] ) sizes[0] = info_list[0] sizes[1] = 1 self.info_buffer_repr = np.ndarray( sizes[0], dtype=_UINT_ShM_TYPE, - buffer=self.info_buffer.buf[2 * _UINT_SIZE:], + buffer=self.info_buffer.buf[2 * _UINT_SIZE :], ) logging.info( [ @@ -896,14 +850,12 @@ def create_mem_resource(self): def load_mem_resource(self): self.info_buffer = shared_memory.SharedMemory(self.info_buffer_name) sizes = np.ndarray( - 2, - dtype=_UINT_ShM_TYPE, - buffer=self.info_buffer.buf[0: _UINT_SIZE * 2] + 2, dtype=_UINT_ShM_TYPE, buffer=self.info_buffer.buf[0 : _UINT_SIZE * 2] ) self.info_buffer_repr = np.ndarray( sizes[0], dtype=_UINT_ShM_TYPE, - buffer=self.info_buffer.buf[2 * _UINT_SIZE:], + buffer=self.info_buffer.buf[2 * _UINT_SIZE :], ) logging.info( [ @@ -919,9 +871,7 @@ def load_mem_resource(self): self.image_buffers.append(buffer) self.image_reprs.append( np.ndarray( - buffer.size // _BYTE_SIZE, - dtype=_BYTE_ShM_TYPE, - buffer=buffer.buf + buffer.size // _BYTE_SIZE, dtype=_BYTE_ShM_TYPE, buffer=buffer.buf ) ) @@ -940,7 +890,9 @@ def cleanup(self): f"Shared Memory {self.info_buffer_name}\ (info_buffer) File not found" ) - for buffer, name in zip(self.image_buffers, self.image_buffer_names): + for buffer, name in zip( + self.image_buffers, self.image_buffer_names, strict=False + ): buffer.close() if self._created: try: diff --git a/fury/stream/widget.py b/fury/stream/widget.py index a76d81141..469da2ca9 100644 --- a/fury/stream/widget.py +++ b/fury/stream/widget.py @@ -51,9 +51,9 @@ def __init__( showm, ms_stream=33, ms_interaction=33, - host='localhost', + host="localhost", port=None, - encoding='mjpeg', + encoding="mjpeg", ms_jpeg=33, queue_size=20, ): @@ -80,8 +80,8 @@ def __init__( """ if not PY_VERSION_8: raise ImportError( - 'Python 3.8 or greater is required to use the\ - widget class' + "Python 3.8 or greater is required to use the\ + widget class" ) self.showm = showm self.window_size = self.showm.size @@ -113,21 +113,21 @@ def command_string(self): command_string : str """ - s = 'from fury.stream.server import web_server;' - s += 'web_server(image_buffer_names=' - s += f'{self.stream.img_manager.image_buffer_names}' + s = "from fury.stream.server import web_server;" + s += "web_server(image_buffer_names=" + s += f"{self.stream.img_manager.image_buffer_names}" s += f",info_buffer_name='{self.stream.img_manager.info_buffer_name}'," s += "queue_head_tail_buffer_name='" s += f"{self.stream_interaction.circular_queue.head_tail_buffer_name}'" s += ",queue_buffer_name='" s += f"{self.stream_interaction.circular_queue.buffer.buffer_name}'" - if self.encoding == 'mjpeg': - s += ',provides_mjpeg=True' - s += f',ms_jpeg={self.ms_jpeg}' - s += ',provides_webrtc=False' + if self.encoding == "mjpeg": + s += ",provides_mjpeg=True" + s += f",ms_jpeg={self.ms_jpeg}" + s += ",provides_webrtc=False" s += f",port={self._port},host='{self._host}'," - s += 'avoid_unlink_shared_mem=True' - s += ')' + s += "avoid_unlink_shared_mem=True" + s += ")" return s def _start_fury_client(self, use_asyncio=False): @@ -156,8 +156,7 @@ def _start_fury_client(self, use_asyncio=False): use_raw_array=False, ) - self.stream_interaction.start(ms=self.ms_interaction, - use_asyncio=use_asyncio) + self.stream_interaction.start(ms=self.ms_interaction, use_asyncio=use_asyncio) self.stream.start(self.ms_stream, use_asyncio=use_asyncio) self._server_started = True self.pserver = None @@ -177,7 +176,7 @@ def run_command(self): return False if self._server_started: - args = [sys.executable, '-c', self.command_string] + args = [sys.executable, "-c", self.command_string] self.pserver = subprocess.Popen( args, # f'python -c "{self.command_string}"', @@ -190,14 +189,14 @@ def run_command(self): @property def url(self): """Return the url to access the server""" - url = f'http://{self._host}:{self._port}' - url += f'?iframe=1&encoding={self.encoding}' + url = f"http://{self._host}:{self._port}" + url += f"?iframe=1&encoding={self.encoding}" return url 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')) + display(IFrame(self.url, "100%", f"{int(height)}px")) def start(self, use_asyncio=False): """Start the fury client and the interaction client and return the url @@ -214,7 +213,7 @@ def start(self, use_asyncio=False): if not ok: self.stop() return False - print(f'url: {self.url}') + print(f"url: {self.url}") def display(self, height=150): """Start the server and display the url in an iframe""" diff --git a/fury/testing.py b/fury/testing.py index 0f4983dc6..b8d6fc1b3 100644 --- a/fury/testing.py +++ b/fury/testing.py @@ -37,50 +37,47 @@ def captured_output(): sys.stdout, sys.stderr = old_out, old_err -def assert_operator(value1, value2, msg='', op=operator.eq): +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 = 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}') +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}") assert_true = partial( - assert_operator, value2=True, op=operator.eq, msg='False is not true' + assert_operator, value2=True, op=operator.eq, msg="False is not true" ) assert_false = partial( - assert_operator, value2=False, op=operator.eq, msg='True is not false' + assert_operator, value2=False, op=operator.eq, msg="True is not false" ) assert_not_equal = partial(assert_operator, op=operator.ne) assert_equal = partial(assert_operator, op=operator.eq) def assert_arrays_equal(arrays1, arrays2): - for arr1, arr2 in zip(arrays1, arrays2): + for arr1, arr2 in zip(arrays1, arrays2, strict=False): assert_array_equal(arr1, arr2) class EventCounter: - def __init__( - self, - events_names=[ - 'CharEvent', - 'MouseMoveEvent', - 'KeyPressEvent', - 'KeyReleaseEvent', - 'LeftButtonPressEvent', - 'LeftButtonReleaseEvent', - 'RightButtonPressEvent', - 'RightButtonReleaseEvent', - 'MiddleButtonPressEvent', - 'MiddleButtonReleaseEvent', - ], - ): + def __init__(self, events_names=None): + if events_names is None: + events_names = [ + "CharEvent", + "MouseMoveEvent", + "KeyPressEvent", + "KeyReleaseEvent", + "LeftButtonPressEvent", + "LeftButtonReleaseEvent", + "RightButtonPressEvent", + "RightButtonReleaseEvent", + "MiddleButtonPressEvent", + "MiddleButtonReleaseEvent", + ] + # Events to count self.events_counts = {name: 0 for name in events_names} @@ -94,13 +91,13 @@ def monitor(self, ui_component): ui_component.add_callback(obj_actor, event, self.count) def save(self, filename): - with open(filename, 'w') as f: + with open(filename, "w") as f: json.dump(self.events_counts, f) @classmethod def load(cls, filename): event_counter = cls() - with open(filename, 'r') as f: + with open(filename, "r") as f: event_counter.events_counts = json.load(f) return event_counter @@ -109,17 +106,14 @@ def check_counts(self, expected): assert_equal(len(self.events_counts), len(expected.events_counts)) # Useful loop for debugging. - msg = '{}: {} vs. {} (expected)' + msg = "{}: {} vs. {} (expected)" for event, count in expected.events_counts.items(): if self.events_counts[event] != count: print(msg.format(event, self.events_counts[event], count)) 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): @@ -174,7 +168,7 @@ def __init__(self, record=True, modules=()): def __enter__(self): for mod in self.modules: - if hasattr(mod, '__warningregistry__'): + if hasattr(mod, "__warningregistry__"): mod_reg = mod.__warningregistry__ self._warnreg_copies[mod] = mod_reg.copy() mod_reg.clear() @@ -183,7 +177,7 @@ def __enter__(self): def __exit__(self, *exc_info): super(clear_and_catch_warnings, self).__exit__(*exc_info) for mod in self.modules: - if hasattr(mod, '__warningregistry__'): + if hasattr(mod, "__warningregistry__"): mod.__warningregistry__.clear() if mod in self._warnreg_copies: mod.__warningregistry__.update(self._warnreg_copies[mod]) @@ -200,15 +194,15 @@ def setup_test(): https://github.com/nipy/nibabel/pull/556 """ - if LooseVersion(np.__version__) >= LooseVersion('1.14'): - np.set_printoptions(legacy='1.13') + if LooseVersion(np.__version__) >= LooseVersion("1.14"): + np.set_printoptions(legacy="1.13") # Temporary fix until scipy release in October 2018 # must be removed after that # print the first occurrence of matching warnings for each location # (module + line number) where the warning is issued if ( - LooseVersion(np.__version__) >= LooseVersion('1.15') - and LooseVersion(scipy.version.short_version) <= '1.1.0' + LooseVersion(np.__version__) >= LooseVersion("1.15") + and LooseVersion(scipy.version.short_version) <= "1.1.0" ): - warnings.simplefilter('default') + warnings.simplefilter("default") diff --git a/fury/tests/test_actors.py b/fury/tests/test_actors.py index 318a2df4e..46625250d 100644 --- a/fury/tests/test_actors.py +++ b/fury/tests/test_actors.py @@ -16,16 +16,14 @@ from fury.optpkg import optional_package from fury.primitive import prim_sphere from fury.testing import ( - assert_equal, assert_greater, assert_greater_equal, - assert_less_equal, assert_not_equal, ) from fury.utils import primitives_count_from_actor, rotate, shallow_copy # dipy, have_dipy, _ = optional_package('dipy') -matplotlib, have_matplotlib, _ = optional_package('matplotlib') +matplotlib, have_matplotlib, _ = optional_package("matplotlib") # if have_dipy: # from dipy.data import get_sphere @@ -42,7 +40,6 @@ class Sphere: - vertices = None faces = None @@ -60,7 +57,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, "test_slicer.png", offscreen=True) if verbose: print(arr.sum()) @@ -82,7 +79,7 @@ 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') + fname = os.path.join(tmpdir, "slice.png") window.snapshot(scene, fname, offscreen=True) report = window.analyze_snapshot(fname, find_objects=True) npt.assert_equal(report.objects, 1) @@ -94,7 +91,7 @@ def test_slicer(verbose=False): scene.clear() - rgb = np.zeros((30, 30, 30, 3), dtype='f8') + rgb = np.zeros((30, 30, 30, 3), dtype="f8") rgb[..., 0] = 255 rgb_actor = actor.slicer(rgb) @@ -141,7 +138,7 @@ 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 = actor.slicer(data, affine, interpolation="nearest") slicer.display(None, None, 25) scene.add(slicer) @@ -163,7 +160,7 @@ def test_surface(): from scipy.spatial import Delaunay size = 11 - vertices = list() + vertices = [] for i in range(-size, size): for j in range(-size, size): fact1 = -math.sin(i) * math.cos(j) @@ -179,7 +176,7 @@ def test_surface(): c_loop = [None, c_arr] f_loop = [None, faces] - s_loop = [None, 'butterfly', 'loop'] + s_loop = [None, "butterfly", "loop"] for smooth_type in s_loop: for face in f_loop: @@ -190,13 +187,12 @@ 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, "test_surface.png", offscreen=True) report = window.analyze_snapshot(arr, find_objects=True) npt.assert_equal(report.objects, 1) def test_contour_from_roi(interactive=False): - # Render volume scene = window.Scene() data = np.zeros((50, 50, 50)) @@ -232,8 +228,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, "test_surface.png", offscreen=True) + arr2 = window.snapshot(scene2, "test_surface2.png", offscreen=True) report = window.analyze_snapshot(arr, find_objects=True) report2 = window.analyze_snapshot(arr2, find_objects=True) @@ -244,12 +240,12 @@ def test_contour_from_roi(interactive=False): @pytest.mark.skipif( skip_osx, - reason='This test does not work on macOS + ' - 'Travis. It works on a local machine' - ' with 3 different version of VTK. There' - ' are 2 problems to check: Travis macOS' - ' vs Azure macOS and an issue with' - ' vtkAssembly + actor opacity.', + reason="This test does not work on macOS + " + "Travis. It works on a local machine" + " with 3 different version of VTK. There" + " are 2 problems to check: Travis macOS" + " vs Azure macOS and an issue with" + " vtkAssembly + actor opacity.", ) def test_contour_from_label(interactive=False): # Render volume @@ -291,10 +287,10 @@ def test_contour_from_label(interactive=False): window.show(scene2) arr = window.snapshot( - scene, 'test_surface.png', offscreen=True, order_transparent=False + scene, "test_surface.png", offscreen=True, order_transparent=False ) arr2 = window.snapshot( - scene2, 'test_surface2.png', offscreen=True, order_transparent=True + scene2, "test_surface2.png", offscreen=True, order_transparent=True ) report = window.analyze_snapshot( @@ -354,7 +350,7 @@ def test_streamtube_and_line_actors(): shader_obj = c3.GetShaderProperty() mapper_code = shader_obj.GetGeometryShaderCode() - file_code = shaders.import_fury_shader('line.geom') + file_code = shaders.import_fury_shader("line.geom") npt.assert_equal(mapper_code, file_code) npt.assert_equal(c3.GetProperty().GetRenderLinesAsTubes(), True) @@ -404,7 +400,7 @@ def test_bundle_maps(): line = actor.line(bundle, metric, linewidth=0.1, lookup_colormap=lut) scene.add(line) - scene.add(actor.scalar_bar(lut, ' ')) + scene.add(actor.scalar_bar(lut, " ")) report = window.analyze_scene(scene) @@ -422,7 +418,7 @@ def test_bundle_maps(): # window.show(scene) report = window.analyze_scene(scene) - npt.assert_equal(report.actors_classnames[0], 'vtkLODActor') + npt.assert_equal(report.actors_classnames[0], "vtkLODActor") scene.clear() @@ -434,7 +430,7 @@ def test_bundle_maps(): # window.show(scene) report = window.analyze_scene(scene) - npt.assert_equal(report.actors_classnames[0], 'vtkLODActor') + npt.assert_equal(report.actors_classnames[0], "vtkLODActor") # window.show(scene) arr = window.snapshot(scene) @@ -456,7 +452,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("repulsion100", True) sphere = Sphere() sphere.vertices = vertices sphere.faces = faces @@ -477,12 +473,12 @@ def test_odf_slicer(interactive=False): # Test that affine and mask work odf_actor = actor.odf_slicer( - odfs, sphere=sphere, affine=affine, mask=mask, scale=0.25, colormap='blues' + odfs, sphere=sphere, affine=affine, mask=mask, scale=0.25, colormap="blues" ) k = 2 - I, J, _ = odfs.shape[:3] - odf_actor.display_extent(0, I - 1, 0, J - 1, k, k) + i, j, _ = odfs.shape[:3] + odf_actor.display_extent(0, i - 1, 0, j - 1, k, k) scene = window.Scene() scene.add(odf_actor) @@ -502,7 +498,7 @@ def test_odf_slicer(interactive=False): sphere=sphere, mask=mask, scale=0.25, - colormap='blues', + colormap="blues", norm=False, global_cm=True, ) @@ -542,7 +538,7 @@ def test_odf_slicer(interactive=False): sphere=sphere, mask=mask, scale=0.25, - colormap='blues', + colormap="blues", norm=False, global_cm=True, ) @@ -566,7 +562,7 @@ def test_odf_slicer(interactive=False): global_cm=True, ) - vertices2, faces2 = prim_sphere('repulsion200', True) + vertices2, faces2 = prim_sphere("repulsion200", True) sphere2 = Sphere() sphere2.vertices = vertices2 sphere2.faces = faces2 @@ -599,7 +595,7 @@ def test_odf_slicer(interactive=False): def test_peak_slicer(interactive=False): - _peak_dirs = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype='f4') + _peak_dirs = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype="f4") # peak_dirs.shape = (1, 1, 1) + peak_dirs.shape peak_dirs = np.zeros((11, 11, 11, 3, 3)) @@ -663,7 +659,7 @@ def test_peak_slicer(interactive=False): window.show(scene) report = window.analyze_scene(scene) - ex = ['vtkLODActor', 'vtkLODActor', 'vtkOpenGLActor'] + ex = ["vtkLODActor", "vtkLODActor", "vtkOpenGLActor"] npt.assert_equal(report.actors_classnames, ex) # 6d data @@ -734,7 +730,6 @@ def test_peak(): # @pytest.mark.skipif(not have_dipy, reason="Requires DIPY") def test_tensor_slicer(interactive=False): - evals = np.array([1.4, 0.35, 0.35]) * 10 ** (-3) evecs = np.eye(3) @@ -744,7 +739,7 @@ def test_tensor_slicer(interactive=False): mevals[..., :] = evals mevecs[..., :, :] = evecs - vertices, faces = prim_sphere('symmetric724', True) + vertices, faces = prim_sphere("symmetric724", True) sphere = Sphere() sphere.vertices = vertices sphere.faces = faces @@ -896,8 +891,8 @@ 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) + npt.assert_raises(ExpiredDeprecationError, actor.label, "FURY Rocks") + text_actor = actor.vector_text("FURY Rocks", direction=None) scene = window.Scene() scene.add(text_actor) @@ -909,35 +904,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("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("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("FURY Rocks", direction=(1, 1, 1)) + text_actor_rot_2 = actor.vector_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("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 + "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', + "FURY Rocks", scale=(0.2, 0.2, 0.2), direction=None, align_center=True, @@ -991,7 +986,7 @@ def test_spheres(interactive=False): # test faces and vertices scene.clear() - vertices, faces = fp.prim_sphere(name='symmetric362', gen_faces=False) + vertices, faces = fp.prim_sphere(name="symmetric362", gen_faces=False) sphere_actor = actor.sphere( centers=xyzr[:, :3], colors=colors[:], @@ -1139,7 +1134,7 @@ def test_basic_geometry_actor(interactive=False): arr = window.snapshot(scene) report = window.analyze_snapshot(arr, colors=colors) - msg = 'Failed with {}, scale={}'.format(act_func.__name__, scale) + msg = "Failed with {}, scale={}".format(act_func.__name__, scale) npt.assert_equal(report.objects, 3, err_msg=msg) @@ -1150,10 +1145,10 @@ def test_advanced_geometry_actor(interactive=False): heights = np.array([5, 7, 10]) actor_list = [ - [actor.cone, {'heights': heights, 'resolution': 8}], - [actor.arrow, {'scales': heights, 'resolution': 9}], - [actor.cylinder, {'heights': heights, 'resolution': 10}], - [actor.disk, {'rinner': 4, 'router': 8, 'rresolution': 2, 'cresolution': 2}], + [actor.cone, {"heights": heights, "resolution": 8}], + [actor.arrow, {"scales": heights, "resolution": 9}], + [actor.cylinder, {"heights": heights, "resolution": 10}], + [actor.disk, {"rinner": 4, "router": 8, "rresolution": 2, "cresolution": 2}], ] scene = window.Scene() @@ -1187,34 +1182,34 @@ def test_advanced_geometry_actor(interactive=False): def test_text_3d(): - msg = 'I \nlove\n FURY' + msg = "I \nlove\n FURY" txt_actor = actor.text_3d(msg) npt.assert_equal(txt_actor.get_message().lower(), msg.lower()) - npt.assert_raises(ValueError, txt_actor.justification, 'middle') - npt.assert_raises(ValueError, txt_actor.vertical_justification, 'center') + npt.assert_raises(ValueError, txt_actor.justification, "middle") + npt.assert_raises(ValueError, txt_actor.vertical_justification, "center") scene = window.Scene() scene.add(txt_actor) - txt_actor.vertical_justification('middle') - txt_actor.justification('right') + txt_actor.vertical_justification("middle") + txt_actor.justification("right") arr_right = window.snapshot(scene, size=(1920, 1080), offscreen=True) scene.clear() - txt_actor.vertical_justification('middle') - txt_actor.justification('left') + txt_actor.vertical_justification("middle") + txt_actor.justification("left") scene.add(txt_actor) arr_left = window.snapshot(scene, size=(1920, 1080), offscreen=True) # X axis of right alignment should have a higher center of mass position # than left assert_greater(center_of_mass(arr_right)[0], center_of_mass(arr_left)[0]) scene.clear() - txt_actor.justification('center') - txt_actor.vertical_justification('top') + txt_actor.justification("center") + txt_actor.vertical_justification("top") scene.add(txt_actor) arr_top = window.snapshot(scene, size=(1920, 1080), offscreen=True) scene.clear() - txt_actor.justification('center') - txt_actor.vertical_justification('bottom') + txt_actor.justification("center") + txt_actor.vertical_justification("bottom") scene.add(txt_actor) arr_bottom = window.snapshot(scene, size=(1920, 1080), offscreen=True) assert_greater_equal(center_of_mass(arr_top)[0], center_of_mass(arr_bottom)[0]) @@ -1274,27 +1269,27 @@ def test_grid(_interactive=False): texts = [] actors.append(contour_actor1) - text_actor1 = actor.text_3d('cube 1', justification='center') + text_actor1 = actor.text_3d("cube 1", justification="center") texts.append(text_actor1) actors.append(contour_actor2) - text_actor2 = actor.text_3d('cube 2', justification='center') + text_actor2 = actor.text_3d("cube 2", justification="center") texts.append(text_actor2) actors.append(contour_actor3) - text_actor3 = actor.text_3d('cube 3', justification='center') + text_actor3 = actor.text_3d("cube 3", justification="center") texts.append(text_actor3) actors.append(shallow_copy(contour_actor1)) - text_actor1 = 'cube 4' + text_actor1 = "cube 4" texts.append(text_actor1) actors.append(shallow_copy(contour_actor2)) - text_actor2 = 'cube 5' + text_actor2 = "cube 5" texts.append(text_actor2) actors.append(shallow_copy(contour_actor3)) - text_actor3 = 'cube 6' + text_actor3 = "cube 6" texts.append(text_actor3) # show the grid without the captions @@ -1308,7 +1303,7 @@ def test_grid(_interactive=False): scene.add(container) - scene.projection('orthogonal') + scene.projection("orthogonal") counter = itertools.count() @@ -1356,7 +1351,7 @@ def timer_callback(_obj, _event): def test_direct_sphere_mapping(): - arr = 255 * np.ones((810, 1620, 3), dtype='uint8') + arr = 255 * np.ones((810, 1620, 3), dtype="uint8") rows, cols, _ = arr.shape rs = rows // 2 @@ -1378,7 +1373,7 @@ def test_direct_sphere_mapping(): def test_texture_mapping(): - arr = np.zeros((512, 212, 3), dtype='uint8') + arr = np.zeros((512, 212, 3), dtype="uint8") arr[:256, :] = np.array([255, 0, 0]) arr[256:, :] = np.array([0, 255, 0]) tp = actor.texture(arr, interp=True) @@ -1395,7 +1390,7 @@ def test_texture_mapping(): def test_texture_update(): - arr = np.zeros((512, 212, 3), dtype='uint8') + arr = np.zeros((512, 212, 3), dtype="uint8") arr[:256, :] = np.array([255, 0, 0]) arr[256:, :] = np.array([0, 255, 0]) # create a texture on plane @@ -1411,7 +1406,7 @@ def test_texture_update(): ) # update the texture - new_arr = np.zeros((512, 212, 3), dtype='uint8') + new_arr = np.zeros((512, 212, 3), dtype="uint8") new_arr[:, :] = np.array([255, 255, 255]) actor.texture_update(tp, new_arr) display = window.snapshot(scene) @@ -1429,11 +1424,11 @@ def test_texture_update(): def test_figure_vs_texture_actor(): - arr = (255 * np.ones((512, 212, 4))).astype('uint8') + arr = (255 * np.ones((512, 212, 4))).astype("uint8") arr[20:40, 20:40, 3] = 0 tp = actor.figure(arr) - arr[20:40, 20:40, :] = np.array([255, 0, 0, 255], dtype='uint8') + arr[20:40, 20:40, :] = np.array([255, 0, 0, 255], dtype="uint8") tp2 = actor.texture(arr) scene = window.Scene() scene.add(tp) @@ -1449,9 +1444,9 @@ def test_figure_vs_texture_actor(): npt.assert_equal(res.colors_found, [True, True]) -@pytest.mark.skipif(not have_matplotlib, reason='Requires MatplotLib') +@pytest.mark.skipif(not have_matplotlib, reason="Requires MatplotLib") def test_matplotlib_figure(): - names = ['group_a', 'group_b', 'group_c'] + names = ["group_a", "group_b", "group_c"] values = [1, 10, 100] fig = plt.figure(figsize=(9, 3)) @@ -1462,12 +1457,12 @@ def test_matplotlib_figure(): plt.scatter(names, values) plt.subplot(133) plt.plot(names, values) - plt.suptitle('Categorical Plotting') + plt.suptitle("Categorical Plotting") 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') + plt.close("all") + fig_actor = actor.figure(arr, "cubic") + fig_actor2 = actor.figure(arr, "cubic") scene = window.Scene() scene.background((1, 1, 1.0)) @@ -1478,9 +1473,9 @@ 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, "test_mpl.png", order_transparent=False, offscreen=True ) - res = window.analyze_snapshot( + _ = window.analyze_snapshot( display, bg_color=(255, 255, 255.0), colors=[(31, 119, 180)], find_objects=False ) # omit assert from now until we know why snapshot creates @@ -1577,10 +1572,10 @@ def test_billboard_actor(interactive=False): npt.assert_equal(report.objects, 8) scene.clear() - centers = np.array([[0, 0, 0], [-15, 15, -5], [10, -10, 5], - [-30, 30, -10], [20, -20, 10]]) - colors = np.array([[1, 1, 0], [0, 0, 1], [1, 0, 1], - [1, 0, 0], [0, 1, 0]]) + centers = np.array( + [[0, 0, 0], [-15, 15, -5], [10, -10, 5], [-30, 30, -10], [20, -20, 10]] + ) + colors = np.array([[1, 1, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0], [0, 1, 0]]) scales = [3, 1, 2, 1, 1.5] b_point = """ @@ -1592,15 +1587,16 @@ def test_billboard_actor(interactive=False): {fragOutput0 = vec4(color, 1);} """ - b_type = ['spherical', 'cylindrical_x', 'cylindrical_y'] + b_type = ["spherical", "cylindrical_x", "cylindrical_y"] expected_val = [True, False, False] rotations = [[87, 0, -87, 87], [87, 0, -87, 87], [0, 87, 87, -87]] for i in range(3): - billboard = actor.billboard(centers, colors=colors, scales=scales, - bb_type=b_type[i], fs_impl=b_point) + billboard = actor.billboard( + centers, colors=colors, scales=scales, bb_type=b_type[i], fs_impl=b_point + ) scene.add(billboard) - if b_type[i] == 'spherical': + if b_type[i] == "spherical": arr = window.snapshot(scene) report = window.analyze_snapshot(arr, colors=255 * colors) npt.assert_equal(report.colors_found, [True] * 5) @@ -1633,10 +1629,10 @@ def test_billboard_actor(interactive=False): @pytest.mark.skipif( skip_win, - reason='This test does not work on Windows' - ' due to snapshot (memory access' - ' violation). Check what is causing this' - ' issue with shader', + reason="This test does not work on Windows" + " due to snapshot (memory access" + " violation). Check what is causing this" + " issue with shader", ) def test_sdf_actor(interactive=False): scene = window.Scene() @@ -1645,7 +1641,7 @@ def test_sdf_actor(interactive=False): colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0]]) directions = np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1], [1, 1, 0]]) scales = [1, 2, 3, 4] - primitive = ['sphere', 'ellipsoid', 'torus', 'capsule'] + primitive = ["sphere", "ellipsoid", "torus", "capsule"] sdf_actor = actor.sdf(centers, directions, colors, primitive, scales) scene.add(sdf_actor) @@ -1659,7 +1655,7 @@ def test_sdf_actor(interactive=False): # Draw 3 spheres as the primitive type is str scene.clear() - primitive = 'sphere' + primitive = "sphere" sdf_actor = actor.sdf(centers, directions, colors, primitive, scales) scene.add(sdf_actor) scene.add(actor.axes()) @@ -1673,7 +1669,7 @@ def test_sdf_actor(interactive=False): # A sphere and default back to two torus # as the primitive type is list scene.clear() - primitive = ['sphere'] + primitive = ["sphere"] with npt.assert_warns(UserWarning): sdf_actor = actor.sdf(centers, directions, colors, primitive, scales) @@ -1689,7 +1685,7 @@ def test_sdf_actor(interactive=False): # One sphere and ellipsoid each # Default to torus scene.clear() - primitive = ['sphere', 'ellipsoid'] + primitive = ["sphere", "ellipsoid"] with npt.assert_warns(UserWarning): sdf_actor = actor.sdf(centers, directions, colors, primitive, scales) @@ -1705,17 +1701,17 @@ def test_sdf_actor(interactive=False): @pytest.mark.skipif( skip_linux, - reason='This test does not work on Ubuntu. It ' - 'works on a local machine. Check after ' - 'fixing memory leak with RenderWindow.', + reason="This test does not work on Ubuntu. It " + "works on a local machine. Check after " + "fixing memory leak with RenderWindow.", ) def test_marker_actor(interactive=False): scene = window.Scene() scene.background((1, 1, 1)) centers_3do = np.array([[4, 0, 0], [4, 4, 0], [4, 8, 0]]) - markers_2d = ['o', 's', 'd', '^', 'p', 'h', 's6', 'x', '+'] + markers_2d = ["o", "s", "d", "^", "p", "h", "s6", "x", "+"] center_markers_2d = np.array([[0, i * 2, 0] for i in range(len(markers_2d))]) - fake_spheres = actor.markers(centers_3do, colors=(0, 1, 0), scales=1, marker='3d') + fake_spheres = actor.markers(centers_3do, colors=(0, 1, 0), scales=1, marker="3d") markers_2d = actor.markers( center_markers_2d, colors=(0, 1, 0), scales=1, marker=markers_2d ) @@ -1735,33 +1731,47 @@ def test_marker_actor(interactive=False): def test_ellipsoid_actor(interactive=False): # number of axes does not match with number of centers centers = [-1, 1, 0] - axes = [[[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[1, 2, -2], [2, 1, 2], [2, -2, -1]]] + axes = [[[1, 0, 0], [0, 1, 0], [0, 0, 1]], [[1, 2, -2], [2, 1, 2], [2, -2, -1]]] lengths = [[1, 1, 1]] npt.assert_raises(ValueError, actor.ellipsoid, centers, axes, lengths) # number of lengths does not match with number of centers - lengths = [[1, 1, 1], [1, 1, .5]] + lengths = [[1, 1, 1], [1, 1, 0.5]] npt.assert_raises(ValueError, actor.ellipsoid, centers, axes, lengths) scene = window.Scene() scene.background((0, 0, 0)) - axes = np.array([[[-.6, .5, -.6], [-.8, -.4, .5], [-.1, -.7, -.7]], - [[.1, .6, -.8], [.6, .5, .5], [-.8, .6, .3]], - [[.7, .5, -.5], [0, -.7, -.7], [-.7, .6, -.5]], - [[.7, -.3, -.6], [.2, -.8, .6], [.7, .6, .5]], - [[1, 2, -2], [2, 1, 2], [2, -2, -1]], - [[1, 0, 0], [0, 1, 0], [0, 0, 1]]]) - lengths = np.array([[1, 1, 1], [1, 1, .5], [1, .5, .5], - [1, .5, .25], [1, 1, .3], [1, .3, .3]]) - centers = np.array([[-1, 1, 0], [0, 1, 0], [1, 1, 0], - [-1, 0, 0], [0, 0, 0], [1, 0, 0]]) - colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], - [1, 1, 0], [1, 0, 1], [0, 1, 1]]) - - ellipsoids = actor.ellipsoid(axes=axes, lengths=lengths, centers=centers, - scales=1.0, colors=colors) + axes = np.array( + [ + [[-0.6, 0.5, -0.6], [-0.8, -0.4, 0.5], [-0.1, -0.7, -0.7]], + [[0.1, 0.6, -0.8], [0.6, 0.5, 0.5], [-0.8, 0.6, 0.3]], + [[0.7, 0.5, -0.5], [0, -0.7, -0.7], [-0.7, 0.6, -0.5]], + [[0.7, -0.3, -0.6], [0.2, -0.8, 0.6], [0.7, 0.6, 0.5]], + [[1, 2, -2], [2, 1, 2], [2, -2, -1]], + [[1, 0, 0], [0, 1, 0], [0, 0, 1]], + ] + ) + lengths = np.array( + [ + [1, 1, 1], + [1, 1, 0.5], + [1, 0.5, 0.5], + [1, 0.5, 0.25], + [1, 1, 0.3], + [1, 0.3, 0.3], + ] + ) + centers = np.array( + [[-1, 1, 0], [0, 1, 0], [1, 1, 0], [-1, 0, 0], [0, 0, 0], [1, 0, 0]] + ) + colors = np.array( + [[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0], [1, 0, 1], [0, 1, 1]] + ) + + ellipsoids = actor.ellipsoid( + axes=axes, lengths=lengths, centers=centers, scales=1.0, colors=colors + ) scene.add(ellipsoids) if interactive: @@ -1784,23 +1794,39 @@ def test_uncertainty_cone_actor(interactive=False): mevecs[..., :, :] = evecs signal = np.ones((10, 10, 1, 10)) - sigma = np.array([14.791911, 14.999622, 14.880976, 14.933881, 14.392784, - 14.132468, 14.334953, 14.409375, 14.514647, 14.409275]) - - b_matrix = np.array([[-1.8, -1.9, -4.8, -4.4, -2.3, -1.2, -1.0], - [-5.4, -1.8, -1.6, -1.7, -6.1, -1.3, -1.0], - [-6.2, -5.1, -1.0, -1.9, -9.3, -2.2, -1.0], - [-2.8, -1.9, -4.8, -1.4, -2.1, -3.6, -1.0], - [-5.6, -1.3, -7.8, -2.4, -5.2, -4.2, -1.0], - [-1.8, -2.5, -1.8, -1.2, -2.3, -4.8, -1.0], - [-2.3, -1.9, -6.8, -4.4, -6.4, -1.9, -1.0], - [-1.8, -2.6, -4.8, -6.5, -7.7, -3.1, -1.0], - [-6.2, -1.9, -5.6, -4.6, -1.5, -2.0, -1.0], - [-2.4, -1.9, -4.5, -3.6, -2.5, -1.2, -1.0]]) - - uncert_cones = actor.uncertainty_cone(evecs=mevecs, evals=mevals, - signal=signal, sigma=sigma, - b_matrix=b_matrix) + sigma = np.array( + [ + 14.791911, + 14.999622, + 14.880976, + 14.933881, + 14.392784, + 14.132468, + 14.334953, + 14.409375, + 14.514647, + 14.409275, + ] + ) + + b_matrix = np.array( + [ + [-1.8, -1.9, -4.8, -4.4, -2.3, -1.2, -1.0], + [-5.4, -1.8, -1.6, -1.7, -6.1, -1.3, -1.0], + [-6.2, -5.1, -1.0, -1.9, -9.3, -2.2, -1.0], + [-2.8, -1.9, -4.8, -1.4, -2.1, -3.6, -1.0], + [-5.6, -1.3, -7.8, -2.4, -5.2, -4.2, -1.0], + [-1.8, -2.5, -1.8, -1.2, -2.3, -4.8, -1.0], + [-2.3, -1.9, -6.8, -4.4, -6.4, -1.9, -1.0], + [-1.8, -2.6, -4.8, -6.5, -7.7, -3.1, -1.0], + [-6.2, -1.9, -5.6, -4.6, -1.5, -2.0, -1.0], + [-2.4, -1.9, -4.5, -3.6, -2.5, -1.2, -1.0], + ] + ) + + uncert_cones = actor.uncertainty_cone( + evecs=mevecs, evals=mevals, signal=signal, sigma=sigma, b_matrix=b_matrix + ) scene.add(uncert_cones) if interactive: @@ -1820,9 +1846,9 @@ def test_uncertainty_cone_actor(interactive=False): mevecs[..., :, :] = evecs signal = np.ones((4, 4, 4, 10)) - uncert_cones = actor.uncertainty_cone(evecs=mevecs, evals=mevals, - signal=signal, sigma=sigma, - b_matrix=b_matrix) + uncert_cones = actor.uncertainty_cone( + evecs=mevecs, evals=mevals, signal=signal, sigma=sigma, b_matrix=b_matrix + ) scene.add(uncert_cones) if interactive: @@ -1839,9 +1865,9 @@ def test_actors_primitives_count(): colors = np.array([[1, 0, 0], [1, 0, 0]]) lines = np.array([[[0, 0, 0], [1, 1, 1]], [[1, 1, 1], [2, 2, 2]]]) - args_1 = {'centers': centers} - args_2 = {**args_1, 'colors': colors} - args_3 = {**args_2, 'directions': directions} + args_1 = {"centers": centers} + args_2 = {**args_1, "colors": colors} + args_3 = {**args_2, "directions": directions} cen_c = len(centers) lin_c = len(lines) @@ -1851,8 +1877,8 @@ def test_actors_primitives_count(): [actor.rectangle, args_1, cen_c], [actor.square, args_1, cen_c], [actor.cube, args_1, cen_c], - [actor.sphere, {**args_2, 'use_primitive': True}, cen_c], - [actor.sphere, {**args_2, 'use_primitive': False}, cen_c], + [actor.sphere, {**args_2, "use_primitive": True}, cen_c], + [actor.sphere, {**args_2, "use_primitive": False}, cen_c], [actor.sdf, args_1, cen_c], [actor.billboard, args_1, cen_c], [actor.superquadric, args_1, cen_c], @@ -1864,14 +1890,14 @@ def test_actors_primitives_count(): [actor.rhombicuboctahedron, args_1, cen_c], [actor.cylinder, args_3, cen_c], [actor.disk, args_3, cen_c], - [actor.cone, {**args_3, 'use_primitive': False}, cen_c], - [actor.cone, {**args_3, 'use_primitive': True}, cen_c], - [actor.arrow, {**args_3, 'repeat_primitive': False}, cen_c], - [actor.arrow, {**args_3, 'repeat_primitive': True}, cen_c], - [actor.dot, {'points': centers}, cen_c], - [actor.point, {'points': centers, 'colors': colors}, cen_c], - [actor.line, {'lines': lines}, lin_c], - [actor.streamtube, {'lines': lines}, lin_c], + [actor.cone, {**args_3, "use_primitive": False}, cen_c], + [actor.cone, {**args_3, "use_primitive": True}, cen_c], + [actor.arrow, {**args_3, "repeat_primitive": False}, cen_c], + [actor.arrow, {**args_3, "repeat_primitive": True}, cen_c], + [actor.dot, {"points": centers}, cen_c], + [actor.point, {"points": centers, "colors": colors}, cen_c], + [actor.line, {"lines": lines}, lin_c], + [actor.streamtube, {"lines": lines}, lin_c], ] for test_case in actors_test_cases: act_func = test_case[0] diff --git a/fury/tests/test_colormap.py b/fury/tests/test_colormap.py index 9ecac9235..7c5bf751c 100644 --- a/fury/tests/test_colormap.py +++ b/fury/tests/test_colormap.py @@ -6,7 +6,7 @@ from fury import colormap from fury.optpkg import optional_package -cm, have_matplotlib, _ = optional_package('matplotlib.cm') +cm, have_matplotlib, _ = optional_package("matplotlib.cm") def test_boys2rgb(): @@ -20,7 +20,7 @@ def test_boys2rgb(): v1 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) v2 = np.array([1, 0, 0, 0, 1, 0]) - for v, e in zip([v1, v2], [expected, expected[0]]): + for v, e in zip([v1, v2], [expected, expected[0]], strict=False): c = colormap.boys2rgb(v) npt.assert_array_almost_equal(c, e) @@ -35,8 +35,8 @@ def test_orient2rgb(): def test_get_cmap(): - npt.assert_equal(colormap.get_cmap(''), None) - npt.assert_equal(colormap.get_cmap('blues'), None) + npt.assert_equal(colormap.get_cmap(""), None) + npt.assert_equal(colormap.get_cmap("blues"), None) expected = np.array( [ @@ -52,11 +52,11 @@ def test_get_cmap(): [0.498039, 0.788235, 0.498039, 1], ] ) - cmap = colormap.get_cmap('Blues') + cmap = colormap.get_cmap("Blues") npt.assert_array_almost_equal(cmap((1, 0, 0)), expected) with npt.assert_warns(PendingDeprecationWarning): - cmap = colormap.get_cmap('Accent') + cmap = colormap.get_cmap("Accent") npt.assert_array_almost_equal(cmap((1, 0, 0)), expected2) @@ -65,19 +65,19 @@ def test_line_colors(): s2 = np.array([np.arange(5)] * 4) # 5x4 streamlines = [s1, s2] - s_color = colormap.line_colors(streamlines, cmap='boys_standard') + s_color = colormap.line_colors(streamlines, cmap="boys_standard") npt.assert_equal(s_color.shape, (2, 3)) 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(AttributeError, colormap.create_colormap, value, name="fake") npt.assert_warns( PendingDeprecationWarning, colormap.create_colormap, value, - name='jet', + name="jet", auto=False, ) @@ -134,17 +134,16 @@ def test_lab2rgb(): def test_hex_to_rgb(): expected = np.array([1, 1, 1]) - hexcode = '#FFFFFF' + hexcode = "#FFFFFF" res = colormap.hex_to_rgb(hexcode) npt.assert_array_almost_equal(res, expected) - hashed_hexcode = 'FFFFFF' + hashed_hexcode = "FFFFFF" res = colormap.hex_to_rgb(hashed_hexcode) npt.assert_array_almost_equal(res, expected) def test_color_converters(): - color = np.array([1, 1, 1]) colors = np.array([[1, 1, 1], [0, 0, 0], [0.2, 0.3, 0.4]]) @@ -161,8 +160,8 @@ def test_color_converters(): npt.assert_almost_equal(rgb_from_xyz_color, color) # testing rgb2lab and lab2rgb - illuminant = 'D65' - observer = '2' + 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) diff --git a/fury/tests/test_convert.py b/fury/tests/test_convert.py index 3a40830b3..d7ac36f8b 100644 --- a/fury/tests/test_convert.py +++ b/fury/tests/test_convert.py @@ -9,7 +9,7 @@ # Optional packages from fury.optpkg import optional_package -matplotlib, have_matplotlib, _ = optional_package('matplotlib') +matplotlib, have_matplotlib, _ = optional_package("matplotlib") if have_matplotlib: import matplotlib.pyplot as plt @@ -17,9 +17,9 @@ from fury.convert import matplotlib_figure_to_numpy -@pytest.mark.skipif(not have_matplotlib, reason='Requires MatplotLib') +@pytest.mark.skipif(not have_matplotlib, reason="Requires MatplotLib") def test_convert(): - names = ['group_a', 'group_b', 'group_c'] + names = ["group_a", "group_b", "group_c"] values = [1, 10, 100] fig = plt.figure(figsize=(9, 3)) @@ -29,12 +29,14 @@ def test_convert(): plt.scatter(names, values) plt.subplot(133) plt.plot(names, values) - plt.suptitle('Categorical Plotting') + plt.suptitle("Categorical Plotting") arr2 = matplotlib_figure_to_numpy(fig, transparent=False, flip_up_down=False) with TemporaryDirectory() as tmpdir: - fname = os.path.join(tmpdir, 'tmp.png') + fname = os.path.join(tmpdir, "tmp.png") dpi = 100 - fig.savefig(fname, transparent=False, bbox_inches='tight', pad_inches=0) + fig.savefig( + fname, transparent=False, dpi=dpi, bbox_inches="tight", pad_inches=0 + ) arr1 = load_image(fname) npt.assert_array_equal(arr1, arr2) diff --git a/fury/tests/test_deprecator.py b/fury/tests/test_deprecator.py index aea8b4897..ca1bacad8 100644 --- a/fury/tests/test_deprecator.py +++ b/fury/tests/test_deprecator.py @@ -20,76 +20,76 @@ @pytest.mark.skipif( skip_win and is_py35, - reason='Issue with setuptools, check ' - 'https://github.com/pypa/setuptools/issues/1903', + reason="Issue with setuptools, check " + "https://github.com/pypa/setuptools/issues/1903", ) def test_cmp_pkg_version(): # Test version comparator npt.assert_equal(cmp_pkg_version(fury.__version__), 0) - npt.assert_equal(cmp_pkg_version('0.0'), -1) - npt.assert_equal(cmp_pkg_version('1000.1000.1'), 1) + npt.assert_equal(cmp_pkg_version("0.0"), -1) + npt.assert_equal(cmp_pkg_version("1000.1000.1"), 1) npt.assert_equal(cmp_pkg_version(fury.__version__, fury.__version__), 0) for test_ver, pkg_ver, exp_out in ( - ('1.0', '1.0', 0), - ('1.0.0', '1.0', 0), - ('1.0', '1.0.0', 0), - ('1.1', '1.1', 0), - ('1.2', '1.1', 1), - ('1.1', '1.2', -1), - ('1.1.1', '1.1.1', 0), - ('1.1.2', '1.1.1', 1), - ('1.1.1', '1.1.2', -1), - ('1.1', '1.1dev', 1), - ('1.1dev', '1.1', -1), - ('1.2.1', '1.2.1rc1', 1), - ('1.2.1rc1', '1.2.1', -1), - ('1.2.1rc1', '1.2.1rc', 1), - ('1.2.1rc', '1.2.1rc1', -1), - ('1.2.1rc1', '1.2.1rc', 1), - ('1.2.1rc', '1.2.1rc1', -1), - ('1.2.1b', '1.2.1a', 1), - ('1.2.1a', '1.2.1b', -1), + ("1.0", "1.0", 0), + ("1.0.0", "1.0", 0), + ("1.0", "1.0.0", 0), + ("1.1", "1.1", 0), + ("1.2", "1.1", 1), + ("1.1", "1.2", -1), + ("1.1.1", "1.1.1", 0), + ("1.1.2", "1.1.1", 1), + ("1.1.1", "1.1.2", -1), + ("1.1", "1.1dev", 1), + ("1.1dev", "1.1", -1), + ("1.2.1", "1.2.1rc1", 1), + ("1.2.1rc1", "1.2.1", -1), + ("1.2.1rc1", "1.2.1rc", 1), + ("1.2.1rc", "1.2.1rc1", -1), + ("1.2.1rc1", "1.2.1rc", 1), + ("1.2.1rc", "1.2.1rc1", -1), + ("1.2.1b", "1.2.1a", 1), + ("1.2.1a", "1.2.1b", -1), ): npt.assert_equal(cmp_pkg_version(test_ver, pkg_ver), exp_out) - npt.assert_raises(ValueError, cmp_pkg_version, 'foo.2') - npt.assert_raises(ValueError, cmp_pkg_version, 'foo.2', '1.0') - npt.assert_raises(ValueError, cmp_pkg_version, '1.0', 'foo.2') - npt.assert_raises(ValueError, cmp_pkg_version, 'foo') + npt.assert_raises(ValueError, cmp_pkg_version, "foo.2") + npt.assert_raises(ValueError, cmp_pkg_version, "foo.2", "1.0") + npt.assert_raises(ValueError, cmp_pkg_version, "1.0", "foo.2") + npt.assert_raises(ValueError, cmp_pkg_version, "foo") def test__ensure_cr(): # Make sure text ends with carriage return - npt.assert_equal(_ensure_cr(' foo'), ' foo\n') - npt.assert_equal(_ensure_cr(' foo\n'), ' foo\n') - npt.assert_equal(_ensure_cr(' foo '), ' foo\n') - npt.assert_equal(_ensure_cr('foo '), 'foo\n') - npt.assert_equal(_ensure_cr('foo \n bar'), 'foo \n bar\n') - npt.assert_equal(_ensure_cr('foo \n\n'), 'foo\n') + npt.assert_equal(_ensure_cr(" foo"), " foo\n") + npt.assert_equal(_ensure_cr(" foo\n"), " foo\n") + npt.assert_equal(_ensure_cr(" foo "), " foo\n") + npt.assert_equal(_ensure_cr("foo "), "foo\n") + npt.assert_equal(_ensure_cr("foo \n bar"), "foo \n bar\n") + npt.assert_equal(_ensure_cr("foo \n\n"), "foo\n") def test__add_dep_doc(): # Test utility function to add deprecation message to docstring - npt.assert_equal(_add_dep_doc('', 'foo'), 'foo\n') - npt.assert_equal(_add_dep_doc('bar', 'foo'), 'bar\n\nfoo\n') - npt.assert_equal(_add_dep_doc(' bar', 'foo'), ' bar\n\nfoo\n') - npt.assert_equal(_add_dep_doc(' bar', 'foo\n'), ' bar\n\nfoo\n') - npt.assert_equal(_add_dep_doc('bar\n\n', 'foo'), 'bar\n\nfoo\n') - npt.assert_equal(_add_dep_doc('bar\n \n', 'foo'), 'bar\n\nfoo\n') + npt.assert_equal(_add_dep_doc("", "foo"), "foo\n") + npt.assert_equal(_add_dep_doc("bar", "foo"), "bar\n\nfoo\n") + npt.assert_equal(_add_dep_doc(" bar", "foo"), " bar\n\nfoo\n") + npt.assert_equal(_add_dep_doc(" bar", "foo\n"), " bar\n\nfoo\n") + npt.assert_equal(_add_dep_doc("bar\n\n", "foo"), "bar\n\nfoo\n") + npt.assert_equal(_add_dep_doc("bar\n \n", "foo"), "bar\n\nfoo\n") npt.assert_equal( - _add_dep_doc(' bar\n\nSome explanation', 'foo\nbaz'), - ' bar\n\nfoo\nbaz\n\nSome explanation\n', + _add_dep_doc(" bar\n\nSome explanation", "foo\nbaz"), + " bar\n\nfoo\nbaz\n\nSome explanation\n", ) npt.assert_equal( - _add_dep_doc(' bar\n\n Some explanation', 'foo\nbaz'), - ' bar\n \n foo\n baz\n \n Some explanation\n', + _add_dep_doc(" bar\n\n Some explanation", "foo\nbaz"), + " bar\n \n foo\n baz\n \n Some explanation\n", ) @pytest.mark.skipif( skip_win and is_py35, - reason='Issue with setuptools, check ' - 'https://github.com/pypa/setuptools/issues/1903', + reason="Issue with setuptools, check " + "https://github.com/pypa/setuptools/issues/1903", ) def test_deprecate_with_version(): def func_no_doc(): @@ -107,81 +107,81 @@ class CustomError(Exception): my_mod = sys.modules[__name__] dec = deprecate_with_version - func = dec('foo')(func_no_doc) + func = dec("foo")(func_no_doc) with clear_and_catch_warnings(modules=[my_mod]) as w: - warnings.simplefilter('always') + 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) + npt.assert_equal(func.__doc__, "foo\n") + func = dec("foo")(func_doc) with clear_and_catch_warnings(modules=[my_mod]) as w: - warnings.simplefilter('always') + 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) + 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: - warnings.simplefilter('always') + warnings.simplefilter("always") npt.assert_equal(func(1, 2), None) npt.assert_equal(len(w), 1) - npt.assert_equal(func.__doc__, 'A docstring\n \n foo\n \n Some text\n') + npt.assert_equal(func.__doc__, "A docstring\n \n foo\n \n Some text\n") # 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') + 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: - warnings.simplefilter('always') + warnings.simplefilter("always") npt.assert_equal(func(), None) npt.assert_equal(len(w), 1) - func = dec('foo', until='10.6')(func_no_doc) + func = dec("foo", until="10.6")(func_no_doc) with clear_and_catch_warnings(modules=[my_mod]) as w: - warnings.simplefilter('always') + warnings.simplefilter("always") npt.assert_equal(func(), None) npt.assert_equal(len(w), 1) npt.assert_equal( func.__doc__, - 'foo\n\n* Will raise {} as of version: 10.6\n'.format(ExpiredDeprecationError), + "foo\n\n* Will raise {} as of version: 10.6\n".format(ExpiredDeprecationError), ) - func = dec('foo', until='0.3')(func_no_doc) + func = dec("foo", until="0.3")(func_no_doc) npt.assert_raises(ExpiredDeprecationError, func) npt.assert_equal( func.__doc__, - 'foo\n\n* Raises {} as of version: 0.3\n'.format(ExpiredDeprecationError), + "foo\n\n* Raises {} as of version: 0.3\n".format(ExpiredDeprecationError), ) - func = dec('foo', '0.2', '0.3')(func_no_doc) + func = dec("foo", "0.2", "0.3")(func_no_doc) npt.assert_raises(ExpiredDeprecationError, func) npt.assert_equal( func.__doc__, - 'foo\n\n* deprecated from version: 0.2\n' - '* Raises {} as of version: 0.3\n'.format(ExpiredDeprecationError), + "foo\n\n* deprecated from version: 0.2\n" + "* Raises {} as of version: 0.3\n".format(ExpiredDeprecationError), ) - func = dec('foo', '0.2', '0.3')(func_doc_long) + func = dec("foo", "0.2", "0.3")(func_doc_long) npt.assert_equal( func.__doc__, - 'A docstring\n \n foo\n \n' - ' * deprecated from version: 0.2\n' - ' * Raises {} as of version: 0.3\n \n' - ' Some text\n'.format(ExpiredDeprecationError), + "A docstring\n \n foo\n \n" + " * deprecated from version: 0.2\n" + " * Raises {} as of version: 0.3\n \n" + " Some text\n".format(ExpiredDeprecationError), ) npt.assert_raises(ExpiredDeprecationError, func) # Check different warnings and errors - func = dec('foo', warn_class=UserWarning)(func_no_doc) + func = dec("foo", warn_class=UserWarning)(func_no_doc) with clear_and_catch_warnings(modules=[my_mod]) as w: - warnings.simplefilter('always') + 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) + func = dec("foo", error_class=CustomError)(func_no_doc) with clear_and_catch_warnings(modules=[my_mod]) as w: - warnings.simplefilter('always') + warnings.simplefilter("always") npt.assert_equal(func(), None) npt.assert_equal(len(w), 1) assert_true(w[0].category is DeprecationWarning) - func = dec('foo', until='0.3', error_class=CustomError)(func_no_doc) + func = dec("foo", until="0.3", error_class=CustomError)(func_no_doc) npt.assert_raises(CustomError, func) @@ -189,32 +189,32 @@ def test_deprecated_argument(): # Tests the decorator with function, method, staticmethod and classmethod. class CustomActor: @classmethod - @deprecated_params('height', 'scale', '0.3') + @deprecated_params("height", "scale", "0.3") def test1(cls, scale): return scale @staticmethod - @deprecated_params('height', 'scale', '0.3') + @deprecated_params("height", "scale", "0.3") def test2(scale): return scale - @deprecated_params('height', 'scale', '0.3') + @deprecated_params("height", "scale", "0.3") def test3(self, scale): return scale - @deprecated_params('height', 'scale', '0.3', '0.5') + @deprecated_params("height", "scale", "0.3", "0.5") def test4(self, scale): return scale - @deprecated_params('height', 'scale', '0.3', '10.0.0') + @deprecated_params("height", "scale", "0.3", "10.0.0") def test5(self, scale): return scale - @deprecated_params('height', 'scale', '0.3') + @deprecated_params("height", "scale", "0.3") def custom_actor(scale): return scale - @deprecated_params('height', 'scale', '0.3', '0.5') + @deprecated_params("height", "scale", "0.3", "0.5") def custom_actor_2(scale): return scale @@ -231,7 +231,7 @@ def custom_actor_2(scale): # As new keyword argument npt.assert_equal(method(scale=1), 1) # As old keyword argument - if method.__name__ not in ['test4', 'custom_actor_2']: + if method.__name__ not in ["test4", "custom_actor_2"]: res = npt.assert_warns(ArgsDeprecationWarning, method, height=1) npt.assert_equal(res, 1) else: @@ -246,13 +246,13 @@ def custom_actor_2(scale): def test_deprecated_argument_in_kwargs(): # To rename an argument that is consumed by "kwargs" the "arg_in_kwargs" # parameter is used. - @deprecated_params('height', 'scale', '0.3', arg_in_kwargs=True) + @deprecated_params("height", "scale", "0.3", arg_in_kwargs=True) def test(**kwargs): - return kwargs['scale'] + return kwargs["scale"] - @deprecated_params('height', 'scale', '0.3', '0.5', arg_in_kwargs=True) + @deprecated_params("height", "scale", "0.3", "0.5", arg_in_kwargs=True) def test2(**kwargs): - return kwargs['scale'] + return kwargs["scale"] # As positional argument only npt.assert_raises(TypeError, test, 1) @@ -273,11 +273,11 @@ def test2(**kwargs): def test_deprecated_argument_multi_deprecation(): - @deprecated_params(['x', 'y', 'z'], ['a', 'b', 'c'], [0.3, 0.2, 0.4]) + @deprecated_params(["x", "y", "z"], ["a", "b", "c"], [0.3, 0.2, 0.4]) def test(a, b, c): return a, b, c - @deprecated_params(['x', 'y', 'z'], ['a', 'b', 'c'], '0.3') + @deprecated_params(["x", "y", "z"], ["a", "b", "c"], "0.3") def test2(a, b, c): return a, b, c @@ -296,61 +296,61 @@ def test_deprecated_argument_not_allowed_use(): # arg_in_kwargs parameter. Without it it raises a TypeError. with pytest.raises(TypeError): - @deprecated_params('height', 'scale', '0.3') + @deprecated_params("height", "scale", "0.3") def test1(**kwargs): - return kwargs['scale'] + return kwargs["scale"] # Cannot replace "*args". with pytest.raises(TypeError): - @deprecated_params('scale', 'args', '0.3') + @deprecated_params("scale", "args", "0.3") def test2(*args): return args # Cannot replace "**kwargs". with pytest.raises(TypeError): - @deprecated_params('scale', 'kwargs', '0.3') + @deprecated_params("scale", "kwargs", "0.3") def test3(**kwargs): return kwargs # wrong number of arguments with pytest.raises(ValueError): - @deprecated_params(['a', 'b', 'c'], ['x', 'y'], '0.3') + @deprecated_params(["a", "b", "c"], ["x", "y"], "0.3") def test4(**kwargs): return kwargs def test_deprecated_argument_remove(): - @deprecated_params('x', None, '0.3', alternative='test2.y') + @deprecated_params("x", None, "0.3", alternative="test2.y") def test(dummy=11, x=3): return dummy, x - @deprecated_params('x', None, '0.3', '0.5', alternative='test2.y') + @deprecated_params("x", None, "0.3", "0.5", alternative="test2.y") def test2(dummy=11, x=3): return dummy, x - @deprecated_params(['dummy', 'x'], None, '0.3', alternative='test2.y') + @deprecated_params(["dummy", "x"], None, "0.3", alternative="test2.y") def test3(dummy=11, x=3): return dummy, x - @deprecated_params(['dummy', 'x'], None, '0.3', '0.5', alternative='test2.y') + @deprecated_params(["dummy", "x"], None, "0.3", "0.5", alternative="test2.y") def test4(dummy=11, x=3): return dummy, x - with pytest.warns(ArgsDeprecationWarning, match=r'Use test2\.y instead') as w: + with pytest.warns(ArgsDeprecationWarning, match=r"Use test2\.y instead") as w: npt.assert_equal(test(x=1), (11, 1)) npt.assert_equal(len(w), 1) - with pytest.warns(ArgsDeprecationWarning, match=r'Use test2\.y instead') as w: + with pytest.warns(ArgsDeprecationWarning, match=r"Use test2\.y instead") as w: npt.assert_equal(test(x=1, dummy=10), (10, 1)) npt.assert_equal(len(w), 1) - with pytest.warns(ArgsDeprecationWarning, match=r'Use test2\.y instead'): + with pytest.warns(ArgsDeprecationWarning, match=r"Use test2\.y instead"): npt.assert_equal(test(121, 1), (121, 1)) - with pytest.warns(ArgsDeprecationWarning, match=r'Use test2\.y instead') as w: + with pytest.warns(ArgsDeprecationWarning, match=r"Use test2\.y instead") as w: npt.assert_equal(test3(121, 1), (121, 1)) npt.assert_raises(ExpiredDeprecationError, test4, 121, 1) diff --git a/fury/tests/test_gltf.py b/fury/tests/test_gltf.py index fd81dbecc..8e9febe2f 100644 --- a/fury/tests/test_gltf.py +++ b/fury/tests/test_gltf.py @@ -1,6 +1,5 @@ import itertools import os -import sys from PIL import Image import numpy as np @@ -16,7 +15,7 @@ from fury.gltf import export_scene, glTF from fury.testing import assert_equal, assert_greater -SCIPY_1_8_PLUS = parse(short_version) >= parse('1.8.0') +SCIPY_1_8_PLUS = parse(short_version) >= parse("1.8.0") if SCIPY_1_8_PLUS: from scipy.ndimage._measurements import _stats @@ -25,8 +24,8 @@ def test_load_gltf(): - fetch_gltf('Duck') - filename = read_viz_gltf('Duck', 'glTF') + fetch_gltf("Duck") + filename = read_viz_gltf("Duck", "glTF") importer = glTF(filename) polydatas = importer.polydatas vertices = utils.get_polydata_vertices(polydatas[0]) @@ -45,8 +44,8 @@ def test_load_gltf(): def test_load_texture(): - fetch_gltf('Duck') - filename = read_viz_gltf('Duck', 'glTF') + fetch_gltf("Duck") + filename = read_viz_gltf("Duck", "glTF") importer = glTF(filename) actor = importer.actors()[0] @@ -63,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("BoxVertexColors") + file = read_viz_gltf("BoxVertexColors", "glTF") importer = glTF(file) actor = importer.actors()[0] scene = window.Scene() @@ -80,8 +79,8 @@ def test_colors(): scene.clear() # material colors - fetch_gltf('BoxAnimated') - file = read_viz_gltf('BoxAnimated', 'glTF') + fetch_gltf("BoxAnimated") + file = read_viz_gltf("BoxAnimated", "glTF") importer = glTF(file) actors = importer.actors() scene.add(*actors) @@ -96,8 +95,8 @@ def test_colors(): def test_orientation(): - fetch_gltf('BoxTextured', 'glTF-Embedded') - file = read_viz_gltf('BoxTextured', 'glTF-Embedded') + fetch_gltf("BoxTextured", "glTF-Embedded") + file = read_viz_gltf("BoxTextured", "glTF-Embedded") importer = glTF(file) actor = importer.actors()[0] @@ -130,15 +129,15 @@ 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') - gltf_obj = glTF('test.gltf') + export_scene(scene, "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') - gltf_obj = glTF('test.gltf') + export_scene(scene, "test.gltf") + gltf_obj = glTF("test.gltf") actors = gltf_obj.actors() scene.clear() @@ -150,8 +149,8 @@ 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') - gltf_obj = glTF('test.gltf') + export_scene(scene, "test.gltf") + gltf_obj = glTF("test.gltf") actors = gltf_obj.actors() scene.clear() @@ -163,15 +162,15 @@ def test_export_gltf(): scene.reset_camera_tight() scene.clear() - fetch_gltf('BoxTextured', 'glTF') - filename = read_viz_gltf('BoxTextured') + fetch_gltf("BoxTextured", "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, "test.gltf") scene.clear() - gltf_obj = glTF('test.gltf') + gltf_obj = glTF("test.gltf") actors = gltf_obj.actors() scene.add(*actors) @@ -186,8 +185,8 @@ def test_export_gltf(): def test_simple_animation(): - fetch_gltf('BoxAnimated', 'glTF') - file = read_viz_gltf('BoxAnimated') + fetch_gltf("BoxAnimated", "glTF") + file = read_viz_gltf("BoxAnimated") gltf_obj = glTF(file) timeline = Timeline() animation = gltf_obj.main_animation() @@ -200,15 +199,15 @@ def test_simple_animation(): # timestamp animation seek timeline.seek(0.0) - showm.save_screenshot('keyframe1.png') + showm.save_screenshot("keyframe1.png") timeline.seek(2.57) - showm.save_screenshot('keyframe2.png') + showm.save_screenshot("keyframe2.png") res1 = window.analyze_snapshot( - 'keyframe1.png', colors=[(77, 136, 204), (204, 106, 203)] + "keyframe1.png", colors=[(77, 136, 204), (204, 106, 203)] ) res2 = window.analyze_snapshot( - 'keyframe2.png', colors=[(77, 136, 204), (204, 106, 203)] + "keyframe2.png", colors=[(77, 136, 204), (204, 106, 203)] ) assert_greater(res2.objects, res1.objects) @@ -218,10 +217,10 @@ def test_simple_animation(): def test_skinning(): # animation test - fetch_gltf('SimpleSkin', 'glTF') - file = read_viz_gltf('SimpleSkin') + fetch_gltf("SimpleSkin", "glTF") + file = read_viz_gltf("SimpleSkin") gltf_obj = glTF(file) - animation = gltf_obj.skin_animation()['anim_0'] + animation = gltf_obj.skin_animation()["anim_0"] timeline = Timeline(animation) # checking weights and joints weights = np.array( @@ -267,9 +266,9 @@ def test_skinning(): timeline.seek(1.0) timeline.seek(4.00) - showm.save_screenshot('keyframe2.png') - res1 = np.asarray(Image.open('keyframe1.png')) - res2 = np.asarray(Image.open('keyframe2.png')) + showm.save_screenshot("keyframe2.png") + res1 = np.asarray(Image.open("keyframe1.png")) + res2 = np.asarray(Image.open("keyframe2.png")) avg = center_of_mass(res1) print(avg) @@ -292,9 +291,9 @@ def timer_callback(_obj, _event): joint_matrices = [] ibms = [] for i, bone in enumerate(gltf_obj.bones[0]): - if animation.is_interpolatable(f'transform{bone}'): + if animation.is_interpolatable(f"transform{bone}"): deform = animation.get_value( - f'transform{bone}', animation.current_timestamp + f"transform{bone}", animation.current_timestamp ) ibm = gltf_obj.ibms[0][i].T ibms.append(ibm) @@ -309,9 +308,9 @@ def timer_callback(_obj, _event): showm.render() if cnt == 10: - showm.save_screenshot('keyframe1.png') + showm.save_screenshot("keyframe1.png") if cnt == 100: - showm.save_screenshot('keyframe2.png') + showm.save_screenshot("keyframe2.png") if cnt == 150: showm.destroy_timer(timer_id) @@ -322,15 +321,15 @@ def timer_callback(_obj, _event): def test_morphing(): - fetch_gltf('MorphStressTest', 'glTF') - file = read_viz_gltf('MorphStressTest') + fetch_gltf("MorphStressTest", "glTF") + file = read_viz_gltf("MorphStressTest") gltf_obj = glTF(file) animations = gltf_obj.morph_animation() npt.assert_equal(len(gltf_obj._actors), 2) npt.assert_equal(len(gltf_obj.morph_weights), 16) - npt.assert_equal(list(animations.keys()), ['Individuals', 'TheWave', 'Pulse']) - anim_1 = animations['TheWave'] + npt.assert_equal(list(animations.keys()), ["Individuals", "TheWave", "Pulse"]) + anim_1 = animations["TheWave"] gltf_obj.update_morph(anim_1) scene = window.Scene() @@ -343,18 +342,18 @@ def test_morphing(): timeline_1.seek(0.1) gltf_obj.update_morph(anim_1) - showm.save_screenshot('keyframe1.png') - res_1 = window.analyze_snapshot('keyframe1.png') + showm.save_screenshot("keyframe1.png") + res_1 = window.analyze_snapshot("keyframe1.png") timeline_1.seek(1.50) gltf_obj.update_morph(anim_1) - showm.save_screenshot('keyframe2.png') - res_2 = window.analyze_snapshot('keyframe2.png') + showm.save_screenshot("keyframe2.png") + res_2 = window.analyze_snapshot("keyframe2.png") npt.assert_equal(res_1.colors_found, res_2.colors_found) - img_1 = np.asarray(Image.open('keyframe1.png').convert('L')) - img_2 = np.asarray(Image.open('keyframe2.png').convert('L')) + img_1 = np.asarray(Image.open("keyframe1.png").convert("L")) + img_2 = np.asarray(Image.open("keyframe2.png").convert("L")) stats_1, stats_2 = _stats(img_1), _stats(img_2) # Assert right image size assert_equal(stats_1[0], stats_2[0]) diff --git a/fury/tests/test_interactor.py b/fury/tests/test_interactor.py index 5d6b95db3..33c6132ce 100644 --- a/fury/tests/test_interactor.py +++ b/fury/tests/test_interactor.py @@ -7,16 +7,16 @@ from fury import actor, interactor, ui, utils as vtk_utils, window from fury.data import DATA_DIR -from fury.decorators import skip_osx, skip_win +from fury.decorators import skip_win from fury.lib import VTK_VERSION, Actor2D, PolyDataMapper2D, RegularPolygonSource @pytest.mark.skipif( - skip_win, reason='This test does not work on Windows.' ' Need to be introspected' + skip_win, reason="This test does not work on Windows." " Need to be introspected" ) def test_custom_interactor_style_events(recording=False): - print('Using VTK {}'.format(VTK_VERSION)) - filename = 'test_custom_interactor_style_events.log.gz' + print("Using VTK {}".format(VTK_VERSION)) + filename = "test_custom_interactor_style_events.log.gz" recording_filename = pjoin(DATA_DIR, filename) scene = window.Scene() @@ -48,7 +48,7 @@ def follow_mouse(iren, obj): iren.force_render() interactor_style.add_active_prop(cursor) - interactor_style.add_callback(cursor, 'MouseMoveEvent', follow_mouse) + interactor_style.add_callback(cursor, "MouseMoveEvent", follow_mouse) # create some minimalistic streamlines lines = [ @@ -69,16 +69,16 @@ def counter(iren, _obj): # Assign the counter callback to every possible event. for event in [ - 'CharEvent', - 'MouseMoveEvent', - 'KeyPressEvent', - 'KeyReleaseEvent', - 'LeftButtonPressEvent', - 'LeftButtonReleaseEvent', - 'RightButtonPressEvent', - 'RightButtonReleaseEvent', - 'MiddleButtonPressEvent', - 'MiddleButtonReleaseEvent', + "CharEvent", + "MouseMoveEvent", + "KeyPressEvent", + "KeyReleaseEvent", + "LeftButtonPressEvent", + "LeftButtonReleaseEvent", + "RightButtonPressEvent", + "RightButtonReleaseEvent", + "MiddleButtonPressEvent", + "MiddleButtonReleaseEvent", ]: interactor_style.add_callback(tube1, event, counter) @@ -97,20 +97,20 @@ def scale_down_obj(iren, obj): iren.force_render() iren.event.abort() # Stop propagating the event. - interactor_style.add_callback(tube2, 'MouseWheelForwardEvent', scale_up_obj) - interactor_style.add_callback(tube2, 'MouseWheelBackwardEvent', scale_down_obj) + interactor_style.add_callback(tube2, "MouseWheelForwardEvent", scale_up_obj) + interactor_style.add_callback(tube2, "MouseWheelBackwardEvent", scale_down_obj) # Add callback to hide/show tube1. def toggle_visibility(iren, obj): key = iren.event.key - if key.lower() == 'v': + if key.lower() == "v": obj.SetVisibility(not obj.GetVisibility()) iren.force_render() interactor_style.add_active_prop(tube1) interactor_style.add_active_prop(tube2) interactor_style.remove_active_prop(tube2) - interactor_style.add_callback(tube1, 'CharEvent', toggle_visibility) + interactor_style.add_callback(tube1, "CharEvent", toggle_visibility) if recording: show_manager.record_events_to_file(recording_filename) @@ -119,40 +119,40 @@ def toggle_visibility(iren, obj): show_manager.play_events_from_file(recording_filename) msg = "Wrong count for '{}'." expected = [ - ('CharEvent', 6), - ('KeyPressEvent', 6), - ('KeyReleaseEvent', 6), - ('MouseMoveEvent', 1652), - ('LeftButtonPressEvent', 1), - ('RightButtonPressEvent', 1), - ('MiddleButtonPressEvent', 2), - ('LeftButtonReleaseEvent', 1), - ('MouseWheelForwardEvent', 3), - ('MouseWheelBackwardEvent', 1), - ('MiddleButtonReleaseEvent', 2), - ('RightButtonReleaseEvent', 1), + ("CharEvent", 6), + ("KeyPressEvent", 6), + ("KeyReleaseEvent", 6), + ("MouseMoveEvent", 1652), + ("LeftButtonPressEvent", 1), + ("RightButtonPressEvent", 1), + ("MiddleButtonPressEvent", 2), + ("LeftButtonReleaseEvent", 1), + ("MouseWheelForwardEvent", 3), + ("MouseWheelBackwardEvent", 1), + ("MiddleButtonReleaseEvent", 2), + ("RightButtonReleaseEvent", 1), ] # Useful loop for debugging. for event, count in expected: if states[event] != count: - print('{}: {} vs. {} (expected)'.format(event, states[event], count)) + print("{}: {} vs. {} (expected)".format(event, states[event], count)) for event, count in expected: npt.assert_equal(states[event], count, err_msg=msg.format(event)) def test_double_click_events(recording=False): - filename = 'test_double_click_events.log.gz' + filename = "test_double_click_events.log.gz" recording_filename = pjoin(DATA_DIR, filename) label = ui.TextBlock2D( position=(400, 780), font_size=40, color=(1, 0.5, 0), - justification='center', - vertical_justification='top', - text='FURY rocks!!!', + justification="center", + vertical_justification="top", + text="FURY rocks!!!", ) cube = actor.cube( @@ -165,43 +165,43 @@ def test_double_click_events(recording=False): states = defaultdict(lambda: 0) def left_single_click(iren, obj): - states['LeftButtonPressEvent'] += 1 + states["LeftButtonPressEvent"] += 1 iren.force_render() def left_double_click(iren, obj): - states['LeftButtonDoubleClickEvent'] += 1 + states["LeftButtonDoubleClickEvent"] += 1 label.color = (1, 0, 0) iren.force_render() def right_single_click(iren, obj): - states['RightButtonPressEvent'] += 1 + states["RightButtonPressEvent"] += 1 iren.force_render() def right_double_click(iren, obj): - states['RightButtonDoubleClickEvent'] += 1 + states["RightButtonDoubleClickEvent"] += 1 label.color = (0, 1, 0) iren.force_render() def middle_single_click(iren, obj): - states['MiddleButtonPressEvent'] += 1 + states["MiddleButtonPressEvent"] += 1 iren.force_render() def middle_double_click(iren, obj): - states['MiddleButtonDoubleClickEvent'] += 1 + states["MiddleButtonDoubleClickEvent"] += 1 label.color = (0, 0, 1) iren.force_render() test_events = { - 'LeftButtonPressEvent': left_single_click, - 'LeftButtonDoubleClickEvent': left_double_click, - 'RightButtonPressEvent': right_single_click, - 'RightButtonDoubleClickEvent': right_double_click, - 'MiddleButtonPressEvent': middle_single_click, - 'MiddleButtonDoubleClickEvent': middle_double_click, + "LeftButtonPressEvent": left_single_click, + "LeftButtonDoubleClickEvent": left_double_click, + "RightButtonPressEvent": right_single_click, + "RightButtonDoubleClickEvent": right_double_click, + "MiddleButtonPressEvent": middle_single_click, + "MiddleButtonDoubleClickEvent": middle_double_click, } current_size = (800, 800) - showm = window.ShowManager(size=current_size, title='Double Click Test') + showm = window.ShowManager(size=current_size, title="Double Click Test") showm.scene.add(cube) showm.scene.add(label) @@ -215,23 +215,23 @@ def middle_double_click(iren, obj): showm.play_events_from_file(recording_filename) msg = "Wrong count for '{}'." expected = [ - ('LeftButtonPressEvent', 3), - ('LeftButtonDoubleClickEvent', 1), - ('MiddleButtonPressEvent', 3), - ('MiddleButtonDoubleClickEvent', 1), - ('RightButtonPressEvent', 2), - ('RightButtonDoubleClickEvent', 1), + ("LeftButtonPressEvent", 3), + ("LeftButtonDoubleClickEvent", 1), + ("MiddleButtonPressEvent", 3), + ("MiddleButtonDoubleClickEvent", 1), + ("RightButtonPressEvent", 2), + ("RightButtonDoubleClickEvent", 1), ] # Useful loop for debugging. for event, count in expected: if states[event] != count: - print('{}: {} vs. {} (expected)'.format(event, states[event], count)) + print("{}: {} vs. {} (expected)".format(event, states[event], count)) for event, count in expected: npt.assert_equal(states[event], count, err_msg=msg.format(event)) -if __name__ == '__main__': +if __name__ == "__main__": test_custom_interactor_style_events(recording=False) test_double_click_events(recording=False) diff --git a/fury/tests/test_io.py b/fury/tests/test_io.py index 99f2d8531..a995485c5 100644 --- a/fury/tests/test_io.py +++ b/fury/tests/test_io.py @@ -23,8 +23,8 @@ def test_save_and_load_polydata(): - l_ext = ['vtk', 'fib', 'ply', 'xml'] - fname = 'temp-io' + l_ext = ["vtk", "fib", "ply", "xml"] + fname = "temp-io" for ext in l_ext: with InTemporaryDirectory() as odir: @@ -33,7 +33,7 @@ def test_save_and_load_polydata(): pd = PolyData() pd.SetPoints(numpy_to_vtk_points(data)) - fname_path = pjoin(odir, '{0}.{1}'.format(fname, ext)) + fname_path = pjoin(odir, "{0}.{1}".format(fname, ext)) save_polydata(pd, fname_path) npt.assert_equal(os.path.isfile(fname_path), True) @@ -44,32 +44,32 @@ 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, load_polydata, 'test.vti') - npt.assert_raises(FileNotFoundError, load_polydata, 'does-not-exist.obj') + npt.assert_raises(IOError, save_polydata, PolyData(), "test.vti") + npt.assert_raises(IOError, save_polydata, PolyData(), "test.obj") + npt.assert_raises(IOError, load_polydata, "test.vti") + npt.assert_raises(FileNotFoundError, load_polydata, "does-not-exist.obj") def test_save_and_load_options(): - l_ext = ['ply', 'vtk'] + l_ext = ["ply", "vtk"] l_options = [ { - 'color_array_name': 'horizon', + "color_array_name": "horizon", }, { - 'binary': True, + "binary": True, }, ] - fname = 'temp-io' + fname = "temp-io" - for ext, option in zip(l_ext, l_options): + for ext, option in zip(l_ext, l_options, strict=False): with InTemporaryDirectory() as odir: data = np.random.randint(0, 255, size=(50, 3)) pd = PolyData() pd.SetPoints(numpy_to_vtk_points(data)) - fname_path = pjoin(odir, '{0}.{1}'.format(fname, ext)) + fname_path = pjoin(odir, "{0}.{1}".format(fname, ext)) save_polydata(pd, fname_path, **option) npt.assert_equal(os.path.isfile(fname_path), True) @@ -80,21 +80,21 @@ def test_save_and_load_options(): npt.assert_array_equal(data, out_data) - l_ext = ['vtk', 'vtp', 'ply', 'stl', 'mni.obj'] + l_ext = ["vtk", "vtp", "ply", "stl", "mni.obj"] l_options = [ {}, { - 'binary': False, + "binary": False, }, ] - for ext, option in zip(l_ext, l_options): + for ext, option in zip(l_ext, l_options, strict=False): with InTemporaryDirectory() as odir: data = np.random.randint(0, 255, size=(50, 3)) pd = PolyData() pd.SetPoints(numpy_to_vtk_points(data)) - fname_path = pjoin(odir, '{0}.{1}'.format(fname, ext)) + fname_path = pjoin(odir, "{0}.{1}".format(fname, ext)) save_polydata(pd, fname_path, **option) npt.assert_equal(os.path.isfile(fname_path), True) @@ -102,22 +102,22 @@ def test_save_and_load_options(): def test_save_load_image(): - l_ext = ['png', 'jpeg', 'jpg', 'bmp', 'tiff'] + l_ext = ["png", "jpeg", "jpg", "bmp", "tiff"] fury_logo_link = ( - 'https://raw.githubusercontent.com/fury-gl/' - 'fury-communication-assets/main/fury-logo.png' + "https://raw.githubusercontent.com/fury-gl/" + "fury-communication-assets/main/fury-logo.png" ) - invalid_link = 'https://picsum.photos/200' - fname = 'temp-io' + invalid_link = "https://picsum.photos/200" + fname = "temp-io" for ext in l_ext: with InTemporaryDirectory() as odir: data = np.random.randint(0, 255, size=(50, 3), dtype=np.uint8) url_image = load_image(fury_logo_link) - url_fname_path = pjoin(odir, f'fury_logo.{ext}') - fname_path = pjoin(odir, '{0}.{1}'.format(fname, ext)) + url_fname_path = pjoin(odir, f"fury_logo.{ext}") + fname_path = pjoin(odir, "{0}.{1}".format(fname, ext)) save_image(data, fname_path, compression_quality=100) save_image(url_image, url_fname_path, compression_quality=100) @@ -129,38 +129,37 @@ def test_save_load_image(): assert_greater(os.stat(url_fname_path).st_size, 0) out_image = load_image(fname_path) - if ext not in ['jpeg', 'jpg', 'tiff']: + if ext not in ["jpeg", "jpg", "tiff"]: npt.assert_array_equal(data[..., 0], out_image[..., 0]) else: - npt.assert_array_almost_equal( 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, 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, save_image, np.random.randint(0, 255, size=(50, 3)), "test.vtk" ) npt.assert_raises( IOError, save_image, np.random.randint(0, 255, size=(50, 3)), - 'test.vtk', + "test.vtk", use_pillow=False, ) 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_type = [None, 'bits', 'random'] + compression_type = [None, "bits", "random"] for ct in compression_type: with InTemporaryDirectory() as odir: try: data = np.random.randint(0, 255, size=(50, 3), dtype=np.uint8) - fname_path = pjoin(odir, '{0}.tif'.format(fname)) + fname_path = pjoin(odir, "{0}.tif".format(fname)) save_image(data, fname_path, compression_type=ct, use_pillow=False) npt.assert_equal(os.path.isfile(fname_path), True) @@ -171,15 +170,14 @@ def test_save_load_image(): @pytest.mark.skipif( skip_osx, - reason='This test does not work on OSX due to ' - 'libpng version conflict. Need to be ' - 'introspected on Travis', + reason="This test does not work on OSX due to " + "libpng version conflict. Need to be " + "introspected on Travis", ) def test_pillow(): - with InTemporaryDirectory() as odir: data = (255 * np.random.rand(400, 255, 4)).astype(np.uint8) - fname_path = pjoin(odir, 'test.png') + fname_path = pjoin(odir, "test.png") for opt1, opt2 in [(True, True), (False, True), (True, False), (False, False)]: if not opt1: @@ -194,32 +192,32 @@ def test_pillow(): dpi_tolerance = 0.01 save_image(data, fname_path, use_pillow=True) - img_dpi = Image.open(fname_path).info.get('dpi') + img_dpi = Image.open(fname_path).info.get("dpi") assert abs(72 - img_dpi[0]) < dpi_tolerance assert abs(72 - img_dpi[1]) < dpi_tolerance save_image(data, fname_path, use_pillow=True, dpi=300) - img_dpi = Image.open(fname_path).info.get('dpi') + img_dpi = Image.open(fname_path).info.get("dpi") assert abs(300 - img_dpi[0]) < dpi_tolerance assert abs(300 - img_dpi[1]) < dpi_tolerance save_image(data, fname_path, use_pillow=True, dpi=(45, 45)) - img_dpi = Image.open(fname_path).info.get('dpi') + img_dpi = Image.open(fname_path).info.get("dpi") assert abs(45 - img_dpi[0]) < dpi_tolerance assert abs(45 - img_dpi[1]) < dpi_tolerance save_image(data, fname_path, use_pillow=True, dpi=(300, 72)) - img_dpi = Image.open(fname_path).info.get('dpi') + img_dpi = Image.open(fname_path).info.get("dpi") assert abs(300 - img_dpi[0]) < dpi_tolerance assert abs(72 - img_dpi[1]) < dpi_tolerance def test_load_cubemap_texture(): - l_ext = ['jpg', 'jpeg', 'png', 'bmp', 'tif', 'tiff'] + l_ext = ["jpg", "jpeg", "png", "bmp", "tif", "tiff"] for ext in l_ext: with InTemporaryDirectory() as odir: data = np.random.randint(0, 255, size=(50, 50, 3), dtype=np.uint8) - fname_path = pjoin(odir, f'test.{ext}') + fname_path = pjoin(odir, f"test.{ext}") save_image(data, fname_path) fnames = [fname_path] * 5 @@ -241,15 +239,15 @@ def test_load_cubemap_texture(): def test_load_sprite_sheet(): sprite_URL = ( - 'https://raw.githubusercontent.com/' - 'fury-gl/fury-data/master/unittests/fury_sprite.png' + "https://raw.githubusercontent.com/" + "fury-gl/fury-data/master/unittests/fury_sprite.png" ) with InTemporaryDirectory() as tdir: sprites = load_sprite_sheet(sprite_URL, 5, 5) for idx, sprite in enumerate(list(sprites.values())): - img_name = f'{idx}.png' + img_name = f"{idx}.png" save_image(sprite, os.path.join(tdir, img_name)) sprite_count = len(os.listdir(tdir)) @@ -263,15 +261,15 @@ def test_load_sprite_sheet(): def test_load_text(): with InTemporaryDirectory() as tdir: - test_file_name = 'test.txt' + test_file_name = "test.txt" # Test file does not exist npt.assert_raises(IOError, load_text, test_file_name) # Saving file with content - test_file_contents = 'This is some test text.' + test_file_contents = "This is some test text." test_fname = os.path.join(tdir, test_file_name) - test_file = open(test_fname, 'w') + test_file = open(test_fname, "w") test_file.write(test_file_contents) test_file.close() diff --git a/fury/tests/test_layout.py b/fury/tests/test_layout.py index 983d40209..e7480b46c 100644 --- a/fury/tests/test_layout.py +++ b/fury/tests/test_layout.py @@ -13,12 +13,18 @@ ) from fury.ui.containers import Panel2D +# Define module-level singleton variables +DEFAULT_CENTERS = np.asarray([[[0, 0, 0]], [[5, 5, 5]]]) +DEFAULT_DIRECTIONS = np.asarray([[[0, 0, 0]], [[0, 0, 0]]]) +DEFAULT_COLORS = np.random.rand(2, 3) +DEFAULT_SCALES = [1, 1.5] + def get_default_cubes( - centers=np.asarray([[[0, 0, 0]], [[5, 5, 5]]]), - directions=np.asarray([[[0, 0, 0]], [[0, 0, 0]]]), - colors=np.random.rand(2, 3), - scales=[1, 1.5], + centers=DEFAULT_CENTERS, + directions=DEFAULT_DIRECTIONS, + colors=DEFAULT_COLORS, + scales=DEFAULT_SCALES, ): """Provides cube actors with default parameters @@ -50,7 +56,7 @@ def get_default_cubes( return (cube_first, cube_second) -def get_default_panels(sizes=[(100, 100), (200, 200)], colors=np.random.rand(2, 3)): +def get_default_panels(sizes=None, colors=None): """Provides Panels with default parameters Parameters @@ -61,6 +67,11 @@ def get_default_panels(sizes=[(100, 100), (200, 200)], colors=np.random.rand(2, RGB or RGBA (for opacity) """ + if sizes is None: + sizes = [(100, 100), (200, 200)] + if colors is None: + colors = np.random.rand(2, 3) + panel_first_size, panel_second_size = sizes panel_first_color, panel_second_color = colors @@ -71,7 +82,6 @@ def get_default_panels(sizes=[(100, 100), (200, 200)], colors=np.random.rand(2, def test_layout_apply(): - cube_first, cube_second = get_default_cubes() panel_first, panel_second = get_default_panels() @@ -95,7 +105,6 @@ def test_layout_apply(): def test_layout_compute_postions(): - cube_first, cube_second = get_default_cubes() panel_first, panel_second = get_default_panels() @@ -109,14 +118,13 @@ def test_layout_compute_postions(): def test_grid_layout_get_cell_shape(): - cube_first, cube_second = get_default_cubes() panel_first, panel_second = get_default_panels() grid = GridLayout() - grid_square = GridLayout(cell_shape='square') - grid_diagonal = GridLayout(cell_shape='diagonal') - invalid_gird = GridLayout(cell_shape='invalid') + grid_square = GridLayout(cell_shape="square") + grid_diagonal = GridLayout(cell_shape="diagonal") + invalid_gird = GridLayout(cell_shape="invalid") shape = grid.get_cells_shape([cube_first, cube_second]) shape_square = grid_square.get_cells_shape([cube_first, cube_second]) @@ -159,13 +167,12 @@ def test_grid_layout_get_cell_shape(): def test_grid_layout_compute_positions(): - cube_first, cube_second = get_default_cubes() panel_first, panel_second = get_default_panels() grid = GridLayout() - grid_square = GridLayout(cell_shape='square') - grid_diagonal = GridLayout(cell_shape='diagonal') + grid_square = GridLayout(cell_shape="square") + grid_diagonal = GridLayout(cell_shape="diagonal") position_rect = grid.compute_positions([cube_first, cube_second]) position_square = grid_square.compute_positions([cube_first, cube_second]) @@ -190,11 +197,10 @@ def test_grid_layout_compute_positions(): def test_grid_layout_apply(): - cube_first, cube_second = get_default_cubes() panel_first, panel_second = get_default_panels() - grid_diagonal = GridLayout(cell_shape='diagonal') + grid_diagonal = GridLayout(cell_shape="diagonal") grid_diagonal.apply([cube_first, cube_second]) grid_diagonal.apply([panel_first, panel_second]) @@ -213,8 +219,8 @@ def test_vertical_layout_compute_positions(): (cube_first, cube_second) = get_default_cubes() vertical_layout_rect = VerticalLayout() - vertical_layout_square = VerticalLayout(cell_shape='square') - vertical_layout_diagonal = VerticalLayout(cell_shape='diagonal') + vertical_layout_square = VerticalLayout(cell_shape="square") + vertical_layout_diagonal = VerticalLayout(cell_shape="diagonal") position_rect = vertical_layout_rect.compute_positions([cube_first, cube_second]) @@ -232,12 +238,11 @@ def test_vertical_layout_compute_positions(): def test_horizontal_layout_compute_positions(): - cube_first, cube_second = get_default_cubes() horizontal_rect = HorizontalLayout() - horizontal_square = HorizontalLayout(cell_shape='square') - horizontal_diagonal = HorizontalLayout(cell_shape='diagonal') + horizontal_square = HorizontalLayout(cell_shape="square") + horizontal_diagonal = HorizontalLayout(cell_shape="diagonal") position_rect = horizontal_rect.compute_positions([cube_first, cube_second]) @@ -254,11 +259,11 @@ def test_x_layout(): cube_first, cube_second = get_default_cubes() actors = [cube_first, cube_second] - positive_x_layout = XLayout(direction='x+') - negative_x_layout = XLayout(direction='x-') + positive_x_layout = XLayout(direction="x+") + negative_x_layout = XLayout(direction="x-") with npt.assert_raises(ValueError): - _ = XLayout(direction='Invalid direction') + _ = XLayout(direction="Invalid direction") positive_positions = positive_x_layout.compute_positions(actors) negative_positions = negative_x_layout.compute_positions(actors) @@ -291,11 +296,11 @@ def test_y_layout(): cube_first, cube_second = get_default_cubes() actors = [cube_first, cube_second] - positive_y_layout = YLayout(direction='y+') - negative_y_layout = YLayout(direction='y-') + positive_y_layout = YLayout(direction="y+") + negative_y_layout = YLayout(direction="y-") with npt.assert_raises(ValueError): - _ = YLayout(direction='Invalid direction') + _ = YLayout(direction="Invalid direction") positive_positions = positive_y_layout.compute_positions(actors) negative_positions = negative_y_layout.compute_positions(actors) @@ -328,15 +333,15 @@ def test_z_layout(): cube_first, cube_second = get_default_cubes() actors = [cube_first, cube_second] - positive_z_layout = ZLayout(direction='z+') - negative_z_layout = ZLayout(direction='z-') - diagonal_z_layout = ZLayout(direction='z+', cell_shape='diagonal') + positive_z_layout = ZLayout(direction="z+") + negative_z_layout = ZLayout(direction="z-") + diagonal_z_layout = ZLayout(direction="z+", cell_shape="diagonal") with npt.assert_raises(ValueError): - _ = XLayout(direction='Invalid direction') + _ = XLayout(direction="Invalid direction") with npt.assert_raises(ValueError): - invalid_shape_layout = ZLayout(direction='z+', cell_shape='Invalid Shape') + invalid_shape_layout = ZLayout(direction="z+", cell_shape="Invalid Shape") _ = invalid_shape_layout.get_cells_shape(actors) positive_positions = positive_z_layout.compute_positions(actors) diff --git a/fury/tests/test_material.py b/fury/tests/test_material.py index 8cc4091c4..2d9c32143 100644 --- a/fury/tests/test_material.py +++ b/fury/tests/test_material.py @@ -1,20 +1,15 @@ -import os -from tempfile import TemporaryDirectory - import numpy as np import numpy.testing as npt -import pytest from fury import actor, material, window -from fury.io import load_image from fury.optpkg import optional_package -dipy, have_dipy, _ = optional_package('dipy') +dipy, have_dipy, _ = optional_package("dipy") def test_manifest_pbr_vtk(): # Test non-supported property - test_actor = actor.text_3d('Test') + test_actor = actor.text_3d("Test") npt.assert_warns(UserWarning, material.manifest_pbr, test_actor) # Test non-supported PBR interpolation @@ -92,24 +87,24 @@ def test_manifest_pbr_vtk(): def test_manifest_principled(): # Test non-supported property - test_actor = actor.text_3d('Test') + test_actor = actor.text_3d("Test") npt.assert_warns(UserWarning, material.manifest_principled, test_actor) center = np.array([[0, 0, 0]]) # Test expected parameters expected_principled_params = { - 'subsurface': 0, - 'metallic': 0, - 'specular': 0, - 'specular_tint': 0, - 'roughness': 0, - 'anisotropic': 0, - 'anisotropic_direction': [0, 1, 0.5], - 'sheen': 0, - 'sheen_tint': 0, - 'clearcoat': 0, - 'clearcoat_gloss': 0, + "subsurface": 0, + "metallic": 0, + "specular": 0, + "specular_tint": 0, + "roughness": 0, + "anisotropic": 0, + "anisotropic_direction": [0, 1, 0.5], + "sheen": 0, + "sheen_tint": 0, + "clearcoat": 0, + "clearcoat_gloss": 0, } test_actor = actor.square(center, directions=(1, 1, 1), colors=(0, 0, 1)) actual_principled_params = material.manifest_principled(test_actor) @@ -118,7 +113,7 @@ def test_manifest_principled(): def test_manifest_standard(): # Test non-supported property - test_actor = actor.text_3d('Test') + test_actor = actor.text_3d("Test") npt.assert_warns(UserWarning, material.manifest_standard, test_actor) center = np.array([[0, 0, 0]]) @@ -126,7 +121,7 @@ def test_manifest_standard(): # Test non-supported interpolation method test_actor = actor.square(center, directions=(1, 1, 1), colors=(0, 0, 1)) npt.assert_warns( - UserWarning, material.manifest_standard, test_actor, interpolation='test' + UserWarning, material.manifest_standard, test_actor, interpolation="test" ) scene = window.Scene() # Setup scene diff --git a/fury/tests/test_molecular.py b/fury/tests/test_molecular.py index bfe87c57c..f3ab32116 100644 --- a/fury/tests/test_molecular.py +++ b/fury/tests/test_molecular.py @@ -7,15 +7,15 @@ def test_periodic_table(): # Testing class PeriodicTable() table = mol.PTable() - 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_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_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, "test") def get_default_molecular_info(all_info=False): @@ -32,7 +32,7 @@ def get_default_molecular_info(all_info=False): [0.6632858893e01, 0.6740709254e01, 0.4090898288e01], ] ) - atom_names = np.array(['CA', 'CA', 'H', 'H', 'H', 'H', 'H', 'H']) + atom_names = np.array(["CA", "CA", "H", "H", "H", "H", "H", "H"]) model = np.ones(8) residue = np.ones(8) chain = np.ones(8) * 65 @@ -66,7 +66,7 @@ def test_molecule_creation(): elements = np.array([6, 6]) npt.assert_raises(ValueError, mol.Molecule, elements, atom_coords) - elements = [i for i in range(8)] + elements = list(range(8)) npt.assert_raises(ValueError, mol.Molecule, elements, atom_coords) @@ -149,7 +149,7 @@ def test_sphere_cpk(interactive=False): atomic_numbers, atom_coords = get_default_molecular_info() molecule = mol.Molecule(atomic_numbers, atom_coords) table = mol.PTable() - colormodes = ['discrete', 'single'] + colormodes = ["discrete", "single"] colors = np.array( [ [table.atom_color(1), table.atom_color(6)], @@ -176,7 +176,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, "multiple") def test_bstick(interactive=False): @@ -188,7 +188,7 @@ def test_bstick(interactive=False): npt.assert_raises(ValueError, mol.ball_stick, molecule) mol.add_bond(molecule, 0, 1, 1) - colormodes = ['discrete', 'single'] + colormodes = ["discrete", "single"] atom_scale_factor = [0.3, 0.4] bond_thickness = [0.1, 0.2] multiple_bonds = [True, False] @@ -224,7 +224,7 @@ 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, "multiple") def test_stick(interactive=False): @@ -236,7 +236,7 @@ def test_stick(interactive=False): npt.assert_raises(ValueError, mol.stick, molecule) mol.add_bond(molecule, 0, 1, 1) - colormodes = ['discrete', 'single'] + colormodes = ["discrete", "single"] bond_thickness = [0.1, 0.12] table = mol.PTable() colors = np.array( @@ -264,11 +264,10 @@ def test_stick(interactive=False): scene.clear() # Testing warnings - npt.assert_warns(UserWarning, mol.stick, molecule, 'multiple') + npt.assert_warns(UserWarning, mol.stick, molecule, "multiple") def test_ribbon(interactive=False): - scene = window.Scene() # Testing if helices and sheets are rendered properly @@ -299,26 +298,26 @@ def test_ribbon(interactive=False): elements = np.array([7, 6, 6, 8, 6, 6, 6, 8, 7, 7, 6, 6, 8, 7, 6, 6, 8, 6, 8, 6]) atom_names = np.array( [ - 'N', - 'CA', - 'C', - 'O', - 'CB', - 'CG', - 'CD', - 'OE1', - 'NE2', - 'N', - 'CA', - 'C', - 'O', - 'N', - 'CA', - 'C', - 'O', - 'CB', - 'OG1', - 'OG2', + "N", + "CA", + "C", + "O", + "CB", + "CG", + "CD", + "OE1", + "NE2", + "N", + "CA", + "C", + "O", + "N", + "CA", + "C", + "O", + "CB", + "OG1", + "OG2", ] ) model = np.ones(20) diff --git a/fury/tests/test_optpkg.py b/fury/tests/test_optpkg.py index bb4c1bff3..1810db182 100644 --- a/fury/tests/test_optpkg.py +++ b/fury/tests/test_optpkg.py @@ -11,49 +11,49 @@ def test_get_info(): expected_keys = [ - 'fury_version', - 'pkg_path', - 'commit_hash', - 'sys_version', - 'sys_executable', - 'sys_platform', - 'numpy_version', - 'scipy_version', - 'vtk_version', + "fury_version", + "pkg_path", + "commit_hash", + "sys_version", + "sys_executable", + "sys_platform", + "numpy_version", + "scipy_version", + "vtk_version", ] info = get_info() current_keys = info.keys() for ek in expected_keys: assert_true(ek in current_keys) - assert_true(info[ek] not in [None, '']) + assert_true(info[ek] not in [None, ""]) def test_is_tripwire(): assert_false(is_tripwire(object())) - assert_true(is_tripwire(TripWire('some message'))) - assert_false(is_tripwire(ValueError('some message'))) + assert_true(is_tripwire(TripWire("some message"))) + assert_false(is_tripwire(ValueError("some message"))) def test_tripwire(): # Test tripwire object - silly_module_name = TripWire('We do not have silly_module_name') - npt.assert_raises(TripWireError, getattr, silly_module_name, 'do_silly_thing') + silly_module_name = TripWire("We do not have silly_module_name") + npt.assert_raises(TripWireError, getattr, silly_module_name, "do_silly_thing") npt.assert_raises(TripWireError, silly_module_name) # Check AttributeError can be checked too try: - silly_module_name.__wrapped__ + _ = silly_module_name.__wrapped__ except TripWireError as err: assert_true(isinstance(err, AttributeError)) else: - raise RuntimeError('No error raised, but expected') + raise RuntimeError("No error raised, but expected") def test_optional_package(): - pkg, have_pkg, _ = optional_package('fake_pkg') + pkg, have_pkg, _ = optional_package("fake_pkg") npt.assert_raises(TripWireError, pkg) assert_false(have_pkg) - pkg, have_pkg, _ = optional_package('os') + pkg, have_pkg, _ = optional_package("os") assert_true(isinstance(pkg, ModuleType)) - npt.assert_equal(pkg.__name__, 'os') + npt.assert_equal(pkg.__name__, "os") assert_true(have_pkg) diff --git a/fury/tests/test_pick.py b/fury/tests/test_pick.py index 5e09bb7c0..bfe5c09ac 100644 --- a/fury/tests/test_pick.py +++ b/fury/tests/test_pick.py @@ -24,12 +24,11 @@ def test_fake(): @pytest.mark.skipif( True, - reason='Pytests triggers segfault here that ' - 'cannot be replicated by individual' - 'tests', + reason="Pytests triggers segfault here that " + "cannot be replicated by individual" + "tests", ) def test_picking_manager(): - xyz = 10 * np.random.rand(100, 3) colors = np.random.rand(100, 4) radii = np.random.rand(100) + 0.5 @@ -51,7 +50,7 @@ def test_picking_manager(): pickm = pick.PickingManager() - record_indices = {'vertex_indices': [], 'face_indices': [], 'xyz': [], 'actor': []} + record_indices = {"vertex_indices": [], "face_indices": [], "xyz": [], "actor": []} def timer_callback(_obj, _event): cnt = next(counter) @@ -61,10 +60,10 @@ def timer_callback(_obj, _event): if cnt % 10 == 0: # pick at position info = pickm.pick((900 / 2, 768 / 2), scene) - record_indices['vertex_indices'].append(info['vertex']) - record_indices['face_indices'].append(info['face']) - record_indices['xyz'].append(info['xyz']) - record_indices['actor'].append(info['actor']) + record_indices["vertex_indices"].append(info["vertex"]) + record_indices["face_indices"].append(info["face"]) + record_indices["xyz"].append(info["xyz"]) + record_indices["actor"].append(info["actor"]) showm.render() if cnt == 15: @@ -76,14 +75,14 @@ def timer_callback(_obj, _event): showm.add_timer_callback(True, 200, timer_callback) showm.start() - assert_greater(np.sum(np.array(record_indices['vertex_indices'])), 1) - assert_greater(np.sum(np.array(record_indices['face_indices'])), 1) + assert_greater(np.sum(np.array(record_indices["vertex_indices"])), 1) + assert_greater(np.sum(np.array(record_indices["face_indices"])), 1) - for ac in record_indices['actor']: + for ac in record_indices["actor"]: if ac is not None: npt.assert_equal(ac is sphere_actor, True) - assert_greater(np.sum(np.abs(np.diff(np.array(record_indices['xyz']), axis=0))), 0) + assert_greater(np.sum(np.abs(np.diff(np.array(record_indices["xyz"]), axis=0))), 0) def _get_three_cubes(): @@ -95,12 +94,11 @@ def _get_three_cubes(): @pytest.mark.skipif( True, - reason='Pytests triggers segfault here that ' - 'cannot be replicated by individual' - 'tests', + reason="Pytests triggers segfault here that " + "cannot be replicated by individual" + "tests", ) def test_selector_manager(): - centers, colors, radii = _get_three_cubes() scene = window.Scene() @@ -126,7 +124,7 @@ def test_selector_manager(): # use itertools to avoid global variables counter = itertools.count() - selm = pick.SelectionManager(select='faces') + selm = pick.SelectionManager(select="faces") selm.selectable_off([tex_actor]) selm.selectable_on([tex_actor]) @@ -139,13 +137,13 @@ def timer_callback(_obj, _event): # select large area info_plus = selm.select((900 // 2, 768 // 2), scene, (30, 30)) for info in info_plus.keys(): - if info_plus[info]['actor'] in [cube_actor, pts_actor]: + if info_plus[info]["actor"] in [cube_actor, pts_actor]: npt.assert_(True) else: npt.assert_(False) # select single pixel info_ = selm.pick((900 // 2, 768 // 2), scene) - if info_['actor'] in [cube_actor, pts_actor]: + if info_["actor"] in [cube_actor, pts_actor]: npt.assert_(True) else: npt.assert_(False) @@ -164,14 +162,14 @@ def timer_callback(_obj, _event): @pytest.mark.skipif( True, - reason='Pytests triggers segfault here that ' - 'cannot be replicated by individual' - 'tests', + reason="Pytests triggers segfault here that " + "cannot be replicated by individual" + "tests", ) def test_hover_selection_faces(recording=False): # simply hover going through blue, green, red - recording_filename = join(DATA_DIR, 'selector_faces.log.gz') + recording_filename = join(DATA_DIR, "selector_faces.log.gz") centers, colors, radii = _get_three_cubes() @@ -181,7 +179,7 @@ def test_hover_selection_faces(recording=False): scene.add(cube_actor) - selm = pick.SelectionManager(select='faces') + selm = pick.SelectionManager(select="faces") showm = window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True @@ -194,7 +192,7 @@ def hover_callback(_obj, _event): global track_objects event_pos = selm.event_position(showm.iren) info = selm.select(event_pos, showm.scene, (10, 10)) - selected_faces = info[0]['face'] + selected_faces = info[0]["face"] if selected_faces is not None: track_objects.append(selected_faces[0] // 12) showm.render() @@ -215,15 +213,15 @@ def hover_callback(_obj, _event): @pytest.mark.skipif( True, - reason='Pytests triggers segfault here that ' - 'cannot be replicated by individual' - 'tests', + reason="Pytests triggers segfault here that " + "cannot be replicated by individual" + "tests", ) def test_hover_selection_vertices(recording=False): # simply hover through blue, green, red cubes # close to any vertices of each of the cubes - recording_filename = join(DATA_DIR, 'selector_vertices.log.gz') + recording_filename = join(DATA_DIR, "selector_vertices.log.gz") centers, colors, radii = _get_three_cubes() @@ -233,7 +231,7 @@ def test_hover_selection_vertices(recording=False): scene.add(cube_actor) - selm = pick.SelectionManager(select='vertices') + selm = pick.SelectionManager(select="vertices") showm = window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True @@ -246,7 +244,7 @@ def hover_callback(_obj, _event): global track_objects2 event_pos = selm.event_position(showm.iren) info = selm.select(event_pos, showm.scene, (100, 100)) - selected_triangles = info[0]['vertex'] + selected_triangles = info[0]["vertex"] if selected_triangles is not None: track_objects2.append(selected_triangles[0] // 8) showm.render() @@ -267,14 +265,14 @@ def hover_callback(_obj, _event): @pytest.mark.skipif( True, - reason='Pytests triggers segfault here that ' - 'cannot be replicated by individual' - 'tests', + reason="Pytests triggers segfault here that " + "cannot be replicated by individual" + "tests", ) def test_hover_selection_actors_only(recording=False): # simply hover going through blue, green, red cubes - recording_filename = join(DATA_DIR, 'selector_actors.log.gz') + recording_filename = join(DATA_DIR, "selector_actors.log.gz") centers, colors, radii = _get_three_cubes() @@ -284,7 +282,7 @@ def test_hover_selection_actors_only(recording=False): scene.add(cube_actor) - selm = pick.SelectionManager(select='actors') + selm = pick.SelectionManager(select="actors") showm = window.ShowManager( scene, size=(900, 768), reset_camera=False, order_transparent=True @@ -293,7 +291,7 @@ def test_hover_selection_actors_only(recording=False): def hover_callback(_obj, _event): event_pos = selm.event_position(showm.iren) info = selm.pick(event_pos, showm.scene) - selected_actor = info['actor'] + selected_actor = info["actor"] # print(id(selected_actor), id(cube_actor)) if selected_actor is not None: npt.assert_equal(id(cube_actor), id(selected_actor)) @@ -308,5 +306,5 @@ def hover_callback(_obj, _event): showm.play_events_from_file(recording_filename) -if __name__ == '__main__': +if __name__ == "__main__": npt.run_module_suite() diff --git a/fury/tests/test_primitive.py b/fury/tests/test_primitive.py index bffa4e396..baac44a2b 100644 --- a/fury/tests/test_primitive.py +++ b/fury/tests/test_primitive.py @@ -45,7 +45,7 @@ def test_vertices_primitives_octagonalprism(): # Testing the default vertices of the primitive octagonal prism. vertices, _ = fp.prim_octagonalprism() shape = (16, 3) - two = (1 + float('{:.7f}'.format(math.sqrt(2)))) / 4 + two = (1 + float("{:.7f}".format(math.sqrt(2)))) / 4 npt.assert_equal(vertices.shape, shape) npt.assert_equal(np.mean(vertices), 0) @@ -56,12 +56,8 @@ def test_vertices_primitives_octagonalprism(): def test_vertices_primitives_pentagonalprism(): # Testing the default vertices of the primitive pentagonal prism. vertices, _ = fp.prim_pentagonalprism() - lower_face = vertices[:, 0:2][ - 0:5, - ] - upper_face = vertices[:, 0:2][ - 5:10, - ] + lower_face = vertices[:, 0:2][0:5,] + upper_face = vertices[:, 0:2][5:10,] centroid_upper = np.mean(upper_face, 0) centroid_lower = np.mean(lower_face, 0) shape = (10, 3) @@ -78,7 +74,7 @@ def test_vertices_primitives_triangularprism(): # Testing the default vertices of the primitive triangular prism. vertices, _ = fp.prim_triangularprism() shape = (6, 3) - three = float('{:.7f}'.format(math.sqrt(3))) + three = float("{:.7f}".format(math.sqrt(3))) npt.assert_equal(vertices.shape, shape) npt.assert_equal(np.mean(vertices), 0) npt.assert_equal(vertices.min(), -1 / three) @@ -103,12 +99,12 @@ def test_triangles_primitives(): def test_spheres_primitives(): l_primitives = [ - ('symmetric362', 362, 720), - ('symmetric642', 642, 1280), - ('symmetric724', 724, 1444), - ('repulsion724', 724, 1444), - ('repulsion100', 100, 196), - ('repulsion200', 200, 396), + ("symmetric362", 362, 720), + ("symmetric642", 642, 1280), + ("symmetric724", 724, 1444), + ("repulsion724", 724, 1444), + ("repulsion100", 100, 196), + ("repulsion200", 200, 396), ] for name, nb_verts, nb_triangles in l_primitives: @@ -120,7 +116,7 @@ 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, "sym362") l_primitives = [ (10, 10, 82, 160), @@ -142,7 +138,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("symmetric362") npt.assert_equal(sq_verts.shape, s_verts.shape) npt.assert_equal(sq_faces.shape, s_faces.shape) @@ -266,7 +262,7 @@ def test_repeat_primitive_function(): colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) * 255 phi_theta = np.array([[1, 1], [1, 2], [2, 1]]) - res = fp.repeat_primitive_function( + _ = fp.repeat_primitive_function( func=fp.prim_superquadric, centers=centers, func_args=phi_theta, diff --git a/fury/tests/test_stream.py b/fury/tests/test_stream.py index 9e9a6fe8a..b257e53b7 100644 --- a/fury/tests/test_stream.py +++ b/fury/tests/test_stream.py @@ -42,7 +42,7 @@ def loop(): def test_rtc_video_stream(loop: asyncio.AbstractEventLoop): if not WEBRTC_AVAILABLE: - print('\n aiortc not available -> skipping test\n') + print("\n aiortc not available -> skipping test\n") return def test(use_raw_array, ms_stream=16): @@ -135,7 +135,7 @@ def test_pillow(): img_buffer_manager.get_jpeg() width, height, frame = img_buffer_manager.get_current_frame() - image = np.frombuffer(frame, 'uint8')[0 : width * height * 3].reshape( + image = np.frombuffer(frame, "uint8")[0 : width * height * 3].reshape( (height, width, 3) ) report = window.analyze_snapshot(image, find_objects=True) @@ -147,14 +147,14 @@ def test_pillow(): def test_rtc_video_stream_whitout_cython(loop: asyncio.AbstractEventLoop): if not WEBRTC_AVAILABLE: - print('\n aiortc not available -> skipping test\n') + print("\n aiortc not available -> skipping test\n") return use_raw_array = True ms_stream = 0 # creates a context without cython - with mock.patch.dict(sys.modules, {'pyximport': None}): - reload(sys.modules['fury.stream.server.main']) + with mock.patch.dict(sys.modules, {"pyximport": None}): + reload(sys.modules["fury.stream.server.main"]) width_0 = 100 height_0 = 200 @@ -196,7 +196,7 @@ def test_rtc_video_stream_whitout_cython(loop: asyncio.AbstractEventLoop): stream.stop() stream.cleanup() - reload(sys.modules['fury.stream.server.main']) + reload(sys.modules["fury.stream.server.main"]) def test_client_and_buffer_manager(): @@ -240,7 +240,7 @@ def test(use_raw_array, ms_stream=16): width, height, frame = img_buffer_manager.get_current_frame() # assert width == showm.size[0] and height == showm.size[1] - image = np.frombuffer(frame, 'uint8')[0 : width * height * 3].reshape( + image = np.frombuffer(frame, "uint8")[0 : width * height * 3].reshape( (height, width, 3) ) # image = np.flipud(image) @@ -381,13 +381,13 @@ async def test(use_raw_array, ms_stream=16): for _ in range(10): stream_interaction.circular_queue.enqueue( np.array( - [_CQUEUE.event_ids.mouse_weel, 1, 0, 0, 0, 0, 0.1, 0], dtype='d' + [_CQUEUE.event_ids.mouse_weel, 1, 0, 0, 0, 0, 0.1, 0], dtype="d" ) ) for _ in range(10): stream_interaction.circular_queue.enqueue( np.array( - [_CQUEUE.event_ids.mouse_weel, -1, 0, 0, 0, 0, 0.1, 0], dtype='d' + [_CQUEUE.event_ids.mouse_weel, -1, 0, 0, 0, 0, 0.1, 0], dtype="d" ) ) dxs = [] @@ -397,7 +397,7 @@ async def test(use_raw_array, ms_stream=16): stream_interaction.circular_queue.enqueue( np.array( [_CQUEUE.event_ids.left_btn_press, 0, x, y, ctrl, shift, 0.1, 0], - dtype='d', + dtype="d", ) ) for i in range(50): @@ -413,13 +413,13 @@ async def test(use_raw_array, ms_stream=16): stream_interaction.circular_queue.enqueue( np.array( [_CQUEUE.event_ids.mouse_move, 0, x, y, ctrl, shift, 0.1, 0], - dtype='d', + dtype="d", ) ) stream_interaction.circular_queue.enqueue( np.array( [_CQUEUE.event_ids.left_btn_release, 0, x, y, ctrl, shift, 0.1, 0], - dtype='d', + dtype="d", ) ) @@ -537,7 +537,7 @@ def test(use_raw_array=False): m_buffer = tools.SharedMemMultiDimensionalBuffer( max_size=max_size, dimension=dimension ) - m_buffer.buffer = np.arange((max_size + 1) * dimension).astype('d') + m_buffer.buffer = np.arange((max_size + 1) * dimension).astype("d") m_buffer[1] = np.array([0.2, 0.3, 0.4, 0.5]) assert len(m_buffer[0]) == dimension if not use_raw_array: @@ -679,7 +679,7 @@ def test_queue_and_webserver(): queue = tools.ArrayCircularQueue(max_size=max_size, dimension=dimension) else: queue = tools.SharedMemCircularQueue(max_size=max_size, dimension=dimension) - set_weel({'deltaY': 0.2, 'timestampInMs': 123}, queue) + set_weel({"deltaY": 0.2, "timestampInMs": 123}, queue) arr_queue = queue.dequeue() arr = np.zeros(dimension) arr[0] = _CQUEUE.event_ids.mouse_weel @@ -688,36 +688,36 @@ def test_queue_and_webserver(): npt.assert_equal(arr, arr_queue) # if the mouse position has been stored correctly in the circular queue - data = {'x': -3, 'y': 2.0, 'ctrlKey': 1, 'shiftKey': 0, 'timestampInMs': 123} + data = {"x": -3, "y": 2.0, "ctrlKey": 1, "shiftKey": 0, "timestampInMs": 123} set_mouse(data, queue) arr_queue = queue.dequeue() arr = np.zeros(dimension) arr[0] = _CQUEUE.event_ids.mouse_move - arr[_CQUEUE.index_info.x] = data['x'] - arr[_CQUEUE.index_info.y] = data['y'] - arr[_CQUEUE.index_info.ctrl] = data['ctrlKey'] - arr[_CQUEUE.index_info.shift] = data['shiftKey'] - arr[_CQUEUE.index_info.user_timestamp] = data['timestampInMs'] + arr[_CQUEUE.index_info.x] = data["x"] + arr[_CQUEUE.index_info.y] = data["y"] + arr[_CQUEUE.index_info.ctrl] = data["ctrlKey"] + arr[_CQUEUE.index_info.shift] = data["shiftKey"] + arr[_CQUEUE.index_info.user_timestamp] = data["timestampInMs"] npt.assert_equal(arr, arr_queue) data = { - 'mouseButton': 0, - 'on': 1, - 'x': -3, - 'y': 2.0, - 'ctrlKey': 1, - 'shiftKey': 0, - 'timestampInMs': 123, + "mouseButton": 0, + "on": 1, + "x": -3, + "y": 2.0, + "ctrlKey": 1, + "shiftKey": 0, + "timestampInMs": 123, } set_mouse_click(data, queue) arr_queue = queue.dequeue() arr = np.zeros(dimension) arr[0] = _CQUEUE.event_ids.left_btn_press - arr[_CQUEUE.index_info.x] = data['x'] - arr[_CQUEUE.index_info.y] = data['y'] - arr[_CQUEUE.index_info.ctrl] = data['ctrlKey'] - arr[_CQUEUE.index_info.shift] = data['shiftKey'] - arr[_CQUEUE.index_info.user_timestamp] = data['timestampInMs'] + arr[_CQUEUE.index_info.x] = data["x"] + arr[_CQUEUE.index_info.y] = data["y"] + arr[_CQUEUE.index_info.ctrl] = data["ctrlKey"] + arr[_CQUEUE.index_info.shift] = data["shiftKey"] + arr[_CQUEUE.index_info.user_timestamp] = data["timestampInMs"] npt.assert_equal(arr, arr_queue) queue.cleanup() @@ -749,7 +749,7 @@ def test(use_raw_array): stream_interaction.circular_queue.head_tail_buffer, stream_interaction.circular_queue.buffer._buffer, 8000, - 'localhost', + "localhost", True, True, run_app=False, @@ -761,7 +761,7 @@ def test(use_raw_array): stream_interaction.circular_queue.head_tail_buffer_name, stream_interaction.circular_queue.buffer.buffer_name, 8000, - 'localhost', + "localhost", True, True, True, @@ -777,7 +777,7 @@ def test(use_raw_array): test(False) -@pytest.mark.skipif(True, reason='Infinite loop. Need to check this test.') +@pytest.mark.skipif(True, reason="Infinite loop. Need to check this test.") def test_widget(): if not PY_VERSION_8: return diff --git a/fury/tests/test_testing.py b/fury/tests/test_testing.py index 79c99b393..39aae8bf7 100644 --- a/fury/tests/test_testing.py +++ b/fury/tests/test_testing.py @@ -1,4 +1,5 @@ """Testing file unittest.""" + import sys import warnings @@ -13,16 +14,16 @@ def test_callback(): events_name = [ - 'CharEvent', - 'MouseMoveEvent', - 'KeyPressEvent', - 'KeyReleaseEvent', - 'LeftButtonPressEvent', - 'LeftButtonReleaseEvent', - 'RightButtonPressEvent', - 'RightButtonReleaseEvent', - 'MiddleButtonPressEvent', - 'MiddleButtonReleaseEvent', + "CharEvent", + "MouseMoveEvent", + "KeyPressEvent", + "KeyReleaseEvent", + "LeftButtonPressEvent", + "LeftButtonReleaseEvent", + "RightButtonPressEvent", + "RightButtonReleaseEvent", + "MiddleButtonPressEvent", + "MiddleButtonReleaseEvent", ] class SimplestUI(UI): @@ -47,24 +48,24 @@ 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, size=current_size, title="FURY GridUI") scene.add(simple_ui) event_counter = ft.EventCounter() event_counter.monitor(simple_ui) - events_name = ['{0} 0 0 0 0 0 0 0'.format(name) for name in events_name] - events_str = '# StreamVersion 1\n' + '\n'.join(events_name) + events_name = ["{0} 0 0 0 0 0 0 0".format(name) for name in events_name] + events_str = "# StreamVersion 1\n" + "\n".join(events_name) show_manager.play_events(events_str) npt.assert_equal(len(event_counter.events_counts), len(events_name)) def test_captured_output(): def foo(): - print('hello world!') + print("hello world!") with ft.captured_output() as (out, _): foo() - npt.assert_equal(out.getvalue().strip(), 'hello world!') + npt.assert_equal(out.getvalue().strip(), "hello world!") def test_assert(): @@ -88,7 +89,7 @@ def assert_warn_len_equal(mod, n_in_context): # when raising warnings inside a catch_warnings block. So, there is a # warning generated by the tests within the context manager, but no # previous warnings. - if 'version' in mod_warns: + if "version" in mod_warns: npt.assert_equal(len(mod_warns), 2) # including 'version' else: npt.assert_equal(len(mod_warns), n_in_context) @@ -102,21 +103,21 @@ def test_clear_and_catch_warnings(): except AttributeError: pass - npt.assert_equal(getattr(my_mod, '__warningregistry__', {}), {}) + npt.assert_equal(getattr(my_mod, "__warningregistry__", {}), {}) with ft.clear_and_catch_warnings(modules=[my_mod]): - warnings.simplefilter('ignore') - warnings.warn('Some warning') + warnings.simplefilter("ignore") + warnings.warn("Some warning", stacklevel=1) npt.assert_equal(my_mod.__warningregistry__, {}) # Without specified modules, don't clear warnings during context with ft.clear_and_catch_warnings(): - warnings.warn('Some warning') + warnings.warn("Some warning", stacklevel=1) assert_warn_len_equal(my_mod, 1) # Confirm that specifying module keeps old warning, does not add new with ft.clear_and_catch_warnings(modules=[my_mod]): - warnings.warn('Another warning') + warnings.warn("Another warning", stacklevel=1) assert_warn_len_equal(my_mod, 1) # Another warning, no module spec does add to warnings dict, except on # Python 3 (see comments in `assert_warn_len_equal`) with ft.clear_and_catch_warnings(): - warnings.warn('Another warning') + warnings.warn("Another warning", stacklevel=1) assert_warn_len_equal(my_mod, 2) diff --git a/fury/tests/test_thread.py b/fury/tests/test_thread.py index 1427ffb74..35e2ac041 100644 --- a/fury/tests/test_thread.py +++ b/fury/tests/test_thread.py @@ -1,10 +1,7 @@ - from threading import Thread import time import numpy as np -import numpy.testing as npt -import pytest from fury import actor, window from fury.utils import rotate, update_actor, vertices_from_actor @@ -16,17 +13,15 @@ def test_multithreading(): radii = np.random.random(100) + 0.5 scene = window.Scene() - sphere_actor = actor.sphere(centers=xyz, - colors=colors, - radii=radii, - use_primitive=False) + sphere_actor = actor.sphere( + centers=xyz, colors=colors, radii=radii, use_primitive=False + ) scene.add(sphere_actor) # Preparing the show manager as usual - showm = window.ShowManager(scene, - size=(900, 768), - reset_camera=False, - order_transparent=True) + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) # showm.initialize() @@ -45,9 +40,13 @@ def callback1(): showm.exit() # if not showm.is_done(): - # arr = window.snapshot(scene, render_window = showm.window, fname = "test.png") - # showm.exit() - # npt.assert_equal(np.sum(arr) > 1, True) + # arr = window.snapshot( + # scene, + # render_window=showm.window, + # fname="test.png", + # ) + # showm.exit() + # npt.assert_equal(np.sum(arr) > 1, True) thread_a = Thread(target=callback1) thread_a.start() diff --git a/fury/tests/test_transform.py b/fury/tests/test_transform.py index 2ecd92f62..8c463592e 100644 --- a/fury/tests/test_transform.py +++ b/fury/tests/test_transform.py @@ -66,7 +66,7 @@ def test_sphere_cart(): def test_euler_matrix(): - rotation = euler_matrix(1, 2, 3, 'syxz') + rotation = euler_matrix(1, 2, 3, "syxz") npt.assert_equal(np.allclose(np.sum(rotation[0]), -1.34786452), True) rotation = euler_matrix(1, 2, 3, (0, 1, 0, 1)) diff --git a/fury/tests/test_utils.py b/fury/tests/test_utils.py index 07d5a2785..83aeac3f3 100644 --- a/fury/tests/test_utils.py +++ b/fury/tests/test_utils.py @@ -1,4 +1,5 @@ """Module for testing primitive.""" + import numpy as np import numpy.testing as npt import pytest @@ -55,16 +56,16 @@ vtk_matrix_to_numpy, ) -dipy, have_dipy, _ = optional_package('dipy') +dipy, have_dipy, _ = optional_package("dipy") def test_apply_affine_to_actor(interactive=False): text_act = actor.text_3d( - 'ALIGN TOP RIGHT', justification='right', vertical_justification='top' + "ALIGN TOP RIGHT", justification="right", vertical_justification="top" ) text_act2 = TextActor3D() - text_act2.SetInput('ALIGN TOP RIGHT') + text_act2.SetInput("ALIGN TOP RIGHT") text_act2.GetTextProperty().SetFontFamilyToArial() text_act2.GetTextProperty().SetFontSize(24) text_act2.SetScale((1.0 / 24.0 * 12,) * 3) @@ -76,7 +77,7 @@ def test_apply_affine_to_actor(interactive=False): text_bounds = [0, 0, 0, 0] text_act2.GetBoundingBox(text_bounds) - initial_bounds = text_act2.GetBounds() + _ = text_act2.GetBounds() affine = np.eye(4) affine[:3, -1] += (-text_bounds[1], 0, 0) @@ -117,7 +118,7 @@ def test_map_coordinates_3d_4d(): ] ) - for d, e in zip([data_1, data_2], [expected, expected2]): + for d, e in zip([data_1, data_2], [expected, expected2], strict=False): values = map_coordinates_3d_4d(d, indices) npt.assert_array_almost_equal(values, e) @@ -163,7 +164,7 @@ def test_polydata_polygon(interactive=False): [1, 5, 7], [1, 7, 3], ], - dtype='i8', + dtype="i8", ) my_vertices = np.array( [ @@ -251,60 +252,60 @@ def test_add_polydata_numeric_field(): poly_field_data = my_polydata.GetFieldData() npt.assert_equal(poly_field_data.GetNumberOfArrays(), 0) bool_data = True - add_polydata_numeric_field(my_polydata, 'Test Bool', bool_data) + add_polydata_numeric_field(my_polydata, "Test Bool", bool_data) npt.assert_equal(poly_field_data.GetNumberOfArrays(), 1) - npt.assert_equal(poly_field_data.GetArray('Test Bool').GetValue(0), bool_data) - poly_field_data.RemoveArray('Test Bool') + npt.assert_equal(poly_field_data.GetArray("Test Bool").GetValue(0), bool_data) + poly_field_data.RemoveArray("Test Bool") npt.assert_equal(poly_field_data.GetNumberOfArrays(), 0) int_data = 1 - add_polydata_numeric_field(my_polydata, 'Test Int', int_data) + add_polydata_numeric_field(my_polydata, "Test Int", int_data) npt.assert_equal(poly_field_data.GetNumberOfArrays(), 1) - npt.assert_equal(poly_field_data.GetArray('Test Int').GetValue(0), int_data) - poly_field_data.RemoveArray('Test Int') + npt.assert_equal(poly_field_data.GetArray("Test Int").GetValue(0), int_data) + poly_field_data.RemoveArray("Test Int") npt.assert_equal(poly_field_data.GetNumberOfArrays(), 0) float_data = 0.1 add_polydata_numeric_field( - my_polydata, 'Test Float', float_data, array_type=VTK_FLOAT + my_polydata, "Test Float", float_data, array_type=VTK_FLOAT ) npt.assert_equal(poly_field_data.GetNumberOfArrays(), 1) npt.assert_almost_equal( - poly_field_data.GetArray('Test Float').GetValue(0), float_data + poly_field_data.GetArray("Test Float").GetValue(0), float_data ) - poly_field_data.RemoveArray('Test Float') + poly_field_data.RemoveArray("Test Float") npt.assert_equal(poly_field_data.GetNumberOfArrays(), 0) double_data = 0.1 add_polydata_numeric_field( - my_polydata, 'Test Double', double_data, array_type=VTK_DOUBLE + my_polydata, "Test Double", double_data, array_type=VTK_DOUBLE ) npt.assert_equal(poly_field_data.GetNumberOfArrays(), 1) - npt.assert_equal(poly_field_data.GetArray('Test Double').GetValue(0), double_data) - poly_field_data.RemoveArray('Test Double') + npt.assert_equal(poly_field_data.GetArray("Test Double").GetValue(0), double_data) + poly_field_data.RemoveArray("Test Double") npt.assert_equal(poly_field_data.GetNumberOfArrays(), 0) array_data = [-1, 0, 1] - add_polydata_numeric_field(my_polydata, 'Test Array', array_data) + add_polydata_numeric_field(my_polydata, "Test Array", array_data) npt.assert_equal(poly_field_data.GetNumberOfArrays(), 1) npt.assert_equal( - numpy_support.vtk_to_numpy(poly_field_data.GetArray('Test Array')), array_data + numpy_support.vtk_to_numpy(poly_field_data.GetArray("Test Array")), array_data ) - poly_field_data.RemoveArray('Test Array') + poly_field_data.RemoveArray("Test Array") npt.assert_equal(poly_field_data.GetNumberOfArrays(), 0) ndarray_data = np.array([[-0.1, -0.1], [0, 0], [0.1, 0.1]]) add_polydata_numeric_field( - my_polydata, 'Test NDArray', ndarray_data, array_type=VTK_FLOAT + my_polydata, "Test NDArray", ndarray_data, array_type=VTK_FLOAT ) npt.assert_equal(poly_field_data.GetNumberOfArrays(), 1) npt.assert_almost_equal( - numpy_support.vtk_to_numpy(poly_field_data.GetArray('Test NDArray')), + numpy_support.vtk_to_numpy(poly_field_data.GetArray("Test NDArray")), ndarray_data, ) def test_get_polydata_field(): my_polydata = PolyData() - field_data = get_polydata_field(my_polydata, 'Test') + field_data = get_polydata_field(my_polydata, "Test") npt.assert_equal(field_data, None) data = 1 - field_name = 'Test' + field_name = "Test" vtk_data = numpy_support.numpy_to_vtk(data) vtk_data.SetName(field_name) my_polydata.GetFieldData().AddArray(vtk_data) @@ -331,20 +332,20 @@ def test_set_polydata_tangents(): array = np.array([[0, 0, 0], [1, 1, 1]]) set_polydata_tangents(my_polydata, array) npt.assert_equal(poly_point_data.GetNumberOfArrays(), 1) - npt.assert_equal(poly_point_data.HasArray('Tangents'), True) + npt.assert_equal(poly_point_data.HasArray("Tangents"), True) def test_asbytes(): - text = [b'test', 'test'] + text = [b"test", "test"] for t in text: - npt.assert_equal(utils.asbytes(t), b'test') + npt.assert_equal(utils.asbytes(t), b"test") def trilinear_interp_numpy(input_array, indices): """Evaluate the input_array data at the given indices.""" if input_array.ndim <= 2 or input_array.ndim >= 5: - raise ValueError('Input array can only be 3d or 4d') + raise ValueError("Input array can only be 3d or 4d") x_indices = indices[:, 0] y_indices = indices[:, 1] @@ -387,7 +388,6 @@ def trilinear_interp_numpy(input_array, indices): def test_trilinear_interp(): - A = np.zeros((5, 5, 5)) A[2, 2, 2] = 1 @@ -406,7 +406,6 @@ def test_trilinear_interp(): def test_vtk_matrix_to_numpy(): - A = np.array([[2.0, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 1]]) for shape in [3, 4]: @@ -445,7 +444,6 @@ def test_numpy_to_vtk_image_data(): def test_get_grid_cell_position(): - shapes = 10 * [(50, 50), (50, 50), (50, 50), (80, 50)] npt.assert_raises(ValueError, get_grid_cells_position, shapes=shapes, dim=(1, 1)) @@ -456,7 +454,6 @@ def test_get_grid_cell_position(): def test_rotate(interactive=False): - A = np.zeros((50, 50, 50)) A[20:30, 20:30, 10:40] = 100 @@ -495,14 +492,12 @@ def test_rotate(interactive=False): if interactive: window.show(scene) else: - arr = window.snapshot(scene, offscreen=True) red_sum_new = arr[..., 0].sum() npt.assert_equal(red_sum_new > red_sum, True) def test_triangle_order(): - test_vert = np.array([[-1, -2, 0], [1, -1, 0], [2, 1, 0], [3, 0, 0]]) test_tri = np.array([[0, 1, 2], [2, 1, 0]]) @@ -515,7 +510,6 @@ def test_triangle_order(): def test_change_vertices_order(): - triangles = np.array([[1, 2, 3], [3, 2, 1], [5, 4, 3], [3, 4, 5]]) npt.assert_equal(triangles[0], utils.change_vertices_order(triangles[1])) @@ -523,7 +517,6 @@ def test_change_vertices_order(): def test_winding_order(): - vertices = np.array([[0, 0, 0], [1, 2, 0], [3, 0, 0], [2, 0, 0]]) triangles = np.array([[0, 1, 3], [2, 1, 0]]) @@ -534,7 +527,6 @@ def test_winding_order(): def test_vertices_from_actor(interactive=False): - expected = np.array( [ [1.5, -0.5, 0.0], @@ -578,15 +570,15 @@ def test_vertices_from_actor(interactive=False): # test colors_from_actor: l_colors = utils.colors_from_actor(actr) l_colors_vtk = utils.colors_from_actor(actr, as_vtk=True) - l_colors_none = utils.colors_from_actor(actr, array_name='col') + l_colors_none = utils.colors_from_actor(actr, array_name="col") npt.assert_equal(l_colors_none, None) npt.assert_equal(isinstance(l_colors_vtk, UnsignedCharArray), True) npt.assert_equal(np.unique(l_colors, axis=0).shape, colors.shape) - l_array = utils.array_from_actor(actr, 'colors') - l_array_vtk = utils.array_from_actor(actr, 'colors', as_vtk=True) - l_array_none = utils.array_from_actor(actr, 'col') + l_array = utils.array_from_actor(actr, "colors") + l_array_vtk = utils.array_from_actor(actr, "colors", as_vtk=True) + l_array_none = utils.array_from_actor(actr, "col") npt.assert_array_equal(l_array, l_colors) npt.assert_equal(l_array_none, None) @@ -608,11 +600,11 @@ def test_normals_from_actor(): def test_normals_to_actor(): my_actor = actor.square(np.array([[0, 0, 0]])) poly_point_data = my_actor.GetMapper().GetInput().GetPointData() - npt.assert_equal(poly_point_data.HasArray('Normals'), False) + npt.assert_equal(poly_point_data.HasArray("Normals"), False) array = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]]) normals_to_actor(my_actor, array) - npt.assert_equal(poly_point_data.HasArray('Normals'), True) - normals = numpy_support.vtk_to_numpy(poly_point_data.GetArray('Normals')) + npt.assert_equal(poly_point_data.HasArray("Normals"), True) + normals = numpy_support.vtk_to_numpy(poly_point_data.GetArray("Normals")) npt.assert_array_equal(normals, array) @@ -639,11 +631,11 @@ def test_tangents_from_direction_of_anisotropy(): def test_tangents_to_actor(): my_actor = actor.square(np.array([[0, 0, 0]])) poly_point_data = my_actor.GetMapper().GetInput().GetPointData() - npt.assert_equal(poly_point_data.HasArray('Tangents'), False) + npt.assert_equal(poly_point_data.HasArray("Tangents"), False) array = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]]) tangents_to_actor(my_actor, array) - npt.assert_equal(poly_point_data.HasArray('Tangents'), True) - tangents = numpy_support.vtk_to_numpy(poly_point_data.GetArray('Tangents')) + npt.assert_equal(poly_point_data.HasArray("Tangents"), True) + tangents = numpy_support.vtk_to_numpy(poly_point_data.GetArray("Tangents")) npt.assert_array_equal(tangents, array) @@ -877,7 +869,7 @@ def test_color_check(): def test_is_ui(): panel = Panel2D(position=(0, 0), size=(100, 100)) valid_ui = DummyUI(act=[]) - invalid_ui = DummyActor(act='act') + invalid_ui = DummyActor(act="act") npt.assert_equal(True, is_ui(panel)) npt.assert_equal(True, is_ui(valid_ui)) @@ -894,7 +886,7 @@ def test_empty_array_to_polydata(): npt.assert_raises(ValueError, utils.lines_to_vtk_polydata, lines) -@pytest.mark.skipif(not have_dipy, reason='Requires DIPY') +@pytest.mark.skipif(not have_dipy, reason="Requires DIPY") def test_empty_array_sequence_to_polydata(): from dipy.tracking.streamline import Streamlines @@ -906,13 +898,13 @@ def test_set_polydata_primitives_count(): polydata = PolyData() set_polydata_primitives_count(polydata, 1) - prim_count = get_polydata_field(polydata, 'prim_count')[0] + prim_count = get_polydata_field(polydata, "prim_count")[0] npt.assert_equal(prim_count, 1) def test_get_polydata_primitives_count(): polydata = PolyData() - add_polydata_numeric_field(polydata, 'prim_count', 1, array_type=VTK_INT) + add_polydata_numeric_field(polydata, "prim_count", 1, array_type=VTK_INT) prim_count = get_polydata_primitives_count(polydata) npt.assert_equal(prim_count, 1) @@ -922,14 +914,14 @@ def test_primitives_count_to_actor(): act = actor.axes() primitives_count_to_actor(act, 1) polydata = act.GetMapper().GetInput() - prim_count = get_polydata_field(polydata, 'prim_count')[0] + prim_count = get_polydata_field(polydata, "prim_count")[0] npt.assert_equal(prim_count, 1) def test_primitives_count_from_actor(): act = actor.axes() polydata = act.GetMapper().GetInput() - add_polydata_numeric_field(polydata, 'prim_count', 1, array_type=VTK_INT) + add_polydata_numeric_field(polydata, "prim_count", 1, array_type=VTK_INT) prim_count = primitives_count_from_actor(act) npt.assert_equal(prim_count, 1) diff --git a/fury/tests/test_window.py b/fury/tests/test_window.py index f45607fc9..87115298e 100644 --- a/fury/tests/test_window.py +++ b/fury/tests/test_window.py @@ -8,7 +8,7 @@ from fury import actor, io, shaders, window from fury.animation import Animation, Timeline -from fury.decorators import skip_linux, skip_osx, skip_win +from fury.decorators import skip_osx, skip_win from fury.lib import ImageData, Texture, numpy_support from fury.testing import assert_greater, assert_less_equal, assert_true, captured_output from fury.utils import remove_observer_from_actor @@ -23,7 +23,7 @@ def test_scene(): # numerical errors when moving from float to int values bg_float = (1, 0.501, 0) # That will come in the image in the 0-255 uint scale - bg_color = tuple((np.round(255 * np.array(bg_float))).astype('uint8')) + bg_color = tuple((np.round(255 * np.array(bg_float))).astype("uint8")) scene.background(bg_float) arr = window.snapshot(scene) report = window.analyze_snapshot( @@ -73,12 +73,12 @@ def test_scene(): scene.camera_info() npt.assert_equal( out.getvalue().strip(), - '# Active Camera\n ' - 'Position (0.00, 0.00, 1.00)\n ' - 'Focal Point (0.00, 0.00, 0.00)\n ' - 'View Up (0.00, 1.00, 0.00)', + "# Active Camera\n " + "Position (0.00, 0.00, 1.00)\n " + "Focal Point (0.00, 0.00, 0.00)\n " + "View Up (0.00, 1.00, 0.00)", ) - npt.assert_equal(err.getvalue().strip(), '') + npt.assert_equal(err.getvalue().strip(), "") # Tests for skybox functionality # Test scene created without skybox scene = window.Scene() @@ -98,11 +98,11 @@ def test_scene(): vtk_img.SetDimensions(2, 2, 1) img_arr = np.zeros((2, 2, 3), dtype=np.uint8) img_arr[:, :, i // 2] = checker_arr - vtk_arr = numpy_support.numpy_to_vtk(img_arr.reshape((-1, 3), order='F')) - vtk_arr.SetName('Image') + vtk_arr = numpy_support.numpy_to_vtk(img_arr.reshape((-1, 3), order="F")) + vtk_arr.SetName("Image") img_point_data = vtk_img.GetPointData() img_point_data.AddArray(vtk_arr) - img_point_data.SetActiveScalars('Image') + img_point_data.SetActiveScalars("Image") test_tex.SetInputDataObject(i, vtk_img) test_tex.InterpolateOn() test_tex.MipmapOn() @@ -192,7 +192,6 @@ def test_active_camera(): def test_parallel_projection(): - scene = window.Scene() axes = actor.axes() axes2 = actor.axes() @@ -211,7 +210,7 @@ def test_parallel_projection(): scene.reset_camera() arr = window.snapshot(scene) - scene.projection('parallel') + scene.projection("parallel") # window.show(scene, reset_camera=False) arr2 = window.snapshot(scene) # Because of the parallel projection the two axes @@ -219,13 +218,12 @@ 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("perspective") arr2 = window.snapshot(scene) npt.assert_equal(np.sum(arr2 > 0), np.sum(arr > 0)) def test_order_transparent(): - scene = window.Scene() red_cube = actor.cube( @@ -288,11 +286,11 @@ def test_skybox(): vtk_img.SetDimensions(2, 2, 1) img_arr = np.zeros((2, 2, 3), dtype=np.uint8) img_arr[:, :, i // 2] = checker_arr - vtk_arr = numpy_support.numpy_to_vtk(img_arr.reshape((-1, 3), order='F')) - vtk_arr.SetName('Image') + vtk_arr = numpy_support.numpy_to_vtk(img_arr.reshape((-1, 3), order="F")) + vtk_arr.SetName("Image") img_point_data = vtk_img.GetPointData() img_point_data.AddArray(vtk_arr) - img_point_data.SetActiveScalars('Image') + img_point_data.SetActiveScalars("Image") test_tex.SetInputDataObject(i, vtk_img) test_tex.InterpolateOn() test_tex.MipmapOn() @@ -327,7 +325,7 @@ def test_save_screenshot(): show_m = window.ShowManager(scene, size=window_sz) with InTemporaryDirectory(): - fname = 'test.png' + fname = "test.png" # Basic test show_m.save_screenshot(fname) npt.assert_equal(os.path.exists(fname), True) @@ -351,7 +349,7 @@ def test_save_screenshot(): @pytest.mark.skipif( - skip_win, reason='This test does not work on Windows.' ' Need to be introspected' + skip_win, reason="This test does not work on Windows." " Need to be introspected" ) def test_stereo(): scene = window.Scene() @@ -373,16 +371,16 @@ def test_stereo(): scene.reset_camera() mono = window.snapshot( - scene, fname='stereo_off.png', offscreen=True, size=(300, 300), stereo='off' + scene, fname="stereo_off.png", offscreen=True, size=(300, 300), stereo="off" ) with npt.assert_warns(UserWarning): stereo = window.snapshot( scene, - fname='stereo_horizontal.png', + fname="stereo_horizontal.png", offscreen=True, size=(300, 300), - stereo='On', + stereo="On", ) # mono render should have values in the center @@ -434,7 +432,7 @@ def timer_callback(_obj, _event): # assert_al(ideal_fps, actual_fps) this is very imprecise -@pytest.mark.skipif(True, reason='See TODO in the code') +@pytest.mark.skipif(True, reason="See TODO in the code") def test_record(): xyzr = np.array([[0, 0, 0, 10], [100, 0, 0, 25], [200, 0, 0, 50]]) colors = np.array([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1.0, 1]]) @@ -449,7 +447,7 @@ def test_record(): scene = window.Scene() scene.add(sphere_actor) - def test_content(filename='fury.png', colors_found=(True, True)): + def test_content(filename="fury.png", colors_found=(True, True)): npt.assert_equal(os.path.isfile(filename), True) arr = io.load_image(filename) report = window.analyze_snapshot(arr, colors=[(0, 255, 0), (0, 0, 255)]) @@ -464,16 +462,16 @@ def test_content(filename='fury.png', colors_found=(True, True)): # test out_path and path_numbering, n_frame with InTemporaryDirectory(): - filename = 'tmp_snapshot.png' + filename = "tmp_snapshot.png" window.record(scene, out_path=filename) test_content(filename) window.record(scene, out_path=filename, path_numbering=True) - test_content(filename + '000000.png') + test_content(filename + "000000.png") window.record(scene, out_path=filename, path_numbering=True, n_frames=3) - test_content(filename + '000000.png') - test_content(filename + '000001.png') - test_content(filename + '000002.png') - npt.assert_equal(os.path.isfile(filename + '000003.png'), False) + test_content(filename + "000000.png") + test_content(filename + "000001.png") + test_content(filename + "000002.png") + npt.assert_equal(os.path.isfile(filename + "000003.png"), False) # test verbose with captured_output() as (out, _): @@ -481,9 +479,9 @@ def test_content(filename='fury.png', colors_found=(True, True)): npt.assert_equal( out.getvalue().strip(), - 'Camera Position (315.32, 0.00, 536.73)\n' - 'Camera Focal Point (119.97, 0.00, 0.00)\n' - 'Camera View Up (0.00, 1.00, 0.00)', + "Camera Position (315.32, 0.00, 536.73)\n" + "Camera Focal Point (119.97, 0.00, 0.00)\n" + "Camera View Up (0.00, 1.00, 0.00)", ) # test camera option with InTemporaryDirectory(): @@ -499,18 +497,18 @@ def test_content(filename='fury.png', colors_found=(True, True)): if not skip_osx: with InTemporaryDirectory(): window.record( - scene, out_path='fury_1.png', size=(1000, 1000), magnification=5 + scene, out_path="fury_1.png", size=(1000, 1000), magnification=5 ) - npt.assert_equal(os.path.isfile('fury_1.png'), True) - arr = io.load_image('fury_1.png') + npt.assert_equal(os.path.isfile("fury_1.png"), True) + arr = io.load_image("fury_1.png") npt.assert_equal(arr.shape, (5000, 5000, 3)) window.record( - scene, out_path='fury_2.png', size=(5000, 5000), screen_clip=True + scene, out_path="fury_2.png", size=(5000, 5000), screen_clip=True ) - npt.assert_equal(os.path.isfile('fury_2.png'), True) - arr = io.load_image('fury_2.png') + npt.assert_equal(os.path.isfile("fury_2.png"), True) + arr = io.load_image("fury_2.png") assert_less_equal(arr.shape[0], 5000) assert_less_equal(arr.shape[1], 5000) @@ -530,14 +528,13 @@ def test_opengl_state_simple(): window.gl_set_subtractive_blending, window.gl_set_additive_blending_white_background, ]: - scene = window.Scene() 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]]) actors = actor.markers( centers, - marker='s', + marker="s", colors=colors, marker_opacity=0.5, scales=0.2, @@ -555,7 +552,7 @@ def test_opengl_state_simple(): showm.exit() -@pytest.mark.skipif(True, reason='See TODO in the code') +@pytest.mark.skipif(True, reason="See TODO in the code") def test_opengl_state_add_remove_and_check(): scene = window.Scene() centers = np.array([[0, 0, 0], [-0.1, 0, 0], [0.1, 0, 0]]) @@ -563,7 +560,7 @@ def test_opengl_state_add_remove_and_check(): actor_no_depth_test = actor.markers( centers, - marker='s', + marker="s", colors=colors, marker_opacity=0.5, scales=0.2, @@ -576,7 +573,7 @@ def test_opengl_state_add_remove_and_check(): showm.render() state = window.gl_get_current_state(showm.window.GetState()) - before_depth_test = state['GL_DEPTH_TEST'] + before_depth_test = state["GL_DEPTH_TEST"] npt.assert_equal(before_depth_test, True) # TODO: we are getting bad request for enum status # it seems we are not provide the correct values @@ -594,13 +591,13 @@ def test_opengl_state_add_remove_and_check(): showm.render() state = window.gl_get_current_state(showm.window.GetState()) # print('type', type(showm.window.GetState())) - after_depth_test = state['GL_DEPTH_TEST'] + after_depth_test = state["GL_DEPTH_TEST"] npt.assert_equal(after_depth_test, False) # removes the no_depth_test effect remove_observer_from_actor(actor_no_depth_test, id_observer) showm.render() state = window.gl_get_current_state(showm.window.GetState()) - after_remove_depth_test_observer = state['GL_DEPTH_TEST'] + after_remove_depth_test_observer = state["GL_DEPTH_TEST"] npt.assert_equal(after_remove_depth_test_observer, True) diff --git a/fury/transform.py b/fury/transform.py index 66f5306aa..ac9c1aba8 100644 --- a/fury/transform.py +++ b/fury/transform.py @@ -8,36 +8,36 @@ # map axes strings to/from tuples of inner axis, parity, repetition, frame _AXES2TUPLE = { - 'sxyz': (0, 0, 0, 0), - 'sxyx': (0, 0, 1, 0), - 'sxzy': (0, 1, 0, 0), - 'sxzx': (0, 1, 1, 0), - 'syzx': (1, 0, 0, 0), - 'syzy': (1, 0, 1, 0), - 'syxz': (1, 1, 0, 0), - 'syxy': (1, 1, 1, 0), - 'szxy': (2, 0, 0, 0), - 'szxz': (2, 0, 1, 0), - 'szyx': (2, 1, 0, 0), - 'szyz': (2, 1, 1, 0), - 'rzyx': (0, 0, 0, 1), - 'rxyx': (0, 0, 1, 1), - 'ryzx': (0, 1, 0, 1), - 'rxzx': (0, 1, 1, 1), - 'rxzy': (1, 0, 0, 1), - 'ryzy': (1, 0, 1, 1), - 'rzxy': (1, 1, 0, 1), - 'ryxy': (1, 1, 1, 1), - 'ryxz': (2, 0, 0, 1), - 'rzxz': (2, 0, 1, 1), - 'rxyz': (2, 1, 0, 1), - 'rzyz': (2, 1, 1, 1), + "sxyz": (0, 0, 0, 0), + "sxyx": (0, 0, 1, 0), + "sxzy": (0, 1, 0, 0), + "sxzx": (0, 1, 1, 0), + "syzx": (1, 0, 0, 0), + "syzy": (1, 0, 1, 0), + "syxz": (1, 1, 0, 0), + "syxy": (1, 1, 1, 0), + "szxy": (2, 0, 0, 0), + "szxz": (2, 0, 1, 0), + "szyx": (2, 1, 0, 0), + "szyz": (2, 1, 1, 0), + "rzyx": (0, 0, 0, 1), + "rxyx": (0, 0, 1, 1), + "ryzx": (0, 1, 0, 1), + "rxzx": (0, 1, 1, 1), + "rxzy": (1, 0, 0, 1), + "ryzy": (1, 0, 1, 1), + "rzxy": (1, 1, 0, 1), + "ryxy": (1, 1, 1, 1), + "ryxz": (2, 0, 0, 1), + "rzxz": (2, 0, 1, 1), + "rxyz": (2, 1, 0, 1), + "rzyz": (2, 1, 1, 1), } -_TUPLE2AXES = dict((v, k) for k, v in _AXES2TUPLE.items()) +_TUPLE2AXES = {v: k for k, v in _AXES2TUPLE.items()} -def euler_matrix(ai, aj, ak, axes='sxyz'): +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 @@ -252,10 +252,7 @@ def translate(translation): 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) diff --git a/fury/ui/__init__.py b/fury/ui/__init__.py index 8e45eb504..f6fdc9bd3 100644 --- a/fury/ui/__init__.py +++ b/fury/ui/__init__.py @@ -1,3 +1,50 @@ -from fury.ui.containers import * -from fury.ui.core import * -from fury.ui.elements import * +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, +) + +__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", +] diff --git a/fury/ui/containers.py b/fury/ui/containers.py index 8223f4ee4..ca1606108 100644 --- a/fury/ui/containers.py +++ b/fury/ui/containers.py @@ -1,7 +1,5 @@ """UI container module.""" -__all__ = ['Panel2D', 'TabPanel2D', 'TabUI', 'ImageContainer2D', 'GridUI'] - from warnings import warn import numpy as np @@ -40,7 +38,7 @@ def __init__( position=(0, 0), color=(0.1, 0.1, 0.1), opacity=0.7, - align='left', + align="left", border_color=(1, 1, 1), border_width=0, has_border=False, @@ -90,17 +88,17 @@ def _setup(self): if self.has_border: self.borders = { - 'left': Rectangle2D(), - 'right': Rectangle2D(), - 'top': Rectangle2D(), - 'bottom': Rectangle2D(), + "left": Rectangle2D(), + "right": Rectangle2D(), + "top": Rectangle2D(), + "bottom": Rectangle2D(), } self.border_coords = { - 'left': (0.0, 0.0), - 'right': (1.0, 0.0), - 'top': (0.0, 1.0), - 'bottom': (0.0, 0.0), + "left": (0.0, 0.0), + "right": (1.0, 0.0), + "top": (0.0, 1.0), + "bottom": (0.0, 0.0), } for key in self.borders.keys(): @@ -156,19 +154,19 @@ def resize(self, size): self.background.resize(size) if self.has_border: - self.borders['left'].resize( + self.borders["left"].resize( (self._border_width, size[1] + self._border_width) ) - self.borders['right'].resize( + self.borders["right"].resize( (self._border_width, size[1] + self._border_width) ) - self.borders['top'].resize( + self.borders["top"].resize( (self.size[0] + self._border_width, self._border_width) ) - self.borders['bottom'].resize( + self.borders["bottom"].resize( (self.size[0] + self._border_width, self._border_width) ) @@ -207,7 +205,7 @@ def opacity(self): def opacity(self, opacity): self.background.opacity = opacity - def add_element(self, element, coords, anchor='position'): + 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 @@ -228,13 +226,13 @@ def add_element(self, element, coords, anchor='position'): if np.issubdtype(coords.dtype, np.floating): if np.any(coords < 0) or np.any(coords > 1): - raise ValueError('Normalized coordinates must be in [0,1].') + raise ValueError("Normalized coordinates must be in [0,1].") coords = coords * self.size - if anchor == 'center': + if anchor == "center": element.center = self.position + coords - elif anchor == 'position': + elif anchor == "position": element.position = self.position + coords else: msg = "Unknown anchor {}. Supported anchors are 'position'" " and 'center'." @@ -257,7 +255,7 @@ def remove_element(self, element): del self._elements[idx] del self.element_offsets[idx] - def update_element(self, element, coords, anchor='position'): + def update_element(self, element, coords, anchor="position"): """Update the position of a UI component in the panel. Parameters @@ -296,21 +294,21 @@ def re_align(self, window_size_change): New window size (width, height) in pixels. """ - if self.alignment == 'left': + if self.alignment == "left": pass - elif self.alignment == 'right': + elif self.alignment == "right": self.position += np.array(window_size_change) else: - msg = 'You can only left-align or right-align objects in a panel.' + msg = "You can only left-align or right-align objects in a panel." raise ValueError(msg) def update_border_coords(self): """Update the coordinates of the borders""" self.border_coords = { - 'left': (0.0, 0.0), - 'right': (1.0, 0.0), - 'top': (0.0, 1.0), - 'bottom': (0.0, 0.0), + "left": (0.0, 0.0), + "right": (1.0, 0.0), + "top": (0.0, 1.0), + "bottom": (0.0, 0.0), } for key in self.borders.keys(): @@ -318,7 +316,7 @@ def update_border_coords(self): @property def border_color(self): - sides = ['left', 'right', 'top', 'bottom'] + sides = ["left", "right", "top", "bottom"] return [self.borders[side].color for side in sides] @border_color.setter @@ -333,23 +331,23 @@ def border_color(self, side_color): """ side, color = side_color - if side.lower() not in ['left', 'right', 'top', 'bottom']: - raise ValueError(f'{side} not a valid border side') + if side.lower() not in ["left", "right", "top", "bottom"]: + raise ValueError(f"{side} not a valid border side") self.borders[side].color = color @property def border_width(self): - sides = ['left', 'right', 'top', 'bottom'] + sides = ["left", "right", "top", "bottom"] widths = [] for side in sides: - if side in ['left', 'right']: + if side in ["left", "right"]: widths.append(self.borders[side].width) - elif side in ['top', 'bottom']: + elif side in ["top", "bottom"]: widths.append(self.borders[side].height) else: - raise ValueError(f'{side} not a valid border side') + raise ValueError(f"{side} not a valid border side") return widths @border_width.setter @@ -364,12 +362,12 @@ def border_width(self, side_width): """ side, border_width = side_width - if side.lower() in ['left', 'right']: + if side.lower() in ["left", "right"]: self.borders[side].width = border_width - elif side.lower() in ['top', 'bottom']: + elif side.lower() in ["top", "bottom"]: self.borders[side].height = border_width else: - raise ValueError(f'{side} not a valid border side') + raise ValueError(f"{side} not a valid border side") class TabPanel2D(UI): @@ -388,7 +386,7 @@ def __init__( self, position=(0, 0), size=(100, 100), - title='New Tab', + title="New Tab", color=(0.5, 0.5, 0.5), content_panel=None, ): @@ -457,7 +455,7 @@ def _set_position(self, _coords): self.panel.position = _coords def _get_size(self): - self.panel.size + return self.panel.size def resize(self, size): """Resize Tab panel. @@ -574,7 +572,7 @@ def title_italic(self, italic): """ self.text_block.italic = italic - def add_element(self, element, coords, anchor='position'): + 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 @@ -605,7 +603,7 @@ def remove_element(self, element): """ self.content_panel.remove_element(element) - def update_element(self, element, coords, anchor='position'): + def update_element(self, element, coords, anchor="position"): """Update the position of a UI component in the content panel. Parameters @@ -620,7 +618,7 @@ def update_element(self, element, coords, anchor='position'): panel's size. """ - self.content_panel.update_element(element, coords, anchor='position') + self.content_panel.update_element(element, coords, anchor="position") class TabUI(UI): @@ -742,8 +740,8 @@ def _get_size(self): def update_tabs(self): """Update position, size and callbacks for tab panels.""" self.tab_panel_size = (self.size[0] // self.nb_tabs, int(0.1 * self.size[1])) - if self.tab_bar_pos.lower() not in ['top', 'bottom']: - warn("tab_bar_pos can only have value top/bottom") + if self.tab_bar_pos.lower() not in ["top", "bottom"]: + warn("tab_bar_pos can only have value top/bottom", stacklevel=2) self.tab_bar_pos = "top" if self.tab_bar_pos.lower() == "top": @@ -757,24 +755,32 @@ def update_tabs(self): content_panel = tab_panel.content_panel if self.draggable: - tab_panel.panel.background.on_left_mouse_button_pressed = \ + tab_panel.panel.background.on_left_mouse_button_pressed = ( self.left_button_pressed - content_panel.background.on_left_mouse_button_pressed = \ + ) + content_panel.background.on_left_mouse_button_pressed = ( self.left_button_pressed - tab_panel.text_block.on_left_mouse_button_pressed = \ + ) + tab_panel.text_block.on_left_mouse_button_pressed = ( self.left_button_pressed + ) - tab_panel.panel.background.on_left_mouse_button_dragged = \ + tab_panel.panel.background.on_left_mouse_button_dragged = ( self.left_button_dragged - content_panel.background.on_left_mouse_button_dragged = \ + ) + content_panel.background.on_left_mouse_button_dragged = ( self.left_button_dragged - tab_panel.text_block.on_left_mouse_button_dragged = \ + ) + tab_panel.text_block.on_left_mouse_button_dragged = ( self.left_button_dragged + ) else: - tab_panel.panel.background.on_left_mouse_button_dragged = \ + tab_panel.panel.background.on_left_mouse_button_dragged = ( lambda i_ren, _obj, _comp: i_ren.force_render - content_panel.background.on_left_mouse_button_dragged = \ + ) + content_panel.background.on_left_mouse_button_dragged = ( lambda i_ren, _obj, _comp: i_ren.force_render + ) tab_panel.text_block.on_left_mouse_button_clicked = self.select_tab_callback tab_panel.panel.background.on_left_mouse_button_clicked = ( @@ -789,11 +795,9 @@ def update_tabs(self): tab_panel.content_panel.resize(self.content_size) self.parent_panel.add_element(tab_panel, tab_panel_pos) if self.tab_bar_pos.lower() == "top": - self.parent_panel.add_element(tab_panel.content_panel, - (0.0, 0.0)) + self.parent_panel.add_element(tab_panel.content_panel, (0.0, 0.0)) elif self.tab_bar_pos.lower() == "bottom": - self.parent_panel.add_element(tab_panel.content_panel, - (0.0, 0.1)) + self.parent_panel.add_element(tab_panel.content_panel, (0.0, 0.1)) tab_panel_pos[0] += 1 / self.nb_tabs def select_tab_callback(self, iren, _obj, _tab_comp): @@ -831,28 +835,28 @@ 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'): + 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) if tab_idx == self.active_tab_idx: element.set_visibility(True) else: - raise IndexError('Tab with index ' '{} does not exist'.format(tab_idx)) + raise IndexError("Tab with index " "{} does not exist".format(tab_idx)) def remove_element(self, tab_idx, element): """Remove element from content panel after checking its existence.""" if tab_idx < self.nb_tabs and tab_idx >= 0: self.tabs[tab_idx].remove_element(element) else: - raise IndexError('Tab with index ' '{} does not exist'.format(tab_idx)) + raise IndexError("Tab with index " "{} does not exist".format(tab_idx)) - def update_element(self, tab_idx, element, coords, anchor='position'): + 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) else: - raise IndexError('Tab with index ' '{} does not exist'.format(tab_idx)) + raise IndexError("Tab with index " "{} does not exist".format(tab_idx)) def left_button_pressed(self, i_ren, _obj, _sub_component): click_pos = np.array(i_ren.event.position) @@ -1030,13 +1034,12 @@ def __init__( captions=None, caption_offset=(0, -100, 0), cell_padding=0, - cell_shape='rect', + cell_shape="rect", aspect_ratio=16 / 9.0, dim=None, rotation_speed=1, rotation_axis=(0, 1, 0), ): - # TODO: add rotation axis None by default self.container = grid( @@ -1056,7 +1059,7 @@ def __init__( for item in self.container._items: actor = item if captions is None else item._items[0] self._actors.append(actor) - self._actors_dict[actor] = {'x': -np.inf, 'y': -np.inf} + self._actors_dict[actor] = {"x": -np.inf, "y": -np.inf} super(GridUI, self).__init__(position=(0, 0, 0)) @@ -1071,7 +1074,6 @@ def left_click_callback(istyle, _obj, _what): @staticmethod def left_release_callback(istyle, _obj, _what): - istyle.trackball_actor.OnLeftButtonUp() istyle.force_render() istyle.event.abort() @@ -1084,7 +1086,6 @@ def mouse_move_callback(istyle, _obj, _what): @staticmethod def left_click_callback2(istyle, obj, self): - rx, ry, rz = self.rotation_axis clockwise_rotation = np.array([self.rotation_speed, rx, ry, rz]) rotate(obj, clockwise_rotation) @@ -1094,33 +1095,29 @@ def left_click_callback2(istyle, obj, self): @staticmethod def left_release_callback2(istyle, _obj, _what): - istyle.force_render() istyle.event.abort() @staticmethod def mouse_move_callback2(istyle, obj, self): - - if self._actors_dict[obj]['y'] == -np.inf: - + if self._actors_dict[obj]["y"] == -np.inf: iren = istyle.GetInteractor() event_pos = iren.GetEventPosition() - self._actors_dict[obj]['y'] = event_pos[1] + self._actors_dict[obj]["y"] = event_pos[1] else: - iren = istyle.GetInteractor() event_pos = iren.GetEventPosition() rx, ry, rz = self.rotation_axis - if event_pos[1] >= self._actors_dict[obj]['y']: + if event_pos[1] >= self._actors_dict[obj]["y"]: clockwise_rotation = np.array([-self.rotation_speed, rx, ry, rz]) rotate(obj, clockwise_rotation) else: anti_clockwise_rotation = np.array([self.rotation_speed, rx, ry, rz]) rotate(obj, anti_clockwise_rotation) - self._actors_dict[obj]['y'] = event_pos[1] + self._actors_dict[obj]["y"] = event_pos[1] istyle.force_render() istyle.event.abort() @@ -1132,19 +1129,19 @@ def mouse_move_callback2(istyle, obj, self): def key_press_callback(self, istyle, obj, _what): has_changed = False - if istyle.event.key == 'Left': + if istyle.event.key == "Left": has_changed = True for a in self._actors: rotate(a, self.ANTICLOCKWISE_ROTATION_Y) - elif istyle.event.key == 'Right': + elif istyle.event.key == "Right": has_changed = True for a in self._actors: rotate(a, self.CLOCKWISE_ROTATION_Y) - elif istyle.event.key == 'Up': + elif istyle.event.key == "Up": has_changed = True for a in self._actors: rotate(a, self.ANTICLOCKWISE_ROTATION_X) - elif istyle.event.key == 'Down': + elif istyle.event.key == "Down": has_changed = True for a in self._actors: rotate(a, self.CLOCKWISE_ROTATION_X) @@ -1160,24 +1157,24 @@ def _setup(self): if self.rotation_axis is None: self.add_callback( - actor, 'LeftButtonPressEvent', self.left_click_callback + actor, "LeftButtonPressEvent", self.left_click_callback ) self.add_callback( - actor, 'LeftButtonReleaseEvent', self.left_release_callback + actor, "LeftButtonReleaseEvent", self.left_release_callback ) - self.add_callback(actor, 'MouseMoveEvent', self.mouse_move_callback) + self.add_callback(actor, "MouseMoveEvent", self.mouse_move_callback) else: self.add_callback( - actor, 'LeftButtonPressEvent', self.left_click_callback2 + actor, "LeftButtonPressEvent", self.left_click_callback2 ) # TODO: possibly add this too self.add_callback( - actor, 'LeftButtonReleaseEvent', self.left_release_callback2 + actor, "LeftButtonReleaseEvent", self.left_release_callback2 ) - self.add_callback(actor, 'MouseMoveEvent', self.mouse_move_callback2) + self.add_callback(actor, "MouseMoveEvent", self.mouse_move_callback2) # TODO: this is currently not running - self.add_callback(actor, 'KeyPressEvent', self.key_press_callback) + self.add_callback(actor, "KeyPressEvent", self.key_press_callback) # self.on_key_press = self.key_press_callback2 def _get_actors(self): diff --git a/fury/ui/core.py b/fury/ui/core.py index c6dbe99e0..5507a613a 100644 --- a/fury/ui/core.py +++ b/fury/ui/core.py @@ -1,7 +1,5 @@ """UI core module that describe UI abstract class.""" -__all__ = ['Rectangle2D', 'Disk2D', 'TextBlock2D', 'Button2D'] - import abc import numpy as np @@ -98,9 +96,9 @@ def __init__(self, position=(0, 0)): self._setup() # Setup needed actors and sub UI components. self.position = position - self.left_button_state = 'released' - self.right_button_state = 'released' - self.middle_button_state = 'released' + self.left_button_state = "released" + self.right_button_state = "released" + self.middle_button_state = "released" self.on_left_mouse_button_pressed = lambda i_ren, obj, element: None self.on_left_mouse_button_dragged = lambda i_ren, obj, element: None @@ -127,13 +125,13 @@ def _setup(self): components. """ - msg = 'Subclasses of UI must implement `_setup(self)`.' + msg = "Subclasses of UI must implement `_setup(self)`." raise NotImplementedError(msg) @abc.abstractmethod def _get_actors(self): """Get the actors composing this UI component.""" - msg = 'Subclasses of UI must implement `_get_actors(self)`.' + msg = "Subclasses of UI must implement `_get_actors(self)`." raise NotImplementedError(msg) @property @@ -150,7 +148,7 @@ def _add_to_scene(self, _scene): _scene : Scene """ - msg = 'Subclasses of UI must implement `_add_to_scene(self, scene)`.' + msg = "Subclasses of UI must implement `_add_to_scene(self, scene)`." raise NotImplementedError(msg) def add_to_scene(self, scene): @@ -169,13 +167,12 @@ def add_to_scene(self, scene): for callback in self._callbacks: if not isinstance(iren, CustomInteractorStyle): msg = ( - 'The ShowManager requires `CustomInteractorStyle` in' - ' order to use callbacks.' + "The ShowManager requires `CustomInteractorStyle` in" + " order to use callbacks." ) raise TypeError(msg) if callback[0] == self._scene: - iren.add_callback(iren, callback[1], callback[2], args=[self]) else: iren.add_callback(*callback, args=[self]) @@ -219,7 +216,7 @@ def _set_position(self, _coords): Absolute pixel coordinates (x, y). """ - msg = 'Subclasses of UI must implement `_set_position(self, coords)`.' + msg = "Subclasses of UI must implement `_set_position(self, coords)`." raise NotImplementedError(msg) @property @@ -228,7 +225,7 @@ def size(self): @abc.abstractmethod def _get_size(self): - msg = 'Subclasses of UI must implement property `size`.' + msg = "Subclasses of UI must implement property `size`." raise NotImplementedError(msg) @property @@ -245,8 +242,8 @@ def center(self, coords): Absolute pixel coordinates (x, y). """ - if not hasattr(self, 'size'): - msg = 'Subclasses of UI must implement the `size` property.' + if not hasattr(self, "size"): + msg = "Subclasses of UI must implement the `size` property." raise NotImplementedError(msg) new_center = np.array(coords) @@ -261,89 +258,89 @@ def set_visibility(self, visibility): def handle_events(self, actor): self.add_callback( - actor, 'LeftButtonPressEvent', self.left_button_click_callback + actor, "LeftButtonPressEvent", self.left_button_click_callback ) self.add_callback( - actor, 'LeftButtonReleaseEvent', self.left_button_release_callback + actor, "LeftButtonReleaseEvent", self.left_button_release_callback ) self.add_callback( - actor, 'RightButtonPressEvent', self.right_button_click_callback + actor, "RightButtonPressEvent", self.right_button_click_callback ) self.add_callback( - actor, 'RightButtonReleaseEvent', self.right_button_release_callback + actor, "RightButtonReleaseEvent", self.right_button_release_callback ) self.add_callback( - actor, 'MiddleButtonPressEvent', self.middle_button_click_callback + actor, "MiddleButtonPressEvent", self.middle_button_click_callback ) self.add_callback( - actor, 'MiddleButtonReleaseEvent', self.middle_button_release_callback + actor, "MiddleButtonReleaseEvent", self.middle_button_release_callback ) - self.add_callback(actor, 'MouseMoveEvent', self.mouse_move_callback) - self.add_callback(actor, 'KeyPressEvent', self.key_press_callback) + self.add_callback(actor, "MouseMoveEvent", self.mouse_move_callback) + self.add_callback(actor, "KeyPressEvent", self.key_press_callback) @staticmethod def left_button_click_callback(i_ren, obj, self): - self.left_button_state = 'pressing' + self.left_button_state = "pressing" self.on_left_mouse_button_pressed(i_ren, obj, self) i_ren.event.abort() @staticmethod def left_button_release_callback(i_ren, obj, self): - if self.left_button_state == 'pressing': + if self.left_button_state == "pressing": self.on_left_mouse_button_clicked(i_ren, obj, self) - self.left_button_state = 'released' + self.left_button_state = "released" self.on_left_mouse_button_released(i_ren, obj, self) @staticmethod def right_button_click_callback(i_ren, obj, self): - self.right_button_state = 'pressing' + self.right_button_state = "pressing" self.on_right_mouse_button_pressed(i_ren, obj, self) i_ren.event.abort() @staticmethod def right_button_release_callback(i_ren, obj, self): - if self.right_button_state == 'pressing': + if self.right_button_state == "pressing": self.on_right_mouse_button_clicked(i_ren, obj, self) - self.right_button_state = 'released' + self.right_button_state = "released" self.on_right_mouse_button_released(i_ren, obj, self) @staticmethod def middle_button_click_callback(i_ren, obj, self): - self.middle_button_state = 'pressing' + self.middle_button_state = "pressing" self.on_middle_mouse_button_pressed(i_ren, obj, self) i_ren.event.abort() @staticmethod def middle_button_release_callback(i_ren, obj, self): - if self.middle_button_state == 'pressing': + if self.middle_button_state == "pressing": self.on_middle_mouse_button_clicked(i_ren, obj, self) - self.middle_button_state = 'released' + self.middle_button_state = "released" self.on_middle_mouse_button_released(i_ren, obj, self) @staticmethod def mouse_move_callback(i_ren, obj, self): left_pressing_or_dragging = ( - self.left_button_state == 'pressing' or self.left_button_state == 'dragging' + self.left_button_state == "pressing" or self.left_button_state == "dragging" ) right_pressing_or_dragging = ( - self.right_button_state == 'pressing' - or self.right_button_state == 'dragging' + self.right_button_state == "pressing" + or self.right_button_state == "dragging" ) middle_pressing_or_dragging = ( - self.middle_button_state == 'pressing' - or self.middle_button_state == 'dragging' + self.middle_button_state == "pressing" + or self.middle_button_state == "dragging" ) if left_pressing_or_dragging: - self.left_button_state = 'dragging' + self.left_button_state = "dragging" self.on_left_mouse_button_dragged(i_ren, obj, self) elif right_pressing_or_dragging: - self.right_button_state = 'dragging' + self.right_button_state = "dragging" self.on_right_mouse_button_dragged(i_ren, obj, self) elif middle_pressing_or_dragging: - self.middle_button_state = 'dragging' + self.middle_button_state = "dragging" self.on_middle_mouse_button_dragged(i_ren, obj, self) @staticmethod @@ -696,11 +693,11 @@ class TextBlock2D(UI): def __init__( self, - text='Text Block', + text="Text Block", font_size=18, - font_family='Arial', - justification='left', - vertical_justification='bottom', + font_family="Arial", + justification="left", + vertical_justification="bottom", bold=False, italic=False, shadow=False, @@ -709,7 +706,7 @@ def __init__( bg_color=None, position=(0, 0), auto_font_scale=False, - dynamic_bbox=False + dynamic_bbox=False, ): """Init class instance. @@ -866,7 +863,7 @@ def font_family(self): return self.actor.GetTextProperty().GetFontFamilyAsString() @font_family.setter - def font_family(self, family='Arial'): + def font_family(self, family="Arial"): """Set font family. Currently Arial and Courier are supported. @@ -877,12 +874,12 @@ def font_family(self, family='Arial'): The font family. """ - if family == 'Arial': + if family == "Arial": self.actor.GetTextProperty().SetFontFamilyToArial() - elif family == 'Courier': + elif family == "Courier": self.actor.GetTextProperty().SetFontFamilyToCourier() else: - raise ValueError('Font not supported yet: {}.'.format(family)) + raise ValueError("Font not supported yet: {}.".format(family)) @property def justification(self): @@ -1124,37 +1121,38 @@ def dynamic_bbox(self, flag): self.update_bounding_box() def update_alignment(self): - """Update Text Alignment. - """ + """Update Text Alignment.""" text_property = self.actor.GetTextProperty() updated_text_position = [0, 0] - if self.justification.lower() == 'left': + if self.justification.lower() == "left": text_property.SetJustificationToLeft() updated_text_position[0] = self.boundingbox[0] - elif self.justification.lower() == 'center': + elif self.justification.lower() == "center": text_property.SetJustificationToCentered() - updated_text_position[0] = self.boundingbox[0] + \ - (self.boundingbox[2]-self.boundingbox[0])//2 - elif self.justification.lower() == 'right': + updated_text_position[0] = ( + self.boundingbox[0] + (self.boundingbox[2] - self.boundingbox[0]) // 2 + ) + elif self.justification.lower() == "right": text_property.SetJustificationToRight() updated_text_position[0] = self.boundingbox[2] else: - msg = 'Text can only be justified left, right and center.' + msg = "Text can only be justified left, right and center." raise ValueError(msg) - if self.vertical_justification.lower() == 'bottom': + if self.vertical_justification.lower() == "bottom": text_property.SetVerticalJustificationToBottom() updated_text_position[1] = self.boundingbox[1] - elif self.vertical_justification.lower() == 'middle': + elif self.vertical_justification.lower() == "middle": text_property.SetVerticalJustificationToCentered() - updated_text_position[1] = self.boundingbox[1] + \ - (self.boundingbox[3]-self.boundingbox[1])//2 - elif self.vertical_justification.lower() == 'top': + updated_text_position[1] = ( + self.boundingbox[1] + (self.boundingbox[3] - self.boundingbox[1]) // 2 + ) + elif self.vertical_justification.lower() == "top": text_property.SetVerticalJustificationToTop() updated_text_position[1] = self.boundingbox[3] else: - msg = 'Vertical justification must be: bottom, middle or top.' + msg = "Vertical justification must be: bottom, middle or top." raise ValueError(msg) self.actor.SetPosition(updated_text_position) @@ -1163,7 +1161,7 @@ def cal_size_from_message(self): """Calculate size of background according to the message it contains.""" lines = self.message.split("\n") max_length = max(len(line) for line in lines) - return [max_length*self.font_size, len(lines)*self.font_size] + return [max_length * self.font_size, len(lines) * self.font_size] def update_bounding_box(self, size=None): """Update Text Bounding Box. @@ -1178,14 +1176,19 @@ def update_bounding_box(self, size=None): if size is None: size = self.cal_size_from_message() - self.boundingbox = [self.position[0], self.position[1], - self.position[0]+size[0], self.position[1]+size[1]] + self.boundingbox = [ + self.position[0], + self.position[1], + self.position[0] + size[0], + self.position[1] + size[1], + ] self.background.resize(size) if self.auto_font_scale: self.actor.SetPosition2( - self.boundingbox[2]-self.boundingbox[0], - self.boundingbox[3]-self.boundingbox[1]) + self.boundingbox[2] - self.boundingbox[0], + self.boundingbox[3] - self.boundingbox[1], + ) else: self.update_alignment() @@ -1202,8 +1205,10 @@ def _set_position(self, position): self.background.position = position def _get_size(self): - bb_size = (self.boundingbox[2]-self.boundingbox[0], - self.boundingbox[3]-self.boundingbox[1]) + bb_size = ( + self.boundingbox[2] - self.boundingbox[0], + self.boundingbox[3] - self.boundingbox[1], + ) if self.dynamic_bbox or self.auto_font_scale or sum(bb_size): return bb_size return self.cal_size_from_message() @@ -1234,7 +1239,7 @@ def __init__(self, icon_fnames, position=(0, 0), size=(30, 30)): """ super(Button2D, self).__init__(position) - self.icon_extents = dict() + self.icon_extents = {} self.icons = self._build_icons(icon_fnames) self.icon_names = [icon[0] for icon in self.icons] self.current_icon_id = 0 diff --git a/fury/ui/elements.py b/fury/ui/elements.py index db67817f9..7bd17d997 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -1,23 +1,23 @@ """UI components module.""" __all__ = [ - 'TextBox2D', - 'LineSlider2D', - 'LineDoubleSlider2D', - 'RingSlider2D', - 'RangeSlider', - 'Checkbox', - 'Option', - 'RadioButton', - 'ComboBox2D', - 'ListBox2D', - 'ListBoxItem2D', - 'FileMenu2D', - 'DrawShape', - 'DrawPanel', - 'PlaybackPanel', - 'Card2D', - 'SpinBox' + "TextBox2D", + "LineSlider2D", + "LineDoubleSlider2D", + "RingSlider2D", + "RangeSlider", + "Checkbox", + "Option", + "RadioButton", + "ComboBox2D", + "ListBox2D", + "ListBoxItem2D", + "FileMenu2D", + "DrawShape", + "DrawPanel", + "PlaybackPanel", + "Card2D", + "SpinBox", ] from collections import OrderedDict @@ -77,12 +77,12 @@ def __init__( self, width, height, - text='Enter Text', + text="Enter Text", position=(100, 10), color=(0, 0, 0), font_size=18, - font_family='Arial', - justification='left', + font_family="Arial", + justification="left", bold=False, italic=False, shadow=False, @@ -208,12 +208,12 @@ def width_set_text(self, text): A multi line formatted text. """ - multi_line_text = '' + multi_line_text = "" for i, t in enumerate(text): multi_line_text += t if (i + 1) % self.width == 0: - multi_line_text += '\n' - return multi_line_text.rstrip('\n') + multi_line_text += "\n" + return multi_line_text.rstrip("\n") def handle_character(self, key, key_char): """Handle button events. @@ -225,17 +225,17 @@ def handle_character(self, key, key_char): character : str """ - if key.lower() == 'return': + if key.lower() == "return": self.render_text(False) self.off_focus(self) return True - elif key_char != '' and key_char in printable: + elif key_char != "" and key_char in printable: self.add_character(key_char) - if key.lower() == 'backspace': + if key.lower() == "backspace": self.remove_character() - elif key.lower() == 'left': + elif key.lower() == "left": self.move_left() - elif key.lower() == 'right': + elif key.lower() == "right": self.move_right() self.render_text() @@ -277,10 +277,10 @@ def add_character(self, character): character : str """ - if len(character) > 1 and character.lower() != 'space': + if len(character) > 1 and character.lower() != "space": return - if character.lower() == 'space': - character = ' ' + if character.lower() == "space": + character = " " self.message = ( self.message[: self.caret_pos] + character + self.message[self.caret_pos :] ) @@ -331,7 +331,7 @@ def showable_text(self, show_caret): """ if show_caret: ret_text = ( - self.message[: self.caret_pos] + '_' + self.message[self.caret_pos :] + self.message[: self.caret_pos] + "_" + self.message[self.caret_pos :] ) else: ret_text = self.message @@ -348,14 +348,14 @@ def render_text(self, show_caret=True): """ text = self.showable_text(show_caret) - if text == '': - text = 'Enter Text' + if text == "": + text = "Enter Text" self.text.message = self.width_set_text(text) def edit_mode(self): """Turn on edit mode.""" if self.init: - self.message = '' + self.message = "" self.init = False self.caret_pos = 0 self.render_text() @@ -434,10 +434,10 @@ def __init__( outer_radius=10, handle_side=20, font_size=16, - orientation='horizontal', - text_alignment='', - text_template='{value:.1f} ({ratio:.0%})', - shape='disk', + orientation="horizontal", + text_alignment="", + text_template="{value:.1f} ({ratio:.0%})", + shape="disk", ): """Init this UI element. @@ -481,24 +481,24 @@ def __init__( self.shape = shape self.orientation = orientation.lower().strip() self.align_dict = { - 'horizontal': ['top', 'bottom'], - 'vertical': ['left', 'right'], + "horizontal": ["top", "bottom"], + "vertical": ["left", "right"], } self.default_color = (1, 1, 1) self.active_color = (0, 0, 1) self.alignment = text_alignment.lower() super(LineSlider2D, self).__init__() - if self.orientation == 'horizontal': - self.alignment = 'bottom' if not self.alignment else self.alignment + if self.orientation == "horizontal": + self.alignment = "bottom" if not self.alignment else self.alignment self.track.width = length self.track.height = line_width - elif self.orientation == 'vertical': - self.alignment = 'left' if not self.alignment else self.alignment + elif self.orientation == "vertical": + self.alignment = "left" if not self.alignment else self.alignment self.track.width = line_width self.track.height = length else: - raise ValueError('Unknown orientation') + raise ValueError("Unknown orientation") if self.alignment not in self.align_dict[self.orientation]: raise ValueError( @@ -507,10 +507,10 @@ def __init__( ) ) - if shape == 'disk': + if shape == "disk": self.handle.inner_radius = inner_radius self.handle.outer_radius = outer_radius - elif shape == 'square': + elif shape == "square": self.handle.width = handle_side self.handle.height = handle_side self.center = center @@ -539,14 +539,14 @@ def _setup(self): self.track.color = (1, 0, 0) # Slider's handle - if self.shape == 'disk': + if self.shape == "disk": self.handle = Disk2D(outer_radius=1) - elif self.shape == 'square': + elif self.shape == "square": self.handle = Rectangle2D(size=(1, 1)) self.handle.color = self.default_color # Slider Text - self.text = TextBlock2D(justification='center', vertical_justification='top') + self.text = TextBlock2D(justification="center", vertical_justification="top") # Add default events listener for this UI component. self.track.on_left_mouse_button_pressed = self.track_click_callback @@ -575,7 +575,7 @@ def _get_size(self): # Consider the handle's size when computing the slider's size. width = None height = None - if self.orientation == 'horizontal': + if self.orientation == "horizontal": width = self.track.width + self.handle.size[0] height = max(self.track.height, self.handle.size[1]) else: @@ -595,7 +595,7 @@ def _set_position(self, coords): """ # Offset the slider line by the handle's radius. track_position = coords + self.handle.size / 2.0 - if self.orientation == 'horizontal': + if self.orientation == "horizontal": # Offset the slider line height by half the slider line width. track_position[1] -= self.track.size[1] / 2.0 else: @@ -606,14 +606,14 @@ def _set_position(self, coords): self.handle.position = self.handle.position.astype(float) self.handle.position += coords - self.position # Position the text below the handle. - if self.orientation == 'horizontal': - align = 35 if self.alignment == 'top' else -10 + if self.orientation == "horizontal": + align = 35 if self.alignment == "top" else -10 self.text.position = ( self.handle.center[0], self.handle.position[1] + align, ) else: - align = 70 if self.alignment == 'right' else -35 + align = 70 if self.alignment == "right" else -35 self.text.position = ( self.handle.position[0] + align, self.handle.center[1] + 2, @@ -645,7 +645,7 @@ def set_position(self, position): """ # Move slider disk. - if self.orientation == 'horizontal': + if self.orientation == "horizontal": x_position = position[0] x_position = max(x_position, self.left_x_position) x_position = min(x_position, self.right_x_position) @@ -689,17 +689,17 @@ def update(self): disk_position_x = None disk_position_y = None - if self.orientation == 'horizontal': + if self.orientation == "horizontal": length = float(self.right_x_position - self.left_x_position) length = np.round(length, decimals=6) if length != self.track.width: - raise ValueError('Disk position outside the slider line') + raise ValueError("Disk position outside the slider line") disk_position_x = self.handle.center[0] self._ratio = (disk_position_x - self.left_x_position) / length else: length = float(self.top_y_position - self.bottom_y_position) if length != self.track.height: - raise ValueError('Disk position outside the slider line') + raise ValueError("Disk position outside the slider line") disk_position_y = self.handle.center[1] self._ratio = (disk_position_y - self.bottom_y_position) / length @@ -712,7 +712,7 @@ def update(self): self.text.message = text # Move the text below the slider's handle. - if self.orientation == 'horizontal': + if self.orientation == "horizontal": self.text.position = (disk_position_x, self.text.position[1]) else: self.text.position = (self.text.position[0], disk_position_y) @@ -811,9 +811,9 @@ def __init__( min_value=0, max_value=100, font_size=16, - text_template='{value:.1f}', - orientation='horizontal', - shape='disk', + text_template="{value:.1f}", + orientation="horizontal", + shape="disk", ): """Init this UI element. @@ -857,22 +857,22 @@ def __init__( self.orientation = orientation.lower() super(LineDoubleSlider2D, self).__init__() - if self.orientation == 'horizontal': + if self.orientation == "horizontal": self.track.width = length self.track.height = line_width - elif self.orientation == 'vertical': + elif self.orientation == "vertical": self.track.width = line_width self.track.height = length else: - raise ValueError('Unknown orientation') + raise ValueError("Unknown orientation") self.center = center - if shape == 'disk': + if shape == "disk": self.handles[0].inner_radius = inner_radius self.handles[0].outer_radius = outer_radius self.handles[1].inner_radius = inner_radius self.handles[1].outer_radius = outer_radius - elif shape == 'square': + elif shape == "square": self.handles[0].width = handle_side self.handles[0].height = handle_side self.handles[1].width = handle_side @@ -910,10 +910,10 @@ def _setup(self): # Handles self.handles = [] - if self.shape == 'disk': + if self.shape == "disk": self.handles.append(Disk2D(outer_radius=1)) self.handles.append(Disk2D(outer_radius=1)) - elif self.shape == 'square': + elif self.shape == "square": self.handles.append(Rectangle2D(size=(1, 1))) self.handles.append(Rectangle2D(size=(1, 1))) self.handles[0].color = self.default_color @@ -921,8 +921,8 @@ def _setup(self): # Slider Text self.text = [ - TextBlock2D(justification='center', vertical_justification='top'), - TextBlock2D(justification='center', vertical_justification='top'), + TextBlock2D(justification="center", vertical_justification="top"), + TextBlock2D(justification="center", vertical_justification="top"), ] # Add default events listener for this UI component. @@ -960,7 +960,7 @@ def _get_size(self): # Consider the handle's size when computing the slider's size. width = None height = None - if self.orientation == 'horizontal': + if self.orientation == "horizontal": width = self.track.width + self.handles[0].size[0] height = max(self.track.height, self.handles[0].size[1]) else: @@ -980,7 +980,7 @@ def _set_position(self, coords): """ # Offset the slider line by the handle's radius. track_position = coords - if self.orientation == 'horizontal': + if self.orientation == "horizontal": # Offset the slider line height by half the slider line width. track_position[1] -= self.track.size[1] / 2.0 else: @@ -995,7 +995,7 @@ def _set_position(self, coords): self.handles[0].position += coords - self.position self.handles[1].position += coords - self.position - if self.orientation == 'horizontal': + if self.orientation == "horizontal": # Position the text below the handles. self.text[0].position = ( self.handles[0].center[0], @@ -1051,7 +1051,7 @@ def ratio_to_coord(self, ratio): ratio : float """ - if self.orientation == 'horizontal': + if self.orientation == "horizontal": return self.left_x_position + ratio * self.track.width return self.bottom_y_position + ratio * self.track.height @@ -1063,7 +1063,7 @@ def coord_to_ratio(self, coord): coord : float """ - if self.orientation == 'horizontal': + if self.orientation == "horizontal": return (coord - self.left_x_position) / float(self.track.width) return (coord - self.bottom_y_position) / float(self.track.height) @@ -1089,7 +1089,7 @@ def set_position(self, position, disk_number): The index of disk being moved. """ - if self.orientation == 'horizontal': + if self.orientation == "horizontal": x_position = position[0] if disk_number == 0 and x_position >= self.handles[1].center[0]: @@ -1295,7 +1295,7 @@ def update(self, disk_number): """ # Compute the ratio determined by the position of the slider disk. - if self.orientation == 'horizontal': + if self.orientation == "horizontal": self._ratio[disk_number] = self.coord_to_ratio( self.handles[disk_number].center[0] ) @@ -1311,7 +1311,7 @@ def update(self, disk_number): text = self.format_text(disk_number) self.text[disk_number].message = text - if self.orientation == 'horizontal': + if self.orientation == "horizontal": self.text[disk_number].position = ( self.handles[disk_number].center[0], self.text[disk_number].position[1], @@ -1399,7 +1399,7 @@ def __init__( handle_inner_radius=0, handle_outer_radius=10, font_size=16, - text_template='{ratio:.0%}', + text_template="{ratio:.0%}", ): """Init this UI element. @@ -1472,8 +1472,7 @@ def _setup(self): self.handle.color = self.default_color # Slider Text - self.text = TextBlock2D(justification='center', - vertical_justification='middle') + self.text = TextBlock2D(justification="center", vertical_justification="middle") # Add default events listener for this UI component. self.track.on_left_mouse_button_pressed = self.track_click_callback @@ -1678,9 +1677,9 @@ def __init__( max_value=100, font_size=16, range_precision=1, - orientation='horizontal', + orientation="horizontal", value_precision=2, - shape='disk', + shape="disk", ): """Init this class instance. @@ -1728,8 +1727,8 @@ def __init__( self.shape = shape self.orientation = orientation.lower() - self.range_slider_text_template = '{value:.' + str(range_precision) + 'f}' - self.value_slider_text_template = '{value:.' + str(value_precision) + 'f}' + self.range_slider_text_template = "{value:." + str(range_precision) + "f}" + self.value_slider_text_template = "{value:." + str(value_precision) + "f}" self.range_slider_center = range_slider_center self.value_slider_center = value_slider_center @@ -1868,15 +1867,15 @@ def _setup(self): """Setup this UI component.""" # Option's button self.button_icons = [] - self.button_icons.append(('unchecked', read_viz_icons(fname='stop2.png'))) - self.button_icons.append(('checked', read_viz_icons(fname='checkmark.png'))) + self.button_icons.append(("unchecked", read_viz_icons(fname="stop2.png"))) + self.button_icons.append(("checked", read_viz_icons(fname="checkmark.png"))) self.button = Button2D(icon_fnames=self.button_icons, size=self.button_size) self.text = TextBlock2D(text=self.label, font_size=self.font_size) # Display initial state if self.checked: - self.button.set_icon_by_name('checked') + self.button.set_icon_by_name("checked") # Add callbacks self.button.on_left_mouse_button_clicked = self.toggle @@ -1911,7 +1910,7 @@ def _set_position(self, coords): Absolute pixel coordinates (x, y). """ - num_newlines = self.label.count('\n') + num_newlines = self.label.count("\n") self.button.position = coords + (0, num_newlines * self.font_size * 0.5) offset = (self.button.size[0] + self.button_label_gap, 0) self.text.position = coords + offset @@ -1927,11 +1926,11 @@ def toggle(self, i_ren, _obj, _element): def select(self): self.checked = True - self.button.set_icon_by_name('checked') + self.button.set_icon_by_name("checked") def deselect(self): self.checked = False - self.button.set_icon_by_name('unchecked') + self.button.set_icon_by_name("unchecked") class Checkbox(UI): @@ -1955,7 +1954,7 @@ def __init__( checked_labels=(), padding=1, font_size=18, - font_family='Arial', + font_family="Arial", position=(0, 0), ): """Init this class instance. @@ -1990,7 +1989,6 @@ def _setup(self): self.options = OrderedDict() button_y = self.position[1] for label in self.labels: - option = Option( label=label, font_size=self.font_size, @@ -2001,7 +1999,7 @@ def _setup(self): line_spacing = option.text.actor.GetTextProperty().GetLineSpacing() button_y = ( button_y - + self.font_size * (label.count('\n') + 1) * (line_spacing + 0.1) + + self.font_size * (label.count("\n") + 1) * (line_spacing + 0.1) + self.padding ) self.options[label] = option @@ -2063,7 +2061,7 @@ def _set_position(self, coords): button_y = ( button_y + self.font_size - * (self.labels[option_no].count('\n') + 1) + * (self.labels[option_no].count("\n") + 1) * (line_spacing + 0.1) + self.padding ) @@ -2100,7 +2098,7 @@ def __init__( checked_labels, padding=1, font_size=18, - font_family='Arial', + font_family="Arial", position=(0, 0), ): """Init class instance. @@ -2123,7 +2121,7 @@ def __init__( """ if len(checked_labels) > 1: - err_msg = 'Only one option can be pre-selected for radio buttons.' + err_msg = "Only one option can be pre-selected for radio buttons." raise ValueError(err_msg) super(RadioButton, self).__init__( @@ -2160,10 +2158,10 @@ class ComboBox2D(UI): def __init__( self, - items=[], + items=None, position=(0, 0), size=(300, 200), - placeholder='Choose selection...', + placeholder="Choose selection...", draggable=True, selection_text_color=(0, 0, 0), selection_bg_color=(1, 1, 1), @@ -2214,6 +2212,9 @@ def __init__( Distance between drop down menu's items in pixels. """ + if items is None: + items = [] + self.items = items.copy() self.font_size = font_size self.reverse_scrolling = reverse_scrolling @@ -2238,8 +2239,8 @@ def __init__( self.drop_button_size = (int(0.1 * size[0]), int(0.1 * size[1])) self._icon_files = [ - ('left', read_viz_icons(fname='circle-left.png')), - ('down', read_viz_icons(fname='circle-down.png')), + ("left", read_viz_icons(fname="circle-left.png")), + ("down", read_viz_icons(fname="circle-down.png")), ] super(ComboBox2D, self).__init__() @@ -2319,19 +2320,17 @@ def _setup(self): for slot in self.drop_down_menu.slots: slot.add_callback( slot.textblock.actor, - 'LeftButtonPressEvent', + "LeftButtonPressEvent", self.select_option_callback, ) slot.add_callback( slot.background.actor, - 'LeftButtonPressEvent', + "LeftButtonPressEvent", self.select_option_callback, ) - self.drop_down_button.on_left_mouse_button_clicked = ( - self.menu_toggle_callback - ) + self.drop_down_button.on_left_mouse_button_clicked = self.menu_toggle_callback # Offer some standard hooks to the user. self.on_change = lambda ui: None @@ -2373,8 +2372,10 @@ def _set_position(self, coords): """ self.panel.position = coords - self.panel.position = (self.panel.position[0], - self.panel.position[1] - self.drop_menu_size[1]) + self.panel.position = ( + self.panel.position[0], + self.panel.position[1] - self.drop_menu_size[1], + ) def _add_to_scene(self, scene): """Add all subcomponents or VTK props that compose this UI component. @@ -2419,7 +2420,7 @@ def append_item(self, *items): elif isinstance(item, (str, Number)): self.items.append(str(item)) else: - raise TypeError('Invalid item instance {}'.format(type(item))) + raise TypeError("Invalid item instance {}".format(type(item))) self.drop_down_menu.update_scrollbar() if not self._menu_visibility: @@ -2630,8 +2631,8 @@ def _setup(self): self.scroll_bar.on_left_mouse_button_dragged = self.scroll_drag_callback # Handle mouse wheel events on the panel. - up_event = 'MouseWheelForwardEvent' - down_event = 'MouseWheelBackwardEvent' + up_event = "MouseWheelForwardEvent" + down_event = "MouseWheelBackwardEvent" if self.reverse_scrolling: up_event, down_event = down_event, up_event # Swap events @@ -2951,15 +2952,15 @@ def _setup(self): """ self.background = Rectangle2D() self.textblock = TextBlock2D( - justification='left', vertical_justification='middle' + justification="left", vertical_justification="middle" ) # Add default events listener for this UI component. self.add_callback( - self.textblock.actor, 'LeftButtonPressEvent', self.left_button_clicked + self.textblock.actor, "LeftButtonPressEvent", self.left_button_clicked ) self.add_callback( - self.background.actor, 'LeftButtonPressEvent', self.left_button_clicked + self.background.actor, "LeftButtonPressEvent", self.left_button_clicked ) def _get_actors(self): @@ -3014,7 +3015,7 @@ def element(self): @element.setter def element(self, element): self._element = element - self.textblock.message = '' if self._element is None else str(element) + self.textblock.message = "" if self._element is None else str(element) def left_button_clicked(self, i_ren, _obj, _list_box_item): """Handle left click for this UI element. @@ -3089,7 +3090,7 @@ def __init__( self.multiselection = multiselection self.reverse_scrolling = reverse_scrolling self.line_spacing = line_spacing - self.extensions = extensions or ['*'] + self.extensions = extensions or ["*"] self.current_directory = directory_path self.menu_size = size self.directory_contents = [] @@ -3116,12 +3117,12 @@ def _setup(self): ) self.add_callback( - self.listbox.scroll_bar.actor, 'MouseMoveEvent', self.scroll_callback + self.listbox.scroll_bar.actor, "MouseMoveEvent", self.scroll_callback ) # Handle mouse wheel events on the panel. - up_event = 'MouseWheelForwardEvent' - down_event = 'MouseWheelBackwardEvent' + up_event = "MouseWheelForwardEvent" + down_event = "MouseWheelBackwardEvent" if self.reverse_scrolling: up_event, down_event = down_event, up_event # Swap events @@ -3140,12 +3141,12 @@ def _setup(self): self.add_callback(slot.textblock.actor, down_event, self.scroll_callback) slot.add_callback( slot.textblock.actor, - 'LeftButtonPressEvent', + "LeftButtonPressEvent", self.directory_click_callback, ) slot.add_callback( slot.background.actor, - 'LeftButtonPressEvent', + "LeftButtonPressEvent", self.directory_click_callback, ) @@ -3193,11 +3194,11 @@ def get_all_file_names(self): directory_names = self.get_directory_names() for directory_name in directory_names: - all_file_names.append((directory_name, 'directory')) + all_file_names.append((directory_name, "directory")) file_names = self.get_file_names() for file_name in file_names: - all_file_names.append((file_name, 'file')) + all_file_names.append((file_name, "file")) return all_file_names @@ -3212,11 +3213,11 @@ def get_directory_names(self): """ # A list of directory names in the current directory directory_names = [] - for (_, dirnames, _) in os.walk(self.current_directory): + for _, dirnames, _ in os.walk(self.current_directory): directory_names += dirnames break directory_names.sort(key=lambda s: s.lower()) - directory_names.insert(0, '../') + directory_names.insert(0, "../") return directory_names def get_file_names(self): @@ -3229,16 +3230,18 @@ def get_file_names(self): """ # A list of file names with extension in the current directory - for (_, _, files) in os.walk(self.current_directory): + files = [] + for _, _, f in os.walk(self.current_directory): + files += f break file_names = [] - if '*' in self.extensions or '' in self.extensions: + if "*" in self.extensions or "" in self.extensions: file_names = files else: for ext in self.extensions: for file in files: - if file.endswith('.' + ext): + if file.endswith("." + ext): file_names.append(file) file_names.sort(key=lambda s: s.lower()) return file_names @@ -3251,9 +3254,9 @@ def set_slot_colors(self): list_idx = min( self.listbox.view_offset + idx, len(self.directory_contents) - 1 ) - if self.directory_contents[list_idx][1] == 'directory': + if self.directory_contents[list_idx][1] == "directory": slot.textblock.color = (0, 0.6, 0) - elif self.directory_contents[list_idx][1] == 'file': + elif self.directory_contents[list_idx][1] == "file": slot.textblock.color = (0, 0, 0.7) def scroll_callback(self, i_ren, _obj, _filemenu_item): @@ -3282,7 +3285,7 @@ def directory_click_callback(self, i_ren, _obj, listboxitem): listboxitem: :class:`ListBoxItem2D` """ - if (listboxitem.element, 'directory') in self.directory_contents: + if (listboxitem.element, "directory") in self.directory_contents: new_directory_path = os.path.join( self.current_directory, listboxitem.element ) @@ -3329,14 +3332,14 @@ def _setup(self): Create a Shape. """ - if self.shape_type == 'line': + if self.shape_type == "line": self.shape = Rectangle2D(size=(3, 3)) - elif self.shape_type == 'quad': + elif self.shape_type == "quad": self.shape = Rectangle2D(size=(3, 3)) - elif self.shape_type == 'circle': + elif self.shape_type == "circle": self.shape = Disk2D(outer_radius=2) else: - raise IOError('Unknown shape type: {}.'.format(self.shape_type)) + raise IOError("Unknown shape type: {}.".format(self.shape_type)) self.shape.on_left_mouse_button_pressed = self.left_button_pressed self.shape.on_left_mouse_button_dragged = self.left_button_dragged @@ -3369,7 +3372,7 @@ def _set_position(self, coords): Absolute pixel coordinates (x, y). """ - if self.shape_type == 'circle': + if self.shape_type == "circle": self.shape.center = coords else: self.shape.position = coords @@ -3384,7 +3387,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, "center") self.cal_bounding_box() @property @@ -3432,7 +3435,7 @@ def rotate(self, angle): Value by which the vertices are rotated in radian. """ - if self.shape_type == 'circle': + if self.shape_type == "circle": return points_arr = vertices_from_actor(self.shape.actor) new_points_arr = rotate_2d(points_arr, angle) @@ -3477,15 +3480,15 @@ def clamp_position(self, center=None): def resize(self, size): """Resize the UI.""" - if self.shape_type == 'line': + if self.shape_type == "line": hyp = np.hypot(size[0], size[1]) self.shape.resize((hyp, 3)) self.rotate(angle=np.arctan2(size[1], size[0])) - elif self.shape_type == 'quad': + elif self.shape_type == "quad": self.shape.resize(size) - elif self.shape_type == 'circle': + elif self.shape_type == "circle": hyp = np.hypot(size[0], size[1]) if self.max_size and hyp > self.max_size: hyp = self.max_size @@ -3500,14 +3503,14 @@ def remove(self): def left_button_pressed(self, i_ren, _obj, shape): mode = self.drawpanel.current_mode - if mode == 'selection': + if mode == "selection": self.drawpanel.update_shape_selection(self) click_pos = np.array(i_ren.event.position) self._drag_offset = click_pos - self.center self.drawpanel.show_rotation_slider() i_ren.event.abort() - elif mode == 'delete': + elif mode == "delete": self.remove() else: self.drawpanel.left_button_pressed(i_ren, _obj, self.drawpanel) @@ -3554,7 +3557,7 @@ def __init__(self, size=(400, 400), position=(0, 0), is_draggable=False): self.current_mode = None if is_draggable: - self.current_mode = 'selection' + self.current_mode = "selection" self.shape_list = [] self.current_shape = None @@ -3572,11 +3575,11 @@ def _setup(self): # Convert mode_data into a private variable and make it read-only # Then add the ability to insert user-defined mode mode_data = { - 'selection': ['selection.png', 'selection-pressed.png'], - 'line': ['line.png', 'line-pressed.png'], - 'quad': ['quad.png', 'quad-pressed.png'], - 'circle': ['circle.png', 'circle-pressed.png'], - 'delete': ['delete.png', 'delete-pressed.png'], + "selection": ["selection.png", "selection-pressed.png"], + "line": ["line.png", "line-pressed.png"], + "quad": ["quad.png", "quad-pressed.png"], + "circle": ["circle.png", "circle-pressed.png"], + "delete": ["delete.png", "delete-pressed.png"], } padding = 5 @@ -3588,9 +3591,9 @@ def _setup(self): for mode, fname in mode_data.items(): icon_files = [] - icon_files.append((mode, read_viz_icons(style='new_icons', fname=fname[0]))) + icon_files.append((mode, read_viz_icons(style="new_icons", fname=fname[0]))) icon_files.append( - (mode + '-pressed', read_viz_icons(style='new_icons', fname=fname[1])) + (mode + "-pressed", read_viz_icons(style="new_icons", fname=fname[1])) ) btn = Button2D(icon_fnames=icon_files) @@ -3606,12 +3609,13 @@ def mode_selector(i_ren, _obj, btn): self.canvas.add_element(self.mode_panel, (0, -mode_panel_size[1])) self.mode_text = TextBlock2D( - text='Select appropriate drawing mode using below icon' + text="Select appropriate drawing mode using below icon" ) self.canvas.add_element(self.mode_text, (0.0, 1.0)) - self.rotation_slider = RingSlider2D(initial_value=0, - text_template="{angle:5.1f}°") + self.rotation_slider = RingSlider2D( + initial_value=0, text_template="{angle:5.1f}°" + ) self.rotation_slider.set_visibility(False) def rotate_shape(slider): @@ -3623,7 +3627,8 @@ def rotate_shape(slider): self.current_shape.rotate(np.deg2rad(rotation_angle)) self.current_shape.rotation = slider.value self.current_shape.update_shape_position( - current_center - self.canvas.position) + current_center - self.canvas.position + ) self.rotation_slider.on_moving_slider = rotate_shape @@ -3655,9 +3660,10 @@ def _set_position(self, coords): """ self.canvas.position = coords + [0, self.mode_panel.size[1]] - slider_position = self.canvas.position + \ - [self.canvas.size[0] - self.rotation_slider.size[0]/2, - self.rotation_slider.size[1]/2] + slider_position = self.canvas.position + [ + self.canvas.size[0] - self.rotation_slider.size[0] / 2, + self.rotation_slider.size[1] / 2, + ] self.rotation_slider.center = slider_position def resize(self, size): @@ -3673,7 +3679,7 @@ def current_mode(self, mode): self.update_button_icons(mode) self._current_mode = mode if mode is not None: - self.mode_text.message = f'Mode: {mode}' + self.mode_text.message = f"Mode: {mode}" def cal_min_boundary_distance(self, position): """Calculate minimum distance between the current position and canvas boundary. @@ -3711,7 +3717,7 @@ def draw_shape(self, shape_type, current_position): shape = DrawShape( shape_type=shape_type, drawpanel=self, position=current_position ) - if shape_type == 'circle': + if shape_type == "circle": shape.max_size = self.cal_min_boundary_distance(current_position) self.shape_list.append(shape) self._scene.add(shape) @@ -3739,8 +3745,7 @@ def update_shape_selection(self, selected_shape): shape.is_selected = False def show_rotation_slider(self): - """Display the RingSlider2D to allow rotation of shape from the center. - """ + """Display the RingSlider2D to allow rotation of shape from the center.""" self._scene.rm(*self.rotation_slider.actors) self.rotation_slider.add_to_scene(self._scene) self.rotation_slider.set_visibility(True) @@ -3781,11 +3786,11 @@ def clamp_mouse_position(self, mouse_position): ) def handle_mouse_click(self, position): - if self.current_mode == 'selection': + if self.current_mode == "selection": if self.is_draggable: self._drag_offset = position - self.position self.current_shape.is_selected = False - if self.current_mode in ['line', 'quad', 'circle']: + if self.current_mode in ["line", "quad", "circle"]: self.draw_shape(self.current_mode, position) def left_button_pressed(self, i_ren, _obj, element): @@ -3793,11 +3798,11 @@ def left_button_pressed(self, i_ren, _obj, element): i_ren.force_render() def handle_mouse_drag(self, position): - if self.is_draggable and self.current_mode == 'selection': + if self.is_draggable and self.current_mode == "selection": if self._drag_offset is not None: new_position = position - self._drag_offset self.position = new_position - if self.current_mode in ['line', 'quad', 'circle']: + if self.current_mode in ["line", "quad", "circle"]: self.resize_shape(position) def left_button_dragged(self, i_ren, _obj, element): @@ -3836,31 +3841,31 @@ def _setup(self): """Setup this Panel component.""" self.time_text = TextBlock2D() self.speed_text = TextBlock2D( - text='1', + text="1", font_size=21, color=(0.2, 0.2, 0.2), bold=True, - justification='center', - vertical_justification='middle', + justification="center", + vertical_justification="middle", ) self.panel = Panel2D( size=(190, 30), color=(1, 1, 1), - align='right', + align="right", has_border=True, border_color=(0, 0.3, 0), border_width=2, ) play_pause_icons = [ - ('play', read_viz_icons(fname='play3.png')), - ('pause', read_viz_icons(fname='pause2.png')), + ("play", read_viz_icons(fname="play3.png")), + ("pause", read_viz_icons(fname="pause2.png")), ] loop_icons = [ - ('once', read_viz_icons(fname='checkmark.png')), - ('loop', read_viz_icons(fname='infinite.png')), + ("once", read_viz_icons(fname="checkmark.png")), + ("loop", read_viz_icons(fname="infinite.png")), ] self._play_pause_btn = Button2D(icon_fnames=play_pause_icons) @@ -3868,25 +3873,25 @@ def _setup(self): self._loop_btn = Button2D(icon_fnames=loop_icons) self._stop_btn = Button2D( - icon_fnames=[('stop', read_viz_icons(fname='stop2.png'))] + icon_fnames=[("stop", read_viz_icons(fname="stop2.png"))] ) self._speed_up_btn = Button2D( - icon_fnames=[('plus', read_viz_icons(fname='plus.png'))], size=(15, 15) + icon_fnames=[("plus", read_viz_icons(fname="plus.png"))], size=(15, 15) ) self._slow_down_btn = Button2D( - icon_fnames=[('minus', read_viz_icons(fname='minus.png'))], size=(15, 15) + icon_fnames=[("minus", read_viz_icons(fname="minus.png"))], size=(15, 15) ) self._progress_bar = LineSlider2D( initial_value=0, - orientation='horizontal', + orientation="horizontal", min_value=0, max_value=100, - text_alignment='top', + text_alignment="top", length=590, - text_template='', + text_template="", line_width=9, ) @@ -3953,30 +3958,30 @@ def on_progress_change(slider): def play(self): """Play the playback""" self._playing = True - self._play_pause_btn.set_icon_by_name('pause') + self._play_pause_btn.set_icon_by_name("pause") self.on_play() def stop(self): """Stop the playback""" self._playing = False - self._play_pause_btn.set_icon_by_name('play') + self._play_pause_btn.set_icon_by_name("play") self.on_stop() def pause(self): """Pause the playback""" self._playing = False - self._play_pause_btn.set_icon_by_name('play') + self._play_pause_btn.set_icon_by_name("play") self.on_pause() def loop(self): """Set repeating mode to loop.""" self._loop = True - self._loop_btn.set_icon_by_name('loop') + self._loop_btn.set_icon_by_name("loop") def play_once(self): """Set repeating mode to repeat once.""" self._loop = False - self._loop_btn.set_icon_by_name('once') + self._loop_btn.set_icon_by_name("once") @property def final_time(self): @@ -4057,11 +4062,11 @@ def current_time_str(self, t): t = np.clip(t, 0, self.final_time) if self.final_time < 3600: m, s = divmod(t, 60) - t_str = r'%02d:%05.2f' % (m, s) + t_str = r"%02d:%05.2f" % (m, s) else: m, s = divmod(t, 60) h, m = divmod(m, 60) - t_str = r'%02d:%02d:%02d' % (h, m, s) + t_str = r"%02d:%02d:%02d" % (h, m, s) self.time_text.message = t_str @property @@ -4089,7 +4094,7 @@ def speed(self, speed): if speed <= 0: speed = 0.01 self._speed = speed - speed_str = f'{speed}'.strip('0').rstrip('.') + speed_str = f"{speed}".strip("0").rstrip(".") self.speed_text.font_size = 21 if 0.01 <= speed < 100 else 14 self.speed_text.message = speed_str @@ -4180,12 +4185,24 @@ class Card2D(UI): """ - def __init__(self, image_path, body_text="", draggable=True, - title_text="", padding=10, position=(0, 0), - size=(400, 400), image_scale=0.5, bg_color=(0.5, 0.5, 0.5), - bg_opacity=1, title_color=(0., 0., 0.), - body_color=(0., 0., 0.), border_color=(1., 1., 1.), - border_width=0, maintain_aspect=False): + def __init__( + self, + image_path, + body_text="", + draggable=True, + title_text="", + padding=10, + position=(0, 0), + size=(400, 400), + image_scale=0.5, + bg_color=(0.5, 0.5, 0.5), + bg_opacity=1, + title_color=(0.0, 0.0, 0.0), + body_color=(0.0, 0.0, 0.0), + border_color=(1.0, 1.0, 1.0), + border_width=0, + maintain_aspect=False, + ): """Parameters ---------- image_path: str @@ -4223,10 +4240,11 @@ def __init__(self, image_path, body_text="", draggable=True, """ self.image_path = image_path self._basename = os.path.basename(self.image_path) - self._extension = self._basename.split('.')[-1] - if self._extension not in ['jpg', 'jpeg', 'png']: + self._extension = self._basename.split(".")[-1] + if self._extension not in ["jpg", "jpeg", "png"]: raise UnidentifiedImageError( - f'Image extension {self._extension} not supported') + f"Image extension {self._extension} not supported" + ) self.body_text = body_text self.title_text = title_text @@ -4247,8 +4265,7 @@ def __init__(self, image_path, body_text="", draggable=True, if self.maintain_aspect: self._true_image_size = Image.open(urlopen(self.image_path)).size - self._image_size = (self.card_size[0], self.card_size[1] * - self.image_scale) + self._image_size = (self.card_size[0], self.card_size[1] * self.image_scale) self.border_width = border_width self.has_border = bool(border_width) @@ -4257,8 +4274,10 @@ def __init__(self, image_path, body_text="", draggable=True, self.position = position if self.maintain_aspect: - self._new_size = (self._true_image_size[0], - self._true_image_size[1] // self.image_scale) + self._new_size = ( + self._true_image_size[0], + self._true_image_size[1] // self.image_scale, + ) self.resize(self._new_size) else: self.resize(size) @@ -4269,41 +4288,43 @@ def _setup(self): Create the title and body. Create a Panel2D widget to hold image, title, body. """ - self.image = ImageContainer2D(img_path=self.image_path, - size=self._image_size) + self.image = ImageContainer2D(img_path=self.image_path, size=self._image_size) - self.body_box = TextBlock2D(text=self.body_text, - color=self.body_color) + self.body_box = TextBlock2D(text=self.body_text, color=self.body_color) - self.title_box = TextBlock2D(text=self.title_text, bold=True, - color=self.title_color) + self.title_box = TextBlock2D( + text=self.title_text, bold=True, color=self.title_color + ) - self.panel = Panel2D(self.card_size, color=self.bg_color, - opacity=self.bg_opacity, - border_color=self.border_color, - border_width=self.border_width, - has_border=self.has_border) + self.panel = Panel2D( + self.card_size, + color=self.bg_color, + opacity=self.bg_opacity, + border_color=self.border_color, + border_width=self.border_width, + has_border=self.has_border, + ) - self.panel.add_element(self.image, (0., 0.)) - self.panel.add_element(self.title_box, (0., 0.)) - self.panel.add_element(self.body_box, (0., 0.)) + self.panel.add_element(self.image, (0.0, 0.0)) + self.panel.add_element(self.title_box, (0.0, 0.0)) + self.panel.add_element(self.body_box, (0.0, 0.0)) if self.draggable: - self.panel.background.on_left_mouse_button_dragged =\ - self.left_button_dragged - self.panel.background.on_left_mouse_button_pressed\ - = self.left_button_pressed - self.image.on_left_mouse_button_dragged =\ + self.panel.background.on_left_mouse_button_dragged = ( self.left_button_dragged - self.image.on_left_mouse_button_pressed =\ + ) + self.panel.background.on_left_mouse_button_pressed = ( self.left_button_pressed + ) + self.image.on_left_mouse_button_dragged = self.left_button_dragged + self.image.on_left_mouse_button_pressed = self.left_button_pressed else: - self.panel.background.on_left_mouse_button_dragged =\ + self.panel.background.on_left_mouse_button_dragged = ( lambda i_ren, _obj, _comp: i_ren.force_render + ) def _get_actors(self): - """Get the actors composing this UI component. - """ + """Get the actors composing this UI component.""" return self.panel.actors def _add_to_scene(self, _scene): @@ -4316,11 +4337,11 @@ def _add_to_scene(self, _scene): """ self.panel.add_to_scene(_scene) if self.size[0] <= 200: - clip_overflow(self.body_box, self.size[0]-2*self.padding) + clip_overflow(self.body_box, self.size[0] - 2 * self.padding) else: - wrap_overflow(self.body_box, self.size[0]-2*self.padding) + wrap_overflow(self.body_box, self.size[0] - 2 * self.padding) - wrap_overflow(self.title_box, self.size[0]-2*self.padding) + wrap_overflow(self.title_box, self.size[0] - 2 * self.padding) def _get_size(self): return self.panel.size @@ -4337,25 +4358,31 @@ def resize(self, size): _width, _height = size self.panel.resize(size) - self._image_size = (size[0]-int(self.border_width), - int(self.image_scale*size[1])) + self._image_size = ( + size[0] - int(self.border_width), + int(self.image_scale * size[1]), + ) - _title_box_size = (_width - 2 * self.padding, _height * - 0.34 * self.text_scale / 2) + _title_box_size = ( + _width - 2 * self.padding, + _height * 0.34 * self.text_scale / 2, + ) - _body_box_size = (_width - 2 * self.padding, _height * - self.text_scale / 2) + _body_box_size = (_width - 2 * self.padding, _height * self.text_scale / 2) - _img_coords = (int(self.border_width), - int(size[1] - self._image_size[1])) + _img_coords = (int(self.border_width), int(size[1] - self._image_size[1])) - _title_coords = (self.padding, int(_img_coords[1] - - _title_box_size[1] - self.padding + - self.border_width)) + _title_coords = ( + self.padding, + int(_img_coords[1] - _title_box_size[1] - self.padding + self.border_width), + ) - _text_coords = (self.padding, int(_title_coords[1] - - _body_box_size[1] - self.padding + - self.border_width)) + _text_coords = ( + self.padding, + int( + _title_coords[1] - _body_box_size[1] - self.padding + self.border_width + ), + ) self.panel.update_element(self.image, _img_coords) self.panel.update_element(self.body_box, _text_coords) @@ -4377,8 +4404,7 @@ def _set_position(self, _coords): @property def color(self): - """Returns the background color of card. - """ + """Returns the background color of card.""" return self.panel.color @color.setter @@ -4394,8 +4420,7 @@ def color(self, color): @property def body(self): - """Returns the body text of the card. - """ + """Returns the body text of the card.""" return self.body_box.message @body.setter @@ -4404,8 +4429,7 @@ def body(self, text): @property def title(self): - """Returns the title text of the card - """ + """Returns the title text of the card""" return self.title_box.message @title.setter @@ -4426,12 +4450,21 @@ def left_button_dragged(self, i_ren, _obj, _sub_component): class SpinBox(UI): - """SpinBox UI. - """ + """SpinBox UI.""" - def __init__(self, position=(350, 400), size=(300, 100), padding=10, - panel_color=(1, 1, 1), min_val=0, max_val=100, - initial_val=50, step=1, max_column=10, max_line=2): + def __init__( + self, + position=(350, 400), + size=(300, 100), + padding=10, + panel_color=(1, 1, 1), + min_val=0, + max_val=100, + initial_val=50, + step=1, + max_column=10, + max_line=2, + ): """Init this UI element. Parameters @@ -4482,24 +4515,23 @@ def _setup(self): """ self.panel = Panel2D(size=self.panel_size, color=self.panel_color) - self.textbox = TextBox2D(width=self.max_column, - height=self.max_line) + self.textbox = TextBox2D(width=self.max_column, height=self.max_line) self.textbox.text.dynamic_bbox = False self.textbox.text.auto_font_scale = True self.increment_button = Button2D( - icon_fnames=[("up", read_viz_icons(fname="circle-up.png"))]) + icon_fnames=[("up", read_viz_icons(fname="circle-up.png"))] + ) self.decrement_button = Button2D( - icon_fnames=[("down", read_viz_icons(fname="circle-down.png"))]) + icon_fnames=[("down", read_viz_icons(fname="circle-down.png"))] + ) self.panel.add_element(self.textbox, (0, 0)) self.panel.add_element(self.increment_button, (0, 0)) self.panel.add_element(self.decrement_button, (0, 0)) # Adding button click callbacks - self.increment_button.on_left_mouse_button_pressed = \ - self.increment_callback - self.decrement_button.on_left_mouse_button_pressed = \ - self.decrement_callback + self.increment_button.on_left_mouse_button_pressed = self.increment_callback + self.decrement_button.on_left_mouse_button_pressed = self.decrement_callback self.textbox.off_focus = self.textbox_update_value def resize(self, size): @@ -4521,11 +4553,15 @@ def resize(self, size): self.increment_button.resize(self.button_size) self.decrement_button.resize(self.button_size) - textbox_pos = (self.padding, int((size[1] - self.textbox_size[1])/2)) - inc_btn_pos = (size[0] - self.padding - self.button_size[0], - int((1.5*size[1] - self.button_size[1])/2)) - dec_btn_pos = (size[0] - self.padding - self.button_size[0], - int((0.5*size[1] - self.button_size[1])/2)) + textbox_pos = (self.padding, int((size[1] - self.textbox_size[1]) / 2)) + inc_btn_pos = ( + size[0] - self.padding - self.button_size[0], + int((1.5 * size[1] - self.button_size[1]) / 2), + ) + dec_btn_pos = ( + size[0] - self.padding - self.button_size[0], + int((0.5 * size[1] - self.button_size[1]) / 2), + ) self.panel.update_element(self.textbox, textbox_pos) self.panel.update_element(self.increment_button, inc_btn_pos) diff --git a/fury/ui/helpers.py b/fury/ui/helpers.py index 3a33df2e2..8a9c39de5 100644 --- a/fury/ui/helpers.py +++ b/fury/ui/helpers.py @@ -5,7 +5,7 @@ TWO_PI = 2 * np.pi -def clip_overflow(textblock, width, side='right'): +def clip_overflow(textblock, width, side="right"): """Clips overflowing text of TextBlock2D with respect to width. Parameters @@ -27,7 +27,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, "...", side) if clip_idx == 0: return original_str @@ -36,7 +36,7 @@ def clip_overflow(textblock, width, side='right'): return textblock.message -def wrap_overflow(textblock, wrap_width, side='right'): +def wrap_overflow(textblock, wrap_width, side="right"): """Wraps overflowing text of TextBlock2D with respect to width. Parameters @@ -59,7 +59,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, "", side) if wrap_idx == 0: return original_str @@ -69,18 +69,18 @@ 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, "", side) if wrap_idx != 0: wrap_idxs.append(wrap_idxs[-1] + wrap_idx + 1) for idx in wrap_idxs: - original_str = original_str[:idx] + '\n' + original_str[idx:] + original_str = original_str[:idx] + "\n" + original_str[idx:] textblock.message = original_str return textblock.message -def check_overflow(textblock, width, overflow_postfix='', side='right'): +def check_overflow(textblock, width, overflow_postfix="", side="right"): """Checks if the text is overflowing. Parameters @@ -99,7 +99,7 @@ def check_overflow(textblock, width, overflow_postfix='', side='right'): """ side = side.lower() - if side not in ['left', 'right']: + if side not in ["left", "right"]: raise ValueError("side can only take values 'left' or 'right'") original_str = textblock.message @@ -107,7 +107,7 @@ def check_overflow(textblock, width, overflow_postfix='', side='right'): mid_ptr = 0 end_ptr = len(original_str) - if side == 'left': + if side == "left": original_str = original_str[::-1] if textblock.cal_size_from_message()[0] <= width: @@ -122,9 +122,11 @@ def check_overflow(textblock, width, overflow_postfix='', side='right'): elif textblock.cal_size_from_message()[0] > width: end_ptr = mid_ptr - if (mid_ptr == (start_ptr + end_ptr) // 2 or - textblock.cal_size_from_message()[0] == width): - if side == 'left': + if ( + mid_ptr == (start_ptr + end_ptr) // 2 + or textblock.cal_size_from_message()[0] == width + ): + if side == "left": textblock.message = textblock.message[::-1] return mid_ptr @@ -139,7 +141,7 @@ def cal_bounding_box_2d(vertices): """ if vertices.ndim != 2 or vertices.shape[1] not in [2, 3]: - raise IOError('vertices should be a 2D array with shape (n,2) or (n,3).') + raise IOError("vertices should be a 2D array with shape (n,2) or (n,3).") if vertices.shape[1] == 3: vertices = vertices[:, :-1] @@ -157,9 +159,9 @@ def cal_bounding_box_2d(vertices): if y > max_y: max_y = y - bounding_box_min = np.asarray([min_x, min_y], dtype='int') - bounding_box_max = np.asarray([max_x, max_y], dtype='int') - bounding_box_size = np.asarray([max_x - min_x, max_y - min_y], dtype='int') + bounding_box_min = np.asarray([min_x, min_y], dtype="int") + bounding_box_max = np.asarray([max_x, max_y], dtype="int") + bounding_box_size = np.asarray([max_x - min_x, max_y - min_y], dtype="int") return bounding_box_min, bounding_box_max, bounding_box_size @@ -176,7 +178,7 @@ def rotate_2d(vertices, angle): """ if vertices.ndim != 2 or vertices.shape[1] != 3: - raise IOError('vertices should be a 2D array with shape (n,3).') + raise IOError("vertices should be a 2D array with shape (n,3).") rotation_matrix = np.array( [ diff --git a/fury/ui/tests/test_containers.py b/fury/ui/tests/test_containers.py index 79edcd4a0..333fb7b44 100644 --- a/fury/ui/tests/test_containers.py +++ b/fury/ui/tests/test_containers.py @@ -22,13 +22,13 @@ 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(dummy_scene, interactor_style="trackball") npt.assert_raises(TypeError, panel.add_to_scene, dummy_scene) @pytest.mark.skipif( skip_linux or skip_win, - reason='This test does not work on Windows.' ' Need to be introspected', + reason="This test does not work on Windows." " Need to be introspected", ) def test_grid_ui1(interactive=False): vol1 = np.zeros((100, 100, 100)) @@ -52,39 +52,39 @@ def test_grid_ui1(interactive=False): texts = [] actors.append(contour_actor1) - text_actor1 = actor.text_3d('cube 1', justification='center') + text_actor1 = actor.text_3d("cube 1", justification="center") texts.append(text_actor1) actors.append(contour_actor2) - text_actor2 = actor.text_3d('cube 2', justification='center') + text_actor2 = actor.text_3d("cube 2", justification="center") texts.append(text_actor2) actors.append(contour_actor3) - text_actor3 = actor.text_3d('cube 3', justification='center') + text_actor3 = actor.text_3d("cube 3", justification="center") texts.append(text_actor3) actors.append(shallow_copy(contour_actor1)) - text_actor1 = actor.text_3d('cube 4', justification='center') + text_actor1 = actor.text_3d("cube 4", justification="center") texts.append(text_actor1) actors.append(shallow_copy(contour_actor2)) - text_actor2 = actor.text_3d('cube 5', justification='center') + text_actor2 = actor.text_3d("cube 5", justification="center") texts.append(text_actor2) actors.append(shallow_copy(contour_actor3)) - text_actor3 = actor.text_3d('cube 6', justification='center') + text_actor3 = actor.text_3d("cube 6", justification="center") texts.append(text_actor3) actors.append(shallow_copy(contour_actor1)) - text_actor1 = actor.text_3d('cube 7', justification='center') + text_actor1 = actor.text_3d("cube 7", justification="center") texts.append(text_actor1) actors.append(shallow_copy(contour_actor2)) - text_actor2 = actor.text_3d('cube 8', justification='center') + text_actor2 = actor.text_3d("cube 8", justification="center") texts.append(text_actor2) actors.append(shallow_copy(contour_actor3)) - text_actor3 = actor.text_3d('cube 9', justification='center') + text_actor3 = actor.text_3d("cube 9", justification="center") texts.append(text_actor3) counter = itertools.count() @@ -125,14 +125,13 @@ def timer_callback(_obj, _event): grid_ui_2 = ui.GridUI(actors=actors) new_sm.scene.add(grid_ui_2) t = 1 - except: + except: # noqa: E722 pass npt.assert_equal(t, 1) def test_grid_ui2(interactive=False): - vol1 = np.zeros((100, 100, 100)) vol1[25:75, 25:75, 25:75] = 100 @@ -154,52 +153,52 @@ def test_grid_ui2(interactive=False): texts = [] actors.append(contour_actor1) - text_actor1 = actor.text_3d('cube 1', justification='center') + text_actor1 = actor.text_3d("cube 1", justification="center") texts.append(text_actor1) actors.append(contour_actor2) - text_actor2 = actor.text_3d('cube 2', justification='center') + text_actor2 = actor.text_3d("cube 2", justification="center") texts.append(text_actor2) actors.append(contour_actor3) - text_actor3 = actor.text_3d('cube 3', justification='center') + text_actor3 = actor.text_3d("cube 3", justification="center") texts.append(text_actor3) actors.append(shallow_copy(contour_actor1)) - text_actor1 = actor.text_3d('cube 4', justification='center') + text_actor1 = actor.text_3d("cube 4", justification="center") texts.append(text_actor1) actors.append(shallow_copy(contour_actor2)) - text_actor2 = actor.text_3d('cube 5', justification='center') + text_actor2 = actor.text_3d("cube 5", justification="center") texts.append(text_actor2) actors.append(shallow_copy(contour_actor3)) - text_actor3 = actor.text_3d('cube 6', justification='center') + text_actor3 = actor.text_3d("cube 6", justification="center") texts.append(text_actor3) actors.append(shallow_copy(contour_actor1)) - text_actor1 = actor.text_3d('cube 7', justification='center') + text_actor1 = actor.text_3d("cube 7", justification="center") texts.append(text_actor1) actors.append(shallow_copy(contour_actor2)) - text_actor2 = actor.text_3d('cube 8', justification='center') + text_actor2 = actor.text_3d("cube 8", justification="center") texts.append(text_actor2) actors.append(shallow_copy(contour_actor3)) - text_actor3 = actor.text_3d('cube 9', justification='center') + text_actor3 = actor.text_3d("cube 9", justification="center") texts.append(text_actor3) # this needs to happen automatically when start() ends. # for act in actors: # act.RemoveAllObservers() - filename = 'test_grid_ui' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_grid_ui" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") current_size = (900, 600) scene = window.Scene() - show_manager = window.ShowManager(scene, size=current_size, title='FURY GridUI') + show_manager = window.ShowManager(scene, size=current_size, title="FURY GridUI") grid_ui2 = ui.GridUI( actors=actors, @@ -234,7 +233,7 @@ def test_grid_ui2(interactive=False): def test_ui_image_container_2d(interactive=False): - image_test = ui.ImageContainer2D(img_path=read_viz_icons(fname='home3.png')) + image_test = ui.ImageContainer2D(img_path=read_viz_icons(fname="home3.png")) image_test.center = (300, 300) npt.assert_equal(image_test.size, (100, 100)) @@ -243,23 +242,22 @@ def test_ui_image_container_2d(interactive=False): npt.assert_equal(image_test.size, (200, 200)) current_size = (600, 600) - show_manager = window.ShowManager(size=current_size, title='FURY Button') + show_manager = window.ShowManager(size=current_size, title="FURY Button") show_manager.scene.add(image_test) if interactive: show_manager.start() def test_ui_tab_ui(interactive=False): - filename = 'test_ui_tab_ui' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_tab_ui" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") - tab_ui = ui.TabUI( - position=(50, 50), size=(300, 300), nb_tabs=3, draggable=True) + tab_ui = ui.TabUI(position=(50, 50), size=(300, 300), nb_tabs=3, draggable=True) - tab_ui.tabs[0].title = 'Tab 1' - tab_ui.tabs[1].title = 'Tab 2' - tab_ui.tabs[2].title = 'Tab 3' + tab_ui.tabs[0].title = "Tab 1" + tab_ui.tabs[1].title = "Tab 2" + tab_ui.tabs[2].title = "Tab 3" npt.assert_equal(tab_ui.tabs[0].title_bold, False) npt.assert_equal(tab_ui.tabs[1].title_bold, False) @@ -273,17 +271,17 @@ def test_ui_tab_ui(interactive=False): npt.assert_equal(tab_ui.tabs[1].title_bold, False) npt.assert_equal(tab_ui.tabs[2].title_bold, True) - npt.assert_equal(tab_ui.tabs[0].title_color, (.0, .0, .0)) - npt.assert_equal(tab_ui.tabs[1].title_color, (.0, .0, .0)) - npt.assert_equal(tab_ui.tabs[2].title_color, (.0, .0, .0)) + npt.assert_equal(tab_ui.tabs[0].title_color, (0.0, 0.0, 0.0)) + npt.assert_equal(tab_ui.tabs[1].title_color, (0.0, 0.0, 0.0)) + npt.assert_equal(tab_ui.tabs[2].title_color, (0.0, 0.0, 0.0)) tab_ui.tabs[0].title_color = (1, 0, 0) tab_ui.tabs[1].title_color = (0, 1, 0) tab_ui.tabs[2].title_color = (0, 0, 1) - npt.assert_equal(tab_ui.tabs[0].title_color, (1., .0, .0)) - npt.assert_equal(tab_ui.tabs[1].title_color, (.0, 1., .0)) - npt.assert_equal(tab_ui.tabs[2].title_color, (.0, .0, 1.)) + npt.assert_equal(tab_ui.tabs[0].title_color, (1.0, 0.0, 0.0)) + npt.assert_equal(tab_ui.tabs[1].title_color, (0.0, 1.0, 0.0)) + npt.assert_equal(tab_ui.tabs[2].title_color, (0.0, 0.0, 1.0)) npt.assert_equal(tab_ui.tabs[0].title_font_size, 18) npt.assert_equal(tab_ui.tabs[1].title_font_size, 18) @@ -309,8 +307,7 @@ def test_ui_tab_ui(interactive=False): npt.assert_equal(tab_ui.tabs[1].title_italic, True) npt.assert_equal(tab_ui.tabs[2].title_italic, False) - tab_ui.add_element(0, ui.Checkbox(['Option 1', 'Option 2']), - (0.5, 0.5)) + tab_ui.add_element(0, ui.Checkbox(["Option 1", "Option 2"]), (0.5, 0.5)) tab_ui.add_element(1, ui.LineSlider2D(), (0.0, 0.5)) tab_ui.add_element(2, ui.TextBlock2D(), (0.5, 0.5)) @@ -323,9 +320,9 @@ def test_ui_tab_ui(interactive=False): with npt.assert_raises(IndexError): tab_ui.update_element(3, ui.TextBlock2D(), (0.5, 0.5, 0.5)) - npt.assert_equal('Tab 1', tab_ui.tabs[0].title) - npt.assert_equal('Tab 2', tab_ui.tabs[1].title) - npt.assert_equal('Tab 3', tab_ui.tabs[2].title) + npt.assert_equal("Tab 1", tab_ui.tabs[0].title) + npt.assert_equal("Tab 2", tab_ui.tabs[1].title) + npt.assert_equal("Tab 3", tab_ui.tabs[2].title) npt.assert_equal(3, tab_ui.nb_tabs) @@ -346,8 +343,7 @@ def tab_change(tab_ui): event_counter.monitor(tab_ui) current_size = (800, 800) - show_manager = window.ShowManager(size=current_size, - title='Tab UI Test') + show_manager = window.ShowManager(size=current_size, title="Tab UI Test") show_manager.scene.add(tab_ui) if interactive: @@ -365,26 +361,25 @@ def tab_change(tab_ui): def test_ui_tab_ui_position(interactive=False): - filename = 'test_ui_tab_ui_top_position' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_tab_ui_top_position" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") tab_ui_top = ui.TabUI( - position=(50, 50), size=(300, 300), nb_tabs=3, draggable=True, - tab_bar_pos='top') + position=(50, 50), size=(300, 300), nb_tabs=3, draggable=True, tab_bar_pos="top" + ) - tab_ui_top.tabs[0].title = 'Tab 1' - tab_ui_top.tabs[1].title = 'Tab 2' - tab_ui_top.tabs[2].title = 'Tab 3' + tab_ui_top.tabs[0].title = "Tab 1" + tab_ui_top.tabs[1].title = "Tab 2" + tab_ui_top.tabs[2].title = "Tab 3" - tab_ui_top.add_element(0, ui.Checkbox(['Option 1', 'Option 2']), - (0.5, 0.5)) + tab_ui_top.add_element(0, ui.Checkbox(["Option 1", "Option 2"]), (0.5, 0.5)) tab_ui_top.add_element(1, ui.LineSlider2D(), (0.0, 0.5)) tab_ui_top.add_element(2, ui.TextBlock2D(), (0.5, 0.5)) - npt.assert_equal('Tab 1', tab_ui_top.tabs[0].title) - npt.assert_equal('Tab 2', tab_ui_top.tabs[1].title) - npt.assert_equal('Tab 3', tab_ui_top.tabs[2].title) + npt.assert_equal("Tab 1", tab_ui_top.tabs[0].title) + npt.assert_equal("Tab 2", tab_ui_top.tabs[1].title) + npt.assert_equal("Tab 3", tab_ui_top.tabs[2].title) npt.assert_equal(3, tab_ui_top.nb_tabs) @@ -401,21 +396,24 @@ def test_ui_tab_ui_position(interactive=False): tab_ui_top.update_element(3, ui.TextBlock2D(), (0.5, 0.5, 0.5)) tab_ui_bottom = ui.TabUI( - position=(350, 50), size=(300, 300), nb_tabs=3, draggable=True, - tab_bar_pos='bottom') + position=(350, 50), + size=(300, 300), + nb_tabs=3, + draggable=True, + tab_bar_pos="bottom", + ) - tab_ui_bottom.tabs[0].title = 'Tab 1' - tab_ui_bottom.tabs[1].title = 'Tab 2' - tab_ui_bottom.tabs[2].title = 'Tab 3' + tab_ui_bottom.tabs[0].title = "Tab 1" + tab_ui_bottom.tabs[1].title = "Tab 2" + tab_ui_bottom.tabs[2].title = "Tab 3" - tab_ui_bottom.add_element(0, ui.Checkbox(['Option 1', 'Option 2']), - (0.5, 0.5)) + tab_ui_bottom.add_element(0, ui.Checkbox(["Option 1", "Option 2"]), (0.5, 0.5)) tab_ui_bottom.add_element(1, ui.LineSlider2D(), (0.0, 0.5)) tab_ui_bottom.add_element(2, ui.TextBlock2D(), (0.5, 0.5)) - npt.assert_equal('Tab 1', tab_ui_bottom.tabs[0].title) - npt.assert_equal('Tab 2', tab_ui_bottom.tabs[1].title) - npt.assert_equal('Tab 3', tab_ui_bottom.tabs[2].title) + npt.assert_equal("Tab 1", tab_ui_bottom.tabs[0].title) + npt.assert_equal("Tab 2", tab_ui_bottom.tabs[1].title) + npt.assert_equal("Tab 3", tab_ui_bottom.tabs[2].title) npt.assert_equal(3, tab_ui_bottom.nb_tabs) @@ -452,8 +450,7 @@ def tab_change(tab_ui_top): event_counter.monitor(tab_ui_bottom) current_size = (800, 800) - show_manager = window.ShowManager(size=current_size, - title='Tab UI Test') + show_manager = window.ShowManager(size=current_size, title="Tab UI Test") show_manager.scene.add(tab_ui_top) show_manager.scene.add(tab_ui_bottom) diff --git a/fury/ui/tests/test_core.py b/fury/ui/tests/test_core.py index 3ee849216..5e76a1cfe 100644 --- a/fury/ui/tests/test_core.py +++ b/fury/ui/tests/test_core.py @@ -1,6 +1,6 @@ """Core module testing.""" + from os.path import join as pjoin -import warnings import numpy as np import numpy.testing as npt @@ -11,9 +11,9 @@ def test_ui_button_panel(recording=False): - filename = 'test_ui_button_panel' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_button_panel" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") # Rectangle rectangle_test = ui.Rectangle2D(size=(10, 10)) @@ -23,8 +23,8 @@ def test_ui_button_panel(recording=False): fetch_viz_icons() icon_files = [] - icon_files.append(('stop', read_viz_icons(fname='stop2.png'))) - icon_files.append(('play', read_viz_icons(fname='play3.png'))) + icon_files.append(("stop", read_viz_icons(fname="stop2.png"))) + icon_files.append(("play", read_viz_icons(fname="play3.png"))) button_test = ui.Button2D(icon_fnames=icon_files) button_test.center = (20, 20) @@ -53,7 +53,7 @@ def modify_button_callback(i_ren, _obj, button): # TextBlock text_block_test = ui.TextBlock2D() - text_block_test.message = 'TextBlock' + text_block_test.message = "TextBlock" text_block_test.color = (0, 0, 0) # Panel @@ -61,13 +61,13 @@ def modify_button_callback(i_ren, _obj, button): size=(300, 150), position=(290, 15), color=(1, 1, 1), - align='right', + align="right", has_border=True, ) non_bordered_panel = ui.Panel2D(size=(100, 100), has_border=False) - npt.assert_equal(hasattr(non_bordered_panel, 'borders'), False) + npt.assert_equal(hasattr(non_bordered_panel, "borders"), False) panel.add_element(rectangle_test, (290, 135)) panel.add_element(button_test, (0.1, 0.1)) @@ -94,33 +94,33 @@ def modify_button_callback(i_ren, _obj, button): * 4, ) - panel.border_width = ['bottom', 10.0] + panel.border_width = ["bottom", 10.0] npt.assert_equal(panel.border_width[3], 10.0) - npt.assert_equal(panel.borders['bottom'].height, 10.0) + npt.assert_equal(panel.borders["bottom"].height, 10.0) - panel.border_width = ['right', 10.0] + panel.border_width = ["right", 10.0] npt.assert_equal(panel.border_width[1], 10.0) - npt.assert_equal(panel.borders['right'].width, 10.0) + npt.assert_equal(panel.borders["right"].width, 10.0) with npt.assert_raises(ValueError): - panel.border_width = ['invalid_label', 10.0] + panel.border_width = ["invalid_label", 10.0] - panel.border_color = ['bottom', (0.4, 0.5, 0.6)] + panel.border_color = ["bottom", (0.4, 0.5, 0.6)] npt.assert_equal(panel.border_color[3], (0.4, 0.5, 0.6)) with npt.assert_raises(ValueError): - panel.border_color = ['invalid_label', (0.4, 0.5, 0.6)] + panel.border_color = ["invalid_label", (0.4, 0.5, 0.6)] new_size = (400, 400) panel.resize(new_size) - npt.assert_equal(panel.borders['bottom'].width, 400.0) + npt.assert_equal(panel.borders["bottom"].width, 400.0) # Assign the counter callback to every possible event. event_counter = EventCounter() event_counter.monitor(button_test) event_counter.monitor(panel.background) current_size = (600, 600) - show_manager = window.ShowManager(size=current_size, title='FURY Button') + show_manager = window.ShowManager(size=current_size, title="FURY Button") show_manager.scene.add(panel) # from time import sleep @@ -219,27 +219,27 @@ def _check_property(obj, attr, values): setattr(obj, attr, value) npt.assert_equal(getattr(obj, attr), value) - _check_property(text_block, 'bold', [True, False]) - _check_property(text_block, 'italic', [True, False]) - _check_property(text_block, 'shadow', [True, False]) - _check_property(text_block, 'auto_font_scale', [True, False]) - _check_property(text_block, 'font_size', range(100)) - _check_property(text_block, 'message', ['', 'Hello World', 'Line\nBreak']) - _check_property(text_block, 'justification', ['left', 'center', 'right']) - _check_property(text_block, 'position', [(350, 350), (0.5, 0.5)]) - _check_property(text_block, 'color', [(0.0, 0.5, 1.0)]) - _check_property(text_block, 'background_color', [(0.0, 0.5, 1.0), None]) - _check_property(text_block, 'vertical_justification', ['top', 'middle', 'bottom']) - _check_property(text_block, 'font_family', ['Arial', 'Courier']) + _check_property(text_block, "bold", [True, False]) + _check_property(text_block, "italic", [True, False]) + _check_property(text_block, "shadow", [True, False]) + _check_property(text_block, "auto_font_scale", [True, False]) + _check_property(text_block, "font_size", range(100)) + _check_property(text_block, "message", ["", "Hello World", "Line\nBreak"]) + _check_property(text_block, "justification", ["left", "center", "right"]) + _check_property(text_block, "position", [(350, 350), (0.5, 0.5)]) + _check_property(text_block, "color", [(0.0, 0.5, 1.0)]) + _check_property(text_block, "background_color", [(0.0, 0.5, 1.0), None]) + _check_property(text_block, "vertical_justification", ["top", "middle", "bottom"]) + _check_property(text_block, "font_family", ["Arial", "Courier"]) with npt.assert_raises(ValueError): - text_block.font_family = 'Verdana' + text_block.font_family = "Verdana" with npt.assert_raises(ValueError): - text_block.justification = 'bottom' + text_block.justification = "bottom" with npt.assert_raises(ValueError): - text_block.vertical_justification = 'left' + text_block.vertical_justification = "left" def test_text_block_2d_justification(): @@ -276,103 +276,103 @@ def test_text_block_2d_justification(): texts = [] texts += [ ui.TextBlock2D( - 'HH', + "HH", position=(left, top), font_size=font_size, color=(1, 0, 0), bg_color=bg_color, - justification='left', - vertical_justification='top', + justification="left", + vertical_justification="top", ) ] texts += [ ui.TextBlock2D( - 'HH', + "HH", position=(center, top), font_size=font_size, color=(0, 1, 0), bg_color=bg_color, - justification='center', - vertical_justification='top', + justification="center", + vertical_justification="top", ) ] texts += [ ui.TextBlock2D( - 'HH', + "HH", position=(right, top), font_size=font_size, color=(0, 0, 1), bg_color=bg_color, - justification='right', - vertical_justification='top', + justification="right", + vertical_justification="top", ) ] texts += [ ui.TextBlock2D( - 'HH', + "HH", position=(left, middle), font_size=font_size, color=(1, 1, 0), bg_color=bg_color, - justification='left', - vertical_justification='middle', + justification="left", + vertical_justification="middle", ) ] texts += [ ui.TextBlock2D( - 'HH', + "HH", position=(center, middle), font_size=font_size, color=(0, 1, 1), bg_color=bg_color, - justification='center', - vertical_justification='middle', + justification="center", + vertical_justification="middle", ) ] texts += [ ui.TextBlock2D( - 'HH', + "HH", position=(right, middle), font_size=font_size, color=(1, 0, 1), bg_color=bg_color, - justification='right', - vertical_justification='middle', + justification="right", + vertical_justification="middle", ) ] texts += [ ui.TextBlock2D( - 'HH', + "HH", position=(left, bottom), font_size=font_size, color=(0.5, 0, 1), bg_color=bg_color, - justification='left', - vertical_justification='bottom', + justification="left", + vertical_justification="bottom", ) ] texts += [ ui.TextBlock2D( - 'HH', + "HH", position=(center, bottom), font_size=font_size, color=(1, 0.5, 0), bg_color=bg_color, - justification='center', - vertical_justification='bottom', + justification="center", + vertical_justification="bottom", ) ] texts += [ ui.TextBlock2D( - 'HH', + "HH", position=(right, bottom), font_size=font_size, color=(0, 1, 0.5), bg_color=bg_color, - justification='right', - vertical_justification='bottom', + justification="right", + vertical_justification="bottom", ) ] @@ -385,7 +385,6 @@ def test_text_block_2d_justification(): def test_text_block_2d_size(): - text_block_0 = ui.TextBlock2D() npt.assert_equal(text_block_0.actor.GetTextScaleMode(), 0) @@ -401,23 +400,33 @@ def test_text_block_2d_size(): text_block_1 = ui.TextBlock2D(dynamic_bbox=True) npt.assert_equal(text_block_1.actor.GetTextScaleMode(), 0) - npt.assert_equal(text_block_1.size, ((len("Text Block") * - text_block_1.font_size, text_block_1.font_size))) + npt.assert_equal( + text_block_1.size, + ((len("Text Block") * text_block_1.font_size, text_block_1.font_size)), + ) text_block_1.font_size = 50 - npt.assert_equal(text_block_1.size, (len("Text Block") * - text_block_1.font_size, text_block_1.font_size)) + npt.assert_equal( + text_block_1.size, + (len("Text Block") * text_block_1.font_size, text_block_1.font_size), + ) text_block_1.resize((500, 200)) npt.assert_equal(text_block_1.actor.GetTextScaleMode(), 0) npt.assert_equal(text_block_1.size, (500, 200)) text_block_2 = ui.TextBlock2D( - text="Just Another Text Block", dynamic_bbox=True, auto_font_scale=True) + text="Just Another Text Block", dynamic_bbox=True, auto_font_scale=True + ) npt.assert_equal(text_block_2.actor.GetTextScaleMode(), 1) - npt.assert_equal(text_block_2.size, (len("Just Another Text Block") * - text_block_2.font_size, text_block_2.font_size)) + npt.assert_equal( + text_block_2.size, + ( + len("Just Another Text Block") * text_block_2.font_size, + text_block_2.font_size, + ), + ) text_block_2.resize((500, 200)) npt.assert_equal(text_block_2.actor.GetTextScaleMode(), 1) diff --git a/fury/ui/tests/test_elements.py b/fury/ui/tests/test_elements.py index a37d2ed17..7df1645b1 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -1,18 +1,16 @@ """Test for components module.""" -import itertools + import os from os.path import join as pjoin -import shutil from tempfile import TemporaryDirectory as InTemporaryDirectory import numpy as np import numpy.testing as npt import pytest -from fury import actor, ui, window +from fury import ui, window from fury.data import DATA_DIR -from fury.decorators import skip_osx, skip_win -from fury.primitive import prim_sphere +from fury.decorators import skip_osx from fury.testing import ( EventCounter, assert_arrays_equal, @@ -30,16 +28,16 @@ def test_ui_textbox(recording=False): - filename = 'test_ui_textbox' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_textbox" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") print(recording_filename) # TextBox - textbox_test = ui.TextBox2D(height=3, width=10, text='Text') + textbox_test = ui.TextBox2D(height=3, width=10, text="Text") - another_textbox_test = ui.TextBox2D(height=3, width=10, text='Enter Text') - another_textbox_test.set_message('Enter Text') + another_textbox_test = ui.TextBox2D(height=3, width=10, text="Enter Text") + another_textbox_test.set_message("Enter Text") # Checking whether textbox went out of focus is_off_focused = [False] @@ -55,7 +53,7 @@ def _off_focus(textbox): event_counter.monitor(textbox_test) current_size = (600, 600) - show_manager = window.ShowManager(size=current_size, title='FURY TextBox') + show_manager = window.ShowManager(size=current_size, title="FURY TextBox") show_manager.scene.add(textbox_test) @@ -73,16 +71,16 @@ def _off_focus(textbox): def test_ui_line_slider_2d_horizontal_bottom(recording=False): - filename = 'test_ui_line_slider_2d_horizontal_bottom' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_line_slider_2d_horizontal_bottom" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") line_slider_2d_test = ui.LineSlider2D( initial_value=-2, min_value=-5, max_value=5, - orientation='horizontal', - text_alignment='bottom', + orientation="horizontal", + text_alignment="bottom", ) line_slider_2d_test.center = (300, 300) @@ -92,7 +90,7 @@ def test_ui_line_slider_2d_horizontal_bottom(recording=False): current_size = (600, 600) show_manager = window.ShowManager( - size=current_size, title='FURY Horizontal Line Slider' + size=current_size, title="FURY Horizontal Line Slider" ) show_manager.scene.add(line_slider_2d_test) @@ -109,16 +107,16 @@ def test_ui_line_slider_2d_horizontal_bottom(recording=False): def test_ui_line_slider_2d_horizontal_top(recording=False): - filename = 'test_ui_line_slider_2d_horizontal_top' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_line_slider_2d_horizontal_top" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") line_slider_2d_test = ui.LineSlider2D( initial_value=-2, min_value=-5, max_value=5, - orientation='horizontal', - text_alignment='top', + orientation="horizontal", + text_alignment="top", ) line_slider_2d_test.center = (300, 300) @@ -128,7 +126,7 @@ def test_ui_line_slider_2d_horizontal_top(recording=False): current_size = (600, 600) show_manager = window.ShowManager( - size=current_size, title='FURY Horizontal Line Slider' + size=current_size, title="FURY Horizontal Line Slider" ) show_manager.scene.add(line_slider_2d_test) @@ -145,16 +143,16 @@ def test_ui_line_slider_2d_horizontal_top(recording=False): def test_ui_line_slider_2d_vertical_left(recording=False): - filename = 'test_ui_line_slider_2d_vertical_left' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_line_slider_2d_vertical_left" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") line_slider_2d_test = ui.LineSlider2D( initial_value=-2, min_value=-5, max_value=5, - orientation='vertical', - text_alignment='left', + orientation="vertical", + text_alignment="left", ) line_slider_2d_test.center = (300, 300) @@ -164,7 +162,7 @@ def test_ui_line_slider_2d_vertical_left(recording=False): current_size = (600, 600) show_manager = window.ShowManager( - size=current_size, title='FURY Vertical Line Slider' + size=current_size, title="FURY Vertical Line Slider" ) show_manager.scene.add(line_slider_2d_test) @@ -181,16 +179,16 @@ def test_ui_line_slider_2d_vertical_left(recording=False): def test_ui_line_slider_2d_vertical_right(recording=False): - filename = 'test_ui_line_slider_2d_vertical_right' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_line_slider_2d_vertical_right" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") line_slider_2d_test = ui.LineSlider2D( initial_value=-2, min_value=-5, max_value=5, - orientation='vertical', - text_alignment='right', + orientation="vertical", + text_alignment="right", ) line_slider_2d_test.center = (300, 300) @@ -200,7 +198,7 @@ def test_ui_line_slider_2d_vertical_right(recording=False): current_size = (600, 600) show_manager = window.ShowManager( - size=current_size, title='FURY Vertical Line Slider' + size=current_size, title="FURY Vertical Line Slider" ) show_manager.scene.add(line_slider_2d_test) @@ -219,18 +217,16 @@ def test_ui_line_slider_2d_vertical_right(recording=False): def test_ui_2d_line_slider_hooks(recording=False): global changed, value_changed, slider_moved - filename = 'test_ui_line_slider_2d_hooks' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_line_slider_2d_hooks" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") line_slider_2d = ui.LineSlider2D(center=(300, 300)) event_counter = EventCounter() event_counter.monitor(line_slider_2d) - show_manager = window.ShowManager( - size=(600, 600), - title='FURY Line Slider hooks') + show_manager = window.ShowManager(size=(600, 600), title="FURY Line Slider hooks") # counters for the hooks to increment changed = value_changed = slider_moved = 0 @@ -274,46 +270,31 @@ def on_line_slider_value_changed(slider): def test_ui_line_double_slider_2d(interactive=False): line_double_slider_2d_horizontal_test = ui.LineDoubleSlider2D( center=(300, 300), - shape='disk', + shape="disk", outer_radius=15, min_value=-10, max_value=10, initial_values=(-10, 10), ) - npt.assert_equal( - line_double_slider_2d_horizontal_test.handles[0].size, - (30, 30)) - npt.assert_equal( - line_double_slider_2d_horizontal_test.left_disk_value, - -10 - ) - npt.assert_equal( - line_double_slider_2d_horizontal_test.right_disk_value, - 10 - ) + npt.assert_equal(line_double_slider_2d_horizontal_test.handles[0].size, (30, 30)) + npt.assert_equal(line_double_slider_2d_horizontal_test.left_disk_value, -10) + npt.assert_equal(line_double_slider_2d_horizontal_test.right_disk_value, 10) line_double_slider_2d_vertical_test = ui.LineDoubleSlider2D( center=(300, 300), - shape='disk', + shape="disk", outer_radius=15, min_value=-10, max_value=10, initial_values=(-10, 10), ) - npt.assert_equal( - line_double_slider_2d_vertical_test.handles[0].size, - (30, 30) - ) - npt.assert_equal( - line_double_slider_2d_vertical_test.bottom_disk_value, - -10) - npt.assert_equal( - line_double_slider_2d_vertical_test.top_disk_value, - 10) + npt.assert_equal(line_double_slider_2d_vertical_test.handles[0].size, (30, 30)) + npt.assert_equal(line_double_slider_2d_vertical_test.bottom_disk_value, -10) + npt.assert_equal(line_double_slider_2d_vertical_test.top_disk_value, 10) if interactive: show_manager = window.ShowManager( - size=(600, 600), title='FURY Line Double Slider' + size=(600, 600), title="FURY Line Double Slider" ) show_manager.scene.add(line_double_slider_2d_horizontal_test) show_manager.scene.add(line_double_slider_2d_vertical_test) @@ -321,26 +302,22 @@ def test_ui_line_double_slider_2d(interactive=False): line_double_slider_2d_horizontal_test = ui.LineDoubleSlider2D( center=(300, 300), - shape='square', + shape="square", handle_side=5, - orientation='horizontal', + orientation="horizontal", initial_values=(50, 40), ) - npt.assert_equal( - line_double_slider_2d_horizontal_test.handles[0].size, - (5, 5)) + npt.assert_equal(line_double_slider_2d_horizontal_test.handles[0].size, (5, 5)) npt.assert_equal(line_double_slider_2d_horizontal_test.left_disk_value, 39) - npt.assert_equal( - line_double_slider_2d_horizontal_test.right_disk_value, - 40) + npt.assert_equal(line_double_slider_2d_horizontal_test.right_disk_value, 40) npt.assert_equal(line_double_slider_2d_horizontal_test.left_disk_ratio, 0.39) npt.assert_equal(line_double_slider_2d_horizontal_test.right_disk_ratio, 0.4) line_double_slider_2d_vertical_test = ui.LineDoubleSlider2D( center=(300, 300), - shape='square', + shape="square", handle_side=5, - orientation='vertical', + orientation="vertical", initial_values=(50, 40), ) npt.assert_equal(line_double_slider_2d_vertical_test.handles[0].size, (5, 5)) @@ -350,11 +327,11 @@ def test_ui_line_double_slider_2d(interactive=False): npt.assert_equal(line_double_slider_2d_vertical_test.top_disk_ratio, 0.4) with npt.assert_raises(ValueError): - ui.LineDoubleSlider2D(orientation='Not_hor_not_vert') + ui.LineDoubleSlider2D(orientation="Not_hor_not_vert") if interactive: show_manager = window.ShowManager( - size=(600, 600), title='FURY Line Double Slider' + size=(600, 600), title="FURY Line Double Slider" ) show_manager.scene.add(line_double_slider_2d_horizontal_test) show_manager.scene.add(line_double_slider_2d_vertical_test) @@ -364,9 +341,9 @@ def test_ui_line_double_slider_2d(interactive=False): def test_ui_2d_line_double_slider_hooks(recording=False): global changed, value_changed, slider_moved - filename = 'test_ui_line_double_slider_2d_hooks' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_line_double_slider_2d_hooks" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") line_double_slider_2d = ui.LineDoubleSlider2D(center=(300, 300)) @@ -374,7 +351,7 @@ def test_ui_2d_line_double_slider_hooks(recording=False): event_counter.monitor(line_double_slider_2d) show_manager = window.ShowManager( - size=(600, 600), title='FURY Line Double Slider hooks' + size=(600, 600), title="FURY Line Double Slider hooks" ) # counters for the line double slider's changes @@ -418,9 +395,9 @@ def on_line_double_slider_value_changed(slider): def test_ui_ring_slider_2d(recording=False): - filename = 'test_ui_ring_slider_2d' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_ring_slider_2d" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") ring_slider_2d_test = ui.RingSlider2D() ring_slider_2d_test.center = (300, 300) @@ -431,7 +408,7 @@ def test_ui_ring_slider_2d(recording=False): event_counter.monitor(ring_slider_2d_test) current_size = (600, 600) - show_manager = window.ShowManager(size=current_size, title='FURY Ring Slider') + show_manager = window.ShowManager(size=current_size, title="FURY Ring Slider") show_manager.scene.add(ring_slider_2d_test) @@ -456,16 +433,16 @@ def test_ui_ring_slider_2d(recording=False): def test_ui_2d_ring_slider_hooks(recording=False): global changed, value_changed, slider_moved - filename = 'test_ui_ring_slider_2d_hooks' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_ring_slider_2d_hooks" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") ring_slider_2d = ui.RingSlider2D(center=(300, 300)) event_counter = EventCounter() event_counter.monitor(ring_slider_2d) - show_manager = window.ShowManager(size=(600, 600), title='FURY Ring Slider hooks') + show_manager = window.ShowManager(size=(600, 600), title="FURY Ring Slider hooks") # counters for the ring slider changes changed = value_changed = slider_moved = 0 @@ -507,12 +484,12 @@ def on_ring_slider_value_changed(slider): def test_ui_range_slider(interactive=False): - range_slider_test_horizontal = ui.RangeSlider(shape='square') - range_slider_test_vertical = ui.RangeSlider(shape='square', orientation='vertical') + range_slider_test_horizontal = ui.RangeSlider(shape="square") + range_slider_test_vertical = ui.RangeSlider(shape="square", orientation="vertical") if interactive: show_manager = window.ShowManager( - size=(600, 600), title='FURY Line Double Slider' + size=(600, 600), title="FURY Line Double Slider" ) show_manager.scene.add(range_slider_test_horizontal) show_manager.scene.add(range_slider_test_vertical) @@ -569,7 +546,7 @@ def test_ui_slider_value_range(): def test_ui_option(interactive=False): - option_test = ui.Option(label='option 1', position=(10, 10)) + option_test = ui.Option(label="option 1", position=(10, 10)) npt.assert_equal(option_test.checked, False) @@ -580,14 +557,14 @@ def test_ui_option(interactive=False): def test_ui_checkbox_initial_state(recording=False): - filename = 'test_ui_checkbox_initial_state' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_checkbox_initial_state" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") checkbox_test = ui.Checkbox( - labels=['option 1', 'option 2\nOption 2', 'option 3', 'option 4'], + labels=["option 1", "option 2\nOption 2", "option 3", "option 4"], position=(100, 100), - checked_labels=['option 1', 'option 4'], + checked_labels=["option 1", "option 4"], ) # Collect the sequence of options that have been checked in this list. @@ -603,7 +580,7 @@ def _on_change(checkbox): event_counter.monitor(checkbox_test) # Create a show manager and record/play events. - show_manager = window.ShowManager(size=(600, 600), title='FURY Checkbox') + show_manager = window.ShowManager(size=(600, 600), title="FURY Checkbox") show_manager.scene.add(checkbox_test) if recording: @@ -629,16 +606,16 @@ def _on_change(checkbox): # 10. Click on button of option 3. # Check if the right options were selected. expected = [ - ['option 4'], - ['option 4', 'option 2\nOption 2'], - ['option 4', 'option 2\nOption 2', 'option 1'], - ['option 4', 'option 2\nOption 2', 'option 1', 'option 3'], - ['option 4', 'option 2\nOption 2', 'option 3'], - ['option 2\nOption 2', 'option 3'], - ['option 2\nOption 2', 'option 3', 'option 1'], - ['option 3', 'option 1'], - ['option 3', 'option 1', 'option 4'], - ['option 1', 'option 4'], + ["option 4"], + ["option 4", "option 2\nOption 2"], + ["option 4", "option 2\nOption 2", "option 1"], + ["option 4", "option 2\nOption 2", "option 1", "option 3"], + ["option 4", "option 2\nOption 2", "option 3"], + ["option 2\nOption 2", "option 3"], + ["option 2\nOption 2", "option 3", "option 1"], + ["option 3", "option 1"], + ["option 3", "option 1", "option 4"], + ["option 1", "option 4"], ] npt.assert_equal(len(selected_options), len(expected)) @@ -646,12 +623,12 @@ def _on_change(checkbox): def test_ui_checkbox_default(recording=False): - filename = 'test_ui_checkbox_initial_state' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_checkbox_initial_state" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") checkbox_test = ui.Checkbox( - labels=['option 1', 'option 2\nOption 2', 'option 3', 'option 4'], + labels=["option 1", "option 2\nOption 2", "option 3", "option 4"], position=(10, 10), checked_labels=[], ) @@ -681,7 +658,7 @@ def _on_change(checkbox): event_counter.monitor(checkbox_test) # Create a show manager and record/play events. - show_manager = window.ShowManager(size=(600, 600), title='FURY Checkbox') + show_manager = window.ShowManager(size=(600, 600), title="FURY Checkbox") show_manager.scene.add(checkbox_test) if recording: @@ -707,15 +684,15 @@ def _on_change(checkbox): # Check if the right options were selected. expected = [ - ['option 1'], - ['option 1', 'option 2\nOption 2'], - ['option 2\nOption 2'], - ['option 2\nOption 2', 'option 3'], - ['option 2\nOption 2', 'option 3', 'option 1'], - ['option 2\nOption 2', 'option 3', 'option 1', 'option 4'], - ['option 2\nOption 2', 'option 3', 'option 4'], - ['option 3', 'option 4'], - ['option 3'], + ["option 1"], + ["option 1", "option 2\nOption 2"], + ["option 2\nOption 2"], + ["option 2\nOption 2", "option 3"], + ["option 2\nOption 2", "option 3", "option 1"], + ["option 2\nOption 2", "option 3", "option 1", "option 4"], + ["option 2\nOption 2", "option 3", "option 4"], + ["option 3", "option 4"], + ["option 3"], [], ] npt.assert_equal(len(selected_options), len(expected)) @@ -723,14 +700,14 @@ def _on_change(checkbox): def test_ui_radio_button_initial_state(recording=False): - filename = 'test_ui_radio_button_initial' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_radio_button_initial" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") radio_button_test = ui.RadioButton( - labels=['option 1', 'option 2\nOption 2', 'option 3', 'option 4'], + labels=["option 1", "option 2\nOption 2", "option 3", "option 4"], position=(100, 100), - checked_labels=['option 4'], + checked_labels=["option 4"], ) selected_option = [] @@ -745,7 +722,7 @@ def _on_change(radio_button): event_counter.monitor(radio_button_test) # Create a show manager and record/play events. - show_manager = window.ShowManager(size=(600, 600), title='FURY Checkbox') + show_manager = window.ShowManager(size=(600, 600), title="FURY Checkbox") show_manager.scene.add(radio_button_test) if recording: show_manager.record_events_to_file(recording_filename) @@ -767,26 +744,26 @@ def _on_change(radio_button): # Check if the right options were selected. expected = [ - ['option 1'], - ['option 2\nOption 2'], - ['option 2\nOption 2'], - ['option 2\nOption 2'], - ['option 1'], - ['option 3'], - ['option 4'], - ['option 4'], + ["option 1"], + ["option 2\nOption 2"], + ["option 2\nOption 2"], + ["option 2\nOption 2"], + ["option 1"], + ["option 3"], + ["option 4"], + ["option 4"], ] npt.assert_equal(len(selected_option), len(expected)) assert_arrays_equal(selected_option, expected) def test_ui_radio_button_default(recording=False): - filename = 'test_ui_radio_button_initial' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_radio_button_initial" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") radio_button_test = ui.RadioButton( - labels=['option 1', 'option 2\nOption 2', 'option 3', 'option 4'], + labels=["option 1", "option 2\nOption 2", "option 3", "option 4"], position=(10, 10), checked_labels=[], ) @@ -814,7 +791,7 @@ def _on_change(radio_button): event_counter.monitor(radio_button_test) # Create a show manager and record/play events. - show_manager = window.ShowManager(size=(600, 600), title='FURY Checkbox') + show_manager = window.ShowManager(size=(600, 600), title="FURY Checkbox") show_manager.scene.add(radio_button_test) if recording: show_manager.record_events_to_file(recording_filename) @@ -836,14 +813,14 @@ def _on_change(radio_button): # Check if the right options were selected. expected = [ - ['option 1'], - ['option 2\nOption 2'], - ['option 2\nOption 2'], - ['option 2\nOption 2'], - ['option 1'], - ['option 3'], - ['option 4'], - ['option 4'], + ["option 1"], + ["option 2\nOption 2"], + ["option 2\nOption 2"], + ["option 2\nOption 2"], + ["option 1"], + ["option 3"], + ["option 4"], + ["option 4"], ] npt.assert_equal(len(selected_option), len(expected)) assert_arrays_equal(selected_option, expected) @@ -853,22 +830,22 @@ def test_multiple_radio_button_pre_selected(): npt.assert_raises( ValueError, ui.RadioButton, - labels=['option 1', 'option 2\nOption 2', 'option 3', 'option 4'], - checked_labels=['option 1', 'option 4'], + labels=["option 1", "option 2\nOption 2", "option 3", "option 4"], + checked_labels=["option 1", "option 4"], ) @pytest.mark.skipif( - True, reason='Need investigation. Incorrect ' 'number of event for each vtk version' + True, reason="Need investigation. Incorrect " "number of event for each vtk version" ) def test_ui_listbox_2d(interactive=False): - filename = 'test_ui_listbox_2d' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_listbox_2d" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") # Values that will be displayed by the listbox. values = list(range(1, 42 + 1)) - values.append('A Very Very Long Item To Test Text Overflow of List Box 2D') + values.append("A Very Very Long Item To Test Text Overflow of List Box 2D") if interactive: listbox = ui.ListBox2D( @@ -881,7 +858,7 @@ def test_ui_listbox_2d(interactive=False): listbox.center = (300, 300) listbox.panel.opacity = 0.2 - show_manager = window.ShowManager(size=(600, 600), title='FURY ListBox') + show_manager = window.ShowManager(size=(600, 600), title="FURY ListBox") show_manager.scene.add(listbox) show_manager.start() @@ -915,7 +892,7 @@ def _on_change(): event_counter = EventCounter() event_counter.monitor(listbox) - show_manager = window.ShowManager(size=(600, 600), title='FURY ListBox') + show_manager = window.ShowManager(size=(600, 600), title="FURY ListBox") show_manager.scene.add(listbox) show_manager.play_events_from_file(recording_filename) expected = EventCounter.load(expected_events_counts_filename) @@ -927,8 +904,8 @@ def _on_change(): [1, 2], [1], [ - 'A Very Very Long Item To \ -Test Text Overflow of List Box 2D' + "A Very Very Long Item To \ +Test Text Overflow of List Box 2D" ], [1], values, @@ -947,13 +924,13 @@ def _on_change(): [2], [2], [ - 'A Very Very Long Item To \ -Test Text Overflow of List Box 2D' + "A Very Very Long Item To \ +Test Text Overflow of List Box 2D" ], [1], [ - 'A Very Very Long Item To Test \ -Text Overflow of List Box 2D' + "A Very Very Long Item To Test \ +Text Overflow of List Box 2D" ], ] npt.assert_equal(len(selected_values), len(expected)) @@ -962,12 +939,12 @@ def _on_change(): def test_ui_listbox_2d_visibility(): l1 = ui.ListBox2D( - values=['Violet', 'Indigo', 'Blue', 'Yellow'], + values=["Violet", "Indigo", "Blue", "Yellow"], position=(12, 10), size=(100, 100), ) l2 = ui.ListBox2D( - values=['Violet', 'Indigo', 'Blue', 'Yellow'], + values=["Violet", "Indigo", "Blue", "Yellow"], position=(10, 10), size=(100, 300), ) @@ -985,19 +962,19 @@ def assert_listbox(list_box, expected_scroll_bar_height): def test_ui_file_menu_2d(interactive=False): - filename = 'test_ui_file_menu_2d' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_file_menu_2d" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") with InTemporaryDirectory() as tmpdir: - test_dir = os.path.join(tmpdir, 'testdir') - os.makedirs(os.path.join(test_dir, 'tempdir')) + test_dir = os.path.join(tmpdir, "testdir") + os.makedirs(os.path.join(test_dir, "tempdir")) for i in range(10): - open(os.path.join(test_dir, 'tempdir', f'test{i}.txt'), 'wt').close() - open(os.path.join(test_dir, 'testfile.txt'), 'wt').close() + open(os.path.join(test_dir, "tempdir", f"test{i}.txt"), "wt").close() + open(os.path.join(test_dir, "testfile.txt"), "wt").close() filemenu = ui.FileMenu2D( - size=(500, 500), extensions=['txt'], directory_path=test_dir + size=(500, 500), extensions=["txt"], directory_path=test_dir ) # We will collect the sequence of files that have been selected. @@ -1014,7 +991,7 @@ def _on_change(): event_counter.monitor(filemenu) # Create a show manager and record/play events. - show_manager = window.ShowManager(size=(600, 600), title='FURY FileMenu') + show_manager = window.ShowManager(size=(600, 600), title="FURY FileMenu") show_manager.scene.add(filemenu) # Recorded events: @@ -1030,38 +1007,38 @@ def _on_change(): # Check if the right files were selected. expected = [ - ['testfile.txt'], - ['tempdir'], - ['test0.txt'], + ["testfile.txt"], + ["tempdir"], + ["test0.txt"], [ - 'test0.txt', - 'test1.txt', - 'test2.txt', - 'test3.txt', - 'test4.txt', - 'test5.txt', - 'test6.txt', + "test0.txt", + "test1.txt", + "test2.txt", + "test3.txt", + "test4.txt", + "test5.txt", + "test6.txt", ], - ['../'], - ['testfile.txt'], + ["../"], + ["testfile.txt"], ] npt.assert_equal(len(selected_files), len(expected)) assert_arrays_equal(selected_files, expected) if interactive: filemenu = ui.FileMenu2D(size=(500, 500), directory_path=os.getcwd()) - show_manager = window.ShowManager(size=(600, 600), title='FURY FileMenu') + show_manager = window.ShowManager(size=(600, 600), title="FURY FileMenu") show_manager.scene.add(filemenu) show_manager.start() def test_ui_combobox_2d(interactive=False): - filename = 'test_ui_combobox_2d' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_combobox_2d" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") - values = ['An Item' + str(i) for i in range(0, 5)] - new_values = ['An Item5', 'An Item6'] + values = ["An Item" + str(i) for i in range(0, 5)] + new_values = ["An Item5", "An Item6"] combobox = ui.ComboBox2D(items=values, position=(400, 400), size=(300, 200)) @@ -1070,20 +1047,20 @@ def test_ui_combobox_2d(interactive=False): event_counter.monitor(combobox) current_size = (800, 800) - show_manager = window.ShowManager(size=current_size, title='ComboBox UI Example') + show_manager = window.ShowManager(size=current_size, title="ComboBox UI Example") show_manager.scene.add(combobox) values.extend(new_values) combobox.append_item(*new_values) npt.assert_equal(values, combobox.items) - values.append('An Item7') - combobox.append_item('An Item7') + values.append("An Item7") + combobox.append_item("An Item7") npt.assert_equal(values, combobox.items) - values.append('An Item8') - values.append('An Item9') - combobox.append_item('An Item8', 'An Item9') + values.append("An Item8") + values.append("An Item9") + combobox.append_item("An Item8", "An Item9") npt.assert_equal(values, combobox.items) complex_list = [[0], (1, [[2, 3], 4], 5)] @@ -1091,7 +1068,7 @@ def test_ui_combobox_2d(interactive=False): values.extend([str(i) for i in range(6)]) npt.assert_equal(values, combobox.items) - invalid_item = {'Hello': 1, 'World': 2} + invalid_item = {"Hello": 1, "World": 2} npt.assert_raises(TypeError, combobox.append_item, invalid_item) npt.assert_equal(values, combobox.items) @@ -1111,7 +1088,7 @@ def test_ui_combobox_2d(interactive=False): expected = EventCounter.load(expected_events_counts_filename) event_counter.check_counts(expected) - npt.assert_equal('An Item1', combobox.selected_text) + npt.assert_equal("An Item1", combobox.selected_text) npt.assert_equal(1, combobox.selected_text_index) combobox.resize((450, 300)) @@ -1121,14 +1098,10 @@ def test_ui_combobox_2d(interactive=False): def test_ui_combobox_2d_dropdown_visibility(interactive=False): - - values = ['An Item' + str(i) for i in range(0, 5)] + values = ["An Item" + str(i) for i in range(0, 5)] tab_ui = ui.TabUI(position=(49, 94), size=(400, 400), nb_tabs=1, draggable=True) - combobox = ui.ComboBox2D( - items=values, - position=(400, 400), size=(300, 200) - ) + combobox = ui.ComboBox2D(items=values, position=(400, 400), size=(300, 200)) tab_ui.add_element(0, combobox, (0.1, 0.3)) @@ -1138,40 +1111,28 @@ def test_ui_combobox_2d_dropdown_visibility(interactive=False): event_counter.monitor(tab_ui) current_size = (800, 800) - show_manager = window.ShowManager(size=current_size, title='ComboBox UI Example') + show_manager = window.ShowManager(size=current_size, title="ComboBox UI Example") show_manager.scene.add(tab_ui) tab_ui.tabs[0].content_panel.set_visibility(True) npt.assert_equal(False, combobox._menu_visibility) - npt.assert_equal( - False, - combobox.drop_down_menu.panel.actors[0].GetVisibility() - ) + npt.assert_equal(False, combobox.drop_down_menu.panel.actors[0].GetVisibility()) npt.assert_equal(0, combobox.drop_down_button.current_icon_id) npt.assert_equal(True, combobox.drop_down_button.actors[0].GetVisibility()) npt.assert_equal(True, combobox.selection_box.actors[0].GetVisibility()) tab_ui.tabs[0].content_panel.set_visibility(False) npt.assert_equal(False, combobox._menu_visibility) - npt.assert_equal( - False, - combobox.drop_down_menu.panel.actors[0].GetVisibility() - ) + npt.assert_equal(False, combobox.drop_down_menu.panel.actors[0].GetVisibility()) npt.assert_equal(0, combobox.drop_down_button.current_icon_id) - npt.assert_equal( - False, - combobox.drop_down_button.actors[0].GetVisibility() - ) + npt.assert_equal(False, combobox.drop_down_button.actors[0].GetVisibility()) npt.assert_equal(False, combobox.selection_box.actors[0].GetVisibility()) iren = show_manager.scene.GetRenderWindow().GetInteractor().GetInteractorStyle() combobox.menu_toggle_callback(iren, None, None) tab_ui.tabs[0].content_panel.set_visibility(True) npt.assert_equal(True, combobox._menu_visibility) - npt.assert_equal( - True, - combobox.drop_down_menu.panel.actors[0].GetVisibility() - ) + npt.assert_equal(True, combobox.drop_down_menu.panel.actors[0].GetVisibility()) npt.assert_equal(1, combobox.drop_down_button.current_icon_id) npt.assert_equal(True, combobox.drop_down_button.actors[0].GetVisibility()) npt.assert_equal(True, combobox.selection_box.actors[0].GetVisibility()) @@ -1179,22 +1140,22 @@ def test_ui_combobox_2d_dropdown_visibility(interactive=False): @pytest.mark.skipif( skip_osx, - reason='This test does not work on macOS.' - 'It works on the local machines.' - 'The colors provided for shapes are ' - 'normalized values whereas when we test' - 'it, the values returned are between ' - '0-255. So while conversion from one' - 'representation to another, there may be' - 'something which causes these issues.', + reason="This test does not work on macOS." + "It works on the local machines." + "The colors provided for shapes are " + "normalized values whereas when we test" + "it, the values returned are between " + "0-255. So while conversion from one" + "representation to another, there may be" + "something which causes these issues.", ) def test_ui_draw_shape(): - line = ui.DrawShape(shape_type='line', position=(150, 150)) - quad = ui.DrawShape(shape_type='quad', position=(300, 300)) - circle = ui.DrawShape(shape_type='circle', position=(150, 300)) + line = ui.DrawShape(shape_type="line", position=(150, 150)) + quad = ui.DrawShape(shape_type="quad", position=(300, 300)) + circle = ui.DrawShape(shape_type="circle", position=(150, 300)) with npt.assert_raises(IOError): - ui.DrawShape('poly') + ui.DrawShape("poly") line.resize((100, 5)) line.shape.color = (0, 1, 0) @@ -1203,14 +1164,14 @@ def test_ui_draw_shape(): circle.resize((25, 0)) circle.shape.color = (0, 0, 1) - line_color = np.round(255 * np.array(line.shape.color)).astype('uint8') - quad_color = np.round(255 * np.array(quad.shape.color)).astype('uint8') - circle_color = np.round(255 * np.array(circle.shape.color)).astype('uint8') + line_color = np.round(255 * np.array(line.shape.color)).astype("uint8") + quad_color = np.round(255 * np.array(quad.shape.color)).astype("uint8") + circle_color = np.round(255 * np.array(circle.shape.color)).astype("uint8") current_size = (900, 900) scene = window.Scene() show_manager = window.ShowManager( - scene, size=current_size, title='DrawShape UI Example' + scene, size=current_size, title="DrawShape UI Example" ) scene.add(line, circle, quad) @@ -1223,9 +1184,9 @@ def test_ui_draw_shape(): def test_ui_draw_panel_basic(interactive=False): - filename = 'test_ui_draw_panel_basic' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_draw_panel_basic" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") drawpanel = ui.DrawPanel(size=(600, 600), position=(30, 10)) @@ -1235,7 +1196,7 @@ def test_ui_draw_panel_basic(interactive=False): current_size = (680, 680) show_manager = window.ShowManager( - size=current_size, title='DrawPanel Basic UI Example' + size=current_size, title="DrawPanel Basic UI Example" ) show_manager.scene.add(drawpanel) @@ -1256,9 +1217,9 @@ def test_ui_draw_panel_basic(interactive=False): def test_ui_draw_panel_rotation(interactive=False): - filename = 'test_ui_draw_panel_rotation' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_ui_draw_panel_rotation" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") drawpanel = ui.DrawPanel(size=(600, 600), position=(30, 10)) @@ -1268,7 +1229,7 @@ def test_ui_draw_panel_rotation(interactive=False): current_size = (680, 680) show_manager = window.ShowManager( - size=current_size, title='DrawPanel Rotation UI Example' + size=current_size, title="DrawPanel Rotation UI Example" ) show_manager.scene.add(drawpanel) @@ -1294,12 +1255,12 @@ def test_playback_panel(interactive=False): current_size = (900, 620) show_manager = window.ShowManager( - size=current_size, title='PlaybackPanel UI Example' + size=current_size, title="PlaybackPanel UI Example" ) - filename = 'test_playback_panel' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_playback_panel" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") def play(): global playing @@ -1349,10 +1310,10 @@ def change_t(value): assert_true(stopped) assert_equal(playback.current_time, ts) assert_greater(playback.current_time, 0) - assert_not_equal(playback.current_time_str, '00:00.00') + assert_not_equal(playback.current_time_str, "00:00.00") playback.current_time = 5 assert_equal(playback.current_time, 5) - assert_equal(playback.current_time_str, '00:05.00') + assert_equal(playback.current_time_str, "00:05.00") # test show/hide playback.show() ss = window.snapshot(show_manager.scene) @@ -1363,20 +1324,28 @@ def change_t(value): def test_card_ui(interactive=False): - filename = 'test_card_ui' - recording_filename = pjoin(DATA_DIR, filename + '.log.gz') - expected_events_counts_filename = pjoin(DATA_DIR, filename + '.json') + filename = "test_card_ui" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") - img_url = "https://raw.githubusercontent.com/fury-gl"\ - "/fury-communication-assets/main/fury-logo.png" + img_url = ( + "https://raw.githubusercontent.com/fury-gl" + "/fury-communication-assets/main/fury-logo.png" + ) title = "FURY" - body = "FURY - Free Unified Rendering in pYthon."\ - "A software library for scientific visualization in Python." + body = ( + "FURY - Free Unified Rendering in pYthon." + "A software library for scientific visualization in Python." + ) - card = ui.elements.Card2D(image_path=img_url, draggable=True, - title_text=title, body_text=body, - image_scale=0.5) + card = ui.elements.Card2D( + image_path=img_url, + draggable=True, + title_text=title, + body_text=body, + image_scale=0.5, + ) # Assign the counter callback to every possible event. @@ -1390,11 +1359,11 @@ def test_card_ui(interactive=False): npt.assert_equal(card.color, (0.5, 0.5, 0.5)) npt.assert_equal(card.panel.position, (0, 0)) - card.title = 'Changed Title' - npt.assert_equal(card.title, 'Changed Title') + card.title = "Changed Title" + npt.assert_equal(card.title, "Changed Title") - card.body = 'Changed Body' - npt.assert_equal(card.body, 'Changed Body') + card.body = "Changed Body" + npt.assert_equal(card.body, "Changed Body") card.title = title card.body = body @@ -1404,7 +1373,7 @@ def test_card_ui(interactive=False): card.resize((300, 300)) npt.assert_equal(card.image.size[1], 150.0) current_size = (600, 600) - show_manager = window.ShowManager(size=current_size, title='FURY Card') + show_manager = window.ShowManager(size=current_size, title="FURY Card") show_manager.scene.add(card) if interactive: @@ -1447,9 +1416,7 @@ def test_ui_spinbox(interactive=False): event_counter.monitor(spinbox) current_size = (800, 800) - show_manager = window.ShowManager( - size=current_size, - title="SpinBox UI Example") + show_manager = window.ShowManager(size=current_size, title="SpinBox UI Example") show_manager.scene.add(spinbox) if interactive: diff --git a/fury/ui/tests/test_elements_callback.py b/fury/ui/tests/test_elements_callback.py index 3a5503ff0..89c6aa506 100644 --- a/fury/ui/tests/test_elements_callback.py +++ b/fury/ui/tests/test_elements_callback.py @@ -1,19 +1,15 @@ """Test for components module.""" + import itertools -import os -from os.path import join as pjoin -import shutil -from tempfile import TemporaryDirectory as InTemporaryDirectory import numpy as np import numpy.testing as npt import pytest from fury import actor, ui, window -from fury.data import DATA_DIR from fury.decorators import skip_osx, skip_win from fury.primitive import prim_sphere -from fury.testing import EventCounter, assert_arrays_equal, assert_greater +from fury.testing import assert_greater def test_frame_rate_and_anti_aliasing(): @@ -79,7 +75,7 @@ def timer_callback(_obj, _event): if cnt % 1 == 0: fps = np.round(showm.frame_rate, 0) frh.fpss.append(fps) - msg = 'FPS ' + str(fps) + ' ' + str(cnt) + msg = "FPS " + str(fps) + " " + str(cnt) tb.message = msg showm.render() if cnt > 10: @@ -135,9 +131,9 @@ def timer_callback(_obj, _event): @pytest.mark.skipif( skip_win, - reason='This test does not work on windows. It ' - 'works on a local machine. Check after ' - 'fixing memory leak with RenderWindow.', + reason="This test does not work on windows. It " + "works on a local machine. Check after " + "fixing memory leak with RenderWindow.", ) def test_timer(): """Testing add a timer and exit window and app from inside timer.""" @@ -149,14 +145,14 @@ def test_timer(): sphere_actor = actor.sphere(centers=xyzr[:, :3], colors=colors[:], radii=xyzr[:, 3]) - vertices, faces = prim_sphere('repulsion724') + vertices, faces = prim_sphere("repulsion724") sphere_actor2 = actor.sphere( centers=xyzr2[:, :3], colors=colors[:], radii=xyzr2[:, 3], vertices=vertices, - faces=faces.astype('i8'), + faces=faces.astype("i8"), ) scene.add(sphere_actor) diff --git a/fury/ui/tests/test_helpers.py b/fury/ui/tests/test_helpers.py index fbf3bde13..039d28d83 100644 --- a/fury/ui/tests/test_helpers.py +++ b/fury/ui/tests/test_helpers.py @@ -1,4 +1,5 @@ """Test helpers function .""" + import numpy as np import numpy.testing as npt @@ -13,88 +14,93 @@ def test_clip_overflow(): - text = ui.TextBlock2D(text='', position=(50, 50), color=(1, 0, 0), size=(100, 50)) + text = ui.TextBlock2D(text="", position=(50, 50), color=(1, 0, 0), size=(100, 50)) sm = window.ShowManager() sm.scene.add(text) - text.message = 'Hello' + text.message = "Hello" clip_overflow(text, text.size[0]) - npt.assert_equal('Hello', text.message) + npt.assert_equal("Hello", text.message) text.message = "Hello what's up?" clip_overflow(text, text.size[0]) - npt.assert_equal('He...', text.message) + npt.assert_equal("He...", text.message) - text.message = 'A very very long message to clip text overflow' + text.message = "A very very long message to clip text overflow" clip_overflow(text, text.size[0]) - npt.assert_equal('A ...', text.message) + npt.assert_equal("A ...", text.message) - text.message = 'Hello' - clip_overflow(text, text.size[0], 'left') - npt.assert_equal('Hello', text.message) + text.message = "Hello" + clip_overflow(text, text.size[0], "left") + npt.assert_equal("Hello", text.message) - text.message = 'Hello wassup' - clip_overflow(text, text.size[0], 'left') - npt.assert_equal('...up', text.message) + text.message = "Hello wassup" + clip_overflow(text, text.size[0], "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') - npt.assert_equal('...ow', text.message) + text.message = "A very very long message to clip text overflow" + clip_overflow(text, text.size[0], "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') - npt.assert_equal('...ow', text.message) + text.message = "A very very long message to clip text overflow" + clip_overflow(text, text.size[0], "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') - npt.assert_equal('A ...', text.message) + text.message = "A very very long message to clip text overflow" + clip_overflow(text, text.size[0], "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], "middle") def test_wrap_overflow(): - text = ui.TextBlock2D(text='', position=(50, 50), color=(1, 0, 0), size=(100, 50)) + text = ui.TextBlock2D(text="", position=(50, 50), color=(1, 0, 0), size=(100, 50)) sm = window.ShowManager() sm.scene.add(text) - text.message = 'Hello' + text.message = "Hello" wrap_overflow(text, text.size[0]) - npt.assert_equal('Hello', text.message) + npt.assert_equal("Hello", text.message) text.message = "Hello what's up?" wrap_overflow(text, text.size[0]) npt.assert_equal("Hello\n what\n's up\n?", text.message) - text.message = 'A very very long message to clip text overflow' + text.message = "A very very long message to clip text overflow" wrap_overflow(text, text.size[0]) npt.assert_equal( - 'A ver\ny ver\ny lon\ng mes\nsage \nto cl\nip te\nxt ov\nerflo\nw', text.message + "A ver\ny ver\ny lon\ng mes\nsage \nto cl\nip te\nxt ov\nerflo\nw", text.message ) - text.message = 'A very very long message to clip text overflow' + text.message = "A very very long message to clip text overflow" wrap_overflow(text, 0) - npt.assert_equal(text.message, '') + npt.assert_equal(text.message, "") - text.message = 'A very very long message to clip text overflow' + text.message = "A very very long message to clip text overflow" wrap_overflow(text, -2 * text.size[0]) - npt.assert_equal(text.message, '') + npt.assert_equal(text.message, "") def test_check_overflow(): - text = ui.TextBlock2D(text='', position=(50, 50), - color=(1, 0, 0), size=(100, 50), bg_color=(.5, .5, .5)) + text = ui.TextBlock2D( + text="", + position=(50, 50), + color=(1, 0, 0), + size=(100, 50), + bg_color=(0.5, 0.5, 0.5), + ) sm = window.ShowManager() sm.scene.add(text) - text.message = 'A very very long message to clip text overflow' + text.message = "A very very long message to clip text overflow" - overflow_idx = check_overflow(text, 100, '~') + overflow_idx = check_overflow(text, 100, "~") npt.assert_equal(4, overflow_idx) - npt.assert_equal('A ve~', text.message) + npt.assert_equal("A ve~", text.message) def test_cal_bounding_box_2d(): @@ -134,8 +140,8 @@ def test_rotate_2d(): new_vertices = rotate_2d(vertices, np.deg2rad(90)) npt.assert_equal( - np.array([[-1.0, 1.0, 0.0], [-10.0, 10.0, 0.0]], dtype='float32'), - new_vertices.astype('float32'), + np.array([[-1.0, 1.0, 0.0], [-10.0, 10.0, 0.0]], dtype="float32"), + new_vertices.astype("float32"), ) with npt.assert_raises(IOError): diff --git a/fury/utils.py b/fury/utils.py index 405a4af53..12aeb2214 100644 --- a/fury/utils.py +++ b/fury/utils.py @@ -34,12 +34,12 @@ def remove_observer_from_actor(actor, id): id of the observer to remove """ - if not hasattr(actor, 'GetMapper'): - raise ValueError('Invalid actor') + if not hasattr(actor, "GetMapper"): + raise ValueError("Invalid actor") mapper = actor.GetMapper() - if not hasattr(mapper, 'RemoveObserver'): - raise ValueError('Invalid mapper') + if not hasattr(mapper, "RemoveObserver"): + raise ValueError("Invalid mapper") mapper.RemoveObserver(id) @@ -83,11 +83,7 @@ def numpy_to_vtk_points(points): """ vtk_points = Points() - vtk_points.SetData( - numpy_support.numpy_to_vtk( - np.asarray(points), - deep=True) - ) + vtk_points.SetData(numpy_support.numpy_to_vtk(np.asarray(points), deep=True)) return vtk_points @@ -140,7 +136,7 @@ def numpy_to_vtk_cells(data, is_coords=True): offsets_dtype = np.int64 else: offsets_dtype = np.dtype(data._offsets.dtype) - if offsets_dtype.kind == 'u': + if offsets_dtype.kind == "u": offsets_dtype = np.dtype(offsets_dtype.name[1:]) data = np.array(data, dtype=object) nb_cells = len(data) @@ -168,14 +164,8 @@ def numpy_to_vtk_cells(data, is_coords=True): vtk_array_type = numpy_support.get_vtk_array_type(offsets_dtype) cell_array.SetData( - numpy_support.numpy_to_vtk( - offset, - deep=True, - array_type=vtk_array_type), - numpy_support.numpy_to_vtk( - connectivity, - deep=True, - array_type=vtk_array_type), + numpy_support.numpy_to_vtk(offset, deep=True, array_type=vtk_array_type), + numpy_support.numpy_to_vtk(connectivity, deep=True, array_type=vtk_array_type), ) cell_array.SetNumberOfCells(nb_cells) @@ -204,7 +194,7 @@ def numpy_to_vtk_image_data( """ if array.ndim not in [2, 3]: - raise IOError('only 2D (L, RGB, RGBA) or 3D image available') + raise IOError("only 2D (L, RGB, RGBA) or 3D image available") vtk_image = ImageData() depth = 1 if array.ndim == 2 else array.shape[2] @@ -240,7 +230,7 @@ def map_coordinates_3d_4d(input_array, indices): """ if input_array.ndim <= 2 or input_array.ndim >= 5: - raise ValueError('Input array can only be 3d or 4d') + raise ValueError("Input array can only be 3d or 4d") if input_array.ndim == 3: return map_coordinates(input_array, indices.T, order=1) @@ -248,10 +238,7 @@ def map_coordinates_3d_4d(input_array, indices): if input_array.ndim == 4: values_4d = [] for i in range(input_array.shape[-1]): - values_tmp = map_coordinates( - input_array[..., i], - indices.T, - order=1) + values_tmp = map_coordinates(input_array[..., i], indices.T, order=1) values_4d.append(values_tmp) return np.ascontiguousarray(np.array(values_4d).T) @@ -292,13 +279,13 @@ def lines_to_vtk_polydata(lines, colors=None): """ # Get the 3d points_array - if lines.__class__.__name__ == 'ArraySequence': + if lines.__class__.__name__ == "ArraySequence": points_array = lines._data else: points_array = np.vstack(lines) if points_array.size == 0: - raise ValueError('Empty lines/streamlines data.') + raise ValueError("Empty lines/streamlines data.") # Set Points to vtk array format vtk_points = numpy_to_vtk_points(points_array) @@ -333,10 +320,7 @@ def lines_to_vtk_polydata(lines, colors=None): else: if len(cols_arr) == nb_points: if cols_arr.ndim == 1: # values for every point - vtk_colors = numpy_support.numpy_to_vtk( - cols_arr, - deep=True - ) + vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) color_is_scalar = True elif cols_arr.ndim == 2: # map color to each point vtk_colors = numpy_to_vtk_colors(255 * cols_arr) @@ -344,13 +328,10 @@ def lines_to_vtk_polydata(lines, colors=None): elif cols_arr.ndim == 1: if len(cols_arr) == nb_lines: # values for every streamline cols_arrx = [] - for (i, value) in enumerate(colors): + for i, value in enumerate(colors): cols_arrx += lines[i].shape[0] * [value] cols_arrx = np.array(cols_arrx) - vtk_colors = numpy_support.numpy_to_vtk( - cols_arrx, - deep=True - ) + vtk_colors = numpy_support.numpy_to_vtk(cols_arrx, deep=True) color_is_scalar = True else: # the same colors for all points vtk_colors = numpy_to_vtk_colors( @@ -358,24 +339,15 @@ def lines_to_vtk_polydata(lines, colors=None): ) elif cols_arr.ndim == 2: # map color to each line - colors_mapper = np.repeat( - lines_range, - points_per_line, - axis=0 - ) - vtk_colors = numpy_to_vtk_colors( - 255 * cols_arr[colors_mapper] - ) + colors_mapper = np.repeat(lines_range, points_per_line, axis=0) + vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) else: # colormap # get colors for each vertex cols_arr = map_coordinates_3d_4d(cols_arr, points_array) - vtk_colors = numpy_support.numpy_to_vtk( - cols_arr, - deep=True - ) + vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) color_is_scalar = True - vtk_colors.SetName('colors') + vtk_colors.SetName("colors") poly_data.GetPointData().SetScalars(vtk_colors) return poly_data, color_is_scalar @@ -394,9 +366,7 @@ def get_polydata_lines(line_polydata): List of N curves represented as 2D ndarrays """ - lines_vertices = numpy_support.vtk_to_numpy( - line_polydata.GetPoints().GetData() - ) + lines_vertices = numpy_support.vtk_to_numpy(line_polydata.GetPoints().GetData()) lines_idx = numpy_support.vtk_to_numpy(line_polydata.GetLines().GetData()) lines = [] @@ -405,7 +375,7 @@ def get_polydata_lines(line_polydata): line_len = lines_idx[current_idx] next_idx = current_idx + line_len + 1 - line_range = lines_idx[current_idx + 1: next_idx] + line_range = lines_idx[current_idx + 1 : next_idx] lines += [lines_vertices[line_range]] current_idx = next_idx @@ -428,7 +398,7 @@ def get_polydata_triangles(polydata): vtk_polys = numpy_support.vtk_to_numpy(polydata.GetPolys().GetData()) # test if its really triangles if not (vtk_polys[::4] == 3).all(): - raise AssertionError('Shape error: this is not triangles') + raise AssertionError("Shape error: this is not triangles") return np.vstack([vtk_polys[1::4], vtk_polys[2::4], vtk_polys[3::4]]).T @@ -556,12 +526,7 @@ 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 - ): +def add_polydata_numeric_field(polydata, field_name, field_data, array_type=VTK_INT): """Add a field to a vtk polydata. Parameters @@ -590,7 +555,7 @@ def set_polydata_primitives_count(polydata, primitives_count): """ add_polydata_numeric_field( - polydata, 'prim_count', primitives_count, array_type=VTK_INT + polydata, "prim_count", primitives_count, array_type=VTK_INT ) @@ -606,7 +571,7 @@ def get_polydata_primitives_count(polydata): primitives count : int """ - return get_polydata_field(polydata, 'prim_count')[0] + return get_polydata_field(polydata, "prim_count")[0] def primitives_count_to_actor(actor, primitives_count): @@ -681,7 +646,7 @@ def set_polydata_normals(polydata, normals): vtk_normals = numpy_support.numpy_to_vtk(normals, deep=True) # VTK does not require a specific name for the normals array, however, for # readability purposes, we set it to "Normals" - vtk_normals.SetName('Normals') + vtk_normals.SetName("Normals") polydata.GetPointData().SetNormals(vtk_normals) return polydata @@ -695,19 +660,15 @@ def set_polydata_tangents(polydata, tangents): tangents : tangents, represented as 2D ndarrays (Nx3) (one per vertex) """ - vtk_tangents = numpy_support.numpy_to_vtk( - tangents, - deep=True, - array_type=VTK_FLOAT - ) + vtk_tangents = numpy_support.numpy_to_vtk(tangents, deep=True, array_type=VTK_FLOAT) # VTK does not require a specific name for the tangents array, however, for # readability purposes, we set it to "Tangents" - vtk_tangents.SetName('Tangents') + vtk_tangents.SetName("Tangents") polydata.GetPointData().SetTangents(vtk_tangents) return polydata -def set_polydata_colors(polydata, colors, array_name='colors'): +def set_polydata_colors(polydata, colors, array_name="colors"): """Set polydata colors with a numpy array (ndarrays Nx3 int). Parameters @@ -738,11 +699,7 @@ def set_polydata_tcoords(polydata, tcoords): (one per vertex range (0, 1)) """ - vtk_tcoords = numpy_support.numpy_to_vtk( - tcoords, - deep=True, - array_type=VTK_FLOAT - ) + vtk_tcoords = numpy_support.numpy_to_vtk(tcoords, deep=True, array_type=VTK_FLOAT) polydata.GetPointData().SetTCoords(vtk_tcoords) return polydata @@ -825,12 +782,7 @@ def get_actor_from_polydata(polydata): 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. @@ -864,13 +816,13 @@ def get_actor_from_primitive( set_polydata_primitives_count(pd, prim_count) if isinstance(colors, np.ndarray): if len(colors) != len(vertices): - msg = 'Vertices and Colors should have the same size.' - msg += ' Please, update your color array or use the function ' - msg += '``fury.primitive.repeat_primitives`` to normalize your ' - msg += 'color array before calling this function. e.g.' + msg = "Vertices and Colors should have the same size." + msg += " Please, update your color array or use the function " + msg += "``fury.primitive.repeat_primitives`` to normalize your " + msg += "color array before calling this function. e.g." raise ValueError(msg) - set_polydata_colors(pd, colors, array_name='colors') + set_polydata_colors(pd, colors, array_name="colors") if isinstance(normals, np.ndarray): set_polydata_normals(pd, normals) @@ -891,27 +843,27 @@ def repeat_sources( ): """Transform a vtksource to glyph.""" if source is None and faces is None: - raise IOError('A source or faces should be defined') + raise IOError("A source or faces should be defined") if np.array(colors).ndim == 1: colors = np.tile(colors, (len(centers), 1)) pts = numpy_to_vtk_points(np.ascontiguousarray(centers)) cols = numpy_to_vtk_colors(255 * np.ascontiguousarray(colors)) - cols.SetName('colors') + cols.SetName("colors") if isinstance(active_scalars, (float, int)): active_scalars = np.tile(active_scalars, (len(centers), 1)) if isinstance(active_scalars, np.ndarray): ascalars = numpy_support.numpy_to_vtk( np.asarray(active_scalars), deep=True, array_type=VTK_DOUBLE ) - ascalars.SetName('active_scalars') + ascalars.SetName("active_scalars") if directions is not None: directions_fa = numpy_support.numpy_to_vtk( np.asarray(directions), deep=True, array_type=VTK_DOUBLE ) - directions_fa.SetName('directions') + directions_fa.SetName("directions") polydata_centers = PolyData() polydata_geom = PolyData() @@ -926,10 +878,10 @@ def repeat_sources( if directions is not None: polydata_centers.GetPointData().AddArray(directions_fa) - polydata_centers.GetPointData().SetActiveVectors('directions') + polydata_centers.GetPointData().SetActiveVectors("directions") if isinstance(active_scalars, np.ndarray): polydata_centers.GetPointData().AddArray(ascalars) - polydata_centers.GetPointData().SetActiveScalars('active_scalars') + polydata_centers.GetPointData().SetActiveScalars("active_scalars") glyph = Glyph3D() if faces is None: @@ -952,7 +904,7 @@ def repeat_sources( mapper = PolyDataMapper() mapper.SetInputData(glyph.GetOutput()) mapper.SetScalarModeToUsePointFieldData() - mapper.SelectColorArray('colors') + mapper.SelectColorArray("colors") actor = Actor() actor.SetMapper(mapper) @@ -1050,7 +1002,7 @@ def apply_affine(aff, pts): def asbytes(s): if isinstance(s, bytes): return s - return s.encode('latin1') + return s.encode("latin1") def vtk_matrix_to_numpy(matrix): @@ -1080,7 +1032,7 @@ def numpy_to_vtk_matrix(array): elif array.shape == (3, 3): matrix = Matrix3x3() else: - raise ValueError('Invalid matrix shape: {0}'.format(array.shape)) + raise ValueError("Invalid matrix shape: {0}".format(array.shape)) for i in range(array.shape[0]): for j in range(array.shape[1]): @@ -1135,17 +1087,12 @@ def get_grid_cells_position(shapes, aspect_ratio=16 / 9.0, dim=None): n_rows, n_cols = dim if n_cols * n_rows < count: - msg = 'Size is too small, it cannot contain at least {} elements.' + msg = "Size is too small, it cannot contain at least {} elements." raise ValueError(msg.format(count)) # Use indexing="xy" so the cells are in row-major (C-order). Also, # the Y coordinates are negative so the cells are order from top to bottom. - X, Y, Z = np.meshgrid( - np.arange(n_cols), - -np.arange(n_rows), - [0], - indexing='xy' - ) + X, Y, Z = np.meshgrid(np.arange(n_cols), -np.arange(n_rows), [0], indexing="xy") return cell_shape * np.array([X.flatten(), Y.flatten(), Z.flatten()]).T @@ -1214,11 +1161,11 @@ def rgb_to_vtk(data): grid.SetDimensions(data.shape[1], data.shape[0], 1) nd = data.shape[-1] vtkarr = numpy_support.numpy_to_vtk( - np.flip(data.swapaxes(0, 1), axis=1).reshape((-1, nd), order='F') + np.flip(data.swapaxes(0, 1), axis=1).reshape((-1, nd), order="F") ) - vtkarr.SetName('Image') + vtkarr.SetName("Image") grid.GetPointData().AddArray(vtkarr) - grid.GetPointData().SetActiveScalars('Image') + grid.GetPointData().SetActiveScalars("Image") grid.GetPointData().Update() return grid @@ -1392,7 +1339,7 @@ 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): +def colors_from_actor(actor, array_name="colors", as_vtk=False): """Access colors from actor which uses polydata. Parameters @@ -1460,9 +1407,7 @@ def array_from_actor(actor, array_name, as_vtk=False): output : array (N, 3) """ - vtk_array = actor.GetMapper().GetInput().GetPointData().GetArray( - array_name - ) + vtk_array = actor.GetMapper().GetInput().GetPointData().GetArray(array_name) if vtk_array is None: return None if as_vtk: @@ -1618,7 +1563,7 @@ def color_check(pts_len, colors=None): opacities = np.unique(colors[:, 3]) global_opacity = opacities[0] if len(opacities) == 1 else -1 color_array = numpy_to_vtk_colors(255 * colors) - color_array.SetName('colors') + color_array.SetName("colors") return color_array, global_opacity @@ -1632,7 +1577,7 @@ def is_ui(actor): actor that is to be checked """ - return all([hasattr(actor, attr) for attr in ['add_to_scene', '_setup']]) + return all(hasattr(actor, attr) for attr in ["add_to_scene", "_setup"]) def set_actor_origin(actor, center=None): diff --git a/fury/window.py b/fury/window.py index b2f177a2f..7c36cedf3 100644 --- a/fury/window.py +++ b/fury/window.py @@ -32,7 +32,7 @@ from fury.utils import asbytes try: - basestring + _ = basestring except NameError: basestring = str @@ -83,7 +83,9 @@ def skybox(self, visible=True, gamma_correct=True): else: self.rm(self.__skybox_actor) else: - warn('Scene created without a skybox. Nothing to show or hide.') + warn( + "Scene created without a skybox. Nothing to show or hide.", stacklevel=2 + ) def add(self, *actors): """Add an actor to the scene.""" @@ -92,7 +94,7 @@ def add(self, *actors): self.AddVolume(actor) elif isinstance(actor, Actor2D): self.AddActor2D(actor) - elif hasattr(actor, 'add_to_scene'): + elif hasattr(actor, "add_to_scene"): actor.add_to_scene(self) else: self.AddActor(actor) @@ -110,7 +112,7 @@ def rm_all(self): """Remove all actors from the scene.""" self.RemoveAllViewProps() - def projection(self, proj_type='perspective'): + def projection(self, proj_type="perspective"): """Decide between parallel or perspective projection. Parameters @@ -119,7 +121,7 @@ def projection(self, proj_type='perspective'): Can be 'parallel' or 'perspective' (default). """ - if proj_type == 'parallel': + if proj_type == "parallel": self.GetActiveCamera().ParallelProjectionOn() else: self.GetActiveCamera().ParallelProjectionOff() @@ -173,10 +175,10 @@ def get_camera(self): def camera_info(self): """Return Camera information.""" cam = self.camera() - print('# Active Camera') - print(' Position (%.2f, %.2f, %.2f)' % cam.GetPosition()) - print(' Focal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) - print(' View Up (%.2f, %.2f, %.2f)' % cam.GetViewUp()) + print("# Active Camera") + print(" Position (%.2f, %.2f, %.2f)" % cam.GetPosition()) + 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): """Set up camera position / Focal Point / View Up.""" @@ -291,13 +293,13 @@ class ShowManager: def __init__( self, scene=None, - title='FURY', + title="FURY", size=(300, 300), png_magnify=1, reset_camera=True, order_transparent=False, - interactor_style='custom', - stereo='off', + interactor_style="custom", + stereo="off", multi_samples=8, max_peels=4, occlusion_ratio=0.0, @@ -386,7 +388,7 @@ def __init__( self.window = RenderWindow() - if self.stereo.lower() != 'off': + if self.stereo.lower() != "off": enable_stereo(self.window, self.stereo) self.window.AddRenderer(scene) @@ -403,11 +405,11 @@ def __init__( occlusion_ratio=occlusion_ratio, ) - if self.interactor_style == 'image': + if self.interactor_style == "image": self.style = InteractorStyleImage() - elif self.interactor_style == 'trackball': + elif self.interactor_style == "trackball": self.style = InteractorStyleTrackballCamera() - elif self.interactor_style == 'custom': + elif self.interactor_style == "custom": self.style = CustomInteractorStyle() else: self.style = interactor_style @@ -481,10 +483,7 @@ def animation_cbk(_obj, _event): [anim.update_animation() for anim in self._animations] self.render() - self._animation_callback = self.add_timer_callback( - True, - 10, - animation_cbk) + self._animation_callback = self.add_timer_callback(True, 10, animation_cbk) def remove_animation(self, animation): """Remove an Animation or a Timeline from the ShowManager. @@ -535,8 +534,8 @@ def start(self, multithreaded=False, desired_fps=60): """ try: - if self.title.upper() == 'FURY': - self.window.SetWindowName(self.title + ' ' + fury_version) + if self.title.upper() == "FURY": + self.window.SetWindowName(self.title + " " + fury_version) else: self.window.SetWindowName(self.title) if multithreaded: @@ -568,8 +567,8 @@ def start(self, multithreaded=False, desired_fps=60): interactor_style=self.interactor_style, ) self.render() - if self.title.upper() == 'FURY': - self.window.SetWindowName(self.title + ' ' + fury_version) + if self.title.upper() == "FURY": + self.window.SetWindowName(self.title + " " + fury_version) else: self.window.SetWindowName(self.title) self.iren.Start() @@ -600,7 +599,7 @@ def lock_current(self): """ if self.is_done(): return False - if not hasattr(self, 'window'): + if not hasattr(self, "window"): return False try: self.lock() @@ -642,7 +641,7 @@ def record_events(self): """ with InTemporaryDirectory(): - filename = 'recorded_events.log' + filename = "recorded_events.log" recorder = InteractorEventRecorder() recorder.SetInteractor(self.iren) recorder.SetFileName(filename) @@ -652,7 +651,7 @@ def _stop_recording_and_close(_obj, _evt): recorder.Stop() self.iren.TerminateApp() - self.iren.AddObserver('ExitEvent', _stop_recording_and_close) + self.iren.AddObserver("ExitEvent", _stop_recording_and_close) recorder.EnabledOn() recorder.Record() @@ -663,11 +662,11 @@ def _stop_recording_and_close(_obj, _evt): # to close the file. recorder = None # Retrieved recorded events. - with open(filename, 'r') as f: + with open(filename, "r") as f: events = f.read() return events - def record_events_to_file(self, filename='record.log'): + def record_events_to_file(self, filename="record.log"): """Record events during the interaction. The recording is represented as a list of VTK events @@ -683,11 +682,11 @@ def record_events_to_file(self, filename='record.log'): events = self.record_events() # Compress file if needed - if filename.endswith('.gz'): - with gzip.open(filename, 'wb') as fgz: + if filename.endswith(".gz"): + with gzip.open(filename, "wb") as fgz: fgz.write(asbytes(events)) else: - with open(filename, 'w') as f: + with open(filename, "w") as f: f.write(events) def play_events(self, events): @@ -736,8 +735,8 @@ def play_events_from_file(self, filename): """ # Uncompress file if needed. - if filename.endswith('.gz'): - with gzip.open(filename, 'r') as f: + if filename.endswith(".gz"): + with gzip.open(filename, "r") as f: events = f.read() else: with open(filename) as f: @@ -753,7 +752,7 @@ def add_window_callback(self, win_callback, event=Command.ModifiedEvent): def add_timer_callback(self, repeat, duration, timer_callback): if not self.iren.GetInitialized(): self.initialize() - self.iren.AddObserver('TimerEvent', timer_callback) + self.iren.AddObserver("TimerEvent", timer_callback) if repeat: timer_id = self.iren.CreateRepeatingTimer(duration) @@ -762,7 +761,7 @@ 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'): + def add_iren_callback(self, iren_callback, event="MouseMoveEvent"): if not self.iren.GetInitialized(): self.initialize() self.iren.AddObserver(event, iren_callback) @@ -832,12 +831,12 @@ def save_screenshot(self, fname, magnification=1, size=None, stereo=None): def show( scene, - title='FURY', + title="FURY", size=(300, 300), png_magnify=1, reset_camera=True, order_transparent=False, - stereo='off', + stereo="off", multi_samples=8, max_peels=4, occlusion_ratio=0.0, @@ -933,7 +932,7 @@ def record( size=(300, 300), reset_camera=True, screen_clip=False, - stereo='off', + stereo="off", verbose=False, ): """Record a video of your scene. @@ -1015,7 +1014,7 @@ def record( if reset_camera: scene.ResetCamera() - if stereo.lower() != 'off': + if stereo.lower() != "off": enable_stereo(renWin, stereo) renderLarge = RenderLargeImage() @@ -1037,9 +1036,9 @@ def record( cam = scene.GetActiveCamera() if verbose: - print('Camera Position (%.2f, %.2f, %.2f)' % cam.GetPosition()) - print('Camera Focal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) - print('Camera View Up (%.2f, %.2f, %.2f)' % cam.GetViewUp()) + print("Camera Position (%.2f, %.2f, %.2f)" % cam.GetPosition()) + print("Camera Focal Point (%.2f, %.2f, %.2f)" % cam.GetFocalPoint()) + print("Camera View Up (%.2f, %.2f, %.2f)" % cam.GetViewUp()) for i in range(n_frames): scene.GetActiveCamera().Azimuth(ang) @@ -1050,12 +1049,12 @@ def record( if path_numbering: if out_path is None: - filename = str(i).zfill(6) + '.png' + filename = str(i).zfill(6) + ".png" else: - filename = out_path + str(i).zfill(6) + '.png' + filename = out_path + str(i).zfill(6) + ".png" else: if out_path is None: - filename = 'fury.png' + filename = "fury.png" else: filename = out_path @@ -1074,11 +1073,7 @@ def record( renWin.Finalize() -def antialiasing(scene, - win, - multi_samples=8, - max_peels=4, - occlusion_ratio=0.0): +def antialiasing(scene, win, multi_samples=8, max_peels=4, occlusion_ratio=0.0): """Enable anti-aliasing and ordered transparency. Parameters @@ -1127,7 +1122,7 @@ def snapshot( size=(300, 300), offscreen=True, order_transparent=False, - stereo='off', + stereo="off", multi_samples=8, max_peels=4, occlusion_ratio=0.0, @@ -1188,7 +1183,7 @@ def snapshot( render_window = RenderWindow() if offscreen: render_window.SetOffScreenRendering(1) - if stereo.lower() != 'off': + if stereo.lower() != "off": enable_stereo(render_window, stereo) render_window.AddRenderer(scene) render_window.SetSize(width, height) @@ -1207,8 +1202,7 @@ def snapshot( h, w, _ = vtk_image.GetDimensions() vtk_array = vtk_image.GetPointData().GetScalars() components = vtk_array.GetNumberOfComponents() - arr = numpy_support.vtk_to_numpy(vtk_array).reshape( - w, h, components).copy() + arr = numpy_support.vtk_to_numpy(vtk_array).reshape(w, h, components).copy() arr = np.flipud(arr) if fname is None: @@ -1279,10 +1273,10 @@ class ReportSnapshot: colors_found = False def __str__(self): - msg = 'Report:\n-------\n' - msg += 'objects: {}\n'.format(self.objects) - msg += 'labels: \n{}\n'.format(self.labels) - msg += 'colors_found: {}\n'.format(self.colors_found) + msg = "Report:\n-------\n" + msg += "objects: {}\n".format(self.objects) + msg += "labels: \n{}\n".format(self.labels) + msg += "colors_found: {}\n".format(self.colors_found) return msg report = ReportSnapshot() @@ -1291,11 +1285,9 @@ def __str__(self): if isinstance(colors, tuple): colors = [colors] flags = [False] * len(colors) - for (i, col) in enumerate(colors): + for i, col in enumerate(colors): # find if the current color exist in the array - flags[i] = np.any( - np.any(np.all(np.equal(im[..., :3], col[:3]), axis=-1)) - ) + flags[i] = np.any(np.any(np.all(np.equal(im[..., :3], col[:3]), axis=-1))) report.colors_found = flags @@ -1342,18 +1334,20 @@ def enable_stereo(renwin, stereo_type): # stereo type ints from # https://gitlab.kitware.com/vtk/vtk/blob/master/Rendering/Core/vtkRenderWindow.h#L57 stereo_type_dictionary = { - 'opengl': 1, - 'interlaced': 3, - 'anaglyph': 7, - 'checkerboard': 8, - 'horizontal': 9, + "opengl": 1, + "interlaced": 3, + "anaglyph": 7, + "checkerboard": 8, + "horizontal": 9, } # default to horizontal since it is easy to see if it is working if stereo_type not in stereo_type_dictionary: - warn('Unknown stereo type provided. ' - "Setting stereo type to 'horizontal'.") - stereo_type = 'horizontal' + warn( + "Unknown stereo type provided. " "Setting stereo type to 'horizontal'.", + stacklevel=2, + ) + stereo_type = "horizontal" renwin.SetStereoType(stereo_type_dictionary[stereo_type]) @@ -1368,8 +1362,7 @@ def gl_get_current_state(gl_state): """ state_description = { - glName: gl_state.GetEnumState(glNumber - ) for glName, glNumber in _GL.items() + glName: gl_state.GetEnumState(glNumber) for glName, glNumber in _GL.items() } return state_description @@ -1402,7 +1395,7 @@ def gl_enable_depth(gl_state): gl_state : vtkOpenGLState """ - gl_state.vtkglEnable(_GL['GL_DEPTH_TEST']) + gl_state.vtkglEnable(_GL["GL_DEPTH_TEST"]) def gl_disable_depth(gl_state): @@ -1413,7 +1406,7 @@ def gl_disable_depth(gl_state): gl_state : vtkOpenGLState """ - gl_state.vtkglDisable(_GL['GL_DEPTH_TEST']) + gl_state.vtkglDisable(_GL["GL_DEPTH_TEST"]) def gl_enable_blend(gl_state): @@ -1424,7 +1417,7 @@ def gl_enable_blend(gl_state): gl_state : vtkOpenGLState """ - gl_state.vtkglEnable(_GL['GL_BLEND']) + gl_state.vtkglEnable(_GL["GL_BLEND"]) def gl_disable_blend(gl_state): @@ -1442,8 +1435,8 @@ def gl_disable_blend(gl_state): """ # noqa - gl_state.vtkglDisable(_GL['GL_CULL_FACE']) - gl_state.vtkglDisable(_GL['GL_BLEND']) + gl_state.vtkglDisable(_GL["GL_CULL_FACE"]) + gl_state.vtkglDisable(_GL["GL_BLEND"]) def gl_set_additive_blending(gl_state): @@ -1455,9 +1448,9 @@ def gl_set_additive_blending(gl_state): """ gl_reset_blend(gl_state) - gl_state.vtkglEnable(_GL['GL_BLEND']) - gl_state.vtkglDisable(_GL['GL_DEPTH_TEST']) - gl_state.vtkglBlendFunc(_GL['GL_SRC_ALPHA'], _GL['GL_ONE']) + gl_state.vtkglEnable(_GL["GL_BLEND"]) + gl_state.vtkglDisable(_GL["GL_DEPTH_TEST"]) + gl_state.vtkglBlendFunc(_GL["GL_SRC_ALPHA"], _GL["GL_ONE"]) def gl_set_additive_blending_white_background(gl_state): @@ -1469,13 +1462,13 @@ def gl_set_additive_blending_white_background(gl_state): """ gl_reset_blend(gl_state) - gl_state.vtkglEnable(_GL['GL_BLEND']) - gl_state.vtkglDisable(_GL['GL_DEPTH_TEST']) + gl_state.vtkglEnable(_GL["GL_BLEND"]) + gl_state.vtkglDisable(_GL["GL_DEPTH_TEST"]) gl_state.vtkglBlendFuncSeparate( - _GL['GL_SRC_ALPHA'], - _GL['GL_ONE_MINUS_SRC_ALPHA'], - _GL['GL_ONE'], - _GL['GL_ZERO'], + _GL["GL_SRC_ALPHA"], + _GL["GL_ONE_MINUS_SRC_ALPHA"], + _GL["GL_ONE"], + _GL["GL_ZERO"], ) @@ -1487,14 +1480,14 @@ def gl_set_normal_blending(gl_state): gl_state : vtkOpenGLState """ - gl_state.vtkglEnable(_GL['GL_BLEND']) - gl_state.vtkglEnable(_GL['GL_DEPTH_TEST']) - gl_state.vtkglBlendFunc(_GL['GL_ONE'], _GL['GL_ONE']) + gl_state.vtkglEnable(_GL["GL_BLEND"]) + gl_state.vtkglEnable(_GL["GL_DEPTH_TEST"]) + gl_state.vtkglBlendFunc(_GL["GL_ONE"], _GL["GL_ONE"]) gl_state.vtkglBlendFuncSeparate( - _GL['GL_SRC_ALPHA'], - _GL['GL_ONE_MINUS_SRC_ALPHA'], - _GL['GL_ONE'], - _GL['GL_ONE_MINUS_SRC_ALPHA'], + _GL["GL_SRC_ALPHA"], + _GL["GL_ONE_MINUS_SRC_ALPHA"], + _GL["GL_ONE"], + _GL["GL_ONE_MINUS_SRC_ALPHA"], ) @@ -1507,7 +1500,7 @@ def gl_set_multiplicative_blending(gl_state): """ gl_reset_blend(gl_state) - gl_state.vtkglBlendFunc(_GL['GL_ZERO'], _GL['GL_SRC_COLOR']) + gl_state.vtkglBlendFunc(_GL["GL_ZERO"], _GL["GL_SRC_COLOR"]) def gl_set_subtractive_blending(gl_state): @@ -1519,7 +1512,7 @@ def gl_set_subtractive_blending(gl_state): """ gl_reset_blend(gl_state) - gl_state.vtkglBlendFunc(_GL['GL_ZERO'], _GL['GL_ONE_MINUS_SRC_COLOR']) + gl_state.vtkglBlendFunc(_GL["GL_ZERO"], _GL["GL_ONE_MINUS_SRC_COLOR"]) def release_context(window): diff --git a/pyproject.toml b/pyproject.toml index 9395a0b50..87a8a26bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ doc = [ "texext", "tomli; python_version < \"3.11\"", ] -style = ["flake8", "blue", "ruff", "pre-commit"] +style = ["ruff", "pre-commit"] typing = ["mypy", "types-Pillow", "data-science-types"] test = [ "coverage", @@ -97,20 +97,6 @@ raw-options = { version_scheme = "release-branch-semver" } [tool.hatch.build.hooks.vcs] version-file = "fury/_version.py" -[tool.blue] -line_length = 88 -target-version = ["py38"] -force-exclude = """ -( - _version.py - *docs/experimental/* -) -""" - -[flake8] -max-line-length = 88 -extend-exclude = ["_version.py", "externals", "*docs/experimental*"] - [tool.mypy] python_version = "3.11" ignore_missing_imports = "True" diff --git a/ruff.toml b/ruff.toml index 673eca617..901943097 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,14 +1,43 @@ target-version = "py310" +line-length = 88 +force-exclude = true +extend-exclude = [ + "__pycache__", + "build", + "_version.py", + "docs/experimental/**", +] -lint.select = [ - "I", # isort +[lint] +select = [ + "F", + "E", + "C", + "W", + "B", + "I", +] +ignore = [ + "C901", + "E203" ] +[lint.extend-per-file-ignores] +"docs/examples/**" = ["I001"] +"docs/source/conf.py" = ["E402"] + +[lint.flake8-quotes] +inline-quotes = "double" + [lint.isort] case-sensitive = true combine-as-imports = true force-sort-within-sections = true +known-first-party = ["fury"] no-sections = false order-by-type = true relative-imports-order = "closest-to-furthest" section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"] + +[format] +quote-style = "double"