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():