From 8a1d884a86427ed7339f66f26bd6dec523f45478 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Mon, 31 Mar 2025 12:07:50 +0200 Subject: [PATCH 1/5] use ruff --- .github/workflows/{black.yml => lint.yml} | 0 pyproject.toml | 18 +++++++----------- 2 files changed, 7 insertions(+), 11 deletions(-) rename .github/workflows/{black.yml => lint.yml} (100%) diff --git a/.github/workflows/black.yml b/.github/workflows/lint.yml similarity index 100% rename from .github/workflows/black.yml rename to .github/workflows/lint.yml diff --git a/pyproject.toml b/pyproject.toml index 846c9070b..e8287aafc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ dependencies = [ ] [project.optional-dependencies] +lint = ["ruff"] docs = [ "sphinx", "sphinx-gallery", @@ -56,7 +57,7 @@ tests = [ "tqdm", ] imgui = ["imgui-bundle"] -dev = ["fastplotlib[docs,notebook,tests,imgui]"] +dev = ["fastplotlib[lint,docs,notebook,tests,imgui]"] [project.urls] Homepage = "https://www.fastplotlib.org/" @@ -71,14 +72,9 @@ build-backend = "flit_core.buildapi" # ===== Tooling -# [tool.ruff] -# line-length = 88 +[tool.ruff] +line-length = 88 -# [tool.ruff.lint] -# select = ["F", "E", "W", "N", "B", "RUF", "TC"] -# ignore = [ -# "E501", # Line too long -# "E731", # Do not assign a `lambda` expression, use a `def` -# "B019", # Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks -# "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`" -# ] +[tool.ruff.lint] +select = ["F", "E", "W", "N", "B", "RUF", "TC"] +ignore = [] From de242bc9b52f2b7e02bba9deddbdda7a78ce2d8f Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Mon, 31 Mar 2025 12:08:37 +0200 Subject: [PATCH 2/5] Update lint ci job --- .github/workflows/lint.yml | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index cebee50a0..5b4a15bf8 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -name: black +name: lint on: push: @@ -15,10 +15,24 @@ on: jobs: lint: + name: Test Linting + timeout-minutes: 5 runs-on: ubuntu-latest - if: ${{ !github.event.pull_request.draft }} + strategy: + fail-fast: false steps: - - uses: actions/checkout@v4 - - uses: psf/black@stable - with: - src: "./fastplotlib" + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ruff + - name: Ruff lint + run: | + ruff check --output-format=github . + - name: Ruff format + run: | + ruff format --check . From e8ac5fcb5a09853333861a560685fdbb968bc38a Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Mon, 31 Mar 2025 12:09:04 +0200 Subject: [PATCH 3/5] Actually run ruff --- docs/source/conf.py | 10 +- docs/source/generate_api.py | 15 +-- examples/gridplot/gridplot_viewports_check.py | 6 +- examples/gridplot/multigraphic_gridplot.py | 13 +-- examples/guis/image_widget_imgui.py | 16 ++- examples/guis/imgui_basic.py | 28 ++++-- examples/image/image_small.py | 5 +- examples/image_widget/image_widget_grid.py | 2 +- examples/image_widget/image_widget_videos.py | 2 +- examples/line/line_cmap.py | 10 +- examples/line/line_cmap_more.py | 12 ++- examples/line/line_colorslice.py | 24 ++--- .../line_collection_cmap_values.py | 1 + ...line_collection_cmap_values_qualitative.py | 12 +-- examples/line_collection/line_stack.py | 4 +- examples/line_collection/line_stack_3d.py | 4 +- examples/machine_learning/covariance.py | 1 - examples/machine_learning/kmeans.py | 23 ++--- examples/misc-dev/garbage_collection.py | 6 +- examples/misc-dev/selector_performance.ipynb | 30 +++--- examples/misc/cycle_animation.py | 13 ++- examples/misc/em_wave_animation.py | 42 ++++---- examples/misc/image_animation.py | 1 + examples/misc/line3d_animation.py | 4 +- examples/misc/lorenz_animation.py | 16 +-- examples/misc/multiplot_animation.py | 10 +- examples/misc/scatter_animation.py | 4 +- examples/misc/scatter_sizes_animation.py | 2 + examples/misc/simple_event.py | 4 +- examples/notebooks/image_widget.ipynb | 18 ++-- examples/notebooks/image_widget_test.ipynb | 18 ++-- .../multiprocessing_zmq_plot.ipynb | 8 +- examples/notebooks/nb_test_utils.py | 9 +- examples/notebooks/quickstart.ipynb | 98 +++++++++++-------- examples/notebooks/test_gc.ipynb | 18 ++-- examples/qt/embed.py | 5 +- examples/qt/imagewidget.py | 5 +- examples/scatter/scatter_cmap_iris.py | 6 +- examples/scatter/scatter_colorslice_iris.py | 2 +- examples/scatter/scatter_dataslice.py | 8 +- examples/scatter/scatter_dataslice_iris.py | 4 +- examples/scatter/scatter_iris.py | 4 +- examples/scatter/spinning_spiral.py | 24 +++-- examples/selection_tools/fft.py | 19 +++- .../linear_region_line_collection.py | 1 - .../selection_tools/linear_region_selector.py | 2 +- .../linear_region_selectors_match_offsets.py | 2 +- examples/selection_tools/linear_selector.py | 51 +++++----- .../selection_tools/linear_selector_image.py | 2 +- .../selection_tools/rectangle_selector.py | 4 +- .../rectangle_selector_zoom.py | 6 +- examples/selection_tools/unit_circle.py | 7 +- examples/tests/test_examples.py | 10 +- examples/window_layouts/extent_frac_layout.py | 9 +- examples/window_layouts/extent_layout.py | 9 +- examples/window_layouts/rect_frac_layout.py | 9 +- examples/window_layouts/rect_layout.py | 9 +- fastplotlib/graphics/_base.py | 3 +- fastplotlib/graphics/_features/_base.py | 2 +- fastplotlib/graphics/image.py | 1 - fastplotlib/graphics/line_collection.py | 6 +- fastplotlib/graphics/selectors/_rectangle.py | 2 - fastplotlib/utils/functions.py | 1 - fastplotlib/widgets/image_widget/_widget.py | 1 - scripts/generate_add_graphic_methods.py | 2 +- tests/conftest.py | 4 +- tests/test_positions_graphics.py | 7 +- tests/test_texture_array.py | 1 - 68 files changed, 382 insertions(+), 335 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 865c462a6..542e2c18c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -44,7 +44,7 @@ "sphinx.ext.viewcode", "sphinx_copybutton", "sphinx_design", - "sphinx_gallery.gen_gallery" + "sphinx_gallery.gen_gallery", ] sphinx_gallery_conf = { @@ -70,9 +70,9 @@ "../../examples/qt", ] ), - "ignore_pattern": r'__init__\.py', + "ignore_pattern": r"__init__\.py", "nested_sections": False, - "thumbnail_size": (250, 250) + "thumbnail_size": (250, 250), } extra_conf = find_examples_for_gallery(EXAMPLES_DIR) @@ -100,8 +100,8 @@ "check_switcher": True, "switcher": { "json_url": "http://www.fastplotlib.org/_static/switcher.json", - "version_match": release - } + "version_match": release, + }, } html_static_path = ["_static"] diff --git a/docs/source/generate_api.py b/docs/source/generate_api.py index 6887566cb..912f6ff08 100644 --- a/docs/source/generate_api.py +++ b/docs/source/generate_api.py @@ -42,15 +42,10 @@ "fastplotlib\n" "***********\n\n" ".. currentmodule:: fastplotlib\n\n" - ".. autofunction:: fastplotlib.pause_events\n\n" - ".. autofunction:: fastplotlib.enumerate_adapters\n\n" - ".. autofunction:: fastplotlib.select_adapter\n\n" - ".. autofunction:: fastplotlib.print_wgpu_report\n\n" - "fastplotlib.loop\n" "------------------\n" "See the rendercanvas docs: https://rendercanvas.readthedocs.io/stable/api.html#rendercanvas.BaseLoop " @@ -60,7 +55,6 @@ f.write( "fastplotlib.utils\n" "*****************\n\n" - "..currentmodule:: fastplotlib.utils\n" "..automodule:: fastplotlib.utils.functions\n" " : members:\n" @@ -161,13 +155,7 @@ def generate_page( ): page_name_underline = "*" * len(page_name) with open(source_path, "w") as f: - f.write( - f".. _api.{page_name}:\n" - f"\n" - f"{page_name}\n" - f"{page_name_underline}\n" - f"\n" - ) + f.write(f".. _api.{page_name}:\n\n{page_name}\n{page_name_underline}\n\n") for cls, module in zip(classes, modules): to_write = generate_class(cls, module) @@ -362,5 +350,6 @@ def main(): " utils\n" ) + if __name__ == "__main__": main() diff --git a/examples/gridplot/gridplot_viewports_check.py b/examples/gridplot/gridplot_viewports_check.py index 99584b411..9d19c2807 100644 --- a/examples/gridplot/gridplot_viewports_check.py +++ b/examples/gridplot/gridplot_viewports_check.py @@ -12,11 +12,7 @@ import numpy as np -figure = fpl.Figure( - shape=(2, 3), - size=(700, 560), - names=list(map(str, range(6))) -) +figure = fpl.Figure(shape=(2, 3), size=(700, 560), names=list(map(str, range(6)))) np.random.seed(0) a = np.random.rand(6, 10, 10) diff --git a/examples/gridplot/multigraphic_gridplot.py b/examples/gridplot/multigraphic_gridplot.py index 1bed60b31..9d9a28f2a 100644 --- a/examples/gridplot/multigraphic_gridplot.py +++ b/examples/gridplot/multigraphic_gridplot.py @@ -17,7 +17,7 @@ figure = fpl.Figure( shape=(2, 2), names=[["image-overlay", "circles"], ["line-stack", "scatter"]], - size=(700, 560) + size=(700, 560), ) img = iio.imread("imageio:coffee.png") @@ -36,6 +36,7 @@ # add overlay to image figure["image-overlay"].add_image(data=overlay) + # generate some circles def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: theta = np.linspace(0, 2 * np.pi, n_points) @@ -54,12 +55,7 @@ def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: circles.append(make_circle(center, 5, n_points=75)) # things like class labels, cluster labels, etc. -cmap_transform = [ - 0, 1, 1, 2, - 0, 0, 1, 1, - 2, 2, 8, 3, - 1, 9, 1, 5 -] +cmap_transform = [0, 1, 1, 2, 0, 0, 1, 1, 2, 2, 8, 3, 1, 9, 1, 5] # add an image to overlay the circles on img2 = iio.imread("imageio:coins.png")[10::5, 5::5] @@ -73,7 +69,7 @@ def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: cmap_transform=cmap_transform, thickness=3, alpha=0.5, - name="circles-graphic" + name="circles-graphic", ) # move the circles graphic so that it is centered over the image @@ -115,4 +111,3 @@ def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: if __name__ == "__main__": print(__doc__) fpl.loop.run() - diff --git a/examples/guis/image_widget_imgui.py b/examples/guis/image_widget_imgui.py index 13d41af20..c535d93fa 100644 --- a/examples/guis/image_widget_imgui.py +++ b/examples/guis/image_widget_imgui.py @@ -41,14 +41,18 @@ def update(self): something_changed = False # slider for gaussian filter sigma value - changed, value = imgui.slider_float(label="sigma", v=self.sigma, v_min=0.0, v_max=20.0) + changed, value = imgui.slider_float( + label="sigma", v=self.sigma, v_min=0.0, v_max=20.0 + ) if changed: self.sigma = value something_changed = True # int entries for gaussian filter order for axis in ["x", "y"]: - changed, value = imgui.input_int(f"order {axis}", v=getattr(self, f"order_{axis}")) + changed, value = imgui.input_int( + f"order {axis}", v=getattr(self, f"order_{axis}") + ) if changed: if value < 0: value = 0 @@ -63,11 +67,15 @@ def update(self): # do not call imgui.end_frame(), this is handled by Figure def process_image(self): - processed = gaussian_filter(a, sigma=self.sigma, order=(self.order_y, self.order_x)) + processed = gaussian_filter( + a, sigma=self.sigma, order=(self.order_y, self.order_x) + ) iw.set_data(processed) -gui = ImageProcessingWindow(iw.figure, size=200, location="right", title="Gaussian Filter") +gui = ImageProcessingWindow( + iw.figure, size=200, location="right", title="Gaussian Filter" +) iw.figure.add_gui(gui) diff --git a/examples/guis/imgui_basic.py b/examples/guis/imgui_basic.py index eac39121c..659f030c5 100644 --- a/examples/guis/imgui_basic.py +++ b/examples/guis/imgui_basic.py @@ -29,10 +29,14 @@ figure = fpl.Figure(size=(700, 560)) # make some scatter points at every 10th point -figure[0, 0].add_scatter(data[::10], colors="cyan", sizes=15, name="sine-scatter", uniform_color=True) +figure[0, 0].add_scatter( + data[::10], colors="cyan", sizes=15, name="sine-scatter", uniform_color=True +) # place a line above the scatter -figure[0, 0].add_line(data, thickness=3, colors="r", name="sine-wave", uniform_color=True) +figure[0, 0].add_line( + data, thickness=3, colors="r", name="sine-wave", uniform_color=True +) class ImguiExample(EdgeWindow): @@ -60,7 +64,9 @@ def update(self): # get current line color alpha value alpha = self._line.colors[-1] # make float slider - changed_alpha, new_alpha = imgui.slider_float("alpha", v=alpha, v_min=0.0, v_max=1.0) + changed_alpha, new_alpha = imgui.slider_float( + "alpha", v=alpha, v_min=0.0, v_max=1.0 + ) # if RGB or alpha changed if changed_color | changed_alpha: @@ -68,19 +74,25 @@ def update(self): self._line.colors = [*rgb, new_alpha] # example of a slider, you can also use input_float - changed, amplitude = imgui.slider_float("amplitude", v=self._amplitude, v_max=10, v_min=0.1) + changed, amplitude = imgui.slider_float( + "amplitude", v=self._amplitude, v_max=10, v_min=0.1 + ) if changed: # set y values self._amplitude = amplitude self._set_data() # slider for thickness - changed, thickness = imgui.slider_float("thickness", v=self._line.thickness, v_max=50.0, v_min=2.0) + changed, thickness = imgui.slider_float( + "thickness", v=self._line.thickness, v_max=50.0, v_min=2.0 + ) if changed: self._line.thickness = thickness # slider for gaussian noise - changed, sigma = imgui.slider_float("noise-sigma", v=self._sigma, v_max=1.0, v_min=0.0) + changed, sigma = imgui.slider_float( + "noise-sigma", v=self._sigma, v_max=1.0, v_min=0.0 + ) if changed: self._sigma = sigma self._set_data() @@ -99,7 +111,9 @@ def update(self): self._set_data() def _set_data(self): - self._line.data[:, 1] = (np.sin(xs) * self._amplitude) + np.random.normal(scale=self._sigma, size=100) + self._line.data[:, 1] = (np.sin(xs) * self._amplitude) + np.random.normal( + scale=self._sigma, size=100 + ) # make GUI instance diff --git a/examples/image/image_small.py b/examples/image/image_small.py index eebc49797..2e5a5103c 100644 --- a/examples/image/image_small.py +++ b/examples/image/image_small.py @@ -14,10 +14,7 @@ figure = fpl.Figure(size=(700, 560)) -data = np.array( - [[0, 1, 2], - [3, 4, 5]] -) +data = np.array([[0, 1, 2], [3, 4, 5]]) image_graphic = figure[0, 0].add_image(data) figure.show() diff --git a/examples/image_widget/image_widget_grid.py b/examples/image_widget/image_widget_grid.py index f52f38bc5..b827ab600 100644 --- a/examples/image_widget/image_widget_grid.py +++ b/examples/image_widget/image_widget_grid.py @@ -18,7 +18,7 @@ iw = fpl.ImageWidget( data=[img1, img2, img3, img4], - rgb=[False, True, True, True], # mix of grayscale and RGB images + rgb=[False, True, True, True], # mix of grayscale and RGB images names=["cameraman", "astronaut", "chelsea", "Almar's cat"], # ImageWidget will sync controllers by default # by setting `controller_ids=None` we can have independent controllers for each subplot diff --git a/examples/image_widget/image_widget_videos.py b/examples/image_widget/image_widget_videos.py index 7de4a9c04..9e3c07246 100644 --- a/examples/image_widget/image_widget_videos.py +++ b/examples/image_widget/image_widget_videos.py @@ -29,7 +29,7 @@ [random_data, cockatoo_sub], rgb=[False, True], figure_shape=(2, 1), # 2 rows, 1 column - figure_kwargs={"size": (700, 940)} + figure_kwargs={"size": (700, 940)}, ) iw.show() diff --git a/examples/line/line_cmap.py b/examples/line/line_cmap.py index b2fb39779..5900009b6 100644 --- a/examples/line/line_cmap.py +++ b/examples/line/line_cmap.py @@ -24,19 +24,13 @@ # cmap_transform from an array, so the colors on the sine line will be based on the sine y-values sine_graphic = figure[0, 0].add_line( - data=sine, - thickness=10, - cmap="plasma", - cmap_transform=sine[:, 1] + data=sine, thickness=10, cmap="plasma", cmap_transform=sine[:, 1] ) # qualitative colormaps, useful for cluster labels or other types of categorical labels labels = [0] * 25 + [5] * 10 + [1] * 35 + [2] * 30 cosine_graphic = figure[0, 0].add_line( - data=cosine, - thickness=10, - cmap="tab10", - cmap_transform=labels + data=cosine, thickness=10, cmap="tab10", cmap_transform=labels ) figure.show() diff --git a/examples/line/line_cmap_more.py b/examples/line/line_cmap_more.py index 37fd68cdb..6432aa9c0 100644 --- a/examples/line/line_cmap_more.py +++ b/examples/line/line_cmap_more.py @@ -31,16 +31,22 @@ # set colormap by mapping data using a transform # here we map the color using the y-values of the sine data # i.e., the color is a function of sine(x) -line2 = figure[0, 0].add_line(sine, thickness=10, cmap="jet", cmap_transform=sine[:, 1], offset=(0, 4, 0)) +line2 = figure[0, 0].add_line( + sine, thickness=10, cmap="jet", cmap_transform=sine[:, 1], offset=(0, 4, 0) +) # make a line and change the cmap afterward, here we are using the cosine instead fot the transform -line3 = figure[0, 0].add_line(sine, thickness=10, cmap="jet", cmap_transform=cosine[:, 1], offset=(0, 6, 0)) +line3 = figure[0, 0].add_line( + sine, thickness=10, cmap="jet", cmap_transform=cosine[:, 1], offset=(0, 6, 0) +) # change the cmap line3.cmap = "bwr" # use quantitative colormaps with categorical cmap_transforms labels = [0] * 25 + [1] * 5 + [2] * 50 + [3] * 20 -line4 = figure[0, 0].add_line(sine, thickness=10, cmap="tab10", cmap_transform=labels, offset=(0, 8, 0)) +line4 = figure[0, 0].add_line( + sine, thickness=10, cmap="tab10", cmap_transform=labels, offset=(0, 8, 0) +) # some text labels for i in range(5): diff --git a/examples/line/line_colorslice.py b/examples/line/line_colorslice.py index 788aa342d..86cefacb4 100644 --- a/examples/line/line_colorslice.py +++ b/examples/line/line_colorslice.py @@ -27,36 +27,30 @@ ys = np.sinc(xs) * 3 sinc = np.column_stack([xs, ys]) -sine_graphic = figure[0, 0].add_line( - data=sine, - thickness=5, - colors="magenta" -) +sine_graphic = figure[0, 0].add_line(data=sine, thickness=5, colors="magenta") # you can also use colormaps for lines! cosine_graphic = figure[0, 0].add_line( data=cosine, thickness=12, cmap="autumn", - offset=(0, 3, 0) # places the graphic at a y-axis offset of 3, offsets don't affect data + offset=( + 0, + 3, + 0, + ), # places the graphic at a y-axis offset of 3, offsets don't affect data ) # or a list of colors for each datapoint colors = ["r"] * 25 + ["purple"] * 25 + ["y"] * 25 + ["b"] * 25 sinc_graphic = figure[0, 0].add_line( - data=sinc, - thickness=5, - colors=colors, - offset=(0, 6, 0) + data=sinc, thickness=5, colors=colors, offset=(0, 6, 0) ) zeros = np.zeros(xs.size) zeros_data = np.column_stack([xs, zeros]) zeros_graphic = figure[0, 0].add_line( - data=zeros_data, - thickness=8, - colors="w", - offset=(0, 10, 0) + data=zeros_data, thickness=8, colors="w", offset=(0, 10, 0) ) figure.show() @@ -67,7 +61,7 @@ cosine_graphic.colors[60] = "w" # more complex indexing, set the blue value directly from an array -cosine_graphic.colors[65:90, 0] = np.linspace(0, 1, 90-65) +cosine_graphic.colors[65:90, 0] = np.linspace(0, 1, 90 - 65) # additional fancy indexing using numpy key = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 67, 19]) diff --git a/examples/line_collection/line_collection_cmap_values.py b/examples/line_collection/line_collection_cmap_values.py index c577609f9..59d0c2088 100644 --- a/examples/line_collection/line_collection_cmap_values.py +++ b/examples/line_collection/line_collection_cmap_values.py @@ -12,6 +12,7 @@ import numpy as np import fastplotlib as fpl + def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: theta = np.linspace(0, 2 * np.pi, n_points) xs = radius * np.sin(theta) diff --git a/examples/line_collection/line_collection_cmap_values_qualitative.py b/examples/line_collection/line_collection_cmap_values_qualitative.py index 7b1c0a419..e4df93300 100644 --- a/examples/line_collection/line_collection_cmap_values_qualitative.py +++ b/examples/line_collection/line_collection_cmap_values_qualitative.py @@ -34,20 +34,12 @@ def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: # qualitative colormap used for mapping 16 cmap values for each line # for example, these could be cluster labels -cmap_values = [ - 0, 1, 1, 2, - 0, 0, 1, 1, - 2, 2, 3, 3, - 1, 1, 1, 5 -] +cmap_values = [0, 1, 1, 2, 0, 0, 1, 1, 2, 2, 3, 3, 1, 1, 1, 5] figure = fpl.Figure(size=(700, 560)) figure[0, 0].add_line_collection( - circles, - cmap="tab10", - cmap_transform=cmap_values, - thickness=10 + circles, cmap="tab10", cmap_transform=cmap_values, thickness=10 ) # remove clutter diff --git a/examples/line_collection/line_stack.py b/examples/line_collection/line_stack.py index 95b681b76..3d2088753 100644 --- a/examples/line_collection/line_stack.py +++ b/examples/line_collection/line_stack.py @@ -21,7 +21,9 @@ figure = fpl.Figure(size=(700, 560)) -line_stack = figure[0, 0].add_line_stack( +line_stack = figure[ + 0, 0 +].add_line_stack( multi_data, # shape: (10, 100, 2), i.e. [n_lines, n_points, xy] cmap="jet", # applied along n_lines thickness=5, diff --git a/examples/line_collection/line_stack_3d.py b/examples/line_collection/line_stack_3d.py index 35fe48ca9..0c34d8d6e 100644 --- a/examples/line_collection/line_stack_3d.py +++ b/examples/line_collection/line_stack_3d.py @@ -26,7 +26,9 @@ # make grid invisible to remove clutter figure[0, 0].axes.grids.visible = False -line_stack = figure[0, 0].add_line_stack( +line_stack = figure[ + 0, 0 +].add_line_stack( multi_data, # shape: (10, 100, 2), i.e. [n_lines, n_points, xy] cmap="jet", # applied along n_lines thickness=3, diff --git a/examples/machine_learning/covariance.py b/examples/machine_learning/covariance.py index 84c5bf531..8f7a74df0 100644 --- a/examples/machine_learning/covariance.py +++ b/examples/machine_learning/covariance.py @@ -8,7 +8,6 @@ # test_example = false # sphinx_gallery_pygfx_docs = 'animate 10s' - import fastplotlib as fpl from sklearn import datasets from sklearn.preprocessing import StandardScaler diff --git a/examples/machine_learning/kmeans.py b/examples/machine_learning/kmeans.py index 0aae8fdae..71f993265 100644 --- a/examples/machine_learning/kmeans.py +++ b/examples/machine_learning/kmeans.py @@ -21,8 +21,8 @@ mnist = load_digits() # get the data and labels -data = mnist['data'] # (1797, 64) -labels = mnist['target'] # (1797,) +data = mnist["data"] # (1797, 64) +labels = mnist["target"] # (1797,) # visualize the first 5 digits # NOTE: this is just to give a sense of the dataset if you are unfamiliar, @@ -44,7 +44,7 @@ # project the data from 64 dimensions down to the number of unique digits n_digits = len(np.unique(labels)) # 10 -reduced_data = PCA(n_components=n_digits).fit_transform(data) # (1797, 10) +reduced_data = PCA(n_components=n_digits).fit_transform(data) # (1797, 10) # performs K-Means clustering, take the best of 4 runs kmeans = KMeans(n_clusters=n_digits, n_init=4) @@ -59,7 +59,7 @@ shape=(1, 2), size=(700, 560), cameras=["3d", "2d"], - controller_types=["fly", "panzoom"] + controller_types=["fly", "panzoom"], ) # set the axes to False in the image subplot @@ -72,14 +72,14 @@ figure[0, 0].add_scatter( data=np.vstack([centroids[:, 0], centroids[:, 1], centroids[:, 2]]).T, colors="white", - sizes=15 + sizes=15, ) # plot the down-projected data -digit_scatter = figure[0,0].add_scatter( +digit_scatter = figure[0, 0].add_scatter( data=np.vstack([reduced_data[:, 0], reduced_data[:, 1], reduced_data[:, 2]]).T, sizes=5, - cmap="tab10", # use a qualitative cmap - cmap_transform=kmeans.labels_, # color by the predicted cluster + cmap="tab10", # use a qualitative cmap + cmap_transform=kmeans.labels_, # color by the predicted cluster ) # initial index @@ -87,10 +87,7 @@ # plot the initial image digit_img = figure[0, 1].add_image( - data=data[ix].reshape(8,8), - cmap="gray", - name="digit", - interpolation="linear" + data=data[ix].reshape(8, 8), cmap="gray", name="digit", interpolation="linear" ) # change the color and size of the initial selected data point @@ -122,4 +119,4 @@ def update(ev): # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": print(__doc__) - fpl.loop.run() \ No newline at end of file + fpl.loop.run() diff --git a/examples/misc-dev/garbage_collection.py b/examples/misc-dev/garbage_collection.py index baa92e848..b7bde86b9 100644 --- a/examples/misc-dev/garbage_collection.py +++ b/examples/misc-dev/garbage_collection.py @@ -28,7 +28,11 @@ def draw(): def print_nvidia(msg=""): print(msg) print( - subprocess.check_output(["nvidia-smi", "--format=csv", "--query-gpu=memory.used"]).decode().split("\n")[1] + subprocess.check_output( + ["nvidia-smi", "--format=csv", "--query-gpu=memory.used"] + ) + .decode() + .split("\n")[1] ) print() diff --git a/examples/misc-dev/selector_performance.ipynb b/examples/misc-dev/selector_performance.ipynb index 39dbba6b8..459753e80 100644 --- a/examples/misc-dev/selector_performance.ipynb +++ b/examples/misc-dev/selector_performance.ipynb @@ -27,15 +27,17 @@ }, "outputs": [], "source": [ - "def make_circle(center: Tuple[float, float], radius: float, n_points: int = 50) -> np.ndarray:\n", + "def make_circle(\n", + " center: Tuple[float, float], radius: float, n_points: int = 50\n", + ") -> np.ndarray:\n", " theta = np.linspace(0, 2 * np.pi, n_points)\n", " xs = radius * np.sin(theta)\n", " ys = radius * np.cos(theta)\n", " zs = np.zeros(xs.size)\n", - " \n", + "\n", " xs += center[0]\n", " ys += center[1]\n", - " \n", + "\n", " return np.ascontiguousarray(np.column_stack([xs, ys, zs]).astype(np.float32))" ] }, @@ -163,7 +165,7 @@ "\n", "for l in lines[100:1000]:\n", " l.visible = False\n", - " \n", + "\n", "# canvas.request_draw()\n", "\n", "time() - t1" @@ -186,7 +188,7 @@ " ys = np.sin(xs) * 10\n", " else:\n", " ys = np.cos(xs) * 10\n", - " \n", + "\n", " temporal.append(ys)" ] }, @@ -233,7 +235,7 @@ "def update_visible(ev):\n", " ixs_visible = ev.pick_info[\"selected_indices\"]\n", " ixs_hide = np.setdiff1d(np.arange(len(circles)), ixs_visible)\n", - " \n", + "\n", " # very fast, 20 ms to change 1,000\n", " for i, g in enumerate(contours.graphics):\n", " if not g.visible and i in ixs_visible:\n", @@ -320,10 +322,10 @@ "\n", "for c in contours.graphics[100:1000]:\n", " c.visible = True\n", - " \n", + "\n", "# for i in range(100, 1000):\n", "# contours.graphics[i].world_object.visible = True\n", - " \n", + "\n", "time() - t1" ] }, @@ -342,7 +344,7 @@ "for c in circles:\n", " start_offset += c.shape[0]\n", " zero_alpha_ixs += [start_offset - 1, start_offset]\n", - " \n", + "\n", "zero_alpha_ixs = zero_alpha_ixs[:-1]" ] }, @@ -370,13 +372,13 @@ "def set_visible_alpha(ev):\n", " ixs_visible = ev.pick_info[\"selected_indices\"]\n", " ixs_hide = np.setdiff1d(np.arange(len(circles)), ixs_visible)\n", - " \n", + "\n", " for i in ixs_visible:\n", - " contours.world_object.geometry.colors.data[(i * 75) + 1:(i * 75) + 74, -1] = 1\n", - " \n", + " contours.world_object.geometry.colors.data[(i * 75) + 1 : (i * 75) + 74, -1] = 1\n", + "\n", " for i in ixs_hide:\n", - " contours.world_object.geometry.colors.data[(i * 75) + 1:(i * 75) + 74, -1] = 0\n", - " \n", + " contours.world_object.geometry.colors.data[(i * 75) + 1 : (i * 75) + 74, -1] = 0\n", + "\n", " contours.world_object.geometry.colors.update_range()" ] }, diff --git a/examples/misc/cycle_animation.py b/examples/misc/cycle_animation.py index e369b957c..053c89ef0 100644 --- a/examples/misc/cycle_animation.py +++ b/examples/misc/cycle_animation.py @@ -37,18 +37,23 @@ figure = fpl.Figure(size=(700, 560)) subplot_scatter = figure[0, 0] # use an alpha value since this will be a lot of points -scatter_graphic = subplot_scatter.add_scatter(data=cloud, sizes=3, colors=colors, alpha=0.6) +scatter_graphic = subplot_scatter.add_scatter( + data=cloud, sizes=3, colors=colors, alpha=0.6 +) i = 0.05 + + def cycle_colors(subplot): global i # cycle the red values - scatter_graphic.colors[n_points * 2:, 0] = np.abs(np.sin(i)) - scatter_graphic.colors[n_points * 2:, 1] = np.abs(np.sin(i + (np.pi / 4))) - scatter_graphic.colors[n_points * 2:, 2] = np.abs(np.cos(i)) + scatter_graphic.colors[n_points * 2 :, 0] = np.abs(np.sin(i)) + scatter_graphic.colors[n_points * 2 :, 1] = np.abs(np.sin(i + (np.pi / 4))) + scatter_graphic.colors[n_points * 2 :, 2] = np.abs(np.cos(i)) i += 0.05 + subplot_scatter.add_animations(cycle_colors) figure.show() diff --git a/examples/misc/em_wave_animation.py b/examples/misc/em_wave_animation.py index 06c60ccaf..d7433e0c8 100644 --- a/examples/misc/em_wave_animation.py +++ b/examples/misc/em_wave_animation.py @@ -11,11 +11,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure( - cameras="3d", - controller_types="orbit", - size=(700, 560) -) +figure = fpl.Figure(cameras="3d", controller_types="orbit", size=(700, 560)) start, stop = 0, 4 * np.pi @@ -37,28 +33,36 @@ figure[0, 0].add_line(magnetic, colors="red", thickness=2, name="m") # draw vector line at every 10th position -electric_vectors = [np.array([[0, 0, z], [x, 0, z]]) for (x, z) in zip(e_xs[::10], zs[::10])] -magnetic_vectors = [np.array([[0, 0, z], [0, y, z]]) for (y, z) in zip(m_ys[::10], zs[::10])] +electric_vectors = [ + np.array([[0, 0, z], [x, 0, z]]) for (x, z) in zip(e_xs[::10], zs[::10]) +] +magnetic_vectors = [ + np.array([[0, 0, z], [0, y, z]]) for (y, z) in zip(m_ys[::10], zs[::10]) +] # add as a line collection -figure[0, 0].add_line_collection(electric_vectors, colors="blue", thickness=1.5, name="e-vec") -figure[0, 0].add_line_collection(magnetic_vectors, colors="red", thickness=1.5, name="m-vec") +figure[0, 0].add_line_collection( + electric_vectors, colors="blue", thickness=1.5, name="e-vec" +) +figure[0, 0].add_line_collection( + magnetic_vectors, colors="red", thickness=1.5, name="m-vec" +) # note that the z_offset in `add_line_collection` is not data-related # it is the z-offset for where to place the *graphic*, by default with Orthographic cameras (i.e. 2D views) # it will increment by 1 for each line in the collection, we want to disable this so set z_position=0 # just a pre-saved camera state state = { - 'position': np.array([-8.0 , 6.0, -2.0]), - 'rotation': np.array([0.09, 0.9 , 0.2, -0.5]), - 'scale': np.array([1., 1., 1.]), - 'reference_up': np.array([0., 1., 0.]), - 'fov': 50.0, - 'width': 12, - 'height': 12, - 'zoom': 1.35, - 'maintain_aspect': True, - 'depth_range': None + "position": np.array([-8.0, 6.0, -2.0]), + "rotation": np.array([0.09, 0.9, 0.2, -0.5]), + "scale": np.array([1.0, 1.0, 1.0]), + "reference_up": np.array([0.0, 1.0, 0.0]), + "fov": 50.0, + "width": 12, + "height": 12, + "zoom": 1.35, + "maintain_aspect": True, + "depth_range": None, } diff --git a/examples/misc/image_animation.py b/examples/misc/image_animation.py index bc5f83957..2f3559156 100644 --- a/examples/misc/image_animation.py +++ b/examples/misc/image_animation.py @@ -25,6 +25,7 @@ def update_data(figure_instance): new_data = np.random.rand(512, 512) figure_instance[0, 0]["random-image"].data = new_data + figure.add_animations(update_data) figure.show() diff --git a/examples/misc/line3d_animation.py b/examples/misc/line3d_animation.py index b26bfd3a0..292d77dd8 100644 --- a/examples/misc/line3d_animation.py +++ b/examples/misc/line3d_animation.py @@ -23,9 +23,9 @@ figure = fpl.Figure(cameras="3d", size=(700, 560)) -line_graphic = figure[0,0].add_line(data=spiral, thickness=3, cmap='jet') +line_graphic = figure[0, 0].add_line(data=spiral, thickness=3, cmap="jet") -marker = figure[0,0].add_scatter(data=spiral[0], sizes=10, name="marker") +marker = figure[0, 0].add_scatter(data=spiral[0], sizes=10, name="marker") marker_index = 0 diff --git a/examples/misc/lorenz_animation.py b/examples/misc/lorenz_animation.py index 4d4c5129f..927565d99 100644 --- a/examples/misc/lorenz_animation.py +++ b/examples/misc/lorenz_animation.py @@ -41,7 +41,7 @@ def lorenz(xyz, *, s=10, r=28, b=2.667): for i in range(5): xyzs = np.empty((num_steps + 1, 3)) # Need one more for the initial values - xyzs[0] = (0., (i * 0.3) + 1, 1.05) # Set initial values + xyzs[0] = (0.0, (i * 0.3) + 1, 1.05) # Set initial values # Step through "time", calculating the partial derivatives at the current point # and using them to estimate the next point for j in range(num_steps): @@ -49,18 +49,18 @@ def lorenz(xyz, *, s=10, r=28, b=2.667): lorenz_data[i] = xyzs -figure = fpl.Figure( - cameras="3d", - controller_types="fly", - size=(700, 560) -) +figure = fpl.Figure(cameras="3d", controller_types="fly", size=(700, 560)) -lorenz_line = figure[0, 0].add_line_collection(data=lorenz_data, thickness=.1, cmap="tab10") +lorenz_line = figure[0, 0].add_line_collection( + data=lorenz_data, thickness=0.1, cmap="tab10" +) scatter_markers = list() for graphic in lorenz_line: - marker = figure[0, 0].add_scatter(graphic.data.value[0], sizes=16, colors=graphic.colors[0]) + marker = figure[0, 0].add_scatter( + graphic.data.value[0], sizes=16, colors=graphic.colors[0] + ) scatter_markers.append(marker) # initialize time diff --git a/examples/misc/multiplot_animation.py b/examples/misc/multiplot_animation.py index 18512add1..3b4ce33d6 100644 --- a/examples/misc/multiplot_animation.py +++ b/examples/misc/multiplot_animation.py @@ -21,10 +21,11 @@ # add an image to the subplot subplot.add_image(data, name="rand-img") -figure[0,1]["rand-img"].cmap = "viridis" -figure[1,0]["rand-img"].cmap = "Wistia" -figure[0,2]["rand-img"].cmap = "gray" -figure[1,1]["rand-img"].cmap = "spring" +figure[0, 1]["rand-img"].cmap = "viridis" +figure[1, 0]["rand-img"].cmap = "Wistia" +figure[0, 2]["rand-img"].cmap = "gray" +figure[1, 1]["rand-img"].cmap = "spring" + # Define a function to update the image graphics with new data # add_animations will pass the gridplot to the animation function @@ -34,6 +35,7 @@ def update_data(f): # index the image graphic by name and set the data subplot["rand-img"].data = new_data + # add the animation function figure.add_animations(update_data) diff --git a/examples/misc/scatter_animation.py b/examples/misc/scatter_animation.py index d85a33e6a..77b866b39 100644 --- a/examples/misc/scatter_animation.py +++ b/examples/misc/scatter_animation.py @@ -37,7 +37,9 @@ figure = fpl.Figure(size=(700, 560)) subplot_scatter = figure[0, 0] # use an alpha value since this will be a lot of points -scatter_graphic = subplot_scatter.add_scatter(data=cloud, sizes=3, colors=colors, alpha=0.6) +scatter_graphic = subplot_scatter.add_scatter( + data=cloud, sizes=3, colors=colors, alpha=0.6 +) def update_points(subplot): diff --git a/examples/misc/scatter_sizes_animation.py b/examples/misc/scatter_sizes_animation.py index 45782564d..4b48b69d8 100644 --- a/examples/misc/scatter_sizes_animation.py +++ b/examples/misc/scatter_sizes_animation.py @@ -24,6 +24,8 @@ i = 0 + + def update_sizes(subplot): global i diff --git a/examples/misc/simple_event.py b/examples/misc/simple_event.py index e382f04b5..6ec9aacff 100644 --- a/examples/misc/simple_event.py +++ b/examples/misc/simple_event.py @@ -17,7 +17,7 @@ figure = fpl.Figure(size=(700, 560)) # plot sine wave, use a single color -image_graphic = figure[0,0].add_image(data=data) +image_graphic = figure[0, 0].add_image(data=data) # show the plot figure.show() @@ -41,7 +41,7 @@ def click_event(event_data): xy = (event_data.x, event_data.y) # map the screen coordinates to world coordinates - xy = figure[0,0].map_screen_to_world(xy)[:-1] + xy = figure[0, 0].map_screen_to_world(xy)[:-1] # print the click location print(xy) diff --git a/examples/notebooks/image_widget.ipynb b/examples/notebooks/image_widget.ipynb index 5136ba028..eb85c9fb3 100644 --- a/examples/notebooks/image_widget.ipynb +++ b/examples/notebooks/image_widget.ipynb @@ -45,10 +45,7 @@ }, "outputs": [], "source": [ - "iw = ImageWidget(\n", - " data=a,\n", - " cmap=\"viridis\"\n", - ")" + "iw = ImageWidget(data=a, cmap=\"viridis\")" ] }, { @@ -113,10 +110,7 @@ }, "outputs": [], "source": [ - "iw_movie = ImageWidget(\n", - " data=gray_movie, \n", - " cmap=\"gray\"\n", - ")" + "iw_movie = ImageWidget(data=gray_movie, cmap=\"gray\")" ] }, { @@ -231,7 +225,7 @@ "outputs": [], "source": [ "iw_movie.set_data(new_data=new_data)\n", - "iw_movie.figure[0, 0].auto_scale()# sidecar is optional" + "iw_movie.figure[0, 0].auto_scale() # sidecar is optional" ] }, { @@ -299,7 +293,7 @@ " data=[zfish_data[:, i] for i in range(n_planes)],\n", " window_funcs={\"t\": (np.mean, 5)},\n", " names=[f\"plane-{i}\" for i in range(n_planes)],\n", - " cmap=\"gnuplot2\", \n", + " cmap=\"gnuplot2\",\n", ")" ] }, @@ -439,9 +433,9 @@ "outputs": [], "source": [ "iw_z = ImageWidget(\n", - " data=zfish_data, # you can also provide a list of tzxy arrays\n", + " data=zfish_data, # you can also provide a list of tzxy arrays\n", " window_funcs={\"t\": (np.mean, 5)},\n", - " cmap=\"gnuplot2\", \n", + " cmap=\"gnuplot2\",\n", ")" ] }, diff --git a/examples/notebooks/image_widget_test.ipynb b/examples/notebooks/image_widget_test.ipynb index 2c05db6b0..2c263d915 100644 --- a/examples/notebooks/image_widget_test.ipynb +++ b/examples/notebooks/image_widget_test.ipynb @@ -127,7 +127,7 @@ "outputs": [], "source": [ "iw_movie = ImageWidget(\n", - " data=gray_movie, \n", + " data=gray_movie,\n", " cmap=\"gray\",\n", " figure_kwargs={\"size\": (900, 600)},\n", ")" @@ -287,7 +287,7 @@ " data=[zfish_data[:, i] for i in range(n_planes)],\n", " window_funcs={\"t\": (np.mean, 5)},\n", " names=[f\"plane-{i}\" for i in range(n_planes)],\n", - " cmap=\"gnuplot2\", \n", + " cmap=\"gnuplot2\",\n", " figure_kwargs={\"size\": (900, 600)},\n", ")" ] @@ -351,15 +351,13 @@ "source": [ "# reverse planes and test set_data\n", "iw_zfish.set_data(\n", - " [zfish_data[:, i] for i in range(n_planes - 1, -1, -1)],\n", - " reset_indices=False\n", + " [zfish_data[:, i] for i in range(n_planes - 1, -1, -1)], reset_indices=False\n", ")\n", "\n", "plot_test(\"image-widget-zfish-grid-set_data-reset-indices-false\", iw_zfish.figure)\n", "\n", "iw_zfish.set_data(\n", - " [zfish_data[:, i] for i in range(n_planes - 1, -1, -1)],\n", - " reset_indices=True\n", + " [zfish_data[:, i] for i in range(n_planes - 1, -1, -1)], reset_indices=True\n", ")\n", "plot_test(\"image-widget-zfish-grid-set_data-reset-indices-true\", iw_zfish.figure)" ] @@ -392,9 +390,9 @@ "outputs": [], "source": [ "iw_z = ImageWidget(\n", - " data=zfish_data, # you can also provide a list of tzxy arrays\n", + " data=zfish_data, # you can also provide a list of tzxy arrays\n", " window_funcs={\"t\": (np.mean, 5)},\n", - " cmap=\"gnuplot2\", \n", + " cmap=\"gnuplot2\",\n", " figure_kwargs={\"size\": (900, 600)},\n", ")" ] @@ -480,10 +478,10 @@ "movie = iio.imread(\"imageio:cockatoo.mp4\")\n", "\n", "iw_mixed_shapes = ImageWidget(\n", - " data=[zfish_frame_1, movie], # you can also provide a list of tzxy arrays\n", + " data=[zfish_frame_1, movie], # you can also provide a list of tzxy arrays\n", " rgb=[False, True],\n", " histogram_widget=True,\n", - " cmap=\"gnuplot2\", \n", + " cmap=\"gnuplot2\",\n", " figure_kwargs={\"controller_ids\": None, \"size\": (900, 400)},\n", ")\n", "\n", diff --git a/examples/notebooks/multiprocessing_zmq/multiprocessing_zmq_plot.ipynb b/examples/notebooks/multiprocessing_zmq/multiprocessing_zmq_plot.ipynb index 564512451..c1365e33e 100644 --- a/examples/notebooks/multiprocessing_zmq/multiprocessing_zmq_plot.ipynb +++ b/examples/notebooks/multiprocessing_zmq/multiprocessing_zmq_plot.ipynb @@ -49,7 +49,7 @@ " pass\n", " else:\n", " return b\n", - " \n", + "\n", " return None" ] }, @@ -66,17 +66,19 @@ "data = np.random.rand(512, 512).astype(np.float32)\n", "fig[0, 0].add_image(data, name=\"image\")\n", "\n", + "\n", "def update_frame(subplot):\n", " # recieve bytes\n", " b = get_bytes()\n", - " \n", + "\n", " if b is not None:\n", " # numpy array from bytes, MUST specify dtype and make sure it matches what you sent\n", " a = np.frombuffer(b, dtype=np.float32).reshape(512, 512)\n", - " \n", + "\n", " # set graphic data\n", " subplot[\"image\"].data = a\n", "\n", + "\n", "fig[0, 0].add_animations(update_frame)\n", "fig.show()" ] diff --git a/examples/notebooks/nb_test_utils.py b/examples/notebooks/nb_test_utils.py index 9d99e3be3..466022fb4 100644 --- a/examples/notebooks/nb_test_utils.py +++ b/examples/notebooks/nb_test_utils.py @@ -31,6 +31,7 @@ # TODO: consolidate testing functions into one module so we don't have this separate one for notebooks + def rgba_to_rgb(img: np.ndarray) -> np.ndarray: black = np.zeros(img.shape).astype(np.uint8) black[:, :, -1] = 255 @@ -149,9 +150,7 @@ def assert_screenshot_equal(name, data): update_diffs(name, similar, data, ground_truth) if not similar: - FAILURES.append( - (name, rmse) - ) + FAILURES.append((name, rmse)) def update_diffs(name, is_similar, img, ground_truth): @@ -193,6 +192,4 @@ def notebook_finished(): return if len(FAILURES) > 0: - raise AssertionError( - f"Failures for plots:\n{FAILURES}" - ) + raise AssertionError(f"Failures for plots:\n{FAILURES}") diff --git a/examples/notebooks/quickstart.ipynb b/examples/notebooks/quickstart.ipynb index 737aee3e7..c8d233abb 100644 --- a/examples/notebooks/quickstart.ipynb +++ b/examples/notebooks/quickstart.ipynb @@ -561,16 +561,19 @@ "# plot the data\n", "fig_v[0, 0].add_image(data=data, name=\"random-image\")\n", "\n", + "\n", "# a function to update the image_graphic\n", "# a figure-level animation function will optionally take the figure as an argument\n", "def update_data(figure_instance):\n", " new_data = np.random.rand(512, 512)\n", " figure_instance[0, 0][\"random-image\"].data = new_data\n", "\n", + "\n", "# you can also add animation functions to individual subplots\n", "def update_data_subplot(subplot_instance):\n", " pass\n", "\n", + "\n", "# add this as an animation function\n", "fig_v.add_animations(update_data)\n", "\n", @@ -604,12 +607,14 @@ "\n", "image_graphic_instance = fig_sync[0, 0].add_image(data=data, cmap=\"viridis\")\n", "\n", + "\n", "# you will need to define a new animation function for this graphic\n", "def update_data_2():\n", " new_data = np.random.rand(512, 512)\n", " # alternatively, you can use the stored reference to the graphic as well instead of indexing the subplot\n", " image_graphic_instance.data = new_data\n", "\n", + "\n", "fig_sync.add_animations(update_data_2)\n", "\n", "fig_sync.show()" @@ -727,7 +732,7 @@ "\n", "# or a list of colors for each datapoint\n", "colors = [\"r\"] * 25 + [\"purple\"] * 25 + [\"y\"] * 25 + [\"b\"] * 25\n", - "sinc_graphic = subplot.add_line(data=sinc, thickness=5, colors = colors)\n", + "sinc_graphic = subplot.add_line(data=sinc, thickness=5, colors=colors)\n", "\n", "# show the plot\n", "fig_lines.show(sidecar=True, sidecar_kwargs={\"title\": \"lines\"})" @@ -803,7 +808,7 @@ "sine_graphic.cmap = \"seismic\"\n", "\n", "# more complex indexing, set the blue value directly from an array\n", - "cosine_graphic.colors[65:90, 0] = np.linspace(0, 1, 90-65)" + "cosine_graphic.colors[65:90, 0] = np.linspace(0, 1, 90 - 65)" ] }, { @@ -824,6 +829,7 @@ "def callback_func(event_data):\n", " print(event_data)\n", "\n", + "\n", "# Will print event data when the color changes\n", "cosine_graphic.add_event_handler(callback_func, \"colors\")" ] @@ -983,12 +989,12 @@ "metadata": {}, "outputs": [], "source": [ - "# increment along the x-axis on each render loop :D \n", + "# increment along the x-axis on each render loop :D\n", "def update_line(subplot):\n", " global increment, start, stop\n", " xs = np.linspace(start + increment, stop + increment, 100)\n", " ys = np.sin(xs)\n", - " \n", + "\n", " start += increment\n", " stop += increment\n", "\n", @@ -1074,7 +1080,7 @@ "# note: you usually mix 3D and 2D graphics on the same plot\n", "spiral = np.column_stack([xs, ys, zs])\n", "\n", - "fig_l3d[0, 0].add_line(data=spiral, thickness=2, cmap='winter')\n", + "fig_l3d[0, 0].add_line(data=spiral, thickness=2, cmap=\"winter\")\n", "\n", "fig_l3d.show()" ] @@ -1189,11 +1195,7 @@ "metadata": {}, "outputs": [], "source": [ - "fig_em = fpl.Figure(\n", - " cameras=\"3d\", \n", - " controller_types=\"orbit\", \n", - " size=(700, 400)\n", - ")\n", + "fig_em = fpl.Figure(cameras=\"3d\", controller_types=\"orbit\", size=(700, 400))\n", "\n", "start, stop = 0, 4 * np.pi\n", "\n", @@ -1215,12 +1217,20 @@ "fig_em[0, 0].add_line(magnetic, colors=\"red\", thickness=2, name=\"m\")\n", "\n", "# draw vector line at every 10th position\n", - "electric_vectors = [np.array([[0, 0, z], [x, 0, z]]) for (x, z) in zip(e_xs[::10], zs[::10])]\n", - "magnetic_vectors = [np.array([[0, 0, z], [0, y, z]]) for (y, z) in zip(m_ys[::10], zs[::10])]\n", + "electric_vectors = [\n", + " np.array([[0, 0, z], [x, 0, z]]) for (x, z) in zip(e_xs[::10], zs[::10])\n", + "]\n", + "magnetic_vectors = [\n", + " np.array([[0, 0, z], [0, y, z]]) for (y, z) in zip(m_ys[::10], zs[::10])\n", + "]\n", "\n", "# add as a line collection\n", - "fig_em[0, 0].add_line_collection(electric_vectors, colors=\"blue\", thickness=1.5, name=\"e-vec\")\n", - "fig_em[0, 0].add_line_collection(magnetic_vectors, colors=\"red\", thickness=1.5, name=\"m-vec\")\n", + "fig_em[0, 0].add_line_collection(\n", + " electric_vectors, colors=\"blue\", thickness=1.5, name=\"e-vec\"\n", + ")\n", + "fig_em[0, 0].add_line_collection(\n", + " magnetic_vectors, colors=\"red\", thickness=1.5, name=\"m-vec\"\n", + ")\n", "\n", "# axes are a WIP, just draw a white line along z for now\n", "z_axis = np.array([[0, 0, 0], [0, 0, stop]])\n", @@ -1228,16 +1238,16 @@ "\n", "# just a pre-saved camera state\n", "state = {\n", - " 'position': np.array([-8.0 , 6.0, -2.0]),\n", - " 'rotation': np.array([0.09, 0.9 , 0.2, -0.5]),\n", - " 'scale': np.array([1., 1., 1.]),\n", - " 'reference_up': np.array([0., 1., 0.]),\n", - " 'fov': 50.0,\n", - " 'width': 12,\n", - " 'height': 12,\n", - " 'zoom': 1.35,\n", - " 'maintain_aspect': True,\n", - " 'depth_range': None\n", + " \"position\": np.array([-8.0, 6.0, -2.0]),\n", + " \"rotation\": np.array([0.09, 0.9, 0.2, -0.5]),\n", + " \"scale\": np.array([1.0, 1.0, 1.0]),\n", + " \"reference_up\": np.array([0.0, 1.0, 0.0]),\n", + " \"fov\": 50.0,\n", + " \"width\": 12,\n", + " \"height\": 12,\n", + " \"zoom\": 1.35,\n", + " \"maintain_aspect\": True,\n", + " \"depth_range\": None,\n", "}\n", "\n", "\n", @@ -1273,6 +1283,7 @@ "source": [ "increment = np.pi * 4 / 100\n", "\n", + "\n", "# moves the wave one step along the z-axis\n", "def tick(subplot):\n", " global increment, start, stop, zs\n", @@ -1288,10 +1299,11 @@ " for i, (value, z) in enumerate(zip(new_data[::10], zs[::10])):\n", " subplot[\"e-vec\"].graphics[i].data = np.array([[0, 0, z], [value, 0, z]])\n", " subplot[\"m-vec\"].graphics[i].data = np.array([[0, 0, z], [0, value, z]])\n", - " \n", + "\n", " start += increment\n", " stop += increment\n", "\n", + "\n", "fig_em[0, 0].add_animations(tick)" ] }, @@ -1327,9 +1339,9 @@ "# create a random distribution of 10,000 xyz coordinates\n", "n_points = 10_000\n", "\n", - "# if you have a good GPU go for 1.5 million points :D \n", + "# if you have a good GPU go for 1.5 million points :D\n", "# this is multiplied by 3\n", - "#n_points = 500_000\n", + "# n_points = 500_000\n", "\n", "# dimensions always have to be [n_points, xyz]\n", "dims = (n_points, 3)\n", @@ -1354,7 +1366,9 @@ "fig_scatter = fpl.Figure()\n", "subplot_scatter = fig_scatter[0, 0]\n", "# use an alpha value since this will be a lot of points\n", - "scatter_graphic = subplot_scatter.add_scatter(data=cloud, sizes=3, colors=colors, alpha=0.6)\n", + "scatter_graphic = subplot_scatter.add_scatter(\n", + " data=cloud, sizes=3, colors=colors, alpha=0.6\n", + ")\n", "\n", "fig_scatter.show(sidecar=True)" ] @@ -1397,7 +1411,7 @@ "outputs": [], "source": [ "# set the green value directly\n", - "scatter_graphic.colors[n_points:n_points * 2, 1] = 0.3" + "scatter_graphic.colors[n_points : n_points * 2, 1] = 0.3" ] }, { @@ -1408,7 +1422,7 @@ "outputs": [], "source": [ "# set color values directly using an array\n", - "scatter_graphic.colors[n_points * 2:] = np.repeat([[1, 1, 0, 0.5]], n_points, axis=0)" + "scatter_graphic.colors[n_points * 2 :] = np.repeat([[1, 1, 0, 0.5]], n_points, axis=0)" ] }, { @@ -1419,7 +1433,7 @@ "outputs": [], "source": [ "# change the data, change y-values\n", - "scatter_graphic.data[n_points:n_points * 2, 1] += 15" + "scatter_graphic.data[n_points : n_points * 2, 1] += 15" ] }, { @@ -1430,7 +1444,7 @@ "outputs": [], "source": [ "# set x values directly but using an array\n", - "scatter_graphic.data[n_points:n_points * 2, 0] = np.linspace(-40, 0, n_points)" + "scatter_graphic.data[n_points : n_points * 2, 0] = np.linspace(-40, 0, n_points)" ] }, { @@ -1474,6 +1488,7 @@ " deltas = np.random.normal(size=scatter_graphic.data.value.shape, loc=0, scale=0.15)\n", " scatter_graphic.data = scatter_graphic.data[:] + deltas\n", "\n", + "\n", "subplot_scatter.add_animations(update_points)" ] }, @@ -1493,14 +1508,17 @@ "outputs": [], "source": [ "i = 0.05\n", + "\n", + "\n", "def cycle_colors(subplot):\n", " global i\n", " # cycle the red values\n", - " scatter_graphic.colors[n_points * 2:, 0] = np.abs(np.sin(i))\n", - " scatter_graphic.colors[n_points * 2:, 1] = np.abs(np.sin(i + (np.pi / 4)))\n", - " scatter_graphic.colors[n_points * 2:, 2] = np.abs(np.cos(i))\n", + " scatter_graphic.colors[n_points * 2 :, 0] = np.abs(np.sin(i))\n", + " scatter_graphic.colors[n_points * 2 :, 1] = np.abs(np.sin(i + (np.pi / 4)))\n", + " scatter_graphic.colors[n_points * 2 :, 2] = np.abs(np.cos(i))\n", " i += 0.05\n", "\n", + "\n", "subplot_scatter.add_animations(cycle_colors)" ] }, @@ -1550,6 +1568,7 @@ " # add an image to the subplot\n", " subplot.add_image(data, name=\"rand-img\")\n", "\n", + "\n", "# Define a function to update the image graphics with new data\n", "# add_animations will pass the gridplot to the animation function\n", "def update_data(f):\n", @@ -1558,6 +1577,7 @@ " # index the image graphic by name and set the data\n", " subplot[\"rand-img\"].data = new_data\n", "\n", + "\n", "# add the animation function\n", "figure_grid.add_animations(update_data)\n", "\n", @@ -1772,15 +1792,12 @@ "# same controller ID\n", "controller_ids = [\n", " [0, 3, 1], # id each controller with an integer\n", - " [2, 2, 3]\n", + " [2, 2, 3],\n", "]\n", "\n", "\n", "# you can give string names for each subplot within the gridplot\n", - "names = [\n", - " [\"subplot0\", \"subplot1\", \"subplot2\"],\n", - " [\"subplot3\", \"subplot4\", \"subplot5\"]\n", - "]\n", + "names = [[\"subplot0\", \"subplot1\", \"subplot2\"], [\"subplot3\", \"subplot4\", \"subplot5\"]]\n", "\n", "# Create the grid plot\n", "figure_grid = fpl.Figure(\n", @@ -1804,6 +1821,7 @@ " new_data = np.random.rand(512, 512)\n", " subplot[\"rand-image\"].data = new_data\n", "\n", + "\n", "# add the animation\n", "figure_grid.add_animations(set_random_frame)\n", "figure_grid.show()" diff --git a/examples/notebooks/test_gc.ipynb b/examples/notebooks/test_gc.ipynb index df08e7a2d..17c73a202 100644 --- a/examples/notebooks/test_gc.ipynb +++ b/examples/notebooks/test_gc.ipynb @@ -24,7 +24,9 @@ " for i in range(len(plot_objects)):\n", " with pytest.raises(ReferenceError) as failure:\n", " plot_objects[i]\n", - " pytest.fail(f\"GC failed for object: {plot_objects[i]} of type: {plot_objects[i].__class__.__name__}\")" + " pytest.fail(\n", + " f\"GC failed for object: {plot_objects[i]} of type: {plot_objects[i].__class__.__name__}\"\n", + " )" ] }, { @@ -112,7 +114,7 @@ "outputs": [], "source": [ "objects = list()\n", - "weakrefs = list() # used to make sure the real objs are garbage collected\n", + "weakrefs = list() # used to make sure the real objs are garbage collected\n", "for subplot in fig:\n", " for obj in subplot.objects:\n", " objects.append(obj)\n", @@ -205,21 +207,21 @@ "if fpl.IMGUI:\n", " # do image widget tests only if imgui is installed\n", " movies = [np.random.rand(100, 100, 100) for i in range(6)]\n", - " \n", + "\n", " iw = fpl.ImageWidget(movies)\n", - " \n", + "\n", " # add some events onto all the image graphics\n", " for g in iw.managed_graphics:\n", " for f in g._features:\n", " g.add_event_handler(feature_changed_handler, f)\n", - " \n", + "\n", " iw.show()\n", - " \n", + "\n", " old_graphics = [weakref.proxy(g) for g in iw.managed_graphics]\n", - " \n", + "\n", " # Test that setting new data with different dims clears old ImageGraphics\n", " new_movies = [np.random.rand(100, 200, 200) for i in range(6)]\n", - " \n", + "\n", " iw.set_data(new_movies)\n", " test_references(old_graphics)" ] diff --git a/examples/qt/embed.py b/examples/qt/embed.py index ba20c5084..e3b6d3715 100644 --- a/examples/qt/embed.py +++ b/examples/qt/embed.py @@ -42,10 +42,7 @@ def update_frame(ix): dock.setWidget(slider) # put the dock in the main window -main_window.addDockWidget( - QtCore.Qt.DockWidgetArea.BottomDockWidgetArea, - dock -) +main_window.addDockWidget(QtCore.Qt.DockWidgetArea.BottomDockWidgetArea, dock) # calling fig.show() is required to start the rendering loop qwidget = fig.show() diff --git a/examples/qt/imagewidget.py b/examples/qt/imagewidget.py index 8a5b8937c..b4e760f3f 100644 --- a/examples/qt/imagewidget.py +++ b/examples/qt/imagewidget.py @@ -24,10 +24,7 @@ # another image widget with multiple images images_list = [np.random.rand(100, 512, 512) for i in range(4)] -iw_mult = fpl.ImageWidget( - images_list, - cmap="viridis" -) +iw_mult = fpl.ImageWidget(images_list, cmap="viridis") widget_multi = iw_mult.show() widget_multi.resize(800, 800) diff --git a/examples/scatter/scatter_cmap_iris.py b/examples/scatter/scatter_cmap_iris.py index 139554dae..976444729 100644 --- a/examples/scatter/scatter_cmap_iris.py +++ b/examples/scatter/scatter_cmap_iris.py @@ -20,12 +20,14 @@ agg = AgglomerativeClustering(n_clusters=3) agg.fit_predict(data) -scatter_graphic = figure[0, 0].add_scatter( +scatter_graphic = figure[ + 0, 0 +].add_scatter( data=data[:, :-1], # use only xy data sizes=15, alpha=0.7, cmap="Set1", - cmap_transform=agg.labels_ # use the labels as a transform to map colors from the colormap + cmap_transform=agg.labels_, # use the labels as a transform to map colors from the colormap ) figure.show() diff --git a/examples/scatter/scatter_colorslice_iris.py b/examples/scatter/scatter_colorslice_iris.py index 725374ef7..d6a07016d 100644 --- a/examples/scatter/scatter_colorslice_iris.py +++ b/examples/scatter/scatter_colorslice_iris.py @@ -23,7 +23,7 @@ data=data[:, :-1], sizes=6, alpha=0.7, - colors=colors # use colors from the list of strings + colors=colors, # use colors from the list of strings ) figure.show() diff --git a/examples/scatter/scatter_dataslice.py b/examples/scatter/scatter_dataslice.py index 840553237..0cf8b4cad 100644 --- a/examples/scatter/scatter_dataslice.py +++ b/examples/scatter/scatter_dataslice.py @@ -24,13 +24,13 @@ gaussian_cloud2 = np.random.multivariate_normal(mean, covariance, n_points) # use an alpha value since this will be a lot of points -scatter1 = figure[0,0].add_scatter(data=gaussian_cloud, sizes=3) -scatter2 = figure[0,0].add_scatter(data=gaussian_cloud2, colors="r", sizes=3) +scatter1 = figure[0, 0].add_scatter(data=gaussian_cloud, sizes=3) +scatter2 = figure[0, 0].add_scatter(data=gaussian_cloud2, colors="r", sizes=3) figure.show() -scatter1.data[:500] = np.array([0 , 0, 0]) -scatter2.data[500:] = np.array([0 , 0, 0]) +scatter1.data[:500] = np.array([0, 0, 0]) +scatter2.data[500:] = np.array([0, 0, 0]) # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively # please see our docs for using fastplotlib interactively in ipython and jupyter diff --git a/examples/scatter/scatter_dataslice_iris.py b/examples/scatter/scatter_dataslice_iris.py index cc688eeb4..6f2736f8d 100644 --- a/examples/scatter/scatter_dataslice_iris.py +++ b/examples/scatter/scatter_dataslice_iris.py @@ -20,7 +20,9 @@ n_points = 50 colors = ["yellow"] * n_points + ["cyan"] * n_points + ["magenta"] * n_points -scatter_graphic = figure[0, 0].add_scatter(data=data[:, :-1], sizes=6, alpha=0.7, colors=colors) +scatter_graphic = figure[0, 0].add_scatter( + data=data[:, :-1], sizes=6, alpha=0.7, colors=colors +) figure.show() diff --git a/examples/scatter/scatter_iris.py b/examples/scatter/scatter_iris.py index e000d5a0a..b6b9c5395 100644 --- a/examples/scatter/scatter_iris.py +++ b/examples/scatter/scatter_iris.py @@ -23,7 +23,9 @@ n_points = 50 colors = ["yellow"] * n_points + ["cyan"] * n_points + ["magenta"] * n_points -scatter_graphic = figure[0, 0].add_scatter(data=data[:, :-1], sizes=6, alpha=0.7, colors=colors) +scatter_graphic = figure[0, 0].add_scatter( + data=data[:, :-1], sizes=6, alpha=0.7, colors=colors +) figure.show() diff --git a/examples/scatter/spinning_spiral.py b/examples/scatter/spinning_spiral.py index 56cdcb906..1b883b45b 100644 --- a/examples/scatter/spinning_spiral.py +++ b/examples/scatter/spinning_spiral.py @@ -29,9 +29,7 @@ sizes = np.abs(np.random.normal(loc=0, scale=1, size=n)) figure = fpl.Figure( - cameras="3d", - size=(700, 560), - canvas_kwargs={"max_fps": 500, "vsync": False} + cameras="3d", size=(700, 560), canvas_kwargs={"max_fps": 500, "vsync": False} ) spiral = figure[0, 0].add_scatter(data, cmap="viridis_r", alpha=0.5, sizes=sizes) @@ -58,16 +56,16 @@ def update(): # pre-saved camera state camera_state = { - 'position': np.array([-0.13046005, 20.09142224, 29.03347696]), - 'rotation': np.array([-0.44485092, 0.05335406, 0.11586037, 0.88647469]), - 'scale': np.array([1., 1., 1.]), - 'reference_up': np.array([0., 1., 0.]), - 'fov': 50.0, - 'width': 62.725074768066406, - 'height': 8.856056690216064, - 'zoom': 0.75, - 'maintain_aspect': True, - 'depth_range': None + "position": np.array([-0.13046005, 20.09142224, 29.03347696]), + "rotation": np.array([-0.44485092, 0.05335406, 0.11586037, 0.88647469]), + "scale": np.array([1.0, 1.0, 1.0]), + "reference_up": np.array([0.0, 1.0, 0.0]), + "fov": 50.0, + "width": 62.725074768066406, + "height": 8.856056690216064, + "zoom": 0.75, + "maintain_aspect": True, + "depth_range": None, } figure[0, 0].camera.set_state(camera_state) diff --git a/examples/selection_tools/fft.py b/examples/selection_tools/fft.py index f249f2c11..ad172d709 100644 --- a/examples/selection_tools/fft.py +++ b/examples/selection_tools/fft.py @@ -26,7 +26,14 @@ # create an ImageWidget to display all the images iw = fpl.ImageWidget( data=[image, log_abs_img_fft, zeros, zeros, zeros, zeros], - names=["image", "DFT", "selected", "FFT of selected", "not-selected", "IFFT of not-selected"], + names=[ + "image", + "DFT", + "selected", + "FFT of selected", + "not-selected", + "IFFT of not-selected", + ], figure_shape=(3, 2), # so we can see image and fft side by side figure_kwargs={"size": (700, 1024)}, histogram_widget=False, @@ -45,8 +52,14 @@ iw.managed_graphics[-1].cmap = "gray" # set contrast limits based on the full DFT for the DFT-selection images -iw.figure["selected"].graphics[0].vmin, iw.figure["selected"].graphics[0].vmax = log_abs_img_fft.min(), log_abs_img_fft.max() -iw.figure["not-selected"].graphics[0].vmin, iw.figure["not-selected"].graphics[0].vmax = log_abs_img_fft.min(), log_abs_img_fft.max() +iw.figure["selected"].graphics[0].vmin, iw.figure["selected"].graphics[0].vmax = ( + log_abs_img_fft.min(), + log_abs_img_fft.max(), +) +( + iw.figure["not-selected"].graphics[0].vmin, + iw.figure["not-selected"].graphics[0].vmax, +) = log_abs_img_fft.min(), log_abs_img_fft.max() iw.show() diff --git a/examples/selection_tools/linear_region_line_collection.py b/examples/selection_tools/linear_region_line_collection.py index 76739d784..5f8152a42 100644 --- a/examples/selection_tools/linear_region_line_collection.py +++ b/examples/selection_tools/linear_region_line_collection.py @@ -8,7 +8,6 @@ # test_example = false # sphinx_gallery_pygfx_docs = 'screenshot' - import fastplotlib as fpl import numpy as np diff --git a/examples/selection_tools/linear_region_selector.py b/examples/selection_tools/linear_region_selector.py index 6fa17db38..218dd3a91 100644 --- a/examples/selection_tools/linear_region_selector.py +++ b/examples/selection_tools/linear_region_selector.py @@ -19,7 +19,7 @@ # names for out subplots names = [ ["y = sine(x)", "x = sine(y), sine(y) > 0 = 0"], - ["zoomed sine(x)", "zoomed sine(y)"] + ["zoomed sine(x)", "zoomed sine(y)"], ] # 2 rows, 2 columns diff --git a/examples/selection_tools/linear_region_selectors_match_offsets.py b/examples/selection_tools/linear_region_selectors_match_offsets.py index b48e30f28..33e149568 100644 --- a/examples/selection_tools/linear_region_selectors_match_offsets.py +++ b/examples/selection_tools/linear_region_selectors_match_offsets.py @@ -14,7 +14,7 @@ # names for out subplots names = [ ["y = sine(x)", "x = sine(y), sine(y) > 0 = 0"], - ["zoomed sine(x)", "zoomed sine(y)"] + ["zoomed sine(x)", "zoomed sine(y)"], ] # 2 rows, 2 columns diff --git a/examples/selection_tools/linear_selector.py b/examples/selection_tools/linear_selector.py index 1edf6345c..9018ba470 100644 --- a/examples/selection_tools/linear_selector.py +++ b/examples/selection_tools/linear_selector.py @@ -23,10 +23,7 @@ image_data = multiplier * np.sin(image_xs) + multiplier * np.cos(image_ys) # create a figure -figure = fpl.Figure( - shape=(1, 2), - size=(700, 560) -) +figure = fpl.Figure(shape=(1, 2), size=(700, 560)) # line of a single sine wave from 0 - 10π line = figure[0, 0].add_line(sine, cmap="jet") @@ -34,14 +31,16 @@ # add a linear selector to the line line_selector = line.add_linear_selector() -line_selector_text = (f"x value: {line_selector.selection / np.pi:.2f}π\n" - f"y value: {line.data[0, 1]:.2f}\n" - f"index: {line_selector.get_selected_index()}") +line_selector_text = ( + f"x value: {line_selector.selection / np.pi:.2f}π\n" + f"y value: {line.data[0, 1]:.2f}\n" + f"index: {line_selector.get_selected_index()}" +) # a label that will change to display line data based on the linear selector line_selection_label = figure[0, 0].add_text( line_selector_text, - offset=(0., 1.75, 0.), + offset=(0.0, 1.75, 0.0), anchor="middle-left", font_size=32, face_color=line.colors[0], @@ -59,28 +58,33 @@ def line_selector_changed(ev): index = ev.get_selected_index() # set text to display selection data - line_selection_label.text = \ - (f"x value: {selection / np.pi:.2f}π\n" - f"y value: {line.data[index, 1]:.2f}\n" - f"index: {index}") + line_selection_label.text = ( + f"x value: {selection / np.pi:.2f}π\n" + f"y value: {line.data[index, 1]:.2f}\n" + f"index: {index}" + ) # set text color based on line color at selection index line_selection_label.face_color = line.colors[index] # line stack, sine and cosine wave -line_stack = figure[0, 1].add_line_stack([sine, cosine], colors=["magenta", "cyan"], separation=1) +line_stack = figure[0, 1].add_line_stack( + [sine, cosine], colors=["magenta", "cyan"], separation=1 +) line_stack_selector = line_stack.add_linear_selector() -line_stack_selector_text = (f"x value: {line_stack_selector.selection / np.pi:.2f}π\n" - f"index: {line_selector.get_selected_index()}\n" - f"sine y value: {line_stack[0].data[0, 1]:.2f}\n" - f"cosine y value: {line_stack[1].data[0, 1]:.2f}\n") +line_stack_selector_text = ( + f"x value: {line_stack_selector.selection / np.pi:.2f}π\n" + f"index: {line_selector.get_selected_index()}\n" + f"sine y value: {line_stack[0].data[0, 1]:.2f}\n" + f"cosine y value: {line_stack[1].data[0, 1]:.2f}\n" +) # a label that will change to display line_stack data based on the linear selector line_stack_selector_label = figure[0, 1].add_text( line_stack_selector_text, - offset=(0., 7.0, 0.), + offset=(0.0, 7.0, 0.0), anchor="middle-left", font_size=24, face_color="w", @@ -95,11 +99,12 @@ def line_stack_selector_changed(ev): index = ev.get_selected_index()[0] # set text to display selection data - line_stack_selector_label.text = \ - (f"x value: {selection / np.pi:.2f}π\n" - f"index: {index}\n" - f"sine y value: {line_stack[0].data[index, 1]:.2f}\n" - f"cosine y value: {line_stack[1].data[index, 1]:.2f}\n") + line_stack_selector_label.text = ( + f"x value: {selection / np.pi:.2f}π\n" + f"index: {index}\n" + f"sine y value: {line_stack[0].data[index, 1]:.2f}\n" + f"cosine y value: {line_stack[1].data[index, 1]:.2f}\n" + ) # add an event handler, you can also use a decorator diff --git a/examples/selection_tools/linear_selector_image.py b/examples/selection_tools/linear_selector_image.py index 00484aba7..57cc07b7c 100644 --- a/examples/selection_tools/linear_selector_image.py +++ b/examples/selection_tools/linear_selector_image.py @@ -17,7 +17,7 @@ figure = fpl.Figure( (1, 3), size=(700, 300), - names=[["image", "selected row data", "selected column data"]] + names=[["image", "selected row data", "selected column data"]], ) # create an image diff --git a/examples/selection_tools/rectangle_selector.py b/examples/selection_tools/rectangle_selector.py index 850937f7a..f85a2922e 100644 --- a/examples/selection_tools/rectangle_selector.py +++ b/examples/selection_tools/rectangle_selector.py @@ -13,9 +13,7 @@ from itertools import product # create a figure -figure = fpl.Figure( - size=(700, 560) -) +figure = fpl.Figure(size=(700, 560)) # generate some data diff --git a/examples/selection_tools/rectangle_selector_zoom.py b/examples/selection_tools/rectangle_selector_zoom.py index 33ba2ae2a..092acda16 100644 --- a/examples/selection_tools/rectangle_selector_zoom.py +++ b/examples/selection_tools/rectangle_selector_zoom.py @@ -12,10 +12,7 @@ import fastplotlib as fpl # create a figure -figure = fpl.Figure( - shape=(2, 1), - size=(700, 560) -) +figure = fpl.Figure(shape=(2, 1), size=(700, 560)) # add image image_graphic = figure[0, 0].add_image(data=iio.imread("imageio:camera.png")) @@ -44,6 +41,7 @@ def update_data(ev): # autoscale the plot figure[1, 0].auto_scale() + figure.show() # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively diff --git a/examples/selection_tools/unit_circle.py b/examples/selection_tools/unit_circle.py index 2850b1bc1..1307326cb 100644 --- a/examples/selection_tools/unit_circle.py +++ b/examples/selection_tools/unit_circle.py @@ -14,7 +14,6 @@ # test_example = false # sphinx_gallery_pygfx_docs = 'screenshot' - import numpy as np import fastplotlib as fpl @@ -52,9 +51,7 @@ def make_circle(center, radius: float, n_points: int) -> np.ndarray: # create a figure with 3 subplots figure = fpl.Figure( - extents=extents, - names=["unit circle", "sin(x)", "cos(x)"], - size=(700, 560) + extents=extents, names=["unit circle", "sin(x)", "cos(x)"], size=(700, 560) ) # set the axes to intersect at (0, 0, 0) to better illustrate the unit circle @@ -111,6 +108,7 @@ def set_circle_cmap(ev): # set circle cmap transform circle_graphic.cmap.transform = cmap_transform + # when the sine or cosine graphic is clicked, the cmap_transform # of the sine, cosine and circle line graphics are all set from # the y-values of the clicked line @@ -128,6 +126,7 @@ def set_x_val(ev): circle_radius.data[1, :-1] = circle_data[index] + # add same event handler to both graphics sine_selector.add_event_handler(set_x_val, "selection") cosine_selector.add_event_handler(set_x_val, "selection") diff --git a/examples/tests/test_examples.py b/examples/tests/test_examples.py index 7fbd32e2f..04a9bb53c 100644 --- a/examples/tests/test_examples.py +++ b/examples/tests/test_examples.py @@ -98,7 +98,9 @@ def test_example_screenshots(module, force_offscreen): if fpl.IMGUI: # there doesn't seem to be a resize event for the manual offscreen canvas - example.figure.imgui_renderer._backend.io.display_size = example.figure.canvas.get_logical_size() + example.figure.imgui_renderer._backend.io.display_size = ( + example.figure.canvas.get_logical_size() + ) # run this once so any edge widgets set their sizes and therefore the subplots get the correct rect # hacky but it works for now example.figure.imgui_renderer.render() @@ -148,9 +150,9 @@ def test_example_screenshots(module, force_offscreen): if os.environ["REGENERATE_SCREENSHOTS"] == "1": iio.imwrite(screenshot_path, rgb) - assert ( - screenshot_path.exists() - ), "found # test_example = true but no reference screenshot available" + assert screenshot_path.exists(), ( + "found # test_example = true but no reference screenshot available" + ) ref_img = iio.imread(screenshot_path) diff --git a/examples/window_layouts/extent_frac_layout.py b/examples/window_layouts/extent_frac_layout.py index 0c5293e09..174d8718a 100644 --- a/examples/window_layouts/extent_frac_layout.py +++ b/examples/window_layouts/extent_frac_layout.py @@ -41,8 +41,13 @@ # also give each subplot a name figure = fpl.Figure( extents=extents, - names=["astronaut image", "wikkie image", "astronaut histogram", "wikkie histogram"], - size=size + names=[ + "astronaut image", + "wikkie image", + "astronaut histogram", + "wikkie histogram", + ], + size=size, ) # add image to the corresponding subplots diff --git a/examples/window_layouts/extent_layout.py b/examples/window_layouts/extent_layout.py index e6facaaa2..b9f662e00 100644 --- a/examples/window_layouts/extent_layout.py +++ b/examples/window_layouts/extent_layout.py @@ -41,8 +41,13 @@ # also give each subplot a name figure = fpl.Figure( extents=extents, - names=["astronaut image", "wikkie image", "astronaut histogram", "wikkie histogram"], - size=size + names=[ + "astronaut image", + "wikkie image", + "astronaut histogram", + "wikkie histogram", + ], + size=size, ) # add image to the corresponding subplots diff --git a/examples/window_layouts/rect_frac_layout.py b/examples/window_layouts/rect_frac_layout.py index 072fa1107..f989c5fbf 100644 --- a/examples/window_layouts/rect_frac_layout.py +++ b/examples/window_layouts/rect_frac_layout.py @@ -41,8 +41,13 @@ # also give each subplot a name figure = fpl.Figure( rects=rects, - names=["astronaut image", "wikkie image", "astronaut histogram", "wikkie histogram"], - size=size + names=[ + "astronaut image", + "wikkie image", + "astronaut histogram", + "wikkie histogram", + ], + size=size, ) # add image to the corresponding subplots diff --git a/examples/window_layouts/rect_layout.py b/examples/window_layouts/rect_layout.py index 962b8a4f1..2e1b4a69a 100644 --- a/examples/window_layouts/rect_layout.py +++ b/examples/window_layouts/rect_layout.py @@ -41,8 +41,13 @@ # also give each subplot a name figure = fpl.Figure( rects=rects, - names=["astronaut image", "wikkie image", "astronaut histogram", "wikkie histogram"], - size=size + names=[ + "astronaut image", + "wikkie image", + "astronaut histogram", + "wikkie histogram", + ], + size=size, ) # add image to the corresponding subplots diff --git a/fastplotlib/graphics/_base.py b/fastplotlib/graphics/_base.py index 61ad291ee..1418899d2 100644 --- a/fastplotlib/graphics/_base.py +++ b/fastplotlib/graphics/_base.py @@ -466,8 +466,7 @@ def right_click_menu(self): def right_click_menu(self, menu): if not IMGUI: raise ImportError( - "imgui is required to set right-click menus:\n" - "pip install imgui_bundle" + "imgui is required to set right-click menus:\npip install imgui_bundle" ) self._right_click_menu = menu diff --git a/fastplotlib/graphics/_features/_base.py b/fastplotlib/graphics/_features/_base.py index 1088dc005..f9868c8a9 100644 --- a/fastplotlib/graphics/_features/_base.py +++ b/fastplotlib/graphics/_features/_base.py @@ -318,7 +318,7 @@ def __len__(self): raise NotImplementedError def __repr__(self): - return f"{self.__class__.__name__} buffer data:\n" f"{self.value.__repr__()}" + return f"{self.__class__.__name__} buffer data:\n{self.value.__repr__()}" def block_reentrance(set_value): diff --git a/fastplotlib/graphics/image.py b/fastplotlib/graphics/image.py index 8b937023b..a73ba7199 100644 --- a/fastplotlib/graphics/image.py +++ b/fastplotlib/graphics/image.py @@ -160,7 +160,6 @@ def __init__( # iterate through each texture chunk and create # an _ImageTIle, offset the tile using the data indices for texture, chunk_index, data_slice in self._data: - # create an ImageTile using the texture for this chunk img = _ImageTile( geometry=pygfx.Geometry(grid=texture), diff --git a/fastplotlib/graphics/line_collection.py b/fastplotlib/graphics/line_collection.py index c4af5dddc..0748a613c 100644 --- a/fastplotlib/graphics/line_collection.py +++ b/fastplotlib/graphics/line_collection.py @@ -198,19 +198,19 @@ def __init__( if not isinstance(thickness, (float, int)): if len(thickness) != len(data): raise ValueError( - f"len(thickness) != len(data)\n" f"{len(thickness)} != {len(data)}" + f"len(thickness) != len(data)\n{len(thickness)} != {len(data)}" ) if names is not None: if len(names) != len(data): raise ValueError( - f"len(names) != len(data)\n" f"{len(names)} != {len(data)}" + f"len(names) != len(data)\n{len(names)} != {len(data)}" ) if metadatas is not None: if len(metadatas) != len(data): raise ValueError( - f"len(metadata) != len(data)\n" f"{len(metadatas)} != {len(data)}" + f"len(metadata) != len(data)\n{len(metadatas)} != {len(data)}" ) if kwargs_lines is not None: diff --git a/fastplotlib/graphics/selectors/_rectangle.py b/fastplotlib/graphics/selectors/_rectangle.py index 51c3209b1..a663f351d 100644 --- a/fastplotlib/graphics/selectors/_rectangle.py +++ b/fastplotlib/graphics/selectors/_rectangle.py @@ -336,7 +336,6 @@ def get_selected_data( f"`mode` must be one of 'full', 'partial', or 'ignore', you have passed {mode}" ) if "Line" in source.__class__.__name__: - if isinstance(source, GraphicCollection): data_selections: List[np.ndarray] = list() @@ -478,7 +477,6 @@ def get_selected_indices( return ixs def _move_graphic(self, delta: np.ndarray): - # new selection positions xmin_new = self.selection[0] + delta[0] xmax_new = self.selection[1] + delta[0] diff --git a/fastplotlib/utils/functions.py b/fastplotlib/utils/functions.py index 6ad365e40..0c830e115 100644 --- a/fastplotlib/utils/functions.py +++ b/fastplotlib/utils/functions.py @@ -381,7 +381,6 @@ def parse_cmap_values( # can also use cm.category == "qualitative" if cmap_lib.Colormap(cmap_name).interpolation == "nearest": - # check that cmap_values are and within the number of colors `n_colors` # do not scale, use directly diff --git a/fastplotlib/widgets/image_widget/_widget.py b/fastplotlib/widgets/image_widget/_widget.py index 0fbc02be3..bc61008d2 100644 --- a/fastplotlib/widgets/image_widget/_widget.py +++ b/fastplotlib/widgets/image_widget/_widget.py @@ -515,7 +515,6 @@ def __init__( self._histogram_widget = histogram_widget for data_ix, (d, subplot) in enumerate(zip(self.data, self.figure)): - frame = self._process_indices(d, slice_indices=self._current_index) frame = self._process_frame_apply(frame, data_ix) diff --git a/scripts/generate_add_graphic_methods.py b/scripts/generate_add_graphic_methods.py index 533ae77c6..a3377f5aa 100644 --- a/scripts/generate_add_graphic_methods.py +++ b/scripts/generate_add_graphic_methods.py @@ -10,7 +10,7 @@ # so that fastplotlib will import # hacky but it works with open(filename, "w") as f: - f.write(f"class GraphicMethodsMixin:\n" f" pass") + f.write(f"class GraphicMethodsMixin:\n pass") from fastplotlib import graphics diff --git a/tests/conftest.py b/tests/conftest.py index 3f5414a71..73142bb2c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,4 +5,6 @@ def pytest_sessionstart(session): - pygfx.renderers.wgpu.set_wgpu_limits(**{"max-texture-dimension-2d": MAX_TEXTURE_SIZE}) + pygfx.renderers.wgpu.set_wgpu_limits( + **{"max-texture-dimension-2d": MAX_TEXTURE_SIZE} + ) diff --git a/tests/test_positions_graphics.py b/tests/test_positions_graphics.py index b76ece2ca..466e199ae 100644 --- a/tests/test_positions_graphics.py +++ b/tests/test_positions_graphics.py @@ -309,7 +309,8 @@ def test_cmap( "colors", [None, *generate_color_inputs("multi")] ) # cmap arg overrides colors @pytest.mark.parametrize( - "uniform_color", [True] # none of these will work with a uniform buffer + "uniform_color", + [True], # none of these will work with a uniform buffer ) def test_incompatible_cmap_color_args(graphic_type, cmap, colors, uniform_color): # test incompatible cmap args @@ -334,7 +335,8 @@ def test_incompatible_cmap_color_args(graphic_type, cmap, colors, uniform_color) @pytest.mark.parametrize("graphic_type", ["line", "scatter"]) @pytest.mark.parametrize("colors", [*generate_color_inputs("multi")]) @pytest.mark.parametrize( - "uniform_color", [True] # none of these will work with a uniform buffer + "uniform_color", + [True], # none of these will work with a uniform buffer ) def test_incompatible_color_args(graphic_type, colors, uniform_color): # test incompatible color args @@ -475,7 +477,6 @@ def test_size_space(graphic_type, size_space): assert graphic.world_object.material.thickness_space == "world" elif graphic_type == "scatter": - # test getter graphic = fig[0, 0].add_scatter(data=data, **kwargs) assert graphic.world_object.material.size_space == size_space diff --git a/tests/test_texture_array.py b/tests/test_texture_array.py index c85fc7652..c4e96985e 100644 --- a/tests/test_texture_array.py +++ b/tests/test_texture_array.py @@ -35,7 +35,6 @@ def check_texture_array( row_indices_values: np.ndarray, col_indices_values: np.ndarray, ): - npt.assert_almost_equal(ta.value, data) assert ta.buffer.size == buffer_size From b7a49ebbb412f382e4e869408b1293af39ee13f7 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Mon, 31 Mar 2025 12:09:32 +0200 Subject: [PATCH 4/5] Run ruff check --fix --- docs/source/generate_api.py | 20 +++++----- examples/gridplot/gridplot_viewports_check.py | 2 +- examples/misc-dev/selector_performance.ipynb | 5 +-- examples/misc/em_wave_animation.py | 6 +-- examples/misc/lorenz_animation.py | 2 +- examples/notebooks/quickstart.ipynb | 10 ++--- examples/qt/imagewidget.py | 1 - examples/qt/minimal.py | 1 - examples/tests/test_examples.py | 3 -- fastplotlib/__init__.py | 22 +++++----- fastplotlib/graphics/__init__.py | 6 +-- fastplotlib/graphics/_axes.py | 6 +-- fastplotlib/graphics/_collection_base.py | 3 +- fastplotlib/graphics/_features/__init__.py | 40 +++++++++---------- fastplotlib/graphics/_features/_base.py | 6 +-- .../graphics/_features/_positions_graphics.py | 10 ++--- fastplotlib/graphics/_features/utils.py | 8 ++-- fastplotlib/graphics/_positions_base.py | 2 +- fastplotlib/graphics/line.py | 2 +- fastplotlib/graphics/line_collection.py | 10 ++--- fastplotlib/graphics/selectors/__init__.py | 2 +- fastplotlib/graphics/utils.py | 2 +- fastplotlib/layouts/_figure.py | 6 +-- fastplotlib/layouts/_imgui_figure.py | 2 +- fastplotlib/layouts/_plot_area.py | 6 +-- fastplotlib/layouts/_rect.py | 2 +- fastplotlib/layouts/_utils.py | 7 ++-- fastplotlib/legends/legend.py | 2 +- fastplotlib/ui/_base.py | 1 - .../ui/right_click_menus/_standard_menu.py | 8 ++-- fastplotlib/utils/functions.py | 2 +- fastplotlib/utils/gui.py | 3 +- fastplotlib/widgets/image_widget/_widget.py | 20 +++++----- scripts/generate_add_graphic_methods.py | 2 +- tests/events.py | 1 - tests/test_common_features.py | 3 +- tests/test_figure.py | 10 ++--- tests/test_positions_graphics.py | 1 - tests/test_texture_array.py | 2 +- 39 files changed, 116 insertions(+), 131 deletions(-) diff --git a/docs/source/generate_api.py b/docs/source/generate_api.py index 912f6ff08..0f629dc04 100644 --- a/docs/source/generate_api.py +++ b/docs/source/generate_api.py @@ -157,7 +157,7 @@ def generate_page( with open(source_path, "w") as f: f.write(f".. _api.{page_name}:\n\n{page_name}\n{page_name_underline}\n\n") - for cls, module in zip(classes, modules): + for cls, module in zip(classes, modules, strict=False): to_write = generate_class(cls, module) f.write(to_write) @@ -187,15 +187,15 @@ def main(): # layouts classes index file with open(LAYOUTS_DIR.joinpath("index.rst"), "w") as f: f.write( - f"Layouts\n" - f"********\n" - f"\n" - f".. toctree::\n" - f" :maxdepth: 1\n" - f"\n" - f" imgui_figure\n" - f" figure\n" - f" subplot\n" + "Layouts\n" + "********\n" + "\n" + ".. toctree::\n" + " :maxdepth: 1\n" + "\n" + " imgui_figure\n" + " figure\n" + " subplot\n" ) # the rest of this is a mess and can be refactored later diff --git a/examples/gridplot/gridplot_viewports_check.py b/examples/gridplot/gridplot_viewports_check.py index 9d19c2807..97fa2516f 100644 --- a/examples/gridplot/gridplot_viewports_check.py +++ b/examples/gridplot/gridplot_viewports_check.py @@ -17,7 +17,7 @@ np.random.seed(0) a = np.random.rand(6, 10, 10) -for data, subplot in zip(a, figure): +for data, subplot in zip(a, figure, strict=False): subplot.add_image(data) subplot.docks["left"].size = 20 subplot.docks["right"].size = 30 diff --git a/examples/misc-dev/selector_performance.ipynb b/examples/misc-dev/selector_performance.ipynb index 459753e80..a89e4c77c 100644 --- a/examples/misc-dev/selector_performance.ipynb +++ b/examples/misc-dev/selector_performance.ipynb @@ -14,8 +14,7 @@ "from time import time\n", "\n", "import numpy as np\n", - "import fastplotlib as fpl\n", - "import pygfx" + "import fastplotlib as fpl" ] }, { @@ -78,7 +77,7 @@ }, "outputs": [], "source": [ - "from wgpu.gui.auto import WgpuCanvas, run\n", + "from wgpu.gui.auto import WgpuCanvas\n", "import pygfx as gfx" ] }, diff --git a/examples/misc/em_wave_animation.py b/examples/misc/em_wave_animation.py index d7433e0c8..5a03946df 100644 --- a/examples/misc/em_wave_animation.py +++ b/examples/misc/em_wave_animation.py @@ -34,10 +34,10 @@ # draw vector line at every 10th position electric_vectors = [ - np.array([[0, 0, z], [x, 0, z]]) for (x, z) in zip(e_xs[::10], zs[::10]) + np.array([[0, 0, z], [x, 0, z]]) for (x, z) in zip(e_xs[::10], zs[::10], strict=False) ] magnetic_vectors = [ - np.array([[0, 0, z], [0, y, z]]) for (y, z) in zip(m_ys[::10], zs[::10]) + np.array([[0, 0, z], [0, y, z]]) for (y, z) in zip(m_ys[::10], zs[::10], strict=False) ] # add as a line collection @@ -92,7 +92,7 @@ def tick(subplot): subplot["m"].data[:, 2] = new_zs # update the vector lines - for i, (value, z) in enumerate(zip(new_data[::10], new_zs[::10])): + for i, (value, z) in enumerate(zip(new_data[::10], new_zs[::10], strict=False)): subplot["e-vec"].graphics[i].data = np.array([[0, 0, z], [value, 0, z]]) subplot["m-vec"].graphics[i].data = np.array([[0, 0, z], [0, value, z]]) diff --git a/examples/misc/lorenz_animation.py b/examples/misc/lorenz_animation.py index 927565d99..b287d3fc6 100644 --- a/examples/misc/lorenz_animation.py +++ b/examples/misc/lorenz_animation.py @@ -75,7 +75,7 @@ def animate(subplot): if time >= xyzs.shape[0]: time = 0 - for scatter, g in zip(scatter_markers, lorenz_line): + for scatter, g in zip(scatter_markers, lorenz_line, strict=False): scatter.data = g.data.value[time] diff --git a/examples/notebooks/quickstart.ipynb b/examples/notebooks/quickstart.ipynb index c8d233abb..c0d4bbfd9 100644 --- a/examples/notebooks/quickstart.ipynb +++ b/examples/notebooks/quickstart.ipynb @@ -55,7 +55,7 @@ "outputs": [], "source": [ "import fastplotlib as fpl\n", - "from ipywidgets import VBox, HBox, IntSlider\n", + "from ipywidgets import HBox\n", "import numpy as np" ] }, @@ -69,7 +69,7 @@ "outputs": [], "source": [ "# this is only for testing, you do not need this to use fastplotlib\n", - "from nb_test_utils import plot_test, notebook_finished, TESTING" + "from nb_test_utils import plot_test, notebook_finished" ] }, { @@ -1218,10 +1218,10 @@ "\n", "# draw vector line at every 10th position\n", "electric_vectors = [\n", - " np.array([[0, 0, z], [x, 0, z]]) for (x, z) in zip(e_xs[::10], zs[::10])\n", + " np.array([[0, 0, z], [x, 0, z]]) for (x, z) in zip(e_xs[::10], zs[::10], strict=False)\n", "]\n", "magnetic_vectors = [\n", - " np.array([[0, 0, z], [0, y, z]]) for (y, z) in zip(m_ys[::10], zs[::10])\n", + " np.array([[0, 0, z], [0, y, z]]) for (y, z) in zip(m_ys[::10], zs[::10], strict=False)\n", "]\n", "\n", "# add as a line collection\n", @@ -1296,7 +1296,7 @@ " subplot[\"m\"].data[:, 1] = new_data\n", "\n", " # update the vector lines\n", - " for i, (value, z) in enumerate(zip(new_data[::10], zs[::10])):\n", + " for i, (value, z) in enumerate(zip(new_data[::10], zs[::10], strict=False)):\n", " subplot[\"e-vec\"].graphics[i].data = np.array([[0, 0, z], [value, 0, z]])\n", " subplot[\"m-vec\"].graphics[i].data = np.array([[0, 0, z], [0, value, z]])\n", "\n", diff --git a/examples/qt/imagewidget.py b/examples/qt/imagewidget.py index b4e760f3f..a63ae75b3 100644 --- a/examples/qt/imagewidget.py +++ b/examples/qt/imagewidget.py @@ -9,7 +9,6 @@ # sphinx_gallery_pygfx_docs = 'code' import numpy as np -from PyQt6 import QtWidgets import fastplotlib as fpl import imageio.v3 as iio diff --git a/examples/qt/minimal.py b/examples/qt/minimal.py index 0424df403..cc1d1e1e5 100644 --- a/examples/qt/minimal.py +++ b/examples/qt/minimal.py @@ -11,7 +11,6 @@ # sphinx_gallery_pygfx_docs = 'code' # import Qt or PySide -from PyQt6 import QtWidgets import fastplotlib as fpl import imageio.v3 as iio diff --git a/examples/tests/test_examples.py b/examples/tests/test_examples.py index 04a9bb53c..b3c64ab67 100644 --- a/examples/tests/test_examples.py +++ b/examples/tests/test_examples.py @@ -17,16 +17,13 @@ from .testutils import ( ROOT, - examples_dir, screenshots_dir, find_examples, wgpu_backend, is_lavapipe, diffs_dir, - generate_diff, image_similarity, normalize_image, - prep_for_write, ) # run all tests unless they opt-out diff --git a/fastplotlib/__init__.py b/fastplotlib/__init__.py index 6d92efffa..742bbaacc 100644 --- a/fastplotlib/__init__.py +++ b/fastplotlib/__init__.py @@ -26,16 +26,16 @@ from warnings import warn warn( - f"WGPU could not enumerate any adapters, fastplotlib will not work.\n" - f"This is caused by one of the following:\n" - f"1. You do not have a hardware GPU installed and you do not have " - f"software rendering (ex. lavapipe) installed either\n" - f"2. Your GPU drivers are not installed or something is wrong with your GPU driver installation, " - f"re-installing the latest drivers from your hardware vendor (probably Nvidia or AMD) may help.\n" - f"3. You are missing system libraries that are required for WGPU to access GPU(s), this is " - f"common in cloud computing environments.\n" - f"These two links can help you troubleshoot:\n" - f"https://wgpu-py.readthedocs.io/en/stable/start.html#platform-requirements\n" - f"https://fastplotlib.readthedocs.io/en/latest/user_guide/gpu.html\n", + "WGPU could not enumerate any adapters, fastplotlib will not work.\n" + "This is caused by one of the following:\n" + "1. You do not have a hardware GPU installed and you do not have " + "software rendering (ex. lavapipe) installed either\n" + "2. Your GPU drivers are not installed or something is wrong with your GPU driver installation, " + "re-installing the latest drivers from your hardware vendor (probably Nvidia or AMD) may help.\n" + "3. You are missing system libraries that are required for WGPU to access GPU(s), this is " + "common in cloud computing environments.\n" + "These two links can help you troubleshoot:\n" + "https://wgpu-py.readthedocs.io/en/stable/start.html#platform-requirements\n" + "https://fastplotlib.readthedocs.io/en/latest/user_guide/gpu.html\n", RuntimeWarning, ) diff --git a/fastplotlib/graphics/__init__.py b/fastplotlib/graphics/__init__.py index ff96baa4c..5c942aec0 100644 --- a/fastplotlib/graphics/__init__.py +++ b/fastplotlib/graphics/__init__.py @@ -6,10 +6,10 @@ __all__ = [ - "LineGraphic", "ImageGraphic", - "ScatterGraphic", - "TextGraphic", "LineCollection", + "LineGraphic", "LineStack", + "ScatterGraphic", + "TextGraphic", ] diff --git a/fastplotlib/graphics/_axes.py b/fastplotlib/graphics/_axes.py index 10774fc2a..43d346a5a 100644 --- a/fastplotlib/graphics/_axes.py +++ b/fastplotlib/graphics/_axes.py @@ -1,7 +1,7 @@ import numpy as np import pygfx -from pylinalg import quat_from_vecs, vec_transform_quat +from pylinalg import quat_from_vecs GRID_PLANES = ["xy", "xz", "yz"] @@ -284,7 +284,7 @@ def basis(self, basis: np.ndarray): raise ValueError # apply quaternion to each of x, y, z rulers - for dim, cbasis, new_basis in zip(["x", "y", "z"], CANONICAL_BAIS, basis): + for dim, cbasis, new_basis in zip(["x", "y", "z"], CANONICAL_BAIS, basis, strict=False): ruler: pygfx.Ruler = getattr(self, dim) ruler.local.rotation = quat_from_vecs(cbasis, new_basis) @@ -327,7 +327,7 @@ def colors(self, colors: tuple[pygfx.Color | str]): if len(colors) != 3: raise ValueError - for dim, color in zip(["x", "y", "z"], colors): + for dim, color in zip(["x", "y", "z"], colors, strict=False): getattr(self, dim).line.material.color = color @property diff --git a/fastplotlib/graphics/_collection_base.py b/fastplotlib/graphics/_collection_base.py index 36f83ec7a..09fea340f 100644 --- a/fastplotlib/graphics/_collection_base.py +++ b/fastplotlib/graphics/_collection_base.py @@ -1,4 +1,3 @@ -from contextlib import suppress from typing import Any import numpy as np @@ -17,7 +16,7 @@ def _set_feature(self, feature, values): if not len(values) == len(self): raise IndexError - for g, v in zip(self, values): + for g, v in zip(self, values, strict=False): setattr(g, feature, v) @property diff --git a/fastplotlib/graphics/_features/__init__.py b/fastplotlib/graphics/_features/__init__.py index a1915bbe9..7abe3352a 100644 --- a/fastplotlib/graphics/_features/__init__.py +++ b/fastplotlib/graphics/_features/__init__.py @@ -40,31 +40,31 @@ __all__ = [ - "VertexColors", - "UniformColor", - "UniformSize", - "SizeSpace", - "Thickness", - "VertexPositions", - "PointsSizesFeature", - "VertexCmap", - "TextureArray", + "Deleted", + "FontSize", "ImageCmap", - "ImageVmin", - "ImageVmax", - "ImageInterpolation", "ImageCmapInterpolation", - "TextData", - "FontSize", - "TextFaceColor", - "TextOutlineColor", - "TextOutlineThickness", - "LinearSelectionFeature", + "ImageInterpolation", + "ImageVmax", + "ImageVmin", "LinearRegionSelectionFeature", - "RectangleSelectionFeature", + "LinearSelectionFeature", "Name", "Offset", + "PointsSizesFeature", + "RectangleSelectionFeature", "Rotation", + "SizeSpace", + "TextData", + "TextFaceColor", + "TextOutlineColor", + "TextOutlineThickness", + "TextureArray", + "Thickness", + "UniformColor", + "UniformSize", + "VertexCmap", + "VertexColors", + "VertexPositions", "Visible", - "Deleted", ] diff --git a/fastplotlib/graphics/_features/_base.py b/fastplotlib/graphics/_features/_base.py index f9868c8a9..776819383 100644 --- a/fastplotlib/graphics/_features/_base.py +++ b/fastplotlib/graphics/_features/_base.py @@ -59,7 +59,7 @@ def __init__(self, **kwargs): @property def value(self) -> Any: """Graphic Feature value, must be implemented in subclass""" - raise NotImplemented + raise NotImplementedError def set_value(self, graphic, value: float): """Graphic Feature value setter, must be implemented in subclass""" @@ -191,8 +191,8 @@ def shared(self) -> int: @property def __array_interface__(self): raise BufferError( - f"Cannot use graphic feature buffer as an array, use .value instead.\n" - f"Examples: line.data.value, line.colors.value, scatter.data.value, scatter.sizes.value" + "Cannot use graphic feature buffer as an array, use .value instead.\n" + "Examples: line.data.value, line.colors.value, scatter.data.value, scatter.sizes.value" ) def __getitem__(self, item): diff --git a/fastplotlib/graphics/_features/_positions_graphics.py b/fastplotlib/graphics/_features/_positions_graphics.py index 78e53f545..5a88df835 100644 --- a/fastplotlib/graphics/_features/_positions_graphics.py +++ b/fastplotlib/graphics/_features/_positions_graphics.py @@ -120,8 +120,8 @@ def __setitem__( else: raise TypeError( - f"invalid key for setting colors, you may set colors using integer indices, slices, or " - f"fancy indexing using an array of integers or bool" + "invalid key for setting colors, you may set colors using integer indices, slices, or " + "fancy indexing using an array of integers or bool" ) self.buffer.data[key] = value @@ -238,7 +238,7 @@ def _fix_data(self, data): if data.shape[1] != 3: if data.shape[1] != 2: - raise ValueError(f"Must pass 1D, 2D or 3D data") + raise ValueError("Must pass 1D, 2D or 3D data") # zeros for z zs = np.zeros(data.shape[0], dtype=data.dtype) @@ -307,8 +307,8 @@ def _fix_sizes( sizes = np.asarray(sizes, dtype=np.float32) # read it in as a numpy.float32 if (sizes.ndim != 1) or (sizes.size != n_datapoints): raise ValueError( - f"sequence of `sizes` must be 1 dimensional with " - f"the same length as the number of datapoints" + "sequence of `sizes` must be 1 dimensional with " + "the same length as the number of datapoints" ) else: diff --git a/fastplotlib/graphics/_features/utils.py b/fastplotlib/graphics/_features/utils.py index e2f6e3428..644df5ce6 100644 --- a/fastplotlib/graphics/_features/utils.py +++ b/fastplotlib/graphics/_features/utils.py @@ -52,8 +52,8 @@ def parse_colors( if all([isinstance(val, str) for val in colors]): if not len(colors) == n_colors: raise ValueError( - f"Valid iterable color arguments must be a `tuple` or `list` of `str` " - f"where the length of the iterable is the same as the number of datapoints." + "Valid iterable color arguments must be a `tuple` or `list` of `str` " + "where the length of the iterable is the same as the number of datapoints." ) data = np.vstack([np.array(pygfx.Color(c)) for c in colors]) @@ -65,8 +65,8 @@ def parse_colors( else: raise ValueError( - f"Valid iterable color arguments must be a `tuple` or `list` representing RGBA values or " - f"an iterable of `str` with the same length as the number of datapoints." + "Valid iterable color arguments must be a `tuple` or `list` representing RGBA values or " + "an iterable of `str` with the same length as the number of datapoints." ) elif isinstance(colors, str): if colors == "random": diff --git a/fastplotlib/graphics/_positions_base.py b/fastplotlib/graphics/_positions_base.py index 565a4cd98..2315c2427 100644 --- a/fastplotlib/graphics/_positions_base.py +++ b/fastplotlib/graphics/_positions_base.py @@ -131,7 +131,7 @@ def __init__( else: if uniform_color: if not isinstance(colors, str): # not a single color - if not len(colors) in [3, 4]: # not an RGB(A) array + if len(colors) not in [3, 4]: # not an RGB(A) array raise TypeError( "must pass a single color if using `uniform_colors=True`" ) diff --git a/fastplotlib/graphics/line.py b/fastplotlib/graphics/line.py index 489c64930..15b3ff7d5 100644 --- a/fastplotlib/graphics/line.py +++ b/fastplotlib/graphics/line.py @@ -6,7 +6,7 @@ from ._positions_base import PositionsGraphic from .selectors import LinearRegionSelector, LinearSelector, RectangleSelector -from ._features import Thickness, SizeSpace +from ._features import Thickness class LineGraphic(PositionsGraphic): diff --git a/fastplotlib/graphics/line_collection.py b/fastplotlib/graphics/line_collection.py index 0748a613c..9b0157792 100644 --- a/fastplotlib/graphics/line_collection.py +++ b/fastplotlib/graphics/line_collection.py @@ -31,7 +31,7 @@ def colors(self, values: str | np.ndarray | tuple[float] | list[float] | list[st if not len(values) == len(self): raise IndexError - for g, v in zip(self.graphics, values): + for g, v in zip(self.graphics, values, strict=False): g.colors = v return @@ -39,7 +39,7 @@ def colors(self, values: str | np.ndarray | tuple[float] | list[float] | list[st if isinstance(values, np.ndarray): if values.ndim == 2: # assume individual colors for each - for g, v in zip(self, values): + for g, v in zip(self, values, strict=False): g.colors = v return @@ -49,7 +49,7 @@ def colors(self, values: str | np.ndarray | tuple[float] | list[float] | list[st else: # assume individual colors for each - for g, v in zip(self, values): + for g, v in zip(self, values, strict=False): g.colors = v @property @@ -59,7 +59,7 @@ def data(self) -> CollectionFeature: @data.setter def data(self, values): - for g, v in zip(self, values): + for g, v in zip(self, values, strict=False): g.data = v @property @@ -107,7 +107,7 @@ def thickness(self, values: np.ndarray | list[float]): if not len(values) == len(self): raise IndexError - for g, v in zip(self, values): + for g, v in zip(self, values, strict=False): g.thickness = v diff --git a/fastplotlib/graphics/selectors/__init__.py b/fastplotlib/graphics/selectors/__init__.py index 9133192e9..e427d2bbd 100644 --- a/fastplotlib/graphics/selectors/__init__.py +++ b/fastplotlib/graphics/selectors/__init__.py @@ -4,4 +4,4 @@ from ._rectangle import RectangleSelector -__all__ = ["LinearSelector", "LinearRegionSelector", "RectangleSelector"] +__all__ = ["LinearRegionSelector", "LinearSelector", "RectangleSelector"] diff --git a/fastplotlib/graphics/utils.py b/fastplotlib/graphics/utils.py index 6be5aefc4..cda5d9fe8 100644 --- a/fastplotlib/graphics/utils.py +++ b/fastplotlib/graphics/utils.py @@ -33,5 +33,5 @@ def pause_events(*graphics: Graphic): g.block_events = True yield - for g, value in zip(graphics, original_vals): + for g, value in zip(graphics, original_vals, strict=False): g.block_events = value diff --git a/fastplotlib/layouts/_figure.py b/fastplotlib/layouts/_figure.py index a1bae965e..e8df5568c 100644 --- a/fastplotlib/layouts/_figure.py +++ b/fastplotlib/layouts/_figure.py @@ -241,8 +241,8 @@ def __init__( controller_ids = np.zeros(n_subplots, dtype=int) else: raise ValueError( - f"`controller_ids` must be one of 'sync', an array/list of subplot names, or an array/list of " - f"integer ids. See the docstring for more details." + "`controller_ids` must be one of 'sync', an array/list of subplot names, or an array/list of " + "integer ids. See the docstring for more details." ) # list controller_ids @@ -259,7 +259,7 @@ def __init__( # make sure each controller_id str is a subplot name if not all([n in subplot_names for n in ids_flat]): raise KeyError( - f"all `controller_ids` strings must be one of the subplot names" + "all `controller_ids` strings must be one of the subplot names" ) if len(ids_flat) > len(set(ids_flat)): diff --git a/fastplotlib/layouts/_imgui_figure.py b/fastplotlib/layouts/_imgui_figure.py index 40145fe50..f3a958399 100644 --- a/fastplotlib/layouts/_imgui_figure.py +++ b/fastplotlib/layouts/_imgui_figure.py @@ -126,7 +126,7 @@ def _draw_imgui(self) -> imgui.ImDrawData: imgui.new_frame() for subplot, toolbar in zip( - self._subplots.ravel(), self._subplot_toolbars.ravel() + self._subplots.ravel(), self._subplot_toolbars.ravel(), strict=False ): if not subplot.toolbar: # if subplot.toolbar is False diff --git a/fastplotlib/layouts/_plot_area.py b/fastplotlib/layouts/_plot_area.py index e780607ce..ddd632847 100644 --- a/fastplotlib/layouts/_plot_area.py +++ b/fastplotlib/layouts/_plot_area.py @@ -510,8 +510,8 @@ def _add_or_insert_graphic( def _check_graphic_name_exists(self, name): if name in self: raise ValueError( - f"Graphic with given name already exists in subplot or plot area. " - f"All graphics within a subplot or plot area must have a unique name." + "Graphic with given name already exists in subplot or plot area. " + "All graphics within a subplot or plot area must have a unique name." ) def center_graphic(self, graphic: Graphic, zoom: float = 1.0): @@ -683,7 +683,7 @@ def __getitem__(self, name: str): if graphic.name == name: return graphic - raise IndexError(f"No graphic or selector of given name in plot area.\n") + raise IndexError("No graphic or selector of given name in plot area.\n") def __contains__(self, item: str | Graphic): if isinstance(item, Graphic): diff --git a/fastplotlib/layouts/_rect.py b/fastplotlib/layouts/_rect.py index aa84ee8a2..434a68f1e 100644 --- a/fastplotlib/layouts/_rect.py +++ b/fastplotlib/layouts/_rect.py @@ -22,7 +22,7 @@ def _set(self, rect): set the internal fractional and absolute screen space rects """ rect = np.asarray(rect) - for val, name in zip(rect, ["x-position", "y-position", "width", "height"]): + for val, name in zip(rect, ["x-position", "y-position", "width", "height"], strict=False): if val < 0: raise ValueError( f"Invalid rect value < 0: {rect}\n All values must be non-negative." diff --git a/fastplotlib/layouts/_utils.py b/fastplotlib/layouts/_utils.py index 98a6268f1..8489b9a49 100644 --- a/fastplotlib/layouts/_utils.py +++ b/fastplotlib/layouts/_utils.py @@ -33,21 +33,20 @@ def make_canvas_and_renderer( if canvas is None: canvas = RenderCanvas(**canvas_kwargs) elif isinstance(canvas, str): - import rendercanvas m = importlib.import_module("rendercanvas." + canvas) canvas = m.RenderCanvas(**canvas_kwargs) elif not isinstance(canvas, (BaseRenderCanvas, Texture)): raise TypeError( - f"canvas option must either be a valid BaseRenderCanvas implementation, a pygfx Texture" - f" or a str with the gui backend name, valid str are: 'qt', 'glfw', 'jupyter', 'wx', and 'offscreen'" + "canvas option must either be a valid BaseRenderCanvas implementation, a pygfx Texture" + " or a str with the gui backend name, valid str are: 'qt', 'glfw', 'jupyter', 'wx', and 'offscreen'" ) if renderer is None: renderer = WgpuRenderer(canvas) elif not isinstance(renderer, Renderer): raise TypeError( - f"renderer option must be a pygfx.Renderer instance such as pygfx.WgpuRenderer" + "renderer option must be a pygfx.Renderer instance such as pygfx.WgpuRenderer" ) return canvas, renderer diff --git a/fastplotlib/legends/legend.py b/fastplotlib/legends/legend.py index df78d5662..066367a4b 100644 --- a/fastplotlib/legends/legend.py +++ b/fastplotlib/legends/legend.py @@ -7,7 +7,7 @@ from ..graphics._base import Graphic from ..graphics._features._base import FeatureEvent -from ..graphics import LineGraphic, ScatterGraphic, ImageGraphic +from ..graphics import LineGraphic from ..utils import mesh_masks diff --git a/fastplotlib/ui/_base.py b/fastplotlib/ui/_base.py index 6c134d415..fff94454d 100644 --- a/fastplotlib/ui/_base.py +++ b/fastplotlib/ui/_base.py @@ -1,5 +1,4 @@ from typing import Literal -import numpy as np from imgui_bundle import imgui diff --git a/fastplotlib/ui/right_click_menus/_standard_menu.py b/fastplotlib/ui/right_click_menus/_standard_menu.py index 1937df858..1a309d87c 100644 --- a/fastplotlib/ui/right_click_menus/_standard_menu.py +++ b/fastplotlib/ui/right_click_menus/_standard_menu.py @@ -57,13 +57,13 @@ def update(self): if self._last_right_click_pos == imgui.get_mouse_pos(): if self.get_subplot() is not False: # must explicitly check for False # open only if right click was inside a subplot - imgui.open_popup(f"right-click-menu") + imgui.open_popup("right-click-menu") # TODO: call this just once when going from open -> closed state if not imgui.is_popup_open("right-click-menu"): self.cleanup() - if imgui.begin_popup(f"right-click-menu"): + if imgui.begin_popup("right-click-menu"): if self.get_subplot() is False: # must explicitly check for False # for some reason it will still trigger at certain locations # despite open_popup() only being called when an actual @@ -81,10 +81,10 @@ def update(self): imgui.separator() # autoscale, center, maintain aspect - if imgui.menu_item(f"Autoscale", "", False)[0]: + if imgui.menu_item("Autoscale", "", False)[0]: self.get_subplot().auto_scale() - if imgui.menu_item(f"Center", "", False)[0]: + if imgui.menu_item("Center", "", False)[0]: self.get_subplot().center_scene() _, maintain_aspect = imgui.menu_item( diff --git a/fastplotlib/utils/functions.py b/fastplotlib/utils/functions.py index 0c830e115..b08da9191 100644 --- a/fastplotlib/utils/functions.py +++ b/fastplotlib/utils/functions.py @@ -264,7 +264,7 @@ def make_colors_dict(labels: Sequence, cmap: str, **kwargs) -> OrderedDict: colors = make_colors(len(labels), cmap, **kwargs) - return OrderedDict(zip(labels, colors)) + return OrderedDict(zip(labels, colors, strict=False)) def quick_min_max(data: np.ndarray) -> tuple[float, float]: diff --git a/fastplotlib/utils/gui.py b/fastplotlib/utils/gui.py index 6a0d8dfdc..9ee53bcfd 100644 --- a/fastplotlib/utils/gui.py +++ b/fastplotlib/utils/gui.py @@ -33,8 +33,7 @@ # Let wgpu do the auto gui selection -from rendercanvas import BaseRenderCanvas -from rendercanvas.auto import RenderCanvas, loop +from rendercanvas.auto import RenderCanvas # Get the name of the backend ('qt', 'glfw', 'jupyter') GUI_BACKEND = RenderCanvas.__module__.split(".")[-1] diff --git a/fastplotlib/widgets/image_widget/_widget.py b/fastplotlib/widgets/image_widget/_widget.py index bc61008d2..5b98da772 100644 --- a/fastplotlib/widgets/image_widget/_widget.py +++ b/fastplotlib/widgets/image_widget/_widget.py @@ -1,10 +1,8 @@ -from copy import deepcopy from typing import Callable from warnings import warn import numpy as np -from rendercanvas import BaseRenderCanvas from ...layouts import ImguiFigure as Figure from ...graphics import ImageGraphic @@ -143,7 +141,7 @@ def cmap(self, names: str | list[str]): f"{len(self.managed_graphics)} image widget subplots" ) - for name, g in zip(names, self.managed_graphics): + for name, g in zip(names, self.managed_graphics, strict=False): g.cmap = name elif isinstance(names, str): @@ -214,7 +212,7 @@ def current_index(self, index: dict[str, int]): self._current_index.update(index) - for i, (ig, data) in enumerate(zip(self.managed_graphics, self.data)): + for i, (ig, data) in enumerate(zip(self.managed_graphics, self.data, strict=False)): frame = self._process_indices(data, self._current_index) frame = self._process_frame_apply(frame, i) ig.data = frame @@ -482,7 +480,7 @@ def __init__( # get max bound for all data arrays for all slider dimensions and ensure compatibility across slider dims self._dims_max_bounds: dict[str, int] = {k: 0 for k in self.slider_dims} for i, _dim in enumerate(list(self._dims_max_bounds.keys())): - for array, partition in zip(self.data, self.n_scrollable_dims): + for array, partition in zip(self.data, self.n_scrollable_dims, strict=False): if partition <= i: continue else: @@ -514,7 +512,7 @@ def __init__( self._figure: Figure = Figure(**figure_kwargs_default) self._histogram_widget = histogram_widget - for data_ix, (d, subplot) in enumerate(zip(self.data, self.figure)): + for data_ix, (d, subplot) in enumerate(zip(self.data, self.figure, strict=False)): frame = self._process_indices(d, slice_indices=self._current_index) frame = self._process_frame_apply(frame, data_ix) @@ -829,7 +827,7 @@ def reset_vmin_vmax(self): """ Reset the vmin and vmax w.r.t. the full data """ - for data, subplot in zip(self.data, self.figure): + for data, subplot in zip(self.data, self.figure, strict=False): if "histogram_lut" not in subplot.docks["right"]: continue hlut = subplot.docks["right"]["histogram_lut"] @@ -893,7 +891,7 @@ def set_data( f" current number of data arrays {len(self._data)}" ) # check all arrays - for i, (new_array, current_array) in enumerate(zip(new_data, self._data)): + for i, (new_array, current_array) in enumerate(zip(new_data, self._data, strict=False)): if new_array.ndim != current_array.ndim: raise ValueError( f"new data ndim {new_array.ndim} at index {i} " @@ -905,13 +903,13 @@ def set_data( if self.n_scrollable_dims[i] != new_scrollable_dims: raise ValueError( - f"number of dimensions of data arrays must match number of dimensions of " - f"existing data arrays" + "number of dimensions of data arrays must match number of dimensions of " + "existing data arrays" ) # if checks pass, update with new data for i, (new_array, current_array, subplot) in enumerate( - zip(new_data, self._data, self.figure) + zip(new_data, self._data, self.figure, strict=False) ): # check last two dims (x and y) to see if data shape is changing old_data_shape = self._data[i].shape[-self.n_img_dims[i] :] diff --git a/scripts/generate_add_graphic_methods.py b/scripts/generate_add_graphic_methods.py index a3377f5aa..da8470a04 100644 --- a/scripts/generate_add_graphic_methods.py +++ b/scripts/generate_add_graphic_methods.py @@ -10,7 +10,7 @@ # so that fastplotlib will import # hacky but it works with open(filename, "w") as f: - f.write(f"class GraphicMethodsMixin:\n pass") + f.write("class GraphicMethodsMixin:\n pass") from fastplotlib import graphics diff --git a/tests/events.py b/tests/events.py index ea160dec3..4e343ce67 100644 --- a/tests/events.py +++ b/tests/events.py @@ -2,7 +2,6 @@ import pytest import numpy as np from numpy import testing as npt -import pygfx import fastplotlib as fpl from fastplotlib.graphics._features import FeatureEvent diff --git a/tests/test_common_features.py b/tests/test_common_features.py index 332ac71ae..25992e29b 100644 --- a/tests/test_common_features.py +++ b/tests/test_common_features.py @@ -1,10 +1,9 @@ -import numpy import numpy as np from numpy import testing as npt import pytest import fastplotlib as fpl -from fastplotlib.graphics._features import FeatureEvent, Name, Offset, Rotation, Visible +from fastplotlib.graphics._features import FeatureEvent def make_graphic(kind: str, **kwargs): diff --git a/tests/test_figure.py b/tests/test_figure.py index 757b1eeae..f9236ed51 100644 --- a/tests/test_figure.py +++ b/tests/test_figure.py @@ -25,14 +25,14 @@ def test_cameras_controller_properties(): subplot_cameras = [subplot.camera for subplot in fig] subplot_controllers = [subplot.controller for subplot in fig] - for c1, c2 in zip(subplot_cameras, fig.cameras.ravel()): + for c1, c2 in zip(subplot_cameras, fig.cameras.ravel(), strict=False): assert c1 is c2 - for c1, c2 in zip(subplot_controllers, fig.controllers.ravel()): + for c1, c2 in zip(subplot_controllers, fig.controllers.ravel(), strict=False): assert c1 is c2 for camera_type, subplot_camera in zip( - np.asarray(cameras).ravel(), fig.cameras.ravel() + np.asarray(cameras).ravel(), fig.cameras.ravel(), strict=False ): if camera_type == "2d": assert subplot_camera.fov == 0 @@ -40,7 +40,7 @@ def test_cameras_controller_properties(): assert subplot_camera.fov == 50 for controller_type, subplot_controller in zip( - np.asarray(controller_types).ravel(), fig.controllers.ravel() + np.asarray(controller_types).ravel(), fig.controllers.ravel(), strict=False ): match controller_type: case "panzoom": @@ -148,7 +148,7 @@ def test_set_controllers_from_existing_controllers(): shape=fig.shape, controllers=fig.controllers[:-1], canvas="offscreen" ) - for fig1_subplot, fig2_subplot in zip(fig, fig2): + for fig1_subplot, fig2_subplot in zip(fig, fig2, strict=False): assert fig1_subplot.controller is fig2_subplot.controller cameras = [[pygfx.PerspectiveCamera(), "3d"], ["3d", "2d"]] diff --git a/tests/test_positions_graphics.py b/tests/test_positions_graphics.py index 466e199ae..da7566b70 100644 --- a/tests/test_positions_graphics.py +++ b/tests/test_positions_graphics.py @@ -20,7 +20,6 @@ generate_positions_spiral_data, generate_color_inputs, MULTI_COLORS_TRUTH, - generate_slice_indices, ) diff --git a/tests/test_texture_array.py b/tests/test_texture_array.py index c4e96985e..b20cd21d2 100644 --- a/tests/test_texture_array.py +++ b/tests/test_texture_array.py @@ -87,7 +87,7 @@ def make_image_graphic(data) -> fpl.ImageGraphic: def check_image_graphic(texture_array, graphic): # make sure each ImageTile has the right texture for (texture, chunk_index, data_slice), img in zip( - texture_array, graphic.world_object.children + texture_array, graphic.world_object.children, strict=False ): assert isinstance(img, _ImageTile) assert img.geometry.grid is texture From d9e6b883ca8712be6ac1f5f13df1612fabf1429e Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Mon, 31 Mar 2025 12:17:09 +0200 Subject: [PATCH 5/5] ignore some cases --- pyproject.toml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e8287aafc..910211b01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,4 +77,13 @@ line-length = 88 [tool.ruff.lint] select = ["F", "E", "W", "N", "B", "RUF", "TC"] -ignore = [] +ignore = [ + "F403", # `from typing import *` used; unable to detect undefined names -> Would be good to fix this one and the next + "F405", # X may be undefined, or defined from star imports + "F841", # Local variable X is assigned to but never used" + "E501", # Line too long + "B007", # Loop control variable X not used within loop body + "B028", # No explicit X keyword argument found + "B905", # `zip()` without an explicit `strict=` parameter + "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` +]