diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9adb67f77..bc223ae27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ jobs: docs-build: name: Docs runs-on: bigmem + timeout-minutes: 10 if: ${{ !github.event.pull_request.draft }} strategy: fail-fast: false @@ -49,6 +50,7 @@ jobs: test-build-full: name: Test Linux, notebook + glfw runs-on: bigmem + timeout-minutes: 10 if: ${{ !github.event.pull_request.draft }} strategy: fail-fast: false @@ -105,6 +107,7 @@ jobs: test-build-desktop: name: Test Linux, only glfw runs-on: bigmem + timeout-minutes: 10 if: ${{ !github.event.pull_request.draft }} strategy: fail-fast: false diff --git a/.github/workflows/screenshots.yml b/.github/workflows/screenshots.yml index baad8b655..c1ed81644 100644 --- a/.github/workflows/screenshots.yml +++ b/.github/workflows/screenshots.yml @@ -14,6 +14,7 @@ jobs: screenshots: name: Regenerate runs-on: bigmem + timeout-minutes: 10 if: ${{ !github.event.pull_request.draft }} steps: - name: Install git-lfs diff --git a/docs/source/api/fastplotlib.rst b/docs/source/api/fastplotlib.rst new file mode 100644 index 000000000..74349156f --- /dev/null +++ b/docs/source/api/fastplotlib.rst @@ -0,0 +1,14 @@ +fastplotlib +*********** + +.. currentmodule:: fastplotlib + +.. autofunction:: fastplotlib.pause_events + +.. autofunction:: fastplotlib.enumerate_adapters + +.. autofunction:: fastplotlib.select_adapter + +.. autofunction:: fastplotlib.print_wgpu_report + +.. autofunction:: fastplotlib.run diff --git a/docs/source/api/gpu.rst b/docs/source/api/gpu.rst deleted file mode 100644 index 6f94aff23..000000000 --- a/docs/source/api/gpu.rst +++ /dev/null @@ -1,6 +0,0 @@ -fastplotlib.utils.gpu -********************* - -.. currentmodule:: fastplotlib.utils.gpu -.. automodule:: fastplotlib - :members: diff --git a/docs/source/api/graphics/ImageGraphic.rst b/docs/source/api/graphics/ImageGraphic.rst index a0ae8a5ed..1f15c6963 100644 --- a/docs/source/api/graphics/ImageGraphic.rst +++ b/docs/source/api/graphics/ImageGraphic.rst @@ -20,6 +20,7 @@ Properties .. autosummary:: :toctree: ImageGraphic_api + ImageGraphic.axes ImageGraphic.block_events ImageGraphic.cmap ImageGraphic.cmap_interpolation @@ -41,6 +42,7 @@ Methods .. autosummary:: :toctree: ImageGraphic_api + ImageGraphic.add_axes ImageGraphic.add_event_handler ImageGraphic.add_linear_region_selector ImageGraphic.add_linear_selector diff --git a/docs/source/api/graphics/LineCollection.rst b/docs/source/api/graphics/LineCollection.rst index c000b7334..23e0b512d 100644 --- a/docs/source/api/graphics/LineCollection.rst +++ b/docs/source/api/graphics/LineCollection.rst @@ -20,6 +20,7 @@ Properties .. autosummary:: :toctree: LineCollection_api + LineCollection.axes LineCollection.block_events LineCollection.cmap LineCollection.colors @@ -45,6 +46,7 @@ Methods .. autosummary:: :toctree: LineCollection_api + LineCollection.add_axes LineCollection.add_event_handler LineCollection.add_graphic LineCollection.add_linear_region_selector diff --git a/docs/source/api/graphics/LineGraphic.rst b/docs/source/api/graphics/LineGraphic.rst index d260c3214..96c9ff62b 100644 --- a/docs/source/api/graphics/LineGraphic.rst +++ b/docs/source/api/graphics/LineGraphic.rst @@ -20,6 +20,7 @@ Properties .. autosummary:: :toctree: LineGraphic_api + LineGraphic.axes LineGraphic.block_events LineGraphic.cmap LineGraphic.colors @@ -39,6 +40,7 @@ Methods .. autosummary:: :toctree: LineGraphic_api + LineGraphic.add_axes LineGraphic.add_event_handler LineGraphic.add_linear_region_selector LineGraphic.add_linear_selector diff --git a/docs/source/api/graphics/LineStack.rst b/docs/source/api/graphics/LineStack.rst index 18b35932d..41cd3fbc8 100644 --- a/docs/source/api/graphics/LineStack.rst +++ b/docs/source/api/graphics/LineStack.rst @@ -20,6 +20,7 @@ Properties .. autosummary:: :toctree: LineStack_api + LineStack.axes LineStack.block_events LineStack.cmap LineStack.colors @@ -45,6 +46,7 @@ Methods .. autosummary:: :toctree: LineStack_api + LineStack.add_axes LineStack.add_event_handler LineStack.add_graphic LineStack.add_linear_region_selector diff --git a/docs/source/api/graphics/ScatterGraphic.rst b/docs/source/api/graphics/ScatterGraphic.rst index 8f2b17fd6..595346f07 100644 --- a/docs/source/api/graphics/ScatterGraphic.rst +++ b/docs/source/api/graphics/ScatterGraphic.rst @@ -20,6 +20,7 @@ Properties .. autosummary:: :toctree: ScatterGraphic_api + ScatterGraphic.axes ScatterGraphic.block_events ScatterGraphic.cmap ScatterGraphic.colors @@ -39,6 +40,7 @@ Methods .. autosummary:: :toctree: ScatterGraphic_api + ScatterGraphic.add_axes ScatterGraphic.add_event_handler ScatterGraphic.clear_event_handlers ScatterGraphic.remove_event_handler diff --git a/docs/source/api/graphics/TextGraphic.rst b/docs/source/api/graphics/TextGraphic.rst index a3cd9bbb9..107bc1c74 100644 --- a/docs/source/api/graphics/TextGraphic.rst +++ b/docs/source/api/graphics/TextGraphic.rst @@ -20,6 +20,7 @@ Properties .. autosummary:: :toctree: TextGraphic_api + TextGraphic.axes TextGraphic.block_events TextGraphic.deleted TextGraphic.event_handlers @@ -40,6 +41,7 @@ Methods .. autosummary:: :toctree: TextGraphic_api + TextGraphic.add_axes TextGraphic.add_event_handler TextGraphic.clear_event_handlers TextGraphic.remove_event_handler diff --git a/docs/source/api/layouts/subplot.rst b/docs/source/api/layouts/subplot.rst index dc77a725a..efe2fa4fc 100644 --- a/docs/source/api/layouts/subplot.rst +++ b/docs/source/api/layouts/subplot.rst @@ -20,6 +20,8 @@ Properties .. autosummary:: :toctree: Subplot_api + Subplot.axes + Subplot.background_color Subplot.camera Subplot.canvas Subplot.controller @@ -60,8 +62,6 @@ Methods Subplot.remove_animation Subplot.remove_graphic Subplot.render - Subplot.set_axes_visibility - Subplot.set_grid_visibility Subplot.set_title Subplot.set_viewport_rect diff --git a/docs/source/api/selectors/LinearRegionSelector.rst b/docs/source/api/selectors/LinearRegionSelector.rst index c9140bc7d..34df92b2a 100644 --- a/docs/source/api/selectors/LinearRegionSelector.rst +++ b/docs/source/api/selectors/LinearRegionSelector.rst @@ -20,6 +20,7 @@ Properties .. autosummary:: :toctree: LinearRegionSelector_api + LinearRegionSelector.axes LinearRegionSelector.axis LinearRegionSelector.block_events LinearRegionSelector.deleted @@ -39,6 +40,7 @@ Methods .. autosummary:: :toctree: LinearRegionSelector_api + LinearRegionSelector.add_axes LinearRegionSelector.add_event_handler LinearRegionSelector.add_ipywidget_handler LinearRegionSelector.clear_event_handlers diff --git a/docs/source/api/selectors/LinearSelector.rst b/docs/source/api/selectors/LinearSelector.rst index fa21f8f15..31f546e2c 100644 --- a/docs/source/api/selectors/LinearSelector.rst +++ b/docs/source/api/selectors/LinearSelector.rst @@ -20,6 +20,7 @@ Properties .. autosummary:: :toctree: LinearSelector_api + LinearSelector.axes LinearSelector.axis LinearSelector.block_events LinearSelector.deleted @@ -39,6 +40,7 @@ Methods .. autosummary:: :toctree: LinearSelector_api + LinearSelector.add_axes LinearSelector.add_event_handler LinearSelector.add_ipywidget_handler LinearSelector.clear_event_handlers diff --git a/docs/source/conf.py b/docs/source/conf.py index 0df47e579..68eb728a3 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,7 +25,7 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = "fastplotlib" -copyright = "2023, Kushal Kolar, Caitlin Lewis" +copyright = "2024, Kushal Kolar, Caitlin Lewis" author = "Kushal Kolar, Caitlin Lewis" release = fastplotlib.__version__ @@ -57,7 +57,8 @@ "../../examples/desktop/line_collection", "../../examples/desktop/scatter", "../../examples/desktop/heatmap", - "../../examples/desktop/misc" + "../../examples/desktop/misc", + "../../examples/desktop/selectors", ] ), "ignore_pattern": r'__init__\.py', @@ -102,6 +103,7 @@ "numpy": ("https://numpy.org/doc/stable/", None), "pygfx": ("https://pygfx.com/stable", None), "wgpu": ("https://wgpu-py.readthedocs.io/en/latest", None), + "fastplotlib": ("https://fastplotlib.readthedocs.io/en/latest/", None), } html_theme_options = { diff --git a/docs/source/index.rst b/docs/source/index.rst index 2b40cdeca..cf752a83b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -11,7 +11,8 @@ Welcome to fastplotlib's documentation! .. toctree:: :maxdepth: 1 :caption: API - + + fastplotlib Figure Subplot Graphics @@ -19,7 +20,6 @@ Welcome to fastplotlib's documentation! Selectors Widgets Utils - GPU .. toctree:: :caption: Gallery diff --git a/examples/desktop/gridplot/gridplot.py b/examples/desktop/gridplot/gridplot.py index 044adae80..a77cb7872 100644 --- a/examples/desktop/gridplot/gridplot.py +++ b/examples/desktop/gridplot/gridplot.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import imageio.v3 as iio -figure = fpl.Figure(shape=(2, 2)) +figure = fpl.Figure(shape=(2, 2), size=(700, 560)) im = iio.imread("imageio:clock.png") im2 = iio.imread("imageio:astronaut.png") @@ -25,10 +25,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -for subplot in figure: - subplot.auto_scale() # 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/desktop/gridplot/gridplot_non_square.py b/examples/desktop/gridplot/gridplot_non_square.py index c8a68cc85..a7874319e 100644 --- a/examples/desktop/gridplot/gridplot_non_square.py +++ b/examples/desktop/gridplot/gridplot_non_square.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import imageio.v3 as iio -figure = fpl.Figure(shape=(2, 2), controller_ids="sync") +figure = fpl.Figure(shape=(2, 2), size=(700, 560)) im = iio.imread("imageio:clock.png") im2 = iio.imread("imageio:astronaut.png") @@ -23,10 +23,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -for subplot in figure: - subplot.auto_scale() # 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/desktop/gridplot/multigraphic_gridplot.py b/examples/desktop/gridplot/multigraphic_gridplot.py index edb0aaafd..eec0d06fa 100644 --- a/examples/desktop/gridplot/multigraphic_gridplot.py +++ b/examples/desktop/gridplot/multigraphic_gridplot.py @@ -14,7 +14,11 @@ from itertools import product # define figure -figure = fpl.Figure(shape=(2, 2), names=[["image-overlay", "circles"], ["line-stack", "scatter"]]) +figure = fpl.Figure( + shape=(2, 2), + names=[["image-overlay", "circles"], ["line-stack", "scatter"]], + size=(700, 560) +) img = iio.imread("imageio:coffee.png") @@ -106,8 +110,6 @@ def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: figure.show() -figure.canvas.set_logical_size(700, 560) - # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": diff --git a/examples/desktop/heatmap/heatmap.py b/examples/desktop/heatmap/heatmap.py index 08b284749..008686464 100644 --- a/examples/desktop/heatmap/heatmap.py +++ b/examples/desktop/heatmap/heatmap.py @@ -10,22 +10,20 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) -xs = np.linspace(0, 1_000, 10_000, dtype=np.float32) +xs = np.linspace(0, 1_000, 9_000, dtype=np.float32) sine = np.sin(np.sqrt(xs)) -data = np.vstack([sine * i for i in range(20_000)]) +data = np.vstack([sine * i for i in range(15_000)]) # plot the image data img = figure[0, 0].add_image(data=data, name="heatmap") +del data figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() # 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/desktop/heatmap/heatmap_cmap.py b/examples/desktop/heatmap/heatmap_cmap.py index f51981bed..8791741a7 100644 --- a/examples/desktop/heatmap/heatmap_cmap.py +++ b/examples/desktop/heatmap/heatmap_cmap.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) xs = np.linspace(0, 1_000, 10_000, dtype=np.float32) @@ -24,10 +24,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() - img.cmap = "viridis" # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively diff --git a/examples/desktop/heatmap/heatmap_data.py b/examples/desktop/heatmap/heatmap_data.py index 9334ea4d7..f524f5476 100644 --- a/examples/desktop/heatmap/heatmap_data.py +++ b/examples/desktop/heatmap/heatmap_data.py @@ -10,7 +10,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) xs = np.linspace(0, 1_000, 9_000, dtype=np.float32) @@ -23,9 +23,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() cosine = np.cos(np.sqrt(xs)[:3000]) # change first 2,000 rows and 3,000 columns diff --git a/examples/desktop/heatmap/heatmap_square.py b/examples/desktop/heatmap/heatmap_square.py index 51e71695a..aee4f7d44 100644 --- a/examples/desktop/heatmap/heatmap_square.py +++ b/examples/desktop/heatmap/heatmap_square.py @@ -11,7 +11,7 @@ import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) xs = np.linspace(0, 1_000, 20_000, dtype=np.float32) @@ -25,9 +25,6 @@ del data # data no longer needed after given to graphic figure.show() -figure.canvas.set_logical_size(1500, 1500) - -figure[0, 0].auto_scale() if __name__ == "__main__": print(__doc__) diff --git a/examples/desktop/heatmap/heatmap_vmin_vmax.py b/examples/desktop/heatmap/heatmap_vmin_vmax.py index 45c960fd8..e7f9c758b 100644 --- a/examples/desktop/heatmap/heatmap_vmin_vmax.py +++ b/examples/desktop/heatmap/heatmap_vmin_vmax.py @@ -10,7 +10,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) xs = np.linspace(0, 1_000, 10_000, dtype=np.float32) @@ -23,10 +23,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() - img.vmin = -5_000 img.vmax = 10_000 diff --git a/examples/desktop/heatmap/heatmap_wide.py b/examples/desktop/heatmap/heatmap_wide.py index dccf531e2..6bf3ff72d 100644 --- a/examples/desktop/heatmap/heatmap_wide.py +++ b/examples/desktop/heatmap/heatmap_wide.py @@ -11,7 +11,7 @@ import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) xs = np.linspace(0, 1_000, 20_000, dtype=np.float32) @@ -24,9 +24,6 @@ figure.show() -figure.canvas.set_logical_size(1500, 1500) - -figure[0, 0].auto_scale() if __name__ == "__main__": print(__doc__) diff --git a/examples/desktop/image/image_cmap.py b/examples/desktop/image/image_cmap.py index c70af7346..4aad934b2 100644 --- a/examples/desktop/image/image_cmap.py +++ b/examples/desktop/image/image_cmap.py @@ -13,17 +13,13 @@ im = iio.imread("imageio:camera.png") -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) # plot the image data image_graphic = figure[0, 0].add_image(data=im, name="random-image") figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() - image_graphic.cmap = "viridis" # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively diff --git a/examples/desktop/image/image_rgb.py b/examples/desktop/image/image_rgb.py index 951142fd7..e89f3d192 100644 --- a/examples/desktop/image/image_rgb.py +++ b/examples/desktop/image/image_rgb.py @@ -13,16 +13,13 @@ im = iio.imread("imageio:astronaut.png") -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) # plot the image data image_graphic = figure[0, 0].add_image(data=im, name="iio astronaut") figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() # 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/desktop/image/image_rgbvminvmax.py b/examples/desktop/image/image_rgbvminvmax.py index 25d3904e8..2263f1307 100644 --- a/examples/desktop/image/image_rgbvminvmax.py +++ b/examples/desktop/image/image_rgbvminvmax.py @@ -13,17 +13,13 @@ im = iio.imread("imageio:astronaut.png") -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) # plot the image data image_graphic = figure[0, 0].add_image(data=im, name="iio astronaut") figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() - image_graphic.vmin = 0.5 image_graphic.vmax = 0.75 diff --git a/examples/desktop/image/image_simple.py b/examples/desktop/image/image_simple.py index dab5188a1..cec8e3313 100644 --- a/examples/desktop/image/image_simple.py +++ b/examples/desktop/image/image_simple.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import imageio.v3 as iio -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) data = iio.imread("imageio:camera.png") @@ -20,9 +20,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() # 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/desktop/image/image_small.py b/examples/desktop/image/image_small.py index 95c263a28..937411ab1 100644 --- a/examples/desktop/image/image_small.py +++ b/examples/desktop/image/image_small.py @@ -12,7 +12,7 @@ import fastplotlib as fpl -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) data = np.array( [[0, 1, 2], @@ -22,9 +22,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() # 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/desktop/image/image_vminvmax.py b/examples/desktop/image/image_vminvmax.py index d9e49b18e..0503c5ff2 100644 --- a/examples/desktop/image/image_vminvmax.py +++ b/examples/desktop/image/image_vminvmax.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import imageio.v3 as iio -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) data = iio.imread("imageio:astronaut.png") @@ -20,10 +20,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() - image_graphic.vmin = 0.5 image_graphic.vmax = 0.75 diff --git a/examples/desktop/image/image_widget.py b/examples/desktop/image/image_widget.py index de1d27de1..131e02bd7 100644 --- a/examples/desktop/image/image_widget.py +++ b/examples/desktop/image/image_widget.py @@ -6,15 +6,17 @@ When run in a notebook, or with the Qt GUI backend, sliders are also shown. """ -# sphinx_gallery_pygfx_docs = 'hidden' +# sphinx_gallery_pygfx_docs = 'screenshot' import fastplotlib as fpl import imageio.v3 as iio # not a fastplotlib dependency, only used for examples a = iio.imread("imageio:camera.png") -iw = fpl.ImageWidget(data=a, cmap="viridis") +iw = fpl.ImageWidget(data=a, cmap="viridis", figure_kwargs={"size": (700, 560)}) iw.show() +figure = iw.figure + # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": diff --git a/examples/desktop/line/line.py b/examples/desktop/line/line.py index cd661da1e..eb1afbe60 100644 --- a/examples/desktop/line/line.py +++ b/examples/desktop/line/line.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) xs = np.linspace(-10, 10, 100) # sine wave @@ -36,11 +36,9 @@ colors = ["r"] * 25 + ["purple"] * 25 + ["y"] * 25 + ["b"] * 25 sinc_graphic = figure[0, 0].add_line(data=sinc, thickness=5, colors=colors) +figure[0, 0].axes.grids.xy.visible = True figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() # 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/desktop/line/line_cmap.py b/examples/desktop/line/line_cmap.py index 5ffea6fef..b7dfe4424 100644 --- a/examples/desktop/line/line_cmap.py +++ b/examples/desktop/line/line_cmap.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) xs = np.linspace(-10, 10, 100) # sine wave @@ -41,7 +41,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) # 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/desktop/line/line_colorslice.py b/examples/desktop/line/line_colorslice.py index 3d18d74b7..0b71efc3d 100644 --- a/examples/desktop/line/line_colorslice.py +++ b/examples/desktop/line/line_colorslice.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) xs = np.linspace(-10, 10, 100) # sine wave @@ -82,9 +82,6 @@ zeros_graphic.cmap[50:75] = "jet" zeros_graphic.cmap[75:] = "viridis" -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() # 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/desktop/line/line_dataslice.py b/examples/desktop/line/line_dataslice.py index eac765c68..83a9ae34a 100644 --- a/examples/desktop/line/line_dataslice.py +++ b/examples/desktop/line/line_dataslice.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) xs = np.linspace(-10, 10, 100) # sine wave @@ -46,9 +46,6 @@ bool_key = [True, True, True, False, False] * 20 sinc_graphic.data[bool_key, 1] = 7 # y vals to 1 -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() # 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/desktop/line_collection/line_collection.py b/examples/desktop/line_collection/line_collection.py index 44b765319..67f3834d3 100644 --- a/examples/desktop/line_collection/line_collection.py +++ b/examples/desktop/line_collection/line_collection.py @@ -29,13 +29,15 @@ def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: pos_xy = np.vstack(circles) -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) figure[0, 0].add_line_collection(circles, cmap="jet", thickness=5) +# remove clutter +figure[0, 0].axes.visible = False + figure.show() -figure.canvas.set_logical_size(700, 560) # 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/desktop/line_collection/line_collection_cmap_values.py b/examples/desktop/line_collection/line_collection_cmap_values.py index e94a161ad..e0b6f2507 100644 --- a/examples/desktop/line_collection/line_collection_cmap_values.py +++ b/examples/desktop/line_collection/line_collection_cmap_values.py @@ -34,15 +34,17 @@ def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: # highest values, lowest values, mid-high values, mid values cmap_values = [10] * 4 + [0] * 4 + [7] * 4 + [5] * 4 -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) figure[0, 0].add_line_collection( circles, cmap="bwr", cmap_transform=cmap_values, thickness=10 ) +# remove clutter +figure[0, 0].axes.visible = False + figure.show() -figure.canvas.set_logical_size(700, 560) # 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/desktop/line_collection/line_collection_cmap_values_qualitative.py b/examples/desktop/line_collection/line_collection_cmap_values_qualitative.py index 5f9ea0000..bbb463c2f 100644 --- a/examples/desktop/line_collection/line_collection_cmap_values_qualitative.py +++ b/examples/desktop/line_collection/line_collection_cmap_values_qualitative.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) @@ -40,7 +41,7 @@ def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: 1, 1, 1, 5 ] -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) figure[0, 0].add_line_collection( circles, @@ -49,9 +50,11 @@ def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: thickness=10 ) +# remove clutter +figure[0, 0].axes.visible = False + figure.show() -figure.canvas.set_logical_size(700, 560) # 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/desktop/line_collection/line_collection_colors.py b/examples/desktop/line_collection/line_collection_colors.py index bf3e818cd..23ca25b25 100644 --- a/examples/desktop/line_collection/line_collection_colors.py +++ b/examples/desktop/line_collection/line_collection_colors.py @@ -33,13 +33,15 @@ def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray: # this will produce 16 circles so we will define 16 colors colors = ["blue"] * 4 + ["red"] * 4 + ["yellow"] * 4 + ["w"] * 4 -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) figure[0, 0].add_line_collection(circles, colors=colors, thickness=10) +# remove clutter +figure[0, 0].axes.visible = False + figure.show() -figure.canvas.set_logical_size(700, 560) # 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/desktop/line_collection/line_collection_slicing.py b/examples/desktop/line_collection/line_collection_slicing.py index a7525f7ba..fbeab53c2 100644 --- a/examples/desktop/line_collection/line_collection_slicing.py +++ b/examples/desktop/line_collection/line_collection_slicing.py @@ -20,12 +20,12 @@ multi_data = np.stack([data] * 15) -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) lines = figure[0, 0].add_line_stack( multi_data, thickness=[2, 10, 2, 5, 5, 5, 8, 8, 8, 9, 3, 3, 3, 4, 4], - separation=1, + separation=4, metadatas=list(range(15)), # some metadata names=list("abcdefghijklmno"), # unique name for each line ) @@ -63,7 +63,15 @@ figure.show(maintain_aspect=False) -figure.canvas.set_logical_size(700, 580) +# individual y axis for each line +for line in lines: + line.add_axes() + line.axes.x.visible = False + line.axes.update_using_bbox(line.world_object.get_world_bounding_box()) + +# no y axis in subplot +figure[0, 0].axes.y.visible = False + if __name__ == "__main__": print(__doc__) diff --git a/examples/desktop/line_collection/line_stack.py b/examples/desktop/line_collection/line_stack.py index e7f7125e1..9ca2a937e 100644 --- a/examples/desktop/line_collection/line_stack.py +++ b/examples/desktop/line_collection/line_stack.py @@ -19,7 +19,7 @@ data = np.column_stack([xs, ys]) multi_data = np.stack([data] * 10) -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) line_stack = figure[0, 0].add_line_stack( multi_data, # shape: (10, 100, 2), i.e. [n_lines, n_points, xy] @@ -30,7 +30,6 @@ figure.show(maintain_aspect=False) -figure.canvas.set_logical_size(700, 560) # 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/desktop/line_collection/line_stack_3d.py b/examples/desktop/line_collection/line_stack_3d.py index 314a97ff2..46a24ef75 100644 --- a/examples/desktop/line_collection/line_stack_3d.py +++ b/examples/desktop/line_collection/line_stack_3d.py @@ -21,7 +21,10 @@ multi_data = np.stack([data] * 10) # create figure to plot lines and use an orbit controller in 3D -figure = fpl.Figure(cameras="3d", controller_types="orbit") +figure = fpl.Figure(cameras="3d", controller_types="orbit", size=(700, 560)) + +# make grid invisible to remove clutter +figure[0, 0].axes.grids.visible = False line_stack = figure[0, 0].add_line_stack( multi_data, # shape: (10, 100, 2), i.e. [n_lines, n_points, xy] @@ -88,7 +91,7 @@ def animate_colors(subplot): "fov": 50.0, "width": 32, "height": 20, - "zoom": 1, + "zoom": 0.7, "maintain_aspect": True, "depth_range": None, } @@ -97,7 +100,6 @@ def animate_colors(subplot): figure[0, 0].camera.set_state(camera_state) -figure.canvas.set_logical_size(700, 560) # 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/desktop/misc/cycle_animation.py b/examples/desktop/misc/cycle_animation.py index bb402a1f7..f866434a1 100644 --- a/examples/desktop/misc/cycle_animation.py +++ b/examples/desktop/misc/cycle_animation.py @@ -34,7 +34,7 @@ colors = ["yellow"] * n_points + ["cyan"] * n_points + ["magenta"] * n_points # create plot -figure = fpl.Figure() +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) @@ -53,10 +53,9 @@ def cycle_colors(subplot): figure.show() -subplot_scatter.canvas.set_logical_size(700, 560) # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": print(__doc__) - fpl.run() \ No newline at end of file + fpl.run() diff --git a/examples/desktop/misc/em_wave_animation.py b/examples/desktop/misc/em_wave_animation.py index 50ab27ed6..bfccedf5f 100644 --- a/examples/desktop/misc/em_wave_animation.py +++ b/examples/desktop/misc/em_wave_animation.py @@ -6,7 +6,7 @@ """ # test_example = false -# sphinx_gallery_pygfx_docs = 'animate' +# sphinx_gallery_pygfx_docs = 'animate 8s' import fastplotlib as fpl import numpy as np @@ -14,7 +14,7 @@ figure = fpl.Figure( cameras="3d", controller_types="orbit", - size=(700, 400) + size=(700, 560) ) start, stop = 0, 4 * np.pi @@ -47,10 +47,6 @@ # 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 -# axes are a WIP, just draw a white line along z for now -z_axis = np.array([[0, 0, 0], [0, 0, stop]]) -figure[0, 0].add_line(z_axis, colors="w", thickness=1) - # just a pre-saved camera state state = { 'position': np.array([-8.0 , 6.0, -2.0]), @@ -68,13 +64,15 @@ figure[0, 0].camera.set_state(state) +# make all grids except xz plane invisible to remove clutter +figure[0, 0].axes.grids.xz.visible = True + figure.show() figure[0, 0].camera.zoom = 1.5 increment = np.pi * 4 / 100 -figure.canvas.set_logical_size(700, 560) # moves the wave one step along the z-axis def tick(subplot): @@ -84,22 +82,34 @@ def tick(subplot): # just change the x-axis vals for the electric field subplot["e"].data[:, 0] = new_data + subplot["e"].data[:, 2] = new_zs # and y-axis vals for magnetic field subplot["m"].data[:, 1] = new_data + subplot["m"].data[:, 2] = new_zs # update the vector lines - for i, (value, z) in enumerate(zip(new_data[::10], zs[::10])): + for i, (value, z) in enumerate(zip(new_data[::10], new_zs[::10])): 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]]) + # update axes and center scene + subplot.axes.z.start_value = start + subplot.axes.z.update(subplot.camera, subplot.viewport.logical_size) + subplot.center_scene() + start += increment stop += increment +figure[0, 0].axes.x.visible = False +figure[0, 0].axes.y.visible = False +figure[0, 0].axes.auto_grid = False + figure[0, 0].add_animations(tick) +print(figure[0, 0]._fpl_graphics_scene.children) # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": print(__doc__) - fpl.run() \ No newline at end of file + fpl.run() diff --git a/examples/desktop/misc/image_animation.py b/examples/desktop/misc/image_animation.py index df84f3c5a..8c323f464 100644 --- a/examples/desktop/misc/image_animation.py +++ b/examples/desktop/misc/image_animation.py @@ -13,7 +13,7 @@ data = np.random.rand(512, 512) -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) # plot the image data image_graphic = figure[0, 0].add_image(data=data, name="random-image") @@ -29,7 +29,6 @@ def update_data(figure_instance): figure.show() -figure.canvas.set_logical_size(700, 560) # 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/desktop/misc/line3d_animation.py b/examples/desktop/misc/line3d_animation.py index 27d22c78a..4f2f089e6 100644 --- a/examples/desktop/misc/line3d_animation.py +++ b/examples/desktop/misc/line3d_animation.py @@ -6,7 +6,7 @@ """ # test_example = false -# sphinx_gallery_pygfx_docs = 'animate 5s' +# sphinx_gallery_pygfx_docs = 'animate 8s' import numpy as np import fastplotlib as fpl @@ -21,7 +21,7 @@ # make data 3d, with shape [, 3] spiral = np.dstack([xs, ys, zs])[0] -figure = fpl.Figure(cameras="3d") +figure = fpl.Figure(cameras="3d", size=(700, 560)) line_graphic = figure[0,0].add_line(data=spiral, thickness=3, cmap='jet') @@ -46,11 +46,13 @@ def move_marker(): # add `move_marker` to the animations figure.add_animations(move_marker) -figure.show() +# remove clutter +figure[0, 0].axes.grids.xy.visible = True +figure[0, 0].axes.grids.xz.visible = True + -figure.canvas.set_logical_size(700, 560) +figure.show() -figure[0,0].auto_scale(maintain_aspect=False) # 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/desktop/misc/line_animation.py b/examples/desktop/misc/line_animation.py index 50faad5c7..a602a6e7d 100644 --- a/examples/desktop/misc/line_animation.py +++ b/examples/desktop/misc/line_animation.py @@ -19,7 +19,7 @@ xs = np.linspace(start, stop, 100) ys = np.sin(xs) -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) # plot the image data sine = figure[0, 0].add_line(ys, name="sine", colors="r") @@ -40,14 +40,11 @@ def update_line(subplot): figure[0, 0].add_animations(update_line) -figure.show() +figure.show(maintain_aspect=False) -figure.canvas.set_logical_size(700, 560) - -figure[0,0].auto_scale(maintain_aspect=False) # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": print(__doc__) - fpl.run() \ No newline at end of file + fpl.run() diff --git a/examples/desktop/misc/multiplot_animation.py b/examples/desktop/misc/multiplot_animation.py index a712ce9ef..b0a942d0a 100644 --- a/examples/desktop/misc/multiplot_animation.py +++ b/examples/desktop/misc/multiplot_animation.py @@ -2,7 +2,7 @@ Multi-Subplot Image Update ========================== -Example showing updating a single plot with new random 512x512 data. +Example showing updating a multiple subplots with new random 512x512 data. """ # test_example = false @@ -12,7 +12,7 @@ import numpy as np # Figure of shape 2 x 3 with all controllers synced -figure = fpl.Figure(shape=(2, 3), controller_ids="sync") +figure = fpl.Figure(shape=(2, 3), controller_ids="sync", size=(700, 560)) # Make a random image graphic for each subplot for subplot in figure: @@ -40,10 +40,9 @@ def update_data(f): # show the gridplot figure.show() -figure.canvas.set_logical_size(700, 560) # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": print(__doc__) - fpl.run() \ No newline at end of file + fpl.run() diff --git a/examples/desktop/misc/scatter_animation.py b/examples/desktop/misc/scatter_animation.py index aa1495dd9..de57292a5 100644 --- a/examples/desktop/misc/scatter_animation.py +++ b/examples/desktop/misc/scatter_animation.py @@ -34,7 +34,7 @@ colors = ["yellow"] * n_points + ["cyan"] * n_points + ["magenta"] * n_points # create plot -figure = fpl.Figure() +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) @@ -50,10 +50,9 @@ def update_points(subplot): figure.show() -subplot_scatter.canvas.set_logical_size(700, 560) # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": print(__doc__) - fpl.run() \ No newline at end of file + fpl.run() diff --git a/examples/desktop/misc/simple_event.py b/examples/desktop/misc/simple_event.py index b6d408862..574b8ea5e 100644 --- a/examples/desktop/misc/simple_event.py +++ b/examples/desktop/misc/simple_event.py @@ -14,7 +14,7 @@ data = iio.imread("imageio:camera.png") # Create a figure -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) # plot sine wave, use a single color image_graphic = figure[0,0].add_image(data=data) @@ -47,8 +47,6 @@ def click_event(event_data): print(xy) -figure.canvas.set_logical_size(700, 560) - # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": diff --git a/examples/desktop/scatter/scatter.py b/examples/desktop/scatter/scatter.py index 05dd7a99b..fe1f6ce6d 100644 --- a/examples/desktop/scatter/scatter.py +++ b/examples/desktop/scatter/scatter.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) # create a random distribution of 10,000 xyz coordinates n_points = 5_000 @@ -35,17 +35,11 @@ # color each of them separately colors = ["yellow"] * n_points + ["cyan"] * n_points + ["magenta"] * n_points -# create plot -figure = fpl.Figure() - # use an alpha value since this will be a lot of points figure[0,0].add_scatter(data=cloud, sizes=3, colors=colors, alpha=0.6) figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() # 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/desktop/scatter/scatter_cmap.py b/examples/desktop/scatter/scatter_cmap.py index 0adf72509..42ff572d8 100644 --- a/examples/desktop/scatter/scatter_cmap.py +++ b/examples/desktop/scatter/scatter_cmap.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) # create a random distribution of 10,000 xyz coordinates n_points = 5_000 @@ -42,9 +42,6 @@ figure[0,0].graphics[0].cmap = "viridis" -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() # 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/desktop/scatter/scatter_cmap_iris.py b/examples/desktop/scatter/scatter_cmap_iris.py index 700f5c136..b25369c60 100644 --- a/examples/desktop/scatter/scatter_cmap_iris.py +++ b/examples/desktop/scatter/scatter_cmap_iris.py @@ -13,7 +13,7 @@ from sklearn import datasets -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) data = datasets.load_iris()["data"] @@ -30,10 +30,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() - scatter_graphic.cmap = "tab10" diff --git a/examples/desktop/scatter/scatter_colorslice.py b/examples/desktop/scatter/scatter_colorslice.py index 3d3a3fa26..839df3826 100644 --- a/examples/desktop/scatter/scatter_colorslice.py +++ b/examples/desktop/scatter/scatter_colorslice.py @@ -11,7 +11,7 @@ import fastplotlib as fpl import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) # create a random distribution of 10,000 xyz coordinates n_points = 5_000 @@ -35,20 +35,13 @@ # color each of them separately colors = ["yellow"] * n_points + ["cyan"] * n_points + ["magenta"] * n_points -# create plot -figure = fpl.Figure() - # use an alpha value since this will be a lot of points figure[0,0].add_scatter(data=cloud, sizes=3, colors=colors, alpha=0.6) figure.show() -figure.canvas.set_logical_size(700, 560) - scatter_graphic = figure[0, 0].graphics[0] -figure[0, 0].auto_scale() - scatter_graphic.colors[0:75] = "red" scatter_graphic.colors[75:150] = "white" scatter_graphic.colors[::2] = "blue" diff --git a/examples/desktop/scatter/scatter_colorslice_iris.py b/examples/desktop/scatter/scatter_colorslice_iris.py index a1e6d5318..92df1f66c 100644 --- a/examples/desktop/scatter/scatter_colorslice_iris.py +++ b/examples/desktop/scatter/scatter_colorslice_iris.py @@ -12,7 +12,7 @@ from sklearn import datasets -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) data = datasets.load_iris()["data"] @@ -28,10 +28,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() - scatter_graphic.colors[0:75] = "red" scatter_graphic.colors[75:150] = "white" scatter_graphic.colors[::2] = "blue" diff --git a/examples/desktop/scatter/scatter_dataslice.py b/examples/desktop/scatter/scatter_dataslice.py index af2fffebd..715959e06 100644 --- a/examples/desktop/scatter/scatter_dataslice.py +++ b/examples/desktop/scatter/scatter_dataslice.py @@ -12,7 +12,7 @@ import numpy as np -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) # create a gaussian cloud of 5_000 points n_points = 1_000 @@ -23,19 +23,12 @@ gaussian_cloud = np.random.multivariate_normal(mean, covariance, n_points) gaussian_cloud2 = np.random.multivariate_normal(mean, covariance, n_points) -# create plot -figure = fpl.Figure() - # 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) figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() - scatter1.data[:500] = np.array([0 , 0, 0]) scatter2.data[500:] = np.array([0 , 0, 0]) diff --git a/examples/desktop/scatter/scatter_dataslice_iris.py b/examples/desktop/scatter/scatter_dataslice_iris.py index 0d47c6efd..04ac4b85f 100644 --- a/examples/desktop/scatter/scatter_dataslice_iris.py +++ b/examples/desktop/scatter/scatter_dataslice_iris.py @@ -13,7 +13,7 @@ from sklearn import datasets -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) data = datasets.load_iris()["data"] @@ -24,10 +24,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() - scatter_graphic.data[0] = np.array([[5, 3, 1.5]]) scatter_graphic.data[1] = np.array([[4.3, 3.2, 1.3]]) scatter_graphic.data[2] = np.array([[5.2, 2.7, 1.7]]) diff --git a/examples/desktop/scatter/scatter_iris.py b/examples/desktop/scatter/scatter_iris.py index c16a4b135..6937ffe4b 100644 --- a/examples/desktop/scatter/scatter_iris.py +++ b/examples/desktop/scatter/scatter_iris.py @@ -13,7 +13,7 @@ from pathlib import Path import sys -figure = fpl.Figure() +figure = fpl.Figure(size=(700, 560)) current_file = Path(sys.argv[0]).resolve() @@ -27,12 +27,9 @@ figure.show() -figure.canvas.set_logical_size(700, 560) - -figure[0, 0].auto_scale() # NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively # please see our docs for using fastplotlib interactively in ipython and jupyter if __name__ == "__main__": print(__doc__) - fpl.run() \ No newline at end of file + fpl.run() diff --git a/examples/desktop/scatter/scatter_size.py b/examples/desktop/scatter/scatter_size.py index bd4e2db2b..0cecb6dad 100644 --- a/examples/desktop/scatter/scatter_size.py +++ b/examples/desktop/scatter/scatter_size.py @@ -18,7 +18,7 @@ names = [["scalar_size"], ["array_size"]] # Create the grid plot -figure = fpl.Figure(shape=shape, names=names, size=(1000, 1000)) +figure = fpl.Figure(shape=shape, names=names, size=(700, 560)) # get y_values using sin function angles = np.arange(0, 20 * np.pi + 0.001, np.pi / 20) @@ -39,7 +39,6 @@ figure.show() -figure.canvas.set_logical_size(700, 560) # 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/desktop/screenshots/gridplot.png b/examples/desktop/screenshots/gridplot.png index 315958673..99ba70155 100644 --- a/examples/desktop/screenshots/gridplot.png +++ b/examples/desktop/screenshots/gridplot.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d43e6972bf76aa2de400616bde4275cd05d3a945475742ec7f63f7658628292b -size 264437 +oid sha256:a0da6067ecd930fb0add52124dfd97f7d73b27ab7696df681c75e333c749975a +size 328971 diff --git a/examples/desktop/screenshots/gridplot_non_square.png b/examples/desktop/screenshots/gridplot_non_square.png index 689585b40..6db1c3f2a 100644 --- a/examples/desktop/screenshots/gridplot_non_square.png +++ b/examples/desktop/screenshots/gridplot_non_square.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:703285790dc96500a7a376f6e78953c943643f4ecf3102182072c2bd0bf8190c -size 173753 +oid sha256:2763431048efa1642a276bc3e659ed93a2f787ff6db700bcd29acc619d542f3f +size 236206 diff --git a/examples/desktop/screenshots/heatmap.png b/examples/desktop/screenshots/heatmap.png index 0514daf94..a8f91765e 100644 --- a/examples/desktop/screenshots/heatmap.png +++ b/examples/desktop/screenshots/heatmap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:03b3ab1fc8aa602eb94beed1f5fa5712452ee802bb3230c4fd066d073bdd4ad2 -size 40100 +oid sha256:d40c5e47f686dc498f003684efeefc16e6962d6ce1e2edc4c2cd8537b3ff3387 +size 82267 diff --git a/examples/desktop/screenshots/image_cmap.png b/examples/desktop/screenshots/image_cmap.png index 91124db6a..837d6765f 100644 --- a/examples/desktop/screenshots/image_cmap.png +++ b/examples/desktop/screenshots/image_cmap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f18a55da8cede25dbb77b18e8cf374d158a66b823d029714983218e55ee68249 -size 187688 +oid sha256:95ed35b1ab7d5e56ff81e883d5c56419ddede3481f1a0c77f5af01dba83d03ea +size 236774 diff --git a/examples/desktop/screenshots/image_rgb.png b/examples/desktop/screenshots/image_rgb.png index 8ae39eaad..2ca946c15 100644 --- a/examples/desktop/screenshots/image_rgb.png +++ b/examples/desktop/screenshots/image_rgb.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3851bea9ee908a460750b40a0a5709aff1b28afa6adf11c9ad2ed8239958caa4 -size 216343 +oid sha256:86e421deb8e013f25737b9a752409890ba14f794a1a01fbed728d474490292bb +size 269316 diff --git a/examples/desktop/screenshots/image_rgbvminvmax.png b/examples/desktop/screenshots/image_rgbvminvmax.png index 478ce40fe..c31263344 100644 --- a/examples/desktop/screenshots/image_rgbvminvmax.png +++ b/examples/desktop/screenshots/image_rgbvminvmax.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ec8ddd362197ba802f8381d5baea226dc30689eee5e5dc744c2da710f0b3482 -size 33860 +oid sha256:fc5983f07d840320bf6866896d221845f59eecedbc6d89a7a0bc5dd1f6472c7b +size 49999 diff --git a/examples/desktop/screenshots/image_simple.png b/examples/desktop/screenshots/image_simple.png index c60293498..194e5afe4 100644 --- a/examples/desktop/screenshots/image_simple.png +++ b/examples/desktop/screenshots/image_simple.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:216791f48cee8ddb9979ecc8b7b7435c0fe22c2734148c25314f1827a5c9ad66 -size 187868 +oid sha256:ec0770ff5671a9f83f43f8ece18e45b74137244ff578b8035eace3fd98291595 +size 237699 diff --git a/examples/desktop/screenshots/image_small.png b/examples/desktop/screenshots/image_small.png index cda3a2584..5ed8f615d 100644 --- a/examples/desktop/screenshots/image_small.png +++ b/examples/desktop/screenshots/image_small.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f2af0ed16ec82842ad9d45d5a8b6189e77a2f2f8adb21dd82bc1636979cd2c7 -size 2325 +oid sha256:3818b137bcfce829ea6a8670ca52a20122b2489f536ca5ff38e0ed6288043113 +size 12824 diff --git a/examples/desktop/screenshots/image_vminvmax.png b/examples/desktop/screenshots/image_vminvmax.png index 478ce40fe..c31263344 100644 --- a/examples/desktop/screenshots/image_vminvmax.png +++ b/examples/desktop/screenshots/image_vminvmax.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ec8ddd362197ba802f8381d5baea226dc30689eee5e5dc744c2da710f0b3482 -size 33860 +oid sha256:fc5983f07d840320bf6866896d221845f59eecedbc6d89a7a0bc5dd1f6472c7b +size 49999 diff --git a/examples/desktop/screenshots/line.png b/examples/desktop/screenshots/line.png index 605540225..3cf15db2d 100644 --- a/examples/desktop/screenshots/line.png +++ b/examples/desktop/screenshots/line.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d7f3736d4464cfd942e87d21be1a18d09f5d0d239a7e1c7679e918dcc5c9331c -size 26701 +oid sha256:e0ea3004cc871f54d1f12f6e5a39afbda568748ca907468a0533268949c67916 +size 173435 diff --git a/examples/desktop/screenshots/line_cmap.png b/examples/desktop/screenshots/line_cmap.png index cab91220f..6ec5a4998 100644 --- a/examples/desktop/screenshots/line_cmap.png +++ b/examples/desktop/screenshots/line_cmap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f154346cffbaa0957a9986d8b7beef417b66ef0cec7dbed3c20780d91425567 -size 29231 +oid sha256:cbf54efd9999593043c48a53f189c675ef6544a962c44297ce76df4fbe75ad42 +size 47804 diff --git a/examples/desktop/screenshots/line_collection.png b/examples/desktop/screenshots/line_collection.png index f3fb5052b..ffe8cc96e 100644 --- a/examples/desktop/screenshots/line_collection.png +++ b/examples/desktop/screenshots/line_collection.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca08ce57a1cf57c334add1c41351f3b823f06ad8da463017d0815cf7cfea03b3 -size 91085 +oid sha256:b373c63989b4d3d3c9b5ea1607ef1602fa7d45753cdc0895a6e6d1d4a2c5420b +size 106504 diff --git a/examples/desktop/screenshots/line_collection_cmap_values.png b/examples/desktop/screenshots/line_collection_cmap_values.png index 33af5b917..66d36dec3 100644 --- a/examples/desktop/screenshots/line_collection_cmap_values.png +++ b/examples/desktop/screenshots/line_collection_cmap_values.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12ddca084dc83478c6b3d263f11f456f8b81e7a8a291d6b9024dbcecbfb049c0 -size 57107 +oid sha256:dff530c128132f26aded7c2ad9e202cc98e7486fbad84146a9055b6514c99453 +size 67561 diff --git a/examples/desktop/screenshots/line_collection_cmap_values_qualitative.png b/examples/desktop/screenshots/line_collection_cmap_values_qualitative.png index 57f45605b..b144dbdcb 100644 --- a/examples/desktop/screenshots/line_collection_cmap_values_qualitative.png +++ b/examples/desktop/screenshots/line_collection_cmap_values_qualitative.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74d5999cdd0b992f73bafb1bd74c318fd9cf058aed232068ab7dcb76d86df556 -size 60881 +oid sha256:ce6e25567214539b296248a4dc665552f47687cda03d412f715db7f72138c341 +size 69992 diff --git a/examples/desktop/screenshots/line_collection_colors.png b/examples/desktop/screenshots/line_collection_colors.png index 9c27854ed..90948c126 100644 --- a/examples/desktop/screenshots/line_collection_colors.png +++ b/examples/desktop/screenshots/line_collection_colors.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a152331c51ed5440c5faf2a59439d90832521fbb1498d9635ddae088219ca353 -size 46941 +oid sha256:9aeb3ef27fd7a393b4884749e7988e8cde3906c9f19b573e51bd78bf31fc7a45 +size 60514 diff --git a/examples/desktop/screenshots/line_collection_slicing.png b/examples/desktop/screenshots/line_collection_slicing.png index 1145e84dc..26933c5cc 100644 --- a/examples/desktop/screenshots/line_collection_slicing.png +++ b/examples/desktop/screenshots/line_collection_slicing.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bdfdc2b2c5799e814ef5a1e32748a2a6d2dd88005f6fa0d9c456b8dadfada5db -size 124609 +oid sha256:beb5193965530c490324edeb253ed429237e44289c5239079743a71d2aece797 +size 132171 diff --git a/examples/desktop/screenshots/line_colorslice.png b/examples/desktop/screenshots/line_colorslice.png index 825ce8e3f..34ff56c4f 100644 --- a/examples/desktop/screenshots/line_colorslice.png +++ b/examples/desktop/screenshots/line_colorslice.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de5a56c96a062ed0ec154ae21f3a3a67087e0c8aef6d8e4681c67a016424144a -size 31971 +oid sha256:c8afbeb5a79192eb1805c7c8478b26f6aabc534f3ac58fc7190f108ebb8640fe +size 56462 diff --git a/examples/desktop/screenshots/line_dataslice.png b/examples/desktop/screenshots/line_dataslice.png index 71c3d1918..c135997bb 100644 --- a/examples/desktop/screenshots/line_dataslice.png +++ b/examples/desktop/screenshots/line_dataslice.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e4dece6f721068a1ae37c6830110f97df64ea57c467ef4d7f42b73575d2ee476 -size 43995 +oid sha256:e6c5c4ef3aaeca5597c11e5db3764599c8c41b191c692db5fda54f525d8079da +size 68033 diff --git a/examples/desktop/screenshots/line_stack.png b/examples/desktop/screenshots/line_stack.png index 026b1f61e..ea5a3a330 100644 --- a/examples/desktop/screenshots/line_stack.png +++ b/examples/desktop/screenshots/line_stack.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1384f1030e81fc05b24db040ac47a3bd62663358dcbdd0e77b3d675d5edd4357 -size 86938 +oid sha256:cdb26c1460583f8f605ffe6751c926c0e84463b10d68343169660593b82a9078 +size 130495 diff --git a/examples/desktop/screenshots/linear_selector.png b/examples/desktop/screenshots/linear_selector.png new file mode 100644 index 000000000..2db42319d --- /dev/null +++ b/examples/desktop/screenshots/linear_selector.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09f60f24e702dd6b17ba525604c1a04f23682eb08c8c2100d45a34b2626bebc6 +size 153115 diff --git a/examples/desktop/screenshots/scatter_cmap_iris.png b/examples/desktop/screenshots/scatter_cmap_iris.png index 2a6ae7016..96acbec6c 100644 --- a/examples/desktop/screenshots/scatter_cmap_iris.png +++ b/examples/desktop/screenshots/scatter_cmap_iris.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b781b387476028a5eaf2083c40d57306afbcbc2a6754dce6fb66cf71ddd689d1 -size 31719 +oid sha256:79f7d22b575c3a68dfdcd4bf806f79f1896a784ecbb6a2d3ba01da5731fa78dd +size 59731 diff --git a/examples/desktop/screenshots/scatter_colorslice_iris.png b/examples/desktop/screenshots/scatter_colorslice_iris.png index 45c5d940c..73fcddebf 100644 --- a/examples/desktop/screenshots/scatter_colorslice_iris.png +++ b/examples/desktop/screenshots/scatter_colorslice_iris.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68f93c08d361232c9be2220a68db8659c9c3c81c3cdb4e1a1ce9b366fb28b4f5 -size 13215 +oid sha256:3c778cf9c51c9636d4f4ff13e4a1c841795a4dba327eb7118de2a0fb60c7e3f3 +size 35810 diff --git a/examples/desktop/screenshots/scatter_dataslice_iris.png b/examples/desktop/screenshots/scatter_dataslice_iris.png index 1121d032c..32f797c67 100644 --- a/examples/desktop/screenshots/scatter_dataslice_iris.png +++ b/examples/desktop/screenshots/scatter_dataslice_iris.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d662e151062a136a17dac1f8693ba13f41daac05e91e32ee9c7053715f9ee17 -size 14437 +oid sha256:444f0bd81459a4977df2eb9aa5645c0f7745fce97baa0c9e39c254bd32cdb1e6 +size 38351 diff --git a/examples/desktop/screenshots/scatter_iris.png b/examples/desktop/screenshots/scatter_iris.png index 7d107d964..dc53d97b0 100644 --- a/examples/desktop/screenshots/scatter_iris.png +++ b/examples/desktop/screenshots/scatter_iris.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4fc88e52cc4ede6d1453746461da645f8b3df0a3099155caf639768a5ad4424c -size 14148 +oid sha256:153db7a803709978a1a997d7c94db37ebc0504ec9a7eebce80977d4c90d48f61 +size 37365 diff --git a/examples/desktop/screenshots/scatter_size.png b/examples/desktop/screenshots/scatter_size.png index 66b31cab9..74c1b6e56 100644 --- a/examples/desktop/screenshots/scatter_size.png +++ b/examples/desktop/screenshots/scatter_size.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d1eeb96dc1f52c4d48889a8b00387387cccb7b83d479c1c4b47789b281a1cd5 -size 34222 +oid sha256:381877c06882f40a8b46bbe07e1e1ca41a74ff9cda84544cca4ee92a4b522cda +size 62476 diff --git a/examples/desktop/selectors/README.rst b/examples/desktop/selectors/README.rst new file mode 100644 index 000000000..0f7e412a7 --- /dev/null +++ b/examples/desktop/selectors/README.rst @@ -0,0 +1,2 @@ +Selection Tools +=============== \ No newline at end of file diff --git a/examples/desktop/selectors/linear_selector.py b/examples/desktop/selectors/linear_selector.py new file mode 100644 index 000000000..b224c197f --- /dev/null +++ b/examples/desktop/selectors/linear_selector.py @@ -0,0 +1,157 @@ +""" +Linear Selectors +================ + +Example showing how to use a `LinearSelector` with lines, line collections, and images +""" + +# test_example = false +# sphinx_gallery_pygfx_docs = 'screenshot' + +import fastplotlib as fpl +import numpy as np + +# create some data +xs = np.linspace(0, 10 * np.pi, 100) +sine = np.column_stack([xs, np.sin(xs)]) +cosine = np.column_stack([xs, np.cos(xs)]) + +# a varying sine-cosine quilted pattern +image_xs, image_ys = np.meshgrid(xs, xs) +multiplier = np.linspace(0, 10, 100) +image_data = multiplier * np.sin(image_xs) + multiplier * np.cos(image_ys) + +# create a figure +figure = fpl.Figure( + shape=(2, 2), + size=(700, 560) +) + +# line of a single sine wave from 0 - 10π +line = figure[0, 0].add_line(sine, cmap="jet") + +# 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()}") + +# 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.), + anchor="middle-left", + font_size=22, + face_color=line.colors[0], + outline_color="w", + outline_thickness=0.1, +) + + +# add an event handler using a decorator, selectors are just like other graphics +@line_selector.add_event_handler("selection") +def line_selector_changed(ev): + selection = ev.info["value"] + 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}") + + # 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_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") + +# 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.), + anchor="middle-left", + font_size=18, + face_color="w", +) + + +# add an event handler using a decorator +@line_stack_selector.add_event_handler("selection") +def line_stack_selector_changed(ev): + selection = ev.info["value"] + + # a linear selectors one a line collection returns a + # list of selected indices for each graphic in the collection + 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") + + +# create an image +image = figure[1, 0].add_image(image_data) + +# add a row selector +image_row_selector = image.add_linear_selector(axis="y") + +# add column selector +image_col_selector = image.add_linear_selector() + +# make a line to indicate row data +line_image_row = figure[1, 1].add_line(image.data[0]) + +# make a line to indicate column data +line_image_col_data = np.column_stack([image.data[:, 0], np.arange(100)]) +line_image_col = figure[1, 1].add_line(line_image_col_data) + + +# callbacks to change the line data in subplot [1, 1] +# to display selected row and selected column data +def image_row_selector_changed(ev): + ix = ev.get_selected_index() + new_data = image.data[ix] + # set y values of line + line_image_row.data[:, 1] = new_data + + +def image_col_selector_changed(ev): + ix = ev.get_selected_index() + new_data = image.data[:, ix] + # set x values of line + line_image_col.data[:, 0] = new_data + + +# add event handlers, you can also use a decorator +image_row_selector.add_event_handler(image_row_selector_changed, "selection") +image_col_selector.add_event_handler(image_col_selector_changed, "selection") + +figure.show(maintain_aspect=False) + +# some axes and camera zoom settings +for subplot in [figure[0, 0], figure[0, 1]]: + subplot.axes.auto_grid = False + subplot.axes.grids.xy.major_step = (np.pi, 1) + subplot.axes.grids.xy.minor_step = (0, 0) + subplot.camera.zoom = 0.6 + +figure[1, 1].camera.zoom = 0.5 + + +# NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively +# please see our docs for using fastplotlib interactively in ipython and jupyter +if __name__ == "__main__": + print(__doc__) + fpl.run() \ No newline at end of file diff --git a/examples/notebooks/image_widget_test.ipynb b/examples/notebooks/image_widget_test.ipynb index 321f7b84f..aaf41f3e3 100644 --- a/examples/notebooks/image_widget_test.ipynb +++ b/examples/notebooks/image_widget_test.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "07019035-83f2-4753-9e7c-628ae439b441", "metadata": { "tags": [] @@ -18,14 +18,12 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "10b8ab40-944d-472c-9b7e-cae8a129e7ce", "metadata": {}, "outputs": [], "source": [ - "from nb_test_utils import plot_test, notebook_finished\n", - "import nb_test_utils\n", - "nb_test_utils.TOLERANCE = 0.035" + "from nb_test_utils import plot_test, notebook_finished" ] }, { @@ -450,7 +448,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "id": "ed783360-992d-40f8-bb6f-152a59edff43", "metadata": {}, "outputs": [], @@ -465,7 +463,7 @@ " rgb=[False, True],\n", " histogram_widget=True,\n", " cmap=\"gnuplot2\", \n", - " figure_kwargs = {\"controller_ids\": None},\n", + " figure_kwargs={\"controller_ids\": None, \"size\": (900, 400)},\n", ")\n", "\n", "iw_mixed_shapes.show()" @@ -473,7 +471,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": null, "id": "274c67b4-aa07-4fcf-a094-1b1e70d0378a", "metadata": {}, "outputs": [], @@ -481,11 +479,11 @@ "iw_mixed_shapes.sliders[\"t\"].value = 50\n", "plot_test(\"image-widget-zfish-mixed-rgb-cockatoo-frame-50\", iw_mixed_shapes.figure)\n", "\n", - "#Set the data, changing the first array and also the size of the \"T\" slider\n", + "# Set the data, changing the first array and also the size of the \"T\" slider\n", "iw_mixed_shapes.set_data([zfish_frame_2, movie[:200, :, :, :]], reset_indices=True)\n", "plot_test(\"image-widget-zfish-mixed-rgb-cockatoo-set-data\", iw_mixed_shapes.figure)\n", "\n", - "#Check how a window function might work on the RGB data\n", + "# Check how a window function might work on the RGB data\n", "iw_mixed_shapes.window_funcs = {\"t\": (np.mean, 4)}\n", "iw_mixed_shapes.sliders[\"t\"].value = 20\n", "plot_test(\"image-widget-zfish-mixed-rgb-cockatoo-windowrgb\", iw_mixed_shapes.figure)" @@ -518,7 +516,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.11.3" } }, "nbformat": 4, diff --git a/examples/notebooks/lineplot.ipynb b/examples/notebooks/lineplot.ipynb index 85ebb60f5..e700c866a 100644 --- a/examples/notebooks/lineplot.ipynb +++ b/examples/notebooks/lineplot.ipynb @@ -69,11 +69,6 @@ "for i, subplot in enumerate(fig):\n", " # create and add the LineGraphic\n", " line_graphic = subplot.add_line(data=spiral, thickness=3, cmap='jet')\n", - " \n", - " # make axes visible\n", - " subplot.set_axes_visibility(True)\n", - " subplot.set_grid_visibility(True)\n", - " \n", " marker = subplot.add_scatter(data=spiral[0], sizes=10, name=\"marker\")\n", " \n", "marker_index = 0\n", @@ -121,7 +116,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.3" + "version": "3.11.2" } }, "nbformat": 4, diff --git a/examples/notebooks/nb_test_utils.py b/examples/notebooks/nb_test_utils.py index 791640fe2..3d9e50d34 100644 --- a/examples/notebooks/nb_test_utils.py +++ b/examples/notebooks/nb_test_utils.py @@ -16,7 +16,7 @@ os.makedirs(SCREENSHOTS_DIR, exist_ok=True) os.makedirs(DIFFS_DIR, exist_ok=True) -TOLERANCE = 0.025 +TOLERANCE = 0.05 # store all the failures to allow the nb to proceed to test other examples FAILURES = list() diff --git a/examples/notebooks/scatter.ipynb b/examples/notebooks/scatter.ipynb index b78521064..0389b462b 100644 --- a/examples/notebooks/scatter.ipynb +++ b/examples/notebooks/scatter.ipynb @@ -92,9 +92,6 @@ "\n", "for subplot in fig:\n", " subplot.add_scatter(data=cloud, colors=colors, alpha=0.7, sizes=5)\n", - " \n", - " subplot.set_axes_visibility(True)\n", - " subplot.set_grid_visibility(True)\n", "\n", "\n", "fig.show()" @@ -185,7 +182,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.3" + "version": "3.11.2" } }, "nbformat": 4, diff --git a/examples/notebooks/screenshots/nb-astronaut.png b/examples/notebooks/screenshots/nb-astronaut.png index 9c28b6cfa..70c1a95a7 100644 --- a/examples/notebooks/screenshots/nb-astronaut.png +++ b/examples/notebooks/screenshots/nb-astronaut.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:afb405dfcd90d9165b4be8c2b79a82b45964debb119d25851835b8a6e2f18785 -size 111986 +oid sha256:c1491279a44125be3fc51678a2662b0632d8618a7425b7894677a7eba919eae9 +size 84735 diff --git a/examples/notebooks/screenshots/nb-astronaut_RGB.png b/examples/notebooks/screenshots/nb-astronaut_RGB.png index 1939c12d7..0443de1c4 100644 --- a/examples/notebooks/screenshots/nb-astronaut_RGB.png +++ b/examples/notebooks/screenshots/nb-astronaut_RGB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f86ef886266279ace4672904860bdaeee49dd23498998c8f68ae0b36cecc529 -size 110588 +oid sha256:716e19f1f9d16443602de327716daee8663731e1afccfa4a9b16c68ffd3b0c11 +size 76074 diff --git a/examples/notebooks/screenshots/nb-camera.png b/examples/notebooks/screenshots/nb-camera.png index cfdf2673e..e71803ade 100644 --- a/examples/notebooks/screenshots/nb-camera.png +++ b/examples/notebooks/screenshots/nb-camera.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:124e52fdb8c200be3295f79331f25a51d423d159a7f8cde1863daa00e54c0894 -size 77665 +oid sha256:b84ffb87948cfd523941041a3c9c6827ccac51bb5648faddd810d15a4bd0912c +size 52034 diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-set_data.png b/examples/notebooks/screenshots/nb-image-widget-movie-set_data.png index e49ad3c38..e8e74e817 100644 --- a/examples/notebooks/screenshots/nb-image-widget-movie-set_data.png +++ b/examples/notebooks/screenshots/nb-image-widget-movie-set_data.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5acd7eeccbf47af45aa8306befb040f9b53d21f1727e7366b536d73261b407ce -size 43494 +oid sha256:d9421323aac16e9e8d3489332b7db7b2381effc4b10a132e2c58dc86544720ae +size 45797 diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-0-reset.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-0-reset.png index dfcb98736..4fce1c96a 100644 --- a/examples/notebooks/screenshots/nb-image-widget-movie-single-0-reset.png +++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-0-reset.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ca702fffc4eebea5ba31b77062b60f848c2e5d689568d16b39a62561a0b8b73 -size 134201 +oid sha256:949885c0eab52bbb5293aa74ded4d3dedfd5172d1217934fa8963b7c74f176e8 +size 118713 diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-0.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-0.png index dfcb98736..ffb80c4ec 100644 --- a/examples/notebooks/screenshots/nb-image-widget-movie-single-0.png +++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ca702fffc4eebea5ba31b77062b60f848c2e5d689568d16b39a62561a0b8b73 -size 134201 +oid sha256:f05522f502bc848086c01ba86f17036b310617e8bfb239d83505ef31c2ad23a7 +size 106685 diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-279.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-279.png index 787e2757e..0063b3fa2 100644 --- a/examples/notebooks/screenshots/nb-image-widget-movie-single-279.png +++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-279.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:73bdd6a91ab679dcf237626bc7d3edd267d402ea8de2b6e2c3db7bba9b9418ac -size 169211 +oid sha256:9cb358df1f9dcb67f26818cad619c0740f25602cdbb634b737112d6d43c89fc8 +size 142265 diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-max-33.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-max-33.png index ca2357ddd..9c48d5258 100644 --- a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-max-33.png +++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-max-33.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:afb9c5bfbfbc2ce800d613f779021b0a93d098f415d89157f994cc9b1632361b -size 149454 +oid sha256:62c303c87a6fbc2f2874b817ca0d938b8a6f83042e81a659d9feb7d7fe7442a6 +size 127805 diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-13.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-13.png index ac3f4cb61..388a280e1 100644 --- a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-13.png +++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-13.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c3c07d75cd4673e411d814c1dab1e62d6543b26c89f208eed15ccb941bbe3ab2 -size 124795 +oid sha256:b22f9823bab849de025b256558f008efdfadcb181c66510f32293d2fea53c6f0 +size 110339 diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-33.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-33.png index 3a77efced..1d0802226 100644 --- a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-33.png +++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-33.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f39d68bbc2c7d52cc13609ff60274dbfe49bea4d4a03cfbf1d1c15cf7fb8e8c -size 114013 +oid sha256:5baf57418ed6f36278715187250ac69307cd88eb4232df586a3c929ffbc40d4b +size 102774 diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-reset.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-reset.png index e34f9deb3..6534b9907 100644 --- a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-reset.png +++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-reset.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2825af49b1964fb76dcf2ccd494bb61623df4d5fffad7be30cf389b9b7e6d4bf -size 146186 +oid sha256:e009147472683c8d207a23d7c64575465f936ee48250dfa9fe15654ed7d34403 +size 126018 diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-50.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-50.png index e34f9deb3..6534b9907 100644 --- a/examples/notebooks/screenshots/nb-image-widget-movie-single-50.png +++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-50.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2825af49b1964fb76dcf2ccd494bb61623df4d5fffad7be30cf389b9b7e6d4bf -size 146186 +oid sha256:e009147472683c8d207a23d7c64575465f936ee48250dfa9fe15654ed7d34403 +size 126018 diff --git a/examples/notebooks/screenshots/nb-image-widget-single-gnuplot2.png b/examples/notebooks/screenshots/nb-image-widget-single-gnuplot2.png index 4cd3248a0..f157e63c2 100644 --- a/examples/notebooks/screenshots/nb-image-widget-single-gnuplot2.png +++ b/examples/notebooks/screenshots/nb-image-widget-single-gnuplot2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aff55757a29cac06c1c158599681e8c10e27fd772425c6b3137a06d5d604f95e -size 435106 +oid sha256:4d77e42683f74dbd311aa56e5c66b4bb90449e5e52a5a9d4ae3a04cf774ca4df +size 306329 diff --git a/examples/notebooks/screenshots/nb-image-widget-single.png b/examples/notebooks/screenshots/nb-image-widget-single.png index dd37a74db..c262e74ce 100644 --- a/examples/notebooks/screenshots/nb-image-widget-single.png +++ b/examples/notebooks/screenshots/nb-image-widget-single.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e70812decf8d1c591b1d97c24346159255e8b5cba5722f9c4d67c5b5aa92a8a -size 403368 +oid sha256:a0f6a4eea4dcf0100b6cdd89892fb02bc2d2c5396445ef0694a0810b9d4465e8 +size 274170 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-gaussian.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-gaussian.png index 9be76e5bd..a78761846 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-gaussian.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-gaussian.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d6b97c351f51ee8b0429e7001ba16cb3862c9cfc4f4e0f0227524b8c20d5906 -size 157300 +oid sha256:de65879e7ad15cd85740c989d62bd27e4e2fdbe61de3585238caaa52b554fa95 +size 129651 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-reset.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-reset.png index c877ac887..f5989caa9 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-reset.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-reset.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d74649c5ca7b0401a8e42ffe9b73cebeebdce80953c4790f44a99bfe6624902b -size 71618 +oid sha256:828e3e104d21f0cc743f16b72152642aa276d5727258b4454a3f5dcc6514ac7e +size 81188 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-max-window-13.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-max-window-13.png index 7613ae2a9..3e3cdc025 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-max-window-13.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-max-window-13.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9c99c189dbfffbc3fa24fb6f48015518a2e1c3e681191abb45cf4e29185dcff -size 196855 +oid sha256:e615d9dbcbc09d14eb1ab2aea14c609e996e0f96bafdf3c4513acd0613260509 +size 205824 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-13.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-13.png index e803cdc68..22fe4e54d 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-13.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-13.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:916800ae449d12e875f14be3d13a75db85339524dbd594f9963074b9fc5316ae -size 177769 +oid sha256:d81c351726c3eb1cbef662b28454747e6074374bdd2203d0e71835c6611cda11 +size 151657 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-5.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-5.png index 5b5ef1009..e6a877eec 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-5.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3006a07bfbf6276967ca55809788f61a1852db9851f959cc1db00016a9b3747f -size 140019 +oid sha256:71676028d9a29fb4dbb4e3aaa3dd9173dff585fe08300a5d8884e6d8e413952e +size 131857 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50.png index 4e8803a7b..023cb947c 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e55ffde023955d00804a7272a4e963b4d2a74b74fb401962d32c1a29d76bc24 -size 80880 +oid sha256:dc841d0a37938319d177ecd74662de486c4fe2bc8be35de456ad7a3abd4ca329 +size 90997 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-99.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-99.png index 061195a98..c1fa94056 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-99.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-99.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:405495c384aa52d6e3c8a65237876682f4be62967dce1b6af526e4d069fa44d3 -size 62621 +oid sha256:42a51e116e1455fcea00dd9ea9f387633df31e185706cd0fd18e8101947718be +size 74817 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-gaussian.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-gaussian.png index 0da3abb21..f79d956b0 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-gaussian.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-gaussian.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b30ef1dca9711bd72eb28f0035552f93e143a683f818c3f2aec8df4323306e4 -size 178459 +oid sha256:f9900ac2df273c48d163538c6cbda2d4b43245bbcc55f759a50883aaf51cf876 +size 160362 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-reset.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-reset.png index 21ea17c27..572e1c2a7 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-reset.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-reset.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b3e8fc84f5ea2d5a93bc02e19965781fbe9ec697b660430a5203cb1c91803974 -size 142748 +oid sha256:35d948baddc0c069e65d63d04fb3f22276dd936deee281fdf0bf31c2203c0e01 +size 156432 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-max-window-13.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-max-window-13.png index ece0fee5f..8f083da9b 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-max-window-13.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-max-window-13.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b01f2385991f4941f35d1b913fe54c72cbe42c62522ab181ddb2466b2f2be8d -size 372324 +oid sha256:371727d51121efa1f6250f9aebdb1a3847e2ef79cf1a9137d5c07b8738114b9b +size 307668 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-13.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-13.png index 93dd3b254..e59f9020f 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-13.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-13.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4bac6aedfebab2bf97497dbecd17f59b36cb78b27dcdb1547c6d78f902d5f89b -size 213579 +oid sha256:d179a1279dcd12c10495e3022fdf8ae3b5ee8ed50ca0ba512f0dbd6b1fd325f8 +size 184162 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-5.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-5.png index b6392f095..3d133063f 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-5.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5458f9488a19207c7d4f8a971de06a028dfb22e4a2847c3a0b1e1f45c41109f0 -size 200566 +oid sha256:dae80d58e60532eb151354de65574b70a73bc6ef8dcaba8c65d39da6cc388eda +size 184497 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50.png index 8165824cb..e79a20bbd 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8588b720e7d970a0c5d0b9e43c68ee0695d7ced8c51797d50143b0737d3ae2c1 -size 160340 +oid sha256:ba9a962dfdc0bcfd033dff87e970554b3d480226c904a3fb2428c427312c7e42 +size 176697 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-99.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-99.png index f46e58b4f..9f8791bcb 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-99.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-99.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b86bc324f13ca3a958d0db80251874478e0191b0c30c301f3022913e7b1f62d5 -size 147084 +oid sha256:b3cbdc194f63da1e33a7e367175e93e49bf5f69c988bb8ac03c137bd1505adc5 +size 166434 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-init-mean-window-5.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-init-mean-window-5.png index 8e3e7e2de..fcd0b1382 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-init-mean-window-5.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-init-mean-window-5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9993fe8f8d3e6d6e48d863b251fdd7b37926ba7b97b2d70683cbc3ab45910c99 -size 184668 +oid sha256:051f4e6dc5a6a9824da12165bf6475baf83886ca97c6ba10c0ea2f615dc4e0ee +size 162378 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-false.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-false.png index aae5c9066..9d45ca1aa 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-false.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-false.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4cdb28c8aa72b1cd968f4f78f3c2413d2338b6a2b5c200df02ecdd2bce1568b -size 126337 +oid sha256:6adc3973283da26ad475351af58d91892251c53fe0e09f714cf21cfdab7502c6 +size 140885 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-true.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-true.png index 346495cfc..190025d6d 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-true.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-true.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:19000f2cc6d78e2cc18dd5213778e595ee6710ca3fcd71cb4cbe6286b42b1e8b -size 130255 +oid sha256:bab10f413eaac26d69848ada9528fa1e36e616eab37c5244d7f1c9c3ab85e7d6 +size 143505 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-init-mean-window-5.png b/examples/notebooks/screenshots/nb-image-widget-zfish-init-mean-window-5.png index 2298f904e..e97c2ffd0 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-init-mean-window-5.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-init-mean-window-5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4a141cd3e0d3647accb18c55d84026d16ca2280611b80682737a61151dd9c377 -size 99397 +oid sha256:10042f15d067049e05418f1e82eb3428f56f53a2c159ac4eaa135d42dfc3d057 +size 88268 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-frame-50.png b/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-frame-50.png index 58f4fd87e..de9822952 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-frame-50.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-frame-50.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cbd3cb8399c32cc611a86bb482782bfe55393ec73f2c2a3f4eb0d4e8af2442d6 -size 58842 +oid sha256:1e031e6712bb7a9601f627e32347c05ed2669363ee1ffe428d10797081c32ef0 +size 113064 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-set-data.png b/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-set-data.png index 0eff22834..2e47302a8 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-set-data.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-set-data.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e6e201ecce9db938796d1fc710a154ae8bc49e0a7e1f51d9af586f29f4ee63de -size 57116 +oid sha256:0aaa7782c20f209e07a7259d676b4fc993d4f25ba1a52150d5512d8ef16b82bc +size 130999 diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-windowrgb.png b/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-windowrgb.png index 03a1fc30c..9104fb9ea 100644 --- a/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-windowrgb.png +++ b/examples/notebooks/screenshots/nb-image-widget-zfish-mixed-rgb-cockatoo-windowrgb.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:608c9a0b1466886652299887a4f0f16a77dfb400fc46200a453df25c5a0e7016 -size 55903 +oid sha256:5b478e4cd25c96e2c08b3f595193d019a0cfcac69f8ea3e3a8330cf6c0ffabbf +size 131188 diff --git a/examples/notebooks/screenshots/nb-lines-3d.png b/examples/notebooks/screenshots/nb-lines-3d.png index d1e46a618..65310e7f1 100644 --- a/examples/notebooks/screenshots/nb-lines-3d.png +++ b/examples/notebooks/screenshots/nb-lines-3d.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91f74b1ad6d4eeb08da8a33bfccfc0e9e80d48fc33b2a783cb94890f3c603a94 -size 14131 +oid sha256:fc7a8caabb59ff2f2fd9811678b974542c6a3dddfd0d005109777264056d458a +size 23430 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png b/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png index db1a0e658..9f3a156b9 100644 --- a/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png +++ b/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:58af931da3307204f2699b2ac04d8546b93aa0b4d3c058ab6d181656fd79fae8 -size 11674 +oid sha256:80d318cb1daf701e682e600c0058cf3e5c336062dd459618eac60f92ec2399ad +size 17362 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png b/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png index 9bb734365..677906685 100644 --- a/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png +++ b/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9949949767455061caa08b96dfdf0948d511d604d39ded4a028a9a50deca9797 -size 12990 +oid sha256:996d29cdf767f3863615ebc0d5b91f4ec07af898350c07b2fd78426c239cb452 +size 18817 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet.png b/examples/notebooks/screenshots/nb-lines-cmap-jet.png index 10f9252f3..5195c617d 100644 --- a/examples/notebooks/screenshots/nb-lines-cmap-jet.png +++ b/examples/notebooks/screenshots/nb-lines-cmap-jet.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c04746bb9c6e168644981e808b83b878d5d72e2101f441979765c74bb36c087a -size 10979 +oid sha256:74da9cc1bac480b5d72693ea7e074d5192e382a989816912757bd307a1e04faf +size 17367 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png b/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png index a769ff769..d766bcda0 100644 --- a/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png +++ b/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:704cddf180de18dfc02cccced26dc57a7d8bff3938ceaf5ca9b6db7ccaed5928 -size 9582 +oid sha256:04052da5609011c7df22e4688bfe1100ad90fa757099d7b315d0b2bcaeb8c3d0 +size 15876 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png b/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png index 861efcef5..723beb580 100644 --- a/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png +++ b/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:67310ed0deb418bf0d6d10e1184e902f928f0e914518b91c23e948f3bb9e7b25 -size 9850 +oid sha256:1ea8423ccba04a9a137640b28ff8f84e167d46735d87fd38c48c29373a9601ac +size 16223 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-viridis.png b/examples/notebooks/screenshots/nb-lines-cmap-viridis.png index 2d71b4428..e6493053c 100644 --- a/examples/notebooks/screenshots/nb-lines-cmap-viridis.png +++ b/examples/notebooks/screenshots/nb-lines-cmap-viridis.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6295649505902ac1f37ae6453e278dbbcdacb64426f1c51e27e16ef38650f8a8 -size 13725 +oid sha256:9fd9697d7df47491c6b9e73424dd07088c7e22758d5672a99ddbce56e4ff3b02 +size 19316 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-white.png b/examples/notebooks/screenshots/nb-lines-cmap-white.png index b450a8ea4..cbbbef0bc 100644 --- a/examples/notebooks/screenshots/nb-lines-cmap-white.png +++ b/examples/notebooks/screenshots/nb-lines-cmap-white.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1abc26476bbabf31094bd70929afc918e4064a1996d7742adb716ed6e9c2617 -size 7532 +oid sha256:54242cbcd3f196e5f39fc3a27a98b42f9515f04625d37d3b210afd37721078dc +size 8967 diff --git a/examples/notebooks/screenshots/nb-lines-colors.png b/examples/notebooks/screenshots/nb-lines-colors.png index 88fef4e39..60792f453 100644 --- a/examples/notebooks/screenshots/nb-lines-colors.png +++ b/examples/notebooks/screenshots/nb-lines-colors.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bbbb1b63c69ef4061f0b64fc2360e0c613ee4732d581929657068f55141d6fd9 -size 27274 +oid sha256:9ae3f1bae2ea0fe146c7096af3551e5e58704416bff49a6f0bdd5415cfc1533b +size 37095 diff --git a/examples/notebooks/screenshots/nb-lines-data.png b/examples/notebooks/screenshots/nb-lines-data.png index b8c5bf582..86ce4362b 100644 --- a/examples/notebooks/screenshots/nb-lines-data.png +++ b/examples/notebooks/screenshots/nb-lines-data.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6f677a3c0a1b2fb57771af6118d45d23b1d86f88d3431ca06ef89b79a48dad06 -size 38880 +oid sha256:17ec845345cb97088de4c18c8eebc54c9a27c5770724f8f582b4144f3e70d139 +size 46868 diff --git a/examples/notebooks/screenshots/nb-lines-underlay.png b/examples/notebooks/screenshots/nb-lines-underlay.png index 93edd81d6..7d1280db4 100644 --- a/examples/notebooks/screenshots/nb-lines-underlay.png +++ b/examples/notebooks/screenshots/nb-lines-underlay.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:35e0ea48cac0242e79da491629bda9fccedb94814e8d3d1188323c7d9668e513 -size 49940 +oid sha256:467788d8588fa1794c0cd705e03564537ff49f79762a5e8f092700516d503391 +size 52447 diff --git a/examples/notebooks/screenshots/nb-lines.png b/examples/notebooks/screenshots/nb-lines.png index e28486bf4..4fd64a56d 100644 --- a/examples/notebooks/screenshots/nb-lines.png +++ b/examples/notebooks/screenshots/nb-lines.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:17ee8c3de59b9e80d66c30d61287a38ac06ee996833f32648506a6bf1ebb0da8 -size 23317 +oid sha256:da1e28036caa8077885f52aa3a6ba4dbe1ee4f8cfa79a7b604614483150cd7b7 +size 24798 diff --git a/examples/tests/test_examples.py b/examples/tests/test_examples.py index c08df9005..9562a4357 100644 --- a/examples/tests/test_examples.py +++ b/examples/tests/test_examples.py @@ -68,6 +68,10 @@ def test_example_screenshots(module, force_offscreen): # import the example module example = importlib.import_module(module_name) + for subplot in example.figure: + subplot.viewport.render(subplot.scene, subplot.camera) + example.figure.renderer.flush() + # render a frame img = np.asarray(example.figure.renderer.target.draw()) @@ -104,7 +108,7 @@ def test_example_screenshots(module, force_offscreen): rgb = normalize_image(rgb) ref_img = normalize_image(ref_img) - similar, rmse = image_similarity(rgb, ref_img, threshold=0.025) + similar, rmse = image_similarity(rgb, ref_img, threshold=0.05) update_diffs(module.stem, similar, rgb, ref_img) assert similar, ( diff --git a/examples/tests/testutils.py b/examples/tests/testutils.py index 0e4cd2e1b..2ea4742ea 100644 --- a/examples/tests/testutils.py +++ b/examples/tests/testutils.py @@ -23,7 +23,8 @@ "line/*.py", "line_collection/*.py", "gridplot/*.py", - "misc/*.py" + "misc/*.py", + "selectors/*.py" ] diff --git a/fastplotlib/__init__.py b/fastplotlib/__init__.py index 8b46dcc0b..19dfb1903 100644 --- a/fastplotlib/__init__.py +++ b/fastplotlib/__init__.py @@ -3,6 +3,7 @@ from .utils.gui import run # noqa from .graphics import * from .graphics.selectors import * +from .graphics.utils import pause_events from .legends import * from .layouts import Figure diff --git a/fastplotlib/graphics/_axes.py b/fastplotlib/graphics/_axes.py new file mode 100644 index 000000000..2a63183d5 --- /dev/null +++ b/fastplotlib/graphics/_axes.py @@ -0,0 +1,598 @@ +import numpy as np + +import pygfx + + +GRID_PLANES = ["xy", "xz", "yz"] + + +# very thin subclass that just adds GridMaterial properties to this world object for easier user control +class Grid(pygfx.Grid): + @property + def major_step(self) -> tuple[float, float]: + """The step distance between the major grid lines.""" + return self.material.major_step + + @major_step.setter + def major_step(self, step: tuple[float, float]): + self.material.major_step = step + + @property + def minor_step(self) -> tuple[float, float]: + """The step distance between the minor grid lines.""" + return self.material.minor_step + + @minor_step.setter + def minor_step(self, step: tuple[float, float]): + self.material.minor_step = step + + @property + def axis_thickness(self) -> float: + """The thickness of the axis lines.""" + return self.material.axis_thickness + + @axis_thickness.setter + def axis_thickness(self, thickness: float): + self.material.axis_thickness = thickness + + @property + def major_thickness(self) -> float: + """The thickness of the major grid lines.""" + return self.material.major_thickness + + @major_thickness.setter + def major_thickness(self, thickness: float): + self.material.major_thickness = thickness + + @property + def minor_thickness(self) -> float: + """The thickness of the minor grid lines.""" + return self.material.minor_thickness + + @minor_thickness.setter + def minor_thickness(self, thickness: float): + self.material.minor_thickness = thickness + + @property + def thickness_space(self) -> str: + """The coordinate space in which the thicknesses are expressed. + + See :obj:`pygfx.utils.enums.CoordSpace`: + """ + return self.material.thickness_space + + @thickness_space.setter + def thickness_space(self, value: str): + self.material.thickness_space = value + + @property + def axis_color(self) -> str: + """The color of the axis lines.""" + return self.material.axis_color + + @axis_color.setter + def axis_color(self, color: str): + self.material.axis_color = color + + @property + def major_color(self) -> str: + """The color of the major grid lines.""" + return self.material.major_color + + @major_color.setter + def major_color(self, color: str): + self.material.major_color = color + + @property + def minor_color(self) -> str: + """The color of the minor grid lines.""" + return self.material.minor_color + + @minor_color.setter + def minor_color(self, color: str): + self.material.minor_color = color + + @property + def infinite(self) -> bool: + """Whether the grid is infinite. + + If not infinite, the grid is 1x1 in world space, scaled, rotated, and + positioned with the object's transform. + + (Infinite grids are not actually infinite. Rather they move along with + the camera, and are sized based on the distance between the camera and + the grid.) + """ + return self.material.infinite + + @infinite.setter + def infinite(self, value: str): + self.material.infinite = value + + +class Grids(pygfx.Group): + """Just a class to make accessing the grids easier""" + + def __init__(self, *, xy, xz, yz): + super().__init__() + + self._xy = xy + self._xz = xz + self._yz = yz + + self.add(xy, xz, yz) + + @property + def xy(self) -> Grid: + """xy grid""" + return self._xy + + @property + def xz(self) -> Grid: + """xz grid""" + return self._xz + + @property + def yz(self) -> Grid: + """yz grid""" + return self._yz + + +class Ruler(pygfx.Ruler): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.tick_text_mapper = None + self.font_size = 14 + + def _update_sub_objects(self, ticks, tick_auto_step): + """Update the sub-objects to show the given ticks.""" + assert isinstance(ticks, dict) + + tick_size = 5 + min_n_slots = 8 # todo: can be (much) higher when we use a single text object! + + # Load config + start_pos = self._start_pos + end_pos = self._end_pos + start_value = self._start_value + end_value = self.end_value + + # Derive some more variables + length = end_value - start_value + vec = end_pos - start_pos + if length: + vec /= length + + # Get array to store positions + n_slots = self.points.geometry.positions.nitems + n_positions = len(ticks) + 2 + if n_positions <= n_slots <= max(min_n_slots, 2 * n_positions): + # Re-use existing buffers + positions = self.points.geometry.positions.data + sizes = self.points.geometry.sizes.data + self.points.geometry.positions.update_range() + self.points.geometry.sizes.update_range() + else: + # Allocate new buffers + new_n_slots = max(min_n_slots, int(n_positions * 1.2)) + positions = np.zeros((new_n_slots, 3), np.float32) + sizes = np.zeros((new_n_slots,), np.float32) + self.points.geometry.positions = pygfx.Buffer(positions) + self.points.geometry.sizes = pygfx.Buffer(sizes) + # Allocate text objects + while len(self._text_object_pool) < new_n_slots: + ob = pygfx.Text( + pygfx.TextGeometry("", screen_space=True, font_size=self.font_size), + pygfx.TextMaterial(aa=False), + ) + self._text_object_pool.append(ob) + self._text_object_pool[new_n_slots:] = [] + # Reset children + self.clear() + self.add(self._line, self._points, *self._text_object_pool) + + def define_text(pos, text): + if self.tick_text_mapper is not None and text != "": + text = self.tick_text_mapper(text) + + ob = self._text_object_pool[index] + ob.geometry.anchor = self._text_anchor + ob.geometry.anchor_offset = self._text_anchor_offset + ob.geometry.set_text(text) + ob.local.position = pos + + # Apply start point + index = 0 + positions[0] = start_pos + if self._ticks_at_end_points: + sizes[0] = tick_size + define_text(start_pos, f"{self._start_value:0.4g}") + else: + sizes[0] = 0 + define_text(start_pos, f"") + + # Collect ticks + index += 1 + for value, text in ticks.items(): + pos = start_pos + vec * (value - start_value) + positions[index] = pos + sizes[index] = tick_size + define_text(pos, text) + index += 1 + + # Handle end point, and nullify remaining slots + positions[index:] = end_pos + sizes[index:] = 0 + for ob in self._text_object_pool[index:]: + ob.geometry.set_text("") + + # Show last tick? + if self._ticks_at_end_points: + sizes[index] = tick_size + define_text(end_pos, f"{end_value:0.4g}") + + # Hide the ticks close to the ends? + if self._ticks_at_end_points and ticks: + tick_values = list(ticks.keys()) + if abs(tick_values[0] - start_value) < 0.5 * tick_auto_step: + self._text_object_pool[1].geometry.set_text("") + if abs(tick_values[-1] - end_value) < 0.5 * tick_auto_step: + self._text_object_pool[index - 1].geometry.set_text("") + + +class Axes: + def __init__( + self, + plot_area, + intersection: tuple[int, int, int] | None = None, + x_kwargs: dict = None, + y_kwargs: dict = None, + z_kwargs: dict = None, + grids: bool = True, + grid_kwargs: dict = None, + auto_grid: bool = True, + offset: np.ndarray = np.array([0.0, 0.0, 0.0]), + ): + self._plot_area = plot_area + + if x_kwargs is None: + x_kwargs = dict() + + if y_kwargs is None: + y_kwargs = dict() + + if z_kwargs is None: + z_kwargs = dict() + + x_kwargs = { + "tick_side": "right", + **x_kwargs, + } + + y_kwargs = {"tick_side": "left", **y_kwargs} + + z_kwargs = { + "tick_side": "left", + **z_kwargs, + } + + # create ruler for each dim + self._x = Ruler(**x_kwargs) + self._y = Ruler(**y_kwargs) + self._z = Ruler(**z_kwargs) + + self._offset = offset + + # *MUST* instantiate some start and end positions for the rulers else kernel crashes immediately + # probably a WGPU rust panic + self.x.start_pos = 0, 0, 0 + self.x.end_pos = 100, 0, 0 + self.x.start_value = self.x.start_pos[0] - offset[0] + statsx = self.x.update( + self._plot_area.camera, self._plot_area.viewport.logical_size + ) + + self.y.start_pos = 0, 0, 0 + self.y.end_pos = 0, 100, 0 + self.y.start_value = self.y.start_pos[1] - offset[1] + statsy = self.y.update( + self._plot_area.camera, self._plot_area.viewport.logical_size + ) + + self.z.start_pos = 0, 0, 0 + self.z.end_pos = 0, 0, 100 + self.z.start_value = self.z.start_pos[1] - offset[2] + self.z.update(self._plot_area.camera, self._plot_area.viewport.logical_size) + + # world object for the rulers + grids + self._world_object = pygfx.Group() + + # add rulers + self.world_object.add( + self.x, + self.y, + self.z, + ) + + # set z ruler invisible for orthographic projections for now + if self._plot_area.camera.fov == 0: + # TODO: allow any orientation in the future even for orthographic projections + self.z.visible = False + + if grid_kwargs is None: + grid_kwargs = dict() + + grid_kwargs = { + "major_step": 10, + "minor_step": 1, + "thickness_space": "screen", + "major_thickness": 2, + "minor_thickness": 0.5, + "infinite": True, + **grid_kwargs, + } + + if grids: + _grids = dict() + for plane in GRID_PLANES: + grid = Grid( + geometry=None, + material=pygfx.GridMaterial(**grid_kwargs), + orientation=plane, + visible=False, + ) + + _grids[plane] = grid + + self._grids = Grids(**_grids) + self.world_object.add(self._grids) + + if self._plot_area.camera.fov == 0: + # orthographic projection, place grids far away + self._grids.local.z = -1000 + + major_step_x, major_step_y = statsx["tick_step"], statsy["tick_step"] + + self.grids.xy.material.major_step = major_step_x, major_step_y + self.grids.xy.material.minor_step = 0.2 * major_step_x, 0.2 * major_step_y + + else: + self._grids = False + + self._intersection = intersection + self._auto_grid = auto_grid + + @property + def world_object(self) -> pygfx.WorldObject: + return self._world_object + + @property + def offset(self) -> np.ndarray: + """offset of the axes""" + return self._offset + + @offset.setter + def offset(self, value: np.ndarray): + self._offset = value + + @property + def x(self) -> Ruler: + """x axis ruler""" + return self._x + + @property + def y(self) -> Ruler: + """y axis ruler""" + return self._y + + @property + def z(self) -> Ruler: + """z axis ruler""" + return self._z + + @property + def grids(self) -> Grids | bool: + """grids for each plane: xy, xz, yz""" + return self._grids + + @property + def auto_grid(self) -> bool: + """auto adjust the grid on each render cycle""" + return self._auto_grid + + @auto_grid.setter + def auto_grid(self, value: bool): + self._auto_grid = value + + @property + def visible(self) -> bool: + """set visibility of all axes elements, rulers and grids""" + return self._world_object.visible + + @visible.setter + def visible(self, value: bool): + self._world_object.visible = value + + @property + def intersection(self) -> tuple[float, float, float] | None: + return self._intersection + + @intersection.setter + def intersection(self, intersection: tuple[float, float, float] | None): + """ + intersection point of [x, y, z] rulers. + Set (0, 0, 0) for origin + Set to `None` to follow when panning through the scene with orthographic projection + """ + if intersection is None: + self._intersection = None + return + + if len(intersection) != 3: + raise ValueError( + "intersection must be a float of 3 elements for [x, y, z] or `None`" + ) + + self._intersection = tuple(float(v) for v in intersection) + + def update_using_bbox(self, bbox): + """ + Update the w.r.t. the given bbox + + Parameters + ---------- + bbox: np.ndarray + array of shape [2, 3], [[xmin, ymin, zmin], [xmax, ymax, zmax]] + + """ + + # flip axes if camera scale is flipped + if self._plot_area.camera.local.scale_x < 0: + bbox[0, 0], bbox[1, 0] = bbox[1, 0], bbox[0, 0] + + if self._plot_area.camera.local.scale_y < 0: + bbox[0, 1], bbox[1, 1] = bbox[1, 1], bbox[0, 1] + + if self._plot_area.camera.local.scale_z < 0: + bbox[0, 2], bbox[1, 2] = bbox[1, 2], bbox[0, 2] + + if self.intersection is None: + intersection = (0, 0, 0) + else: + intersection = self.intersection + + self.update(bbox, intersection) + + def update_using_camera(self): + """ + Update the axes w.r.t the current camera state + + For orthographic projections of the xy plane, it will calculate the inverse projection + of the screen space onto world space to determine the current range of the world space + to set the rulers and ticks + + For perspective projections it will just use the bbox of the scene to set the rulers + + """ + + if not self.visible: + return + + if self._plot_area.camera.fov == 0: + xpos, ypos, width, height = self._plot_area.get_rect() + # orthographic projection, get ranges using inverse + + # get range of screen space + xmin, xmax = xpos, xpos + width + ymin, ymax = ypos + height, ypos + + min_vals = self._plot_area.map_screen_to_world((xmin, ymin)) + max_vals = self._plot_area.map_screen_to_world((xmax, ymax)) + + if min_vals is None or max_vals is None: + return + + world_xmin, world_ymin, _ = min_vals + world_xmax, world_ymax, _ = max_vals + + world_zmin, world_zmax = 0, 0 + + bbox = np.array( + [ + [world_xmin, world_ymin, world_zmin], + [world_xmax, world_ymax, world_zmax], + ] + ) + + else: + # set ruler start and end positions based on scene bbox + bbox = self._plot_area._fpl_graphics_scene.get_world_bounding_box() + + if self.intersection is None: + if self._plot_area.camera.fov == 0: + # place the ruler close to the left and bottom edges of the viewport + # TODO: determine this for perspective projections + xscreen_10, yscreen_10 = xpos + (width * 0.1), ypos + (height * 0.9) + intersection = self._plot_area.map_screen_to_world( + (xscreen_10, yscreen_10) + ) + else: + # force origin since None is not supported for Persepctive projections + self._intersection = (0, 0, 0) + intersection = self._intersection + + else: + # axes intersect at the origin + intersection = self.intersection + + self.update(bbox, intersection) + + def update(self, bbox, intersection): + """ + Update the axes using the given bbox and ruler intersection point + + Parameters + ---------- + bbox: np.ndarray + array of shape [2, 3], [[xmin, ymin, zmin], [xmax, ymax, zmax]] + + intersection: float, float, float + intersection point of the x, y, z ruler + + """ + + world_xmin, world_ymin, world_zmin = bbox[0] + world_xmax, world_ymax, world_zmax = bbox[1] + world_x_10, world_y_10, world_z_10 = intersection + + # swap min and max for each dimension if necessary + if self._plot_area.camera.local.scale_y < 0: + world_ymin, world_ymax = world_ymax, world_ymin + self.y.tick_side = "right" # swap tick side + self.x.tick_side = "right" + else: + self.y.tick_side = "left" + self.x.tick_side = "right" + + if self._plot_area.camera.local.scale_x < 0: + world_xmin, world_xmax = world_xmax, world_xmin + self.x.tick_side = "left" + + self.x.start_pos = world_xmin, world_y_10, world_z_10 + self.x.end_pos = world_xmax, world_y_10, world_z_10 + + self.x.start_value = self.x.start_pos[0] - self.offset[0] + statsx = self.x.update( + self._plot_area.camera, self._plot_area.viewport.logical_size + ) + + self.y.start_pos = world_x_10, world_ymin, world_z_10 + self.y.end_pos = world_x_10, world_ymax, world_z_10 + + self.y.start_value = self.y.start_pos[1] - self.offset[1] + statsy = self.y.update( + self._plot_area.camera, self._plot_area.viewport.logical_size + ) + + if self._plot_area.camera.fov != 0: + self.z.start_pos = world_x_10, world_y_10, world_zmin + self.z.end_pos = world_x_10, world_y_10, world_zmax + + self.z.start_value = self.z.start_pos[1] - self.offset[2] + statsz = self.z.update( + self._plot_area.camera, self._plot_area.viewport.logical_size + ) + major_step_z = statsz["tick_step"] + + if self.grids: + if self.auto_grid: + major_step_x, major_step_y = statsx["tick_step"], statsy["tick_step"] + self.grids.xy.major_step = major_step_x, major_step_y + self.grids.xy.minor_step = 0.2 * major_step_x, 0.2 * major_step_y + + if self._plot_area.camera.fov != 0: + self.grids.xz.major_step = major_step_x, major_step_z + self.grids.xz.minor_step = 0.2 * major_step_x, 0.2 * major_step_z + + self.grids.yz.material.major_step = major_step_y, major_step_z + self.grids.yz.minor_step = 0.2 * major_step_y, 0.2 * major_step_z diff --git a/fastplotlib/graphics/_base.py b/fastplotlib/graphics/_base.py index 01482ae6e..27bfbc149 100644 --- a/fastplotlib/graphics/_base.py +++ b/fastplotlib/graphics/_base.py @@ -17,6 +17,7 @@ Rotation, Visible, ) +from ._axes import Axes HexStr: TypeAlias = str @@ -114,6 +115,8 @@ def __init__( self._visible = Visible(visible) self._block_events = False + self._axes: Axes = None + @property def supported_events(self) -> tuple[str]: """events supported by this graphic""" @@ -355,6 +358,12 @@ def _fpl_prepare_del(self): Optionally implemented in subclasses """ + # remove axes if added to this graphic + if self._axes is not None: + self._plot_area.scene.remove(self._axes) + self._plot_area.remove_animation(self._update_axes) + self._axes.world_object.clear() + # signal that a deletion has been requested self.deleted = True @@ -413,3 +422,18 @@ def rotate(self, alpha: float, axis: Literal["x", "y", "z"] = "y"): f"`axis` must be either `x`, `y`, or `z`. `{axis}` provided instead!" ) self.rotation = la.quat_mul(rot, self.rotation) + + @property + def axes(self) -> Axes: + return self._axes + + def add_axes(self): + """Add axes onto this Graphic""" + if self._axes is not None: + raise AttributeError("Axes already added onto this graphic") + + self._axes = Axes(self._plot_area, offset=self.offset, grids=False) + self._axes.world_object.local.rotation = self.world_object.local.rotation + + self._plot_area.scene.add(self.axes.world_object) + self._axes.update_using_bbox(self.world_object.get_world_bounding_box()) diff --git a/fastplotlib/graphics/image.py b/fastplotlib/graphics/image.py index 866ed2486..6730e86cb 100644 --- a/fastplotlib/graphics/image.py +++ b/fastplotlib/graphics/image.py @@ -132,7 +132,7 @@ def __init__( self._vmax = ImageVmax(vmax) # set cmap to None for RGB images - if self._data.value.ndim == 3: + if self._data.value.ndim > 2: self._cmap = None else: self._cmap = ImageCmap(cmap) @@ -192,14 +192,14 @@ def data(self, data): @property def cmap(self) -> str: """colormap name""" - if self.data.value.ndim == 3: - raise AttributeError("RGB images do not have a colormap property") + if self.data.value.ndim > 2: + raise AttributeError("RGB(A) images do not have a colormap property") return self._cmap.value @cmap.setter def cmap(self, name: str): - if self.data.value.ndim == 3: - raise AttributeError("RGB images do not have a colormap property") + if self.data.value.ndim > 2: + raise AttributeError("RGB(A) images do not have a colormap property") self._cmap.set_value(self, name) @property diff --git a/fastplotlib/graphics/selectors/_linear.py b/fastplotlib/graphics/selectors/_linear.py index e7b0032f9..eec4cc910 100644 --- a/fastplotlib/graphics/selectors/_linear.py +++ b/fastplotlib/graphics/selectors/_linear.py @@ -372,7 +372,16 @@ def _get_selected_index(self, graphic): if "Image" in graphic.__class__.__name__: # indices map directly to grid geometry for image data buffer index = self.selection - return round(index) + shape = graphic.data[:].shape + + if self.axis == "x": + # assume selecting columns + upper_bound = shape[1] - 1 + elif self.axis == "y": + # assume selecting rows + upper_bound = shape[0] - 1 + + return min(round(index), upper_bound) def _move_graphic(self, delta: np.ndarray): """ diff --git a/fastplotlib/graphics/utils.py b/fastplotlib/graphics/utils.py new file mode 100644 index 000000000..6be5aefc4 --- /dev/null +++ b/fastplotlib/graphics/utils.py @@ -0,0 +1,37 @@ +from contextlib import contextmanager + +from ._base import Graphic + + +@contextmanager +def pause_events(*graphics: Graphic): + """ + Context manager for pausing Graphic events. + + Examples + -------- + + .. code-block:: + + # pass in any number of graphics + with fpl.pause_events(graphic1, graphic2, graphic3): + # enter context manager + # all events are blocked from graphic1, graphic2, graphic3 + + # context manager exited, event states restored. + + """ + if not all([isinstance(g, Graphic) for g in graphics]): + raise TypeError( + f"`pause_events` only takes Graphic instances as arguments, " + f"you have passed the following types:\n{[type(g) for g in graphics]}" + ) + + original_vals = [g.block_events for g in graphics] + + for g in graphics: + g.block_events = True + yield + + for g, value in zip(graphics, original_vals): + g.block_events = value diff --git a/fastplotlib/layouts/_figure.py b/fastplotlib/layouts/_figure.py index d330c6928..3ad5231c7 100644 --- a/fastplotlib/layouts/_figure.py +++ b/fastplotlib/layouts/_figure.py @@ -474,7 +474,7 @@ def show( _maintain_aspect = subplot.camera.maintain_aspect else: _maintain_aspect = maintain_aspect - subplot.auto_scale(maintain_aspect=_maintain_aspect, zoom=0.95) + subplot.auto_scale(maintain_aspect=maintain_aspect) # return the appropriate OutputContext based on the current canvas if self.canvas.__class__.__name__ == "JupyterWgpuCanvas": @@ -497,6 +497,20 @@ def show( frame=self, make_toolbar=toolbar, add_widgets=add_widgets ) + elif self.canvas.__class__.__name__ == "WgpuManualOffscreenCanvas": + # for test and docs gallery screenshots + for subplot in self: + subplot.set_viewport_rect() + subplot.axes.update_using_camera() + + # render call is blocking only on github actions for some reason, + # but not for rtd build, this is a workaround + # for CI tests, the render call works if it's in test_examples + # but it is necessary for the gallery images too so that's why this check is here + if "RTD_BUILD" in os.environ.keys(): + if os.environ["RTD_BUILD"] == "1": + subplot.viewport.render(subplot.scene, subplot.camera) + else: # assume GLFW, the output context is just the canvas self._output = self.canvas diff --git a/fastplotlib/layouts/_plot_area.py b/fastplotlib/layouts/_plot_area.py index 36d9c4019..e5cf1a74b 100644 --- a/fastplotlib/layouts/_plot_area.py +++ b/fastplotlib/layouts/_plot_area.py @@ -99,11 +99,25 @@ def __init__( # legends, managed just like other graphics as explained above self._legends: list[Legend] = list() + # keep all graphics in a separate group, makes bbox calculations etc. easier + # this is the "real scene" excluding axes, selection tools etc. + self._fpl_graphics_scene = pygfx.Group() + self.scene.add(self._fpl_graphics_scene) + self._name = name # need to think about how to deal with children better self.children = list() + self._background_material = pygfx.BackgroundMaterial( + (0.0, 0.0, 0.0, 1.0), + (0.0, 0.0, 0.0, 1.0), + (0.0, 0.0, 0.0, 1.0), + (0.0, 0.0, 0.0, 1.0), + ) + self._background = pygfx.Background(None, self._background_material) + self.scene.add(self._background) + self.set_viewport_rect() # several read-only properties @@ -240,6 +254,21 @@ def name(self, name: str): raise TypeError("PlotArea `name` must be of type ") self._name = name + @property + def background_color(self) -> tuple[pygfx.Color, ...]: + """background colors, (top left, top right, bottom right, bottom left)""" + return ( + self._background_material.color_top_left, + self._background_material.color_top_right, + self._background_material.color_bottom_right, + self._background_material.color_bottom_left, + ) + + @background_color.setter + def background_color(self, colors: str | tuple[float]): + """1, 2, or 4 colors, each color must be acceptable by pygfx.Color""" + self._background_material.set_colors(*colors) + def get_rect(self) -> tuple[float, float, float, float]: """ Returns the viewport rect to define the rectangle @@ -394,7 +423,7 @@ def add_graphic(self, graphic: Graphic, center: bool = True): if graphic in self: # graphic is already in this plot but was removed from the scene, add it back - self.scene.add(graphic.world_object) + self._fpl_graphics_scene.add(graphic.world_object) return self._add_or_insert_graphic(graphic=graphic, center=center, action="add") @@ -465,12 +494,15 @@ def _add_or_insert_graphic( if isinstance(graphic, BaseSelector): obj_list = self._selectors + self.scene.add(graphic.world_object) elif isinstance(graphic, Legend): obj_list = self._legends + self.scene.add(graphic.world_object) elif isinstance(graphic, Graphic): obj_list = self._graphics + self._fpl_graphics_scene.add(graphic.world_object) else: raise TypeError("graphic must be of type Graphic | BaseSelector | Legend") @@ -482,9 +514,6 @@ def _add_or_insert_graphic( else: raise ValueError("valid actions are 'insert' | 'add'") - # add world object to scene - self.scene.add(graphic.world_object) - if center: self.center_graphic(graphic) @@ -518,7 +547,7 @@ def center_graphic(self, graphic: Graphic, zoom: float = 1.35): # probably because camera.show_object uses bounding sphere self.camera.zoom = zoom - def center_scene(self, *, zoom: float = 1.35): + def center_scene(self, *, zoom: float = 1.0): """ Auto-center the scene, does not scale. @@ -528,13 +557,13 @@ def center_scene(self, *, zoom: float = 1.35): apply a zoom after centering the scene """ - if not len(self.scene.children) > 0: + if not len(self._fpl_graphics_scene.children) > 0: return # scale all cameras associated with this controller # else it looks wonky for camera in self.controller.cameras: - camera.show_object(self.scene) + camera.show_object(self._fpl_graphics_scene) # camera.show_object can cause the camera width and height to increase so apply a zoom to compensate # probably because camera.show_object uses bounding sphere @@ -544,7 +573,7 @@ def auto_scale( self, *, # since this is often used as an event handler, don't want to coerce maintain_aspect = True maintain_aspect: None | bool = None, - zoom: float = 0.8, + zoom: float = 0.75, ): """ Auto-scale the camera w.r.t to the scene @@ -559,12 +588,8 @@ def auto_scale( zoom value for the camera after auto-scaling, if zoom = 1.0 then the graphics in the scene will fill the entire canvas. """ - if not len(self.scene.children) > 0: + if not len(self._fpl_graphics_scene.children) > 0: return - # hacky workaround for now until we decide if we want to put selectors in their own scene - # remove all selectors from a scene to calculate scene bbox - for selector in self.selectors: - self.scene.remove(selector.world_object) self.center_scene() @@ -575,8 +600,10 @@ def auto_scale( for camera in self.controller.cameras: camera.maintain_aspect = maintain_aspect - if len(self.scene.children) > 0: - width, height, depth = np.ptp(self.scene.get_world_bounding_box(), axis=0) + if len(self._fpl_graphics_scene.children) > 0: + width, height, depth = np.ptp( + self._fpl_graphics_scene.get_world_bounding_box(), axis=0 + ) else: width, height, depth = (1, 1, 1) @@ -586,9 +613,6 @@ def auto_scale( if height < 0.01: height = 1 - for selector in self.selectors: - self.scene.add(selector.world_object) - # scale all cameras associated with this controller else it looks wonky for camera in self.controller.cameras: camera.width = width @@ -609,7 +633,11 @@ def remove_graphic(self, graphic: Graphic): """ - self.scene.remove(graphic.world_object) + if isinstance(graphic, (BaseSelector, Legend)): + self.scene.remove(graphic.world_object) + + elif isinstance(graphic, Graphic): + self._fpl_graphics_scene.remove(graphic.world_object) def delete_graphic(self, graphic: Graphic): """ @@ -626,6 +654,7 @@ def delete_graphic(self, graphic: Graphic): if isinstance(graphic, BaseSelector): self._selectors.remove(graphic) + elif isinstance(graphic, Legend): self._legends.remove(graphic) @@ -636,6 +665,9 @@ def delete_graphic(self, graphic: Graphic): if graphic.world_object in self.scene.children: self.scene.remove(graphic.world_object) + elif graphic.world_object in self._fpl_graphics_scene.children: + self._fpl_graphics_scene.remove(graphic.world_object) + # cleanup graphic._fpl_prepare_del() diff --git a/fastplotlib/layouts/_subplot.py b/fastplotlib/layouts/_subplot.py index 059307e6b..293cea00c 100644 --- a/fastplotlib/layouts/_subplot.py +++ b/fastplotlib/layouts/_subplot.py @@ -10,6 +10,7 @@ from ._utils import make_canvas_and_renderer, create_camera, create_controller from ._plot_area import PlotArea from ._graphic_methods_mixin import GraphicMethodsMixin +from ..graphics._axes import Axes class Subplot(PlotArea, GraphicMethodsMixin): @@ -88,12 +89,6 @@ def __init__( self.spacing = 2 - self._axes: pygfx.AxesHelper = pygfx.AxesHelper(size=100) - for arrow in self._axes.children: - self._axes.remove(arrow) - - self._grid: pygfx.GridHelper = pygfx.GridHelper(size=100, thickness=1) - self._title_graphic: TextGraphic = None super(Subplot, self).__init__( @@ -116,6 +111,13 @@ def __init__( if self.name is not None: self.set_title(self.name) + self._axes = Axes(self) + self.scene.add(self.axes.world_object) + + @property + def axes(self) -> Axes: + return self._axes + @property def name(self) -> str: return self._name @@ -140,6 +142,10 @@ def docks(self) -> dict: """ return self._docks + def render(self): + self.axes.update_using_camera() + super().render() + def set_title(self, text: str): """Sets the plot title, stored as a ``TextGraphic`` in the "top" dock area""" if text is None: @@ -169,7 +175,7 @@ def center_title(self): def get_rect(self): """Returns the bounding box that defines the Subplot within the canvas.""" row_ix, col_ix = self.position - width_canvas, height_canvas = self.renderer.logical_size + width_canvas, height_canvas = self.canvas.get_logical_size() x_pos = ( (width_canvas / self.ncols) + ((col_ix - 1) * (width_canvas / self.ncols)) @@ -187,20 +193,6 @@ def get_rect(self): return rect - def set_axes_visibility(self, visible: bool): - """Toggles axes visibility.""" - if visible: - self.scene.add(self._axes) - else: - self.scene.remove(self._axes) - - def set_grid_visibility(self, visible: bool): - """Toggles grid visibility.""" - if visible: - self.scene.add(self._grid) - else: - self.scene.remove(self._grid) - class Dock(PlotArea): _valid_positions = ["right", "left", "top", "bottom"] diff --git a/fastplotlib/widgets/histogram_lut.py b/fastplotlib/widgets/histogram_lut.py index a3b36eb45..0f63eb8f4 100644 --- a/fastplotlib/widgets/histogram_lut.py +++ b/fastplotlib/widgets/histogram_lut.py @@ -1,14 +1,28 @@ +from math import ceil import weakref import numpy as np -from pygfx import Group +import pygfx from ..graphics import LineGraphic, ImageGraphic, TextGraphic +from ..graphics.utils import pause_events from ..graphics._base import Graphic from ..graphics.selectors import LinearRegionSelector +def _get_image_graphic_events(image_graphic: ImageGraphic) -> list[str]: + """Small helper function to return the relevant events for an ImageGraphic""" + events = ["vmin", "vmax"] + + if not image_graphic.data.value.ndim > 2: + events.append("cmap") + + # if RGB(A), do not add cmap + + return events + + # TODO: This is a widget, we can think about a BaseWidget class later if necessary class HistogramLUT(Graphic): def __init__( @@ -47,7 +61,7 @@ def __init__( self._histogram_line = LineGraphic(line_data) - bounds = (edges[0], edges[-1]) + bounds = (edges[0] * self._scale_factor, edges[-1] * self._scale_factor) limits = (edges_flanked[0], edges_flanked[-1]) size = 120 # since it's scaled to 100 origin = (hist_scaled.max() / 2, 0) @@ -64,8 +78,8 @@ def __init__( # there will be a small difference with the histogram edges so this makes them both line up exactly self._linear_region_selector.selection = ( - self._image_graphic.vmin, - self._image_graphic.vmax, + self._image_graphic.vmin * self._scale_factor, + self._image_graphic.vmax * self._scale_factor, ) self._vmin = self.image_graphic.vmin @@ -95,7 +109,7 @@ def __init__( self._text_vmax.world_object.material.pick_write = False - widget_wo = Group() + widget_wo = pygfx.Group() widget_wo.add( self._histogram_line.world_object, self._linear_region_selector.world_object, @@ -115,7 +129,46 @@ def __init__( self._linear_region_handler, "selection" ) - self.image_graphic.add_event_handler(self._image_cmap_handler, "vmin", "vmax") + ig_events = _get_image_graphic_events(self.image_graphic) + + self.image_graphic.add_event_handler(self._image_cmap_handler, *ig_events) + + # colorbar for grayscale images + if self.image_graphic.data.value.ndim != 3: + self._colorbar: ImageGraphic = self._make_colorbar(edges_flanked) + + self.world_object.add(self._colorbar.world_object) + else: + self._colorbar = None + self._cmap = None + + def _make_colorbar(self, edges_flanked) -> ImageGraphic: + # use the histogram edge values as data for an + # image with 2 columns, this will be our colorbar! + colorbar_data = np.column_stack( + [ + np.linspace( + edges_flanked[0], edges_flanked[-1], ceil(np.ptp(edges_flanked)) + ) + ] + * 2 + ).astype(np.float32) + + colorbar_data /= self._scale_factor + + cbar = ImageGraphic( + data=colorbar_data, + vmin=self.vmin, + vmax=self.vmax, + cmap=self.image_graphic.cmap, + interpolation="linear", + offset=(-55, edges_flanked[0], -1), + ) + + cbar.world_object.world.scale_x = 20 + self._cmap = self.image_graphic.cmap + + return cbar def _get_vmin_vmax_str(self) -> tuple[str, str]: if self.vmin < 0.001 or self.vmin > 99_999: @@ -136,6 +189,7 @@ def _fpl_add_plot_area_hook(self, plot_area): self._histogram_line._fpl_add_plot_area_hook(plot_area) self._plot_area.auto_scale() + self._plot_area.controller.enabled = True def _calculate_histogram(self, data): if data.ndim > 2: @@ -209,27 +263,39 @@ def _linear_region_handler(self, ev): def _image_cmap_handler(self, ev): setattr(self, ev.type, ev.info["value"]) + @property + def cmap(self) -> str: + return self._cmap + + @cmap.setter + def cmap(self, name: str): + if self._colorbar is None: + return + + with pause_events(self.image_graphic): + self.image_graphic.cmap = name + + self._cmap = name + self._colorbar.cmap = name + @property def vmin(self) -> float: return self._vmin @vmin.setter def vmin(self, value: float): - self.image_graphic.block_events = True - self._linear_region_selector.block_events = True - - # must use world coordinate values directly from selection() - # otherwise the linear region bounds jump to the closest bin edges - self._linear_region_selector.selection = ( - value * self._scale_factor, - self._linear_region_selector.selection[1], - ) - self.image_graphic.vmin = value - - self.image_graphic.block_events = False - self._linear_region_selector.block_events = False + with pause_events(self.image_graphic, self._linear_region_selector): + # must use world coordinate values directly from selection() + # otherwise the linear region bounds jump to the closest bin edges + self._linear_region_selector.selection = ( + value * self._scale_factor, + self._linear_region_selector.selection[1], + ) + self.image_graphic.vmin = value self._vmin = value + if self._colorbar is not None: + self._colorbar.vmin = value vmin_str, vmax_str = self._get_vmin_vmax_str() self._text_vmin.offset = (-120, self._linear_region_selector.selection[0], 0) @@ -241,22 +307,19 @@ def vmax(self) -> float: @vmax.setter def vmax(self, value: float): - self.image_graphic.block_events = True - self._linear_region_selector.block_events = True - - # must use world coordinate values directly from selection() - # otherwise the linear region bounds jump to the closest bin edges - self._linear_region_selector.selection = ( - self._linear_region_selector.selection[0], - value * self._scale_factor, - ) - - self.image_graphic.vmax = value + with pause_events(self.image_graphic, self._linear_region_selector): + # must use world coordinate values directly from selection() + # otherwise the linear region bounds jump to the closest bin edges + self._linear_region_selector.selection = ( + self._linear_region_selector.selection[0], + value * self._scale_factor, + ) - self.image_graphic.block_events = False - self._linear_region_selector.block_events = False + self.image_graphic.vmax = value self._vmax = value + if self._colorbar is not None: + self._colorbar.vmax = value vmin_str, vmax_str = self._get_vmin_vmax_str() self._text_vmax.offset = (-120, self._linear_region_selector.selection[1], 0) @@ -279,15 +342,23 @@ def set_data(self, data, reset_vmin_vmax: bool = True): self._linear_region_selector.limits = limits self._linear_region_selector.selection = bounds else: - # don't change the current selection - self.image_graphic.block_events = True - self._linear_region_selector.block_events = True - self._linear_region_selector.limits = limits - self.image_graphic.block_events = False - self._linear_region_selector.block_events = False + with pause_events(self.image_graphic, self._linear_region_selector): + # don't change the current selection + self._linear_region_selector.limits = limits self._data = weakref.proxy(data) + if self._colorbar is not None: + self.world_object.remove(self._colorbar.world_object) + + if self.image_graphic.data.value.ndim != 3: + self._colorbar: ImageGraphic = self._make_colorbar(edges_flanked) + + self.world_object.add(self._colorbar.world_object) + else: + self._colorbar = None + self._cmap = None + # reset plotarea dims self._plot_area.auto_scale() @@ -304,14 +375,20 @@ def image_graphic(self, graphic): if self._image_graphic is not None: # cleanup events from current image graphic - self._image_graphic.remove_event_handler(self._image_cmap_handler) + ig_events = _get_image_graphic_events(self._image_graphic) + self._image_graphic.remove_event_handler( + self._image_cmap_handler, *ig_events + ) self._image_graphic = graphic - self.image_graphic.add_event_handler(self._image_cmap_handler) + ig_events = _get_image_graphic_events(self._image_graphic) + + self.image_graphic.add_event_handler(self._image_cmap_handler, *ig_events) def disconnect_image_graphic(self): - self._image_graphic.remove_event_handler(self._image_cmap_handler) + ig_events = _get_image_graphic_events(self._image_graphic) + self._image_graphic.remove_event_handler(self._image_cmap_handler, *ig_events) del self._image_graphic # self._image_graphic = None diff --git a/fastplotlib/widgets/image.py b/fastplotlib/widgets/image.py index 749403781..1819f8742 100644 --- a/fastplotlib/widgets/image.py +++ b/fastplotlib/widgets/image.py @@ -126,7 +126,7 @@ def managed_graphics(self) -> list[ImageGraphic]: def cmap(self) -> list[str]: cmaps = list() for g in self.managed_graphics: - cmaps.append(g.cmap.name) + cmaps.append(g.cmap) return cmaps pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy