From 9ebbb5984f4ecad3f2d70e543e2c6ee17dd75520 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. --- .flake8 | 14 - .pre-commit-config.yaml | 11 +- docs/examples/collision-particles.py | 6 +- docs/examples/viz_advanced.py | 38 +- docs/examples/viz_animated_surfaces.py | 23 +- docs/examples/viz_arrow.py | 2 +- docs/examples/viz_ball_collide.py | 6 +- docs/examples/viz_bezier_interpolator.py | 30 +- docs/examples/viz_billboard_sdf_spheres.py | 98 ++-- docs/examples/viz_brick_wall.py | 6 +- docs/examples/viz_brownian_motion.py | 28 +- docs/examples/viz_bundles.py | 28 +- docs/examples/viz_buttons.py | 22 +- docs/examples/viz_camera.py | 6 +- docs/examples/viz_card.py | 34 +- docs/examples/viz_card_sprite_sheet.py | 49 +- docs/examples/viz_chain.py | 7 +- docs/examples/viz_check_boxes.py | 18 +- docs/examples/viz_color_interpolators.py | 12 +- docs/examples/viz_combobox.py | 26 +- docs/examples/viz_cone.py | 2 +- docs/examples/viz_custom_interpolator.py | 20 +- docs/examples/viz_domino.py | 6 +- docs/examples/viz_drawpanel.py | 8 +- docs/examples/viz_dt_ellipsoids.py | 129 +++-- 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 | 10 +- docs/examples/viz_helical_motion.py | 8 +- docs/examples/viz_hierarchical_animation.py | 2 +- docs/examples/viz_interaction.py | 8 +- docs/examples/viz_interpolators.py | 10 +- docs/examples/viz_introduction.py | 2 +- docs/examples/viz_layout.py | 14 +- docs/examples/viz_markers.py | 6 +- 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 | 2 +- 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 | 15 +- 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 | 102 ++-- docs/examples/viz_sphere.py | 2 +- docs/examples/viz_spiky.py | 4 +- docs/examples/viz_spinbox.py | 25 +- docs/examples/viz_spline_interpolator.py | 2 +- docs/examples/viz_surfaces.py | 10 +- docs/examples/viz_tab.py | 52 +- docs/examples/viz_tesseract.py | 4 +- docs/examples/viz_texture.py | 4 +- docs/examples/viz_timeline.py | 2 +- docs/examples/viz_timers.py | 2 +- docs/examples/viz_ui.py | 48 +- docs/examples/viz_ui_listbox.py | 12 +- docs/examples/viz_ui_slider.py | 22 +- docs/examples/viz_using_time_equations.py | 4 +- docs/examples/viz_widget.py | 4 +- docs/examples/viz_wrecking_ball.py | 7 +- docs/source/conf.py | 208 ++++--- docs/source/ext/apigen.py | 155 +++-- docs/source/ext/build_modref_templates.py | 42 +- docs/source/ext/github.py | 71 ++- docs/source/ext/github_tools.py | 313 +++++----- docs/source/ext/prepare_gallery.py | 61 +- docs/source/ext/rstjinja.py | 4 +- docs/source/ext/scrap.py | 15 +- docs/upload_to_gh-pages.py | 91 ++- fury/__init__.py | 54 +- fury/actor.py | 601 ++++++++------------ fury/actors/odf_slicer.py | 63 +- fury/actors/peak.py | 73 +-- 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 | 3 +- 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 | 3 +- fury/animation/timeline.py | 61 +- fury/colormap.py | 145 +++-- fury/convert.py | 10 +- fury/data/__init__.py | 31 +- fury/data/fetcher.py | 484 +++++++++------- fury/data/tests/test_fetcher.py | 54 +- fury/decorators.py | 14 +- fury/deprecator.py | 87 ++- fury/gltf.py | 291 ++++------ fury/interactor.py | 154 +++-- fury/io.py | 155 +++-- fury/layout.py | 85 ++- fury/lib.py | 8 +- fury/material.py | 333 +++++++---- fury/molecular.py | 106 ++-- fury/optpkg.py | 8 +- fury/pick.py | 95 ++-- fury/pkg_info.py | 18 +- fury/primitive.py | 125 ++-- fury/shaders/__init__.py | 18 +- fury/shaders/base.py | 118 ++-- fury/shaders/tests/test_base.py | 60 +- fury/stream/client.py | 78 +-- fury/stream/constants.py | 44 +- fury/stream/server/__init__.py | 2 +- fury/stream/server/async_app.py | 166 +++--- fury/stream/server/main.py | 17 +- fury/stream/tools.py | 106 +--- fury/stream/widget.py | 39 +- fury/testing.py | 80 ++- fury/tests/test_actors.py | 341 ++++++----- fury/tests/test_colormap.py | 25 +- fury/tests/test_convert.py | 14 +- fury/tests/test_deprecator.py | 204 +++---- fury/tests/test_gltf.py | 99 ++-- fury/tests/test_interactor.py | 117 ++-- fury/tests/test_io.py | 96 ++-- fury/tests/test_layout.py | 69 +-- fury/tests/test_material.py | 36 +- fury/tests/test_molecular.py | 72 +-- fury/tests/test_optpkg.py | 38 +- fury/tests/test_pick.py | 76 ++- fury/tests/test_primitive.py | 30 +- fury/tests/test_stream.py | 72 +-- fury/tests/test_testing.py | 46 +- fury/tests/test_thread.py | 29 +- fury/tests/test_transform.py | 2 +- fury/tests/test_utils.py | 98 ++-- 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 | 575 ++++++++++--------- fury/ui/helpers.py | 36 +- fury/ui/tests/test_containers.py | 145 +++-- fury/ui/tests/test_core.py | 144 ++--- fury/ui/tests/test_elements.py | 514 ++++++++--------- fury/ui/tests/test_elements_callback.py | 19 +- fury/ui/tests/test_helpers.py | 81 +-- fury/utils.py | 165 ++---- fury/window.py | 189 +++--- pyproject.toml | 52 +- 163 files changed, 5270 insertions(+), 5422 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..ceea67ab2 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: @@ -52,3 +43,5 @@ repos: # Run the linter - id: ruff 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..f62615bb1 100644 --- a/docs/examples/viz_advanced.py +++ b/docs/examples/viz_advanced.py @@ -11,6 +11,7 @@ the main functions using the following modules. """ +import numpy as np from dipy.data.fetcher import fetch_bundles_2_subjects, read_bundles_2_subjects ############################################################################### @@ -35,7 +36,6 @@ # # First we need to fetch and load some datasets. from dipy.tracking.streamline import Streamlines -import numpy as np from fury import actor, ui, window @@ -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..de227a6cc 100644 --- a/docs/examples/viz_ball_collide.py +++ b/docs/examples/viz_ball_collide.py @@ -86,7 +86,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 +122,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 +137,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..ebe695183 100644 --- a/docs/examples/viz_bezier_interpolator.py +++ b/docs/examples/viz_bezier_interpolator.py @@ -44,19 +44,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 +86,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 +109,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 +126,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 +149,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 +181,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..0ee6b8369 100644 --- a/docs/examples/viz_brick_wall.py +++ b/docs/examples/viz_brick_wall.py @@ -230,7 +230,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 +259,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 +299,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..acdf94d81 100644 --- a/docs/examples/viz_buttons.py +++ b/docs/examples/viz_buttons.py @@ -21,15 +21,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 +41,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 +61,7 @@ def change_text_callback(i_ren, _obj, _button): - text.message = 'Clicked!' + text.message = "Clicked!" i_ren.force_render() @@ -78,7 +78,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 +87,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..7522d6ddd 100644 --- a/docs/examples/viz_card.py +++ b/docs/examples/viz_card.py @@ -19,27 +19,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..9c26e34f5 100644 --- a/docs/examples/viz_card_sprite_sheet.py +++ b/docs/examples/viz_card_sprite_sheet.py @@ -24,28 +24,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 +68,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 +80,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 +91,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..0ae9041f4 100644 --- a/docs/examples/viz_chain.py +++ b/docs/examples/viz_chain.py @@ -163,6 +163,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 +205,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 +228,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 +263,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..e83c73e55 100644 --- a/docs/examples/viz_combobox.py +++ b/docs/examples/viz_combobox.py @@ -23,9 +23,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 +33,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 +50,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 +77,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 +86,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..739810e75 100644 --- a/docs/examples/viz_custom_interpolator.py +++ b/docs/examples/viz_custom_interpolator.py @@ -66,11 +66,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 +96,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 +163,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..acfe8b472 100644 --- a/docs/examples/viz_domino.py +++ b/docs/examples/viz_domino.py @@ -173,7 +173,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 +202,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 +243,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..bc198033d 100644 --- a/docs/examples/viz_drawpanel.py +++ b/docs/examples/viz_drawpanel.py @@ -28,7 +28,7 @@ # Now we add DrawPanel to the scene. current_size = (650, 650) -showm = window.ShowManager(size=current_size, title='DrawPanel UI Example') +showm = window.ShowManager(size=current_size, title="DrawPanel UI Example") showm.scene.add(drawing_canvas) @@ -38,8 +38,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..4eaf72cdd 100644 --- a/docs/examples/viz_dt_ellipsoids.py +++ b/docs/examples/viz_dt_ellipsoids.py @@ -31,12 +31,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 +48,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 +69,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 +90,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 +105,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 +133,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 +165,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 +191,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 +213,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 +223,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 +267,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 +284,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 +299,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 +311,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 +328,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 +337,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 +349,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..163e0d8d2 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))) 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))) 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))) 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))) 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..075945e29 100644 --- a/docs/examples/viz_gltf_export.py +++ b/docs/examples/viz_gltf_export.py @@ -30,8 +30,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 +46,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 +64,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..109e91060 100644 --- a/docs/examples/viz_hierarchical_animation.py +++ b/docs/examples/viz_hierarchical_animation.py @@ -140,5 +140,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..cfa44bbc8 100644 --- a/docs/examples/viz_introduction.py +++ b/docs/examples/viz_introduction.py @@ -114,5 +114,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..e708f2344 100644 --- a/docs/examples/viz_markers.py +++ b/docs/examples/viz_markers.py @@ -15,7 +15,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 +39,7 @@ nodes_3d_actor = actor.markers( centers + np.ones_like(centers) * 25, - marker='3d', + marker="3d", colors=colors, scales=0.5, ) @@ -54,4 +54,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..18eb9aeb3 100644 --- a/docs/examples/viz_robot_arm_animation.py +++ b/docs/examples/viz_robot_arm_animation.py @@ -118,4 +118,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..c6e761a1a 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,14 +98,14 @@ 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') + color_change = np.array([150, 0, 0, 255], dtype="uint8") vcolors[ object_index * sec : object_index * sec + sec ] = color_change @@ -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..2e60bb351 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,7 +292,7 @@ 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): # if the planet is saturn then we also need to update the position @@ -331,4 +331,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..aeda8a07d 100644 --- a/docs/examples/viz_spinbox.py +++ b/docs/examples/viz_spinbox.py @@ -22,23 +22,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 +75,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..70d2abd8c 100644 --- a/docs/examples/viz_tab.py +++ b/docs/examples/viz_tab.py @@ -31,7 +31,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 +39,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 +93,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 +113,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 +139,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 +152,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 +184,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 +194,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 +227,7 @@ def collapse(tab_ui): ############################################################################### # Next we prepare the scene and render it with the help of show manager. -sm = window.ShowManager(size=(800, 500), title='Viz Tab') +sm = 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 +236,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..8f5694ea8 100644 --- a/docs/examples/viz_timeline.py +++ b/docs/examples/viz_timeline.py @@ -89,4 +89,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..e67357e1c 100644 --- a/docs/examples/viz_timers.py +++ b/docs/examples/viz_timers.py @@ -67,4 +67,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..73f491a90 100644 --- a/docs/examples/viz_ui_listbox.py +++ b/docs/examples/viz_ui_listbox.py @@ -21,9 +21,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 +41,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 +63,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 +74,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..262c52af3 100644 --- a/docs/examples/viz_ui_slider.py +++ b/docs/examples/viz_ui_slider.py @@ -37,43 +37,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 +117,7 @@ def translate_cube_hor(slider): # manager. current_size = (800, 800) -show_manager = window.ShowManager(size=current_size, title='FURY Cube Example') +show_manager = window.ShowManager(size=current_size, title="FURY Cube Example") show_manager.scene.add(cube) show_manager.scene.add(ring_slider) @@ -149,4 +149,4 @@ def translate_cube_hor(slider): if interactive: show_manager.start() -window.record(show_manager.scene, size=current_size, out_path='viz_slider.png') +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..78760b508 100644 --- a/docs/examples/viz_using_time_equations.py +++ b/docs/examples/viz_using_time_equations.py @@ -60,7 +60,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 +76,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..67e3dbab4 100644 --- a/docs/examples/viz_wrecking_ball.py +++ b/docs/examples/viz_wrecking_ball.py @@ -263,6 +263,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 +316,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 +336,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 +374,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..2f0973069 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -17,46 +17,46 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -from datetime import datetime import os import re import sys +from datetime import datetime # 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..838e1575c 100644 --- a/docs/source/ext/apigen.py +++ b/docs/source/ext/apigen.py @@ -19,9 +19,9 @@ # Stdlib imports import ast -from importlib import import_module import os import re +from importlib import import_module # suppress print statements (warnings for empty files) DEBUG = True @@ -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 ] @@ -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..09cde68a0 100755 --- a/docs/source/ext/build_modref_templates.py +++ b/docs/source/ext/build_modref_templates.py @@ -1,9 +1,9 @@ #!/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 +from os.path import join as pjoin # local imports from apigen import ApiDocWriter @@ -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..09a94d4ed 100644 --- a/docs/source/ext/github_tools.py +++ b/docs/source/ext/github_tools.py @@ -4,13 +4,13 @@ Taken from ipython """ import argparse -from datetime import datetime, timedelta import json import operator import os import re -from subprocess import check_output import sys +from datetime import datetime, timedelta +from subprocess import check_output from urllib.request import Request, urlopen # ---------------------------------------------------------------------------- @@ -22,15 +22,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,26 +49,26 @@ 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 = {} @@ -97,14 +97,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 +113,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 +137,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 +183,67 @@ 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]) + contributor_dict = dict({ + (k, contributor["author"][k]) for k in desired_keys - if k in contributor['author'] - ) + 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 +260,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 @@ -293,30 +293,30 @@ def cumulative_contributors(project='fury-gl/fury', show=True): 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 +334,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 +380,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 +406,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 +455,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 +484,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 +512,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 +538,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 +594,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 +603,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 +612,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..9a3cffc1f 100644 --- a/docs/source/ext/prepare_gallery.py +++ b/docs/source/ext/prepare_gallery.py @@ -1,8 +1,9 @@ -from dataclasses import dataclass, field import fnmatch import os -from pathlib import Path import shutil +import sys +from dataclasses import dataclass, field +from pathlib import Path 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,17 +131,17 @@ 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] 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..db75a5324 100644 --- a/docs/upload_to_gh-pages.py +++ b/docs/upload_to_gh-pages.py @@ -10,15 +10,15 @@ # Imports ############################################################################### import os -from os import chdir as cd -from os.path import join as pjoin import re import shutil -from subprocess import PIPE, CalledProcessError, Popen, check_call import sys +from os import chdir as cd +from os.path import join as pjoin +from subprocess import PIPE, CalledProcessError, Popen, check_call 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..8fdd42606 100644 --- a/fury/__init__.py +++ b/fury/__init__.py @@ -18,8 +18,8 @@ def get_info(verbose=False): with named parameters of interest """ - from os.path import dirname import sys + from os.path import dirname import numpy import scipy @@ -27,31 +27,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 +65,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 +82,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 +100,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..5ba8f2535 100644 --- a/fury/actor.py +++ b/fury/actor.py @@ -1,19 +1,20 @@ """Module that provide actors to render.""" -from functools import partial import os import warnings +from functools import partial import numpy as np -from fury import layout +import fury.primitive as fp +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 @@ -36,8 +37,8 @@ ImageData, ImageMapToColors, ImageReslice, - LODActor, LinearExtrusionFilter, + LODActor, LookupTable, LoopSubdivisionFilter, Matrix4x4, @@ -52,9 +53,9 @@ SplineFilter, TextActor3D, Texture, - TextureMapToPlane, TexturedActor2D, TexturedSphereSource, + TextureMapToPlane, Transform, TransformPolyDataFilter, TriangleFilter, @@ -62,7 +63,6 @@ VectorText, numpy_support, ) -import fury.primitive as fp from fury.shaders import ( add_shader_callback, attribute_to_actor, @@ -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, @@ -3366,13 +3286,12 @@ def grid( if captions is not None: actors_with_caption = [] for actor, caption in zip(actors, captions): - 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..931f9db5d 100644 --- a/fury/actors/peak.py +++ b/fury/actors/peak.py @@ -91,9 +91,9 @@ def __init__( 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 +132,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 +152,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 +182,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 +216,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 +275,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 +290,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 +346,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 +359,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 +372,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 +409,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..03746f386 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())] ) 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..a6cd0b54c 100644 --- a/fury/animation/tests/test_timeline.py +++ b/fury/animation/tests/test_timeline.py @@ -3,10 +3,9 @@ import numpy as np import numpy.testing as npt -from fury.animation import Animation, Timeline import fury.testing as ft +from fury.animation import Animation, Timeline 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..912b3ec6a 100644 --- a/fury/animation/timeline.py +++ b/fury/animation/timeline.py @@ -1,8 +1,8 @@ import os from time import perf_counter -from PIL import Image import numpy as np +from PIL import Image from fury import window from fury.animation.animation import Animation @@ -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..932191227 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,7 +296,7 @@ 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')): + for i, color in enumerate(("red", "green", "blue")): x, y0, _ = zip(*desc[color]) # Matplotlib allows more complex colormaps, but for users who do # not have Matplotlib fury makes a few simple colormaps available. @@ -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 @@ -628,12 +627,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 +671,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 +828,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 +896,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 +950,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 +984,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 +1001,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 +1031,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..8d4e64820 100644 --- a/fury/data/__init__.py +++ b/fury/data/__init__.py @@ -1,6 +1,7 @@ """Read or fetch test or example data.""" -from os.path import dirname, join as pjoin +from os.path import dirname +from os.path import join as pjoin from fury.data.fetcher import ( fetch_gltf, @@ -20,13 +21,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..34cb49335 100644 --- a/fury/data/fetcher.py +++ b/fury/data/fetcher.py @@ -2,52 +2,51 @@ import asyncio import contextlib -from hashlib import sha256 import json import os -from os.path import dirname, join as pjoin import platform -from shutil import copyfileobj import sys import tarfile -from urllib.request import urlopen import warnings import zipfile +from hashlib import sha256 +from os.path import dirname +from os.path import join as pjoin +from shutil import copyfileobj +from urllib.request import urlopen 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 +60,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 +73,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 +93,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 +113,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 +150,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 +190,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 +208,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 +257,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)): + 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 +272,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 +331,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 +365,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,26 +373,25 @@ 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) @@ -393,7 +403,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 +435,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 +694,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 +728,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 +752,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 +771,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 +790,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 +813,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 +836,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 +848,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..14a6190bb 100644 --- a/fury/decorators.py +++ b/fury/decorators.py @@ -3,11 +3,11 @@ 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 +29,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 +38,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..62e3d3517 100644 --- a/fury/deprecator.py +++ b/fury/deprecator.py @@ -9,9 +9,9 @@ """ import functools -from inspect import signature import re import warnings +from inspect import signature from fury import __version__ from fury.optpkg import optional_package @@ -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. @@ -329,7 +328,7 @@ def deprecated_params( ) != 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] @@ -355,7 +354,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,7 +371,7 @@ 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) @@ -381,22 +380,20 @@ def wrapper(*args, **kwargs): 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 +408,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 +418,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 +430,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..28089a20f 100644 --- a/fury/gltf.py +++ b/fury/gltf.py @@ -4,9 +4,9 @@ import os from typing import Dict # noqa -from PIL import Image import numpy as np import pygltflib as gltflib +from PIL import Image from pygltflib.utils import glb2gltf, gltf2glb from fury import actor, io, transform, utils @@ -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: @@ -209,11 +204,7 @@ def transverse_node(self, for bone, ibm in zip(joints, ibms): self.bones.append(bone) self.ibms[bone] = ibm - self.transverse_node( - joints[0], - np.identity(4), - parent, is_joint=True - ) + self.transverse_node(joints[0], np.identity(4), parent, 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 @@ -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'] + timestamps = transforms["timestamps"] + metrices = transforms["matrix"] for time, matrix in zip(timestamps, metrices): - animation.set_keyframe('transform', time[0], matrix) + 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) + animation.set_keyframe("morph", time[0], weights) root_animation.add(animation) root_animation.add_actor(self._actors) @@ -992,42 +956,40 @@ 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]) ) @@ -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..14b985c04 100644 --- a/fury/io.py +++ b/fury/io.py @@ -1,10 +1,10 @@ import os +import warnings from tempfile import TemporaryDirectory as InTemporaryDirectory from urllib.request import urlretrieve -import warnings -from PIL import Image import numpy as np +from PIL import Image from fury.lib import ( BMPReader, @@ -24,9 +24,9 @@ PolyDataWriter, STLReader, STLWriter, + Texture, TIFFReader, TIFFWriter, - Texture, XMLPolyDataReader, XMLPolyDataWriter, numpy_support, @@ -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..7647949b5 100644 --- a/fury/layout.py +++ b/fury/layout.py @@ -13,11 +13,10 @@ def apply(self, actors): positions = self.compute_positions(actors) for a, pos in zip(actors, positions): - 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/lib.py b/fury/lib.py index dc0bf6a47..b1ba71259 100644 --- a/fury/lib.py +++ b/fury/lib.py @@ -1,5 +1,3 @@ -from vtkmodules.util import colors, numpy_support # type: ignore # noqa: F401 -from vtkmodules.util.misc import calldata_type # type: ignore # noqa: F401 import vtkmodules.vtkCommonCore as ccvtk # type: ignore import vtkmodules.vtkCommonDataModel as cdmvtk # type: ignore import vtkmodules.vtkCommonExecutionModel as cemvtk # type: ignore @@ -13,19 +11,21 @@ import vtkmodules.vtkFiltersModeling as fmvtk # type: ignore import vtkmodules.vtkFiltersSources as fsvtk # type: ignore import vtkmodules.vtkFiltersTexture as ftvtk # type: ignore +import vtkmodules.vtkImagingCore as icvtk # type: ignore +import vtkmodules.vtkInteractionStyle as isvtk # type: ignore import vtkmodules.vtkIOGeometry as iogvtk # type: ignore import vtkmodules.vtkIOImage as ioivtk # type: ignore import vtkmodules.vtkIOLegacy as iolvtk # type: ignore import vtkmodules.vtkIOMINC as iomincvtk # type: ignore import vtkmodules.vtkIOPLY as ioplyvtk # type: ignore import vtkmodules.vtkIOXML as ioxmlvtk # type: ignore -import vtkmodules.vtkImagingCore as icvtk # type: ignore -import vtkmodules.vtkInteractionStyle as isvtk # type: ignore import vtkmodules.vtkRenderingAnnotation as ravtk # type: ignore import vtkmodules.vtkRenderingCore as rcvtk # type: ignore import vtkmodules.vtkRenderingFreeType as rftvtk # type: ignore import vtkmodules.vtkRenderingLOD as rlodvtk # type: ignore import vtkmodules.vtkRenderingOpenGL2 as roglvtk # type: ignore +from vtkmodules.util import colors, numpy_support # type: ignore # noqa: F401 +from vtkmodules.util.misc import calldata_type # type: ignore # noqa: F401 VTK_VERSION = ccvtk.vtkVersion.GetVTKVersion() 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..5d2630bd9 100644 --- a/fury/molecular.py +++ b/fury/molecular.py @@ -13,7 +13,6 @@ VTK_UNSIGNED_SHORT, Actor, DataSetAttributes, - Molecule as Mol, OpenGLMoleculeMapper, PeriodicTable, PolyData, @@ -21,6 +20,11 @@ ProteinRibbonFilter, SimpleBondPerceiver, StringArray, +) +from fury.lib import ( + Molecule as Mol, +) +from fury.lib import ( numpy_support as nps, ) from fury.utils import numpy_to_vtk_points @@ -97,7 +101,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 +111,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 +120,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 +417,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 +436,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 +461,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 +500,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 +516,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 +567,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 +582,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 +627,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 +637,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 +677,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 +700,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 +709,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 +720,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 +770,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..892c179ee 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: @@ -121,13 +121,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..64efeaa32 100644 --- a/fury/primitive.py +++ b/fury/primitive.py @@ -11,15 +11,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 +37,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 +46,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 +78,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 +165,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 +184,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 +214,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 +245,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 +289,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 +339,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 +372,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 +440,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 +501,7 @@ def prim_icosahedron(): [10, 9, 6], [9, 10, 11], ], - dtype='i8', + dtype="i8", ) return icosahedron_vertices, icosahedron_mesh @@ -613,7 +596,7 @@ def prim_rhombicuboctahedron(): [22, 20, 5], [20, 1, 5], ], - dtype='i8', + dtype="i8", ) triangles = fix_winding_order(vertices, triangles, clockwise=True) @@ -664,7 +647,7 @@ def prim_star(dim=2): [3, 7, 9], [3, 5, 7], ], - dtype='i8', + dtype="i8", ) if dim == 3: @@ -715,7 +698,7 @@ def prim_star(dim=2): [3, 11, 2], [11, 1, 2], ], - dtype='i8', + dtype="i8", ) return vert, triangles @@ -733,7 +716,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 +812,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 +865,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 +910,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 +940,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 +991,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 +1000,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 +1045,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 +1155,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..7f76152b1 100644 --- a/fury/shaders/base.py +++ b/fury/shaders/base.py @@ -1,5 +1,5 @@ -from functools import partial import os +from functools import partial from fury import enable_warnings from fury.deprecator import deprecate_with_version @@ -15,50 +15,50 @@ 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 +76,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 +132,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 +163,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 +209,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 +256,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..b4586bc20 100644 --- a/fury/stream/client.py +++ b/fury/stream/client.py @@ -1,12 +1,12 @@ -from functools import partial import logging import platform import time +from functools import partial import numpy as np import vtk -from fury.stream.constants import PY_VERSION_8, _CQUEUE +from fury.stream.constants import _CQUEUE, PY_VERSION_8 from fury.stream.tools import ( ArrayCircularQueue, IntervalTimer, @@ -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,8 +192,8 @@ 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 @@ -214,7 +202,7 @@ def cleanup(self): 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 +245,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 +260,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 +270,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 +317,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 +333,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..cae9cbd5c 100644 --- a/fury/stream/constants.py +++ b/fury/stream/constants.py @@ -1,5 +1,5 @@ -from collections import namedtuple import sys +from collections import namedtuple PY_VERSION_8 = sys.version_info.minor >= 8 @@ -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..93f35bd7a 100644 --- a/fury/stream/server/async_app.py +++ b/fury/stream/server/async_app.py @@ -1,12 +1,12 @@ import asyncio -from functools import partial import json import os import weakref +from functools import partial import aiohttp -from aiohttp import MultipartWriter, WSCloseCode, web import numpy as np +from aiohttp import MultipartWriter, WSCloseCode, web try: from aiortc import RTCPeerConnection, RTCSessionDescription @@ -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..6971ba9d3 100644 --- a/fury/stream/server/main.py +++ b/fury/stream/server/main.py @@ -1,10 +1,10 @@ # import os # os.environ['PYTHONASYNCIODEBUG'] = '1' # import logging -from aiohttp import web import numpy as np +from aiohttp import web -from fury.stream.constants import PY_VERSION_8, _CQUEUE +from fury.stream.constants import _CQUEUE, PY_VERSION_8 from fury.stream.server.async_app import get_app from fury.stream.tools import ( ArrayCircularQueue, @@ -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..323d687bb 100644 --- a/fury/stream/tools.py +++ b/fury/stream/tools.py @@ -1,13 +1,13 @@ -from abc import ABC, abstractmethod import asyncio import io import logging import multiprocessing -from threading import Timer import time +from abc import ABC, abstractmethod +from threading import Timer -from PIL import Image, ImageDraw import numpy as np +from PIL import Image, ImageDraw from fury.stream.constants import PY_VERSION_8 @@ -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 ) ) 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..9db8a4ee9 100644 --- a/fury/testing.py +++ b/fury/testing.py @@ -1,17 +1,17 @@ """Utilities for testing.""" -from contextlib import contextmanager -from distutils.version import LooseVersion -from functools import partial import io import json import operator import sys import warnings +from contextlib import contextmanager +from distutils.version import LooseVersion +from functools import partial import numpy as np -from numpy.testing import assert_array_equal import scipy # type: ignore +from numpy.testing import assert_array_equal @contextmanager @@ -37,24 +37,21 @@ 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) @@ -66,21 +63,21 @@ def assert_arrays_equal(arrays1, arrays2): 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..7358aaf8e 100644 --- a/fury/tests/test_actors.py +++ b/fury/tests/test_actors.py @@ -7,7 +7,8 @@ import pytest from scipy.ndimage import center_of_mass -from fury import actor, primitive as fp, shaders, window +from fury import actor, shaders, window +from fury import primitive as fp from fury.actor import grid from fury.decorators import skip_linux, skip_osx, skip_win from fury.deprecator import ExpiredDeprecationError @@ -16,16 +17,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 +41,6 @@ class Sphere: - vertices = None faces = None @@ -60,7 +58,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 +80,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 +92,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 +139,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 +161,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 +177,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 +188,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 +229,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 +241,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 +288,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 +351,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 +401,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 +419,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 +431,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 +453,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 +474,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 +499,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 +539,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 +563,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 +596,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 +660,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 +731,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 +740,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 +892,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 +905,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 +987,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 +1135,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 +1146,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 +1183,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 +1270,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 +1304,7 @@ def test_grid(_interactive=False): scene.add(container) - scene.projection('orthogonal') + scene.projection("orthogonal") counter = itertools.count() @@ -1356,7 +1352,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 +1374,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 +1391,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 +1407,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 +1425,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 +1445,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 +1458,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 +1474,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 +1573,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 +1588,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 +1630,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 +1642,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 +1656,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 +1670,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 +1686,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 +1702,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 +1732,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 +1795,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 +1847,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 +1866,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 +1878,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 +1891,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..14b79a117 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(): @@ -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..f3b9f8a70 100644 --- a/fury/tests/test_gltf.py +++ b/fury/tests/test_gltf.py @@ -1,12 +1,11 @@ import itertools import os -import sys -from PIL import Image import numpy as np import numpy.testing as npt -from packaging.version import parse import pytest +from packaging.version import parse +from PIL import Image from scipy.ndimage import center_of_mass from scipy.version import short_version @@ -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..d92789490 100644 --- a/fury/tests/test_interactor.py +++ b/fury/tests/test_interactor.py @@ -5,18 +5,19 @@ import numpy.testing as npt import pytest -from fury import actor, interactor, ui, utils as vtk_utils, window +from fury import actor, interactor, ui, window +from fury import utils as vtk_utils 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 +49,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 +70,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 +98,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 +120,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 +166,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 +216,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..a959e239b 100644 --- a/fury/tests/test_io.py +++ b/fury/tests/test_io.py @@ -2,10 +2,10 @@ from os.path import join as pjoin from tempfile import TemporaryDirectory as InTemporaryDirectory -from PIL import Image import numpy as np import numpy.testing as npt import pytest +from PIL import Image from fury.decorators import skip_osx from fury.io import ( @@ -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,23 +44,23 @@ 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): with InTemporaryDirectory() as odir: @@ -69,7 +69,7 @@ def test_save_and_load_options(): 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,11 +80,11 @@ 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): @@ -94,7 +94,7 @@ def test_save_and_load_options(): 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..f15652e5d 100644 --- a/fury/tests/test_material.py +++ b/fury/tests/test_material.py @@ -1,20 +1,16 @@ -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 +88,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 +114,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 +122,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..768b39783 100644 --- a/fury/tests/test_molecular.py +++ b/fury/tests/test_molecular.py @@ -1,21 +1,22 @@ import numpy as np import numpy.testing as npt -from fury import molecular as mol, window +from fury import molecular as mol +from fury import window 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 +33,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 +67,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 +150,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 +177,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 +189,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 +225,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 +237,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 +265,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 +299,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..e19e5a178 100644 --- a/fury/tests/test_stream.py +++ b/fury/tests/test_stream.py @@ -1,7 +1,7 @@ import asyncio -from importlib import reload import sys import time +from importlib import reload from unittest import mock import numpy as np @@ -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..e563f6964 100644 --- a/fury/tests/test_testing.py +++ b/fury/tests/test_testing.py @@ -5,24 +5,24 @@ import numpy as np import numpy.testing as npt +import fury.testing as ft from fury import window from fury.lib import Actor2D -import fury.testing as ft from fury.ui.core import UI 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 +47,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 +88,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 +102,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=2) 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=2) 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=2) 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=2) assert_warn_len_equal(my_mod, 2) diff --git a/fury/tests/test_thread.py b/fury/tests/test_thread.py index 1427ffb74..2495c1e2e 100644 --- a/fury/tests/test_thread.py +++ b/fury/tests/test_thread.py @@ -1,10 +1,7 @@ - -from threading import Thread import time +from threading import Thread 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..814710893 100644 --- a/fury/tests/test_utils.py +++ b/fury/tests/test_utils.py @@ -3,6 +3,7 @@ import numpy.testing as npt import pytest +import fury.primitive as fp from fury import actor, utils, window from fury.lib import ( VTK_DOUBLE, @@ -20,7 +21,6 @@ numpy_support, ) from fury.optpkg import optional_package -import fury.primitive as fp from fury.ui.containers import Panel2D from fury.ui.core import UI from fury.utils import ( @@ -55,16 +55,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) @@ -77,6 +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() + npt.assert_array_almost_equal(initial_bounds, text_bounds, decimal=0) affine = np.eye(4) affine[:3, -1] += (-text_bounds[1], 0, 0) @@ -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..2534e6f38 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -1,33 +1,33 @@ """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", ] +import os from collections import OrderedDict from numbers import Number -import os from string import printable from urllib.request import urlopen -from PIL import Image, UnidentifiedImageError import numpy as np +from PIL import Image, UnidentifiedImageError from fury.data import read_viz_icons from fury.lib import Command @@ -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,15 @@ def get_file_names(self): """ # A list of file names with extension in the current directory - for (_, _, files) in os.walk(self.current_directory): - break + files = [f for _, _, f in os.walk(self.current_directory)] 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 +3251,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 +3282,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 +3329,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 +3369,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 +3384,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 +3432,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 +3477,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 +3500,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 +3554,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 +3572,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 +3588,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 +3606,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 +3624,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 +3657,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 +3676,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 +3714,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 +3742,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 +3783,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 +3795,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 +3838,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 +3870,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 +3955,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 +4059,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 +4091,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 +4182,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 +4237,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 +4262,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 +4271,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 +4285,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 +4334,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 +4355,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 +4401,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 +4417,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 +4426,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 +4447,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 +4512,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 +4550,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..9cb0fc5ac 100644 --- a/fury/ui/tests/test_core.py +++ b/fury/ui/tests/test_core.py @@ -1,6 +1,5 @@ """Core module testing.""" from os.path import join as pjoin -import warnings import numpy as np import numpy.testing as npt @@ -11,9 +10,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 +22,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 +52,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 +60,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 +93,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 +218,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 +275,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 +384,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 +399,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..fc93c6de6 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -1,18 +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 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 +27,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 +52,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 +70,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 +89,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 +106,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 +125,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 +142,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 +161,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 +178,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 +197,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 +216,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 +269,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 +301,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 +326,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 +340,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 +350,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 +394,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 +407,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 +432,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 +483,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 +545,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 +556,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 +579,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 +605,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 +622,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 +657,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 +683,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 +699,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 +721,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 +743,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 +790,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 +812,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 +829,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 +857,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 +891,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 +903,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 +923,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 +938,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 +961,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 +990,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 +1006,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 +1046,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 +1067,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 +1087,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 +1097,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 +1110,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 +1139,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 +1163,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 +1183,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 +1195,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 +1216,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 +1228,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 +1254,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 +1309,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 +1323,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 +1358,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 +1372,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 +1415,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..4795d669f 100644 --- a/fury/ui/tests/test_elements_callback.py +++ b/fury/ui/tests/test_elements_callback.py @@ -1,19 +1,14 @@ """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 +74,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 +130,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 +144,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..55d907cc8 100644 --- a/fury/ui/tests/test_helpers.py +++ b/fury/ui/tests/test_helpers.py @@ -13,88 +13,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 +139,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..e3bbee3f6 100644 --- a/fury/window.py +++ b/fury/window.py @@ -1,15 +1,15 @@ # -*- coding: utf-8 -*- import gzip +import time from tempfile import TemporaryDirectory as InTemporaryDirectory from threading import Lock -import time from warnings import warn import numpy as np from scipy import ndimage -from fury import __version__ as fury_version import fury.animation as anim +from fury import __version__ as fury_version from fury.interactor import CustomInteractorStyle from fury.io import load_image, save_image from fury.lib import ( @@ -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..c89c70517 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,19 +97,43 @@ 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.ruff] +line-length = 88 +target-version = "py38" +force-exclude = true +extend-exclude = [ + "__pycache__", + "build", + "_version.py", + "docs/experimental/**", +] + +[tool.ruff.format] +quote-style = "double" + +[tool.ruff.lint] +select = [ + "F", + "E", + "C", + "W", + "B", + "I", +] +ignore = [ + "C901", + "E203" +] + +[tool.ruff.lint.extend-per-file-ignores] +"docs/examples/**" = ["I001"] +"docs/source/conf.py" = ["E402"] + +[tool.ruff.lint.flake8-quotes] +inline-quotes = "double" + +[tool.ruff.lint.isort] +known-first-party=["fury"] [tool.mypy] python_version = "3.11"