diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index bec47fdc5..cebee50a0 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -1,4 +1,4 @@ -name: Lint +name: black on: push: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23bfc8ae7..ad199d28f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,39 +14,6 @@ on: - ready_for_review jobs: - docs-build: - name: Docs - runs-on: ubuntu-latest - timeout-minutes: 10 - if: ${{ !github.event.pull_request.draft }} - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v3 - - name: Set up Python 3.11 - uses: actions/setup-python@v4 - with: - python-version: 3.11 - - name: Install llvmpipe and lavapipe for offscreen canvas, and git lfs - run: | - sudo apt-get update -y -qq - sudo apt-get install --no-install-recommends -y libegl1-mesa libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers git-lfs - - name: Install pandoc v3.14, nbsphinx complains about older pandoc versions - run: | - wget https://github.com/jgm/pandoc/releases/download/3.1.4/pandoc-3.1.4-1-amd64.deb - sudo apt-get install ./pandoc-3.1.4-1-amd64.deb - - name: Install dev dependencies - run: | - python -m pip install --upgrade pip setuptools - # remove pygfx from install_requires, we install using pygfx@main - sed -i "/pygfx/d" ./setup.py - pip install git+https://github.com/pygfx/pygfx.git@main - pip install -e ".[notebook,docs,tests]" - - name: Build docs - run: | - cd docs - make html SPHINXOPTS="-W --keep-going" - test-build-full: name: Test Linux, notebook + offscreen runs-on: ubuntu-latest @@ -101,7 +68,7 @@ jobs: with: name: screenshot-diffs path: | - examples/desktop/diffs + examples/diffs examples/notebooks/diffs test-build-desktop: @@ -157,7 +124,7 @@ jobs: with: name: screenshot-diffs path: | - examples/desktop/diffs + examples/diffs # test-build-full-mac: # name: Test Mac, notebook + glfw diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml new file mode 100644 index 000000000..b13c60849 --- /dev/null +++ b/.github/workflows/docs-deploy.yml @@ -0,0 +1,104 @@ +name: Deploy docs + +on: + push: + branches: + - main + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + - ready_for_review + release: + types: [published] + +jobs: + build-docs: + name: "Build and deploy docs" + runs-on: ubuntu-latest + if: ${{ !github.event.pull_request.draft }} + permissions: + pull-requests: write + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v4 + with: + lfs: true + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.12 + - name: Install llvmpipe and lavapipe for offscreen canvas + run: | + sudo apt-get update -y -qq + sudo apt-get install --no-install-recommends -y ffmpeg libegl1-mesa libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers git-lfs + - name: Install dev dependencies + run: | + python -m pip install --upgrade pip setuptools + # remove pygfx from install_requires, we install using pygfx@main + sed -i "/pygfx/d" ./setup.py + pip install git+https://github.com/pygfx/pygfx.git@main + pip install -e ".["docs"]" + - name: Show wgpu backend + run: + python -c "from examples.tests.testutils import wgpu_backend; print(wgpu_backend)" + - name: build docs + run: | + cd docs + RTD_BUILD=1 make html SPHINXOPTS="-W --keep-going" + + # set environment variable `DOCS_VERSION_DIR` to either the pr-branch name, "dev", or the release version tag + - name: set output pr + if: ${{ github.ref != 'refs/heads/main' }} + # sets dir to the branch name when it's a PR + # ex: fastplotlib.org/ver/feature-branch + run: echo "DOCS_VERSION_DIR=$GITHUB_HEAD_REF" >> "$GITHUB_ENV" + + - name: set output release + if: ${{ github.ref_type == 'tag' }} + # sets dir to the release version tag, ex. v0.3.0 (I think...) + # ex: fastplotlib.org/ver/v0.3.0 + run: echo "DOCS_VERSION_DIR=$GITHUB_REF_NAME" >> "$GITHUB_ENV" + + - name: set output dev + if: ${{ github.ref == 'refs/heads/main' }} + # any push to main goes to fastplotlib.org/ver/dev + run: echo "DOCS_VERSION_DIR=dev" >> "$GITHUB_ENV" + + # upload docs via FTP + - name: Deploy docs + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 + with: + server: ${{ secrets.DOCS_SERVER }} + username: ${{ secrets.DOCS_USERNAME }} + password: ${{ secrets.DOCS_PASSWORD }} + # built docs + local-dir: docs/build/html/ + # output subdir based on the previous if statements + server-dir: ./ver/${{ env.DOCS_VERSION_DIR }}/ + + # comment on PR to provide link to built docs + - name: Add PR link in comment + if: ${{ github.event_name == 'pull_request' }} + uses: mshick/add-pr-comment@v2 + with: + message: | + 📚 Docs preview built and uploaded! https://www.fastplotlib.org/ver/${{ env.DOCS_VERSION_DIR }} + + # also deploy to root if this is a new release + # i.e., fastplotlib.org/ points to docs for the latest release + - name: Deploy docs + if: ${{ github.ref_type == 'tag' }} + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 + with: + server: ${{ secrets.DOCS_SERVER }} + username: ${{ secrets.DOCS_USERNAME }} + password: ${{ secrets.DOCS_PASSWORD }} + local-dir: docs/build/html/ + server-dir: ./ # deploy to the root dir + exclude: | # don't delete the /ver/ dir + **/ver/** diff --git a/.github/workflows/screenshots.yml b/.github/workflows/screenshots.yml index 0686b4445..25a3cf517 100644 --- a/.github/workflows/screenshots.yml +++ b/.github/workflows/screenshots.yml @@ -55,5 +55,5 @@ jobs: with: name: screenshots path: | - examples/desktop/screenshots/ + examples/screenshots/ examples/notebooks/screenshots/ diff --git a/README.md b/README.md index 2a5e33b9c..23aec8ac9 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@ --- -[![CI](https://github.com/kushalkolar/fastplotlib/actions/workflows/ci.yml/badge.svg)](https://github.com/kushalkolar/fastplotlib/actions/workflows/ci.yml) +[![CI](https://github.com/fastplotlib/fastplotlib/actions/workflows/ci.yml/badge.svg)](https://github.com/fastplotlib/fastplotlib/actions/workflows/ci.yml) [![PyPI version](https://badge.fury.io/py/fastplotlib.svg)](https://badge.fury.io/py/fastplotlib) [![Documentation Status](https://readthedocs.org/projects/fastplotlib/badge/?version=latest)](https://fastplotlib.readthedocs.io/en/latest/?badge=latest) [![DOI](https://zenodo.org/badge/485481453.svg)](https://zenodo.org/doi/10.5281/zenodo.13365890) -[**Installation**](https://github.com/kushalkolar/fastplotlib#installation) | +[**Installation**](https://github.com/fastplotlib/fastplotlib#installation) | [**GPU Drivers**](https://github.com/kushalkolar/fastplotlib#graphics-drivers) | [**Documentation**](https://github.com/fastplotlib/fastplotlib#documentation) | [**Examples**](https://github.com/kushalkolar/fastplotlib#examples) | @@ -17,14 +17,9 @@ Next-gen plotting library built using the [`pygfx`](https://github.com/pygfx/pygfx) rendering engine that can utilize [Vulkan](https://en.wikipedia.org/wiki/Vulkan), [DX12](https://en.wikipedia.org/wiki/DirectX#DirectX_12), or [Metal](https://developer.apple.com/metal/) via WGPU, so it is very fast! `fastplotlib` is an expressive plotting library that enables rapid prototyping for large scale explorative scientific visualization. -![scipy-fpl](https://github.com/fastplotlib/fastplotlib/assets/9403332/b981a54c-05f9-443f-a8e4-52cd01cd802a) - -### SciPy 2023 Talk - -[![fpl_thumbnail](http://i3.ytimg.com/vi/Q-UJpAqljsU/hqdefault.jpg)](https://www.youtube.com/watch?v=Q-UJpAqljsU) - -Note that the API is currently evolving quickly. We recommend using the latest notebooks from the repo but the general -concepts are similar to those from the API shown in the video. +> **Note** +> +> `fastplotlib` is currently in the **late alpha stage**, but you're welcome to try it out or contribute! See our [Roadmap](https://github.com/kushalkolar/fastplotlib/issues/55). See this for a discussion on API stability: https://github.com/fastplotlib/fastplotlib/issues/121 # Supported frameworks @@ -36,43 +31,52 @@ concepts are similar to those from the API shown in the video. :heavy_check_mark: `wxPython` **Notes:**\ -:heavy_check_mark: Non-blocking Qt/PySide output is supported in ipython and notebooks by using [`%gui qt`](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-gui). This **must** be called *before* importing `fastplotlib`! +:heavy_check_mark: Non-blocking interactive Qt/PySide output is supported in ipython and notebooks, see http://fastplotlib.org/ver/dev/user_guide/guide.html#using-fastplotlib-in-an-interactive-shell \ :grey_exclamation: We do not officially support `jupyter notebook` through `jupyter_rfb`, this may change with notebook v7\ +:grey_exclamation: We only officially support jupyterlab for use in notebook. This means we do not support vscode notebooks etc. Jupyterlab is the most reliable way to use `fastplotlib` in notebooks.\ :disappointed: [`jupyter_rfb`](https://github.com/vispy/jupyter_rfb) does not work in collab, see https://github.com/vispy/jupyter_rfb/pull/77 -> **Note** -> -> `fastplotlib` is currently in the **late alpha stage**, but you're welcome to try it out or contribute! See our [Roadmap](https://github.com/kushalkolar/fastplotlib/issues/55). See this for a discussion on API stability: https://github.com/fastplotlib/fastplotlib/issues/121 +We recommend sticking to jupyter-lab for notebooks. From our experience the usage on other platforms, such as vscode +notebooks, is not optimal. -# Documentation -http://fastplotlib.readthedocs.io/ +# Documentation -The examples are interactive if you run them locally on your computer. If someone wants to integrate `pyodide` with `pygfx` we would be able to have live interactive examples on the website! +http://www.fastplotlib.org/ Questions, issues, ideas? You are welcome to post an [issue](https://github.com/fastplotlib/fastplotlib/issues) or post on the [discussion forum](https://github.com/fastplotlib/fastplotlib/discussions)! :smiley: # Installation -### Minimal, use with your own `Qt` or `glfw` applications +To install use pip: + ```bash -pip install fastplotlib -``` +# with imgui and jupyterlab +pip install -U "fastplotlib[notebook,imgui]" -**This does not give you `PyQt`/`PySide` or `glfw`, you will have to install your preferred GUI framework separately**. +# minimal install, install glfw, pyqt6 or pyside6 separately +pip install -U fastplotlib -### Notebook -```bash -pip install "fastplotlib[notebook]" +# with imgui +pip install -U "fastplotlib[imgui]" + +# to use in jupyterlab, no imgui +pip install -U "fastplotlib[notebook]" ``` -**Strongly recommended: install `simplejpeg` for much faster notebook visualization, this requires you to first install [libjpeg-turbo](https://libjpeg-turbo.org/)** +We strongly recommend installing ``simplejpeg`` for use in notebooks, you must first install [libjpeg-turbo](https://libjpeg-turbo.org/) + +- If you use ``conda``, you can get ``libjpeg-turbo`` through conda. +- If you are on linux you can get it through your distro's package manager. +- For Windows and Mac compiled binaries are available on their release page: https://github.com/libjpeg-turbo/libjpeg-turbo/releases + +Once you have ``libjpeg-turbo``: ```bash pip install simplejpeg ``` -> **Note** +> **Note**[guide.rst](docs%2Fsource%2Fuser_guide%2Fguide.rst) > > `fastplotlib` and `pygfx` are fast evolving projects, the version available through pip might be outdated, you will need to follow the "For developers" instructions below if you want the latest features. You can find the release history here: https://github.com/fastplotlib/fastplotlib/releases @@ -95,42 +99,23 @@ Se [Contributing](https://github.com/fastplotlib/fastplotlib?tab=readme-ov-file# # Examples -Examples gallery: https://fastplotlib.readthedocs.io/en/latest/_gallery/index.html - -> **Note:** `fastplotlib` and `pygfx` are fast evolving, you will probably require the latest `pygfx` and `fastplotlib` from github to use the examples in the main branch. - -`fastplotlib` code is identical across notebook (`jupyter`), and desktop use with `Qt`/`PySide` or `glfw`. - -Even if you do not intend to use notebooks with `fastplotlib`, the `quickstart.ipynb` tutorial notebook is the best way to get familiar with the API: https://github.com/fastplotlib/fastplotlib/tree/main/examples/notebooks/quickstart.ipynb - -The specifics for running `fastplotlib` in different GUI frameworks are: -- Running in `glfw` requires a `fastplotlib.run()` call (which is really just a `wgpu` `run()` call) -- With `Qt` you can encapsulate it within a `QApplication`, see `examples/qt` -- Notebooks plots have ipywidget-based toolbars and widgets. There are plans to move toward an identical in-canvas toolbar with UI elements across all supported frameworks 😄 - -### Embedding in a `Qt` app - -See these for examples on embedding within a Qt app. Note that you can also use `fastplotlib` with qt interactively using `%gui qt` in jupyter or ipython. - -https://github.com/fastplotlib/fastplotlib/tree/main/examples/qt - -### Notebook examples +Examples gallery: http://fastplotlib.org/ver/dev/_gallery/index.html -Notebook examples are here, these include examples on selector tools. +User guide: http://fastplotlib.org/ver/dev/user_guide/guide.html -https://github.com/fastplotlib/fastplotlib/tree/main/examples/notebooks +`fastplotlib` code is identical across notebook (`jupyterlab`), and desktop use with `Qt`/`PySide` or `glfw`. -### Video +**Notebooks** -Our SciPy 2023 talk walks through numerous demos: https://github.com/fastplotlib/fastplotlib#scipy-talk +The `quickstart.ipynb` tutorial notebook is a great way to get familiar with the API: https://github.com/fastplotlib/fastplotlib/tree/main/examples/notebooks/quickstart.ipynb ## Graphics drivers -You will need a relatively modern GPU (newer integrated GPUs in CPUs are usually fine). Generally if your GPU is from 2017 or later it should be fine. +You will need a relatively modern GPU, modern integrated graphics are usually fine for many use cases. Generally if your GPU is from 2017 or later it should be fine. For more detailed information, such as use on cloud computing infrastructure, see: https://wgpu-py.readthedocs.io/en/stable/start.html#platform-requirements -Some more information on GPUs is here: https://fastplotlib.readthedocs.io/en/latest/user_guide/gpu.html +Some more information on GPUs is here: http://fastplotlib.org/ver/dev/user_guide/gpu.html ### Windows: Vulkan drivers should be installed by default on Windows 11, but you will need to install your GPU manufacturer's driver package (Nvidia or AMD). If you have an integrated GPU within your CPU, you might still need to install a driver package too, check your CPU manufacturer's info. @@ -161,6 +146,6 @@ WGPU uses Metal instead of Vulkan on Mac. You will need at least Mac OSX 10.13. # :heart: Contributing -We welcome contributions! See the contributing guide: https://github.com/kushalkolar/fastplotlib/blob/main/CONTRIBUTING.md +We welcome contributions! See the contributing guide: https://github.com/fastplotlib/fastplotlib/blob/main/CONTRIBUTING.md -You can also take a look at our [**Roadmap for 2025**](https://github.com/kushalkolar/fastplotlib/issues/55) and [**Issues**](https://github.com/kushalkolar/fastplotlib/issues) for ideas on how to contribute! +You can also take a look at our [**Roadmap for 2025**](https://github.com/fastplotlib/fastplotlib/issues/55) and [**Issues**](https://github.com/fastplotlib/fastplotlib/issues) for ideas on how to contribute! diff --git a/docs/source/_static/switcher.json b/docs/source/_static/switcher.json new file mode 100644 index 000000000..67f723e2f --- /dev/null +++ b/docs/source/_static/switcher.json @@ -0,0 +1,7 @@ +[ + { + "name": "dev/main", + "version": "dev", + "url": "http://www.fastplotlib.org/versions/dev" + } +] diff --git a/docs/source/_templates/autosummary/class.rst b/docs/source/_templates/autosummary/class.rst index d4fd5208b..3693c0102 100644 --- a/docs/source/_templates/autosummary/class.rst +++ b/docs/source/_templates/autosummary/class.rst @@ -3,3 +3,6 @@ .. currentmodule:: {{ module }} .. autoclass:: {{ objname }} + +.. minigallery:: fastplotlib.{{ objname }} + :add-heading: Examples diff --git a/docs/source/_templates/autosummary/method.rst b/docs/source/_templates/autosummary/method.rst index 306d2aab5..39daedd4b 100644 --- a/docs/source/_templates/autosummary/method.rst +++ b/docs/source/_templates/autosummary/method.rst @@ -3,3 +3,6 @@ .. currentmodule:: {{ module }} .. automethod:: {{ objname }} + +.. minigallery:: fastplotlib.{{ objname }} + :add-heading: Examples diff --git a/docs/source/_templates/autosummary/property.rst b/docs/source/_templates/autosummary/property.rst index c31bebe07..509e46b8a 100644 --- a/docs/source/_templates/autosummary/property.rst +++ b/docs/source/_templates/autosummary/property.rst @@ -3,3 +3,6 @@ .. currentmodule:: {{ module }} .. autoproperty:: {{ objname }} + +.. minigallery:: fastplotlib.{{ objname }} + :add-heading: Examples diff --git a/docs/source/api/index.rst b/docs/source/api/index.rst new file mode 100644 index 000000000..87c134782 --- /dev/null +++ b/docs/source/api/index.rst @@ -0,0 +1,15 @@ +API Reference +************* + +.. toctree:: + :caption: API Reference + :maxdepth: 2 + + layouts/index + graphics/index + graphic_features/index + selectors/index + ui/index + widgets/index + fastplotlib + utils diff --git a/docs/source/api/layouts/index.rst b/docs/source/api/layouts/index.rst new file mode 100644 index 000000000..51265fbf0 --- /dev/null +++ b/docs/source/api/layouts/index.rst @@ -0,0 +1,9 @@ +Layouts +******** + +.. toctree:: + :maxdepth: 1 + + imgui_figure + figure + subplot diff --git a/docs/source/conf.py b/docs/source/conf.py index 913cfd50f..36d965b83 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -21,7 +21,7 @@ pygfx.renderers.wgpu.set_wgpu_limits(**{"max-texture-dimension2d": MAX_TEXTURE_SIZE}) ROOT_DIR = Path(__file__).parents[1].parents[0] # repo root -EXAMPLES_DIR = Path.joinpath(ROOT_DIR, "examples", "desktop") +EXAMPLES_DIR = Path.joinpath(ROOT_DIR, "examples") sys.path.insert(0, str(ROOT_DIR)) @@ -55,16 +55,17 @@ "remove_config_comments": True, "subsection_order": ExplicitOrder( [ - "../../examples/desktop/image", - "../../examples/desktop/image_widget", - "../../examples/desktop/gridplot", - "../../examples/desktop/line", - "../../examples/desktop/line_collection", - "../../examples/desktop/scatter", - "../../examples/desktop/heatmap", - "../../examples/desktop/misc", - "../../examples/desktop/selectors", - "../../examples/desktop/guis" + "../../examples/image", + "../../examples/image_widget", + "../../examples/gridplot", + "../../examples/line", + "../../examples/line_collection", + "../../examples/scatter", + "../../examples/heatmap", + "../../examples/misc", + "../../examples/selection_tools", + "../../examples/guis", + "../../examples/qt", ] ), "ignore_pattern": r'__init__\.py', @@ -91,7 +92,17 @@ # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output -html_theme = "furo" +html_theme = "pydata_sphinx_theme" + +html_theme_options = { + "navbar_end": ["theme-switcher", "version-switcher", "navbar-icon-links"], + "show_version_warning_banner": True, + "check_switcher": True, + "switcher": { + "json_url": "http://www.fastplotlib.org/_static/switcher.json", + "version_match": release + } +} html_static_path = ["_static"] html_logo = "_static/logo.png" @@ -106,14 +117,8 @@ intersphinx_mapping = { "python": ("https://docs.python.org/3", None), - "numpy": ("https://numpy.org/doc/stable/", None), - "pygfx": ("https://docs.pygfx.org/stable/", None), + "numpy": ("https://numpy.org/doc/stable", None), + "pygfx": ("https://docs.pygfx.org/stable", None), "wgpu": ("https://wgpu-py.readthedocs.io/en/latest", None), - "fastplotlib": ("https://fastplotlib.readthedocs.io/en/latest/", None), -} - -html_theme_options = { - "source_repository": "https://github.com/fastplotlib/fastplotlib", - "source_branch": "main", - "source_directory": "docs/", + # "fastplotlib": ("https://www.fastplotlib.org/", None), } diff --git a/docs/source/generate_api.py b/docs/source/generate_api.py index dbe1d8005..488b28466 100644 --- a/docs/source/generate_api.py +++ b/docs/source/generate_api.py @@ -36,6 +36,35 @@ os.makedirs(source_dir, exist_ok=True) +# this way we can just add the entire api dir to gitignore and generate before pushing +with open(API_DIR.joinpath("fastplotlib.rst"), "w") as f: + f.write( + "fastplotlib\n" + "***********\n\n" + ".. currentmodule:: fastplotlib\n\n" + + ".. autofunction:: fastplotlib.pause_events\n\n" + + ".. autofunction:: fastplotlib.enumerate_adapters\n\n" + + ".. autofunction:: fastplotlib.select_adapter\n\n" + + ".. autofunction:: fastplotlib.print_wgpu_report\n\n" + + ".. autofunction:: fastplotlib.run\n" + ) + +with open(API_DIR.joinpath("utils.rst"), "w") as f: + f.write( + "fastplotlib.utils\n" + "*****************\n\n" + + "..currentmodule:: fastplotlib.utils\n" + "..automodule:: fastplotlib.utils.functions\n" + " : members:\n" + ) + + def get_public_members(cls) -> Tuple[List[str], List[str]]: """ Returns (public_methods, public_properties) @@ -165,6 +194,20 @@ def main(): source_path=LAYOUTS_DIR.joinpath("subplot.rst"), ) + # layouts classes index file + with open(LAYOUTS_DIR.joinpath("index.rst"), "w") as f: + f.write( + f"Layouts\n" + f"********\n" + f"\n" + f".. toctree::\n" + f" :maxdepth: 1\n" + f"\n" + f" imgui_figure\n" + f" figure\n" + f" subplot\n" + ) + # the rest of this is a mess and can be refactored later graphic_classes = [getattr(graphics, g) for g in graphics.__all__] @@ -299,6 +342,23 @@ def main(): with open(API_DIR.joinpath("utils.rst"), "w") as f: f.write(utils_str) + # nake API index file + with open(API_DIR.joinpath("index.rst"), "w") as f: + f.write( + "API Reference\n" + "*************\n\n" + ".. toctree::\n" + " :caption: API Reference\n" + " :maxdepth: 2\n\n" + " layouts/index\n" + " graphics/index\n" + " graphic_features/index\n" + " selectors/index\n" + " ui/index\n" + " widgets/index\n" + " fastplotlib\n" + " utils\n" + ) if __name__ == "__main__": main() diff --git a/docs/source/index.rst b/docs/source/index.rst index 4caa7fc7e..2794bc17e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,52 +2,39 @@ Welcome to fastplotlib's documentation! ======================================= .. toctree:: - :caption: User Guide - :maxdepth: 1 + :caption: Getting started + :maxdepth: 2 - Guide - GPU Info - FAQ + user_guide/index .. toctree:: - :maxdepth: 1 + :maxdepth: 2 :caption: API - fastplotlib - Figure - ImguiFigure - Subplot - Graphics - Graphic Features - Selectors - UI - Widgets - Utils + api/index .. toctree:: :caption: Gallery - :maxdepth: 1 + :maxdepth: 1 - Gallery <_gallery/index> + _gallery/index Summary ======= -Next-gen plotting library built using the `pygfx `_ render engine utilizing `Vulkan `_, `DX12 `_, or `Metal `_ via `WGPU `_, so it is very fast! ``fastplotlib`` is an expressive plotting library that enables rapid prototyping for large scale exploratory scientific visualization. ``fastplotlib`` will run on any framework that ``pygfx`` runs on, this includes ``glfw``, ``Qt`` and ``jupyter lab`` - -Installation -============ - -For installation please see the instructions on GitHub: - -https://github.com/kushalkolar/fastplotlib#installation +Next-gen plotting library built using the `pygfx `_ render engine utilizing +`Vulkan `_, `DX12 `_, or +`Metal `_ via `WGPU `_, so it is very fast! +``fastplotlib`` is an expressive plotting library that enables rapid prototyping for large scale exploratory scientific +visualization. ``fastplotlib`` will run on any framework that ``pygfx`` runs on, this includes ``glfw``, ``Qt`` +and ``jupyter lab`` Contributing ============ -Contributions are welcome! See the contributing guide on GitHub: https://github.com/kushalkolar/fastplotlib/blob/master/CONTRIBUTING.md. +Contributions are welcome! See the `contributing guide on GitHub `_ -Also take a look at the `Roadmap 2025 `_ for future plans or ways in which you could contribute. +Also take a look at the `Roadmap 2025 `_ for future plans or ways in which you could contribute. Indices and tables ================== diff --git a/docs/source/user_guide/faq.rst b/docs/source/user_guide/faq.rst index ebf17fcd6..ffa140ac2 100644 --- a/docs/source/user_guide/faq.rst +++ b/docs/source/user_guide/faq.rst @@ -1,15 +1,15 @@ -fastplotlib FAQ -=============== +FAQ +=== -What is `fastplotlib`? ----------------------- +What is ``fastplotlib``? +------------------------ `fastplotlib` is a scientific plotting library built on top of the `pygfx `_ rendering engine that leverages new graphics APIs and modern GPU hardware to create fast and interactive visualizations. -What can I do with `fastplotlib`? ---------------------------------- +What can I do with ``fastplotlib``? +----------------------------------- `fastplotlib` allows for: - GPU accelerated visualization @@ -28,8 +28,8 @@ Do I need a GPU? Limited software rendering using just the CPU is supported on linux using lavapipe, but this is mostly only useful for testing purposes. -How does `fastplotlib` relate to `matplotlib`? ----------------------------------------------- +How does ``fastplotlib`` relate to ``matplotlib``? +-------------------------------------------------- `fastplotlib` is **not** related to `matplotlib` in any way. @@ -41,8 +41,8 @@ How does `fastplotlib` relate to `matplotlib`? why `fastplotlib` can have an array-like API for plotting. We believe that these design choices make it much easier to learn how to use the library and provide fine-grained control over your visualizations. See the "How can I learn to use `fastplotlib`?" section below. -How can I learn to use `fastplotlib`? -------------------------------------- +How can I learn to use ``fastplotlib``? +--------------------------------------- We want `fastplotlib` to be easy to learn and use. To get started with the library we recommend taking a look at our `guide `_ and `examples gallery `_. @@ -50,14 +50,14 @@ How can I learn to use `fastplotlib`? In general, if you are familiar with numpy and array notation you will already have a intuitive understanding of interacting with your data in `fastplotlib`. If you have any questions, please do not hesitate to post an issue or discussion forum post. -Should I use `fastplotlib` for making publication figures? ----------------------------------------------------------- +Should I use ``fastplotlib`` for making publication figures? +------------------------------------------------------------ While `fastplotlib` figures can be exported to PNG using ``figure.export()``, `fastplotlib` is not intended for creating *static* publication figures. There are many other libraries that are well-suited for this task. -How does `fastplotlib` handle data loading? -------------------------------------------- +How does ``fastplotlib`` handle data loading? +--------------------------------------------- `fastplotlib` is a plotting library and not a data handling or data loading library. These tasks are outside of the scope of the library. @@ -65,8 +65,8 @@ How does `fastplotlib` handle data loading? In general, if your data is an array-like object, `fastplotlib` should be able to use it. However, if you have any problems using your data objects, please do not hesitate to post an issue! See this `issue `_ for more details. -What is the scope of `fastplotlib`? ------------------------------------ +What is the scope of ``fastplotlib``? +------------------------------------- While the capabilities are very far-reaching, we would like to emphasize that `fastplotlib` is a general-purpose plotting library focused on scientific visualization. More specifically, we aim to develop the tools necessary for users to build fast and interactive visualizations for a variety of scientific domains including but not limited to @@ -86,8 +86,8 @@ What types of PRs are we willing to accept? Lastly, documentation is a critical part of open-source software and makes learning/using our tool much easier. We welcome all PRs that add missing or needed documentation of the codebase. If you find a piece of the codebase that is confusing or does not have proper documentation, please also feel free to post an issue on the repo! -What frameworks does `fastplotlib` support? -------------------------------------------- +What frameworks does ``fastplotlib`` support? +--------------------------------------------- The short answer is that `fastplotlib` can run on anything that `pygfx` runs on. This includes, - `jupyter lab` using `jupyter_rfb` @@ -98,8 +98,8 @@ What frameworks does `fastplotlib` support? Note: Use in Google Colab is not highly functional. We recommend using an inexpensive alternative cloud provider such as CodeOcean or Lambda Cloud. We have tested these and `fastplotlib` works very well. -How can I use `fastplotlib` interactively? ------------------------------------------- +How can I use ``fastplotlib`` interactively? +-------------------------------------------- There are multiple ways to use fastplotlib interactively. @@ -127,4 +127,4 @@ How can I use `fastplotlib` interactively? Why the parrot logo? -------------------- - The logo is a `swift parrot `_, they are the fastest species of parrot and they are colorful like fastplotlib visualizations :D \ No newline at end of file + The logo is a `swift parrot `_, they are the fastest species of parrot and they are colorful like fastplotlib visualizations :D diff --git a/docs/source/user_guide/gpu.rst b/docs/source/user_guide/gpu.rst index f4ef89a0c..00653133c 100644 --- a/docs/source/user_guide/gpu.rst +++ b/docs/source/user_guide/gpu.rst @@ -1,14 +1,14 @@ GPU Info and selection -********************** +====================== FAQ -=== +--- 1. Do I need a GPU? Technically no, you can perform limited software rendering on linux using lavapipe (see drivers link below). However ``fastplotlib`` is intentionally built for realtime rendering using the latest GPU technologies, so we strongly -recommend that you use a GPU. +recommend that you use a GPU. Note that modern integrated graphics is often sufficient for many use-cases. 2. My kernel keeps crashing. @@ -24,7 +24,7 @@ If you aren't able to solve it please post an issue on GitHub. :) - Probably driver issues (see next section). Drivers -======= +------- See the README: https://github.com/fastplotlib/fastplotlib?tab=readme-ov-file#graphics-drivers @@ -32,10 +32,10 @@ If you notice weird graphic artifacts, things not rendering, or other glitches t drivers. GPU Info -======== +-------- View available adapters ------------------------ +^^^^^^^^^^^^^^^^^^^^^^^ You can get a summary of all adapters that are available to ``WGPU`` like this:: @@ -71,7 +71,7 @@ General description of the fields: For more information on the fields see: https://gpuweb.github.io/gpuweb/#gpuadapterinfo Adapter currently in use ------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^ If you want to know the adapter that a figure is using you can check the adapter on the renderer:: @@ -85,7 +85,7 @@ If you want to know the adapter that a figure is using you can check the adapter Diagnostic info ---------------- +^^^^^^^^^^^^^^^ After creating a figure you can view WGPU diagnostic info like this:: @@ -259,7 +259,7 @@ Example output:: Select GPU (adapter) -==================== +-------------------- You can select an adapter by passing one of the ``wgpu.GPUAdapter`` instances returned by ``fpl.enumerate_adapters()`` to ``fpl.select_adapter()``:: diff --git a/docs/source/user_guide/guide.rst b/docs/source/user_guide/guide.rst index 4c482e03a..0496054a7 100644 --- a/docs/source/user_guide/guide.rst +++ b/docs/source/user_guide/guide.rst @@ -1,5 +1,5 @@ -The `fastplotlib` guide -======================= +User Guide +========== Installation ------------ @@ -8,14 +8,29 @@ To install use pip: .. code-block:: + # with imgui and jupyterlab + pip install -U "fastplotlib[notebook,imgui]" + + # minimal install, install glfw, pyqt6 or pyside6 separately pip install -U fastplotlib -or install the bleeding edge from Github: + # with imgui + pip install -U "fastplotlib[imgui]" -.. code-block:: + # to use in jupyterlab, no imgui + pip install -U "fastplotlib[notebook]" + +We strongly recommend installing ``simplejpeg`` for use in notebooks, you must first install `libjpeg-turbo `_. - pip install git+https://github.com/fastplotlib/fastplotlib.git@main +- If you use ``conda``, you can get ``libjpeg-turbo`` through conda. +- If you are on linux you can get it through your distro's package manager. +- For Windows and Mac compiled binaries are available on their release page: https://github.com/libjpeg-turbo/libjpeg-turbo/releases +Once you have ``libjpeg-turbo``: + +.. code-block:: + + pip install simplejpeg What is ``fastplotlib``? ------------------------ @@ -56,7 +71,8 @@ This is just a simple example of how the ``fastplotlib`` API works to create a p 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** +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. @@ -68,7 +84,8 @@ indexing (i.e. ``fig_object[i ,j]``). After defining a ``Figure``, we can begin to add ``Graphic`` objects. -**Graphics** +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:: @@ -90,6 +107,8 @@ to be easily accessed from figures:: .. +See the examples gallery for examples on how to create and interactive with all the various types of graphics. + 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. @@ -408,7 +427,8 @@ event_type: "selection" | value | np.ndarray | new [min, max] of selection | +----------+------------+-----------------------------+ -**Renderer Events:** +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. @@ -572,10 +592,10 @@ You can also make custom GUIs and embed them within the canvas, see the examples .. image:: ../_static/guide_imgui.png -Using ``fastplotlib`` interactively ------------------------------------ +Using ``fastplotlib`` in an interactive shell +--------------------------------------------- -There are multiple ways to use ``fastplotlib`` interactively. +There are multiple ways to use ``fastplotlib`` in interactive shells, such as ipython. 1) Jupyter @@ -597,4 +617,3 @@ Lastly, users can also force using ``glfw`` by specifying this as an argument wh 2) IPython Users can select between using a Qt backend or gflw using the same methods as above. - diff --git a/docs/source/user_guide/index.rst b/docs/source/user_guide/index.rst new file mode 100644 index 000000000..59189be22 --- /dev/null +++ b/docs/source/user_guide/index.rst @@ -0,0 +1,10 @@ +User Guide +********** + +.. toctree:: + :caption: User Guide + :maxdepth: 2 + + guide + gpu + faq diff --git a/examples/README.rst b/examples/README.rst index 138ec748b..fd8eb8da2 100644 --- a/examples/README.rst +++ b/examples/README.rst @@ -1,2 +1,2 @@ -Examples that use fastplotlib -============================= +Examples Gallery +**************** diff --git a/examples/desktop/data/iris.npy b/examples/data/iris.npy similarity index 100% rename from examples/desktop/data/iris.npy rename to examples/data/iris.npy diff --git a/examples/desktop/README.rst b/examples/desktop/README.rst deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/desktop/gridplot/README.rst b/examples/gridplot/README.rst similarity index 100% rename from examples/desktop/gridplot/README.rst rename to examples/gridplot/README.rst diff --git a/examples/desktop/gridplot/gridplot.py b/examples/gridplot/gridplot.py similarity index 100% rename from examples/desktop/gridplot/gridplot.py rename to examples/gridplot/gridplot.py diff --git a/examples/desktop/gridplot/gridplot_non_square.py b/examples/gridplot/gridplot_non_square.py similarity index 100% rename from examples/desktop/gridplot/gridplot_non_square.py rename to examples/gridplot/gridplot_non_square.py diff --git a/examples/desktop/gridplot/multigraphic_gridplot.py b/examples/gridplot/multigraphic_gridplot.py similarity index 100% rename from examples/desktop/gridplot/multigraphic_gridplot.py rename to examples/gridplot/multigraphic_gridplot.py diff --git a/examples/desktop/guis/README.rst b/examples/guis/README.rst similarity index 50% rename from examples/desktop/guis/README.rst rename to examples/guis/README.rst index 9cbf4d424..0271f959d 100644 --- a/examples/desktop/guis/README.rst +++ b/examples/guis/README.rst @@ -1,2 +1,2 @@ -ImGUI for within-canvas GUIs +ImGUI for within canvas GUIs ============================ diff --git a/examples/desktop/guis/image_widget_imgui.py b/examples/guis/image_widget_imgui.py similarity index 100% rename from examples/desktop/guis/image_widget_imgui.py rename to examples/guis/image_widget_imgui.py diff --git a/examples/desktop/guis/imgui_basic.py b/examples/guis/imgui_basic.py similarity index 100% rename from examples/desktop/guis/imgui_basic.py rename to examples/guis/imgui_basic.py diff --git a/examples/desktop/heatmap/README.rst b/examples/heatmap/README.rst similarity index 100% rename from examples/desktop/heatmap/README.rst rename to examples/heatmap/README.rst diff --git a/examples/desktop/heatmap/heatmap.py b/examples/heatmap/heatmap.py similarity index 100% rename from examples/desktop/heatmap/heatmap.py rename to examples/heatmap/heatmap.py diff --git a/examples/desktop/image/README.rst b/examples/image/README.rst similarity index 100% rename from examples/desktop/image/README.rst rename to examples/image/README.rst diff --git a/examples/desktop/image/image_cmap.py b/examples/image/image_cmap.py similarity index 100% rename from examples/desktop/image/image_cmap.py rename to examples/image/image_cmap.py diff --git a/examples/desktop/image/image_rgb.py b/examples/image/image_rgb.py similarity index 100% rename from examples/desktop/image/image_rgb.py rename to examples/image/image_rgb.py diff --git a/examples/desktop/image/image_rgbvminvmax.py b/examples/image/image_rgbvminvmax.py similarity index 100% rename from examples/desktop/image/image_rgbvminvmax.py rename to examples/image/image_rgbvminvmax.py diff --git a/examples/desktop/image/image_simple.py b/examples/image/image_simple.py similarity index 100% rename from examples/desktop/image/image_simple.py rename to examples/image/image_simple.py diff --git a/examples/desktop/image/image_small.py b/examples/image/image_small.py similarity index 100% rename from examples/desktop/image/image_small.py rename to examples/image/image_small.py diff --git a/examples/desktop/image/image_vminvmax.py b/examples/image/image_vminvmax.py similarity index 100% rename from examples/desktop/image/image_vminvmax.py rename to examples/image/image_vminvmax.py diff --git a/examples/desktop/image_widget/README.rst b/examples/image_widget/README.rst similarity index 100% rename from examples/desktop/image_widget/README.rst rename to examples/image_widget/README.rst diff --git a/examples/desktop/image_widget/image_widget.py b/examples/image_widget/image_widget.py similarity index 100% rename from examples/desktop/image_widget/image_widget.py rename to examples/image_widget/image_widget.py diff --git a/examples/desktop/image_widget/image_widget_grid.py b/examples/image_widget/image_widget_grid.py similarity index 100% rename from examples/desktop/image_widget/image_widget_grid.py rename to examples/image_widget/image_widget_grid.py diff --git a/examples/desktop/image_widget/image_widget_single_video.py b/examples/image_widget/image_widget_single_video.py similarity index 100% rename from examples/desktop/image_widget/image_widget_single_video.py rename to examples/image_widget/image_widget_single_video.py diff --git a/examples/desktop/image_widget/image_widget_videos.py b/examples/image_widget/image_widget_videos.py similarity index 100% rename from examples/desktop/image_widget/image_widget_videos.py rename to examples/image_widget/image_widget_videos.py diff --git a/examples/desktop/line/README.rst b/examples/line/README.rst similarity index 100% rename from examples/desktop/line/README.rst rename to examples/line/README.rst diff --git a/examples/desktop/line/line.py b/examples/line/line.py similarity index 100% rename from examples/desktop/line/line.py rename to examples/line/line.py diff --git a/examples/desktop/line/line_cmap.py b/examples/line/line_cmap.py similarity index 95% rename from examples/desktop/line/line_cmap.py rename to examples/line/line_cmap.py index b7dfe4424..81895e17b 100644 --- a/examples/desktop/line/line_cmap.py +++ b/examples/line/line_cmap.py @@ -2,7 +2,7 @@ Line Plot Colormap ================== -Example showing cosine, sine, sinc lines. +Example showing basic colormapping with lines """ # test_example = true diff --git a/examples/line/line_cmap_more.py b/examples/line/line_cmap_more.py new file mode 100644 index 000000000..c05f36797 --- /dev/null +++ b/examples/line/line_cmap_more.py @@ -0,0 +1,56 @@ +""" +Lines more colormapping +======================= + +Example showing more on colormapping with lines +""" + +# test_example = true +# sphinx_gallery_pygfx_docs = 'screenshot' + +import numpy as np +import fastplotlib as fpl + +xs = np.linspace(0, 10 * np.pi, 100) +# sine wave +ys = np.sin(xs) +sine = np.column_stack([xs, ys]) + +# cosine wave +ys = np.cos(xs) +cosine = np.column_stack([xs, ys]) + +figure = fpl.Figure(size=(700, 560)) + +# basic white line +line0 = figure[0, 0].add_line(sine, thickness=10) + +# set colormap along line datapoints, use an offset to place it above the previous line +line1 = figure[0, 0].add_line(sine, thickness=10, cmap="jet", offset=(0, 2, 0)) + +# set colormap by mapping data using a transform +# here we map the color using the y-values of the sine data +# i.e., the color is a function of sine(x) +line2 = figure[0, 0].add_line(sine, thickness=10, cmap="jet", cmap_transform=sine[:, 1], offset=(0, 4, 0)) + +# make a line and change the cmap afterward, here we are using the cosine instead fot the transform +line3 = figure[0, 0].add_line(sine, thickness=10, cmap="jet", cmap_transform=cosine[:, 1], offset=(0, 6, 0)) +# change the cmap +line3.cmap = "bwr" + +# use quantitative colormaps with categorical cmap_transforms +labels = [0] * 25 + [1] * 5 + [2] * 50 + [3] * 20 +line4 = figure[0, 0].add_line(sine, thickness=10, cmap="tab10", cmap_transform=labels, offset=(0, 8, 0)) + +# some text labels +for i in range(5): + figure[0, 0].add_text(f"line{i}", font_size=20, offset=(1, (i * 2) + 1.5, 0)) + +figure.show(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() diff --git a/examples/desktop/line/line_colorslice.py b/examples/line/line_colorslice.py similarity index 100% rename from examples/desktop/line/line_colorslice.py rename to examples/line/line_colorslice.py diff --git a/examples/desktop/line/line_dataslice.py b/examples/line/line_dataslice.py similarity index 100% rename from examples/desktop/line/line_dataslice.py rename to examples/line/line_dataslice.py diff --git a/examples/desktop/line_collection/README.rst b/examples/line_collection/README.rst similarity index 100% rename from examples/desktop/line_collection/README.rst rename to examples/line_collection/README.rst diff --git a/examples/desktop/line_collection/line_collection.py b/examples/line_collection/line_collection.py similarity index 100% rename from examples/desktop/line_collection/line_collection.py rename to examples/line_collection/line_collection.py diff --git a/examples/desktop/line_collection/line_collection_cmap_values.py b/examples/line_collection/line_collection_cmap_values.py similarity index 100% rename from examples/desktop/line_collection/line_collection_cmap_values.py rename to examples/line_collection/line_collection_cmap_values.py diff --git a/examples/desktop/line_collection/line_collection_cmap_values_qualitative.py b/examples/line_collection/line_collection_cmap_values_qualitative.py similarity index 100% rename from examples/desktop/line_collection/line_collection_cmap_values_qualitative.py rename to examples/line_collection/line_collection_cmap_values_qualitative.py diff --git a/examples/desktop/line_collection/line_collection_colors.py b/examples/line_collection/line_collection_colors.py similarity index 100% rename from examples/desktop/line_collection/line_collection_colors.py rename to examples/line_collection/line_collection_colors.py diff --git a/examples/desktop/line_collection/line_collection_slicing.py b/examples/line_collection/line_collection_slicing.py similarity index 100% rename from examples/desktop/line_collection/line_collection_slicing.py rename to examples/line_collection/line_collection_slicing.py diff --git a/examples/desktop/line_collection/line_stack.py b/examples/line_collection/line_stack.py similarity index 100% rename from examples/desktop/line_collection/line_stack.py rename to examples/line_collection/line_stack.py diff --git a/examples/desktop/line_collection/line_stack_3d.py b/examples/line_collection/line_stack_3d.py similarity index 100% rename from examples/desktop/line_collection/line_stack_3d.py rename to examples/line_collection/line_stack_3d.py diff --git a/examples/misc/garbage_collection.py b/examples/misc-dev/garbage_collection.py similarity index 100% rename from examples/misc/garbage_collection.py rename to examples/misc-dev/garbage_collection.py diff --git a/examples/misc/large_img.py b/examples/misc-dev/large_img.py similarity index 100% rename from examples/misc/large_img.py rename to examples/misc-dev/large_img.py diff --git a/examples/misc/selector_performance.ipynb b/examples/misc-dev/selector_performance.ipynb similarity index 100% rename from examples/misc/selector_performance.ipynb rename to examples/misc-dev/selector_performance.ipynb diff --git a/examples/desktop/misc/README.rst b/examples/misc/README.rst similarity index 100% rename from examples/desktop/misc/README.rst rename to examples/misc/README.rst diff --git a/examples/desktop/misc/cycle_animation.py b/examples/misc/cycle_animation.py similarity index 100% rename from examples/desktop/misc/cycle_animation.py rename to examples/misc/cycle_animation.py diff --git a/examples/desktop/misc/em_wave_animation.py b/examples/misc/em_wave_animation.py similarity index 100% rename from examples/desktop/misc/em_wave_animation.py rename to examples/misc/em_wave_animation.py diff --git a/examples/desktop/misc/image_animation.py b/examples/misc/image_animation.py similarity index 100% rename from examples/desktop/misc/image_animation.py rename to examples/misc/image_animation.py diff --git a/examples/desktop/misc/line3d_animation.py b/examples/misc/line3d_animation.py similarity index 100% rename from examples/desktop/misc/line3d_animation.py rename to examples/misc/line3d_animation.py diff --git a/examples/desktop/misc/line_animation.py b/examples/misc/line_animation.py similarity index 100% rename from examples/desktop/misc/line_animation.py rename to examples/misc/line_animation.py diff --git a/examples/desktop/misc/lorenz_animation.py b/examples/misc/lorenz_animation.py similarity index 100% rename from examples/desktop/misc/lorenz_animation.py rename to examples/misc/lorenz_animation.py diff --git a/examples/desktop/misc/multiplot_animation.py b/examples/misc/multiplot_animation.py similarity index 100% rename from examples/desktop/misc/multiplot_animation.py rename to examples/misc/multiplot_animation.py diff --git a/examples/desktop/misc/scatter_animation.py b/examples/misc/scatter_animation.py similarity index 100% rename from examples/desktop/misc/scatter_animation.py rename to examples/misc/scatter_animation.py diff --git a/examples/misc/scatter_sizes_animation.py b/examples/misc/scatter_sizes_animation.py new file mode 100644 index 000000000..aeb0466b0 --- /dev/null +++ b/examples/misc/scatter_sizes_animation.py @@ -0,0 +1,47 @@ +""" +Scatter sizes animation +======================= + +Animate scatter sizes +""" + +# test_example = false +# sphinx_gallery_pygfx_docs = 'animate 6s' + +import numpy as np +import fastplotlib as fpl + +xs = np.linspace(0, 10 * np.pi, 1_000) +# sine wave +ys = np.sin(xs) +data = np.column_stack([xs, ys]) + +sizes = np.abs(ys) * 5 + +figure = fpl.Figure(size=(700, 560)) + +figure[0, 0].add_scatter(data, sizes=sizes, name="sine") + + +i = 0 +def update_sizes(subplot): + global i + + xs = np.linspace(0.1 * i, (10 * np.pi) + (0.1 * i), 1_000) + sizes = np.abs(np.sin(xs)) * 5 + + subplot["sine"].sizes = sizes + + i += 1 + + +figure[0, 0].add_animations(update_sizes) + +figure.show(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() diff --git a/examples/desktop/misc/simple_event.py b/examples/misc/simple_event.py similarity index 100% rename from examples/desktop/misc/simple_event.py rename to examples/misc/simple_event.py diff --git a/examples/notebooks/heatmap.ipynb b/examples/notebooks/heatmap.ipynb deleted file mode 100644 index 08fd72501..000000000 --- a/examples/notebooks/heatmap.ipynb +++ /dev/null @@ -1,210 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "d8c90f4b-b635-4027-b7d5-080d77bd40a3", - "metadata": {}, - "source": [ - "# Looking at very large arrays" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "49b2498d-56ae-4559-9282-c8484f3e6b6d", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING: The name 'ylorbr' is an alias for 'colorbrewer:YlOrBr', but is also available as: 'tol:YlOrBr'.\n", - "To silence this warning, use a fully namespaced name.\n", - "WARNING: The name 'rdbu' is an alias for 'colorbrewer:RdBu', but is also available as: 'vispy:RdBu'.\n", - "To silence this warning, use a fully namespaced name.\n", - "WARNING: The name 'rainbow' is an alias for 'gnuplot:rainbow', but is also available as: 'yorick:rainbow'.\n", - "To silence this warning, use a fully namespaced name.\n", - "WARNING: The name 'ice' is an alias for 'cmocean:ice', but is also available as: 'imagej:ice, vispy:ice'.\n", - "To silence this warning, use a fully namespaced name.\n", - "WARNING: The name 'fire' is an alias for 'imagej:fire', but is also available as: 'vispy:fire'.\n", - "To silence this warning, use a fully namespaced name.\n", - "WARNING: The name 'prgn' is an alias for 'colorbrewer:PRGn', but is also available as: 'tol:PRGn'.\n", - "To silence this warning, use a fully namespaced name.\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "7e56de31fa0c41fa8ac48dc276c157b9", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Image(value=b'\\x89PNG\\r\\n\\x1a\\n\\x00\\x00\\x00\\rIHDR\\x00\\x00\\x01,\\x00\\x00\\x007\\x08\\x06\\x00\\x00\\x00\\xb6\\x1bw\\x99\\x…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WGPU: enumerate_adapters() is deprecated, use enumerate_adapters_sync() instead.\n", - "Unable to find extension: VK_EXT_swapchain_colorspace\n", - "WGPU: request_adapter() is deprecated, use request_adapter_sync() instead.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Available devices:\n", - "✅ (default) | AMD RADV POLARIS10 (ACO) | DiscreteGPU | Vulkan | Mesa 20.3.5 (ACO)\n", - "❗ | llvmpipe (LLVM 11.0.1, 256 bits) | CPU | Vulkan | Mesa 20.3.5 (LLVM 11.0.1)\n", - "✅ | NVIDIA GeForce RTX 3080 | DiscreteGPU | Vulkan | 530.30.02\n", - "❗ | Radeon RX 570 Series (POLARIS10, DRM 3.40.0, 5.10.0-21-amd64, LLVM 11.0.1) | Unknown | OpenGL | 4.6 (Core Profile) Mesa 20.3.5\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "import fastplotlib as fpl" - ] - }, - { - "cell_type": "markdown", - "id": "908f93f8-68c3-4a36-8f40-e0aab560955d", - "metadata": {}, - "source": [ - "## Generate some sine and cosine data" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "40718465-abf6-4727-8bd7-4acdd59843d5", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "xs = np.linspace(0, 1_000, 20_000)\n", - "\n", - "sine = np.sin(np.sqrt(xs))\n", - "\n", - "data = np.vstack([sine * i for i in range(10_000)])" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "02b072eb-2909-40c8-8739-950f07efbbc2", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(10000, 20000)" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data.shape" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "84deb31b-5464-4cce-a938-694371011021", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "956570245b55414e9b89bca0dc227535", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "RFBOutputContext()" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WGPU: request_device() is deprecated, use request_device_sync() instead.\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "ce013002bc6f4d1893c14a25bd3ae55b", - "version_major": 2, - "version_minor": 0 - }, - "text/html": [ - "
snapshot
" - ], - "text/plain": [ - "JupyterWgpuCanvas()" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fig = fpl.Figure()\n", - "\n", - "fig[0, 0].add_image(data, cmap=\"viridis\")\n", - "\n", - "fig.show(maintain_aspect=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "df3f8994-0f5b-4578-a36d-4cd9bf0733c0", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/notebooks/linear_region_selector.ipynb b/examples/notebooks/linear_region_selector.ipynb deleted file mode 100644 index 74b304a35..000000000 --- a/examples/notebooks/linear_region_selector.ipynb +++ /dev/null @@ -1,182 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "1db50ec4-8754-4421-9f5e-6ba8ca6b81e3", - "metadata": {}, - "source": [ - "# `LinearRegionSelector` with single lines" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b7bbfeb4-1ad0-47db-9a82-3d3f642a1f63", - "metadata": {}, - "outputs": [], - "source": [ - "import fastplotlib as fpl\n", - "import numpy as np\n", - "# from ipywidgets import IntRangeSlider, FloatRangeSlider, VBox\n", - "\n", - "fig = fpl.Figure((2, 2))\n", - "\n", - "# preallocated size for zoomed data\n", - "zoomed_prealloc = 1_000\n", - "\n", - "# data to plot\n", - "xs = np.linspace(0, 10* np.pi, 1_000)\n", - "sine = np.sin(xs)\n", - "sine += 100\n", - "\n", - "# make sine along x axis\n", - "sine_graphic_x = fig[0, 0].add_line(np.column_stack([xs, sine]), offset=(10, 0, 0))\n", - "\n", - "# just something that looks different for line along y-axis\n", - "sine_y = sine\n", - "sine_y[sine_y > 0] = 0\n", - "\n", - "# sine along y axis\n", - "sine_graphic_y = fig[0, 1].add_line(np.column_stack([sine_y, xs]))\n", - "\n", - "# offset the position of the graphic to demonstrate `get_selected_data()` later\n", - "sine_graphic_y.position_x = 50\n", - "sine_graphic_y.position_y = 50\n", - "\n", - "# add linear selectors\n", - "ls_x = sine_graphic_x.add_linear_region_selector() # default axis is \"x\"\n", - "ls_y = sine_graphic_y.add_linear_region_selector(axis=\"y\")\n", - "\n", - "# preallocate array for storing zoomed in data\n", - "zoomed_init = np.column_stack([np.arange(zoomed_prealloc), np.zeros(zoomed_prealloc)])\n", - "\n", - "# make line graphics for displaying zoomed data\n", - "zoomed_x = fig[1, 0].add_line(zoomed_init)\n", - "zoomed_y = fig[1, 1].add_line(zoomed_init)\n", - "\n", - "\n", - "def interpolate(subdata: np.ndarray, axis: int):\n", - " \"\"\"1D interpolation to display within the preallocated data array\"\"\"\n", - " x = np.arange(0, zoomed_prealloc)\n", - " xp = np.linspace(0, zoomed_prealloc, subdata.shape[0])\n", - " \n", - " # interpolate to preallocated size\n", - " return np.interp(x, xp, fp=subdata[:, axis]) # use the y-values\n", - "\n", - "@ls_x.add_event_handler(\"selection\")\n", - "def set_zoom_x(ev):\n", - " \"\"\"sets zoomed x selector data\"\"\"\n", - " # get the selected data\n", - " selected_data = ev.get_selected_data()\n", - " if selected_data.size == 0:\n", - " # no data selected\n", - " zoomed_x.data[:, 1] = 0\n", - "\n", - " # set the y-values\n", - " zoomed_x.data[:, 1] = interpolate(selected_data, axis=1)\n", - " fig[1, 0].auto_scale()\n", - "\n", - "\n", - "def set_zoom_y(ev):\n", - " \"\"\"sets zoomed x selector data\"\"\"\n", - " # get the selected data\n", - " selected_data = ev.get_selected_data()\n", - " if selected_data.size == 0:\n", - " # no data selected\n", - " zoomed_y.data[:, 0] = 0\n", - "\n", - " # set the x-values\n", - " zoomed_y.data[:, 0] = -interpolate(selected_data, axis=1)\n", - " fig[1, 1].auto_scale()\n", - "\n", - "\n", - "fig.show(maintain_aspect=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a9583d2e-ec52-405c-a875-f3fec5e3aa16", - "metadata": {}, - "outputs": [], - "source": [ - "# data to plot\n", - "xs = np.linspace(0, 100, 1_000)\n", - "sine = np.sin(xs) * 20\n", - "cosine = np.cos(xs) * 20\n", - "\n", - "fig_stack = fpl.Figure((5, 1))\n", - "\n", - "# sines and cosines\n", - "sines = [sine] * 2\n", - "cosines = [cosine] * 2\n", - "\n", - "# make line stack\n", - "line_stack = fig_stack[0, 0].add_line_stack(sines + cosines, separation=50)\n", - "\n", - "# make selector\n", - "selector = line_stack.add_linear_region_selector()\n", - "\n", - "# populate subplots with preallocated graphics\n", - "for i, subplot in enumerate(fig_stack):\n", - " if i == 0:\n", - " # skip the first one\n", - " continue\n", - " # make line graphics for displaying zoomed data\n", - " subplot.add_line(zoomed_init, name=\"zoomed\")\n", - "\n", - "\n", - "@selector.add_event_handler(\"selection\")\n", - "def update_zoomed_subplots(ev):\n", - " \"\"\"update the zoomed subplots\"\"\"\n", - " zoomed_data = ev.get_selected_data()\n", - " \n", - " for i in range(len(zoomed_data)):\n", - " # interpolate y-vals\n", - " data = interpolate(zoomed_data[i], axis=1)\n", - " fig_stack[i + 1, 0][\"zoomed\"].data[:, 1] = data\n", - " fig_stack[i + 1, 0].auto_scale()\n", - "\n", - "\n", - "fig_stack.show()" - ] - }, - { - "cell_type": "markdown", - "id": "0fa051b5-d6bc-4e4e-8f12-44f638a00c88", - "metadata": {}, - "source": [ - "# Large line stack with selector" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cbcd6309-fb47-4941-9fd1-2b091feb3ae7", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/notebooks/linear_selector.ipynb b/examples/notebooks/linear_selector.ipynb deleted file mode 100644 index bac8df182..000000000 --- a/examples/notebooks/linear_selector.ipynb +++ /dev/null @@ -1,150 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "a06e1fd9-47df-42a3-a76c-19e23d7b89fd", - "metadata": {}, - "source": [ - "## `LinearSelector`, draggable selector that can also be linked to an ipywidget slider" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eb95ba19-14b5-4bf4-93d9-05182fa500cb", - "metadata": {}, - "outputs": [], - "source": [ - "import fastplotlib as fpl\n", - "\n", - "import numpy as np\n", - "from ipywidgets import VBox, IntSlider, FloatSlider\n", - "\n", - "fig = fpl.Figure()\n", - "\n", - "# data to plot\n", - "xs = np.linspace(0, 100, 1000)\n", - "sine = np.sin(xs) * 20\n", - "\n", - "# make sine along x axis\n", - "sine_graphic = fig[0, 0].add_line(np.column_stack([xs, sine]).astype(np.float32))\n", - "\n", - "# make some selectors\n", - "selector = sine_graphic.add_linear_selector()\n", - "selector2 = sine_graphic.add_linear_selector(20)\n", - "selector3 = sine_graphic.add_linear_selector(40)\n", - "\n", - "# one of the selectors will change the line colors when it moves\n", - "@selector.add_event_handler(\"selection\")\n", - "def set_color_at_index(ev):\n", - " # changes the color at the index where the slider is\n", - " ix = ev.get_selected_index()\n", - " g = ev.graphic.parent\n", - " g.colors[ix] = \"green\"\n", - "\n", - "# fastplotlib LineSelector can make an ipywidget slider and return it :D \n", - "ipywidget_slider = selector.make_ipywidget_slider()\n", - "ipywidget_slider.description = \"slider1\"\n", - "\n", - "# or you can make your own ipywidget sliders and connect them to the linear selector\n", - "ipywidget_slider2 = IntSlider(min=0, max=100, description=\"slider2\")\n", - "ipywidget_slider3 = FloatSlider(min=0, max=100, description=\"slider3\")\n", - "\n", - "selector2.add_ipywidget_handler(ipywidget_slider2, step=5)\n", - "selector3.add_ipywidget_handler(ipywidget_slider3, step=0.1)\n", - "\n", - "fig[0, 0].auto_scale()\n", - "VBox([fig.show(), ipywidget_slider, ipywidget_slider2, ipywidget_slider3])" - ] - }, - { - "cell_type": "markdown", - "id": "d83caca6-e9b6-45df-b93c-0dfe0498d20e", - "metadata": {}, - "source": [ - "Double click the first selctor, and then use `Shift` + Right/Left Arrow Key to move it!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7ab9f141-f92f-4c4c-808b-97dafd64ca25", - "metadata": {}, - "outputs": [], - "source": [ - "# this controls the step-size of arrow key movements\n", - "selector.step = 0.1" - ] - }, - { - "cell_type": "markdown", - "id": "3b0f448f-bbe4-4b87-98e3-093f561c216c", - "metadata": { - "jp-MarkdownHeadingCollapsed": true - }, - "source": [ - "### Drag linear selectors with the mouse, hold \"Shift\" to synchronize movement of all the selectors" - ] - }, - { - "cell_type": "markdown", - "id": "c6f041b7-8779-46f1-8454-13cec66f53fd", - "metadata": {}, - "source": [ - "## Also works for line collections" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e36da217-f82a-4dfa-9556-1f4a2c7c4f1c", - "metadata": {}, - "outputs": [], - "source": [ - "sines = [sine] * 10\n", - "\n", - "fig = fpl.Figure()\n", - "\n", - "sine_stack = fig[0, 0].add_line_stack(sines)\n", - "\n", - "colors = \"y\", \"blue\", \"red\", \"green\"\n", - "\n", - "selectors = list()\n", - "for i, c in enumerate(colors):\n", - " sel = sine_stack.add_linear_selector(i * 100, color=c, name=str(i))\n", - " selectors.append(sel)\n", - "\n", - "fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "71ae4fca-f644-4d4f-8f32-f9d069bbc2f1", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/notebooks/lineplot.ipynb b/examples/notebooks/lineplot.ipynb deleted file mode 100644 index e700c866a..000000000 --- a/examples/notebooks/lineplot.ipynb +++ /dev/null @@ -1,124 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "386184a4-bd03-4467-a539-2696c3c5a573", - "metadata": { - "tags": [] - }, - "source": [ - "# A more complex example combing different graphics, subplots and multiple perspectives" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9c974494-712e-4981-bae2-a3ee176a6b20", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import fastplotlib as fpl" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c3d8f967-f60f-4f0b-b6ba-21b1251b4856", - "metadata": {}, - "outputs": [], - "source": [ - "# create data in the shape of a spiral\n", - "phi = np.linspace(0, 30, 200)\n", - "\n", - "xs = phi * np.cos(phi)\n", - "ys = phi * np.sin(phi)\n", - "zs = phi\n", - "\n", - "# make data 3d, with shape [, 3]\n", - "spiral = np.dstack([xs, ys, zs])[0]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "78cffe56-1147-4255-82c1-53cec6bc986a", - "metadata": {}, - "outputs": [], - "source": [ - "# figure with 2 rows and 2 columns\n", - "shape = (2, 2)\n", - "\n", - "# pan-zoom controllers for each subplot\n", - "# subplots are synced if they have the\n", - "# same controller ID\n", - "# in this example the first view has its own controller\n", - "# and the last 3 views are synced\n", - "controller_ids = [\n", - " [0, 1], # id each controller with an integer\n", - " [1, 1]\n", - "]\n", - "\n", - "# create the figure\n", - "fig = fpl.Figure(\n", - " shape=shape,\n", - " cameras='3d', # 3D view for all subplots within the figure\n", - " controller_ids=controller_ids\n", - ")\n", - "\n", - "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", - " marker = subplot.add_scatter(data=spiral[0], sizes=10, name=\"marker\")\n", - " \n", - "marker_index = 0\n", - "\n", - "# a function to move the ball along the spiral\n", - "def move_marker():\n", - " global marker_index\n", - " \n", - " marker_index += 1\n", - " \n", - " if marker_index == spiral.shape[0]:\n", - " marker_index = 0\n", - " \n", - " for subplot in fig:\n", - " subplot[\"marker\"].data = spiral[marker_index]\n", - " \n", - "# add `move_marker` to the animations\n", - "fig.add_animations(move_marker)\n", - "\n", - "fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e388eb93-7a9b-4ae4-91fc-cf32947f63a9", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.2" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/notebooks/lines_cmap.ipynb b/examples/notebooks/lines_cmap.ipynb deleted file mode 100644 index 3ceb25326..000000000 --- a/examples/notebooks/lines_cmap.ipynb +++ /dev/null @@ -1,306 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "b169210c-b148-4701-91d2-87f8be2c90da", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "import fastplotlib as fpl" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5d2ef4aa-0e4c-4694-ae2e-05da1153a413", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# this is only for testing, you do not need this to use fastplotlib\n", - "from nb_test_utils import plot_test, notebook_finished" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a6615d45-6a6e-4a1e-a998-18f7cc52f6b9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# linspace, create 100 evenly spaced x values from -10 to 10\n", - "xs = np.linspace(-10, 10, 100)\n", - "# sine wave\n", - "ys = np.sin(xs)\n", - "sine = np.column_stack([xs, ys])\n", - "\n", - "# cosine wave\n", - "ys = np.cos(xs)\n", - "cosine = np.column_stack([xs, ys])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "52a91e8a-25b7-4121-a06f-623d7412b558", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig = fpl.Figure()\n", - "\n", - "fig[0, 0].add_line(sine, thickness=10)\n", - "\n", - "fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "727282c3-aadf-420f-a88e-9dd4d4e91263", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "plot_test(\"lines-cmap-white\", fig)" - ] - }, - { - "cell_type": "markdown", - "id": "889b1858-ed64-4d6b-96ad-3883fbe4d38e", - "metadata": {}, - "source": [ - "# Fancy indexing of line colormaps" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "13185547-07bc-4771-ac6d-83314622bf30", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 0].graphics[0].cmap = \"jet\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3c9b0bc8-b176-425c-8036-63dc55ab7466", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# for testing, ignore\n", - "plot_test(\"lines-cmap-jet\", fig)" - ] - }, - { - "cell_type": "markdown", - "id": "13c1c034-2b3b-4568-b979-7c0bbea698ae", - "metadata": {}, - "source": [ - "map colors from sine data values by setting the cmap transform" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ee9ec4d7-d9a2-417c-92bd-b01a9a019801", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 0].graphics[0].cmap.transform = sine[:, 1]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6b19d2d4-90e7-40ed-afb9-13abe5474ace", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# for testing, ignore\n", - "plot_test(\"lines-cmap-jet-values\", fig)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ebf9f494-782d-4529-9ef6-a2a4032f097d", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# set transform from cosine\n", - "fig[0, 0].graphics[0].cmap.transform = cosine[:, 1]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0a6c4739-fa61-4532-865e-21107eab76f9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# for testing, ignore\n", - "plot_test(\"lines-cmap-jet-values-cosine\", fig)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5ddc95cf-b3be-4212-b525-1c628dc1e091", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# change cmap\n", - "fig[0, 0].graphics[0].cmap = \"viridis\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "45acfd2f-09f5-418c-bca5-3e574348b7d5", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# for testing, ignore\n", - "plot_test(\"lines-cmap-viridis\", fig)" - ] - }, - { - "cell_type": "markdown", - "id": "1f52bfdc-8151-4bab-973c-1bac36011802", - "metadata": {}, - "source": [ - "use cmap transform to map for a qualitative transform" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7712d313-16cd-49e5-89ca-91364412f194", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "cmap_transform = [0] * 25 + [1] * 5 + [2] * 50 + [3] * 20" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c8c13c03-56f0-48c3-b44e-65545a3bc3bc", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 0].graphics[0].cmap.transform = cmap_transform" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7548407f-05ed-4c47-93cc-131c61f8e242", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# for testing, ignore\n", - "plot_test(\"lines-cmap-viridis-values\", fig)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f64d036d-8a9e-4799-b77f-e78afa441fec", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 0].graphics[0].cmap = \"tab10\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c290c642-ba5f-4a46-9a17-c434cb39de26", - "metadata": {}, - "outputs": [], - "source": [ - "# for testing, ignore\n", - "plot_test(\"lines-cmap-tab-10\", fig)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c4b9e735-72e9-4f0e-aa3e-43db57e65c99", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# for testing, ignore\n", - "notebook_finished()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f6735cc0-910c-4854-ac50-8ee553a6475e", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/notebooks/scatter.ipynb b/examples/notebooks/scatter.ipynb deleted file mode 100644 index 0389b462b..000000000 --- a/examples/notebooks/scatter.ipynb +++ /dev/null @@ -1,190 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "eb204b20-160a-48ef-8ac6-54d263e497e4", - "metadata": { - "tags": [] - }, - "source": [ - "# Scatter plots in a `GridPlot` layout with a mix of 2d an 3d cameras" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9b3041ad-d94e-4b2a-af4d-63bcd19bf6c2", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "import fastplotlib as fpl" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "51f1d76a-f815-460f-a884-097fe3ea81ac", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# create a random distribution of 10,000 xyz coordinates\n", - "n_points = 10_000\n", - "\n", - "# if you have a good GPU go for 1.2 million points :D \n", - "# this is multiplied by 3\n", - "#n_points = 400_000\n", - "dims = (n_points, 3)\n", - "\n", - "offset = 15\n", - "\n", - "normal = np.random.normal(size=dims, scale=5)\n", - "cloud = np.vstack(\n", - " [\n", - " normal - offset,\n", - " normal,\n", - " normal + offset,\n", - " ]\n", - ")\n", - "\n", - "colors = [\"yellow\"] * n_points + [\"cyan\"] * n_points + [\"magenta\"] * n_points" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "922990b6-24e9-4fa0-977b-6577f9752d84", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# figure with 2 rows and 2 columns\n", - "shape = (2, 2)\n", - "\n", - "# define the camera\n", - "# a mix of 2d and 3d\n", - "cameras = [\n", - " ['2d', '3d'], \n", - " ['3d', '2d']\n", - "]\n", - "\n", - "# pan-zoom controllers for each subplot\n", - "# subplots are synced if they have the\n", - "# same controller ID\n", - "# you can only sync controllers that use the same camera type\n", - "# i.e. you cannot sync between 2d and 3d subplots\n", - "controller_ids = [\n", - " [0, 1],\n", - " [1, 0]\n", - "]\n", - "\n", - "# create the figure\n", - "fig = fpl.Figure(\n", - " shape=shape,\n", - " cameras=cameras,\n", - " controller_ids=controller_ids\n", - ")\n", - "\n", - "for subplot in fig:\n", - " subplot.add_scatter(data=cloud, colors=colors, alpha=0.7, sizes=5)\n", - "\n", - "\n", - "fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7b912961-f72e-46ef-889f-c03234831059", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 1].graphics[0].colors[n_points:int(n_points * 1.5)] = \"r\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c6085806-c001-4632-ab79-420b4692693a", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 1].graphics[0].colors[:n_points:10] = \"blue\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6f416825-df31-4e5d-b66b-07f23b48e7db", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 1].graphics[0].colors[n_points:] = \"green\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c0fd611e-73e5-49e6-a25c-9d5b64afa5f4", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 1].graphics[0].colors[n_points:, -1] = 0" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cd390542-3a44-4973-8172-89e5583433bc", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 1].graphics[0].data[:n_points] = fig[0, 1].graphics[0].data[n_points * 2:]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a18e7a17-c2af-4674-a499-bf5f3b27c8ca", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.2" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/notebooks/scatter_sizes_animation.ipynb b/examples/notebooks/scatter_sizes_animation.ipynb deleted file mode 100644 index 0cd301fb1..000000000 --- a/examples/notebooks/scatter_sizes_animation.ipynb +++ /dev/null @@ -1,61 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from time import time\n", - "\n", - "import numpy as np\n", - "import fastplotlib as fpl\n", - "\n", - "fig = fpl.Figure()\n", - "\n", - "points = np.array([[-1,0,1],[-1,0,1]], dtype=np.float32).swapaxes(0,1)\n", - "size_delta_scales = np.array([10, 40, 100], dtype=np.float32)\n", - "min_sizes = 6\n", - "\n", - "\n", - "def update_positions(subplot):\n", - " g = subplot.graphics[0]\n", - " g.data[:, :-1] += np.sin(((time() / 4))*np.pi)\n", - "\n", - "\n", - "def update_sizes(subplot):\n", - " sin_sample = np.abs(np.sin((time() / 1)*np.pi))\n", - " size_delta = sin_sample * size_delta_scales\n", - " subplot.graphics[0].sizes = size_delta\n", - "\n", - "\n", - "scatter = fig[0, 0].add_scatter(points, colors=[\"red\", \"green\", \"blue\"], sizes=12)\n", - "fig[0, 0].add_animations(update_positions, update_sizes)\n", - "\n", - "fig[0, 0].camera.width = 12\n", - "fig.show(autoscale=False)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/notebooks/scatter_sizes_grid.ipynb b/examples/notebooks/scatter_sizes_grid.ipynb deleted file mode 100644 index 21985f189..000000000 --- a/examples/notebooks/scatter_sizes_grid.ipynb +++ /dev/null @@ -1,82 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\"\"\"\n", - "Scatter Plot\n", - "============\n", - "Example showing point size change for scatter plot.\n", - "\"\"\"\n", - "\n", - "# test_example = true\n", - "import numpy as np\n", - "import fastplotlib as fpl\n", - "\n", - "# figure with 2 rows and 3 columns\n", - "shape = (2, 1)\n", - "\n", - "# you can give string names for each subplot\n", - "names = [\n", - " [\"scalar_size\"],\n", - " [\"array_size\"]\n", - "]\n", - "\n", - "# Create the figure\n", - "fig = fpl.Figure(\n", - " shape=shape,\n", - " names=names,\n", - " size=(1000, 1000)\n", - ")\n", - "\n", - "# get y_values using sin function\n", - "angles = np.arange(0, 20*np.pi+0.001, np.pi / 20)\n", - "y_values = 30*np.sin(angles) # 1 thousand points\n", - "x_values = np.array([x for x in range(len(y_values))], dtype=np.float32)\n", - "\n", - "data = np.column_stack([x_values, y_values])\n", - "\n", - "fig[\"scalar_size\"].add_scatter(data=data, sizes=5, colors=\"blue\") # add a set of scalar sizes\n", - "\n", - "non_scalar_sizes = np.abs((y_values / np.pi)) # ensure minimum size of 5\n", - "fig[\"array_size\"].add_scatter(data=data, sizes=non_scalar_sizes, colors=\"red\")\n", - "\n", - "for subplot in fig:\n", - " subplot.auto_scale(maintain_aspect=True)\n", - "\n", - "fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png b/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png deleted file mode 100644 index 08b6e8ac1..000000000 --- a/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a499ecad892c779aa857e9074a5e157b02bc914007b28aa4958b2b231b5961a4 -size 18585 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png b/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png deleted file mode 100644 index 83b5c21d9..000000000 --- a/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9506e9838bd5bb1f79d41c8dfaa92c127d12852758bfcecfa37202d02b0ba325 -size 19914 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet.png b/examples/notebooks/screenshots/nb-lines-cmap-jet.png deleted file mode 100644 index 34a6f8b6f..000000000 --- a/examples/notebooks/screenshots/nb-lines-cmap-jet.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8e6a74dad6621df938517558adf89e19e975b39386d1a46d48991f0cffe725dd -size 18549 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png b/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png deleted file mode 100644 index ca41e764d..000000000 --- a/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5725b52f18e1be1f7bd358b489374c0f733cf9c3f1f127a4fbfbd1daec30a57f -size 17061 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png b/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png deleted file mode 100644 index dc7ec0c13..000000000 --- a/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f1f08fea3f0f74ab7632725f544c03303334cfcf1e01b188d01113a8bcc84dd7 -size 17353 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-viridis.png b/examples/notebooks/screenshots/nb-lines-cmap-viridis.png deleted file mode 100644 index 912cae1e4..000000000 --- a/examples/notebooks/screenshots/nb-lines-cmap-viridis.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a5d14cb03071ca2ad4c0c2145d68ab3555d30565f8f6d2be6fa7fc649213d748 -size 20499 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-white.png b/examples/notebooks/screenshots/nb-lines-cmap-white.png deleted file mode 100644 index 2edc6903b..000000000 --- a/examples/notebooks/screenshots/nb-lines-cmap-white.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3c7a2c8ccd70787e67800fb0d9625d7816fb6b004c0128b3b254fec7c7fd7c71 -size 16058 diff --git a/examples/notebooks/subplots.ipynb b/examples/notebooks/subplots.ipynb deleted file mode 100644 index c9774029f..000000000 --- a/examples/notebooks/subplots.ipynb +++ /dev/null @@ -1,218 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "3cfc2d9f-6a09-42f4-a47c-3ba51f1a1801", - "metadata": {}, - "source": [ - "### More in-depth on subplots with a Figure" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a635b3b3-33fa-48f0-b1cc-bf83b1e883ab", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import fastplotlib as fpl" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8de931e2-bdb3-44a3-9538-e0b3965779af", - "metadata": {}, - "outputs": [], - "source": [ - "# grid with 2 rows and 3 columns\n", - "shape = (2, 3)\n", - "\n", - "# pan-zoom controllers for each subplot\n", - "# subplots are synced if they have the\n", - "# same controller ID\n", - "controller_ids = [\n", - " [0, -3, 1], # id each controller with an integer\n", - " [2, 2, -3]\n", - "]\n", - "\n", - "# another way to set controller_ids\n", - "controller_ids = [\n", - " [\"subplot0\", \"subplot4\"],\n", - " [\"subplot1\", \"subplot2\", \"subplot5\"],\n", - "]\n", - "\n", - "\n", - "# you can give string names for each subplot within the figure\n", - "names = [\n", - " [\"subplot0\", \"subplot1\", \"subplot2\"],\n", - " [\"subplot3\", \"subplot4\", \"subplot5\"]\n", - "]\n", - "\n", - "# Create the figure\n", - "fig = fpl.Figure(\n", - " shape=shape,\n", - " controller_ids=controller_ids,\n", - " names=names,\n", - ")\n", - "\n", - "\n", - "# Make a random image graphic for each subplot\n", - "for subplot in fig:\n", - " data = np.random.rand(512, 512)\n", - " # create and add an ImageGraphic\n", - " subplot.add_image(data=data, name=\"rand-image\")\n", - " \n", - "\n", - "# Define a function to update the image graphics \n", - "# with new randomly generated data\n", - "def set_random_frame(gp):\n", - " for subplot in gp:\n", - " new_data = np.random.rand(512, 512)\n", - " subplot[\"rand-image\"].data = new_data\n", - "\n", - "# add the animation\n", - "fig.add_animations(set_random_frame)\n", - "fig.show()" - ] - }, - { - "cell_type": "markdown", - "id": "2867bcd6-7691-4073-91d9-9c33e8fdb896", - "metadata": {}, - "source": [ - "### Accessing subplots" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2a6f7eb5-776e-42a6-b6c2-c26009a26795", - "metadata": { - "is_executing": true - }, - "outputs": [], - "source": [ - "# by name\n", - "fig[\"subplot0\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "45e83bca-5a44-48ce-874f-9ae9ca444233", - "metadata": {}, - "outputs": [], - "source": [ - "# by index\n", - "fig[0, 0]" - ] - }, - { - "cell_type": "markdown", - "id": "3272b8b3-3063-47a4-94c8-15ceeeaecc69", - "metadata": {}, - "source": [ - "## getting graphics within subplots!\n", - "this can be used to get graphics if they are named" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c8cf9bfd-e0cc-4173-b64e-a9f2c87bb2c6", - "metadata": {}, - "outputs": [], - "source": [ - "# can access graphic directly via name\n", - "fig[\"subplot0\"][\"rand-image\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1cfd1d45-8a60-4fc1-b873-46caa966fe6f", - "metadata": {}, - "outputs": [], - "source": [ - "fig[\"subplot0\"][\"rand-image\"].vmin = 0.6\n", - "fig[\"subplot0\"][\"rand-image\"].vmax = 0.8" - ] - }, - { - "cell_type": "markdown", - "id": "39c8a5acbad7980b", - "metadata": { - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } - }, - "source": [ - "If they are not named use .graphics" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d27af25002237db5", - "metadata": { - "collapsed": false, - "is_executing": true, - "jupyter": { - "outputs_hidden": false - } - }, - "outputs": [], - "source": [ - "fig[\"subplot0\"].graphics" - ] - }, - { - "cell_type": "markdown", - "id": "2299a8ae23e39c37", - "metadata": { - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } - }, - "source": [ - "### positional indexing also works" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2fafe992-4783-40f2-b044-26a2835dd50a", - "metadata": {}, - "outputs": [], - "source": [ - "fig[1, 0][\"rand-image\"].vim = 0.1\n", - "fig[1, 0][\"rand-image\"].vmax = 0.3" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/notebooks/subplots_simple.ipynb b/examples/notebooks/subplots_simple.ipynb deleted file mode 100644 index 9ff4e4284..000000000 --- a/examples/notebooks/subplots_simple.ipynb +++ /dev/null @@ -1,259 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "0e42f03b-9cdf-484f-b158-78b07fdf524d", - "metadata": {}, - "source": [ - "## This notebook shows how you can use more of the `fastplotlib` API to create `Graphic` objects and add them to subplots" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5171a06e-1bdc-4908-9726-3c1fd45dbb9d", - "metadata": { - "ExecuteTime": { - "end_time": "2023-11-26T04:01:19.120171Z", - "start_time": "2023-11-26T04:01:18.618087Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "import fastplotlib as fpl" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "86a2488f-ae1c-4b98-a7c0-18eae8013af1", - "metadata": { - "ExecuteTime": { - "end_time": "2023-11-26T04:01:19.467264Z", - "start_time": "2023-11-26T04:01:19.121813Z" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "# Figure of shape 2 x 3 with all controllers synced\n", - "fig = fpl.Figure(shape=(2, 3), controller_ids=\"sync\")\n", - "\n", - "# Make a random image graphic for each subplot\n", - "for subplot in fig:\n", - " # create image data\n", - " data = np.random.rand(512, 512)\n", - " # add an image to the subplot\n", - " subplot.add_image(data, name=\"rand-img\")\n", - "\n", - "# Define a function to update the image graphics with new data\n", - "# add_animations will pass the figure to the animation function\n", - "def update_data(f):\n", - " for sp in f:\n", - " new_data = np.random.rand(512, 512)\n", - " # index the image graphic by name and set the data\n", - " sp[\"rand-img\"].data = new_data\n", - " \n", - "# add the animation function\n", - "fig.add_animations(update_data)\n", - "\n", - "# show the figure\n", - "fig.show()" - ] - }, - { - "cell_type": "markdown", - "id": "e7801781-c3e9-490f-ab12-1cd2f480d3e9", - "metadata": {}, - "source": [ - "## Accessing subplots within `Figure`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "52163bc7-2c77-4699-b7b0-e455a0ed7584", - "metadata": {}, - "outputs": [], - "source": [ - "fig" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "17c6bc4a-5340-49f1-8597-f54528cfe915", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# positional indexing\n", - "# row 0 and col 0\n", - "fig[0, 0]" - ] - }, - { - "cell_type": "markdown", - "id": "276dfede-e9bc-4488-b9e6-3ca5cf91e4dc", - "metadata": {}, - "source": [ - "### You can get the graphics within a subplot" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "34130f12-9ef6-43b0-b929-931de8b7da25", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 1].graphics" - ] - }, - { - "cell_type": "markdown", - "id": "bf33f3e7-ab16-46b1-9126-f0a1ecc07541", - "metadata": {}, - "source": [ - "### and change their properties" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ef8a29a6-b19c-4e6b-a2ba-fb4823c01451", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[0, 1].graphics[0].vmax = 0.5" - ] - }, - { - "cell_type": "markdown", - "id": "00506fa1-2dc0-4435-96a0-e50667d3174f", - "metadata": {}, - "source": [ - "### more indexing" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d6c2fa4b-c634-4dcf-8b61-f1986f7c4918", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# you can give subplots human-readable string names\n", - "fig[0, 2].name = \"top-right-plot\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2f6b549c-3165-496d-98aa-45b96c3de674", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[\"top-right-plot\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "be436e04-33a6-4597-8e6a-17e1e5225419", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# view its position\n", - "fig[\"top-right-plot\"].position" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6699cda6-af86-4258-87f5-1832f989a564", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# these are really the same\n", - "fig[\"top-right-plot\"] is fig[0, 2]" - ] - }, - { - "cell_type": "markdown", - "id": "aac2f6bf-a641-4c86-a3d2-2cb7906ba914", - "metadata": {}, - "source": [ - "Indexing with subplot name and graphic name" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "545b627b-d794-459a-a75a-3fde44f0ea95", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig[\"top-right-plot\"][\"rand-img\"].vmin = 0.5" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "36432d5b-b76c-4a2a-a32c-097faf5ab269", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "fig.close()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b507b723-1371-44e7-aa6d-6aeb3196b27d", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/qt/README.rst b/examples/qt/README.rst new file mode 100644 index 000000000..5ff5471d5 --- /dev/null +++ b/examples/qt/README.rst @@ -0,0 +1,2 @@ +Qt Examples +=========== diff --git a/examples/qt/embed.py b/examples/qt/embed.py index a3b156021..535c08e5f 100644 --- a/examples/qt/embed.py +++ b/examples/qt/embed.py @@ -1,6 +1,15 @@ """ -Use a simple Plot to display a video frame that can be updated using a QSlider +Embed within a Qt Window +======================== + +When using the Qt canvas, `Figure.show()` just returns a QWidget that behaves like any other Qt widget. So you can +embed it and do other things that you can do with ordinary QWidgets. This example use a simple Plot to display a video +frame that can be updated using a QSlider. """ + +# test_example = false +# sphinx_gallery_pygfx_docs = 'code' + from PyQt6 import QtWidgets, QtCore import fastplotlib as fpl import imageio.v3 as iio @@ -52,3 +61,6 @@ def update_frame(ix): # execute Qt app fpl.run() + +# You can also use Qt interactively/in a non-blocking manner in notebooks and ipython +# by using %gui qt and NOT calling `fpl.run()`, see the user guide for more details diff --git a/examples/qt/imagewidget.py b/examples/qt/imagewidget.py index f82d082a0..d18ae9b15 100644 --- a/examples/qt/imagewidget.py +++ b/examples/qt/imagewidget.py @@ -1,6 +1,13 @@ """ -Use ImageWidget to display one or multiple image sequences +ImageWidget as QtWidget +======================= + +This example opens multiple windows to show multiple ImageWidgets. """ + +# test_example = false +# sphinx_gallery_pygfx_docs = 'code' + import numpy as np from PyQt6 import QtWidgets import fastplotlib as fpl @@ -11,22 +18,25 @@ # fastplotlib and wgpu will auto-detect if Qt is imported and then use the Qt canvas iw = fpl.ImageWidget(images) -iw.show() -iw.widget.resize(800, 800) +widget = iw.show() +widget.resize(800, 800) # another image widget with multiple images -images_list = [np.random.rand(100, 512, 512) for i in range(9)] +images_list = [np.random.rand(100, 512, 512) for i in range(4)] iw_mult = fpl.ImageWidget( images_list, cmap="viridis" ) -iw_mult.show() -iw_mult.widget.resize(800, 800) +widget_multi = iw_mult.show() +widget_multi.resize(800, 800) # image widget with rgb data rgb_video = iio.imread("imageio:cockatoo.mp4") -iw_rgb = fpl.ImageWidget(rgb_video, rgb=[True]) +iw_rgb = fpl.ImageWidget(rgb_video, rgb=[True], figure_kwargs={"size": (800, 500)}) iw_rgb.show() fpl.run() + +# You can also use Qt interactively/in a non-blocking manner in notebooks and ipython +# by using %gui qt and NOT calling `fpl.run()`, see the user guide for more details diff --git a/examples/qt/minimal.py b/examples/qt/minimal.py index 0d9009ba7..01b5de352 100644 --- a/examples/qt/minimal.py +++ b/examples/qt/minimal.py @@ -1,6 +1,15 @@ """ -Minimal PyQt example that displays an image. Press "r" key to autoscale +Minimal Qt +========== + +Minimal PyQt example that displays an image. + +`Figure.show()` returns a QWidget that you can use in a Qt app just like any other QWidget! """ + +# test_example = false +# sphinx_gallery_pygfx_docs = 'code' + # import Qt or PySide from PyQt6 import QtWidgets import fastplotlib as fpl @@ -9,12 +18,12 @@ img = iio.imread("imageio:astronaut.png") # fastplotlib and wgpu will auto-detect if Qt is imported and then use the Qt canvas and Qt output context -fig = fpl.Figure() +figure = fpl.Figure() -fig[0, 0].add_image(img) +figure[0, 0].add_image(img) # must call fig.show() to start rendering loop and show the QWidget containing the fastplotlib figure -qwidget = fig.show() +qwidget = figure.show() # set QWidget initial size from image width and height qwidget.resize(*img.shape[:2]) @@ -22,3 +31,6 @@ # execute Qt app # if this is part of a larger Qt QApplication, you can also call app.exec() where app is the QApplication instance fpl.run() + +# You can also use Qt interactively/in a non-blocking manner in notebooks and ipython +# by using %gui qt and NOT calling `fpl.run()`, see the user guide for more details diff --git a/examples/desktop/scatter/README.rst b/examples/scatter/README.rst similarity index 100% rename from examples/desktop/scatter/README.rst rename to examples/scatter/README.rst diff --git a/examples/desktop/scatter/scatter.py b/examples/scatter/scatter.py similarity index 100% rename from examples/desktop/scatter/scatter.py rename to examples/scatter/scatter.py diff --git a/examples/desktop/scatter/scatter_cmap.py b/examples/scatter/scatter_cmap.py similarity index 100% rename from examples/desktop/scatter/scatter_cmap.py rename to examples/scatter/scatter_cmap.py diff --git a/examples/desktop/scatter/scatter_cmap_iris.py b/examples/scatter/scatter_cmap_iris.py similarity index 100% rename from examples/desktop/scatter/scatter_cmap_iris.py rename to examples/scatter/scatter_cmap_iris.py diff --git a/examples/desktop/scatter/scatter_colorslice.py b/examples/scatter/scatter_colorslice.py similarity index 100% rename from examples/desktop/scatter/scatter_colorslice.py rename to examples/scatter/scatter_colorslice.py diff --git a/examples/desktop/scatter/scatter_colorslice_iris.py b/examples/scatter/scatter_colorslice_iris.py similarity index 100% rename from examples/desktop/scatter/scatter_colorslice_iris.py rename to examples/scatter/scatter_colorslice_iris.py diff --git a/examples/desktop/scatter/scatter_dataslice.py b/examples/scatter/scatter_dataslice.py similarity index 100% rename from examples/desktop/scatter/scatter_dataslice.py rename to examples/scatter/scatter_dataslice.py diff --git a/examples/desktop/scatter/scatter_dataslice_iris.py b/examples/scatter/scatter_dataslice_iris.py similarity index 100% rename from examples/desktop/scatter/scatter_dataslice_iris.py rename to examples/scatter/scatter_dataslice_iris.py diff --git a/examples/desktop/scatter/scatter_iris.py b/examples/scatter/scatter_iris.py similarity index 100% rename from examples/desktop/scatter/scatter_iris.py rename to examples/scatter/scatter_iris.py diff --git a/examples/desktop/scatter/scatter_size.py b/examples/scatter/scatter_size.py similarity index 100% rename from examples/desktop/scatter/scatter_size.py rename to examples/scatter/scatter_size.py diff --git a/examples/desktop/screenshots/gridplot.png b/examples/screenshots/gridplot.png similarity index 100% rename from examples/desktop/screenshots/gridplot.png rename to examples/screenshots/gridplot.png diff --git a/examples/desktop/screenshots/gridplot_non_square.png b/examples/screenshots/gridplot_non_square.png similarity index 100% rename from examples/desktop/screenshots/gridplot_non_square.png rename to examples/screenshots/gridplot_non_square.png diff --git a/examples/desktop/screenshots/heatmap.png b/examples/screenshots/heatmap.png similarity index 100% rename from examples/desktop/screenshots/heatmap.png rename to examples/screenshots/heatmap.png diff --git a/examples/desktop/screenshots/image_cmap.png b/examples/screenshots/image_cmap.png similarity index 100% rename from examples/desktop/screenshots/image_cmap.png rename to examples/screenshots/image_cmap.png diff --git a/examples/desktop/screenshots/image_rgb.png b/examples/screenshots/image_rgb.png similarity index 100% rename from examples/desktop/screenshots/image_rgb.png rename to examples/screenshots/image_rgb.png diff --git a/examples/desktop/screenshots/image_rgbvminvmax.png b/examples/screenshots/image_rgbvminvmax.png similarity index 100% rename from examples/desktop/screenshots/image_rgbvminvmax.png rename to examples/screenshots/image_rgbvminvmax.png diff --git a/examples/desktop/screenshots/image_simple.png b/examples/screenshots/image_simple.png similarity index 100% rename from examples/desktop/screenshots/image_simple.png rename to examples/screenshots/image_simple.png diff --git a/examples/desktop/screenshots/image_small.png b/examples/screenshots/image_small.png similarity index 100% rename from examples/desktop/screenshots/image_small.png rename to examples/screenshots/image_small.png diff --git a/examples/desktop/screenshots/image_vminvmax.png b/examples/screenshots/image_vminvmax.png similarity index 100% rename from examples/desktop/screenshots/image_vminvmax.png rename to examples/screenshots/image_vminvmax.png diff --git a/examples/desktop/screenshots/image_widget.png b/examples/screenshots/image_widget.png similarity index 100% rename from examples/desktop/screenshots/image_widget.png rename to examples/screenshots/image_widget.png diff --git a/examples/desktop/screenshots/image_widget_grid.png b/examples/screenshots/image_widget_grid.png similarity index 100% rename from examples/desktop/screenshots/image_widget_grid.png rename to examples/screenshots/image_widget_grid.png diff --git a/examples/desktop/screenshots/image_widget_imgui.png b/examples/screenshots/image_widget_imgui.png similarity index 100% rename from examples/desktop/screenshots/image_widget_imgui.png rename to examples/screenshots/image_widget_imgui.png diff --git a/examples/desktop/screenshots/image_widget_single_video.png b/examples/screenshots/image_widget_single_video.png similarity index 100% rename from examples/desktop/screenshots/image_widget_single_video.png rename to examples/screenshots/image_widget_single_video.png diff --git a/examples/desktop/screenshots/image_widget_videos.png b/examples/screenshots/image_widget_videos.png similarity index 100% rename from examples/desktop/screenshots/image_widget_videos.png rename to examples/screenshots/image_widget_videos.png diff --git a/examples/desktop/screenshots/imgui_basic.png b/examples/screenshots/imgui_basic.png similarity index 100% rename from examples/desktop/screenshots/imgui_basic.png rename to examples/screenshots/imgui_basic.png diff --git a/examples/desktop/screenshots/line.png b/examples/screenshots/line.png similarity index 100% rename from examples/desktop/screenshots/line.png rename to examples/screenshots/line.png diff --git a/examples/desktop/screenshots/line_cmap.png b/examples/screenshots/line_cmap.png similarity index 100% rename from examples/desktop/screenshots/line_cmap.png rename to examples/screenshots/line_cmap.png diff --git a/examples/screenshots/line_cmap_more.png b/examples/screenshots/line_cmap_more.png new file mode 100644 index 000000000..56e3fe8cc --- /dev/null +++ b/examples/screenshots/line_cmap_more.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de08452e47799d9afcadfc583e63da1c02513cf73000bd5c2649236e61ed6b34 +size 126725 diff --git a/examples/desktop/screenshots/line_collection.png b/examples/screenshots/line_collection.png similarity index 100% rename from examples/desktop/screenshots/line_collection.png rename to examples/screenshots/line_collection.png diff --git a/examples/desktop/screenshots/line_collection_cmap_values.png b/examples/screenshots/line_collection_cmap_values.png similarity index 100% rename from examples/desktop/screenshots/line_collection_cmap_values.png rename to examples/screenshots/line_collection_cmap_values.png diff --git a/examples/desktop/screenshots/line_collection_cmap_values_qualitative.png b/examples/screenshots/line_collection_cmap_values_qualitative.png similarity index 100% rename from examples/desktop/screenshots/line_collection_cmap_values_qualitative.png rename to examples/screenshots/line_collection_cmap_values_qualitative.png diff --git a/examples/desktop/screenshots/line_collection_colors.png b/examples/screenshots/line_collection_colors.png similarity index 100% rename from examples/desktop/screenshots/line_collection_colors.png rename to examples/screenshots/line_collection_colors.png diff --git a/examples/desktop/screenshots/line_collection_slicing.png b/examples/screenshots/line_collection_slicing.png similarity index 100% rename from examples/desktop/screenshots/line_collection_slicing.png rename to examples/screenshots/line_collection_slicing.png diff --git a/examples/desktop/screenshots/line_colorslice.png b/examples/screenshots/line_colorslice.png similarity index 100% rename from examples/desktop/screenshots/line_colorslice.png rename to examples/screenshots/line_colorslice.png diff --git a/examples/desktop/screenshots/line_dataslice.png b/examples/screenshots/line_dataslice.png similarity index 100% rename from examples/desktop/screenshots/line_dataslice.png rename to examples/screenshots/line_dataslice.png diff --git a/examples/desktop/screenshots/line_stack.png b/examples/screenshots/line_stack.png similarity index 100% rename from examples/desktop/screenshots/line_stack.png rename to examples/screenshots/line_stack.png diff --git a/examples/screenshots/linear_region_selectors_match_offsets.png b/examples/screenshots/linear_region_selectors_match_offsets.png new file mode 100644 index 000000000..9d2371403 --- /dev/null +++ b/examples/screenshots/linear_region_selectors_match_offsets.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f12310c09c4e84ea2c6f8245d1aa0ce9389a3d9637d7d4f9dc233bea173a0e3 +size 95366 diff --git a/examples/desktop/screenshots/linear_selector.png b/examples/screenshots/linear_selector.png similarity index 100% rename from examples/desktop/screenshots/linear_selector.png rename to examples/screenshots/linear_selector.png diff --git a/examples/desktop/screenshots/scatter_cmap_iris.png b/examples/screenshots/scatter_cmap_iris.png similarity index 100% rename from examples/desktop/screenshots/scatter_cmap_iris.png rename to examples/screenshots/scatter_cmap_iris.png diff --git a/examples/desktop/screenshots/scatter_colorslice_iris.png b/examples/screenshots/scatter_colorslice_iris.png similarity index 100% rename from examples/desktop/screenshots/scatter_colorslice_iris.png rename to examples/screenshots/scatter_colorslice_iris.png diff --git a/examples/desktop/screenshots/scatter_dataslice_iris.png b/examples/screenshots/scatter_dataslice_iris.png similarity index 100% rename from examples/desktop/screenshots/scatter_dataslice_iris.png rename to examples/screenshots/scatter_dataslice_iris.png diff --git a/examples/desktop/screenshots/scatter_iris.png b/examples/screenshots/scatter_iris.png similarity index 100% rename from examples/desktop/screenshots/scatter_iris.png rename to examples/screenshots/scatter_iris.png diff --git a/examples/desktop/screenshots/scatter_size.png b/examples/screenshots/scatter_size.png similarity index 100% rename from examples/desktop/screenshots/scatter_size.png rename to examples/screenshots/scatter_size.png diff --git a/examples/desktop/selectors/README.rst b/examples/selection_tools/README.rst similarity index 100% rename from examples/desktop/selectors/README.rst rename to examples/selection_tools/README.rst diff --git a/examples/selection_tools/linear_region_line_collection.py b/examples/selection_tools/linear_region_line_collection.py new file mode 100644 index 000000000..493062026 --- /dev/null +++ b/examples/selection_tools/linear_region_line_collection.py @@ -0,0 +1,81 @@ +""" +LinearRegionSelectors with LineCollection +========================================= + +Example showing how to use a `LinearRegionSelector` with a `LineCollection` +""" + +# test_example = false +# sphinx_gallery_pygfx_docs = 'screenshot' + + +import fastplotlib as fpl +import numpy as np + +# data to plot +xs = np.linspace(0, 10 * np.pi, 1_000) +sine = np.column_stack([xs, np.sin(xs)]) +cosine = np.column_stack([xs, np.cos(xs)]) + +figure = fpl.Figure((5, 1), size=(700, 1000)) + +# preallocated size for zoomed data +zoomed_prealloc = 1_000 + +# sines and cosines +data = [sine, cosine, sine, cosine] + +# make line stack +line_stack = figure[0, 0].add_line_stack(data, separation=2) + +# make selector +selector = line_stack.add_linear_region_selector() + +# preallocate array for storing zoomed in data +zoomed_init = np.column_stack([np.arange(zoomed_prealloc), np.zeros(zoomed_prealloc)]) + +# populate zoomed view subplots with graphics using preallocated buffer sizes +for i, subplot in enumerate(figure): + if i == 0: + # skip the first one + continue + # make line graphics for displaying zoomed data + subplot.add_line(zoomed_init, name="zoomed") + + +def interpolate(subdata: np.ndarray, axis: int): + """1D interpolation to display within the preallocated data array""" + x = np.arange(0, zoomed_prealloc) + xp = np.linspace(0, zoomed_prealloc, subdata.shape[0]) + + # interpolate to preallocated size + return np.interp(x, xp, fp=subdata[:, axis]) # use the y-values + + +@selector.add_event_handler("selection") +def update_zoomed_subplots(ev): + """update the zoomed subplots""" + zoomed_data = ev.get_selected_data() + + for i in range(len(zoomed_data)): + # interpolate y-vals + data = interpolate(zoomed_data[i], axis=1) + figure[i + 1, 0]["zoomed"].data[:, 1] = data + figure[i + 1, 0].auto_scale() + + +# set initial selection so zoomed plots update +selector.selection = (0, 4 * np.pi) + +# hide toolbars to reduce clutter +for subplot in figure: + subplot.toolbar = False + +figure.show(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() diff --git a/examples/selection_tools/linear_region_selector.py b/examples/selection_tools/linear_region_selector.py new file mode 100644 index 000000000..026da2522 --- /dev/null +++ b/examples/selection_tools/linear_region_selector.py @@ -0,0 +1,114 @@ +""" +LinearRegionSelectors +===================== + +Example showing how to use a `LinearRegionSelector` with lines. We demonstrate two use cases, a horizontal +LinearRegionSelector which selects along the x-axis and a vertical selector which moves along the y-axis. + +In general, a horizontal selector on the x-axis is useful if you are displaying data where y = f(x). +Conversely, a vertical selector that selectors along the y-axis is useful for +displaying data where x = f(y). (ex: vertical histograms) +""" + +# test_example = false +# sphinx_gallery_pygfx_docs = 'screenshot' + +import fastplotlib as fpl +import numpy as np + +# names for out subplots +names = [ + ["y = sine(x)", "x = sine(y), sine(y) > 0 = 0"], + ["zoomed sine(x)", "zoomed sine(y)"] +] + +# 2 rows, 2 columns +figure = fpl.Figure( + (2, 2), + size=(700, 560), + names=names, +) + +# preallocated size for zoomed data +zoomed_prealloc = 1_000 + +# data to plot +xs = np.linspace(0, 10 * np.pi, 1_000) +ys = np.sin(xs) # y = sine(x) + +# make sine along x axis +sine_graphic_x = figure[0, 0].add_line(np.column_stack([xs, ys])) + +# x = sine(y), sine(y) > 0 = 0 +sine_y = ys +sine_y[sine_y > 0] = 0 + +# sine along y axis +sine_graphic_y = figure[0, 1].add_line(np.column_stack([ys, xs])) + +# offset the position of the graphic to demonstrate `get_selected_data()` later +sine_graphic_y.position_x = 50 +sine_graphic_y.position_y = 50 + +# add linear selectors +selector_x = sine_graphic_x.add_linear_region_selector() # default axis is "x" +selector_y = sine_graphic_y.add_linear_region_selector(axis="y") + +# preallocate array for storing zoomed in data +zoomed_init = np.column_stack([np.arange(zoomed_prealloc), np.zeros(zoomed_prealloc)]) + +# make line graphics for displaying zoomed data +zoomed_x = figure[1, 0].add_line(zoomed_init) +zoomed_y = figure[1, 1].add_line(zoomed_init) + + +def interpolate(subdata: np.ndarray, axis: int): + """1D interpolation to display within the preallocated data array""" + x = np.arange(0, zoomed_prealloc) + xp = np.linspace(0, zoomed_prealloc, subdata.shape[0]) + + # interpolate to preallocated size + return np.interp(x, xp, fp=subdata[:, axis]) # use the y-values + + +@selector_x.add_event_handler("selection") +def set_zoom_x(ev): + """sets zoomed x selector data""" + # get the selected data + selected_data = ev.get_selected_data() + if selected_data.size == 0: + # no data selected + zoomed_x.data[:, 1] = 0 + + # interpolate the y-values since y = f(x) + zoomed_x.data[:, 1] = interpolate(selected_data, axis=1) + figure[1, 0].auto_scale() + + +def set_zoom_y(ev): + """sets zoomed x selector data""" + # get the selected data + selected_data = ev.get_selected_data() + if selected_data.size == 0: + # no data selected + zoomed_y.data[:, 1] = 0 + + # interpolate the x values since this x = f(y) + zoomed_y.data[:, 1] = -interpolate(selected_data, axis=0) + figure[1, 1].auto_scale() + + +# you can also add event handlers without a decorator +selector_y.add_event_handler(set_zoom_y, "selection") + +# set initial selection +selector_x.selection = selector_y.selection = (0, 4 * np.pi) + + +figure.show(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() diff --git a/examples/selection_tools/linear_region_selectors_match_offsets.py b/examples/selection_tools/linear_region_selectors_match_offsets.py new file mode 100644 index 000000000..c5d58c9be --- /dev/null +++ b/examples/selection_tools/linear_region_selectors_match_offsets.py @@ -0,0 +1,109 @@ +""" +LinearRegionSelectors match offsets +=================================== + +Identical to linear region selector but with offsets for testing purposes +""" + +# test_example = true +# sphinx_gallery_pygfx_docs = 'hidden' + +import fastplotlib as fpl +import numpy as np + +# names for out subplots +names = [ + ["y = sine(x)", "x = sine(y), sine(y) > 0 = 0"], + ["zoomed sine(x)", "zoomed sine(y)"] +] + +# 2 rows, 2 columns +figure = fpl.Figure( + (2, 2), + size=(700, 560), + names=names, +) + +# preallocated size for zoomed data +zoomed_prealloc = 1_000 + +# data to plot +xs = np.linspace(0, 10 * np.pi, 1_000) +ys = np.sin(xs) # y = sine(x) + +# make sine along x axis +sine_graphic_x = figure[0, 0].add_line(np.column_stack([xs, ys]), offset=(10, 10, 0)) + +# x = sine(y), sine(y) > 0 = 0 +sine_y = ys +sine_y[sine_y > 0] = 0 + +# sine along y axis +sine_graphic_y = figure[0, 1].add_line(np.column_stack([ys, xs]), offset=(10, 10, 0)) + +# offset the position of the graphic to demonstrate `get_selected_data()` later +sine_graphic_y.position_x = 50 +sine_graphic_y.position_y = 50 + +# add linear selectors +selector_x = sine_graphic_x.add_linear_region_selector() # default axis is "x" +selector_y = sine_graphic_y.add_linear_region_selector(axis="y") + +# preallocate array for storing zoomed in data +zoomed_init = np.column_stack([np.arange(zoomed_prealloc), np.zeros(zoomed_prealloc)]) + +# make line graphics for displaying zoomed data +zoomed_x = figure[1, 0].add_line(zoomed_init) +zoomed_y = figure[1, 1].add_line(zoomed_init) + + +def interpolate(subdata: np.ndarray, axis: int): + """1D interpolation to display within the preallocated data array""" + x = np.arange(0, zoomed_prealloc) + xp = np.linspace(0, zoomed_prealloc, subdata.shape[0]) + + # interpolate to preallocated size + return np.interp(x, xp, fp=subdata[:, axis]) # use the y-values + + +@selector_x.add_event_handler("selection") +def set_zoom_x(ev): + """sets zoomed x selector data""" + # get the selected data + selected_data = ev.get_selected_data() + if selected_data.size == 0: + # no data selected + zoomed_x.data[:, 1] = 0 + + # interpolate the y-values since y = f(x) + zoomed_x.data[:, 1] = interpolate(selected_data, axis=1) + figure[1, 0].auto_scale() + + +def set_zoom_y(ev): + """sets zoomed x selector data""" + # get the selected data + selected_data = ev.get_selected_data() + if selected_data.size == 0: + # no data selected + zoomed_y.data[:, 1] = 0 + + # interpolate the x values since this x = f(y) + zoomed_y.data[:, 1] = -interpolate(selected_data, axis=0) + figure[1, 1].auto_scale() + + +# you can also add event handlers without a decorator +selector_y.add_event_handler(set_zoom_y, "selection") + +# set initial selection +selector_x.selection = selector_y.selection = (0, 4 * np.pi) + + +figure.show(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() diff --git a/examples/desktop/selectors/linear_selector.py b/examples/selection_tools/linear_selector.py similarity index 100% rename from examples/desktop/selectors/linear_selector.py rename to examples/selection_tools/linear_selector.py diff --git a/examples/desktop/selectors/linear_selector_image.py b/examples/selection_tools/linear_selector_image.py similarity index 100% rename from examples/desktop/selectors/linear_selector_image.py rename to examples/selection_tools/linear_selector_image.py diff --git a/examples/desktop/selectors/rectangle_selector.py b/examples/selection_tools/rectangle_selector.py similarity index 100% rename from examples/desktop/selectors/rectangle_selector.py rename to examples/selection_tools/rectangle_selector.py diff --git a/examples/desktop/selectors/rectangle_selector_zoom.py b/examples/selection_tools/rectangle_selector_zoom.py similarity index 95% rename from examples/desktop/selectors/rectangle_selector_zoom.py rename to examples/selection_tools/rectangle_selector_zoom.py index b5932d820..45633c42b 100644 --- a/examples/desktop/selectors/rectangle_selector_zoom.py +++ b/examples/selection_tools/rectangle_selector_zoom.py @@ -1,6 +1,7 @@ """ -Rectangle Selectors -=================== +Rectangle Selectors Images +========================== + Example showing how to use a `RectangleSelector` with images """ diff --git a/examples/tests/test_examples.py b/examples/tests/test_examples.py index 0143c9bef..55a3fa84d 100644 --- a/examples/tests/test_examples.py +++ b/examples/tests/test_examples.py @@ -2,6 +2,7 @@ Test that examples run without error. """ +import sys import importlib import runpy import pytest @@ -57,20 +58,25 @@ def test_that_we_are_on_lavapipe(): assert is_lavapipe +def import_from_path(module_name, filename): + spec = importlib.util.spec_from_file_location(module_name, filename) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + + # With this approach the module is not added to sys.modules, which + # is great, because that way the gc can simply clean up when we lose + # the reference to the module + assert module.__name__ == module_name + assert module_name not in sys.modules + + return module + + @pytest.mark.parametrize("module", examples_to_test, ids=lambda x: x.stem) def test_example_screenshots(module, force_offscreen): """Make sure that every example marked outputs the expected.""" - # (relative) module name from project root - module_name = ( - module.relative_to(ROOT / "examples") - .with_suffix("") - .as_posix() - .replace("/", ".") - ) - print(pygfx.renderers.wgpu.get_shared().device.limits["max-texture-dimension2d"]) - # import the example module - example = importlib.import_module(module_name) + example = import_from_path(module.stem, module) # there doesn't seem to be a resize event for the manual offscreen canvas example.figure.imgui_renderer._backend.io.display_size = example.figure.canvas.get_logical_size() diff --git a/examples/tests/testutils.py b/examples/tests/testutils.py index 3db6901ef..f72a87123 100644 --- a/examples/tests/testutils.py +++ b/examples/tests/testutils.py @@ -11,7 +11,7 @@ ROOT = Path(__file__).parents[2] # repo root -examples_dir = ROOT / "examples" / "desktop" +examples_dir = ROOT / "examples" screenshots_dir = examples_dir / "screenshots" diffs_dir = examples_dir / "diffs" @@ -25,7 +25,7 @@ "line_collection/*.py", "gridplot/*.py", "misc/*.py", - "selectors/*.py", + "selection_tools/*.py", "guis/*.py", ] diff --git a/fastplotlib/graphics/selectors/_linear.py b/fastplotlib/graphics/selectors/_linear.py index eec4cc910..ae3648f5e 100644 --- a/fastplotlib/graphics/selectors/_linear.py +++ b/fastplotlib/graphics/selectors/_linear.py @@ -160,9 +160,9 @@ def __init__( self._handled_widgets = list() if axis == "x": - offset = (parent.offset[0], center, 0) + offset = (parent.offset[0], center + parent.offset[1], 0) elif axis == "y": - offset = (center, parent.offset[1], 0) + offset = (center + parent.offset[0], parent.offset[1], 0) # init base selector BaseSelector.__init__( diff --git a/fastplotlib/graphics/selectors/_linear_region.py b/fastplotlib/graphics/selectors/_linear_region.py index ecc67b885..f83385d76 100644 --- a/fastplotlib/graphics/selectors/_linear_region.py +++ b/fastplotlib/graphics/selectors/_linear_region.py @@ -211,9 +211,9 @@ def __init__( # TODO: if parent offset changes, we should set the selector offset too # TODO: add check if parent is `None`, will throw error otherwise if axis == "x": - offset = (parent.offset[0], center, 0) + offset = (parent.offset[0], center + parent.offset[1], 0) elif axis == "y": - offset = (center, parent.offset[1], 0) + offset = (center + parent.offset[1], parent.offset[1], 0) # set the initial bounds of the selector # compensate for any offset from the parent graphic diff --git a/setup.py b/setup.py index 46b68fae6..f4b5eb5db 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ "docs": [ "sphinx", "sphinx-gallery", - "furo", + "pydata-sphinx-theme", "glfw", "jupyter-rfb>=0.4.1", # required so ImageWidget docs show up "ipywidgets>=8.0.0,<9",