diff --git a/.gitattributes b/.gitattributes
index 24a8e8793..e4a509285 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,3 @@
*.png filter=lfs diff=lfs merge=lfs -text
+*.npy filter=lfs diff=lfs merge=lfs -text
+
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7c15e3865..fddfae5f4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -17,7 +17,7 @@ jobs:
docs-build:
name: Docs
- runs-on: ubuntu-latest
+ runs-on: bigmem
strategy:
fail-fast: false
steps:
@@ -48,7 +48,7 @@ jobs:
test-build-full:
name: Test examples, env with notebook and glfw
- runs-on: ubuntu-latest
+ runs-on: bigmem
if: ${{ !github.event.pull_request.draft }}
strategy:
fail-fast: false
@@ -74,7 +74,7 @@ jobs:
- name: Install llvmpipe and lavapipe for offscreen canvas
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
+ 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
@@ -105,7 +105,7 @@ jobs:
test-build-desktop:
name: Test examples, env with only glfw
- runs-on: ubuntu-latest
+ runs-on: bigmem
if: ${{ !github.event.pull_request.draft }}
strategy:
fail-fast: false
diff --git a/.github/workflows/screenshots.yml b/.github/workflows/screenshots.yml
index 40f55d234..d3cdb919b 100644
--- a/.github/workflows/screenshots.yml
+++ b/.github/workflows/screenshots.yml
@@ -13,7 +13,7 @@ on:
jobs:
screenshots:
name: Regenerate
- runs-on: 'ubuntu-latest'
+ runs-on: bigmem
if: ${{ !github.event.pull_request.draft }}
steps:
- name: Install git-lfs
@@ -27,7 +27,7 @@ jobs:
- name: Install llvmpipe and lavapipe for offscreen canvas
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
+ sudo apt-get install --no-install-recommends -y ffmpeg libegl1-mesa libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers
- name: Install dev dependencies
run: |
python -m pip install --upgrade pip setuptools
@@ -38,6 +38,10 @@ jobs:
- name: Show wgpu backend
run:
python -c "from examples.tests.testutils import wgpu_backend; print(wgpu_backend)"
+ - name: fetch git lfs files
+ run: |
+ git lfs fetch --all
+ git lfs pull
- name: Test examples
env:
PYGFX_EXPECT_LAVAPIPE: true
diff --git a/README.md b/README.md
index 0f9ccf547..eb64f3cc3 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@
[**Installation**](https://github.com/kushalkolar/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) |
[**Contributing**](https://github.com/kushalkolar/fastplotlib#heart-contributing)
@@ -35,7 +36,7 @@ Notebooks from talk: https://github.com/fastplotlib/fastplotlib-scipy2023
:heavy_check_mark: `wxPython`
**Notes:**\
-:heavy_check_mark: You can use a non-blocking `glfw` canvas from a notebook, as long as you're working locally or have a way to forward the remote graphical desktop (such as X11 forwarding).\
+:heavy_check_mark: Non-blocking Qt output is supported in ipython and notebooks by using [`%gui qt`](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-gui) before creating plots. This hook only supports pyqt6 at the moment.\
:grey_exclamation: We do not officially support `jupyter notebook` through `jupyter_rfb`, this may change with notebook v7\
:disappointed: [`jupyter_rfb`](https://github.com/vispy/jupyter_rfb) does not work in collab yet, see https://github.com/vispy/jupyter_rfb/pull/77
@@ -167,4 +168,4 @@ WGPU uses Metal instead of Vulkan on Mac. You will need at least Mac OSX 10.13.
We welcome contributions! See the contributing guide: https://github.com/kushalkolar/fastplotlib/blob/main/CONTRIBUTING.md
-You can also take a look at our [**Roadmap for 2023**](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 2024**](https://github.com/kushalkolar/fastplotlib/issues/55) and [**Issues**](https://github.com/kushalkolar/fastplotlib/issues) for ideas on how to contribute!
diff --git a/docs/source/quickstart.ipynb b/docs/source/quickstart.ipynb
index 6a3afec33..0de4667bf 100644
--- a/docs/source/quickstart.ipynb
+++ b/docs/source/quickstart.ipynb
@@ -97,21 +97,7 @@
"id": "be5b408f-dd91-4e36-807a-8c22c8d7d216",
"metadata": {},
"source": [
- "**In live notebooks or desktop applications, you can use the handle on the bottom right corner of the _canvas_ to resize it. You can also pan and zoom using your mouse!**\n",
- "\n",
- "By default the origin is on the bottom left, you can click the flip button to flip the y-axis, or use `plot.camera.world.scale_y *= -1`"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "9b4e977e-2a7d-4e2b-aee4-cfc36767b3c6",
- "metadata": {
- "tags": []
- },
- "outputs": [],
- "source": [
- "plot.camera.world.scale_y *= -1"
+ "**In live notebooks or desktop applications, you can use the handle on the bottom right corner of the _canvas_ to resize it. You can also pan and zoom using your mouse!**"
]
},
{
@@ -510,18 +496,6 @@
"plot_rgb.show()"
]
},
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7e4b5a30-4293-4ae3-87dc-06a1355bb2c7",
- "metadata": {
- "tags": []
- },
- "outputs": [],
- "source": [
- "plot_rgb.camera.world.scale_y *= -1"
- ]
- },
{
"cell_type": "code",
"execution_count": null,
@@ -1361,7 +1335,7 @@
"outputs": [],
"source": [
"# GridPlot of shape 2 x 3 with all controllers synced\n",
- "grid_plot = fpl.GridPlot(shape=(2, 3), controllers=\"sync\")\n",
+ "grid_plot = fpl.GridPlot(shape=(2, 3), controller_ids=\"sync\")\n",
"\n",
"# Make a random image graphic for each subplot\n",
"for subplot in grid_plot:\n",
@@ -1549,7 +1523,7 @@
"# pan-zoom controllers for each view\n",
"# views are synced if they have the \n",
"# same controller ID\n",
- "controllers = [\n",
+ "controller_ids = [\n",
" [0, 3, 1], # id each controller with an integer\n",
" [2, 2, 3]\n",
"]\n",
@@ -1564,7 +1538,7 @@
"# Create the grid plot\n",
"grid_plot = fpl.GridPlot(\n",
" shape=grid_shape,\n",
- " controllers=controllers,\n",
+ " controller_ids=controller_ids,\n",
" names=names,\n",
")\n",
"\n",
@@ -1678,18 +1652,6 @@
"grid_plot[1, 0][\"rand-image\"].vim = 0.1\n",
"grid_plot[1, 0][\"rand-image\"].vmax = 0.3"
]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "8a5753b9-ee71-4ed1-bb0d-52bdb4ea365f",
- "metadata": {
- "tags": []
- },
- "outputs": [],
- "source": [
- "grid_plot[1, 0][\"rand-image\"].type"
- ]
}
],
"metadata": {
diff --git a/examples/desktop/gridplot/gridplot_non_square.py b/examples/desktop/gridplot/gridplot_non_square.py
index a41bcd9f4..fe43a3c04 100644
--- a/examples/desktop/gridplot/gridplot_non_square.py
+++ b/examples/desktop/gridplot/gridplot_non_square.py
@@ -10,7 +10,7 @@
import imageio.v3 as iio
-plot = fpl.GridPlot(shape=(2, 2), controllers="sync")
+plot = fpl.GridPlot(shape=(2, 2), controller_ids="sync")
# to force a specific framework such as glfw:
# plot = fpl.GridPlot(canvas="glfw")
diff --git a/examples/desktop/scatter/scatter_size.py b/examples/desktop/scatter/scatter_size.py
index 5b6987b7c..2ad995584 100644
--- a/examples/desktop/scatter/scatter_size.py
+++ b/examples/desktop/scatter/scatter_size.py
@@ -9,16 +9,7 @@
import fastplotlib as fpl
# grid with 2 rows and 3 columns
-grid_shape = (2,1)
-
-# pan-zoom controllers for each view
-# views are synced if they have the
-# same controller ID
-controllers = [
- [0],
- [0]
-]
-
+grid_shape = (2, 1)
# you can give string names for each subplot within the gridplot
names = [
@@ -29,7 +20,6 @@
# Create the grid plot
plot = fpl.GridPlot(
shape=grid_shape,
- controllers=controllers,
names=names,
size=(1000, 1000)
)
@@ -53,4 +43,4 @@
if __name__ == "__main__":
print(__doc__)
- fpl.run()
\ No newline at end of file
+ fpl.run()
diff --git a/examples/desktop/screenshots/gridplot.png b/examples/desktop/screenshots/gridplot.png
index f2cbb1e7a..bc35ccf8c 100644
--- a/examples/desktop/screenshots/gridplot.png
+++ b/examples/desktop/screenshots/gridplot.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2705c69adab84f7740322b4a66ce33df00001dc7d51624becb8e88204113b028
-size 350236
+oid sha256:e416fc968edd3788513e369f4d265b0abd7216a7ef19ec8b84659c30ca7c8ca1
+size 307384
diff --git a/examples/desktop/screenshots/gridplot_non_square.png b/examples/desktop/screenshots/gridplot_non_square.png
index 7b534aef9..82b2b0eb4 100644
--- a/examples/desktop/screenshots/gridplot_non_square.png
+++ b/examples/desktop/screenshots/gridplot_non_square.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:abf936904d1b5e2018a72311c510108925f2972dfdf59166580ad27876f9e2be
-size 220140
+oid sha256:ab5598b67b80efce0d2559e400e77098e734c91608a3f49b691ddaa030d47edb
+size 203434
diff --git a/examples/desktop/screenshots/heatmap.png b/examples/desktop/screenshots/heatmap.png
index d0df1510a..a0655cf3a 100644
--- a/examples/desktop/screenshots/heatmap.png
+++ b/examples/desktop/screenshots/heatmap.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6c19d6454e79d92074bac01175dfbb8506e882ea55b626c0b2357960ed6e294f
-size 163655
+oid sha256:6872c3cc3e35ec918b054fb2d76525bbd3d82d8b49916aca1046aa1be65ff923
+size 111825
diff --git a/examples/desktop/screenshots/heatmap_cmap.png b/examples/desktop/screenshots/heatmap_cmap.png
index db3038dee..2eb769c14 100644
--- a/examples/desktop/screenshots/heatmap_cmap.png
+++ b/examples/desktop/screenshots/heatmap_cmap.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0328eec32f13042e3e2f243793317e180bba1353fe961604ecad3f38463b8809
-size 156419
+oid sha256:f2eba96c2bfb1d07365810a69e99c79b068741f5dcf74fc745c13d5ff21f16f2
+size 106671
diff --git a/examples/desktop/screenshots/heatmap_data.png b/examples/desktop/screenshots/heatmap_data.png
index 96169ec77..50a8ae79e 100644
--- a/examples/desktop/screenshots/heatmap_data.png
+++ b/examples/desktop/screenshots/heatmap_data.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4a376c24fa123088be69f807ec5212cb5ed5680b146ce9d62df584790c632845
-size 20838
+oid sha256:f0576063658e05e19b7723b4c88dc4d55a8178b090b4a88e33251fc92408b4a1
+size 18051
diff --git a/examples/desktop/screenshots/heatmap_vmin_vmax.png b/examples/desktop/screenshots/heatmap_vmin_vmax.png
index 2a809d545..f10382e87 100644
--- a/examples/desktop/screenshots/heatmap_vmin_vmax.png
+++ b/examples/desktop/screenshots/heatmap_vmin_vmax.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3eb12ad590aa8260f2cf722abadf5b51bcb7d5a8d8d1cb05b7711b50331da07a
-size 165937
+oid sha256:639d50f2f5fb07dba461e7a38de3886092f8754277eadbb5e305e32023289abd
+size 124403
diff --git a/examples/desktop/screenshots/image_cmap.png b/examples/desktop/screenshots/image_cmap.png
index cf3ae8ac0..bed07a41a 100644
--- a/examples/desktop/screenshots/image_cmap.png
+++ b/examples/desktop/screenshots/image_cmap.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d9dcf05ca2953103b9960d9159ccb89dc257bf5e5c6d3906eeaaac9f71686439
-size 274882
+oid sha256:e1d78cc0681079a5c43d9fdb4142f5fee75d477d9f9a1469fca8bc8933c244fc
+size 216210
diff --git a/examples/desktop/screenshots/image_rgb.png b/examples/desktop/screenshots/image_rgb.png
index 5681017c8..a21c0658b 100644
--- a/examples/desktop/screenshots/image_rgb.png
+++ b/examples/desktop/screenshots/image_rgb.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:408e31db97278c584f4aaa0039099366fc8feb5693d15ab335205927d067c42a
-size 319585
+oid sha256:820a73b9b2e5bbaed84fb11438e2c5672b76c8b57a33823f4840a71be03d7dd1
+size 251438
diff --git a/examples/desktop/screenshots/image_rgbvminvmax.png b/examples/desktop/screenshots/image_rgbvminvmax.png
index aea5fdf85..88acfadc5 100644
--- a/examples/desktop/screenshots/image_rgbvminvmax.png
+++ b/examples/desktop/screenshots/image_rgbvminvmax.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d5dbe9a837b3503ca45eb83edbec7b1d7b6463093699af6b01b5303978af4b85
-size 44781
+oid sha256:5f2f562573f8104342ae01b5852f71c960341bdd70ae0bc7967df663166edbd3
+size 39604
diff --git a/examples/desktop/screenshots/image_simple.png b/examples/desktop/screenshots/image_simple.png
index 5ab073433..098d5a055 100644
--- a/examples/desktop/screenshots/image_simple.png
+++ b/examples/desktop/screenshots/image_simple.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4aa397a120ed1b232c4d56ffd3547ea42c2874aa54bfbdbffebfd34129059ccd
-size 272355
+oid sha256:a4ed42d042d8bb7e35f31b5ad0a3e3a495cf9c3164516eb457d8b41d7fae6bab
+size 213075
diff --git a/examples/desktop/screenshots/image_vminvmax.png b/examples/desktop/screenshots/image_vminvmax.png
index aea5fdf85..88acfadc5 100644
--- a/examples/desktop/screenshots/image_vminvmax.png
+++ b/examples/desktop/screenshots/image_vminvmax.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d5dbe9a837b3503ca45eb83edbec7b1d7b6463093699af6b01b5303978af4b85
-size 44781
+oid sha256:5f2f562573f8104342ae01b5852f71c960341bdd70ae0bc7967df663166edbd3
+size 39604
diff --git a/examples/desktop/screenshots/line.png b/examples/desktop/screenshots/line.png
index a38008ab9..cbc0a7b21 100644
--- a/examples/desktop/screenshots/line.png
+++ b/examples/desktop/screenshots/line.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1fe996cd43013ff2e616e8a549933137529c13ad8e320331420e9c64f6ed1690
-size 49738
+oid sha256:018f4a36c60b3de2f1406aa2823b751de5fae2c2340f9d49368d007ba7379637
+size 44422
diff --git a/examples/desktop/screenshots/line_cmap.png b/examples/desktop/screenshots/line_cmap.png
index 0ece6fbde..a07b15d36 100644
--- a/examples/desktop/screenshots/line_cmap.png
+++ b/examples/desktop/screenshots/line_cmap.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c6f511ffd3a10e2c653afd3b9eca8f6bb10af26759a7efc73fe16c825cc1bf15
-size 43718
+oid sha256:c6df49f5f900caa217a5a0b01f601d6e83e1ee5c3a60c8968b9be837df785905
+size 43673
diff --git a/examples/desktop/screenshots/line_collection.png b/examples/desktop/screenshots/line_collection.png
index f7be75201..60ec82bc8 100644
--- a/examples/desktop/screenshots/line_collection.png
+++ b/examples/desktop/screenshots/line_collection.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:4aa71b9b8d2c049dad951493a5f51c32da33a3e536761254cd18368d6b8cd8e8
-size 146755
+oid sha256:e0ddd75bc2fd8e4844ccb46c53fe463dc604927737ed00c8fb6b1c29fd2b1ab2
+size 146797
diff --git a/examples/desktop/screenshots/line_collection_cmap_values.png b/examples/desktop/screenshots/line_collection_cmap_values.png
index a91e4ce69..7223db9ee 100644
--- a/examples/desktop/screenshots/line_collection_cmap_values.png
+++ b/examples/desktop/screenshots/line_collection_cmap_values.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a32210432cd8e88bec20a84b1e6839d0a2d5bb2edb1aea8ebe09569872cb16d8
-size 93580
+oid sha256:311c7ef6f6f46e32983a5a531adc179b0179f382300f3cafbb6d8a7d4aeab565
+size 93676
diff --git a/examples/desktop/screenshots/line_collection_cmap_values_qualitative.png b/examples/desktop/screenshots/line_collection_cmap_values_qualitative.png
index c38e5fb96..500de82bb 100644
--- a/examples/desktop/screenshots/line_collection_cmap_values_qualitative.png
+++ b/examples/desktop/screenshots/line_collection_cmap_values_qualitative.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5be6f9343b47848d3e1be4b82315f0b71bdb1b919503f943c618ef8ba7f6272a
-size 95656
+oid sha256:8714dd43aa3d5c791fb9359e745895447d3a3234e3e8598d171ea3666a3fd7a3
+size 95660
diff --git a/examples/desktop/screenshots/line_collection_colors.png b/examples/desktop/screenshots/line_collection_colors.png
index 1ae597033..f60faae32 100644
--- a/examples/desktop/screenshots/line_collection_colors.png
+++ b/examples/desktop/screenshots/line_collection_colors.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b1e5b913ca91293a8edb8f6898249dd62019cb827223dacf377e3fc6cda89a77
-size 82686
+oid sha256:e2fad15985608a4c6b1fda3005dc89950b4cad5fed956f5d26672257385985d0
+size 82753
diff --git a/examples/desktop/screenshots/line_colorslice.png b/examples/desktop/screenshots/line_colorslice.png
index 003f86e44..7b652f165 100644
--- a/examples/desktop/screenshots/line_colorslice.png
+++ b/examples/desktop/screenshots/line_colorslice.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0033fc23cda3f07cdd7db642d4d1af710319d56a1690339354a9df27bf51c381
-size 57146
+oid sha256:5bd80cee80f491da6ab64c868a3c70254a68072e0bc0caad80c7999cadcb2df9
+size 50497
diff --git a/examples/desktop/screenshots/line_dataslice.png b/examples/desktop/screenshots/line_dataslice.png
index 20c777212..d68a554bd 100644
--- a/examples/desktop/screenshots/line_dataslice.png
+++ b/examples/desktop/screenshots/line_dataslice.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2a169b359a0e56bb48a625069e73e53b26e061e6bcb83d6eb613fbdd1a43cdac
-size 75385
+oid sha256:823651905a775b5cbcc2ce0f79d25d69b29f17b4c060c244d80ae87019f05d5b
+size 69332
diff --git a/examples/desktop/screenshots/line_present_scaling.png b/examples/desktop/screenshots/line_present_scaling.png
index c4a41ac2e..02cd2b1f8 100644
--- a/examples/desktop/screenshots/line_present_scaling.png
+++ b/examples/desktop/screenshots/line_present_scaling.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c67d65b0a5120c014b34dcfc326079113cee22b849c14a0284fc7881dac5d43c
-size 43446
+oid sha256:3d18669d5e75cee3326d0380ae5dd26cab71ea97725ff99bc5228d2555d51454
+size 30373
diff --git a/examples/desktop/screenshots/line_stack.png b/examples/desktop/screenshots/line_stack.png
index 23343df32..443184247 100644
--- a/examples/desktop/screenshots/line_stack.png
+++ b/examples/desktop/screenshots/line_stack.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bc2496c203b2994ef5b8e714e1c7619e726d0b605e0c25498f11e1154d4905ec
-size 360981
+oid sha256:29580e5ebb0597d54adb2b7f2f91de44e4480cf23c0c271ee44426203b4c1c44
+size 360892
diff --git a/examples/desktop/screenshots/scatter.png b/examples/desktop/screenshots/scatter.png
index e35fd9e3c..bf5e8c92a 100644
--- a/examples/desktop/screenshots/scatter.png
+++ b/examples/desktop/screenshots/scatter.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e2efb81fb8b6b11bb1fc3136394c0f6bf1c38972d03dabd07949928f4e53cf71
-size 25240
+oid sha256:bd38399b77e09d915c5bb1e7ee022f936ae90682f598357bc774a95c372dc78f
+size 25231
diff --git a/examples/desktop/screenshots/scatter_cmap.png b/examples/desktop/screenshots/scatter_cmap.png
index 10477e81b..eec22566a 100644
--- a/examples/desktop/screenshots/scatter_cmap.png
+++ b/examples/desktop/screenshots/scatter_cmap.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8b4b364d1cd3ab328f025030db87f8ff4fb2544c3bfb67176ea8f0acdc24f04b
-size 59407
+oid sha256:e712693b403166909dcaa65256131eacba0a15892cd144ad97fdecb6b9835e93
+size 57273
diff --git a/examples/desktop/screenshots/scatter_colorslice.png b/examples/desktop/screenshots/scatter_colorslice.png
index cd5a1f00d..0da0fcd9f 100644
--- a/examples/desktop/screenshots/scatter_colorslice.png
+++ b/examples/desktop/screenshots/scatter_colorslice.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:0d3afcf293e425c2369d93745cb933afb15d971866620f160629e394f50cd9b6
-size 23747
+oid sha256:c620cad9976f390e44a5b037f3ff61fb80e6487e17f4be8118be5df55f276a35
+size 23664
diff --git a/examples/desktop/screenshots/scatter_dataslice.png b/examples/desktop/screenshots/scatter_dataslice.png
index 8ed7ad590..32f56ad11 100644
--- a/examples/desktop/screenshots/scatter_dataslice.png
+++ b/examples/desktop/screenshots/scatter_dataslice.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:974111967bc5e4197b6b38c7a00950ee013ce4e689162c9d91e902d37240221a
-size 26001
+oid sha256:69d2f0999b0bb334e48320702095fc76444f4d89d43a51ac6c5c8f49e1df96ac
+size 25999
diff --git a/examples/desktop/screenshots/scatter_present.png b/examples/desktop/screenshots/scatter_present.png
index 335191d91..8c1e5eed4 100644
--- a/examples/desktop/screenshots/scatter_present.png
+++ b/examples/desktop/screenshots/scatter_present.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fb5b0bf6fb7b7dbfafc1b2553dfff87f329ec5070fb69061313acce46364df52
-size 24627
+oid sha256:e45c1a936771e569e562ed3496421e498e725325093e84243ab494c0718ead3a
+size 23639
diff --git a/examples/desktop/screenshots/scatter_size.png b/examples/desktop/screenshots/scatter_size.png
index 1d0f91f9c..da211cde1 100644
--- a/examples/desktop/screenshots/scatter_size.png
+++ b/examples/desktop/screenshots/scatter_size.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3eb05d8a18aada52a6ab02a0d3d030aab97510aace226cf3967e5c5c1cd3274d
-size 66044
+oid sha256:10533aa5831a50a0f9b38c0a60b89a9b6c33311ecb3a569c5e0b4c82379dc20a
+size 66037
diff --git a/examples/notebooks/gridplot.ipynb b/examples/notebooks/gridplot.ipynb
index cfcae3705..f1ceb2180 100644
--- a/examples/notebooks/gridplot.ipynb
+++ b/examples/notebooks/gridplot.ipynb
@@ -10,7 +10,7 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": null,
"id": "a635b3b3-33fa-48f0-b1cc-bf83b1e883ab",
"metadata": {},
"outputs": [],
@@ -21,52 +21,10 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": null,
"id": "8de931e2-bdb3-44a3-9538-e0b3965779af",
"metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "62f67ebf3b00494c826d92fc5b8bbf76",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "RFBOutputContext()"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "text/html": [
- "

initial snapshot
"
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "b6262056cff84619aea08fc48d00eb79",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "JupyterWgpuCanvas()"
- ]
- },
- "execution_count": 2,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# grid with 2 rows and 3 columns\n",
"grid_shape = (2, 3)\n",
@@ -74,9 +32,15 @@
"# pan-zoom controllers for each view\n",
"# views are synced if they have the \n",
"# same controller ID\n",
- "controllers = [\n",
- " [0, 3, 1], # id each controller with an integer\n",
- " [2, 2, 3]\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",
@@ -89,7 +53,7 @@
"# Create the grid plot\n",
"grid_plot = GridPlot(\n",
" shape=grid_shape,\n",
- " controllers=controllers,\n",
+ " controller_ids=controller_ids,\n",
" names=names,\n",
")\n",
"\n",
@@ -123,24 +87,10 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": null,
"id": "2a6f7eb5-776e-42a6-b6c2-c26009a26795",
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "subplot0: Subplot @ 0x7fd496b32830\n",
- " parent: None\n",
- " Graphics:\n",
- "\t'rand-image': ImageGraphic @ 0x7fd496b327d0"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# can access subplot by name\n",
"grid_plot[\"subplot0\"]"
@@ -148,24 +98,10 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": null,
"id": "45e83bca-5a44-48ce-874f-9ae9ca444233",
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "subplot0: Subplot @ 0x7fd496b32830\n",
- " parent: None\n",
- " Graphics:\n",
- "\t'rand-image': ImageGraphic @ 0x7fd496b327d0"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# can access subplot by index\n",
"grid_plot[0, 0]"
@@ -182,21 +118,10 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": null,
"id": "c8cf9bfd-e0cc-4173-b64e-a9f2c87bb2c6",
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "'rand-image': ImageGraphic @ 0x7fd496b327d0"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# can access graphic directly via name\n",
"grid_plot[\"subplot0\"][\"rand-image\"]"
@@ -204,13 +129,13 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": null,
"id": "1cfd1d45-8a60-4fc1-b873-46caa966fe6f",
"metadata": {},
"outputs": [],
"source": [
- "grid_plot[\"subplot0\"][\"rand-image\"].vmin = 0.6\n",
- "grid_plot[\"subplot0\"][\"rand-image\"].vmax = 0.8"
+ "grid_plot[\"subplot0\"][\"rand-image\"].cmap.vmin = 0.6\n",
+ "grid_plot[\"subplot0\"][\"rand-image\"].cmap.vmax = 0.8"
]
},
{
@@ -223,40 +148,19 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": null,
"id": "2fafe992-4783-40f2-b044-26a2835dd50a",
"metadata": {},
"outputs": [],
"source": [
- "grid_plot[1, 0][\"rand-image\"].vim = 0.1\n",
- "grid_plot[1, 0][\"rand-image\"].vmax = 0.3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "id": "a025b76c-77f8-4aeb-ac33-5bb6d0bb5a9a",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "'image'"
- ]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "grid_plot[1, 0][\"rand-image\"].type"
+ "grid_plot[1, 0][\"rand-image\"].cmap.vim = 0.1\n",
+ "grid_plot[1, 0][\"rand-image\"].cmap.vmax = 0.3"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "62584f91-a8ed-4317-98ee-28ad6d1800d6",
+ "id": "a61e34a5-ee1b-4abb-8718-ec4715ffaa52",
"metadata": {},
"outputs": [],
"source": []
@@ -278,7 +182,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.10.5"
+ "version": "3.11.3"
}
},
"nbformat": 4,
diff --git a/examples/notebooks/gridplot_simple.ipynb b/examples/notebooks/gridplot_simple.ipynb
index 8b50b2701..74807f55a 100644
--- a/examples/notebooks/gridplot_simple.ipynb
+++ b/examples/notebooks/gridplot_simple.ipynb
@@ -10,9 +10,13 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "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": [],
@@ -23,38 +27,19 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "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": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "f9067cd724094b8c8dfecf60208acbfa",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "RFBOutputContext()"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "/home/clewis7/repos/fastplotlib/fastplotlib/graphics/_features/_base.py:34: UserWarning: converting float64 array to float32\n",
- " warn(f\"converting {array.dtype} array to float32\")\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"# GridPlot of shape 2 x 3 with all controllers synced\n",
- "grid_plot = GridPlot(shape=(2, 3), controllers=\"sync\")\n",
+ "grid_plot = GridPlot(shape=(2, 3), controller_ids=\"sync\")\n",
"\n",
"# Make a random image graphic for each subplot\n",
"for subplot in grid_plot:\n",
@@ -88,27 +73,22 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": null,
+ "id": "52163bc7-2c77-4699-b7b0-e455a0ed7584",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "grid_plot"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
"id": "17c6bc4a-5340-49f1-8597-f54528cfe915",
"metadata": {
"tags": []
},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "unnamed: Subplot @ 0x7f15df4f5c50\n",
- " parent: fastplotlib.GridPlot @ 0x7f15d3f27890\n",
- "\n",
- " Graphics:\n",
- "\t'rand-img': ImageGraphic @ 0x7f15d3fb5390"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# positional indexing\n",
"# row 0 and col 0\n",
@@ -125,23 +105,12 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": null,
"id": "34130f12-9ef6-43b0-b929-931de8b7da25",
"metadata": {
"tags": []
},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(,)"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"grid_plot[0, 1].graphics"
]
@@ -156,7 +125,7 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": null,
"id": "ef8a29a6-b19c-4e6b-a2ba-fb4823c01451",
"metadata": {
"tags": []
@@ -176,7 +145,7 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": null,
"id": "d6c2fa4b-c634-4dcf-8b61-f1986f7c4918",
"metadata": {
"tags": []
@@ -189,50 +158,24 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": null,
"id": "2f6b549c-3165-496d-98aa-45b96c3de674",
"metadata": {
"tags": []
},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "top-right-plot: Subplot @ 0x7f15d3f769d0\n",
- " parent: fastplotlib.GridPlot @ 0x7f15d3f27890\n",
- "\n",
- " Graphics:\n",
- "\t'rand-img': ImageGraphic @ 0x7f15b83f7250"
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"grid_plot[\"top-right-plot\"]"
]
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": null,
"id": "be436e04-33a6-4597-8e6a-17e1e5225419",
"metadata": {
"tags": []
},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(0, 2)"
- ]
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# view its position\n",
"grid_plot[\"top-right-plot\"].position"
@@ -240,23 +183,12 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": null,
"id": "6699cda6-af86-4258-87f5-1832f989a564",
"metadata": {
"tags": []
},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 13,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# these are really the same\n",
"grid_plot[\"top-right-plot\"] is grid_plot[0, 2]"
@@ -272,19 +204,19 @@
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": null,
"id": "545b627b-d794-459a-a75a-3fde44f0ea95",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
- "grid_plot[\"top-right-plot\"][\"rand-img\"].vmin = 0.5"
+ "grid_plot[\"top-right-plot\"][\"rand-img\"].cmap.vmin = 0.5"
]
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": null,
"id": "36432d5b-b76c-4a2a-a32c-097faf5ab269",
"metadata": {
"tags": []
diff --git a/examples/notebooks/image_widget.ipynb b/examples/notebooks/image_widget.ipynb
index d8f91c1be..56d5c8a81 100644
--- a/examples/notebooks/image_widget.ipynb
+++ b/examples/notebooks/image_widget.ipynb
@@ -10,7 +10,9 @@
"outputs": [],
"source": [
"from fastplotlib.widgets import ImageWidget\n",
- "import numpy as np"
+ "import numpy as np\n",
+ "\n",
+ "import imageio.v3 as iio # not a fastplotlib dependency, only used for examples"
]
},
{
@@ -30,7 +32,8 @@
},
"outputs": [],
"source": [
- "a = np.random.rand(512, 512)"
+ "# image widget only supports grayscale images for now\n",
+ "a = iio.imread(\"imageio:camera.png\")"
]
},
{
@@ -63,7 +66,7 @@
"id": "b718162f-9aa6-4091-a7a4-c620676b48bd",
"metadata": {},
"source": [
- "### can dynamically change features"
+ "### Access graphics managed by the image widget"
]
},
{
@@ -75,7 +78,7 @@
},
"outputs": [],
"source": [
- "iw.gridplot[0, 0].graphics[0].cmap = \"gnuplot2\""
+ "iw.gridplot[0, 0][\"image_widget_managed\"].cmap = \"gnuplot2\""
]
},
{
@@ -95,7 +98,10 @@
},
"outputs": [],
"source": [
- "a = np.random.rand(500, 512, 512)"
+ "movie = iio.imread(\"imageio:cockatoo.mp4\")\n",
+ "\n",
+ "# convert RGB movie to grayscale, this could take a minute\n",
+ "gray_movie = np.dot(movie[..., :3], [0.299, 0.587, 0.114])"
]
},
{
@@ -107,10 +113,10 @@
},
"outputs": [],
"source": [
- "iw2 = ImageWidget(\n",
- " data=a, \n",
+ "iw_movie = ImageWidget(\n",
+ " data=gray_movie, \n",
" slider_dims=[\"t\"],\n",
- " cmap=\"gnuplot2\"\n",
+ " cmap=\"gray\"\n",
")"
]
},
@@ -123,7 +129,7 @@
},
"outputs": [],
"source": [
- "iw2.show()"
+ "iw_movie.show(sidecar=True)"
]
},
{
@@ -146,7 +152,7 @@
"outputs": [],
"source": [
"# must be in the form of {dim: (func, window_size)}\n",
- "iw2.window_funcs = {\"t\": (np.mean, 13)}"
+ "iw_movie.window_funcs = {\"t\": (np.mean, 13)}"
]
},
{
@@ -159,7 +165,7 @@
"outputs": [],
"source": [
"# change the winow size\n",
- "iw2.window_funcs[\"t\"].window_size = 23"
+ "iw_movie.window_funcs[\"t\"].window_size = 33"
]
},
{
@@ -172,7 +178,7 @@
"outputs": [],
"source": [
"# change the function\n",
- "iw2.window_funcs[\"t\"].func = np.max"
+ "iw_movie.window_funcs[\"t\"].func = np.max"
]
},
{
@@ -184,8 +190,8 @@
},
"outputs": [],
"source": [
- "# or set it again\n",
- "iw2.window_funcs = {\"t\": (np.min, 11)}"
+ "# or reset it\n",
+ "iw_movie.window_funcs = None"
]
},
{
@@ -196,6 +202,26 @@
"### Can also set new data"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f9ee0e42-3d41-4613-a508-042c6c2c27e3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "new_data = iio.imread(\"imageio:stent.npz\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b85d2e08-1479-46fc-a429-2d7a265493d4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "new_data.shape"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
@@ -205,8 +231,18 @@
},
"outputs": [],
"source": [
- "new_data = np.random.rand(500, 512, 512)\n",
- "iw2.set_data(new_data=new_data)"
+ "iw_movie.set_data(new_data=new_data)\n",
+ "iw_movie.gridplot[0, 0].auto_scale()# sidecar is optional"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3d323f67-4717-4241-ad84-5091e6caf2cd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "iw_movie.close()"
]
},
{
@@ -214,7 +250,7 @@
"id": "aca22179-1b1f-4c51-97bf-ce2d7044e451",
"metadata": {},
"source": [
- "# Gridplot of txy data"
+ "# Gridplot of tzxy data"
]
},
{
@@ -226,8 +262,29 @@
},
"outputs": [],
"source": [
- "dims = (100, 512, 512)\n",
- "data = [np.random.rand(*dims) for i in range(4)]"
+ "zfish_data = np.load(\"./zfish_test.npy\")\n",
+ "# snippet of a dataset from Martin Haesemeyer"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b015720c-3de1-4575-80c5-d6eabe4b305f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# data is tzxy\n",
+ "zfish_data.shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fdff388e-d44c-41ff-a177-801f2695fb88",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "n_planes = zfish_data.shape[1]"
]
},
{
@@ -239,22 +296,20 @@
},
"outputs": [],
"source": [
- "iw3 = ImageWidget(\n",
- " data=data, \n",
- " slider_dims=[\"t\"], \n",
- " # dims_order=\"txy\", # you can set this manually if dim order is not the usual\n",
- " names=[\"zero\", \"one\", \"two\", \"three\"],\n",
+ "iw_zfish = ImageWidget(\n",
+ " data=[zfish_data[:, i] for i in range(n_planes)],\n",
" window_funcs={\"t\": (np.mean, 5)},\n",
+ " names=[f\"plane-{i}\" for i in range(n_planes)],\n",
" cmap=\"gnuplot2\", \n",
")"
]
},
{
"cell_type": "markdown",
- "id": "0721dc40-677e-431d-94c6-da59606199cb",
+ "id": "037d899e-9e7c-4d58-a021-5f5b71e1db90",
"metadata": {},
"source": [
- "### pan-zoom controllers are all synced in a `ImageWidget`"
+ "pan-zoom controllers are all synced across subplots in a `ImageWidget`"
]
},
{
@@ -266,7 +321,7 @@
},
"outputs": [],
"source": [
- "iw3.show()"
+ "iw_zfish.show(sidecar=True)"
]
},
{
@@ -274,7 +329,7 @@
"id": "82545214-13c4-475e-87da-962117085834",
"metadata": {},
"source": [
- "### Index the subplots using the names given to `ImageWidget`"
+ "Access the subplots using the names given to `ImageWidget`"
]
},
{
@@ -286,7 +341,7 @@
},
"outputs": [],
"source": [
- "iw3.gridplot[\"two\"]"
+ "iw_zfish.gridplot[\"plane-2\"]"
]
},
{
@@ -294,7 +349,7 @@
"id": "dc727d1a-681e-4cbf-bfb2-898ceb31cbe0",
"metadata": {},
"source": [
- "### change window functions just like before"
+ "change window functions"
]
},
{
@@ -306,70 +361,110 @@
},
"outputs": [],
"source": [
- "iw3.window_funcs[\"t\"].func = np.max"
+ "iw_zfish.window_funcs[\"t\"].func = np.max"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ceeab465-bafa-4834-8775-d0e35bc5c880",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "iw_zfish.window_funcs = None"
]
},
{
"cell_type": "markdown",
- "id": "3e89c10f-6e34-4d63-9805-88403d487432",
+ "id": "8e16a503-0213-4e83-abd3-d1fd202cc193",
"metadata": {},
"source": [
- "## Gridplot of volumetric data"
+ "**Frame-apply functions**\n",
+ "\n",
+ "These are applied on a frame before being displayed in the `ImageGraphic`"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "b1587410-a08e-484c-8795-195a413d6374",
- "metadata": {
- "tags": []
- },
+ "id": "9557f0a1-b8fd-4dfe-ac3f-47c90ce78625",
+ "metadata": {},
"outputs": [],
"source": [
- "dims = (256, 256, 5, 100)\n",
- "data = [np.random.rand(*dims) for i in range(4)]\n",
- "\n",
- "iw4 = ImageWidget(\n",
- " data=data, \n",
- " slider_dims=[\"t\", \"z\"], \n",
- " dims_order=\"xyzt\", # example of how you can set this for non-standard orders\n",
- " names=[\"zero\", \"one\", \"two\", \"three\"],\n",
- " # window_funcs={\"t\": (np.mean, 5)}, # window functions can be slow when indexing multiple dims\n",
- " cmap=\"gnuplot2\", \n",
- ")"
+ "# scipy isn't a fastplotlib dependency, it's just used for this example\n",
+ "from scipy.ndimage import gaussian_filter"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "3ccea6c6-9580-4720-bce8-a5507cf867a3",
- "metadata": {
- "tags": []
- },
+ "id": "f87d7e33-93bc-46e3-9cd1-6c648b132841",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "iw_zfish.frame_apply = lambda frame: gaussian_filter(frame.astype(np.float32), sigma=3)\n",
+ "iw_zfish.reset_vmin_vmax()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8b0aa161-89f1-48e4-9976-4a6996f1e7e9",
+ "metadata": {},
"outputs": [],
"source": [
- "iw4.show()"
+ "# remove the frame-apply function\n",
+ "iw_zfish.frame_apply = None\n",
+ "iw_zfish.reset_vmin_vmax()"
]
},
{
"cell_type": "markdown",
- "id": "2382809c-4c7d-4da4-9955-71d316dee46a",
+ "id": "3e89c10f-6e34-4d63-9805-88403d487432",
"metadata": {},
"source": [
- "### window functions, can be slow when you have \"t\" and \"z\""
+ "## z-sliders\n",
+ "\n",
+ "ImageWidget will also give you a slider for \"z\" in addition to \"t\" if necessary. \n",
+ "\n",
+ "This example uses the same example data shown above, but displays them in a single subplot and `ImageWidget` provides a z-slider. You can use `window_funcs`, `frame_apply` funcs, etc. There is no difference in `ImageWidget` behavior with the z-slider."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b1587410-a08e-484c-8795-195a413d6374",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "iw_z = ImageWidget(\n",
+ " data=zfish_data, # you can also provide a list of tzxy arrays\n",
+ " window_funcs={\"t\": (np.mean, 5)},\n",
+ " cmap=\"gnuplot2\", \n",
+ ")"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "fd4433a9-2add-417c-a618-5891371efae0",
+ "id": "3ccea6c6-9580-4720-bce8-a5507cf867a3",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
- "iw4.window_funcs = {\"t\": (np.mean, 11)}"
+ "iw_z.show()"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "aba0fa3a-f844-4937-8615-adbded02345d",
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
diff --git a/examples/notebooks/image_widget_test.ipynb b/examples/notebooks/image_widget_test.ipynb
new file mode 100644
index 000000000..90747757c
--- /dev/null
+++ b/examples/notebooks/image_widget_test.ipynb
@@ -0,0 +1,470 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "07019035-83f2-4753-9e7c-628ae439b441",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "from fastplotlib.widgets import ImageWidget\n",
+ "import numpy as np\n",
+ "from scipy.ndimage import gaussian_filter\n",
+ "\n",
+ "import imageio.v3 as iio"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "10b8ab40-944d-472c-9b7e-cae8a129e7ce",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from nb_test_utils import plot_test, notebook_finished "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0a9fe48a-cc24-4ecf-b442-b7425ce338d3",
+ "metadata": {},
+ "source": [
+ "# Single image"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "01dd4b84-2960-4c26-8162-f0499698e593",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "a = iio.imread(\"imageio:camera.png\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f9d98a12-9574-4b47-9271-013e659cb93f",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "iw = ImageWidget(\n",
+ " data=a,\n",
+ " cmap=\"viridis\"\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e9d86a12-b5f2-4ad7-bd70-4715c80b5ece",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "iw.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "920ef882-e5e6-45b6-b002-5ed26aa3134e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plot_test(\"image-widget-single\", iw.gridplot)\n",
+ "iw.gridplot[0, 0][\"image_widget_managed\"].cmap = \"gnuplot2\"\n",
+ "plot_test(\"image-widget-single-gnuplot2\", iw.gridplot)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "26120b76-c7b0-4e23-bdb1-411be1944687",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "iw.close()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ffde9820-b388-4f22-b7fd-d55a2ad421ad",
+ "metadata": {},
+ "source": [
+ "# Single image sequence"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2067c88f-2b71-4036-a413-59355fa64292",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "movie = iio.imread(\"imageio:cockatoo.mp4\")\n",
+ "\n",
+ "# convert RGB movie to grayscale, this could take a minute\n",
+ "gray_movie = np.dot(movie[..., :3], [0.299, 0.587, 0.114])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "05d3a905-849b-42ae-82ac-34bdc28c1414",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "iw_movie = ImageWidget(\n",
+ " data=gray_movie, \n",
+ " slider_dims=[\"t\"],\n",
+ " cmap=\"gray\"\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "92df8b8c-8d9f-4111-9b3b-fdab7cc7b3f4",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "iw_movie.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ac0a7fc0-0323-4b9e-8c70-3ddc735b7893",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# testing cell ignore\n",
+ "assert iw_movie.sliders[\"t\"].max == gray_movie.shape[0] - 1\n",
+ "assert iw_movie.sliders[\"t\"].min == 0\n",
+ "plot_test(\"image-widget-movie-single-0\", iw_movie.gridplot)\n",
+ "iw_movie.sliders[\"t\"].value = 50\n",
+ "plot_test(\"image-widget-movie-single-50\", iw_movie.gridplot)\n",
+ "iw_movie.sliders[\"t\"].value = 279\n",
+ "plot_test(\"image-widget-movie-single-279\", iw_movie.gridplot)\n",
+ "iw_movie.sliders[\"t\"].value = 0\n",
+ "plot_test(\"image-widget-movie-single-0-reset\", iw_movie.gridplot)\n",
+ "iw_movie.sliders[\"t\"].value = 50\n",
+ "iw_movie.window_funcs = {\"t\": (np.mean, 13)}\n",
+ "# testing cell ignore\n",
+ "plot_test(\"image-widget-movie-single-50-window-mean-13\", iw_movie.gridplot)\n",
+ "iw_movie.window_funcs[\"t\"].window_size = 33\n",
+ "plot_test(\"image-widget-movie-single-50-window-mean-33\", iw_movie.gridplot)\n",
+ "iw_movie.window_funcs[\"t\"].func = np.max\n",
+ "plot_test(\"image-widget-movie-single-50-window-max-33\", iw_movie.gridplot)\n",
+ "iw_movie.window_funcs = None\n",
+ "plot_test(\"image-widget-movie-single-50-window-reset\", iw_movie.gridplot)\n",
+ "iw_movie.sliders[\"t\"].value = 0"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c5fb9aaa-b1a8-46b9-81a5-a656183ab16d",
+ "metadata": {},
+ "source": [
+ "# Set new data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e1730287-41de-4166-8d00-36ae2daabb47",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "new_data = iio.imread(\"imageio:stent.npz\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9010dd43-83c8-4807-8874-71af8ef5c955",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "iw_movie.set_data(new_data=new_data)\n",
+ "iw_movie.gridplot[0, 0].auto_scale()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "06e6f4fb-fe58-40f0-adf0-191e02cdbd75",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plot_test(\"image-widget-movie-set_data\", iw_movie.gridplot)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e5d55d4e-57f2-4460-b252-7a9d21f7c217",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "iw_movie.close()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d2e6819b-209a-49af-97b7-0b8956023d1a",
+ "metadata": {},
+ "source": [
+ "# zfish"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cf9845b6-1cda-403b-96cd-e2b51803c96a",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "zfish_data = np.load(\"./zfish_test.npy\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f7f0315a-29c0-4852-9d49-edaeb3ee45c6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# data is tzxy\n",
+ "zfish_data.shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "67e840fa-9eb9-4705-ab85-ec981ba29abb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "n_planes = zfish_data.shape[1]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "76535d56-e514-4c16-aa48-a6359f8019d5",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "iw_zfish = ImageWidget(\n",
+ " data=[zfish_data[:, i] for i in range(n_planes)],\n",
+ " window_funcs={\"t\": (np.mean, 5)},\n",
+ " names=[f\"plane-{i}\" for i in range(n_planes)],\n",
+ " cmap=\"gnuplot2\", \n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "13904849-cbc5-41e7-ad90-d6e8a4fc0077",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "iw_zfish.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "75e8cf08-f1d2-414c-84a2-1ba4c2a01072",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# testing cell ignore\n",
+ "assert iw_zfish.sliders[\"t\"].max == zfish_data.shape[0] - 1\n",
+ "assert iw_zfish.sliders[\"t\"].min == 0\n",
+ "plot_test(\"image-widget-zfish-grid-init-mean-window-5\", iw_zfish.gridplot)\n",
+ "iw_zfish.sliders[\"t\"].value = 50\n",
+ "plot_test(\"image-widget-zfish-grid-frame-50-mean-window-5\", iw_zfish.gridplot)\n",
+ "iw_zfish.window_funcs[\"t\"].window_size = 13\n",
+ "plot_test(\"image-widget-zfish-grid-frame-50-mean-window-13\", iw_zfish.gridplot)\n",
+ "iw_zfish.window_funcs = None\n",
+ "plot_test(\"image-widget-zfish-grid-frame-50\", iw_zfish.gridplot)\n",
+ "iw_zfish.sliders[\"t\"].value = 99\n",
+ "plot_test(\"image-widget-zfish-grid-frame-99\", iw_zfish.gridplot)\n",
+ "iw_zfish.sliders[\"t\"].value = 50\n",
+ "iw_zfish.window_funcs = {\"t\": (np.max, 13)}\n",
+ "plot_test(\"image-widget-zfish-grid-frame-50-max-window-13\", iw_zfish.gridplot)\n",
+ "iw_zfish.window_funcs = None\n",
+ "iw_zfish.frame_apply = lambda frame: gaussian_filter(frame.astype(np.float32), sigma=3)\n",
+ "iw_zfish.reset_vmin_vmax()\n",
+ "plot_test(\"image-widget-zfish-grid-frame-50-frame-apply-gaussian\", iw_zfish.gridplot)\n",
+ "iw_zfish.frame_apply = None\n",
+ "iw_zfish.reset_vmin_vmax()\n",
+ "plot_test(\"image-widget-zfish-grid-frame-50-frame-apply-reset\", iw_zfish.gridplot)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "34499f45-cab3-4abd-832a-a679746b1684",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# reverse planes and test set_data\n",
+ "iw_zfish.set_data(\n",
+ " [zfish_data[:, i] for i in range(n_planes - 1, -1, -1)],\n",
+ " reset_indices=False\n",
+ ")\n",
+ "\n",
+ "plot_test(\"image-widget-zfish-grid-set_data-reset-indices-false\", iw_zfish.gridplot)\n",
+ "\n",
+ "iw_zfish.set_data(\n",
+ " [zfish_data[:, i] for i in range(n_planes - 1, -1, -1)],\n",
+ " reset_indices=True\n",
+ ")\n",
+ "plot_test(\"image-widget-zfish-grid-set_data-reset-indices-true\", iw_zfish.gridplot)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "08501aad-8b56-4ae5-98ff-26942cbb5d67",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "iw_zfish.close()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bf5ff2c3-780c-41dd-91a7-74ef8b87d838",
+ "metadata": {},
+ "source": [
+ "## z-sliders"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "87280ff7-5009-46a7-9306-0c1fe03ba4bd",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "iw_z = ImageWidget(\n",
+ " data=zfish_data, # you can also provide a list of tzxy arrays\n",
+ " window_funcs={\"t\": (np.mean, 5)},\n",
+ " cmap=\"gnuplot2\", \n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "94142bdf-78d0-4512-b27a-f5a61b9aba5f",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "iw_z.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "06b66964-b3bf-4545-a0e6-79ddc996a1d0",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# same tests as with the gridplot\n",
+ "assert iw_z.sliders[\"t\"].max == zfish_data.shape[0] - 1\n",
+ "assert iw_z.sliders[\"t\"].min == 0\n",
+ "plot_test(\"image-widget-zfish-init-mean-window-5\", iw_z.gridplot)\n",
+ "iw_z.sliders[\"t\"].value = 50\n",
+ "plot_test(\"image-widget-zfish-frame-50-mean-window-5\", iw_z.gridplot)\n",
+ "iw_z.window_funcs[\"t\"].window_size = 13\n",
+ "plot_test(\"image-widget-zfish-frame-50-mean-window-13\", iw_z.gridplot)\n",
+ "iw_z.window_funcs = None\n",
+ "plot_test(\"image-widget-zfish-frame-50\", iw_z.gridplot)\n",
+ "iw_z.sliders[\"t\"].value = 99\n",
+ "plot_test(\"image-widget-zfish-frame-99\", iw_z.gridplot)\n",
+ "iw_z.sliders[\"t\"].value = 50\n",
+ "iw_z.window_funcs = {\"t\": (np.max, 13)}\n",
+ "plot_test(\"image-widget-zfish-frame-50-max-window-13\", iw_z.gridplot)\n",
+ "iw_z.window_funcs = None\n",
+ "iw_z.frame_apply = lambda frame: gaussian_filter(frame.astype(np.float32), sigma=3)\n",
+ "iw_z.reset_vmin_vmax()\n",
+ "plot_test(\"image-widget-zfish-frame-50-frame-apply-gaussian\", iw_z.gridplot)\n",
+ "iw_z.frame_apply = None\n",
+ "iw_z.reset_vmin_vmax()\n",
+ "plot_test(\"image-widget-zfish-frame-50-frame-apply-reset\", iw_z.gridplot)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b94ae517-4a48-4efe-b85b-7679ae02d233",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "iw_z.close()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "870627ef-09d8-44e4-8952-aedb702d1526",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "notebook_finished()"
+ ]
+ }
+ ],
+ "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/lineplot.ipynb b/examples/notebooks/lineplot.ipynb
index e156a7150..667cae178 100644
--- a/examples/notebooks/lineplot.ipynb
+++ b/examples/notebooks/lineplot.ipynb
@@ -12,7 +12,7 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": null,
"id": "9c974494-712e-4981-bae2-a3ee176a6b20",
"metadata": {},
"outputs": [],
@@ -23,7 +23,7 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": null,
"id": "c3d8f967-f60f-4f0b-b6ba-21b1251b4856",
"metadata": {},
"outputs": [],
@@ -41,60 +41,10 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": null,
"id": "78cffe56-1147-4255-82c1-53cec6bc986a",
"metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "7993e0a4358f4678a7343b78b3b0b24c",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "RFBOutputContext()"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "/home/kushalk/repos/fastplotlib/fastplotlib/layouts/_base.py:214: UserWarning: `center_scene()` not yet implemented for `PerspectiveCamera`\n",
- " warn(\"`center_scene()` not yet implemented for `PerspectiveCamera`\")\n"
- ]
- },
- {
- "data": {
- "text/html": [
- "
initial snapshot
"
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "898a109f489741a5b4624be77bd27db0",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "JupyterWgpuCanvas()"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"# grid with 2 rows and 2 columns\n",
"shape = (2, 2)\n",
@@ -104,7 +54,7 @@
"# same controller ID\n",
"# in this example the first view has its own controller\n",
"# and the last 3 views are synced\n",
- "controllers = [\n",
+ "controller_ids = [\n",
" [0, 1], # id each controller with an integer\n",
" [1, 1]\n",
"]\n",
@@ -113,7 +63,7 @@
"grid_plot = GridPlot(\n",
" shape=shape,\n",
" cameras='3d', # 3D view for all subplots within the grid\n",
- " controllers=controllers\n",
+ " controller_ids=controller_ids\n",
")\n",
"\n",
"for i, subplot in enumerate(grid_plot):\n",
diff --git a/examples/notebooks/scatter.ipynb b/examples/notebooks/scatter.ipynb
index 948403f11..9d7ff099f 100644
--- a/examples/notebooks/scatter.ipynb
+++ b/examples/notebooks/scatter.ipynb
@@ -78,7 +78,7 @@
"# 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",
- "controllers = [\n",
+ "controller_ids = [\n",
" [0, 1],\n",
" [1, 0]\n",
"]\n",
@@ -87,7 +87,7 @@
"grid_plot = GridPlot(\n",
" shape=shape,\n",
" cameras=cameras,\n",
- " controllers=controllers\n",
+ " controller_ids=controller_ids\n",
")\n",
"\n",
"for subplot in grid_plot:\n",
@@ -163,15 +163,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "fb49930f-b795-4b41-bbc6-014a27c2f463",
- "metadata": {},
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7d8aac54-4f36-41d4-8e5b-8d8da2f0d17d",
+ "id": "a18e7a17-c2af-4674-a499-bf5f3b27c8ca",
"metadata": {},
"outputs": [],
"source": []
diff --git a/examples/notebooks/scatter_sizes_animation.ipynb b/examples/notebooks/scatter_sizes_animation.ipynb
index 061f444d6..06a6b11a2 100644
--- a/examples/notebooks/scatter_sizes_animation.ipynb
+++ b/examples/notebooks/scatter_sizes_animation.ipynb
@@ -2,9 +2,39 @@
"cells": [
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 1,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "5d9f9913391a42af95d4d43d07c17b19",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "RFBOutputContext()"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "9cd08c319b814934a09fd266a1b6322b",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "JupyterOutputContext(children=(JupyterWgpuCanvas(), IpywidgetToolBar(children=(Button(icon='expand-arrows-alt'…"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"from time import time\n",
"\n",
@@ -21,8 +51,6 @@
" current_time = time()\n",
" newPositions = points + np.sin(((current_time / 4) % 1)*np.pi)\n",
" plot.graphics[0].data = newPositions\n",
- " plot.camera.width = 4*np.max(newPositions[0,:])\n",
- " plot.camera.height = 4*np.max(newPositions[1,:])\n",
"\n",
"def update_sizes():\n",
" current_time = time()\n",
@@ -30,12 +58,11 @@
" size_delta = sin_sample*size_delta_scales\n",
" plot.graphics[0].sizes = min_sizes + size_delta\n",
"\n",
- "points = np.array([[0,0], \n",
- " [1,1], \n",
- " [2,2]])\n",
"scatter = plot.add_scatter(points, colors=[\"red\", \"green\", \"blue\"], sizes=12)\n",
"plot.add_animations(update_positions, update_sizes)\n",
- "plot.show(autoscale=True)"
+ "\n",
+ "plot.camera.width = 12\n",
+ "plot.show(autoscale=False)"
]
},
{
@@ -48,7 +75,7 @@
],
"metadata": {
"kernelspec": {
- "display_name": "fastplotlib-dev",
+ "display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@@ -62,10 +89,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.4"
- },
- "orig_nbformat": 4
+ "version": "3.11.3"
+ }
},
"nbformat": 4,
- "nbformat_minor": 2
+ "nbformat_minor": 4
}
diff --git a/examples/notebooks/scatter_sizes_grid.ipynb b/examples/notebooks/scatter_sizes_grid.ipynb
index ff64184f7..e152056c9 100644
--- a/examples/notebooks/scatter_sizes_grid.ipynb
+++ b/examples/notebooks/scatter_sizes_grid.ipynb
@@ -19,15 +19,6 @@
"# grid with 2 rows and 3 columns\n",
"grid_shape = (2,1)\n",
"\n",
- "# pan-zoom controllers for each view\n",
- "# views are synced if they have the \n",
- "# same controller ID\n",
- "controllers = [\n",
- " [0],\n",
- " [0]\n",
- "]\n",
- "\n",
- "\n",
"# you can give string names for each subplot within the gridplot\n",
"names = [\n",
" [\"scalar_size\"],\n",
@@ -37,7 +28,6 @@
"# Create the grid plot\n",
"plot = fpl.GridPlot(\n",
" shape=grid_shape,\n",
- " controllers=controllers,\n",
" names=names,\n",
" size=(1000, 1000)\n",
")\n",
@@ -59,11 +49,18 @@
"\n",
"plot.show()"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "fastplotlib-dev",
+ "display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@@ -77,10 +74,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.4"
- },
- "orig_nbformat": 4
+ "version": "3.11.3"
+ }
},
"nbformat": 4,
- "nbformat_minor": 2
+ "nbformat_minor": 4
}
diff --git a/examples/notebooks/screenshots/nb-astronaut.png b/examples/notebooks/screenshots/nb-astronaut.png
index e8345f7b2..2faf79def 100644
--- a/examples/notebooks/screenshots/nb-astronaut.png
+++ b/examples/notebooks/screenshots/nb-astronaut.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:36a11f5c0a80e1cfbdeb318b314886f4d8e02ba8a763bed0db9994ef451bfd42
-size 128068
+oid sha256:4845a61b99f7a489ac82a8688cc3350ce66e4771bb1399354591fd39688a58a2
+size 127977
diff --git a/examples/notebooks/screenshots/nb-astronaut_RGB.png b/examples/notebooks/screenshots/nb-astronaut_RGB.png
index 0ff257ccf..22b2627cb 100644
--- a/examples/notebooks/screenshots/nb-astronaut_RGB.png
+++ b/examples/notebooks/screenshots/nb-astronaut_RGB.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:dc27fc081b464bb53afd98d3748b8bc75764537d76a8012b9f1b2c1d4c10613d
-size 125492
+oid sha256:2c34bd21fd7bf98bab25431019e8fee30b0f4912b6b4495ad963fb9e107b1f21
+size 125479
diff --git a/examples/notebooks/screenshots/nb-camera.png b/examples/notebooks/screenshots/nb-camera.png
index cbf936192..32e83f3ba 100644
--- a/examples/notebooks/screenshots/nb-camera.png
+++ b/examples/notebooks/screenshots/nb-camera.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cbf213d944a16cf9f72542e7a2172330fefa97c8577905f07df12559eb4485c3
-size 89303
+oid sha256:8ce695e954332a9b9122d418645d785900506fc30a897844bdf7fdce0bffb316
+size 89342
diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-set_data.png b/examples/notebooks/screenshots/nb-image-widget-movie-set_data.png
new file mode 100644
index 000000000..61c3aeb8c
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-movie-set_data.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:60318615e4850d37a4ffae16ca1e3bbf2985ddafd0dd65ba6fae997e1d123d67
+size 31251
diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-0-reset.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-0-reset.png
new file mode 100644
index 000000000..d09ce18e4
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-0-reset.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6b9187c64b7439f629a87a3828cc46a855e1b4609eca52d5484223d2c24e8bf7
+size 62562
diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-0.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-0.png
new file mode 100644
index 000000000..d09ce18e4
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-0.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6b9187c64b7439f629a87a3828cc46a855e1b4609eca52d5484223d2c24e8bf7
+size 62562
diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-279.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-279.png
new file mode 100644
index 000000000..d4c299683
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-279.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:11eb83e3489a8e9c55fcffb0e67f1cf773e538629ddf98e109601749927caa56
+size 72525
diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-max-33.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-max-33.png
new file mode 100644
index 000000000..ef5db6693
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-max-33.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:51bc6a90fba5c67935838b8e44dca477e250cbc4ee2b98ddd69f931e683ec17a
+size 63906
diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-13.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-13.png
new file mode 100644
index 000000000..86287ea9e
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-13.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1a2318ab1f242d70045b9784337e4421c635b2345331b6a5e8edc0f32ff15f07
+size 54432
diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-33.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-33.png
new file mode 100644
index 000000000..14c101960
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-mean-33.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6c5b5df5b0efb0b3b641129e08429e4a92bd5d2c62b1c63c97337287867d685e
+size 50341
diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-reset.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-reset.png
new file mode 100644
index 000000000..0df0df92b
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-50-window-reset.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f2e5a5734992333165ef2d5f6f810d869e157e59fb7f54c8dd5f413ac750a3fa
+size 65067
diff --git a/examples/notebooks/screenshots/nb-image-widget-movie-single-50.png b/examples/notebooks/screenshots/nb-image-widget-movie-single-50.png
new file mode 100644
index 000000000..0df0df92b
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-movie-single-50.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f2e5a5734992333165ef2d5f6f810d869e157e59fb7f54c8dd5f413ac750a3fa
+size 65067
diff --git a/examples/notebooks/screenshots/nb-image-widget-single-gnuplot2.png b/examples/notebooks/screenshots/nb-image-widget-single-gnuplot2.png
new file mode 100644
index 000000000..da3033219
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-single-gnuplot2.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:10912f4358278fb26c5efa030a335b0bdb80ebcc2a57fd97838fea3780f9f5d1
+size 143543
diff --git a/examples/notebooks/screenshots/nb-image-widget-single.png b/examples/notebooks/screenshots/nb-image-widget-single.png
new file mode 100644
index 000000000..346c1a987
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-single.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:bf23c969c93bc526244360af4babf72a1377a171f55b1f44443dc026faf12631
+size 134432
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-gaussian.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-gaussian.png
new file mode 100644
index 000000000..6be1058e9
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-gaussian.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:49b65e35bb12e0bce8e753f6700084b2e1100eb6efd0336afc219d9e26972901
+size 64206
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-reset.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-reset.png
new file mode 100644
index 000000000..ead51e894
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-frame-apply-reset.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:df13f86bb18ad52f962f8944cd780579440b4e1d40941019632d4f46a4d9dc2d
+size 50107
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-max-window-13.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-max-window-13.png
new file mode 100644
index 000000000..295180169
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-max-window-13.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:42676358a0199022972b69263c32a977f90a27ce6c3789d18129c67e9b730679
+size 121369
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-13.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-13.png
new file mode 100644
index 000000000..adf129ab2
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-13.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f3d1972c575f1659fc2c611a2c703cb408b74ca47e30c2e4564641dc0a6ad887
+size 76550
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-5.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-5.png
new file mode 100644
index 000000000..f123f83a9
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50-mean-window-5.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e24ea022d48ff41174206e43da911632f38237f6250340f73a7169a43d55f2a6
+size 72238
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50.png
new file mode 100644
index 000000000..8c65f7840
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-50.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:983cf6804561b4287f6acfdac04e2a31810c9d3191108e2da4623cbb852258d5
+size 56707
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-frame-99.png b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-99.png
new file mode 100644
index 000000000..fdc616d07
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-frame-99.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4e6f528bf9508397a97e33d463ccd8b3584d3ebd04499b976b4989e001648626
+size 45174
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-gaussian.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-gaussian.png
new file mode 100644
index 000000000..66d5557ee
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-gaussian.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:69f8a085b84ee851ad1579791ff96fe6bc73551d86f376524d1194c43edf819f
+size 74941
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-reset.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-reset.png
new file mode 100644
index 000000000..3f53f463b
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-frame-apply-reset.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0616c08a8cf008fbc976638cfb7d76d533547bdb6cbfa56071567dac3c7e703d
+size 75619
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-max-window-13.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-max-window-13.png
new file mode 100644
index 000000000..e2f0161b7
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-max-window-13.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e4f7893445c9f2d26f126a5ac87c1fdf0737b31fec730f754ba4c771eae5ec5b
+size 116744
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-13.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-13.png
new file mode 100644
index 000000000..fde3c576b
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-13.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a73e0ef31acf4304bc9a649f0761e0d282eb4517ade89538edfe6b7d8a9b61d0
+size 75487
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-5.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-5.png
new file mode 100644
index 000000000..c100dcaf3
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50-mean-window-5.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:00ade44cd4478bf77e7bd33ccee64e2905136e35620171f013be7e90ddaa0ba6
+size 79123
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50.png
new file mode 100644
index 000000000..08b244755
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-50.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1eb4d6a4cfbdbfffc198dbe5987f621e5cc3fdcf574699c544a12cf3b28bcdb7
+size 82281
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-99.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-99.png
new file mode 100644
index 000000000..6868bf1ff
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-frame-99.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:758c4f444ab3792c6328e51d619c51f59f27fe2589795cc82bdef7fb5daf57e3
+size 79663
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-init-mean-window-5.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-init-mean-window-5.png
new file mode 100644
index 000000000..3bcfe6c24
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-init-mean-window-5.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b75c179afde357fd69d7c3e918ad34e072685c536e388b1424596bd493b041e8
+size 81563
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-false.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-false.png
new file mode 100644
index 000000000..4a8ee413a
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-false.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e6d9460835d55d696ffcef1bff7cb7a86672d4c7345112c62050312669055870
+size 66010
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-true.png b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-true.png
new file mode 100644
index 000000000..984f1537c
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-grid-set_data-reset-indices-true.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7b83f6353ce227d76fbf7362218bcc35afa26216e5600cf145cbcce666bb6dd6
+size 66520
diff --git a/examples/notebooks/screenshots/nb-image-widget-zfish-init-mean-window-5.png b/examples/notebooks/screenshots/nb-image-widget-zfish-init-mean-window-5.png
new file mode 100644
index 000000000..2767f8699
--- /dev/null
+++ b/examples/notebooks/screenshots/nb-image-widget-zfish-init-mean-window-5.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:130c7a58ceee6ffe0ec58f194bce04e6f0892c97448b43ef9f90ced85c9c10ba
+size 62566
diff --git a/examples/notebooks/screenshots/nb-lines-3d.png b/examples/notebooks/screenshots/nb-lines-3d.png
index 6bb05537a..727450428 100644
--- a/examples/notebooks/screenshots/nb-lines-3d.png
+++ b/examples/notebooks/screenshots/nb-lines-3d.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b7e61fb22db10e515a7d249649c5e220731c6ea5a83bb626f06dcf41167f117e
-size 23052
+oid sha256:1da691b87d324d1a5b2c4f9231be89c0c3dddb0584615a07f28a4d027dc59d5c
+size 23057
diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png b/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png
index b1045cde6..2f149e7f4 100644
--- a/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png
+++ b/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1f55806e64a8ffde2f11eed1dc75a874371800046c062da21e71554abedda251
-size 17136
+oid sha256:a755f36126b805b8d63d6ea679ffa270dc20d976a9a3a2cd1420ccdf0e981474
+size 17158
diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png b/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png
index 53b3d4cbd..45a34c5f0 100644
--- a/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png
+++ b/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e5e9bcb785fe5efee324bdde451d62158668dafa0c026179bd11d38298fb0002
-size 18526
+oid sha256:76e55108ce7ace466fb9b90b852a1102ff8b4c931e16f05af231a854519c8467
+size 18505
diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet.png b/examples/notebooks/screenshots/nb-lines-cmap-jet.png
index 8bfd0d577..ed8138ab1 100644
--- a/examples/notebooks/screenshots/nb-lines-cmap-jet.png
+++ b/examples/notebooks/screenshots/nb-lines-cmap-jet.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2d6fd17a9a704b2d9c5341e85763f1ba9c5e3026da88858f004e66a781e02eaa
-size 16310
+oid sha256:7e463ac93808329ffa4fe421838ff8d39ce49081b888d09954405cd170af8a85
+size 16267
diff --git a/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png b/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png
index 3e76883bf..e10d6f5e9 100644
--- a/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png
+++ b/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:672da2cc5e500ce3bbdabb01eaf5a7d2b9fb6ea4e6e95cb3392b2a0573a970d9
-size 14882
+oid sha256:99c10da11e298d69cd85d587b133fe31a5528657ba456e5f0050ca0e48ed0f31
+size 14865
diff --git a/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png b/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png
index 4b6212a6a..da5693226 100644
--- a/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png
+++ b/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:1e1224f75ce0286c4721b5f65af339fc922dcb2308f8d2fa3def10ead48cdce8
-size 15096
+oid sha256:d356938c29834263d9879c3217782414d631e998ea02f11f3c00c0f64d8a63a6
+size 15084
diff --git a/examples/notebooks/screenshots/nb-lines-cmap-viridis.png b/examples/notebooks/screenshots/nb-lines-cmap-viridis.png
index 35c38c881..ddcb6d54a 100644
--- a/examples/notebooks/screenshots/nb-lines-cmap-viridis.png
+++ b/examples/notebooks/screenshots/nb-lines-cmap-viridis.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f6201cd8dc9273adca73329b0eae81faf6aed42c3bf8f7ee503b9251af499dcd
-size 19203
+oid sha256:dfd17b5b191edf58377451b0c34636d047f69de1a89087d9d2d561d967c4d236
+size 19118
diff --git a/examples/notebooks/screenshots/nb-lines-cmap-white.png b/examples/notebooks/screenshots/nb-lines-cmap-white.png
index 67c2fc116..93efe221c 100644
--- a/examples/notebooks/screenshots/nb-lines-cmap-white.png
+++ b/examples/notebooks/screenshots/nb-lines-cmap-white.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ecb2d4d591b852bda8758efcf91d389442f916bbb4a06c5216d52dcf72172370
-size 12955
+oid sha256:d3b512a195ab30075a028d19884716c5f776acd6f118e682046d6659d1e1095e
+size 12962
diff --git a/examples/notebooks/screenshots/nb-lines-colors.png b/examples/notebooks/screenshots/nb-lines-colors.png
index b9972c8f4..a8af1a4be 100644
--- a/examples/notebooks/screenshots/nb-lines-colors.png
+++ b/examples/notebooks/screenshots/nb-lines-colors.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a8eefa5106414bfb540b282d74372831ef3c4a9d941aaf50026ea64a3d3009f7
-size 40544
+oid sha256:c8db3d4ccb1e56919866a6ba510033dc903d23a5af06a961f90ddb7382d16ec7
+size 40477
diff --git a/examples/notebooks/screenshots/nb-lines-data.png b/examples/notebooks/screenshots/nb-lines-data.png
index 14d6f89f0..369a999b2 100644
--- a/examples/notebooks/screenshots/nb-lines-data.png
+++ b/examples/notebooks/screenshots/nb-lines-data.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8e89906d0d749f443e751eeb43b017622a46dfaa91545e9135d0a519e0aad0eb
-size 54446
+oid sha256:2907942f9307eb21764ea02d363a8c6c8b7e4fbf375257b7c19225e1f7b66279
+size 54404
diff --git a/examples/notebooks/screenshots/nb-lines-underlay.png b/examples/notebooks/screenshots/nb-lines-underlay.png
index d8809f301..d6b630362 100644
--- a/examples/notebooks/screenshots/nb-lines-underlay.png
+++ b/examples/notebooks/screenshots/nb-lines-underlay.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:61ed6bde5639d57694cb8752052dda08a5f2f7dcc32966ab62385bc866c299e3
-size 55936
+oid sha256:70800d1739bb5ba7d5d9d2399335ebc1ce8a0874042ed4b6256b6d041014eb18
+size 55884
diff --git a/examples/notebooks/screenshots/nb-lines.png b/examples/notebooks/screenshots/nb-lines.png
index 3dcc1767e..2fcd0637f 100644
--- a/examples/notebooks/screenshots/nb-lines.png
+++ b/examples/notebooks/screenshots/nb-lines.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:39478dbf9af2f74ae0e0240616d94480569d53dcbd5f046315eeff3855d4cb2e
-size 37711
+oid sha256:4f70a9dd8cc631337ba1ccc7931ef2d412d0d6713d5403011994d59258f61e34
+size 37714
diff --git a/examples/notebooks/simple.ipynb b/examples/notebooks/simple.ipynb
index 681980d39..f5901080b 100644
--- a/examples/notebooks/simple.ipynb
+++ b/examples/notebooks/simple.ipynb
@@ -100,7 +100,7 @@
"image_graphic = plot.add_image(data=data, name=\"sample-image\")\n",
"\n",
"# show the plot\n",
- "plot.show()"
+ "plot.show(sidecar=True)"
]
},
{
@@ -589,7 +589,7 @@
"\n",
"plot_sync.add_animations(update_data_2)\n",
"\n",
- "plot_sync.show(sidecar=False)"
+ "plot_sync.show()"
]
},
{
@@ -704,7 +704,7 @@
"sinc_graphic = plot_l.add_line(data=sinc, thickness=5, colors = colors)\n",
"\n",
"# show the plot\n",
- "plot_l.show(sidecar_kwargs={\"title\": \"lines\", \"layout\": {'width': '800px'}})"
+ "plot_l.show(sidecar=True, sidecar_kwargs={\"title\": \"lines\"})"
]
},
{
@@ -1020,6 +1020,14 @@
"plot_l3d.show()"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "29f07af0-cdcb-47cc-bbb3-2fa4449fa084",
+ "metadata": {},
+ "source": [
+ "**Use WASD keys and the mouse to move around, just like in a game :D. Use the mouse weel to control the speed of movement.**"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
@@ -1045,6 +1053,17 @@
"plot_test(\"lines-3d\", plot_l3d)"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7a6da884-8b40-4ebf-837f-929b3e9cf4c4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# change the FOV of the persepctive camera\n",
+ "plot_l3d.camera.fov = 70"
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
@@ -1187,6 +1206,25 @@
"scatter_graphic.data[n_points:n_points * 2, 0] = np.linspace(-40, 0, n_points)"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "5f3e206d-97af-4e07-9969-94f2fdb41004",
+ "metadata": {},
+ "source": [
+ "**Switch to a fly controller to move around the plot in 3D!**"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c67944ca-52e7-4213-b820-6572cc3f76f0",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plot_s.camera = \"3d\"\n",
+ "plot_s.controller = \"fly\""
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
diff --git a/examples/notebooks/zfish_test.npy b/examples/notebooks/zfish_test.npy
new file mode 100644
index 000000000..61f0474e6
--- /dev/null
+++ b/examples/notebooks/zfish_test.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ff73fdbde34cafaf01254b9e72bdc484d865e6c3288ef88fc1953f349fc02152
+size 26214528
diff --git a/fastplotlib/VERSION b/fastplotlib/VERSION
index a0ad4fd5d..d9958b371 100644
--- a/fastplotlib/VERSION
+++ b/fastplotlib/VERSION
@@ -1 +1 @@
-0.1.0.a15
+0.1.0.a16
diff --git a/fastplotlib/layouts/_defaults.py b/fastplotlib/layouts/_defaults.py
index 9a223855f..b28b04f64 100644
--- a/fastplotlib/layouts/_defaults.py
+++ b/fastplotlib/layouts/_defaults.py
@@ -1,46 +1,3 @@
-import pygfx
-from typing import *
-camera_types = {
- "2d": pygfx.OrthographicCamera,
- "3d": pygfx.PerspectiveCamera,
-}
-controller_types = {
- "2d": pygfx.PanZoomController,
- "3d": pygfx.OrbitController,
- pygfx.OrthographicCamera: pygfx.PanZoomController,
- pygfx.PerspectiveCamera: pygfx.OrbitController,
-}
-
-def create_camera(
- camera_type: str, big_camera: bool = False
-) -> Union[pygfx.OrthographicCamera, pygfx.PerspectiveCamera]:
- camera_type = camera_type.split("-")
-
- # kinda messy but works for now
- if len(camera_type) > 1:
- if camera_type[1] == "big":
- big_camera = True
-
- camera_type = camera_type[0]
- else:
- camera_type = camera_type[0]
-
- cls = camera_types[camera_type]
-
- if cls is pygfx.OrthographicCamera:
- if big_camera:
- return cls(1024, 1024, -8192, 8192)
- else:
- return cls(1024, 1024)
-
- else:
- return cls()
-
-
-def create_controller(controller_type: str):
- controller_type = controller_type.split("-")[0]
-
- return controller_types[controller_type]()
diff --git a/fastplotlib/layouts/_gridplot.py b/fastplotlib/layouts/_gridplot.py
index 473196f78..459aca5fd 100644
--- a/fastplotlib/layouts/_gridplot.py
+++ b/fastplotlib/layouts/_gridplot.py
@@ -1,4 +1,4 @@
-from itertools import product
+from itertools import product, chain
import numpy as np
from typing import *
from inspect import getfullargspec
@@ -9,8 +9,8 @@
from wgpu.gui.auto import WgpuCanvas
from ._frame import Frame
-from ._utils import make_canvas_and_renderer
-from ._defaults import create_controller
+from ._utils import make_canvas_and_renderer, create_controller, create_camera
+from ._utils import controller_types as valid_controller_types
from ._subplot import Subplot
from ._record_mixin import RecordMixin
@@ -25,43 +25,47 @@ def to_array(a) -> np.ndarray:
return np.array(a)
-valid_cameras = ["2d", "2d-big", "3d", "3d-big"]
-
-
class GridPlot(Frame, RecordMixin):
def __init__(
self,
shape: Tuple[int, int],
- cameras: Union[np.ndarray, str] = "2d",
- controllers: Union[np.ndarray, str] = None,
+ cameras: Union[str, list, np.ndarray] = "2d",
+ controller_types: Union[str, list, np.ndarray] = None,
+ controller_ids: Union[str, list, np.ndarray] = None,
canvas: Union[str, WgpuCanvas, pygfx.Texture] = None,
renderer: pygfx.WgpuRenderer = None,
size: Tuple[int, int] = (500, 300),
- **kwargs,
+ names: Union[list, np.ndarray] = None,
):
"""
A grid of subplots.
Parameters
----------
- shape: tuple of int
+ shape: (int, int)
(n_rows, n_cols)
- cameras: np.ndarray or str, optional
+ cameras: str, list, or np.ndarray, optional
| One of ``"2d"`` or ``"3d"`` indicating 2D or 3D cameras for all subplots
- | OR
- | Array of ``2d`` and/or ``3d`` that specifies the camera type for each subplot
+ | list/array of ``2d`` and/or ``3d`` that specifies the camera type for each subplot
+ | list/array of pygfx.PerspectiveCamera instances
+
+ controller_types: str, list or np.ndarray, optional
+ list or array that specifies the controller type for each subplot, or list/array of
+ pygfx.Controller instances
- controllers: np.ndarray or str, optional
+ controller_ids: str, list or np.ndarray of int or str ids, optional
| If `None` a unique controller is created for each subplot
| If "sync" all the subplots use the same controller
| If ``numpy.array``, its shape must be the same as ``grid_shape``.
This allows custom assignment of controllers
- | Example:
- | unique controllers for a 2x2 gridplot: np.array([[0, 1], [2, 3]])
- | same controllers for first 2 plots and last 2 plots: np.array([[0, 0, 1], [2, 3, 3]])
+ | Example with integers:
+ | sync first 2 plots, and sync last 2 plots: [[0, 0, 1], [2, 3, 3]]
+ | Example with str subplot names:
+ | list of lists of subplot names, each sublist is synced: [[subplot_a, subplot_b], [subplot_f, subplot_c]]
+ | this syncs subplot_a and subplot_b together; syncs subplot_f and subplot_c together
canvas: WgpuCanvas, optional
Canvas for drawing
@@ -69,70 +73,147 @@ def __init__(
renderer: pygfx.Renderer, optional
pygfx renderer instance
- size: (int, int)
+ size: (int, int), optional
starting size of canvas, default (500, 300)
+ names: list or array of str, optional
+ subplot names
"""
self.shape = shape
+ if names is not None:
+ if len(list(chain(*names))) != self.shape[0] * self.shape[1]:
+ raise ValueError("must provide same number of subplot `names` as specified by gridplot shape")
+
+ self.names = to_array(names).reshape(self.shape)
+ else:
+ self.names = None
+
canvas, renderer = make_canvas_and_renderer(canvas, renderer)
if isinstance(cameras, str):
- if cameras not in valid_cameras:
- raise ValueError(
- f"If passing a str, `cameras` must be one of: {valid_cameras}"
- )
# create the array representing the views for each subplot in the grid
cameras = np.array([cameras] * self.shape[0] * self.shape[1]).reshape(
self.shape
)
- if isinstance(controllers, str):
- if controllers == "sync":
- controllers = np.zeros(
- self.shape[0] * self.shape[1], dtype=int
- ).reshape(self.shape)
+ # list -> array if necessary
+ cameras = to_array(cameras).reshape(self.shape)
- if controllers is None:
- controllers = np.arange(self.shape[0] * self.shape[1]).reshape(self.shape)
+ if cameras.shape != self.shape:
+ raise ValueError("Number of cameras does not match the number of subplots")
- controllers = to_array(controllers)
+ # create the cameras
+ self._cameras = np.empty(self.shape, dtype=object)
+ for i, j in product(range(self.shape[0]), range(self.shape[1])):
+ self._cameras[i, j] = create_camera(camera_type=cameras[i, j])
- if controllers.shape != self.shape:
- raise ValueError
+ if controller_ids is None:
+ # individual controller for each subplot
+ controller_ids = np.arange(self.shape[0] * self.shape[1]).reshape(self.shape)
- cameras = to_array(cameras)
+ elif isinstance(controller_ids, str):
+ if controller_ids == "sync":
+ controller_ids = np.zeros(self.shape, dtype=int)
+ else:
+ raise ValueError(
+ f"`controller_ids` must be one of 'sync', an array/list of subplot names, or an array/list of "
+ f"integer ids. See the docstring for more details."
+ )
- self._controllers = np.empty(shape=cameras.shape, dtype=object)
+ # list controller_ids
+ elif isinstance(controller_ids, (list, np.ndarray)):
+ ids_flat = list(chain(*controller_ids))
- if cameras.shape != self.shape:
- raise ValueError
-
- # create controllers if the arguments were integers
- if np.issubdtype(controllers.dtype, np.integer):
- if not np.all(
- np.sort(np.unique(controllers))
- == np.arange(np.unique(controllers).size)
- ):
- raise ValueError("controllers must be consecutive integers")
-
- for controller in np.unique(controllers):
- cam = np.unique(cameras[controllers == controller])
- if cam.size > 1:
+ # list of str of subplot names, convert this to integer ids
+ if all([isinstance(item, str) for item in ids_flat]):
+ if self.names is None:
+ raise ValueError("must specify subplot `names` to use list of str for `controller_ids`")
+
+ # make sure each controller_id str is a subplot name
+ if not all([n in self.names for n in ids_flat]):
+ raise KeyError(
+ f"all `controller_ids` strings must be one of the subplot names"
+ )
+
+ if len(ids_flat) > len(set(ids_flat)):
raise ValueError(
- f"Controller id: {controller} has been assigned to multiple different camera types"
+ "id strings must not appear twice in `controller_ids`"
)
- self._controllers[controllers == controller] = create_controller(cam[0])
- # else assume it's a single pygfx.Controller instance or a list of controllers
- else:
- if isinstance(controllers, pygfx.Controller):
- self._controllers = np.array(
- [controllers] * shape[0] * shape[1]
- ).reshape(shape)
+ # initialize controller_ids array
+ ids_init = np.arange(self.shape[0] * self.shape[1]).reshape(self.shape)
+
+ # set id based on subplot position for each synced sublist
+ for i, sublist in enumerate(controller_ids):
+ for name in sublist:
+ ids_init[self.names == name] = -(i + 1) # use negative numbers because why not
+
+ controller_ids = ids_init
+
+ # integer ids
+ elif all([isinstance(item, (int, np.integer)) for item in ids_flat]):
+ controller_ids = to_array(controller_ids).reshape(self.shape)
+
else:
- self._controllers = np.array(controllers).reshape(shape)
+ raise TypeError(
+ f"list argument to `controller_ids` must be a list of `str` or `int`, "
+ f"you have passed: {controller_ids}"
+ )
+
+ if controller_ids.shape != self.shape:
+ raise ValueError("Number of controller_ids does not match the number of subplots")
+
+ if controller_types is None:
+ # `create_controller()` will auto-determine controller for each subplot based on defaults
+ controller_types = np.array(["default"] * self.shape[0] * self.shape[1]).reshape(self.shape)
+
+ # validate controller types
+ types_flat = list(chain(*controller_types))
+ # str controller_type or pygfx instances
+ valid_str = list(valid_controller_types.keys()) + ["default"]
+ valid_instances = tuple(valid_controller_types.values())
+
+ # make sure each controller type is valid
+ for controller_type in types_flat:
+ if controller_type is None:
+ continue
+
+ if (controller_type not in valid_str) and (not isinstance(controller_type, valid_instances)):
+ raise ValueError(
+ f"You have passed an invalid controller type, valid controller_types arguments are:\n"
+ f"{valid_str} or instances of {[c.__name__ for c in valid_instances]}"
+ )
+
+ controller_types = to_array(controller_types).reshape(self.shape)
+
+ # make the real controllers for each subplot
+ self._controllers = np.empty(shape=self.shape, dtype=object)
+ for cid in np.unique(controller_ids):
+ cont_type = controller_types[controller_ids == cid]
+ if np.unique(cont_type).size > 1:
+ raise ValueError(
+ "Multiple controller types have been assigned to the same controller id. "
+ "All controllers with the same id must use the same type of controller."
+ )
+
+ cont_type = cont_type[0]
+
+ # get all the cameras that use this controller
+ cams = self._cameras[controller_ids == cid].ravel()
+
+ if cont_type == "default":
+ # hacky fix for now because of how `create_controller()` works
+ cont_type = None
+ _controller = create_controller(controller_type=cont_type, camera=cams[0])
+
+ self._controllers[controller_ids == cid] = _controller
+
+ # add the other cameras that go with this controller
+ if cams.size > 1:
+ for cam in cams[1:]:
+ _controller.add_camera(cam)
if canvas is None:
canvas = WgpuCanvas()
@@ -140,13 +221,6 @@ def __init__(
if renderer is None:
renderer = pygfx.renderers.WgpuRenderer(canvas)
- if "names" in kwargs.keys():
- self.names = to_array(kwargs["names"])
- if self.names.shape != self.shape:
- raise ValueError
- else:
- self.names = None
-
self._canvas = canvas
self._renderer = renderer
@@ -158,7 +232,7 @@ def __init__(
for i, j in self._get_iterator():
position = (i, j)
- camera = cameras[i, j]
+ camera = self._cameras[i, j]
controller = self._controllers[i, j]
if self.names is not None:
@@ -304,5 +378,15 @@ def __next__(self) -> Subplot:
pos = self._current_iter.__next__()
return self._subplots[pos]
+ def __str__(self):
+ return f"{self.__class__.__name__} @ {hex(id(self))}"
+
def __repr__(self):
- return f"fastplotlib.{self.__class__.__name__} @ {hex(id(self))}\n"
+ newline = "\n\t"
+
+ return (
+ f"fastplotlib.{self.__class__.__name__} @ {hex(id(self))}\n"
+ f" Subplots:\n"
+ f"\t{newline.join(subplot.__str__() for subplot in self)}"
+ f"\n"
+ )
diff --git a/fastplotlib/layouts/_plot.py b/fastplotlib/layouts/_plot.py
index 5aa04bb76..34027a276 100644
--- a/fastplotlib/layouts/_plot.py
+++ b/fastplotlib/layouts/_plot.py
@@ -11,10 +11,10 @@
class Plot(Subplot, Frame, RecordMixin):
def __init__(
self,
- canvas: WgpuCanvas = None,
+ canvas: Union[str, WgpuCanvas] = None,
renderer: pygfx.WgpuRenderer = None,
- camera: str = "2d",
- controller: Union[pygfx.PanZoomController, pygfx.OrbitController] = None,
+ camera: Union[str, pygfx.PerspectiveCamera] = "2d",
+ controller: Union[str, pygfx.Controller] = None,
size: Tuple[int, int] = (500, 300),
**kwargs,
):
@@ -29,12 +29,14 @@ def __init__(
renderer: pygfx.Renderer, optional
pygfx renderer instance
- camera:str, optional
+ camera: str or pygfx.PerspectiveCamera, optional
| One of ``"2d"`` or ``"3d"`` indicating 2D or 3D camera
- controller: None, PanZoomController or OrbitOrthoController, optional
+ controller: str or pygfx.Controller, optional
Usually ``None``, you can pass an existing controller from another
- ``Plot`` or ``Subplot`` within a ``GridPlot`` to synchronize them.
+ ``Plot`` or ``Subplot`` to synchronize them.
+
+ You can also pass str arguments of valid controller names, see Subplot docstring for valid names
size: (int, int)
starting size of canvas, default (500, 300)
diff --git a/fastplotlib/layouts/_plot_area.py b/fastplotlib/layouts/_plot_area.py
index 7590bad10..9522832d3 100644
--- a/fastplotlib/layouts/_plot_area.py
+++ b/fastplotlib/layouts/_plot_area.py
@@ -6,18 +6,10 @@
import numpy as np
import pygfx
-from pygfx import (
- Scene,
- OrthographicCamera,
- PerspectiveCamera,
- PanZoomController,
- OrbitController,
- Viewport,
- WgpuRenderer,
-)
from pylinalg import vec_transform, vec_unproject
from wgpu.gui.auto import WgpuCanvas
+from ._utils import create_camera, create_controller
from ..graphics._base import Graphic
from ..graphics.selectors._base_selector import BaseSelector
@@ -33,11 +25,11 @@ def __init__(
self,
parent,
position: Any,
- camera: Union[OrthographicCamera, PerspectiveCamera],
- controller: Union[PanZoomController, OrbitController],
- scene: Scene,
+ camera: Union[pygfx.PerspectiveCamera],
+ controller: Union[pygfx.Controller],
+ scene: pygfx.Scene,
canvas: WgpuCanvas,
- renderer: WgpuRenderer,
+ renderer: pygfx.WgpuRenderer,
name: str = None,
):
"""
@@ -53,25 +45,23 @@ def __init__(
typical use will be for ``subplots`` in a ``gridplot``, position would correspond to the ``[row, column]``
location of the ``subplot`` in its ``gridplot``
- camera: pygfx OrthographicCamera or pygfx PerspectiveCamera
- ``OrthographicCamera`` type is used to visualize 2D content and ``PerspectiveCamera`` type is used to view
- 3D content, used to view the scene
+ camera: pygfx.PerspectiveCamera
+ Use perspective camera for both perspective and orthographic views. Set fov = 0 for orthographic mode.
- controller: pygfx PanZoomController or pygfx OrbitController
- ``PanZoomController`` type is used for 2D pan-zoom camera control and ``OrbitController`` type is used for
- rotating the camera around a center position, used to control the camera
+ controller: pygfx.Controller
+ One of the pygfx controllers, panzoom, fly, orbit, or trackball
- scene: pygfx Scene
+ scene: pygfx.Scene
represents the root of a scene graph, will be viewed by the given ``camera``
canvas: WgpuCanvas
provides surface on which a scene will be rendered
- renderer: WgpuRenderer
- object used to render scenes using wgpu
+ renderer: pygfx.WgpuRenderer
+ renders the scene onto the canvas
name: str, optional
- name of ``subplot`` or ``plot`` subclass being instantiated
+ name this ``subplot`` or ``plot``
"""
@@ -82,14 +72,14 @@ def __init__(
self._canvas = canvas
self._renderer = renderer
if parent is None:
- self._viewport: Viewport = Viewport(renderer)
+ self._viewport: pygfx.Viewport = pygfx.Viewport(renderer)
else:
- self._viewport = Viewport(parent.renderer)
+ self._viewport = pygfx.Viewport(parent.renderer)
self._camera = camera
self._controller = controller
- self.controller.add_camera(self.camera)
+ self.controller.add_camera(self._camera)
self.controller.register_events(
self.viewport,
)
@@ -126,7 +116,7 @@ def position(self) -> Union[Tuple[int, int], Any]:
return self._position
@property
- def scene(self) -> Scene:
+ def scene(self) -> pygfx.Scene:
"""The Scene where Graphics lie in this plot area"""
return self._scene
@@ -136,26 +126,82 @@ def canvas(self) -> WgpuCanvas:
return self._canvas
@property
- def renderer(self) -> WgpuRenderer:
+ def renderer(self) -> pygfx.WgpuRenderer:
"""Renderer associated to the plot area"""
return self._renderer
@property
- def viewport(self) -> Viewport:
+ def viewport(self) -> pygfx.Viewport:
"""The rectangular area of the renderer associated to this plot area"""
return self._viewport
@property
- def camera(self) -> Union[OrthographicCamera, PerspectiveCamera]:
+ def camera(self) -> pygfx.PerspectiveCamera:
"""camera used to view the scene"""
return self._camera
+ @camera.setter
+ def camera(self, new_camera: Union[str, pygfx.PerspectiveCamera]):
+ # user wants to set completely new camera, remove current camera from controller
+ if isinstance(new_camera, pygfx.PerspectiveCamera):
+ self.controller.remove_camera(self._camera)
+ # add new camera to controller
+ self.controller.add_camera(new_camera)
+
+ self._camera = new_camera
+
+ # modify FOV if necessary
+ elif isinstance(new_camera, str):
+ if new_camera == "2d":
+ self._camera.fov = 0
+
+ elif new_camera == "3d":
+ # orthographic -> perspective only if fov = 0, i.e. if camera is in ortho mode
+ # otherwise keep same FOV
+ if self._camera.fov == 0:
+ self._camera.fov = 50
+
+ else:
+ raise ValueError("camera must be one of '2d', '3d' or a pygfx.PerspectiveCamera instance")
+ else:
+ raise ValueError("camera must be one of '2d', '3d' or a pygfx.PerspectiveCamera instance")
+
# in the future we can think about how to allow changing the controller
@property
- def controller(self) -> Union[PanZoomController, OrbitController]:
- """controller used to control camera"""
+ def controller(self) -> pygfx.Controller:
+ """controller used to control the camera"""
return self._controller
+ @controller.setter
+ def controller(self, new_controller: Union[str, pygfx.Controller]):
+ new_controller = create_controller(new_controller, self._camera)
+
+ cameras_list = list()
+
+ # remove all the cameras associated to this controller
+ for camera in self._controller.cameras:
+ self._controller.remove_camera(camera)
+ cameras_list.append(camera)
+
+ # add the associated cameras to the new controller
+ for camera in cameras_list:
+ new_controller.add_camera(camera)
+
+ new_controller.register_events(
+ self.viewport
+ )
+
+ # TODO: monkeypatch until we figure out a better
+ # pygfx plans on refactoring viewports anyways
+ if self.parent is not None:
+ if self.parent.__class__.__name__ == "GridPlot":
+ for subplot in self.parent:
+ if subplot.camera in cameras_list:
+ new_controller.register_events(subplot.viewport)
+ subplot._controller = new_controller
+
+ self._controller = new_controller
+
@property
def graphics(self) -> Tuple[Graphic, ...]:
"""Graphics in the plot area. Always returns a proxy to the Graphic instances."""
@@ -459,7 +505,7 @@ def center_graphic(self, graphic: Graphic, zoom: float = 1.35):
# probably because camera.show_object uses bounding sphere
self.camera.zoom = zoom
- def center_scene(self, zoom: float = 1.35):
+ def center_scene(self, *, zoom: float = 1.35):
"""
Auto-center the scene, does not scale.
@@ -481,15 +527,20 @@ def center_scene(self, zoom: float = 1.35):
# probably because camera.show_object uses bounding sphere
camera.zoom = zoom
- def auto_scale(self, maintain_aspect: bool = False, zoom: float = 0.8):
+ def auto_scale(
+ self,
+ *, # since this is often used as an event handler, don't want to coerce maintain_aspect = True
+ maintain_aspect: Union[None, bool] = None,
+ zoom: float = 0.8
+ ):
"""
Auto-scale the camera w.r.t to the scene
Parameters
----------
- maintain_aspect: bool, default ``False``
- maintain the camera aspect ratio for all dimensions, if ``False`` the camera
- is scaled according to the bounds in each dimension.
+ maintain_aspect: ``None`` or bool, default ``None``
+ Maintain the camera aspect ratio for all dimensions. If ``None``, the aspect is left unchanged.
+ if ``False`` the camera is scaled to the bounding box of the current scene.
zoom: float, default 0.8
zoom value for the camera after auto-scaling, if zoom = 1.0 then the graphics
@@ -503,8 +554,9 @@ def auto_scale(self, maintain_aspect: bool = False, zoom: float = 0.8):
self.scene.remove(selector.world_object)
self.center_scene()
- if not isinstance(maintain_aspect, bool):
- maintain_aspect = False # assume False
+
+ if maintain_aspect is None: # if not provided keep current setting
+ maintain_aspect = self.camera.maintain_aspect
# scale all cameras associated with this controller else it looks wonky
for camera in self.controller.cameras:
@@ -657,7 +709,7 @@ def __repr__(self):
return (
f"{self}\n"
- f" parent: {self.parent}\n"
+ f" parent: {self.parent.__str__()}\n"
f" Graphics:\n"
f"\t{newline.join(graphic.__repr__() for graphic in self.graphics)}"
f"\n"
diff --git a/fastplotlib/layouts/_subplot.py b/fastplotlib/layouts/_subplot.py
index c178c0fca..e9eae7603 100644
--- a/fastplotlib/layouts/_subplot.py
+++ b/fastplotlib/layouts/_subplot.py
@@ -2,22 +2,13 @@
import numpy as np
-from pygfx import (
- Scene,
- OrthographicCamera,
- PanZoomController,
- OrbitController,
- AxesHelper,
- GridHelper,
- WgpuRenderer,
- Texture,
-)
+import pygfx
+
from wgpu.gui.auto import WgpuCanvas
from ..graphics import TextGraphic
-from ._utils import make_canvas_and_renderer
+from ._utils import make_canvas_and_renderer, create_camera, create_controller
from ._plot_area import PlotArea
-from ._defaults import create_camera, create_controller
from .graphic_methods_mixin import GraphicMethodsMixin
@@ -27,12 +18,11 @@ def __init__(
parent: Any = None,
position: Tuple[int, int] = None,
parent_dims: Tuple[int, int] = None,
- camera: str = "2d",
- controller: Union[PanZoomController, OrbitController] = None,
- canvas: Union[str, WgpuCanvas, Texture] = None,
- renderer: WgpuRenderer = None,
+ camera: Union[str, pygfx.PerspectiveCamera] = "2d",
+ controller: Union[str, pygfx.Controller] = None,
+ canvas: Union[str, WgpuCanvas, pygfx.Texture] = None,
+ renderer: pygfx.WgpuRenderer = None,
name: str = None,
- **kwargs,
):
"""
General plot object that composes a ``Gridplot``. Each ``Gridplot`` instance will have [n rows, n columns]
@@ -43,21 +33,25 @@ def __init__(
Parameters
----------
- position: int tuple, optional
+ parent: Any
+ parent GridPlot instance
+
+ position: (int, int), optional
corresponds to the [row, column] position of the subplot within a ``Gridplot``
- parent_dims: int tuple, optional
+ parent_dims: (int, int), optional
dimensions of the parent ``GridPlot``
- camera: str, default '2d'
- indicates the kind of pygfx camera that will be instantiated, '2d' uses pygfx ``OrthographicCamera`` and
- '3d' uses pygfx ``PerspectiveCamera``
+ camera: str or pygfx.PerspectiveCamera, default '2d'
+ indicates the FOV for the camera, '2d' sets ``fov = 0``, '3d' sets ``fov = 50``.
+ ``fov`` can be changed at any time.
- controller: PanZoomController or OrbitOrthoController, optional
- ``PanZoomController`` type is used for 2D pan-zoom camera control and ``OrbitController`` type is used for
- rotating the camera around a center position, used to control the camera
+ controller: str or pygfx.Controller, optional
+ | if ``None``, uses a PanZoomController for "2d" camera or FlyController for "3d" camera.
+ | if ``str``, must be one of: `"panzoom", "fly", "trackball", or "orbit"`.
+ | also accepts a pygfx.Controller instance
- canvas: WgpuCanvas, Texture, or one of "jupyter", "glfw", "qt", optional
+ canvas: one of "jupyter", "glfw", "qt", WgpuCanvas, or pygfx.Texture, optional
Provides surface on which a scene will be rendered. Can optionally provide a WgpuCanvas instance or a str
to force the PlotArea to use a specific canvas from one of the following options: "jupyter", "glfw", "qt".
Can also provide a pygfx Texture to render to.
@@ -82,25 +76,26 @@ def __init__(
self.nrows, self.ncols = parent_dims
- if controller is None:
- controller = create_controller(camera)
+ camera = create_camera(camera)
+
+ controller = create_controller(controller_type=controller, camera=camera)
self._docks = dict()
self.spacing = 2
- self._axes: AxesHelper = AxesHelper(size=100)
+ self._axes: pygfx.AxesHelper = pygfx.AxesHelper(size=100)
for arrow in self._axes.children:
self._axes.remove(arrow)
- self._grid: GridHelper = GridHelper(size=100, thickness=1)
+ self._grid: pygfx.GridHelper = pygfx.GridHelper(size=100, thickness=1)
super(Subplot, self).__init__(
parent=parent,
position=position,
- camera=create_camera(camera),
+ camera=camera,
controller=controller,
- scene=Scene(),
+ scene=pygfx.Scene(),
canvas=canvas,
renderer=renderer,
name=name,
@@ -221,9 +216,9 @@ def __init__(
super(Dock, self).__init__(
parent=parent,
position=position,
- camera=OrthographicCamera(),
- controller=PanZoomController(),
- scene=Scene(),
+ camera=pygfx.OrthographicCamera(),
+ controller=pygfx.PanZoomController(),
+ scene=pygfx.Scene(),
canvas=parent.canvas,
renderer=parent.renderer,
)
diff --git a/fastplotlib/layouts/_utils.py b/fastplotlib/layouts/_utils.py
index dd6fbeb50..7db1d84c4 100644
--- a/fastplotlib/layouts/_utils.py
+++ b/fastplotlib/layouts/_utils.py
@@ -1,5 +1,6 @@
from typing import *
+import pygfx
from pygfx import WgpuRenderer, Texture
# default auto-determined canvas
@@ -66,7 +67,7 @@ def make_canvas_and_renderer(
if canvas is None:
Canvas = auto_determine_canvas()
- canvas = Canvas()
+ canvas = Canvas(max_fps=60)
elif isinstance(canvas, str):
if canvas not in CANVAS_OPTIONS:
@@ -76,7 +77,7 @@ def make_canvas_and_renderer(
f"The {canvas} framework is not installed for using this canvas"
)
else:
- canvas = CANVAS_OPTIONS_AVAILABLE[canvas]()
+ canvas = CANVAS_OPTIONS_AVAILABLE[canvas](max_fps=60)
elif not isinstance(canvas, (WgpuCanvasBase, Texture)):
raise ValueError(
@@ -88,3 +89,58 @@ def make_canvas_and_renderer(
renderer = WgpuRenderer(canvas)
return canvas, renderer
+
+
+def create_camera(
+ camera_type: Union[pygfx.PerspectiveCamera, str],
+) -> pygfx.PerspectiveCamera:
+ if isinstance(camera_type, pygfx.PerspectiveCamera):
+ return camera_type
+
+ elif camera_type == "2d":
+ # use perspective for orthographic, makes it easier to then switch to controllers that make sense with fov > 0
+ return pygfx.PerspectiveCamera(fov=0)
+
+ elif camera_type == "3d":
+ return pygfx.PerspectiveCamera()
+
+ else:
+ raise ValueError(
+ "camera must be one of: '2d', '3d' or an instance of pygfx.PerspectiveCamera"
+ )
+
+
+controller_types = {
+ "fly": pygfx.FlyController,
+ "panzoom": pygfx.PanZoomController,
+ "trackball": pygfx.TrackballController,
+ "orbit": pygfx.OrbitController,
+}
+
+
+def create_controller(
+ controller_type: Union[pygfx.Controller, None, str],
+ camera: pygfx.PerspectiveCamera,
+) -> pygfx.Controller:
+ """
+ Creates the controllers and adds the camera to it.
+ """
+ if isinstance(controller_type, pygfx.Controller):
+ controller_type.add_camera(camera)
+ return controller_type
+
+ if controller_type is None:
+ # default controllers
+ if camera.fov == 0:
+ # default for orthographic
+ return pygfx.PanZoomController(camera)
+ else:
+ return pygfx.FlyController(camera)
+
+ if controller_type not in controller_types.keys():
+ raise KeyError(
+ f"controller must be a valid pygfx.Controller or one of: "
+ f"{list(controller_types.keys())}, you have passed: {controller_type}"
+ )
+
+ return controller_types[controller_type](camera)
diff --git a/fastplotlib/widgets/histogram_lut.py b/fastplotlib/widgets/histogram_lut.py
index 0d8ca9f15..64feb8df6 100644
--- a/fastplotlib/widgets/histogram_lut.py
+++ b/fastplotlib/widgets/histogram_lut.py
@@ -180,7 +180,8 @@ def _calculate_histogram(self, data):
hist_scaled = hist_flanked / (hist_flanked.max() / 100)
if edges_flanked.size > hist_scaled.size:
- edges_flanked = edges_flanked[:-1]
+ # we don't care about accuracy here so if it's off by 1-2 bins that's fine
+ edges_flanked = edges_flanked[:hist_scaled.size]
return hist, edges, hist_scaled, edges_flanked
diff --git a/fastplotlib/widgets/image.py b/fastplotlib/widgets/image.py
index da256207f..a3f6335c9 100644
--- a/fastplotlib/widgets/image.py
+++ b/fastplotlib/widgets/image.py
@@ -40,7 +40,8 @@ def _is_arraylike(obj) -> bool:
class _WindowFunctions:
"""Stores window function and window size"""
- def __init__(self, func: callable, window_size: int):
+ def __init__(self, image_widget, func: callable, window_size: int):
+ self._image_widget = image_widget
self._func = None
self.func = func
@@ -56,6 +57,9 @@ def func(self) -> callable:
def func(self, func: callable):
self._func = func
+ # force update
+ self._image_widget.current_index = self._image_widget.current_index
+
@property
def window_size(self) -> int:
"""Get or set window size"""
@@ -84,6 +88,8 @@ def window_size(self, ws: int):
self._window_size = ws
+ self._image_widget.current_index = self._image_widget.current_index
+
def __repr__(self):
return f"func: {self.func}, window_size: {self.window_size}"
@@ -101,7 +107,7 @@ def widget(self):
"""
Output context, either an ipywidget or QWidget
"""
- return self.gridplot.widget
+ return self._output
@property
def managed_graphics(self) -> List[ImageGraphic]:
@@ -185,6 +191,10 @@ def current_index(self) -> Dict[str, int]:
@current_index.setter
def current_index(self, index: Dict[str, int]):
+ # ignore if output context has not been created yet
+ if self.widget is None:
+ return
+
if not set(index.keys()).issubset(set(self._current_index.keys())):
raise KeyError(
f"All dimension keys for setting `current_index` must be present in the widget sliders. "
@@ -299,6 +309,9 @@ def __init__(
self._names = None
+ # output context
+ self._output = None
+
if isinstance(data, list):
# verify that it's a list of np.ndarray
if all([_is_arraylike(d) for d in data]):
@@ -494,14 +507,14 @@ def __init__(
f"`slider_dims` must a , or , you have passed a: {type(slider_dims)}"
)
- self.frame_apply: Dict[int, callable] = dict()
+ self._frame_apply: Dict[int, callable] = dict()
if frame_apply is not None:
if callable(frame_apply):
- self.frame_apply = {0: frame_apply}
+ self._frame_apply = {0: frame_apply}
elif isinstance(frame_apply, dict):
- self.frame_apply: Dict[int, callable] = dict.fromkeys(
+ self._frame_apply: Dict[int, callable] = dict.fromkeys(
list(range(len(self.data)))
)
@@ -510,7 +523,7 @@ def __init__(
if not isinstance(data_ix, int):
raise TypeError("`frame_apply` dict keys must be ")
try:
- self.frame_apply[data_ix] = frame_apply[data_ix]
+ self._frame_apply[data_ix] = frame_apply[data_ix]
except Exception:
raise IndexError(
f"key index {data_ix} out of bounds for `frame_apply`, the bounds are 0 - {len(self.data)}"
@@ -521,14 +534,14 @@ def __init__(
f"you have passed a: <{type(frame_apply)}>"
)
+ # current_index stores {dimension_index: slice_index} for every dimension
+ self._current_index: Dict[str, int] = {sax: 0 for sax in self.slider_dims}
+
self._window_funcs = None
self.window_funcs = window_funcs
self._sliders: Dict[str, Any] = dict()
- # current_index stores {dimension_index: slice_index} for every dimension
- self._current_index: Dict[str, int] = {sax: 0 for sax in self.slider_dims}
-
# get max bound for all data arrays for all dimensions
self._dims_max_bounds: Dict[str, int] = {k: np.inf for k in self.slider_dims}
for _dim in list(self._dims_max_bounds.keys()):
@@ -537,7 +550,7 @@ def __init__(
self._dims_max_bounds[_dim], array.shape[order.index(_dim)]
)
- grid_plot_kwargs_default = {"controllers": "sync"}
+ grid_plot_kwargs_default = {"controller_ids": "sync"}
if grid_plot_kwargs is None:
grid_plot_kwargs = dict()
@@ -575,6 +588,19 @@ def __init__(
self.block_sliders = False
self._image_widget_toolbar = None
+ @property
+ def frame_apply(self) -> Union[dict, None]:
+ return self._frame_apply
+
+ @frame_apply.setter
+ def frame_apply(self, frame_apply: Dict[int, callable]):
+ if frame_apply is None:
+ frame_apply = dict()
+
+ self._frame_apply = frame_apply
+ # force update image graphic
+ self.current_index = self.current_index
+
@property
def window_funcs(self) -> Dict[str, _WindowFunctions]:
"""
@@ -591,6 +617,8 @@ def window_funcs(self) -> Dict[str, _WindowFunctions]:
def window_funcs(self, sa: Union[int, Dict[str, int]]):
if sa is None:
self._window_funcs = None
+ # force frame to update
+ self.current_index = self.current_index
return
# for a single dim
@@ -606,7 +634,7 @@ def window_funcs(self, sa: Union[int, Dict[str, int]]):
dim_str = self.slider_dims[0]
self._window_funcs = dict()
- self._window_funcs[dim_str] = _WindowFunctions(*sa)
+ self._window_funcs[dim_str] = _WindowFunctions(self, *sa)
# for multiple dims
elif isinstance(sa, dict):
@@ -636,7 +664,7 @@ def window_funcs(self, sa: Union[int, Dict[str, int]]):
if sa[k] is None:
self._window_funcs[k] = None
else:
- self._window_funcs[k] = _WindowFunctions(*sa[k])
+ self._window_funcs[k] = _WindowFunctions(self, *sa[k])
else:
raise TypeError(
@@ -644,6 +672,9 @@ def window_funcs(self, sa: Union[int, Dict[str, int]]):
f"You have passed a {type(sa)}. See the docstring."
)
+ # force frame to update
+ self.current_index = self.current_index
+
def _process_indices(
self, array: np.ndarray, slice_indices: Dict[Union[int, str], int]
) -> np.ndarray:
@@ -750,14 +781,14 @@ def _get_window_indices(self, data_ix, dim, indices_dim):
return indices_dim
def _process_frame_apply(self, array, data_ix) -> np.ndarray:
- if callable(self.frame_apply):
- return self.frame_apply(array)
+ if callable(self._frame_apply):
+ return self._frame_apply(array)
- if data_ix not in self.frame_apply.keys():
+ if data_ix not in self._frame_apply.keys():
return array
- elif self.frame_apply[data_ix] is not None:
- return self.frame_apply[data_ix](array)
+ elif self._frame_apply[data_ix] is not None:
+ return self._frame_apply[data_ix](array)
return array
@@ -783,8 +814,14 @@ def reset_vmin_vmax_frame(self):
ImageGraphic instead of the data in the full data array. For example, if a post-processing
function is used, the range of values in the ImageGraphic can be very different from the
range of values in the full data array.
+
+ TODO: We could think of applying the frame_apply funcs to a subsample of the entire array to get a better estimate of vmin vmax?
"""
+
for subplot in self.gridplot:
+ if "histogram_lut" not in subplot.docks["right"]:
+ continue
+
hlut = subplot.docks["right"]["histogram_lut"]
# set the data using the current image graphic data
hlut.set_data(subplot["image_widget_managed"].data())
@@ -854,6 +891,7 @@ def set_data(
frame = self._process_frame_apply(frame, i)
new_graphic = ImageGraphic(data=frame, name="image_widget_managed")
subplot.insert_graphic(graphic=new_graphic)
+ subplot.docks["right"]["histogram_lut"].image_graphic = new_graphic
if new_array.ndim > 2:
# to set max of time slider, txy or tzxy
@@ -876,11 +914,12 @@ def set_data(
def show(self, toolbar: bool = True, sidecar: bool = False, sidecar_kwargs: dict = None):
"""
- Show the widget
+ Show the widget.
Returns
-------
OutputContext
+ ImageWidget just uses the Gridplot output context
"""
if self.gridplot.canvas.__class__.__name__ == "JupyterWgpuCanvas":
self._image_widget_toolbar = IpywidgetImageWidgetToolbar(self)
@@ -888,13 +927,15 @@ def show(self, toolbar: bool = True, sidecar: bool = False, sidecar_kwargs: dict
elif self.gridplot.canvas.__class__.__name__ == "QWgpuCanvas":
self._image_widget_toolbar = QToolbarImageWidget(self)
- return self.gridplot.show(
+ self._output = self.gridplot.show(
toolbar=toolbar,
sidecar=sidecar,
sidecar_kwargs=sidecar_kwargs,
add_widgets=[self._image_widget_toolbar]
)
+ return self._output
+
def close(self):
"""Close Widget"""
self.gridplot.close()
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index d0bc814f2..000000000
--- a/requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-numpy
-jupyterlab
-jupyter_rfb
-pygfx>=0.1.10
-imageio
\ No newline at end of file
diff --git a/setup.py b/setup.py
index f7195461c..8e8977b57 100644
--- a/setup.py
+++ b/setup.py
@@ -36,7 +36,7 @@
"pytest",
"nbmake",
"scipy",
- "imageio",
+ "imageio[pyav]",
"jupyterlab",
"jupyter-rfb>=0.4.1",
"ipywidgets>=8.0.0,<9",