From d21c9c5646166852ee77b6b089fec2291c5854b5 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 03:53:48 -0400 Subject: [PATCH 01/13] started nb screenshot tests, add reset_vmin_vmax() on ImageCmapFeature --- examples/notebooks/nb_test_utils.py | 87 ++++ examples/notebooks/simple.ipynb | 547 +++++++++++++++------- fastplotlib/graphics/_features/_colors.py | 6 +- 3 files changed, 465 insertions(+), 175 deletions(-) create mode 100644 examples/notebooks/nb_test_utils.py diff --git a/examples/notebooks/nb_test_utils.py b/examples/notebooks/nb_test_utils.py new file mode 100644 index 000000000..2bda0fd3c --- /dev/null +++ b/examples/notebooks/nb_test_utils.py @@ -0,0 +1,87 @@ +import os +from pathlib import Path +from traceback import format_exc + +import pytest +import imageio.v3 as iio +import numpy as np + +from fastplotlib.layouts._base import PlotArea + +# make dirs for screenshots and diffs +current_dir = Path(__file__).parent + +SCREENSHOTS_DIR = current_dir.joinpath("screenshots") +DIFFS_DIR = current_dir.joinpath("diffs") + +os.makedirs(SCREENSHOTS_DIR, exist_ok=True) +os.makedirs(DIFFS_DIR, exist_ok=True) + + +# store all the failures to allow the nb to proceed to test other examples +FAILURES = list() + + +def plot_test(name, plot: PlotArea): + snapshot = plot.canvas.snapshot() + + if "REGENERATE_SCREENSHOTS" in os.environ.keys(): + if os.environ["REGENERATE_SCREENSHOTS"] == "1": + regenerate_screenshot(name, snapshot.data) + + try: + assert_screenshot_equal(name, snapshot.data) + except AssertionError: + FAILURES.append((name, format_exc())) + + +def regenerate_screenshot(name, data): + iio.imwrite(SCREENSHOTS_DIR.joinpath(f"nb-{name}.png"), data) + + +def assert_screenshot_equal(name, data): + ground_truth = iio.imread(SCREENSHOTS_DIR.joinpath(f"nb-{name}.png")) + + is_similar = np.allclose(data, ground_truth) + + update_diffs(name, is_similar, data, ground_truth) + + assert is_similar, ( + f"notebook snapshot for {name} has changed" + ) + + +def update_diffs(name, is_similar, img, ground_truth): + diffs_rgba = None + + def get_diffs_rgba(slicer): + # lazily get and cache the diff computation + nonlocal diffs_rgba + if diffs_rgba is None: + # cast to float32 to avoid overflow + # compute absolute per-pixel difference + diffs_rgba = np.abs(ground_truth.astype("f4") - img) + # magnify small values, making it easier to spot small errors + diffs_rgba = ((diffs_rgba / 255) ** 0.25) * 255 + # cast back to uint8 + diffs_rgba = diffs_rgba.astype("u1") + return diffs_rgba[..., slicer] + + # split into an rgb and an alpha diff + diffs = { + DIFFS_DIR.joinpath(f"nb-diff-{name}-rgb.png"): slice(0, 3), + DIFFS_DIR.joinpath(f"nb-diff-{name}-alpha.png"): 3, + } + + for path, slicer in diffs.items(): + if not is_similar: + diff = get_diffs_rgba(slicer) + iio.imwrite(path, diff) + elif path.exists(): + path.unlink() + + +@pytest.fixture(scope="session", autouse=True) +def check_failures(request): + if len(FAILURES) > 0: + raise AssertionError(FAILURES) diff --git a/examples/notebooks/simple.ipynb b/examples/notebooks/simple.ipynb index 367a0126c..8a3453285 100644 --- a/examples/notebooks/simple.ipynb +++ b/examples/notebooks/simple.ipynb @@ -9,7 +9,7 @@ "source": [ "# Introduction to `fastplotlib`\n", "\n", - "This notebook goes the basic components of the `fastplotlib` API, image, image updates, line plots, and scatter plots. " + "This notebook goes through the basic components of the `fastplotlib` API, image, image updates, line plots, and scatter plots. " ] }, { @@ -23,7 +23,21 @@ "source": [ "from fastplotlib import Plot\n", "from ipywidgets import VBox, HBox, IntSlider\n", - "import numpy as np" + "import numpy as np\n", + "import imageio.v3 as iio" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d374d5e-70e0-4946-937f-82d16a56009f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# this is only for testing, you do not need this to use fastplotlib\n", + "from nb_test_utils import plot_test" ] }, { @@ -31,7 +45,7 @@ "id": "a9b386ac-9218-4f8f-97b3-f29b4201ef55", "metadata": {}, "source": [ - "### Simple image" + "## Simple image" ] }, { @@ -46,11 +60,11 @@ "# create a `Plot` instance\n", "plot = Plot()\n", "\n", - "# make some random 2D image data\n", - "data = np.random.rand(512, 512)\n", + "# get a grayscale image\n", + "data = iio.imread(\"imageio:camera.png\")\n", "\n", "# plot the image data\n", - "image_graphic = plot.add_image(data=data, name=\"random-image\")\n", + "image_graphic = plot.add_image(data=data, name=\"sample-image\")\n", "\n", "# show the plot\n", "plot.show()" @@ -61,7 +75,21 @@ "id": "be5b408f-dd91-4e36-807a-8c22c8d7d216", "metadata": {}, "source": [ - "### Use the handle on the bottom right corner of the _canvas_ to resize it. You can also pan and zoom using your mouse!" + "**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": "58c1dc0b-9bf0-4ad5-8579-7c10396fc6bc", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plot.camera.world.scale_y *= -1" ] }, { @@ -69,7 +97,7 @@ "id": "7c3b637c-a26b-416e-936c-705275852a8a", "metadata": {}, "source": [ - "Changing graphic \"features\"" + "Changing graphic **\"features\"**" ] }, { @@ -84,16 +112,28 @@ "image_graphic.cmap = \"viridis\"" ] }, + { + "cell_type": "markdown", + "id": "da1efe85-c5b8-42e8-ae81-6cbddccc30f7", + "metadata": {}, + "source": [ + "### Slicing data\n", + "\n", + "**Most features, such as `data` support slicing!**\n", + "\n", + "Out image data is of shape [n_rows, n_cols]" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "09350854-5058-4574-a01d-84d00e276c57", + "id": "a04afe48-5534-4ef6-a159-f6e6a4337d8d", "metadata": { "tags": [] }, "outputs": [], "source": [ - "image_graphic.data = 0" + "image_graphic.data().shape" ] }, { @@ -109,351 +149,437 @@ "image_graphic.data[:, ::15] = 1" ] }, + { + "cell_type": "markdown", + "id": "135db5d2-53fb-4d50-8164-2c1f00560c25", + "metadata": {}, + "source": [ + "**Fancy indexing**" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "3e298c1c-7551-4401-ade0-b9af7d2bbe23", + "id": "a89120eb-108b-4df3-8d3f-8192c9315aa6", "metadata": { "tags": [] }, "outputs": [], "source": [ - "image_graphic.data = np.random.rand(512, 512)" + "image_graphic.data[data > 175] = 255" ] }, { "cell_type": "markdown", - "id": "67b92ffd-40cc-43fe-9df9-0e0d94763d8e", + "id": "096ccb73-bf6d-4dba-8168-788a63450406", "metadata": {}, "source": [ - "### Plots are indexable and give you their graphics by name" + "Adjust vmin vmax" ] }, { "cell_type": "code", "execution_count": null, - "id": "e6ba689c-ff4a-44ef-9663-f2c8755072c4", + "id": "f8e69df8-7aaf-4d7c-92e3-861d9ebc8c5f", "metadata": { "tags": [] }, "outputs": [], "source": [ - "plot.graphics" + "image_graphic.cmap.vmin = 50\n", + "image_graphic.cmap.vmax = 150" ] }, { "cell_type": "code", "execution_count": null, - "id": "5b18f4e3-e13b-46d5-af1f-285c5a7fdc12", + "id": "aa67b34a-2694-4ec0-9ba2-e88c469f1a06", "metadata": { "tags": [] }, "outputs": [], "source": [ - "plot[\"random-image\"]" + "# testing cell, ignore\n", + "plot_test(\"camera\", plot)" ] }, { "cell_type": "markdown", - "id": "4316a8b5-5f33-427a-8f52-b101d1daab67", + "id": "da9c9b25-7c8b-49b2-9531-7c741debd71d", "metadata": {}, "source": [ - "#### The `Graphic` instance is also returned when you call `plot.add_`." + "**Set the entire data array again**\n", + "\n", + "Note: The shape of the new data array must match the current data shown in the Graphic." ] }, { "cell_type": "code", "execution_count": null, - "id": "2b5c1321-1fd4-44bc-9433-7439ad3e22cf", + "id": "089170fd-016e-4b2f-a090-c30beb85cc1b", "metadata": { "tags": [] }, "outputs": [], "source": [ - "image_graphic" + "new_data = iio.imread(\"imageio:astronaut.png\")\n", + "new_data.shape" + ] + }, + { + "cell_type": "markdown", + "id": "d14cf14a-282f-40c6-b086-9bcf332ed0c8", + "metadata": {}, + "source": [ + "This is an RGB image, convert to grayscale to maintain the shape of (512, 512)" ] }, { "cell_type": "code", "execution_count": null, - "id": "b12bf75e-4e93-4930-9146-e96324fdf3f6", + "id": "ec9b2874-ce1a-49c6-9b84-ee8f14d55966", "metadata": { "tags": [] }, "outputs": [], "source": [ - "image_graphic == plot[\"random-image\"]" + "gray = new_data.dot([0.3, 0.6, 0.1])\n", + "gray.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8a8fc1d3-19ba-42c0-b9ec-39f6ddd23314", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "image_graphic.data = gray" ] }, { "cell_type": "markdown", - "id": "1cb03f42-1029-4b16-a16b-35447d9e2955", + "id": "bb568f89-ac92-4dde-9359-789049dc758a", + "metadata": {}, + "source": [ + "reset vmin vmax" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de09d977-88ea-472c-8d89-9e24abc845a9", "metadata": { "tags": [] }, + "outputs": [], "source": [ - "### Image updates\n", - "\n", - "This examples show how you can define animation functions that run on every render cycle." + "image_graphic.cmap.reset_vmin_vmax()" ] }, { "cell_type": "code", "execution_count": null, - "id": "aadd757f-6379-4f52-a709-46aa57c56216", + "id": "9cf84998-03e1-41b3-8e63-92d5b59426e6", "metadata": { "tags": [] }, "outputs": [], "source": [ - "# create another `Plot` instance\n", - "plot_v = Plot()\n", - "\n", - "plot.canvas.max_buffered_frames = 1\n", - "\n", - "# make some random data again\n", - "data = np.random.rand(512, 512)\n", - "\n", - "# plot the data\n", - "plot_v.add_image(data=data, name=\"random-image\")\n", - "\n", - "# a function to update the image_graphic\n", - "# a plot will pass its plot instance to the animation function as an arugment\n", - "def update_data(plot_instance):\n", - " new_data = np.random.rand(512, 512)\n", - " plot_instance[\"random-image\"].data = new_data\n", - "\n", - "#add this as an animation function\n", - "plot_v.add_animations(update_data)\n", - "\n", - "# show the plot\n", - "plot_v.show()" + "# testing cell, ignore\n", + "plot_test(\"astronaut\", plot)" ] }, { "cell_type": "markdown", - "id": "b313eda1-6e6c-466f-9fd5-8b70c1d3c110", + "id": "b53bc11a-ddf1-4786-8dca-8f3d2eaf993d", "metadata": {}, "source": [ - "### We can share controllers across plots\n", - "\n", - "This example creates a new plot, but it synchronizes the pan-zoom controller" + "### Indexing plots" + ] + }, + { + "cell_type": "markdown", + "id": "67b92ffd-40cc-43fe-9df9-0e0d94763d8e", + "metadata": {}, + "source": [ + "**Plots are indexable and give you their graphics by name**" ] }, { "cell_type": "code", "execution_count": null, - "id": "86e70b1e-4328-4035-b992-70dff16d2a69", - "metadata": {}, + "id": "e6ba689c-ff4a-44ef-9663-f2c8755072c4", + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "plot_sync = Plot(controller=plot_v.controller)\n", - "\n", - "data = np.random.rand(512, 512)\n", - "\n", - "image_graphic_instance = plot_sync.add_image(data=data, cmap=\"viridis\")\n", - "\n", - "# you will need to define a new animation function for this graphic\n", - "def update_data_2():\n", - " new_data = np.random.rand(512, 512)\n", - " # alternatively, you can use the stored reference to the graphic as well instead of indexing the Plot\n", - " image_graphic_instance.data = new_data\n", - "\n", - "plot_sync.add_animations(update_data_2)\n", - "\n", - "plot_sync.show()" + "plot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b18f4e3-e13b-46d5-af1f-285c5a7fdc12", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plot[\"sample-image\"]" ] }, { "cell_type": "markdown", - "id": "f226c9c2-8d0e-41ab-9ab9-1ae31fd91de5", + "id": "a64314bf-a737-4858-803b-ea2adbd3578c", "metadata": {}, "source": [ - "#### Keeping a reference to the Graphic instance, as shown above `image_graphic_instance`, is useful if you're creating something where you need flexibility in the naming of the graphics" + "**You can also use numerical indexing on `plot.graphics`**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c09a1924-70f8-4d9e-9e92-510d700ac715", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plot.graphics" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec9e6ba6-553f-4718-ba13-471c8c7c3c4e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plot.graphics[0]" ] }, { "cell_type": "markdown", - "id": "d11fabb7-7c76-4e94-893d-80ed9ee3be3d", + "id": "4316a8b5-5f33-427a-8f52-b101d1daab67", "metadata": {}, "source": [ - "### You can also use `ipywidgets.VBox` and `HBox` to stack plots. See the `gridplot` notebooks for a proper gridplot interface for more automated subplotting" + "The `Graphic` instance is also returned when you call `plot.add_`." ] }, { "cell_type": "code", "execution_count": null, - "id": "ef9743b3-5f81-4b79-9502-fa5fca08e56d", - "metadata": {}, + "id": "2b5c1321-1fd4-44bc-9433-7439ad3e22cf", + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "VBox([plot_v.show(), plot_sync.show()])" + "image_graphic" ] }, { "cell_type": "code", "execution_count": null, - "id": "11839d95-8ff7-444c-ae13-6b072c3112c5", - "metadata": {}, + "id": "b12bf75e-4e93-4930-9146-e96324fdf3f6", + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "HBox([plot_v.show(), plot_sync.show()])" + "image_graphic == plot[\"sample-image\"]" ] }, { "cell_type": "markdown", - "id": "eaaeac07-5046-4e17-ab17-b685645e65f4", + "id": "5694dca1-1041-4e09-a1da-85b293c5af47", "metadata": {}, "source": [ - "# Sliders to scroll through image data\n", + "### RGB images are also supported\n", "\n", - "We often already have large image arrays (whether in RAM or through lazy loading), and want to view 2D frames across one or more dimensions. There is an `ImageWidget` that should really be used for this, but this example just shows how you can use `ipywidgets` to change data or any **`GraphicFeature`**" + "`cmap` arguments are ignored for rgb images, but vmin vmax still works" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d6b8ca51-073d-47aa-a464-44511fcaccbc", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plot_rgb = Plot()\n", + "\n", + "plot_rgb.add_image(new_data, name=\"rgb-image\")\n", + "\n", + "plot_rgb.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71eae361-3bbf-4d1f-a903-3615d35b557b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plot_rgb.camera.world.scale_y *= -1" ] }, { "cell_type": "markdown", - "id": "6c9616e3-6ad0-4aa6-9f9f-f3282b05b0f1", + "id": "7fc66377-00e8-4f32-9671-9cf63f74529f", "metadata": {}, "source": [ - "### Some code to generate a bunch of time-varying Gaussians. This code is NOT important for understanding `fastplotlib`, it just generates some video-like data for us to visualize!" + "vmin and vmax are still applicable to rgb images" ] }, { "cell_type": "code", "execution_count": null, - "id": "0bcedf83-cbdd-4ec2-b8d5-172aa72a3e04", - "metadata": {}, + "id": "cafaa403-50a2-403c-b8e7-b0938d48cadd", + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "import numpy as np\n", - "from scipy.stats import multivariate_normal\n", - "\n", - "# set up gaussians centered at component_centers\n", - "n_frames = 1000\n", - "spatial_dims = 512\n", - "\n", - "frame_shape = [512, 512]\n", - "\n", - "n_components = 32\n", - "component_centers = (np.random.rand(n_components, 2) * spatial_dims).astype(int)\n", - "\n", - "# create component images: stack of images one for ech component\n", - "spatial_sigma = 50\n", - "x, y = np.meshgrid(\n", - " np.arange(0, spatial_dims),\n", - " np.arange(0, spatial_dims)\n", - ")\n", + "plot_rgb[\"rgb-image\"].cmap.vmin = 100" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8d600c7-aa80-4c3f-8ec0-6641e9359c3a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# testing cell, ignore\n", + "plot_test(\"astronaut_RGB\", plot_rgb)" + ] + }, + { + "cell_type": "markdown", + "id": "1cb03f42-1029-4b16-a16b-35447d9e2955", + "metadata": { + "tags": [] + }, + "source": [ + "### Image updates\n", "\n", - "pos = np.dstack((x, y))\n", - "component_sigma = np.array(\n", - " [[spatial_sigma, 0],\n", - " [0, spatial_sigma]]\n", - ")\n", + "This examples show how you can define animation functions that run on every render cycle." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aadd757f-6379-4f52-a709-46aa57c56216", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# create another `Plot` instance\n", + "plot_v = Plot()\n", "\n", - "component_images = []\n", - "for comp_ix in range(n_components):\n", - " comp_mean = component_centers[comp_ix]\n", - " gauss_rep = multivariate_normal(comp_mean, component_sigma)\n", - " gauss_img = gauss_rep.pdf(pos)\n", - " component_images.append(gauss_img)\n", + "plot.canvas.max_buffered_frames = 1\n", "\n", - "component_images = np.array(component_images)\n", + "# make some random data again\n", + "data = np.random.rand(512, 512)\n", "\n", + "# plot the data\n", + "plot_v.add_image(data=data, name=\"random-image\")\n", "\n", - "# generate traces\n", - "tau = 10\n", - "max_amp = 2000\n", - "amps_all = []\n", + "# a function to update the image_graphic\n", + "# a plot will pass its plot instance to the animation function as an arugment\n", + "def update_data(plot_instance):\n", + " new_data = np.random.rand(512, 512)\n", + " plot_instance[\"random-image\"].data = new_data\n", "\n", - "for component_num in range(n_components):\n", - " amps = []\n", - " amp = 0\n", - " for time_step in np.arange(n_frames):\n", - " if np.random.uniform(0,1) > 0.98:\n", - " amp = max_amp\n", - " else:\n", - " amp = np.max(np.array([amp - amp/tau, 0]));\n", - " amps.append(amp)\n", - " amps = np.array(amps)\n", - " amps_all.append(amps)\n", - "amps_all = np.array(amps_all)\n", + "#add this as an animation function\n", + "plot_v.add_animations(update_data)\n", "\n", - "# create movie\n", - "movie = np.zeros((n_frames, spatial_dims, spatial_dims))\n", - "for frame_ix in np.arange(n_frames):\n", - " for comp_ix in range(n_components):\n", - " movie[frame_ix] += amps_all[comp_ix][frame_ix] * component_images[comp_ix]" + "# show the plot\n", + "plot_v.show()" ] }, { "cell_type": "markdown", - "id": "9ac18409-56d8-46cc-86bf-32456fcece48", + "id": "b313eda1-6e6c-466f-9fd5-8b70c1d3c110", "metadata": {}, "source": [ - "### Now we have a movie of the following shape, an image sequence" + "### We can share controllers across plots\n", + "\n", + "This example creates a new plot, but it synchronizes the pan-zoom controller" ] }, { "cell_type": "code", "execution_count": null, - "id": "8b560151-c258-415c-a20d-3cccd421f44a", + "id": "86e70b1e-4328-4035-b992-70dff16d2a69", "metadata": {}, "outputs": [], "source": [ - "movie.shape" + "plot_sync = Plot(controller=plot_v.controller)\n", + "\n", + "data = np.random.rand(512, 512)\n", + "\n", + "image_graphic_instance = plot_sync.add_image(data=data, cmap=\"viridis\")\n", + "\n", + "# you will need to define a new animation function for this graphic\n", + "def update_data_2():\n", + " new_data = np.random.rand(512, 512)\n", + " # alternatively, you can use the stored reference to the graphic as well instead of indexing the Plot\n", + " image_graphic_instance.data = new_data\n", + "\n", + "plot_sync.add_animations(update_data_2)\n", + "\n", + "plot_sync.show()" ] }, { "cell_type": "markdown", - "id": "f70cf836-222a-40ef-835f-1d2a02331a12", + "id": "f226c9c2-8d0e-41ab-9ab9-1ae31fd91de5", "metadata": {}, "source": [ - "### This is usually [time, x, y]" + "#### Keeping a reference to the Graphic instance, as shown above `image_graphic_instance`, is useful if you're creating something where you need flexibility in the naming of the graphics" ] }, { "cell_type": "markdown", - "id": "836fef2e-5a27-44ec-9d7e-943d496b7864", + "id": "d11fabb7-7c76-4e94-893d-80ed9ee3be3d", "metadata": {}, "source": [ - "## Plot and scroll through the first dimension with a slider" + "### You can also use `ipywidgets.VBox` and `HBox` to stack plots. See the `gridplot` notebooks for a proper gridplot interface for more automated subplotting" ] }, { "cell_type": "code", "execution_count": null, - "id": "62166a9f-ab43-45cc-a6db-6d441387e9a5", + "id": "ef9743b3-5f81-4b79-9502-fa5fca08e56d", "metadata": {}, "outputs": [], "source": [ - "plot_movie = Plot()\n", - "\n", - "# plot the first frame to initialize\n", - "movie_graphic = plot_movie.add_image(movie[0], vmin=0, vmax=movie.max(), cmap=\"gnuplot2\")\n", - "\n", - "# make a slider\n", - "slider = IntSlider(min=0, max=movie.shape[0] - 1, step=1, value=0)\n", - "\n", - "# function to update movie_graphic\n", - "def update_movie(change): \n", - " index = change[\"new\"]\n", - " movie_graphic.data = movie[index]\n", - " \n", - "slider.observe(update_movie, \"value\")\n", - " \n", - "# Use an ipywidgets VBox to show the plot and slider\n", - "VBox([plot_movie.show(), slider])" + "VBox([plot_v.show(), plot_sync.show()])" ] }, { - "cell_type": "markdown", - "id": "876f1f89-c12e-44a5-9b00-9e6b4781b584", - "metadata": { - "jp-MarkdownHeadingCollapsed": true, - "tags": [] - }, + "cell_type": "code", + "execution_count": null, + "id": "11839d95-8ff7-444c-ae13-6b072c3112c5", + "metadata": {}, + "outputs": [], "source": [ - "#### Note that the use of globals in the `update_movie()` here can get messy, this is not recommended and you should create a class to properly handle combining widgets like this. _However_ if you want slider widgets for imaging data the recommended way to do this is by using the `ImageWidget`, see the `image_widget.ipynb` notebook for details." + "HBox([plot_v.show(), plot_sync.show()])" ] }, { @@ -532,6 +658,19 @@ "plot_l.show()" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4060576-2f29-4e4b-a86a-0410c766bd98", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# testing cell, ignore\n", + "plot_test(\"lines\", plot_l)" + ] + }, { "cell_type": "markdown", "id": "22dde600-0f56-4370-b017-c8f23a6c01aa", @@ -638,6 +777,19 @@ "cosine_graphic.colors[15:50:3] = \"cyan\"" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef8cab1b-8327-43e2-b021-176125b91ca9", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# testing cell, ignore\n", + "plot_test(\"lines-colors\", plot_l)" + ] + }, { "cell_type": "markdown", "id": "c29f81f9-601b-49f4-b20c-575c56e58026", @@ -667,6 +819,19 @@ "cosine_graphic.data[0] = np.array([[-10, 0, 0]])" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "96086bd4-cdaa-467d-a68b-1f57002ad6c5", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# testing cell, ignore\n", + "plot_test(\"lines-data\", plot_l)" + ] + }, { "cell_type": "markdown", "id": "3f6d264b-1b03-407e-9d83-cd6cfb02e706", @@ -759,6 +924,19 @@ "plot_l[\"image\"].position_x = -50" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae3e3dc9-e49b-430a-8471-5d0a0d659d20", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# testing cell, ignore\n", + "plot_test(\"lines-underlay\", plot_l)" + ] + }, { "cell_type": "markdown", "id": "2c90862e-2f2a-451f-a468-0cf6b857e87a", @@ -805,6 +983,19 @@ "plot_l3d.auto_scale(maintain_aspect=True)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "5135f3f1-a004-4451-86cd-ead6acea6e13", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# testing cell, ignore\n", + "plot_test(\"lines-3d\", plot_l)" + ] + }, { "cell_type": "markdown", "id": "a202b3d0-2a0b-450a-93d4-76d0a1129d1d", @@ -841,7 +1032,7 @@ "\n", "# if you have a good GPU go for 1.5 million points :D \n", "# this is multiplied by 3\n", - "n_points = 500_000\n", + "#n_points = 500_000\n", "\n", "# dimensions always have to be [n_points, xyz]\n", "dims = (n_points, 3)\n", @@ -964,6 +1155,14 @@ "metadata": {}, "outputs": [], "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79a3befe-9121-4738-9868-eded79a5d784", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/fastplotlib/graphics/_features/_colors.py b/fastplotlib/graphics/_features/_colors.py index feb349984..256a5d65f 100644 --- a/fastplotlib/graphics/_features/_colors.py +++ b/fastplotlib/graphics/_features/_colors.py @@ -1,7 +1,7 @@ import numpy as np import pygfx -from ...utils import make_colors, get_cmap_texture, make_pygfx_colors, parse_cmap_values +from ...utils import make_colors, get_cmap_texture, make_pygfx_colors, parse_cmap_values, quick_min_max from ._base import ( GraphicFeature, GraphicFeatureIndexable, @@ -349,6 +349,10 @@ def vmax(self, value: float): ) self._feature_changed(key=None, new_data=None) + def reset_vmin_vmax(self): + """Reset vmin vmax values based on current data""" + self.vmin, self.vmax = quick_min_max(self._parent.data()) + def _feature_changed(self, key, new_data): # this is a non-indexable feature so key=None From 0da1f0ac1ed3c05c63f46d170b82b68ade025163 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 03:54:22 -0400 Subject: [PATCH 02/13] nb test screenshots to CI --- .github/workflows/ci.yml | 4 +++- .github/workflows/screenshots.yml | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34284f8bc..3abcfaaf0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -97,4 +97,6 @@ jobs: if: ${{ failure() }} with: name: screenshot-diffs - path: examples/desktop/diffs + path: | + examples/desktop/diffs + examples/notebooks/diffs diff --git a/.github/workflows/screenshots.yml b/.github/workflows/screenshots.yml index 984d84aba..488ad108f 100644 --- a/.github/workflows/screenshots.yml +++ b/.github/workflows/screenshots.yml @@ -44,8 +44,11 @@ jobs: run: | # regenerate screenshots REGENERATE_SCREENSHOTS=1 pytest -v examples + REGENERATE_SCREENSHOTS=1 pytest --nbmake examples/notebooks/ - uses: actions/upload-artifact@v3 if: always() with: name: screenshots - path: examples/desktop/screenshots/ + path: | + examples/desktop/screenshots/ + examples/notebooks/screenshots/ From 61be31796182be861aecb495e98f96b3f2b48c47 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 04:00:51 -0400 Subject: [PATCH 03/13] add simple.ipynb test screenshots --- examples/notebooks/screenshots/nb-astronaut.png | 3 +++ examples/notebooks/screenshots/nb-astronaut_RGB.png | 3 +++ examples/notebooks/screenshots/nb-camera.png | 3 +++ examples/notebooks/screenshots/nb-lines-3d.png | 3 +++ examples/notebooks/screenshots/nb-lines-colors.png | 3 +++ examples/notebooks/screenshots/nb-lines-data.png | 3 +++ examples/notebooks/screenshots/nb-lines-underlay.png | 3 +++ examples/notebooks/screenshots/nb-lines.png | 3 +++ 8 files changed, 24 insertions(+) create mode 100644 examples/notebooks/screenshots/nb-astronaut.png create mode 100644 examples/notebooks/screenshots/nb-astronaut_RGB.png create mode 100644 examples/notebooks/screenshots/nb-camera.png create mode 100644 examples/notebooks/screenshots/nb-lines-3d.png create mode 100644 examples/notebooks/screenshots/nb-lines-colors.png create mode 100644 examples/notebooks/screenshots/nb-lines-data.png create mode 100644 examples/notebooks/screenshots/nb-lines-underlay.png create mode 100644 examples/notebooks/screenshots/nb-lines.png diff --git a/examples/notebooks/screenshots/nb-astronaut.png b/examples/notebooks/screenshots/nb-astronaut.png new file mode 100644 index 000000000..e8345f7b2 --- /dev/null +++ b/examples/notebooks/screenshots/nb-astronaut.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36a11f5c0a80e1cfbdeb318b314886f4d8e02ba8a763bed0db9994ef451bfd42 +size 128068 diff --git a/examples/notebooks/screenshots/nb-astronaut_RGB.png b/examples/notebooks/screenshots/nb-astronaut_RGB.png new file mode 100644 index 000000000..0ff257ccf --- /dev/null +++ b/examples/notebooks/screenshots/nb-astronaut_RGB.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc27fc081b464bb53afd98d3748b8bc75764537d76a8012b9f1b2c1d4c10613d +size 125492 diff --git a/examples/notebooks/screenshots/nb-camera.png b/examples/notebooks/screenshots/nb-camera.png new file mode 100644 index 000000000..cbf936192 --- /dev/null +++ b/examples/notebooks/screenshots/nb-camera.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cbf213d944a16cf9f72542e7a2172330fefa97c8577905f07df12559eb4485c3 +size 89303 diff --git a/examples/notebooks/screenshots/nb-lines-3d.png b/examples/notebooks/screenshots/nb-lines-3d.png new file mode 100644 index 000000000..1600c6bed --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-3d.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fbdee6b3c693082b037b0275111075b53d82c73a76d6f4ad4c20517d2a62d436 +size 59147 diff --git a/examples/notebooks/screenshots/nb-lines-colors.png b/examples/notebooks/screenshots/nb-lines-colors.png new file mode 100644 index 000000000..b9972c8f4 --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-colors.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a8eefa5106414bfb540b282d74372831ef3c4a9d941aaf50026ea64a3d3009f7 +size 40544 diff --git a/examples/notebooks/screenshots/nb-lines-data.png b/examples/notebooks/screenshots/nb-lines-data.png new file mode 100644 index 000000000..14d6f89f0 --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-data.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e89906d0d749f443e751eeb43b017622a46dfaa91545e9135d0a519e0aad0eb +size 54446 diff --git a/examples/notebooks/screenshots/nb-lines-underlay.png b/examples/notebooks/screenshots/nb-lines-underlay.png new file mode 100644 index 000000000..1600c6bed --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-underlay.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fbdee6b3c693082b037b0275111075b53d82c73a76d6f4ad4c20517d2a62d436 +size 59147 diff --git a/examples/notebooks/screenshots/nb-lines.png b/examples/notebooks/screenshots/nb-lines.png new file mode 100644 index 000000000..3dcc1767e --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:39478dbf9af2f74ae0e0240616d94480569d53dcbd5f046315eeff3855d4cb2e +size 37711 From 746dd3d65871c805a8cf3268eba8fe0d537eadd2 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 04:15:10 -0400 Subject: [PATCH 04/13] imageio note in simple.ipynb --- examples/notebooks/simple.ipynb | 35 +++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/examples/notebooks/simple.ipynb b/examples/notebooks/simple.ipynb index 8a3453285..91d0d302c 100644 --- a/examples/notebooks/simple.ipynb +++ b/examples/notebooks/simple.ipynb @@ -12,6 +12,38 @@ "This notebook goes through the basic components of the `fastplotlib` API, image, image updates, line plots, and scatter plots. " ] }, + { + "cell_type": "markdown", + "id": "ae07272b-e94b-4262-b486-6b3ddac63038", + "metadata": {}, + "source": [ + "**The example images are from `imageio` so you will need to install it for this example notebook. But `imageio` is not required to use `fasptlotlib`**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6674c90b-bfe3-4a71-ab7d-21e9cc03c050", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "!pip install imageio" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c50e177-5800-4e19-a4f6-d0e0a082e4cd", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import imageio.v3 as iio" + ] + }, { "cell_type": "code", "execution_count": null, @@ -23,8 +55,7 @@ "source": [ "from fastplotlib import Plot\n", "from ipywidgets import VBox, HBox, IntSlider\n", - "import numpy as np\n", - "import imageio.v3 as iio" + "import numpy as np" ] }, { From 2d8393711c25d0ed00c21a467036fd23e352d77a Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 04:31:40 -0400 Subject: [PATCH 05/13] try to make failure detection work --- examples/notebooks/nb_test_utils.py | 9 +++++---- examples/notebooks/simple.ipynb | 17 +++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/examples/notebooks/nb_test_utils.py b/examples/notebooks/nb_test_utils.py index 2bda0fd3c..8f7d1839a 100644 --- a/examples/notebooks/nb_test_utils.py +++ b/examples/notebooks/nb_test_utils.py @@ -32,7 +32,7 @@ def plot_test(name, plot: PlotArea): try: assert_screenshot_equal(name, snapshot.data) except AssertionError: - FAILURES.append((name, format_exc())) + FAILURES.append(name) def regenerate_screenshot(name, data): @@ -81,7 +81,8 @@ def get_diffs_rgba(slicer): path.unlink() -@pytest.fixture(scope="session", autouse=True) -def check_failures(request): +def notebook_finished(notebook_name: str): if len(FAILURES) > 0: - raise AssertionError(FAILURES) + raise AssertionError( + f"Failures for notebook: <{notebook_name}>:\n{FAILURES}" + ) \ No newline at end of file diff --git a/examples/notebooks/simple.ipynb b/examples/notebooks/simple.ipynb index 91d0d302c..5956aa614 100644 --- a/examples/notebooks/simple.ipynb +++ b/examples/notebooks/simple.ipynb @@ -68,7 +68,7 @@ "outputs": [], "source": [ "# this is only for testing, you do not need this to use fastplotlib\n", - "from nb_test_utils import plot_test" + "from nb_test_utils import plot_test, notebook_finished" ] }, { @@ -295,6 +295,8 @@ "id": "bb568f89-ac92-4dde-9359-789049dc758a", "metadata": {}, "source": [ + "\n", + "\n", "reset vmin vmax" ] }, @@ -1185,15 +1187,10 @@ "id": "370d5837-aecf-4e52-9323-b899ac458bbf", "metadata": {}, "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "79a3befe-9121-4738-9868-eded79a5d784", - "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "# for testing, ignore\n", + "notebook_finished(\"simple.ipynb\")" + ] } ], "metadata": { From f5d81034dcf8212d700e5c7d0cf30494ad362c51 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 04:34:40 -0400 Subject: [PATCH 06/13] faster scatter nb, less points --- examples/notebooks/scatter.ipynb | 116 ++++++++++++------------------- 1 file changed, 44 insertions(+), 72 deletions(-) diff --git a/examples/notebooks/scatter.ipynb b/examples/notebooks/scatter.ipynb index 094204b63..948403f11 100644 --- a/examples/notebooks/scatter.ipynb +++ b/examples/notebooks/scatter.ipynb @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "9b3041ad-d94e-4b2a-af4d-63bcd19bf6c2", "metadata": { "tags": [] @@ -25,9 +25,11 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "51f1d76a-f815-460f-a884-097fe3ea81ac", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "# create a random distribution of 10,000 xyz coordinates\n", @@ -35,7 +37,7 @@ "\n", "# if you have a good GPU go for 1.2 million points :D \n", "# this is multiplied by 3\n", - "n_points = 400_000\n", + "#n_points = 400_000\n", "dims = (n_points, 3)\n", "\n", "offset = 15\n", @@ -54,60 +56,12 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "922990b6-24e9-4fa0-977b-6577f9752d84", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "0d49371132174eb4a9501964b4584d67", - "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": "a94246496c054599bc44a0a77ea7d58e", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "JupyterWgpuCanvas()" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "metadata": { + "tags": [] + }, + "outputs": [], "source": [ "# grid with 2 rows and 2 columns\n", "shape = (2, 2)\n", @@ -148,52 +102,62 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "7b912961-f72e-46ef-889f-c03234831059", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "grid_plot[0, 1].graphics[0].colors[400_000:600_000] = \"r\"" + "grid_plot[0, 1].graphics[0].colors[n_points:int(n_points * 1.5)] = \"r\"" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "c6085806-c001-4632-ab79-420b4692693a", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "grid_plot[0, 1].graphics[0].colors[:100_000:10] = \"blue\"" + "grid_plot[0, 1].graphics[0].colors[:n_points:10] = \"blue\"" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "6f416825-df31-4e5d-b66b-07f23b48e7db", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "grid_plot[0, 1].graphics[0].colors[800_000:] = \"green\"" + "grid_plot[0, 1].graphics[0].colors[n_points:] = \"green\"" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "c0fd611e-73e5-49e6-a25c-9d5b64afa5f4", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "grid_plot[0, 1].graphics[0].colors[800_000:, -1] = 0" + "grid_plot[0, 1].graphics[0].colors[n_points:, -1] = 0" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "cd390542-3a44-4973-8172-89e5583433bc", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "grid_plot[0, 1].graphics[0].data[:400_000] = grid_plot[0, 1].graphics[0].data[800_000:]" + "grid_plot[0, 1].graphics[0].data[:n_points] = grid_plot[0, 1].graphics[0].data[n_points * 2:]" ] }, { @@ -203,6 +167,14 @@ "metadata": {}, "outputs": [], "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d8aac54-4f36-41d4-8e5b-8d8da2f0d17d", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From 30c730ebd02c7569937ede5bc59a2986f76f5fc2 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 04:39:49 -0400 Subject: [PATCH 07/13] lines_cmap nb screenshot tests --- examples/notebooks/lines_cmap.ipynb | 114 ++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/examples/notebooks/lines_cmap.ipynb b/examples/notebooks/lines_cmap.ipynb index 5eb783d77..8f3760e1a 100644 --- a/examples/notebooks/lines_cmap.ipynb +++ b/examples/notebooks/lines_cmap.ipynb @@ -13,6 +13,19 @@ "import fastplotlib as fpl" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d2ef4aa-0e4c-4694-ae2e-05da1153a413", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# this is only for testing, you do not need this to use fastplotlib\n", + "from nb_test_utils import plot_test, notebook_finished" + ] + }, { "cell_type": "code", "execution_count": null, @@ -49,6 +62,18 @@ "plot.show()" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "727282c3-aadf-420f-a88e-9dd4d4e91263", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "plot_test(\"lines-cmap-white\", plot)" + ] + }, { "cell_type": "markdown", "id": "889b1858-ed64-4d6b-96ad-3883fbe4d38e", @@ -69,6 +94,19 @@ "plot.graphics[0].cmap = \"jet\"" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "3c9b0bc8-b176-425c-8036-63dc55ab7466", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# for testing, ignore\n", + "plot_test(\"lines-cmap-jet\", plot)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -81,6 +119,19 @@ "plot.graphics[0].cmap.values = sine[:, 1]" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b19d2d4-90e7-40ed-afb9-13abe5474ace", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# for testing, ignore\n", + "plot_test(\"lines-cmap-jet-values\", plot)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -93,6 +144,19 @@ "plot.graphics[0].cmap.values = cosine[:, 1]" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a6c4739-fa61-4532-865e-21107eab76f9", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# for testing, ignore\n", + "plot_test(\"lines-cmap-jet-values-cosine\", plot)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -105,6 +169,19 @@ "plot.graphics[0].cmap = \"viridis\"" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "45acfd2f-09f5-418c-bca5-3e574348b7d5", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# for testing, ignore\n", + "plot_test(\"lines-cmap-viridis\", plot)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -129,6 +206,19 @@ "plot.graphics[0].cmap.values = cmap_values" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "7548407f-05ed-4c47-93cc-131c61f8e242", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# for testing, ignore\n", + "plot_test(\"lines-cmap-viridis-values\", plot)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -147,6 +237,30 @@ "id": "c290c642-ba5f-4a46-9a17-c434cb39de26", "metadata": {}, "outputs": [], + "source": [ + "# for testing, ignore\n", + "plot_test(\"lines-cmap-tab-10\", plot)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4b9e735-72e9-4f0e-aa3e-43db57e65c99", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# for testing, ignore\n", + "notebook_finished(\"lines_cmap.ipynb\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6735cc0-910c-4854-ac50-8ee553a6475e", + "metadata": {}, + "outputs": [], "source": [] } ], From 5007b0d7d7bfc1914969c194ad7a7f180a1493e6 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 04:55:25 -0400 Subject: [PATCH 08/13] simplify notebook_finished() --- examples/notebooks/nb_test_utils.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/notebooks/nb_test_utils.py b/examples/notebooks/nb_test_utils.py index 8f7d1839a..e9ea05d3e 100644 --- a/examples/notebooks/nb_test_utils.py +++ b/examples/notebooks/nb_test_utils.py @@ -1,8 +1,6 @@ import os from pathlib import Path -from traceback import format_exc -import pytest import imageio.v3 as iio import numpy as np @@ -81,8 +79,8 @@ def get_diffs_rgba(slicer): path.unlink() -def notebook_finished(notebook_name: str): +def notebook_finished(): if len(FAILURES) > 0: raise AssertionError( - f"Failures for notebook: <{notebook_name}>:\n{FAILURES}" - ) \ No newline at end of file + f"Failures for plots:\n{FAILURES}" + ) From 0ae11ec536d3670d037aeb5a8967e119807c6201 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 04:55:41 -0400 Subject: [PATCH 09/13] use real image for lines underlay --- examples/notebooks/simple.ipynb | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/notebooks/simple.ipynb b/examples/notebooks/simple.ipynb index 5956aa614..6940f2a51 100644 --- a/examples/notebooks/simple.ipynb +++ b/examples/notebooks/simple.ipynb @@ -948,13 +948,14 @@ }, "outputs": [], "source": [ - "img = np.random.rand(20, 100)\n", + "img = iio.imread(\"imageio:camera.png\")\n", "\n", - "plot_l.add_image(img, name=\"image\", cmap=\"gray\")\n", + "plot_l.add_image(img[::20, ::20], name=\"image\", cmap=\"gray\")\n", "\n", "# z axix position -1 so it is below all the lines\n", "plot_l[\"image\"].position_z = -1\n", - "plot_l[\"image\"].position_x = -50" + "plot_l[\"image\"].position_x = -8\n", + "plot_l[\"image\"].position_y = -8" ] }, { @@ -1189,8 +1190,16 @@ "outputs": [], "source": [ "# for testing, ignore\n", - "notebook_finished(\"simple.ipynb\")" + "notebook_finished()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52b6c281-ab27-4984-9a6e-f1e27f609e44", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From 30fe787aacf63c0c6a446e27d2eb1fa748420449 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 05:00:22 -0400 Subject: [PATCH 10/13] fix arg --- examples/notebooks/lines_cmap.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/notebooks/lines_cmap.ipynb b/examples/notebooks/lines_cmap.ipynb index 8f3760e1a..c6dc604b4 100644 --- a/examples/notebooks/lines_cmap.ipynb +++ b/examples/notebooks/lines_cmap.ipynb @@ -252,7 +252,7 @@ "outputs": [], "source": [ "# for testing, ignore\n", - "notebook_finished(\"lines_cmap.ipynb\")" + "notebook_finished()" ] }, { From 2327ed18e7dfd7094d8283ea63c836c79b44aee1 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 05:15:33 -0400 Subject: [PATCH 11/13] fix test --- examples/notebooks/simple.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/notebooks/simple.ipynb b/examples/notebooks/simple.ipynb index 6940f2a51..e994bfba8 100644 --- a/examples/notebooks/simple.ipynb +++ b/examples/notebooks/simple.ipynb @@ -1027,7 +1027,7 @@ "outputs": [], "source": [ "# testing cell, ignore\n", - "plot_test(\"lines-3d\", plot_l)" + "plot_test(\"lines-3d\", plot_l3d)" ] }, { From a63caf049ed6a21b9385664502d221cb7cc93113 Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 05:21:23 -0400 Subject: [PATCH 12/13] update nb screenshots --- examples/notebooks/screenshots/nb-lines-3d.png | 4 ++-- .../notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png | 3 +++ examples/notebooks/screenshots/nb-lines-cmap-jet-values.png | 3 +++ examples/notebooks/screenshots/nb-lines-cmap-jet.png | 3 +++ examples/notebooks/screenshots/nb-lines-cmap-tab-10.png | 3 +++ .../notebooks/screenshots/nb-lines-cmap-viridis-values.png | 3 +++ examples/notebooks/screenshots/nb-lines-cmap-viridis.png | 3 +++ examples/notebooks/screenshots/nb-lines-cmap-white.png | 3 +++ examples/notebooks/screenshots/nb-lines-underlay.png | 4 ++-- 9 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png create mode 100644 examples/notebooks/screenshots/nb-lines-cmap-jet-values.png create mode 100644 examples/notebooks/screenshots/nb-lines-cmap-jet.png create mode 100644 examples/notebooks/screenshots/nb-lines-cmap-tab-10.png create mode 100644 examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png create mode 100644 examples/notebooks/screenshots/nb-lines-cmap-viridis.png create mode 100644 examples/notebooks/screenshots/nb-lines-cmap-white.png diff --git a/examples/notebooks/screenshots/nb-lines-3d.png b/examples/notebooks/screenshots/nb-lines-3d.png index 1600c6bed..6bb05537a 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:fbdee6b3c693082b037b0275111075b53d82c73a76d6f4ad4c20517d2a62d436 -size 59147 +oid sha256:b7e61fb22db10e515a7d249649c5e220731c6ea5a83bb626f06dcf41167f117e +size 23052 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png b/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png new file mode 100644 index 000000000..b1045cde6 --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-cmap-jet-values-cosine.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f55806e64a8ffde2f11eed1dc75a874371800046c062da21e71554abedda251 +size 17136 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png b/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png new file mode 100644 index 000000000..53b3d4cbd --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-cmap-jet-values.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e5e9bcb785fe5efee324bdde451d62158668dafa0c026179bd11d38298fb0002 +size 18526 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-jet.png b/examples/notebooks/screenshots/nb-lines-cmap-jet.png new file mode 100644 index 000000000..8bfd0d577 --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-cmap-jet.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d6fd17a9a704b2d9c5341e85763f1ba9c5e3026da88858f004e66a781e02eaa +size 16310 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png b/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png new file mode 100644 index 000000000..3e76883bf --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-cmap-tab-10.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:672da2cc5e500ce3bbdabb01eaf5a7d2b9fb6ea4e6e95cb3392b2a0573a970d9 +size 14882 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png b/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png new file mode 100644 index 000000000..4b6212a6a --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-cmap-viridis-values.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e1224f75ce0286c4721b5f65af339fc922dcb2308f8d2fa3def10ead48cdce8 +size 15096 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-viridis.png b/examples/notebooks/screenshots/nb-lines-cmap-viridis.png new file mode 100644 index 000000000..35c38c881 --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-cmap-viridis.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6201cd8dc9273adca73329b0eae81faf6aed42c3bf8f7ee503b9251af499dcd +size 19203 diff --git a/examples/notebooks/screenshots/nb-lines-cmap-white.png b/examples/notebooks/screenshots/nb-lines-cmap-white.png new file mode 100644 index 000000000..67c2fc116 --- /dev/null +++ b/examples/notebooks/screenshots/nb-lines-cmap-white.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecb2d4d591b852bda8758efcf91d389442f916bbb4a06c5216d52dcf72172370 +size 12955 diff --git a/examples/notebooks/screenshots/nb-lines-underlay.png b/examples/notebooks/screenshots/nb-lines-underlay.png index 1600c6bed..d8809f301 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:fbdee6b3c693082b037b0275111075b53d82c73a76d6f4ad4c20517d2a62d436 -size 59147 +oid sha256:61ed6bde5639d57694cb8752052dda08a5f2f7dcc32966ab62385bc866c299e3 +size 55936 From 998d8efb99f0143c056731edcb6f643e658d758d Mon Sep 17 00:00:00 2001 From: kushalkolar Date: Thu, 6 Jul 2023 05:49:16 -0400 Subject: [PATCH 13/13] type annotation, small change to try and get git lfs to pull in PR action --- examples/notebooks/nb_test_utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/notebooks/nb_test_utils.py b/examples/notebooks/nb_test_utils.py index e9ea05d3e..e16ed2eaf 100644 --- a/examples/notebooks/nb_test_utils.py +++ b/examples/notebooks/nb_test_utils.py @@ -1,10 +1,11 @@ +from typing import * import os from pathlib import Path import imageio.v3 as iio import numpy as np -from fastplotlib.layouts._base import PlotArea +from fastplotlib import Plot, GridPlot # make dirs for screenshots and diffs current_dir = Path(__file__).parent @@ -20,7 +21,7 @@ FAILURES = list() -def plot_test(name, plot: PlotArea): +def plot_test(name, plot: Union[Plot, GridPlot]): snapshot = plot.canvas.snapshot() if "REGENERATE_SCREENSHOTS" in os.environ.keys(): pFad - Phonifier reborn

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy