From 35ede8c87033041926acd93c4bdb720e075656f5 Mon Sep 17 00:00:00 2001 From: Caitlin Date: Fri, 7 Jun 2024 15:31:17 -0400 Subject: [PATCH 01/10] start guide based on new API changes --- docs/source/_static/guide_hello_world.png | 3 + docs/source/_static/guide_image_cmap.png | 3 + docs/source/_static/guide_image_slice.png | 3 + docs/source/conf.py | 54 +------ docs/source/index.rst | 1 + docs/source/user_guide/guide.rst | 172 ++++++++++++++++++++++ 6 files changed, 185 insertions(+), 51 deletions(-) create mode 100644 docs/source/_static/guide_hello_world.png create mode 100644 docs/source/_static/guide_image_cmap.png create mode 100644 docs/source/_static/guide_image_slice.png create mode 100644 docs/source/user_guide/guide.rst diff --git a/docs/source/_static/guide_hello_world.png b/docs/source/_static/guide_hello_world.png new file mode 100644 index 000000000..4244f34cd --- /dev/null +++ b/docs/source/_static/guide_hello_world.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e7c4c89d8112942ce175f20be36a5ccc43660e7f7a79895aa4fdaebee9b1dd6 +size 582082 diff --git a/docs/source/_static/guide_image_cmap.png b/docs/source/_static/guide_image_cmap.png new file mode 100644 index 000000000..67dce15a4 --- /dev/null +++ b/docs/source/_static/guide_image_cmap.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d39d45ac815278e792e461726fd324373242efe2029dee70a3f2f172015114a3 +size 571757 diff --git a/docs/source/_static/guide_image_slice.png b/docs/source/_static/guide_image_slice.png new file mode 100644 index 000000000..ef8517e7a --- /dev/null +++ b/docs/source/_static/guide_image_slice.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d3bb508d1e920e3b9ffe00b1087b30c8183a2be9b3ea28137906928058caaad6 +size 574000 diff --git a/docs/source/conf.py b/docs/source/conf.py index 4d94ec7e7..bc436c39a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -2,24 +2,7 @@ # # For the full list of built-in configuration values, see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html - -import os - -# need to force offscreen rendering before importing fpl -# otherwise fpl tries to select glfw canvas -os.environ["WGPU_FORCE_OFFSCREEN"] = "1" - import fastplotlib -from pygfx.utils.gallery_scraper import find_examples_for_gallery -from pathlib import Path -import sys -from sphinx_gallery.sorting import ExplicitOrder -import imageio.v3 as iio - -ROOT_DIR = Path(__file__).parents[1].parents[0] # repo root -EXAMPLES_DIR = Path.joinpath(ROOT_DIR, "examples", "desktop") - -sys.path.insert(0, str(ROOT_DIR)) # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information @@ -40,40 +23,9 @@ "sphinx.ext.viewcode", "sphinx_copybutton", "sphinx_design", - "sphinx_gallery.gen_gallery" + "nbsphinx", ] -sphinx_gallery_conf = { - "gallery_dirs": "_gallery", - "backreferences_dir": "_gallery/backreferences", - "doc_module": ("fastplotlib",), - "image_scrapers": ("pygfx",), - "remove_config_comments": True, - "subsection_order": ExplicitOrder( - [ - "../../examples/desktop/image", - "../../examples/desktop/gridplot", - "../../examples/desktop/line", - "../../examples/desktop/line_collection", - "../../examples/desktop/scatter", - "../../examples/desktop/heatmap", - "../../examples/desktop/misc" - ] - ), - "ignore_pattern": r'__init__\.py', - "nested_sections": False, - "thumbnail_size": (250, 250) -} - -extra_conf = find_examples_for_gallery(EXAMPLES_DIR) -sphinx_gallery_conf.update(extra_conf) - -# download imageio examples for the gallery -iio.imread("imageio:clock.png") -iio.imread("imageio:astronaut.png") -iio.imread("imageio:coffee.png") -iio.imread("imageio:hubble_deep_field.png") - autosummary_generate = True templates_path = ["_templates"] @@ -100,12 +52,12 @@ intersphinx_mapping = { "python": ("https://docs.python.org/3", None), "numpy": ("https://numpy.org/doc/stable/", None), - "pygfx": ("https://pygfx.com/latest", None), + "pygfx": ("https://pygfx.com/stable/", None), "wgpu": ("https://wgpu-py.readthedocs.io/en/latest", None), } html_theme_options = { - "source_repository": "https://github.com/fastplotlib/fastplotlib", + "source_repository": "https://github.com/kushalkolar/fastplotlib", "source_branch": "main", "source_directory": "docs/", } diff --git a/docs/source/index.rst b/docs/source/index.rst index 6385c2aee..2b40cdeca 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -5,6 +5,7 @@ Welcome to fastplotlib's documentation! :caption: User Guide :maxdepth: 2 + Guide GPU Info .. toctree:: diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst new file mode 100644 index 000000000..6bc690c4a --- /dev/null +++ b/docs/source/user_guide/guide.rst @@ -0,0 +1,172 @@ +The `fastplotlib` guide +======================= + +Installation +------------ + +To install use pip: + +.. code-block:: + + pip install -U fastplotlib + +or install the bleeding edge from Github: + +.. code-block:: + + pip install -U https://github.com/fastplotlib/fastplotlib/archive/main.zip + + +What is `fastplotlib`? +---------------------- + +`fastplotlib` is a cutting-edge plotting library built using the `pygfx `_ rendering engine. +The lower level details of the rendering process (i.e. defining a scene, camera, renderer, etc.) are abstracted away, allowing users to focus on their data. +The fundamental goal of `fastplotlib` is to provide a high-level, expressive API that promotes large-scale explorative scientific visualization. + + +How to use `fastplotlib` +------------------------ + +Before giving a detailed overview of the library, here is a minimal example:: + + import fastplotlib as fpl + import numpy as np + + fig = fpl.Figure() + + data = np.random.rand(512, 512) + + image_graphic = fig[0,0].add_image(data=data) + + fig.show() + + if __name__ == "__main__": + fpl.run() + +.. image:: /_static/guide_hello_world.png + + +This was a simple example of how the `fastplotlib` API works to create a plot, add some data to the plot, and then visualize it. +However, this is just scratching the surface of what we can do with `fastplotlib`. +Next, we will take a look at the building blocks of `fastplotlib` and how they can be used to create more complex visualizations. + +**Figure** + +The base of any visualization in `fastplotlib` is a `Figure` object. This can be a singular plot or a grid of subplots. +The `Figure` object houses and takes care of the underlying rendering components such as the camera, controller, renderer, and canvas. + +Initially, our figure is empty as we have not added any `Graphics`. After defining a `Figure`, we can begin to add `Graphic` objects. + +**Graphics** + +A `Graphic` can be an image, a line, a scatter, a collection of lines, and more. Graphics have what we like to call `GraphicFeatures` which +are mutable, indexable properties that can be linked to events. + +(1) Common `GraphicFeatures` + ++--------------+--------------------------------------------------------------------------------------------------------------+ +| Feature Name | Description | ++==============+==============================================================================================================+ +| Name | Graphic name | ++--------------+--------------------------------------------------------------------------------------------------------------+ +| Offset | Offset position of the graphic, [x, y, z] | ++--------------+--------------------------------------------------------------------------------------------------------------+ +| Rotation | Graphic rotation quaternion | ++--------------+--------------------------------------------------------------------------------------------------------------+ +| Visible | Access or change the visibility | ++--------------+--------------------------------------------------------------------------------------------------------------+ +| Deleted | Used when a graphic is deleted, triggers events that can be useful to indicate this graphic has been deleted | ++--------------+--------------------------------------------------------------------------------------------------------------+ + +(2) Graphic-Specific `GraphicFeatures` + + (a) `ImageGraphic` + + +------------------------+------------------------------------+ + | Feature Name | Description | + +========================+====================================+ + | data | Underlying image data | + +------------------------+------------------------------------+ + | vmin | Lower contrast limit of an image | + +------------------------+------------------------------------+ + | vmax | Upper contrast limit of an image | + +------------------------+------------------------------------+ + | cmap | Colormap of an image | + +------------------------+------------------------------------+ + + (b) `LineGraphic`, `LineCollection`, `LineStack` + + +--------------+--------------------------------+ + | Feature Name | Description | + +==============+================================+ + | data | underlying data of the line(s) | + +--------------+--------------------------------+ + | colors | colors of the line(s) | + +--------------+--------------------------------+ + | cmap | colormap of the line(s) | + +--------------+--------------------------------+ + | thickness | thickness of the line(s) | + +--------------+--------------------------------+ + + (c) `ScatterGraphic` + + +--------------+---------------------------------------+ + | Feature Name | Description | + +==============+=======================================+ + | data | underlying data of the scatter points | + +--------------+---------------------------------------+ + | colors | colors of the scatter points | + +--------------+---------------------------------------+ + | cmap | colormap of the scatter points | + +--------------+---------------------------------------+ + | sizes | size of the scatter points | + +--------------+---------------------------------------+ + + (d) `TextGraphic` + + +-------------------+---------------------------+ + | Feature Name | Description | + +===================+===========================+ + | text | data of the text | + +-------------------+---------------------------+ + | font_size | size of the text | + +-------------------+---------------------------+ + | face_color | color of the text face | + +-------------------+---------------------------+ + | outline_color | color of the text outline | + +-------------------+---------------------------+ + | outline_thickness | thickness of the text | + +-------------------+---------------------------+ + +Using our example from above: once we add a `Graphic` to the figure, we can then begin to change its features. :: + + image_graphic.cmap = "viridis" + +.. image:: /_static/guide_image_cmap.png + +`GraphicFeatures` also support slicing and indexing. For example :: + + image_graphic.data[::15] = 1 + image_graphic.data[15::] = 1 + +.. image:: /_static/guide_image_slice.png + +Now that we have the basics of creating a `Figure`, adding `Graphics` to the `Figure`, and working with `GraphicFeatures` to change or alter a `Graphic`. +Let's take a look at how we can define events to like `Graphics` and their `GraphicFeatures` together. + +Events +------ + + +Selectors +--------- + +`ImageWidget` +------------- + +Animations +---------- + + + From 4135480e8ac563f98d1605a2d4d8e68bdfb77690 Mon Sep 17 00:00:00 2001 From: Caitlin Lewis <69729525+clewis7@users.noreply.github.com> Date: Tue, 11 Jun 2024 14:10:14 +0000 Subject: [PATCH 02/10] Update guide.rst --- docs/source/user_guide/guide.rst | 61 +++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst index 6bc690c4a..2068185ba 100644 --- a/docs/source/user_guide/guide.rst +++ b/docs/source/user_guide/guide.rst @@ -21,7 +21,7 @@ What is `fastplotlib`? ---------------------- `fastplotlib` is a cutting-edge plotting library built using the `pygfx `_ rendering engine. -The lower level details of the rendering process (i.e. defining a scene, camera, renderer, etc.) are abstracted away, allowing users to focus on their data. +The lower-level details of the rendering process (i.e. defining a scene, camera, renderer, etc.) are abstracted away, allowing users to focus on their data. The fundamental goal of `fastplotlib` is to provide a high-level, expressive API that promotes large-scale explorative scientific visualization. @@ -47,7 +47,7 @@ Before giving a detailed overview of the library, here is a minimal example:: .. image:: /_static/guide_hello_world.png -This was a simple example of how the `fastplotlib` API works to create a plot, add some data to the plot, and then visualize it. +This is just a simple example of how the `fastplotlib` API works to create a plot, add some image data to the plot, and then visualize it. However, this is just scratching the surface of what we can do with `fastplotlib`. Next, we will take a look at the building blocks of `fastplotlib` and how they can be used to create more complex visualizations. @@ -56,30 +56,43 @@ Next, we will take a look at the building blocks of `fastplotlib` and how they c The base of any visualization in `fastplotlib` is a `Figure` object. This can be a singular plot or a grid of subplots. The `Figure` object houses and takes care of the underlying rendering components such as the camera, controller, renderer, and canvas. -Initially, our figure is empty as we have not added any `Graphics`. After defining a `Figure`, we can begin to add `Graphic` objects. +After defining a `Figure`, we can begin to add `Graphic` objects. **Graphics** -A `Graphic` can be an image, a line, a scatter, a collection of lines, and more. Graphics have what we like to call `GraphicFeatures` which -are mutable, indexable properties that can be linked to events. +A `Graphic` can be an image, a line, a scatter, a collection of lines, and more. All graphics can be given a string name. This allows graphics +to be easily accessed from figures:: -(1) Common `GraphicFeatures` + fig = fpl.Figure() + + data = np.random.rand(512, 512) + + image_graphic = fig[0,0].add_image(data=data, name="random-img") + + fig.show() + + fig[0,0]["random-img"] +.. + +Graphics also have mutable, indexable properties that can be linked to events. + +(1) Common properties +--------------+--------------------------------------------------------------------------------------------------------------+ | Feature Name | Description | +==============+==============================================================================================================+ -| Name | Graphic name | +| name | Graphic name | +--------------+--------------------------------------------------------------------------------------------------------------+ -| Offset | Offset position of the graphic, [x, y, z] | +| offset | Offset position of the graphic, [x, y, z] | +--------------+--------------------------------------------------------------------------------------------------------------+ -| Rotation | Graphic rotation quaternion | +| rotation | Graphic rotation quaternion | +--------------+--------------------------------------------------------------------------------------------------------------+ -| Visible | Access or change the visibility | +| visible | Access or change the visibility | +--------------+--------------------------------------------------------------------------------------------------------------+ -| Deleted | Used when a graphic is deleted, triggers events that can be useful to indicate this graphic has been deleted | +| deleted | Used when a graphic is deleted, triggers events that can be useful to indicate this graphic has been deleted | +--------------+--------------------------------------------------------------------------------------------------------------+ -(2) Graphic-Specific `GraphicFeatures` +(2) Graphic-Specific properties (a) `ImageGraphic` @@ -153,11 +166,33 @@ Using our example from above: once we add a `Graphic` to the figure, we can then .. image:: /_static/guide_image_slice.png Now that we have the basics of creating a `Figure`, adding `Graphics` to the `Figure`, and working with `GraphicFeatures` to change or alter a `Graphic`. -Let's take a look at how we can define events to like `Graphics` and their `GraphicFeatures` together. +Let's take a look at how we can define events to link `Graphics` and their properties together. Events ------ +All events inherit from the `pygfx.Event` class (add link) + +events table: + +PYGFX_EVENTS = [ + "key_down", + "key_up", + "pointer_down", + "pointer_move", + "pointer_up", + "pointer_enter", + "pointer_leave", + "click", + "double_click", + "wheel", + "close", + "resize", +] + +adding events (2 methods) + +attributes of all events (table) Selectors --------- From 3d153a2185208101149b710bcc9b0663e10a4eee Mon Sep 17 00:00:00 2001 From: Caitlin Date: Tue, 18 Jun 2024 15:13:43 -0400 Subject: [PATCH 03/10] progress on guide --- docs/source/user_guide/guide.rst | 71 ++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst index 2068185ba..297713a0c 100644 --- a/docs/source/user_guide/guide.rst +++ b/docs/source/user_guide/guide.rst @@ -22,7 +22,8 @@ What is `fastplotlib`? `fastplotlib` is a cutting-edge plotting library built using the `pygfx `_ rendering engine. The lower-level details of the rendering process (i.e. defining a scene, camera, renderer, etc.) are abstracted away, allowing users to focus on their data. -The fundamental goal of `fastplotlib` is to provide a high-level, expressive API that promotes large-scale explorative scientific visualization. +The fundamental goal of `fastplotlib` is to provide a high-level, expressive API that promotes large-scale explorative scientific visualization. We want to +make it easy and intuitive to produce interactive visualizations that are as performant and vibrant as a modern video game :D How to use `fastplotlib` @@ -31,11 +32,11 @@ How to use `fastplotlib` Before giving a detailed overview of the library, here is a minimal example:: import fastplotlib as fpl - import numpy as np + import imageio.v3 as iio fig = fpl.Figure() - data = np.random.rand(512, 512) + data = iio.imread("imageio:astronaut.png") image_graphic = fig[0,0].add_image(data=data) @@ -44,7 +45,7 @@ Before giving a detailed overview of the library, here is a minimal example:: if __name__ == "__main__": fpl.run() -.. image:: /_static/guide_hello_world.png +.. This is just a simple example of how the `fastplotlib` API works to create a plot, add some image data to the plot, and then visualize it. @@ -53,28 +54,31 @@ Next, we will take a look at the building blocks of `fastplotlib` and how they c **Figure** -The base of any visualization in `fastplotlib` is a `Figure` object. This can be a singular plot or a grid of subplots. +The starting for creating any visualization in `fastplotlib` is a `Figure` object. This can be a single plot or a grid of subplots. The `Figure` object houses and takes care of the underlying rendering components such as the camera, controller, renderer, and canvas. +Most users won't need to use these directly; however, the ability to directly interact with the rendering engine is still available if +needed. After defining a `Figure`, we can begin to add `Graphic` objects. **Graphics** -A `Graphic` can be an image, a line, a scatter, a collection of lines, and more. All graphics can be given a string name. This allows graphics +A `Graphic` can be an image, a line, a scatter, a collection of lines, and more. All graphics can be given a convenient ``name``. This allows graphics to be easily accessed from figures:: fig = fpl.Figure() data = np.random.rand(512, 512) - image_graphic = fig[0,0].add_image(data=data, name="random-img") + image_graphic = fig[0,0].add_image(data=data, name="astronaut") fig.show() - fig[0,0]["random-img"] + fig[0,0]["astronaut"] .. -Graphics also have mutable, indexable properties that can be linked to events. +Graphics also have mutable properties that can be linked to events. Some of these properties, such as the `data` or `colors` of a line can even be indexed, +allowing for the creation of very powerful visualizations. (1) Common properties @@ -152,20 +156,20 @@ Graphics also have mutable, indexable properties that can be linked to events. | outline_thickness | thickness of the text | +-------------------+---------------------------+ -Using our example from above: once we add a `Graphic` to the figure, we can then begin to change its features. :: +Using our example from above: once we add a `Graphic` to the figure, we can then begin to change its properties. :: - image_graphic.cmap = "viridis" + image_graphic.vmax = "150" -.. image:: /_static/guide_image_cmap.png +.. -`GraphicFeatures` also support slicing and indexing. For example :: +`Graphic` properties also support slicing and indexing. For example :: - image_graphic.data[::15] = 1 - image_graphic.data[15::] = 1 + image_graphic.data[::8, :, :] = 1 + image_graphic.data[:, ::8, :] = 1 -.. image:: /_static/guide_image_slice.png +.. -Now that we have the basics of creating a `Figure`, adding `Graphics` to the `Figure`, and working with `GraphicFeatures` to change or alter a `Graphic`. +Now we have the basics of creating a `Figure`, adding `Graphics` to a `Figure`, and working with `Graphic` properties to dynamically change or alter them. Let's take a look at how we can define events to link `Graphics` and their properties together. Events @@ -200,8 +204,41 @@ Selectors `ImageWidget` ------------- +Often times, developing UIs for interacting with multi-dimension image data can be tedious and repetitive. In order to alleviate the headache that accompanies +constantly recreating visualizations, we created an `ImageWidget` that automatically generates sliders and + Animations ---------- +An animation function is a user-defined function that gets called on every rendering cycle. Let's look at an example: :: + + import fastplotlib as fpl + import numpy as np + + data = np.random.rand(512, 512) + + fig = fpl.Figure() + + fig[0,0].add_image(data=data, name="random-img") + + def update_data(plot_instance): + new_data = np.random.rand(512, 512) + plot_instance["random-img"].data = new_data + + fig[0,0].add_animations(update_data) + + fig.show() + +.. + +Here we are defining a function that updates the data of the `ImageGraphic` in the plot with new random data. When adding an animation function, the +user-defined function will receive a plot instance as an argument when it is called. + +Spaces +------ + + +Using `fastplotlib` interactively +--------------------------------- From dfa3a1ba27a063a68cda998296947541f4fa0ea2 Mon Sep 17 00:00:00 2001 From: Caitlin Date: Sat, 22 Jun 2024 04:45:40 -0400 Subject: [PATCH 04/10] guide updates --- docs/source/_static/guide_animation.gif | 3 ++ docs/source/_static/guide_hello_world.png | 4 +- .../source/_static/guide_hello_world_data.png | 3 ++ .../source/_static/guide_hello_world_vmax.png | 3 ++ docs/source/_static/guide_image_cmap.png | 3 -- docs/source/_static/guide_image_slice.png | 3 -- docs/source/_static/guide_image_widget.gif | 3 ++ docs/source/user_guide/guide.rst | 51 +++++++++++++------ 8 files changed, 50 insertions(+), 23 deletions(-) create mode 100644 docs/source/_static/guide_animation.gif create mode 100644 docs/source/_static/guide_hello_world_data.png create mode 100644 docs/source/_static/guide_hello_world_vmax.png delete mode 100644 docs/source/_static/guide_image_cmap.png delete mode 100644 docs/source/_static/guide_image_slice.png create mode 100644 docs/source/_static/guide_image_widget.gif diff --git a/docs/source/_static/guide_animation.gif b/docs/source/_static/guide_animation.gif new file mode 100644 index 000000000..6328dbefc --- /dev/null +++ b/docs/source/_static/guide_animation.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b69ad02a527f4c7353cb94ce22deedd92134e84b2cc0776bf81f3d0083d0e37 +size 4095880 diff --git a/docs/source/_static/guide_hello_world.png b/docs/source/_static/guide_hello_world.png index 4244f34cd..b66b3d592 100644 --- a/docs/source/_static/guide_hello_world.png +++ b/docs/source/_static/guide_hello_world.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8e7c4c89d8112942ce175f20be36a5ccc43660e7f7a79895aa4fdaebee9b1dd6 -size 582082 +oid sha256:81fdee4dda9bbc46d810a6e80ddc4d6ceb8ff0db8dfea2faf90424f977c000d4 +size 201157 diff --git a/docs/source/_static/guide_hello_world_data.png b/docs/source/_static/guide_hello_world_data.png new file mode 100644 index 000000000..6164f4d55 --- /dev/null +++ b/docs/source/_static/guide_hello_world_data.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cda3395fb158706eeffc669f3f7cf09b99316870e32f51f69aedc9a6f1590ddb +size 123621 diff --git a/docs/source/_static/guide_hello_world_vmax.png b/docs/source/_static/guide_hello_world_vmax.png new file mode 100644 index 000000000..91441a16c --- /dev/null +++ b/docs/source/_static/guide_hello_world_vmax.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36902d1e082730af8dc383ff7f89434c93b9e605f0410dd199d39495cd61c552 +size 143561 diff --git a/docs/source/_static/guide_image_cmap.png b/docs/source/_static/guide_image_cmap.png deleted file mode 100644 index 67dce15a4..000000000 --- a/docs/source/_static/guide_image_cmap.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d39d45ac815278e792e461726fd324373242efe2029dee70a3f2f172015114a3 -size 571757 diff --git a/docs/source/_static/guide_image_slice.png b/docs/source/_static/guide_image_slice.png deleted file mode 100644 index ef8517e7a..000000000 --- a/docs/source/_static/guide_image_slice.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d3bb508d1e920e3b9ffe00b1087b30c8183a2be9b3ea28137906928058caaad6 -size 574000 diff --git a/docs/source/_static/guide_image_widget.gif b/docs/source/_static/guide_image_widget.gif new file mode 100644 index 000000000..06f23c52d --- /dev/null +++ b/docs/source/_static/guide_image_widget.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a3c90078ab4ec8552c4eac199c726d413c89ec63143988e3ea0fca5114393d6 +size 2122357 diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst index 297713a0c..6cb2da7dc 100644 --- a/docs/source/user_guide/guide.rst +++ b/docs/source/user_guide/guide.rst @@ -38,43 +38,46 @@ Before giving a detailed overview of the library, here is a minimal example:: data = iio.imread("imageio:astronaut.png") - image_graphic = fig[0,0].add_image(data=data) + image_graphic = fig[0, 0].add_image(data=data) fig.show() if __name__ == "__main__": fpl.run() -.. +.. image:: _static/guide_hello_world.png This is just a simple example of how the `fastplotlib` API works to create a plot, add some image data to the plot, and then visualize it. -However, this is just scratching the surface of what we can do with `fastplotlib`. -Next, we will take a look at the building blocks of `fastplotlib` and how they can be used to create more complex visualizations. +However, we are just scratching the surface of what is possible with `fastplotlib`. +Next, let's take a look at the building blocks of `fastplotlib` and how they can be used to create more complex visualizations. **Figure** -The starting for creating any visualization in `fastplotlib` is a `Figure` object. This can be a single plot or a grid of subplots. +The starting point for creating any visualization in `fastplotlib` is a `Figure` object. This can be a single plot or a grid of subplots. The `Figure` object houses and takes care of the underlying rendering components such as the camera, controller, renderer, and canvas. Most users won't need to use these directly; however, the ability to directly interact with the rendering engine is still available if needed. +By default, if no ``shape`` argument is provided when creating a `Figure`, there will be a single subplot. All subplots in a `Figure` can be accessed using +indexing (i.e. `fig_object[i ,j]`). + After defining a `Figure`, we can begin to add `Graphic` objects. **Graphics** -A `Graphic` can be an image, a line, a scatter, a collection of lines, and more. All graphics can be given a convenient ``name``. This allows graphics +A `Graphic` can be an image, a line, a scatter, a collection of lines, and more. All graphics can also be given a convenient ``name``. This allows graphics to be easily accessed from figures:: fig = fpl.Figure() - data = np.random.rand(512, 512) + data = iio.imread("imageio:astronaut.png") - image_graphic = fig[0,0].add_image(data=data, name="astronaut") + image_graphic = fig[0, 0].add_image(data=data, name="astronaut") fig.show() - fig[0,0]["astronaut"] + fig[0, 0]["astronaut"] .. Graphics also have mutable properties that can be linked to events. Some of these properties, such as the `data` or `colors` of a line can even be indexed, @@ -158,16 +161,16 @@ allowing for the creation of very powerful visualizations. Using our example from above: once we add a `Graphic` to the figure, we can then begin to change its properties. :: - image_graphic.vmax = "150" + image_graphic.vmax = 150 -.. +.. image:: _static/hello_world_vmax.png `Graphic` properties also support slicing and indexing. For example :: image_graphic.data[::8, :, :] = 1 image_graphic.data[:, ::8, :] = 1 -.. +.. image:: _static/hello_world_data.png Now we have the basics of creating a `Figure`, adding `Graphics` to a `Figure`, and working with `Graphic` properties to dynamically change or alter them. Let's take a look at how we can define events to link `Graphics` and their properties together. @@ -204,8 +207,26 @@ Selectors `ImageWidget` ------------- -Often times, developing UIs for interacting with multi-dimension image data can be tedious and repetitive. In order to alleviate the headache that accompanies -constantly recreating visualizations, we created an `ImageWidget` that automatically generates sliders and +Often times, developing UIs for interacting with multi-dimension image data can be tedious and repetitive. +In order to aid with common image and video visualization requirements the `ImageWidget` automatically generates sliders +to easily navigate through different dimensions of your data. Let's look at an example: :: + + import fastplotlib as fpl + import imageio.v3 as iio + + movie = iio.imread("imageio:cockatoo.mp4") + + # convert RGB movie to grayscale + gray_movie = np.dot(movie[..., :3], [0.299, 0.587, 0.114]) + + iw_movie = ImageWidget( + data=gray_movie, + cmap="gray" + ) + + iw_movie.show() + +.. image:: _static/guide_image_widget.gif Animations ---------- @@ -229,7 +250,7 @@ An animation function is a user-defined function that gets called on every rende fig.show() -.. +.. image:: _static/guide_animation.gif Here we are defining a function that updates the data of the `ImageGraphic` in the plot with new random data. When adding an animation function, the user-defined function will receive a plot instance as an argument when it is called. From e3fe161fd2b2536d971765026d154c3ca7a0583b Mon Sep 17 00:00:00 2001 From: Caitlin Date: Sat, 22 Jun 2024 05:27:30 -0400 Subject: [PATCH 05/10] add spaces and interactive use sections --- docs/source/user_guide/guide.rst | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst index 6cb2da7dc..adb0f7827 100644 --- a/docs/source/user_guide/guide.rst +++ b/docs/source/user_guide/guide.rst @@ -258,8 +258,49 @@ user-defined function will receive a plot instance as an argument when it is cal Spaces ------ +There are several spaces to consider when using `fastplotlib`: + +1) World Space + + World space is the 3D space in which objects live. World space has no limits on its size. Objects + and the camera can exist anywhere in this space. Objects in this space exist relative to a larger + world. + +2) Data Space + + Data space is simply the world space plus any offset or rotation that has been applied to an object. + +3) Screen Space + + Screen space is a 2D space represented in pixels. This space is constrained by the screen width and screen height. + In the rendering process, the camera is responsible for projecting the world space into screen space. + +.. note:: + When interacting with `Graphic` objects, there is a very helpful function for mapping screen space to world space + (`Figure.map_screen_to_world(pos=(x, y))`). This can be particularly useful when working with click events where click + positions are returned in screen space but `Graphic` objects that you may want to interact with exist in world + space. + Using `fastplotlib` interactively --------------------------------- +There are multiple ways to use `fastplotlib` interactively. + +On `jupyter lab` or `jupyter notebook` the jupyter backend (i.e. `jupyter_rfb`) is normally selected. This works via +client-server rendering. Images generated on the server are streamed to the client (Jupyter) via a jpeg byte stream. +Events (such as mouse or keyboard events) are then streamed in the opposite direction prompting new images to be generated +by the server if necessary. This remote-frame-buffer approach makes the rendering process very fast. `fastplotlib` viusalizations +can be displayed in cell output or on the side using `jupyterlab-sidecar`. + +However, a Qt backend can optionally be used as well. If `%gui qt` is selected before importing `fastplotlib` then this backend +will be used instead. +Users can also force using `glfw` by specifying this as an argument when instantiating a `Figure` (i.e. `Figure(canvas="gflw"`). + +.. note:: + Do not mix between gui backends. For example, if you start the notebook using Qt, do not attempt to force using another backend such + as `jupyter_rfb` later. + + +Furthermore, in `IPython`, users can select between using a Qt backend or gflw the same as above. From 33eda1e949580828b25a02ed84682373a8949c19 Mon Sep 17 00:00:00 2001 From: Caitlin Date: Sat, 22 Jun 2024 05:51:13 -0400 Subject: [PATCH 06/10] add selectors to guide --- docs/source/_static/guide_linear_selector.gif | 3 ++ docs/source/user_guide/guide.rst | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 docs/source/_static/guide_linear_selector.gif diff --git a/docs/source/_static/guide_linear_selector.gif b/docs/source/_static/guide_linear_selector.gif new file mode 100644 index 000000000..383c3ef43 --- /dev/null +++ b/docs/source/_static/guide_linear_selector.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:acf1cab72eb4d268581b26295e47cd0ca9aebe08beaf80e1424b100086ed59ca +size 331446 diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst index adb0f7827..300018843 100644 --- a/docs/source/user_guide/guide.rst +++ b/docs/source/user_guide/guide.rst @@ -204,6 +204,37 @@ attributes of all events (table) Selectors --------- +A primary feature of `fastplotlib` is the ability to easily interact with your data. Two extremely helpful tools that can +be used in order to facilitate this process are a `LinearSelector` and `LinearRegionSelector`. + +A `LinearSelector` is a horizontal or vertical line slider. This tool allows you to very easily select different points in your +data. Let's look at an example: :: + + import fastplotlib as fpl + import numpy as np + + # generate data + xs = np.linspace(-10, 10, 100) + ys = np.sin(xs) + sine = np.column_stack([xs, ys]) + + fig = fpl.Figure() + + sine_graphic = fig[0, 0].add_line(data=sine, colors="w") + + # add a linear selector the sine wave + selector = sine_graphic.add_linear_selector() + + fig[0, 0].auto_scale() + + fig.show(maintain_aspect=False) + +.. image:: _static/guide_linear_selector.gif + + +A `LinearRegionSelector` is very similar to a `LinearSelector` but as opposed to selecting a singular point of +your data, you are able to select an entire region. + `ImageWidget` ------------- From be6a8ea5cf43eb54f5ccf58c67a6fb35fbc8537f Mon Sep 17 00:00:00 2001 From: Caitlin Date: Sat, 22 Jun 2024 06:07:46 -0400 Subject: [PATCH 07/10] guide updates --- docs/source/conf.py | 54 ++++++++++++++++++++++++++++++-- docs/source/user_guide/guide.rst | 2 ++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index bc436c39a..0df47e579 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -2,7 +2,24 @@ # # For the full list of built-in configuration values, see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html + +import os + +# need to force offscreen rendering before importing fpl +# otherwise fpl tries to select glfw canvas +os.environ["WGPU_FORCE_OFFSCREEN"] = "1" + import fastplotlib +from pygfx.utils.gallery_scraper import find_examples_for_gallery +from pathlib import Path +import sys +from sphinx_gallery.sorting import ExplicitOrder +import imageio.v3 as iio + +ROOT_DIR = Path(__file__).parents[1].parents[0] # repo root +EXAMPLES_DIR = Path.joinpath(ROOT_DIR, "examples", "desktop") + +sys.path.insert(0, str(ROOT_DIR)) # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information @@ -23,9 +40,40 @@ "sphinx.ext.viewcode", "sphinx_copybutton", "sphinx_design", - "nbsphinx", + "sphinx_gallery.gen_gallery" ] +sphinx_gallery_conf = { + "gallery_dirs": "_gallery", + "backreferences_dir": "_gallery/backreferences", + "doc_module": ("fastplotlib",), + "image_scrapers": ("pygfx",), + "remove_config_comments": True, + "subsection_order": ExplicitOrder( + [ + "../../examples/desktop/image", + "../../examples/desktop/gridplot", + "../../examples/desktop/line", + "../../examples/desktop/line_collection", + "../../examples/desktop/scatter", + "../../examples/desktop/heatmap", + "../../examples/desktop/misc" + ] + ), + "ignore_pattern": r'__init__\.py', + "nested_sections": False, + "thumbnail_size": (250, 250) +} + +extra_conf = find_examples_for_gallery(EXAMPLES_DIR) +sphinx_gallery_conf.update(extra_conf) + +# download imageio examples for the gallery +iio.imread("imageio:clock.png") +iio.imread("imageio:astronaut.png") +iio.imread("imageio:coffee.png") +iio.imread("imageio:hubble_deep_field.png") + autosummary_generate = True templates_path = ["_templates"] @@ -52,12 +100,12 @@ intersphinx_mapping = { "python": ("https://docs.python.org/3", None), "numpy": ("https://numpy.org/doc/stable/", None), - "pygfx": ("https://pygfx.com/stable/", None), + "pygfx": ("https://pygfx.com/stable", None), "wgpu": ("https://wgpu-py.readthedocs.io/en/latest", None), } html_theme_options = { - "source_repository": "https://github.com/kushalkolar/fastplotlib", + "source_repository": "https://github.com/fastplotlib/fastplotlib", "source_branch": "main", "source_directory": "docs/", } diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst index 300018843..2c09e57de 100644 --- a/docs/source/user_guide/guide.rst +++ b/docs/source/user_guide/guide.rst @@ -80,6 +80,7 @@ to be easily accessed from figures:: fig[0, 0]["astronaut"] .. + Graphics also have mutable properties that can be linked to events. Some of these properties, such as the `data` or `colors` of a line can even be indexed, allowing for the creation of very powerful visualizations. @@ -197,6 +198,7 @@ PYGFX_EVENTS = [ "resize", ] + adding events (2 methods) attributes of all events (table) From 9801eae094ad3ed751ba479353c5cd9b66bf54ed Mon Sep 17 00:00:00 2001 From: Caitlin Date: Sat, 22 Jun 2024 09:42:51 -0400 Subject: [PATCH 08/10] rough draft --- docs/source/user_guide/guide.rst | 218 ++++++++++++++++++++++++++----- 1 file changed, 188 insertions(+), 30 deletions(-) diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst index 2c09e57de..e91026ae6 100644 --- a/docs/source/user_guide/guide.rst +++ b/docs/source/user_guide/guide.rst @@ -78,8 +78,8 @@ to be easily accessed from figures:: fig.show() fig[0, 0]["astronaut"] -.. +.. Graphics also have mutable properties that can be linked to events. Some of these properties, such as the `data` or `colors` of a line can even be indexed, allowing for the creation of very powerful visualizations. @@ -173,35 +173,6 @@ Using our example from above: once we add a `Graphic` to the figure, we can then .. image:: _static/hello_world_data.png -Now we have the basics of creating a `Figure`, adding `Graphics` to a `Figure`, and working with `Graphic` properties to dynamically change or alter them. -Let's take a look at how we can define events to link `Graphics` and their properties together. - -Events ------- - -All events inherit from the `pygfx.Event` class (add link) - -events table: - -PYGFX_EVENTS = [ - "key_down", - "key_up", - "pointer_down", - "pointer_move", - "pointer_up", - "pointer_enter", - "pointer_leave", - "click", - "double_click", - "wheel", - "close", - "resize", -] - - -adding events (2 methods) - -attributes of all events (table) Selectors --------- @@ -237,6 +208,193 @@ data. Let's look at an example: :: A `LinearRegionSelector` is very similar to a `LinearSelector` but as opposed to selecting a singular point of your data, you are able to select an entire region. + +Now we have the basics of creating a `Figure`, adding `Graphics` to a `Figure`, and working with `Graphic` properties to dynamically change or alter them. +Let's take a look at how we can define events to link `Graphics` and their properties together. + +Events +------ + +Events can be a multitude of things: traditional events such as mouse or keyboard events, but they can also be +events related to `Graphic` properties. + + +There are two methods for adding events in `fastplotlib`. + +1) Add an event handler directly. :: + + def event_handler(ev): + pass + + graphic.add_event_handler(event_handler, "event_type") + +.. + + +2) Use decorator notation. :: + + @graphic.add_event_handler("event_type") + def event_handler(ev): + pass + +.. + +.. note:: + You can also add events to a `Figure` object's renderer. This is useful for defining click events where + you want to map your click position to the nearest graphic object for example. + + +The `event_handler` is a user-defined function that accepts a singular event object (`ev`) as an argument. +Information about the contents of the event object argument can be found below. The `"event_type"` +is a string that identifies the type of event; this can be either a `pygfx.Event` or a `Graphic` property event. +See the above graphic-specific properties that can be used for events and below for the available `pygfx` events. + +Available `pygfx` Events: + - "key_down" + - "key_up" + - "pointer_down" + - "pointer_move" + - "pointer_up" + - "pointer_enter" + - "pointer_leave" + - "click" + - "double_click" + - "wheel" + - "close" + - "resize" + +When an event occurs, the user-defined event handler will receive and event object. Depending on the type of event, the +event object will have relevant information that can be used in the callback. See below for event tables. + + +**All events have the following attributes:** + + +------------+-------------+-----------------------------------------------+ + | attribute | type | description | + +============+=============+===============================================+ + | type | str | "colors" - name of the event | + +------------+-------------+-----------------------------------------------+ + | graphic | Graphic | graphic instance that the event is from | + +------------+-------------+-----------------------------------------------+ + | info | dict | event info dictionary | + +------------+-------------+-----------------------------------------------+ + | target | WorldObject | pygfx rendering engine object for the graphic | + +------------+-------------+-----------------------------------------------+ + | time_stamp | float | time when the event occurred, in ms | + +------------+-------------+-----------------------------------------------+ + +The ``info`` attribute will house additional information for different `Graphic` property events: + +event_type: "colors" + + Vertex Colors + + **info dict** + + +------------+-----------------------------------------------------------+----------------------------------------------------------------------------------+ + | dict key | value type | value description | + +============+===========================================================+==================================================================================+ + | key | int | slice | np.ndarray[int | bool] | tuple[slice, ...] | key at which colors were indexed/sliced | + +------------+-----------------------------------------------------------+----------------------------------------------------------------------------------+ + | value | np.ndarray | new color values for points that were changed, shape is [n_points_changed, RGBA] | + +------------+-----------------------------------------------------------+----------------------------------------------------------------------------------+ + | user_value | str | np.ndarray | tuple[float] | list[float] | list[str] | user input value that was parsed into the RGBA array | + +------------+-----------------------------------------------------------+----------------------------------------------------------------------------------+ + + Uniform Colors + + **info dict** + + +------------+-----------------------------------------------------------+----------------------------------------------------------------------------------+ + | dict key | value type | value description | + +============+===========================================================+==================================================================================+ + | value | np.ndarray | new color values for points that were changed, shape is [n_points_changed, RGBA] | + +------------+-----------------------------------------------------------+----------------------------------------------------------------------------------+ + +event_type: "sizes" + + **info dict** + + +----------+----------------------------------------------------------+------------------------------------------------------------------------------------------+ + | dict key | value type | value description | + +==========+==========================================================+==========================================================================================+ + | key | int | slice | np.ndarray[int | bool] | tuple[slice, ...] | key at which vertex positions data were indexed/sliced | + +----------+----------------------------------------------------------+------------------------------------------------------------------------------------------+ + | value | np.ndarray | float | list[float] | new data values for points that were changed, shape depends on the indices that were set | + +----------+----------------------------------------------------------+------------------------------------------------------------------------------------------+ + +event_type: "data" + + **info dict** + + +----------+----------------------------------------------------------+------------------------------------------------------------------------------------------+ + | dict key | value type | value description | + +==========+==========================================================+==========================================================================================+ + | key | int | slice | np.ndarray[int | bool] | tuple[slice, ...] | key at which vertex positions data were indexed/sliced | + +----------+----------------------------------------------------------+------------------------------------------------------------------------------------------+ + | value | np.ndarray | float | list[float] | new data values for points that were changed, shape depends on the indices that were set | + +----------+----------------------------------------------------------+------------------------------------------------------------------------------------------+ + +event_type: "thickness" + + **info dict** + + +------------+-----------------------------------------------------------+----------------------------------------------------------------------------------+ + | dict key | value type | value description | + +============+===========================================================+==================================================================================+ + | value | float | new thickness value | + +------------+-----------------------------------------------------------+----------------------------------------------------------------------------------+ + +event_type: "cmap" + + **info dict** + + +------------+-----------------------------------------------------------+----------------------------------------------------------------------------------+ + | dict key | value type | value description | + +============+===========================================================+==================================================================================+ + | value | string | new colormap value | + +------------+-----------------------------------------------------------+----------------------------------------------------------------------------------+ + +event_type: "selection" + + LinearSelector + + **additional event attributes:** + + +--------------------+----------+------------------------------------+ + | attribute | type | description | + +====================+==========+====================================+ + | get_selected_index | callable | returns indices under the selector | + +--------------------+----------+------------------------------------+ + + **info dict:** + + +----------+------------+-------------------------------+ + | dict key | value type | value description | + +==========+============+===============================+ + | value | np.ndarray | new x or y value of selection | + +----------+------------+-------------------------------+ + + LinearRegionSelector + + **additional event attributes:** + + +----------------------+----------+------------------------------------+ + | attribute | type | description | + +======================+==========+====================================+ + | get_selected_indices | callable | returns indices under the selector | + +----------------------+----------+------------------------------------+ + | get_selected_data | callable | returns data under the selector | + +----------------------+----------+------------------------------------+ + + **info dict:** + + +----------+------------+-----------------------------+ + | dict key | value type | value description | + +==========+============+=============================+ + | value | np.ndarray | new [min, max] of selection | + +----------+------------+-----------------------------+ + `ImageWidget` ------------- From 74db25549b4f4f3bc03c6480ecc4599bccc3c199 Mon Sep 17 00:00:00 2001 From: Caitlin Lewis <69729525+clewis7@users.noreply.github.com> Date: Sat, 22 Jun 2024 11:33:22 -0400 Subject: [PATCH 09/10] Apply suggestions from code review Co-authored-by: Kushal Kolar --- docs/source/user_guide/guide.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst index e91026ae6..b5074d56a 100644 --- a/docs/source/user_guide/guide.rst +++ b/docs/source/user_guide/guide.rst @@ -14,16 +14,16 @@ or install the bleeding edge from Github: .. code-block:: - pip install -U https://github.com/fastplotlib/fastplotlib/archive/main.zip + pip install git+https://github.com/fastplotlib/fastplotlib.git@main -What is `fastplotlib`? +What is ``fastplotlib``? ---------------------- -`fastplotlib` is a cutting-edge plotting library built using the `pygfx `_ rendering engine. +``fastplotlib`` is a cutting-edge plotting library built using the ```pygfx`` `_ rendering engine. The lower-level details of the rendering process (i.e. defining a scene, camera, renderer, etc.) are abstracted away, allowing users to focus on their data. The fundamental goal of `fastplotlib` is to provide a high-level, expressive API that promotes large-scale explorative scientific visualization. We want to -make it easy and intuitive to produce interactive visualizations that are as performant and vibrant as a modern video game :D +make it easy and intuitive to produce interactive visualizations that are as performant and vibrant as a modern video game 😄 How to use `fastplotlib` @@ -84,7 +84,7 @@ to be easily accessed from figures:: Graphics also have mutable properties that can be linked to events. Some of these properties, such as the `data` or `colors` of a line can even be indexed, allowing for the creation of very powerful visualizations. -(1) Common properties +(1) Common properties that all graphics have +--------------+--------------------------------------------------------------------------------------------------------------+ | Feature Name | Description | @@ -216,12 +216,12 @@ Events ------ Events can be a multitude of things: traditional events such as mouse or keyboard events, but they can also be -events related to `Graphic` properties. +You can use renderer events, such as mouse or keyboard events, or events related to `Graphic` properties. -There are two methods for adding events in `fastplotlib`. +There are two ways to add events in `fastplotlib`. -1) Add an event handler directly. :: +1) Use the method :: def event_handler(ev): pass @@ -231,7 +231,7 @@ There are two methods for adding events in `fastplotlib`. .. -2) Use decorator notation. :: +2) or a decorator :: @graphic.add_event_handler("event_type") def event_handler(ev): @@ -244,12 +244,12 @@ There are two methods for adding events in `fastplotlib`. you want to map your click position to the nearest graphic object for example. -The `event_handler` is a user-defined function that accepts a singular event object (`ev`) as an argument. -Information about the contents of the event object argument can be found below. The `"event_type"` +The `event_handler` is a user-defined function that accepts an event instance as the first and only positional argument. +Information about the structure of event instances are described below. The `"event_type"` is a string that identifies the type of event; this can be either a `pygfx.Event` or a `Graphic` property event. See the above graphic-specific properties that can be used for events and below for the available `pygfx` events. -Available `pygfx` Events: +Rendering engine (``pygfx``) events: - "key_down" - "key_up" - "pointer_down" @@ -267,7 +267,7 @@ When an event occurs, the user-defined event handler will receive and event obje event object will have relevant information that can be used in the callback. See below for event tables. -**All events have the following attributes:** +**All ``Graphic`` events have the following attributes:** +------------+-------------+-----------------------------------------------+ | attribute | type | description | @@ -453,7 +453,7 @@ There are several spaces to consider when using `fastplotlib`: 1) World Space - World space is the 3D space in which objects live. World space has no limits on its size. Objects + World space is the 3D space in which graphical objects live. Objects and the camera can exist anywhere in this space. Objects in this space exist relative to a larger world. @@ -463,7 +463,7 @@ There are several spaces to consider when using `fastplotlib`: 3) Screen Space - Screen space is a 2D space represented in pixels. This space is constrained by the screen width and screen height. + Screen space is the 2D space in which your screen pixels reside. This space is constrained by the screen width and height in pixels. In the rendering process, the camera is responsible for projecting the world space into screen space. .. note:: From bda47660427b3d3e98ad55d87deb69bab914a54e Mon Sep 17 00:00:00 2001 From: Caitlin Date: Sat, 22 Jun 2024 12:12:59 -0400 Subject: [PATCH 10/10] update guide --- docs/source/user_guide/guide.rst | 181 +++++++++++++++++++++---------- 1 file changed, 122 insertions(+), 59 deletions(-) diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst index b5074d56a..87e2b7fab 100644 --- a/docs/source/user_guide/guide.rst +++ b/docs/source/user_guide/guide.rst @@ -22,11 +22,11 @@ What is ``fastplotlib``? ``fastplotlib`` is a cutting-edge plotting library built using the ```pygfx`` `_ rendering engine. The lower-level details of the rendering process (i.e. defining a scene, camera, renderer, etc.) are abstracted away, allowing users to focus on their data. -The fundamental goal of `fastplotlib` is to provide a high-level, expressive API that promotes large-scale explorative scientific visualization. We want to +The fundamental goal of ``fastplotlib`` is to provide a high-level, expressive API that promotes large-scale explorative scientific visualization. We want to make it easy and intuitive to produce interactive visualizations that are as performant and vibrant as a modern video game 😄 -How to use `fastplotlib` +How to use ``fastplotlib`` ------------------------ Before giving a detailed overview of the library, here is a minimal example:: @@ -34,54 +34,63 @@ Before giving a detailed overview of the library, here is a minimal example:: import fastplotlib as fpl import imageio.v3 as iio + # create a `Figure` fig = fpl.Figure() + # read data data = iio.imread("imageio:astronaut.png") + # add image graphic image_graphic = fig[0, 0].add_image(data=data) + # show the plot fig.show() if __name__ == "__main__": fpl.run() -.. image:: _static/guide_hello_world.png +.. image:: ./_static/guide_hello_world.png -This is just a simple example of how the `fastplotlib` API works to create a plot, add some image data to the plot, and then visualize it. -However, we are just scratching the surface of what is possible with `fastplotlib`. -Next, let's take a look at the building blocks of `fastplotlib` and how they can be used to create more complex visualizations. +This is just a simple example of how the ``fastplotlib`` API works to create a plot, add some image data to the plot, and then visualize it. +However, we are just scratching the surface of what is possible with ``fastplotlib``. +Next, let's take a look at the building blocks of ``fastplotlib`` and how they can be used to create more complex visualizations. **Figure** -The starting point for creating any visualization in `fastplotlib` is a `Figure` object. This can be a single plot or a grid of subplots. -The `Figure` object houses and takes care of the underlying rendering components such as the camera, controller, renderer, and canvas. +The starting point for creating any visualization in ``fastplotlib`` is a ``Figure`` object. This can be a single plot or a grid of subplots. +The ``Figure`` object houses and takes care of the underlying rendering components such as the camera, controller, renderer, and canvas. Most users won't need to use these directly; however, the ability to directly interact with the rendering engine is still available if needed. -By default, if no ``shape`` argument is provided when creating a `Figure`, there will be a single subplot. All subplots in a `Figure` can be accessed using -indexing (i.e. `fig_object[i ,j]`). +By default, if no ``shape`` argument is provided when creating a ``Figure``, there will be a single subplot. All subplots in a ``Figure`` can be accessed using +indexing (i.e. ``fig_object[i ,j]``). -After defining a `Figure`, we can begin to add `Graphic` objects. +After defining a ``Figure``, we can begin to add ``Graphic`` objects. **Graphics** -A `Graphic` can be an image, a line, a scatter, a collection of lines, and more. All graphics can also be given a convenient ``name``. This allows graphics +A ``Graphic`` can be an image, a line, a scatter, a collection of lines, and more. All graphics can also be given a convenient ``name``. This allows graphics to be easily accessed from figures:: + # create a `Figure` fig = fpl.Figure() + # read data data = iio.imread("imageio:astronaut.png") + add image graphic image_graphic = fig[0, 0].add_image(data=data, name="astronaut") + # show plot fig.show() + # index plot to get graphic fig[0, 0]["astronaut"] .. -Graphics also have mutable properties that can be linked to events. Some of these properties, such as the `data` or `colors` of a line can even be indexed, +Graphics also have mutable properties that can be linked to events. Some of these properties, such as the ``data`` or ``colors`` of a line can even be indexed, allowing for the creation of very powerful visualizations. (1) Common properties that all graphics have @@ -102,7 +111,7 @@ allowing for the creation of very powerful visualizations. (2) Graphic-Specific properties - (a) `ImageGraphic` + (a) ``ImageGraphic`` +------------------------+------------------------------------+ | Feature Name | Description | @@ -116,7 +125,7 @@ allowing for the creation of very powerful visualizations. | cmap | Colormap of an image | +------------------------+------------------------------------+ - (b) `LineGraphic`, `LineCollection`, `LineStack` + (b) ``LineGraphic``, ``LineCollection``, ``LineStack`` +--------------+--------------------------------+ | Feature Name | Description | @@ -130,7 +139,7 @@ allowing for the creation of very powerful visualizations. | thickness | thickness of the line(s) | +--------------+--------------------------------+ - (c) `ScatterGraphic` + (c) ``ScatterGraphic`` +--------------+---------------------------------------+ | Feature Name | Description | @@ -144,7 +153,7 @@ allowing for the creation of very powerful visualizations. | sizes | size of the scatter points | +--------------+---------------------------------------+ - (d) `TextGraphic` + (d) ``TextGraphic`` +-------------------+---------------------------+ | Feature Name | Description | @@ -160,27 +169,27 @@ allowing for the creation of very powerful visualizations. | outline_thickness | thickness of the text | +-------------------+---------------------------+ -Using our example from above: once we add a `Graphic` to the figure, we can then begin to change its properties. :: +Using our example from above: once we add a ``Graphic`` to the figure, we can then begin to change its properties. :: image_graphic.vmax = 150 -.. image:: _static/hello_world_vmax.png +.. image:: ./_static/hello_world_vmax.png -`Graphic` properties also support slicing and indexing. For example :: +``Graphic`` properties also support slicing and indexing. For example :: image_graphic.data[::8, :, :] = 1 image_graphic.data[:, ::8, :] = 1 -.. image:: _static/hello_world_data.png +.. image:: ./_static/hello_world_data.png Selectors --------- -A primary feature of `fastplotlib` is the ability to easily interact with your data. Two extremely helpful tools that can -be used in order to facilitate this process are a `LinearSelector` and `LinearRegionSelector`. +A primary feature of ``fastplotlib`` is the ability to easily interact with your data. Two extremely helpful tools that can +be used in order to facilitate this process are a ``LinearSelector`` and ``LinearRegionSelector``. -A `LinearSelector` is a horizontal or vertical line slider. This tool allows you to very easily select different points in your +A ``LinearSelector`` is a horizontal or vertical line slider. This tool allows you to very easily select different points in your data. Let's look at an example: :: import fastplotlib as fpl @@ -205,21 +214,21 @@ data. Let's look at an example: :: .. image:: _static/guide_linear_selector.gif -A `LinearRegionSelector` is very similar to a `LinearSelector` but as opposed to selecting a singular point of +A ``LinearRegionSelector`` is very similar to a ``LinearSelector`` but as opposed to selecting a singular point of your data, you are able to select an entire region. -Now we have the basics of creating a `Figure`, adding `Graphics` to a `Figure`, and working with `Graphic` properties to dynamically change or alter them. -Let's take a look at how we can define events to link `Graphics` and their properties together. +Now we have the basics of creating a ``Figure``, adding ``Graphics`` to a ``Figure``, and working with ``Graphic`` properties to dynamically change or alter them. +Let's take a look at how we can define events to link ``Graphics`` and their properties together. Events ------ Events can be a multitude of things: traditional events such as mouse or keyboard events, but they can also be -You can use renderer events, such as mouse or keyboard events, or events related to `Graphic` properties. +You can use renderer events, such as mouse or keyboard events, or events related to ``Graphic`` properties. -There are two ways to add events in `fastplotlib`. +There are two ways to add events in ``fastplotlib``. 1) Use the method :: @@ -239,15 +248,11 @@ There are two ways to add events in `fastplotlib`. .. -.. note:: - You can also add events to a `Figure` object's renderer. This is useful for defining click events where - you want to map your click position to the nearest graphic object for example. - -The `event_handler` is a user-defined function that accepts an event instance as the first and only positional argument. +The ``event_handler`` is a user-defined function that accepts an event instance as the first and only positional argument. Information about the structure of event instances are described below. The `"event_type"` -is a string that identifies the type of event; this can be either a `pygfx.Event` or a `Graphic` property event. -See the above graphic-specific properties that can be used for events and below for the available `pygfx` events. +is a string that identifies the type of event; this can be either a ``pygfx.Event`` or a ``Graphic`` property event. +See the above graphic-specific properties that can be used for events and below for the available ``pygfx`` events. Rendering engine (``pygfx``) events: - "key_down" @@ -283,7 +288,7 @@ event object will have relevant information that can be used in the callback. Se | time_stamp | float | time when the event occurred, in ms | +------------+-------------+-----------------------------------------------+ -The ``info`` attribute will house additional information for different `Graphic` property events: +The ``info`` attribute will house additional information for different ``Graphic`` property events: event_type: "colors" @@ -357,7 +362,7 @@ event_type: "cmap" event_type: "selection" - LinearSelector + ``LinearSelector`` **additional event attributes:** @@ -375,7 +380,7 @@ event_type: "selection" | value | np.ndarray | new x or y value of selection | +----------+------------+-------------------------------+ - LinearRegionSelector + ``LinearRegionSelector`` **additional event attributes:** @@ -395,11 +400,61 @@ event_type: "selection" | value | np.ndarray | new [min, max] of selection | +----------+------------+-----------------------------+ -`ImageWidget` -------------- +**Renderer Events:** + +You can also add events to a ``Figure`` object's renderer. This is useful for defining click events where +you want to map your click position to the nearest graphic object for example. + +Renderer events can be added using either method mentioned above (i.e. using the method or via a decorator). + +For example: :: + + import fastplotlib as fpl + import numpy as np + + # generate some circles + 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) + ys = radius * np.cos(theta) + + return np.column_stack([xs, ys]) + center + + # this makes 5 circles, so we can create 5 cmap values, so it will use these values to set the + # color of the line based by using the cmap as a LUT with the corresponding cmap_value + circles = list() + for x in range(0, 50, 10): + circles.append(make_circle(center=(x, 0), radius=4, n_points=100)) + + # create figure + fig = fpl.Figure() + + # add circles to plot + circles_graphic = fig[0,0].add_line_collection(data=circles, cmap="tab10", thickness=10) + + # get the nearest graphic that is clicked and change the color + @fig.renderer.add_event_handler("click") + def click_event(ev): + # reset colors + circles_graphic.cmap = "tab10" + + # map the click position to world coordinates + xy = fig[0, 0].map_screen_to_world(ev)[:-1] + + # get the nearest graphic to the position + nearest = fpl.utils.get_nearest_graphics(xy, circles_graphic)[0] + + # change the closest graphic color to white + nearest.colors = "w" + + fig.show() +.. image:: ./_static/click_event.gif + +ImageWidget +----------- Often times, developing UIs for interacting with multi-dimension image data can be tedious and repetitive. -In order to aid with common image and video visualization requirements the `ImageWidget` automatically generates sliders +In order to aid with common image and video visualization requirements the ``ImageWidget`` automatically generates sliders to easily navigate through different dimensions of your data. Let's look at an example: :: import fastplotlib as fpl @@ -443,55 +498,63 @@ An animation function is a user-defined function that gets called on every rende .. image:: _static/guide_animation.gif -Here we are defining a function that updates the data of the `ImageGraphic` in the plot with new random data. When adding an animation function, the +Here we are defining a function that updates the data of the ``ImageGraphic`` in the plot with new random data. When adding an animation function, the user-defined function will receive a plot instance as an argument when it is called. Spaces ------ -There are several spaces to consider when using `fastplotlib`: +There are several spaces to consider when using ``fastplotlib``: 1) World Space World space is the 3D space in which graphical objects live. Objects - and the camera can exist anywhere in this space. Objects in this space exist relative to a larger - world. + and the camera can exist anywhere in this space. 2) Data Space Data space is simply the world space plus any offset or rotation that has been applied to an object. +.. note:: + World space does not always correspond directly to data space, you may have to adjust for any offset or rotation of the ``Graphic``. + 3) Screen Space Screen space is the 2D space in which your screen pixels reside. This space is constrained by the screen width and height in pixels. In the rendering process, the camera is responsible for projecting the world space into screen space. .. note:: - When interacting with `Graphic` objects, there is a very helpful function for mapping screen space to world space - (`Figure.map_screen_to_world(pos=(x, y))`). This can be particularly useful when working with click events where click - positions are returned in screen space but `Graphic` objects that you may want to interact with exist in world + When interacting with ``Graphic`` objects, there is a very helpful function for mapping screen space to world space + (``Figure.map_screen_to_world(pos=(x, y))``). This can be particularly useful when working with click events where click + positions are returned in screen space but ``Graphic`` objects that you may want to interact with exist in world space. +For more information on the various spaces used by rendering engines please see this `article `_ -Using `fastplotlib` interactively ---------------------------------- -There are multiple ways to use `fastplotlib` interactively. +Using ``fastplotlib`` interactively +----------------------------------- -On `jupyter lab` or `jupyter notebook` the jupyter backend (i.e. `jupyter_rfb`) is normally selected. This works via +There are multiple ways to use ``fastplotlib`` interactively. + +1) Jupyter + +On ``jupyter lab`` the jupyter backend (i.e. ``jupyter_rfb``) is normally selected. This works via client-server rendering. Images generated on the server are streamed to the client (Jupyter) via a jpeg byte stream. Events (such as mouse or keyboard events) are then streamed in the opposite direction prompting new images to be generated -by the server if necessary. This remote-frame-buffer approach makes the rendering process very fast. `fastplotlib` viusalizations -can be displayed in cell output or on the side using `jupyterlab-sidecar`. +by the server if necessary. This remote-frame-buffer approach makes the rendering process very fast. ``fastplotlib`` viusalizations +can be displayed in cell output or on the side using ``sidecar``. -However, a Qt backend can optionally be used as well. If `%gui qt` is selected before importing `fastplotlib` then this backend +A Qt backend can also optionally be used as well. If ``%gui qt`` is selected before importing ``fastplotlib`` then this backend will be used instead. -Users can also force using `glfw` by specifying this as an argument when instantiating a `Figure` (i.e. `Figure(canvas="gflw"`). + +Lastly, users can also force using ``glfw`` by specifying this as an argument when instantiating a ``Figure`` (i.e. ``Figure(canvas="gflw"``). .. note:: Do not mix between gui backends. For example, if you start the notebook using Qt, do not attempt to force using another backend such - as `jupyter_rfb` later. + as ``jupyter_rfb`` later. +2) IPython -Furthermore, in `IPython`, users can select between using a Qt backend or gflw the same as above. +Users can select between using a Qt backend or gflw using the same methods as above. 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