diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml index 83508e08d..aebf073dd 100644 --- a/.github/workflows/deploy_docs.yml +++ b/.github/workflows/deploy_docs.yml @@ -27,10 +27,14 @@ jobs: - name: Clone main repo uses: actions/checkout@main with: - path: napari + path: napari-repo ref: main repository: napari/napari + - name: Copy examples to docs folder + run: | + cp -R napari-repo/examples docs + - uses: actions/setup-python@v2 with: python-version: 3.9 @@ -40,7 +44,7 @@ jobs: - name: Install Dependencies run: | python -m pip install --upgrade pip - python -m pip install "napari/[all]" + python -m pip install "napari-repo/[all]" - name: Testing run: | diff --git a/examples/3D_paths.py b/examples/3D_paths.py deleted file mode 100644 index 885e9b78d..000000000 --- a/examples/3D_paths.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -3D Paths -======== - -Display two vectors layers ontop of a 4-D image layer. One of the vectors -layers is 3D and "sliced" with a different set of vectors appearing on -different 3D slices. Another is 2D and "broadcast" with the same vectors -appearing on each slice. - -.. tags:: visualization-advanced, layers -""" - -import numpy as np -from skimage import data -import napari - - -blobs = data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=3, volume_fraction=0.05 - ) - -viewer = napari.Viewer(ndisplay=3) -viewer.add_image(blobs.astype(float)) - -# sample vector coord-like data -path = np.array([np.array([[0, 0, 0], [0, 10, 10], [0, 5, 15], [20, 5, 15], - [56, 70, 21], [127, 127, 127]]), - np.array([[0, 0, 0], [0, 10, 10], [0, 5, 15], [0, 5, 15], - [0, 70, 21], [0, 127, 127]])]) - -print('Path', path.shape) -layer = viewer.add_shapes( - path, shape_type='path', edge_width=4, edge_color=['red', 'blue'] -) - -if __name__ == '__main__': - napari.run() diff --git a/examples/3Dimage_plane_rendering.py b/examples/3Dimage_plane_rendering.py deleted file mode 100644 index 661866c69..000000000 --- a/examples/3Dimage_plane_rendering.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -3D image plane rendering -======================== - -Display one 3D image layer and display it as a plane -with a simple widget for modifying plane parameters. - -.. tags:: visualization-advanced, gui, layers -""" -import napari -import numpy as np -from napari.utils.translations import trans -from skimage import data - -viewer = napari.Viewer(ndisplay=3) - -# add a 3D image -blobs = data.binary_blobs( - length=64, volume_fraction=0.1, n_dim=3 -).astype(np.float32) -image_layer = viewer.add_image( - blobs, rendering='mip', name='volume', blending='additive', opacity=0.25 -) - -# add the same 3D image and render as plane -# plane should be in 'additive' blending mode or depth looks all wrong -plane_parameters = { - 'position': (32, 32, 32), - 'normal': (0, 1, 0), - 'thickness': 10, -} - -plane_layer = viewer.add_image( - blobs, - rendering='average', - name='plane', - depiction='plane', - blending='additive', - opacity=0.5, - plane=plane_parameters -) -viewer.axes.visible = True -viewer.camera.angles = (45, 45, 45) -viewer.camera.zoom = 5 -viewer.text_overlay.text = trans._( - """ -shift + click and drag to move the plane -press 'x', 'y' or 'z' to orient the plane along that axis around the cursor -press 'o' to orient the plane normal along the camera view direction -press and hold 'o' then click and drag to make the plane normal follow the camera -""" -) -viewer.text_overlay.visible = True -if __name__ == '__main__': - napari.run() diff --git a/examples/3d_kymograph_.py b/examples/3d_kymograph_.py deleted file mode 100644 index 6ae3d66ee..000000000 --- a/examples/3d_kymograph_.py +++ /dev/null @@ -1,161 +0,0 @@ -""" -3D Kymographs -============= - -This example demonstrates that the volume rendering capabilities of napari -can also be used to render 2d timelapse acquisitions as kymographs. - -.. tags:: experimental -""" -from typing import Dict, List, Tuple -import numpy as np -import napari -from tqdm import tqdm -from itertools import product - -try: - from omero.gateway import BlitzGateway -except: - print("Could not import BlitzGateway which is") - print("required to download the sample datasets.") - print("Please install omero-py:") - print("https://pypi.org/project/omero-py/") - exit(-1) - - -def IDR_fetch_image(image_id: int, progressbar: bool = True) -> np.ndarray: - """ - Download the image with id image_id from the IDR - - Will fetch all image planes corresponding to separate - timepoints/channels/z-slices and return a numpy - array with dimension order (t,z,y,x,c) - - Displaying download progress can be disabled by passing - False to progressbar. - """ - - conn = BlitzGateway( - host="ws://idr.openmicroscopy.org/omero-ws", - username="public", - passwd="public", - secure=True, - ) - conn.connect() - conn.c.enableKeepAlive(60) - - idr_img = conn.getObject("Image", image_id) - idr_pixels = idr_img.getPrimaryPixels() - - _ = idr_img - nt, nz, ny, nx, nc = ( - _.getSizeT(), - _.getSizeZ(), - _.getSizeY(), - _.getSizeX(), - _.getSizeC(), - ) - - plane_indices = list(product(range(nz), range(nc), range(nt))) - idr_plane_iterator = idr_pixels.getPlanes(plane_indices) - - if progressbar: - idr_plane_iterator = tqdm(idr_plane_iterator, total=len(plane_indices)) - - _tmp = np.asarray(list(idr_plane_iterator)) - _tmp = _tmp.reshape((nz, nc, nt, ny, nx)) - # the following line reorders the axes (no summing, despite the name) - return np.einsum("jmikl", _tmp) - - -description = """ -3D-Kymographs in Napari -======================= - -About -===== -This example demonstrates that the volume rendering capabilities of napari -can also be used to render 2d timelapse acquisitions as kymographs. -Kymographs, also called space-time images, are a powerful tool to visualize -the dynamics of processes. -The most common way to visualize kymographs is to pick a single line through -a 2D image and visualize the time domain along a second axes. -Napari is not limited to 2D visualization an by harnessing its volume -volume rendering capabilities, we can create a 3D kymograph, -a powerful visualization that provides an overview of the complete -spatial and temporal data from a single view. - -Using napari's grid mode we can juxtapose multiple such 3D kymographs to -highlight the differences in cell dynamics under different siRNA treatments. - -The selected samples are from the Mitocheck screen and demonstrate siRNA -knockdowns of several genes. -The date is timelapse fluorescence microscopy of HeLa cells, with GFP- -tagged histone revealing the chromosomes. - -In the juxtaposed kymographs the reduced branching for the mitotitic -phenotypes caused by INCENP, AURKB and KIF11 knockdown compared to -TMPRSS11A knockdown is immediately obvious. - -Data Source -=========== -The samples to demonstrate this is downloaded from IDR: -https://idr.openmicroscopy.org/webclient/?show=screen-1302 - -Reference -========= -The data comes from the Mitocheck screen: - -Phenotypic profiling of the human genome by time-lapse microscopy reveals cell -division genes. - -Neumann B, Walter T, Hériché JK, Bulkescher J, Erfle H, Conrad C, Rogers P, -Poser I, Held M, Liebel U, Cetin C, Sieckmann F, Pau G, Kabbe R, Wünsche A, -Satagopam V, Schmitz MH, Chapuis C, Gerlich DW, Schneider R, Eils R, Huber W, -Peters JM, Hyman AA, Durbin R, Pepperkok R, Ellenberg J. -Nature. 2010 Apr 1;464(7289):721-7. -doi: 10.1038/nature08869. - -Acknowledgements -================ -Beate Neumann (EMBL) for helpful advice on mitotic phenotypes. - -""" - -print(description) - -samples = ( - {"IDRid": 2864587, "description": "AURKB knockdown", "vol": None}, - {"IDRid": 2862565, "description": "KIF11 knockdown", "vol": None}, - {"IDRid": 2867896, "description": "INCENP knockdown", "vol": None}, - {"IDRid": 1486532, "description": "TMPRSS11A knockdown", "vol": None}, -) - -print("-------------------------------------------------------") -print("Sample datasets will require ~490 MB download from IDR.") -answer = input("Press Enter to proceed, 'n' to cancel: ") -if answer.lower().startswith('n'): - print("User cancelled download. Exiting.") - exit(0) -print("-------------------------------------------------------") -for s in samples: - print(f"Downloading sample {s['IDRid']}.") - print(f"Description: {s['description']}") - s["vol"] = np.squeeze(IDR_fetch_image(s["IDRid"])) - -v = napari.Viewer(ndisplay=3) -scale = (5, 1, 1) # "stretch" time domain -for s in samples: - v.add_image( - s["vol"], name=s['description'], scale=scale, blending="opaque" - ) - -v.grid.enabled = True # show the volumes in grid mode -v.axes.visible = True # magenta error shows time direction - -# set an oblique view angle onto the kymograph grid -v.camera.center = (440, 880, 1490) -v.camera.angles = (-20, 23, -50) -v.camera.zoom = 0.17 - -napari.run() \ No newline at end of file diff --git a/examples/README.rst b/examples/README.rst deleted file mode 100644 index 482fb6a2e..000000000 --- a/examples/README.rst +++ /dev/null @@ -1,6 +0,0 @@ -Examples of napari usage. - -.. toctree:: - :maxdepth: 1 - - ../_tags/tagsindex diff --git a/examples/action_manager.py b/examples/action_manager.py deleted file mode 100644 index dbd222210..000000000 --- a/examples/action_manager.py +++ /dev/null @@ -1,116 +0,0 @@ -""" -Action manager -============== - -.. tags:: gui, experimental -""" -from random import shuffle - -import numpy as np -from skimage import data - -import napari -from napari._qt.widgets.qt_viewer_buttons import QtViewerPushButton -from napari.components import ViewerModel -from napari.utils.action_manager import action_manager - - -def rotate45(viewer: napari.Viewer): - """ - Rotate layer 0 of the viewer by 45º - - Parameters - ---------- - viewer : napari.Viewer - active (unique) instance of the napari viewer - - Notes - ----- - The `viewer` parameter needs to be named `viewer`, the action manager will - infer that we need an instance of viewer. - """ - angle = np.pi / 4 - from numpy import cos, sin - - r = np.array([[cos(angle), -sin(angle)], [sin(angle), cos(angle)]]) - layer = viewer.layers[0] - layer.rotate = layer.rotate @ r - - -# create the viewer with an image -viewer = napari.view_image(data.astronaut(), rgb=True) - -layer_buttons = viewer.window.qt_viewer.layerButtons - -# Button do not need to do anything, just need to be pretty; all the action -# binding and (un) binding will be done with the action manager, idem for -# setting the tooltip. -rot_button = QtViewerPushButton('warning') -layer_buttons.layout().insertWidget(3, rot_button) - - -def register_action(): - # Here we pass ViewerModel as the KeymapProvider as we want it to handle the shortcuts. - # we could also pass none and bind the shortcuts at the window level – though we - # are trying to not change the KeymapProvider API too much for now. - # we give an action name to the action for configuration purposes as we need - # it to be storable in json. - - # By convention (may be enforce later), we do give an action name which is iprefixed - # by the name of the package it is defined in, here napari, - action_manager.register_action( - name='napari:rotate45', - command=rotate45, - description='Rotate layer 0 by 45deg', - keymapprovider=ViewerModel, - ) - - -def bind_shortcut(): - # note that the tooltip of the corresponding button will be updated to - # remove the shortcut. - action_manager.unbind_shortcut('napari:reset_view') # Control-R - action_manager.bind_shortcut('napari:rotate45', 'Control-R') - - -def bind_button(): - action_manager.bind_button('napari:rotate45', rot_button) - - -# we can all bind_shortcut or register_action or bind_button in any order; -# this let us configure shortcuts even if plugins are loaded / unloaded. -callbacks = [register_action, bind_shortcut, bind_button] - -shuffle(callbacks) -for c in callbacks: - print('calling', c) - c() - - -# We can set the action manager in debug mode, to help us figure out which -# button is triggering which action. This will update the tooltips of the buttons -# to include the name of the action in between square brackets. - -action_manager._debug(True) - -# Let's also modify some existing shortcuts, by unbinding a few existing actions, -# and rebinding them with new shortcuts; below we change the add and select mode -# to be the = (same as + key on US Keyboards but without modifiers) and - keys. -# unbinding returns the old key if it exists; but we don't use it. - -# in practice you likely don't need to modify the shortcuts this way as it will -# be implemented in settings, though you could imagine a plugin that would -# allow toggling between many keymaps. - -settings = { - 'napari:activate_points_add_mode' : '=', - 'napari:activate_points_select_mode': '-', -} - - -for action, key in settings.items(): - _old_shortcut = action_manager.unbind_shortcut(action) - action_manager.bind_shortcut(action, key) - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_3D_image.py b/examples/add_3D_image.py deleted file mode 100644 index e85e1fb72..000000000 --- a/examples/add_3D_image.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Add 3D image -============ - -Display a 3D image layer using the :meth:`add_image` API. - -.. tags:: visualization-nD, layers -""" - -from skimage import data -import napari - - -blobs = data.binary_blobs(length=64, volume_fraction=0.1, n_dim=3).astype( - float -) -viewer = napari.Viewer(ndisplay=3) -# add the volume -viewer.add_image(blobs, scale=[3, 1, 1]) - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_grayscale_image.py b/examples/add_grayscale_image.py deleted file mode 100644 index ad890a6d8..000000000 --- a/examples/add_grayscale_image.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -Add grayscale image -=================== - -Display one grayscale image using the add_image API. - -.. tags:: visualization-basic -""" - -from skimage import data -import napari -import numpy as np - - -# simulating a grayscale image here for testing contrast limits adjustments -image = data.astronaut().mean(-1) * 100 + 100 -image += np.random.rand(*image.shape) * 3000 -viewer = napari.view_image(image.astype(np.uint16)) - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_image.py b/examples/add_image.py deleted file mode 100644 index b5e99dce5..000000000 --- a/examples/add_image.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -Add image -========= - -Display one image using the :func:`view_image` API. - -.. tags:: visualization-basic -""" - -from skimage import data -import napari - -# create the viewer with an image -viewer = napari.view_image(data.astronaut(), rgb=True) - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_image_transformed.py b/examples/add_image_transformed.py deleted file mode 100644 index a619c2897..000000000 --- a/examples/add_image_transformed.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -Add image transformed -===================== - -Display one image and transform it using the :func:`view_image` API. - -.. tags:: visualization-basic -""" - -from skimage import data -import napari - -# create the viewer with an image and transform (rotate) it -viewer = napari.view_image(data.astronaut(), rgb=True, rotate=45) - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_labels.py b/examples/add_labels.py deleted file mode 100644 index 1c7a6ad65..000000000 --- a/examples/add_labels.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Add labels -========== - -Display a labels layer above of an image layer using the ``add_labels`` and -``add_image`` APIs - -.. tags:: layers, visualization-basic -""" - -from skimage import data -from skimage.filters import threshold_otsu -from skimage.segmentation import clear_border -from skimage.measure import label -from skimage.morphology import closing, square, remove_small_objects -import napari - - -image = data.coins()[50:-50, 50:-50] - -# apply threshold -thresh = threshold_otsu(image) -bw = closing(image > thresh, square(4)) - -# remove artifacts connected to image border -cleared = remove_small_objects(clear_border(bw), 20) - -# label image regions -label_image = label(cleared) - -# initialise viewer with coins image -viewer = napari.view_image(image, name='coins', rgb=False) - -# add the labels -label_layer = viewer.add_labels(label_image, name='segmentation') - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_labels_with_features.py b/examples/add_labels_with_features.py deleted file mode 100644 index e68b15bb0..000000000 --- a/examples/add_labels_with_features.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Add labels with features -======================== - -Display a labels layer with various features - -.. tags:: layers, analysis -""" - - -from skimage import data -from skimage.filters import threshold_otsu -from skimage.segmentation import clear_border -from skimage.measure import label -from skimage.morphology import closing, square, remove_small_objects -import numpy as np -import napari - - -image = data.coins()[50:-50, 50:-50] - -# apply threshold -thresh = threshold_otsu(image) -bw = closing(image > thresh, square(4)) - -# remove artifacts connected to image border -cleared = remove_small_objects(clear_border(bw), 20) - -# label image regions -label_image = label(cleared) - -# initialise viewer with coins image -viewer = napari.view_image(image, name='coins', rgb=False) - -# get the size of each coin (first element is background area) -label_areas = np.bincount(label_image.ravel())[1:] - -# split coins into small or large -size_range = max(label_areas) - min(label_areas) -small_threshold = min(label_areas) + (size_range / 2) -coin_sizes = np.where(label_areas > small_threshold, 'large', 'small') - -label_features = { - 'row': ['none'] - + ['top'] * 4 - + ['bottom'] * 4, # background is row: none - 'size': ['none'] + list(coin_sizes), # background is size: none -} - -color = {1: 'white', 2: 'blue', 3: 'green', 4: 'red', 5: 'yellow'} - -# add the labels -label_layer = viewer.add_labels( - label_image, - name='segmentation', - features=label_features, - color=color, -) - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_multiscale_image.py b/examples/add_multiscale_image.py deleted file mode 100644 index ce2188f14..000000000 --- a/examples/add_multiscale_image.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Add multiscale image -==================== - -Displays a multiscale image - -.. tags:: visualization-advanced -""" - -from skimage import data -from skimage.transform import pyramid_gaussian -import napari -import numpy as np - - -# create multiscale from astronaut image -base = np.tile(data.astronaut(), (8, 8, 1)) -multiscale = list( - pyramid_gaussian(base, downscale=2, max_layer=4, multichannel=True) -) -print('multiscale level shapes: ', [p.shape[:2] for p in multiscale]) - -# add image multiscale -viewer = napari.view_image(multiscale, multiscale=True) - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_points.py b/examples/add_points.py deleted file mode 100644 index ab1a1b0d1..000000000 --- a/examples/add_points.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Add points -========== - -Display a points layer on top of an image layer using the ``add_points`` and -``add_image`` APIs - -.. tags:: visualization-basic -""" - -import numpy as np -from skimage import data -from skimage.color import rgb2gray -import napari - - -# add the image -viewer = napari.view_image(rgb2gray(data.astronaut())) -# add the points -points = np.array([[100, 100], [200, 200], [333, 111]]) -size = np.array([10, 20, 20]) -viewer.add_points(points, size=size) - -# unselect the image layer -viewer.layers.selection.discard(viewer.layers[0]) - -# adjust some of the points layer attributes -layer = viewer.layers[1] - -# change the layer name -layer.name = 'points' - -# change the layer visibility -layer.visible = False -layer.visible = True - -# select the layer -viewer.layers.selection.add(layer) -# deselect the layer -viewer.layers.selection.remove(layer) -# or: viewer.layers.selection.discard(layer) - -# change the layer opacity -layer.opacity = 0.9 - -# change the layer point symbol using an alias -layer.symbol = '+' - -# change the layer point out_of_slice_display status -layer.out_of_slice_display = True - -# change the layer mode -layer.mode = 'add' - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_points_on_nD_shapes.py b/examples/add_points_on_nD_shapes.py deleted file mode 100644 index 1cb95d635..000000000 --- a/examples/add_points_on_nD_shapes.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -Add points on nD shapes -======================= - -Add points on nD shapes in 3D using a mouse callback - -.. tags:: visualization-nD -""" - -import napari -import numpy as np - -# Create rectangles in 4D -data = [ - [ - [0, 50, 75, 75], - [0, 50, 125, 75], - [0, 100, 125, 125], - [0, 100, 75, 125] - ], - [ - [0, 10, 75, 75], - [0, 10, 125, 75], - [0, 40, 125, 125], - [0, 40, 75, 125] - ], - [ - [1, 100, 75, 75], - [1, 100, 125, 75], - [1, 50, 125, 125], - [1, 50, 75, 125] - ] - ] - -shapes_data = np.array(data) - -# add an empty 4d points layer -viewer = napari.view_points(ndim=4, size=3) -points_layer = viewer.layers[0] - -# add the shapes layer to the viewer -features = {'index': [0, 1, 2]} -for shape_type, mult in {('ellipse', 1), ('rectangle', -1)}: - shapes_layer = viewer.add_shapes( - shapes_data * mult, - face_color=['magenta', 'green', 'blue'], - edge_color='white', - blending='additive', - features=features, - text='index', - shape_type=shape_type, - ) - - @shapes_layer.mouse_drag_callbacks.append - def on_click(layer, event): - - shape_index, intersection_point = layer.get_index_and_intersection( - event.position, event.view_direction, event.dims_displayed - ) - - if (shape_index is not None) and (intersection_point is not None): - points_layer.add(intersection_point) - - -for d in data: - viewer.add_points(np.array(d)) -# set the viewer to 3D rendering mode with the first two rectangles in view -viewer.dims.ndisplay = 3 -viewer.dims.set_point(axis=0, value=0) -viewer.camera.angles = (70, 30, 150) -viewer.camera.zoom = 2.5 - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_points_with_features.py b/examples/add_points_with_features.py deleted file mode 100644 index df65f3ba9..000000000 --- a/examples/add_points_with_features.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -Add points with features -======================== - -Display a points layer on top of an image layer using the ``add_points`` and -``add_image`` APIs - -.. tags:: visualization-basic -""" - -import numpy as np -from skimage import data -from skimage.color import rgb2gray -import napari - - -# add the image -viewer = napari.view_image(rgb2gray(data.astronaut())) -# add the points -points = np.array([[100, 100], [200, 200], [333, 111]]) - -# create features for each point -features = { - 'confidence': np.array([1, 0.5, 0]), - 'good_point': np.array([True, False, False]) -} - -# define the color cycle for the face_color annotation -face_color_cycle = ['blue', 'green'] - -# create a points layer where the face_color is set by the good_point feature -# and the edge_color is set via a color map (grayscale) on the confidence -# feature. -points_layer = viewer.add_points( - points, - features=features, - size=20, - edge_width=7, - edge_width_is_relative=False, - edge_color='confidence', - edge_colormap='gray', - face_color='good_point', - face_color_cycle=face_color_cycle -) - -# set the edge_color mode to colormap -points_layer.edge_color_mode = 'colormap' - - -# bind a function to toggle the good_point annotation of the selected points -@viewer.bind_key('t') -def toggle_point_annotation(viewer): - selected_points = list(points_layer.selected_data) - if len(selected_points) > 0: - good_point = points_layer.features['good_point'] - good_point[selected_points] = ~good_point[selected_points] - points_layer.features['good_point'] = good_point - - # we need to manually refresh since we did not use the Points.features - # setter to avoid changing the color map if all points get toggled to - # the same class, we set update_colors=False (only re-colors the point - # using the previously-determined color mapping). - points_layer.refresh_colors(update_color_mapping=False) - - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_points_with_multicolor_text.py b/examples/add_points_with_multicolor_text.py deleted file mode 100644 index 1c70ae306..000000000 --- a/examples/add_points_with_multicolor_text.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Add points with multicolor text -=============================== - -Display a points layer on top of an image layer with text using -multiple face colors mapped from features for the points and text. - -.. tags:: visualization-basic -""" - -import numpy as np -import napari - -# add the image with three points -viewer = napari.view_image(np.zeros((400, 400))) -points = np.array([[100, 100], [200, 300], [333, 111]]) - -# create features for each point -features = { - 'confidence': np.array([1, 0.5, 0]), - 'good_point': np.array([True, False, False]), -} - -# define the color cycle for the points face and text colors -color_cycle = ['blue', 'green'] - -text = { - 'string': 'Confidence is {confidence:.2f}', - 'size': 20, - 'color': {'feature': 'good_point', 'colormap': color_cycle}, - 'translation': np.array([-30, 0]), -} - -# create a points layer where the face_color is set by the good_point feature -# and the edge_color is set via a color map (grayscale) on the confidence -# feature -points_layer = viewer.add_points( - points, - features=features, - text=text, - size=20, - edge_width=7, - edge_width_is_relative=False, - edge_color='confidence', - edge_colormap='gray', - face_color='good_point', - face_color_cycle=color_cycle, -) - -# set the edge_color mode to colormap -points_layer.edge_color_mode = 'colormap' - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_points_with_text.py b/examples/add_points_with_text.py deleted file mode 100644 index 09aafcc45..000000000 --- a/examples/add_points_with_text.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Add points with text -==================== - -Display a points layer on top of an image layer using the ``add_points`` and -``add_image`` APIs - -.. tags:: visualization-basic -""" - -import numpy as np -import napari - - -# add the image -viewer = napari.view_image(np.zeros((400, 400))) -# add the points -points = np.array([[100, 100], [200, 300], [333, 111]]) - -# create features for each point -features = { - 'confidence': np.array([1, 0.5, 0]), - 'good_point': np.array([True, False, False]), -} - -# define the color cycle for the face_color annotation -face_color_cycle = ['blue', 'green'] - -text = { - 'string': 'Confidence is {confidence:.2f}', - 'size': 20, - 'color': 'green', - 'translation': np.array([-30, 0]), -} - -# create a points layer where the face_color is set by the good_point feature -# and the edge_color is set via a color map (grayscale) on the confidence -# feature. -points_layer = viewer.add_points( - points, - features=features, - text=text, - size=20, - edge_width=7, - edge_width_is_relative=False, - edge_color='confidence', - edge_colormap='gray', - face_color='good_point', - face_color_cycle=face_color_cycle, -) - -# set the edge_color mode to colormap -points_layer.edge_color_mode = 'colormap' - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_shapes.py b/examples/add_shapes.py deleted file mode 100644 index 1ae8d6379..000000000 --- a/examples/add_shapes.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -Add shapes -========== - -Display one shapes layer ontop of one image layer using the ``add_shapes`` and -``add_image`` APIs. When the window is closed it will print the coordinates of -your shapes. - -.. tags:: visualization-basic -""" - -import numpy as np -from skimage import data -import napari - - -# add the image -viewer = napari.view_image(data.camera(), name='photographer') - -# create a list of polygons -polygons = [ - np.array([[11, 13], [111, 113], [22, 246]]), - np.array( - [ - [505, 60], - [402, 71], - [383, 42], - [251, 95], - [212, 59], - [131, 137], - [126, 187], - [191, 204], - [171, 248], - [211, 260], - [273, 243], - [264, 225], - [430, 173], - [512, 160], - ] - ), - np.array( - [ - [310, 382], - [229, 381], - [209, 401], - [221, 411], - [258, 411], - [300, 412], - [306, 435], - [268, 434], - [265, 454], - [298, 461], - [307, 461], - [307, 507], - [349, 510], - [352, 369], - [330, 366], - [330, 366], - ] - ), -] - -# add polygons -layer = viewer.add_shapes( - polygons, - shape_type='polygon', - edge_width=1, - edge_color='coral', - face_color='royalblue', - name='shapes', -) - -# shapes of each type can also be added via their respective add_ method -# e.g. for the polygons above: - -# layer = viewer.add_shapes(name='shapes') # create empty layer -# layer.add_polygons( -# polygons, -# edge_width=1, -# edge_color='coral', -# face_color='royalblue', -# ) - - -# change some attributes of the layer -layer.selected_data = set(range(layer.nshapes)) -layer.current_edge_width = 5 -layer.selected_data = set() - -# add an ellipse to the layer -ellipse = np.array([[59, 222], [110, 289], [170, 243], [119, 176]]) -layer.add( - ellipse, - shape_type='ellipse', - edge_width=5, - edge_color='coral', - face_color='purple', -) - -# To save layers to svg: -# viewer.layers.save('viewer.svg', plugin='svg') - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_shapes_with_features.py b/examples/add_shapes_with_features.py deleted file mode 100644 index 65d08ffa6..000000000 --- a/examples/add_shapes_with_features.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -Add shapes with features -======================== - -Display one shapes layer ontop of one image layer using the ``add_shapes`` and -``add_image`` APIs. When the window is closed it will print the coordinates of -your shapes. - -.. tags:: visualization-basic -""" - -import numpy as np -from skimage import data -import napari - - -# add the image -viewer = napari.view_image(data.camera(), name='photographer') - -# create a list of polygons -polygons = [ - np.array([[11, 13], [111, 113], [22, 246]]), - np.array( - [ - [505, 60], - [402, 71], - [383, 42], - [251, 95], - [212, 59], - [131, 137], - [126, 187], - [191, 204], - [171, 248], - [211, 260], - [273, 243], - [264, 225], - [430, 173], - [512, 160], - ] - ), - np.array( - [ - [310, 382], - [229, 381], - [209, 401], - [221, 411], - [258, 411], - [300, 412], - [306, 435], - [268, 434], - [265, 454], - [298, 461], - [307, 461], - [307, 507], - [349, 510], - [352, 369], - [330, 366], - [330, 366], - ] - ), -] - -# create features -features = { - 'likelihood': [0.2, 0.5, 1], - 'class': ['sky', 'person', 'building'], -} -face_color_cycle = ['blue', 'magenta', 'green'] - -# add polygons -layer = viewer.add_shapes( - polygons, - features=features, - shape_type='polygon', - edge_width=1, - edge_color='likelihood', - edge_colormap='gray', - face_color='class', - face_color_cycle=face_color_cycle, - name='shapes', -) - -# change some attributes of the layer -layer.selected_data = set(range(layer.nshapes)) -layer.current_edge_width = 5 -layer.selected_data = set() - -# To save layers to svg: -# viewer.layers.save('viewer.svg', plugin='svg') - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_shapes_with_text.py b/examples/add_shapes_with_text.py deleted file mode 100644 index 891712841..000000000 --- a/examples/add_shapes_with_text.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Add shapes with text -==================== - -Display one shapes layer ontop of one image layer using the ``add_shapes`` and -``add_image`` APIs. When the window is closed it will print the coordinates of -your shapes. - -.. tags:: visualization-basic -""" - -import numpy as np -from skimage import data -import napari - - -# add the image -viewer = napari.view_image(data.camera(), name='photographer') - -# create a list of polygons -polygons = [ - np.array([[225, 146], [283, 146], [283, 211], [225, 211]]), - np.array([[67, 182], [167, 182], [167, 268], [67, 268]]), - np.array([[111, 336], [220, 336], [220, 240], [111, 240]]), -] - -# create features -features = { - 'likelihood': [21.23423, 51.2315, 100], - 'class': ['hand', 'face', 'camera'], -} -edge_color_cycle = ['blue', 'magenta', 'green'] - -text = { - 'string': '{class}: {likelihood:0.1f}%', - 'anchor': 'upper_left', - 'translation': [-5, 0], - 'size': 8, - 'color': 'green', -} - -# add polygons -shapes_layer = viewer.add_shapes( - polygons, - features=features, - shape_type='polygon', - edge_width=3, - edge_color='class', - edge_color_cycle=edge_color_cycle, - face_color='transparent', - text=text, - name='shapes', -) - -# change some attributes of the layer -shapes_layer.opacity = 1 - -# To save layers to svg: -# viewer.layers.save('viewer.svg', plugin='svg') - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_surface_2D.py b/examples/add_surface_2D.py deleted file mode 100644 index ab875843b..000000000 --- a/examples/add_surface_2D.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Add surface 2D -============== - -Display a 2D surface - -.. tags:: visualization-basic -""" - -import numpy as np -import napari - - -data = np.array([[0, 0], [0, 20], [10, 0], [10, 10]]) -faces = np.array([[0, 1, 2], [1, 2, 3]]) -values = np.linspace(0, 1, len(data)) - -# add the surface -viewer = napari.view_surface((data, faces, values)) - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_vectors.py b/examples/add_vectors.py deleted file mode 100644 index f9995c661..000000000 --- a/examples/add_vectors.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Add vectors -=========== - -This example generates an image of vectors -Vector data is an array of shape (N, 4) -Each vector position is defined by an (x, y, x-proj, y-proj) element where -* x and y are the center points -* x-proj and y-proj are the vector projections at each center - -.. tags:: visualization-basic -""" - -import napari -from skimage import data -import numpy as np - - -# create the viewer and window -viewer = napari.Viewer() - -layer = viewer.add_image(data.camera(), name='photographer') - -# sample vector coord-like data -n = 200 -pos = np.zeros((n, 2, 2), dtype=np.float32) -phi_space = np.linspace(0, 4 * np.pi, n) -radius_space = np.linspace(0, 100, n) - -# assign x-y position -pos[:, 0, 0] = radius_space * np.cos(phi_space) + 300 -pos[:, 0, 1] = radius_space * np.sin(phi_space) + 256 - -# assign x-y projection -pos[:, 1, 0] = 2 * radius_space * np.cos(phi_space) -pos[:, 1, 1] = 2 * radius_space * np.sin(phi_space) - -# add the vectors -layer = viewer.add_vectors(pos, edge_width=3) - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_vectors_color_by_angle.py b/examples/add_vectors_color_by_angle.py deleted file mode 100644 index 569578f13..000000000 --- a/examples/add_vectors_color_by_angle.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Add vectors color by angle -========================== - -This example generates a set of vectors in a spiral pattern. -The color of the vectors is mapped to their 'angle' feature. - -.. tags:: visualization-advanced -""" - -import napari -from skimage import data -import numpy as np - - -# create the viewer and window -viewer = napari.Viewer() - -layer = viewer.add_image(data.camera(), name='photographer') - -# sample vector coord-like data -n = 300 -pos = np.zeros((n, 2, 2), dtype=np.float32) -phi_space = np.linspace(0, 4 * np.pi, n) -radius_space = np.linspace(0, 100, n) - -# assign x-y position -pos[:, 0, 0] = radius_space * np.cos(phi_space) + 300 -pos[:, 0, 1] = radius_space * np.sin(phi_space) + 256 - -# assign x-y projection -pos[:, 1, 0] = 2 * radius_space * np.cos(phi_space) -pos[:, 1, 1] = 2 * radius_space * np.sin(phi_space) - -# make the angle feature, range 0-2pi -angle = np.mod(phi_space, 2 * np.pi) - -# create a feature that is true for all angles > pi -pos_angle = angle > np.pi - -# create the features dictionary. -features = { - 'angle': angle, - 'pos_angle': pos_angle, -} - -# add the vectors -layer = viewer.add_vectors( - pos, - edge_width=3, - features=features, - edge_color='angle', - edge_colormap='husl', - name='vectors' -) - -# set the edge color mode to colormap -layer.edge_color_mode = 'colormap' - -if __name__ == '__main__': - napari.run() diff --git a/examples/add_vectors_image.py b/examples/add_vectors_image.py deleted file mode 100644 index 6bfc34597..000000000 --- a/examples/add_vectors_image.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Add vectors image -================= - -This example generates an image of vectors -Vector data is an array of shape (N, M, 2) -Each vector position is defined by an (x-proj, y-proj) element where -* x-proj and y-proj are the vector projections at each center -* each vector is centered on a pixel of the NxM grid - -.. tags:: visualization-basic -""" - -import napari -import numpy as np - - -# create the viewer and window -viewer = napari.Viewer() - -n = 20 -m = 40 - -image = 0.2 * np.random.random((n, m)) + 0.5 -layer = viewer.add_image(image, contrast_limits=[0, 1], name='background') - -# sample vector image-like data -# n x m grid of slanted lines -# random data on the open interval (-1, 1) -pos = np.zeros(shape=(n, m, 2), dtype=np.float32) -rand1 = 2 * (np.random.random_sample(n * m) - 0.5) -rand2 = 2 * (np.random.random_sample(n * m) - 0.5) - -# assign projections for each vector -pos[:, :, 0] = rand1.reshape((n, m)) -pos[:, :, 1] = rand2.reshape((n, m)) - -# add the vectors -vect = viewer.add_vectors(pos, edge_width=0.2, length=2.5) - -print(image.shape, pos.shape) - -if __name__ == '__main__': - napari.run() diff --git a/examples/affine_transforms.py b/examples/affine_transforms.py deleted file mode 100644 index 28fa54ab9..000000000 --- a/examples/affine_transforms.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Affine transforms -================= - -Display an image and its corners before and after an affine transform - -.. tags:: visualization-advanced -""" -import numpy as np -import napari -import scipy.ndimage as ndi - -# Create a random image -image = np.random.random((5, 5)) - -# Define an affine transform -affine = np.array([[1, -1, 4], [2, 3, 2], [0, 0, 1]]) - -# Define the corners of the image, including in homogeneous space -corners = np.array([[0, 0], [4, 0], [0, 4], [4, 4]]) -corners_h = np.concatenate([corners, np.ones((4, 1))], axis=1) - -viewer = napari.Viewer() - -# Add the original image and its corners -viewer.add_image(image, name='background', colormap='red', opacity=.5) -viewer.add_points(corners_h[:, :-1], size=0.5, opacity=.5, face_color=[0.8, 0, 0, 0.8], name='bg corners') - -# Add another copy of the image, now with a transform, and add its transformed corners -viewer.add_image(image, colormap='blue', opacity=.5, name='moving', affine=affine) -viewer.add_points((corners_h @ affine.T)[:, :-1], size=0.5, opacity=.5, face_color=[0, 0, 0.8, 0.8], name='mv corners') - -# Note how the transformed corner points remain at the corners of the transformed image - -# Now add the a regridded version of the image transformed with scipy.ndimage.affine_transform -# Note that we have to use the inverse of the affine as scipy does ‘pull’ (or ‘backward’) resampling, -# transforming the output space to the input to locate data, but napari does ‘push’ (or ‘forward’) direction, -# transforming input to output. -scipy_affine = ndi.affine_transform(image, np.linalg.inv(affine), output_shape=(10, 25), order=5) -viewer.add_image(scipy_affine, colormap='green', opacity=.5, name='scipy') - -# Reset the view -viewer.reset_view() - -if __name__ == '__main__': - napari.run() diff --git a/examples/annotate-2d.py b/examples/annotate-2d.py deleted file mode 100644 index 279b97b69..000000000 --- a/examples/annotate-2d.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Annotate 2D -=========== - -Display one points layer ontop of one image layer using the ``add_points`` and -``add_image`` APIs - -.. tags:: analysis -""" - -import numpy as np -from skimage import data -import napari - - -print("click to add points; close the window when finished.") - -viewer = napari.view_image(data.astronaut(), rgb=True) -points = viewer.add_points(np.zeros((0, 2))) -points.mode = 'add' - -if __name__ == '__main__': - napari.run() - - print("you clicked on:") - print(points.data) diff --git a/examples/annotate_segmentation_with_text.py b/examples/annotate_segmentation_with_text.py deleted file mode 100644 index 45ac3a38e..000000000 --- a/examples/annotate_segmentation_with_text.py +++ /dev/null @@ -1,135 +0,0 @@ -""" -Annotate segmentation with text -=============================== - -Perform a segmentation and annotate the results with -bounding boxes and text - -.. tags:: analysis -""" -import numpy as np -from skimage import data -from skimage.filters import threshold_otsu -from skimage.segmentation import clear_border -from skimage.measure import label, regionprops_table -from skimage.morphology import closing, square, remove_small_objects -import napari - - -def segment(image): - """Segment an image using an intensity threshold determined via - Otsu's method. - - Parameters - ---------- - image : np.ndarray - The image to be segmented - - Returns - ------- - label_image : np.ndarray - The resulting image where each detected object labeled with a unique integer. - """ - # apply threshold - thresh = threshold_otsu(image) - bw = closing(image > thresh, square(4)) - - # remove artifacts connected to image border - cleared = remove_small_objects(clear_border(bw), 20) - - # label image regions - label_image = label(cleared) - - return label_image - - -def make_bbox(bbox_extents): - """Get the coordinates of the corners of a - bounding box from the extents - - Parameters - ---------- - bbox_extents : list (4xN) - List of the extents of the bounding boxes for each of the N regions. - Should be ordered: [min_row, min_column, max_row, max_column] - - Returns - ------- - bbox_rect : np.ndarray - The corners of the bounding box. Can be input directly into a - napari Shapes layer. - """ - minr = bbox_extents[0] - minc = bbox_extents[1] - maxr = bbox_extents[2] - maxc = bbox_extents[3] - - bbox_rect = np.array( - [[minr, minc], [maxr, minc], [maxr, maxc], [minr, maxc]] - ) - bbox_rect = np.moveaxis(bbox_rect, 2, 0) - - return bbox_rect - - -def circularity(perimeter, area): - """Calculate the circularity of the region - - Parameters - ---------- - perimeter : float - the perimeter of the region - area : float - the area of the region - - Returns - ------- - circularity : float - The circularity of the region as defined by 4*pi*area / perimeter^2 - """ - circularity = 4 * np.pi * area / (perimeter ** 2) - - return circularity - - -# load the image and segment it -image = data.coins()[50:-50, 50:-50] -label_image = segment(image) - -# create the features dictionary -features = regionprops_table( - label_image, properties=('label', 'bbox', 'perimeter', 'area') -) -features['circularity'] = circularity( - features['perimeter'], features['area'] -) - -# create the bounding box rectangles -bbox_rects = make_bbox([features[f'bbox-{i}'] for i in range(4)]) - -# specify the display parameters for the text -text_parameters = { - 'string': 'label: {label}\ncirc: {circularity:.2f}', - 'size': 12, - 'color': 'green', - 'anchor': 'upper_left', - 'translation': [-3, 0], -} - -# initialise viewer with coins image -viewer = napari.view_image(image, name='coins', rgb=False) - -# add the labels -label_layer = viewer.add_labels(label_image, name='segmentation') - -shapes_layer = viewer.add_shapes( - bbox_rects, - face_color='transparent', - edge_color='green', - features=features, - text=text_parameters, - name='bounding box', -) - -if __name__ == '__main__': - napari.run() diff --git a/examples/bbox_annotator.py b/examples/bbox_annotator.py deleted file mode 100644 index 48a24d96f..000000000 --- a/examples/bbox_annotator.py +++ /dev/null @@ -1,120 +0,0 @@ -""" -bbox annotator -============== - -.. tags:: gui -""" - -from magicgui.widgets import ComboBox, Container -import napari -import numpy as np -import pandas as pd -from skimage import data - - -# set up the categorical annotation values and text display properties -box_annotations = ['person', 'sky', 'camera'] -text_feature = 'box_label' -features = pd.DataFrame({ - text_feature: pd.Series([], dtype=pd.CategoricalDtype(box_annotations)) -}) -text_color = 'green' -text_size = 20 - - -# create the GUI for selecting the values -def create_label_menu(shapes_layer, label_feature, labels): - """Create a label menu widget that can be added to the napari viewer dock - - Parameters - ---------- - shapes_layer : napari.layers.Shapes - a napari shapes layer - label_feature : str - the name of the shapes feature to use the displayed text - labels : List[str] - list of the possible text labels values. - - Returns - ------- - label_widget : magicgui.widgets.Container - the container widget with the label combobox - """ - # Create the label selection menu - label_menu = ComboBox(label='text label', choices=labels) - label_widget = Container(widgets=[label_menu]) - - def update_label_menu(): - """This is a callback function that updates the label menu when - the default features of the Shapes layer change - """ - new_label = str(shapes_layer.feature_defaults[label_feature][0]) - if new_label != label_menu.value: - label_menu.value = new_label - - shapes_layer.events.feature_defaults.connect(update_label_menu) - - def set_selected_features_to_default(): - """This is a callback that updates the feature values of the currently - selected shapes. This is a side-effect of the deprecated current_properties - setter, but does not occur when modifying feature_defaults.""" - indices = list(shapes_layer.selected_data) - default_value = shapes_layer.feature_defaults[label_feature][0] - shapes_layer.features[label_feature][indices] = default_value - shapes_layer.events.features() - - shapes_layer.events.feature_defaults.connect(set_selected_features_to_default) - shapes_layer.events.features.connect(shapes_layer.refresh_text) - - def label_changed(value: str): - """This is a callback that update the default features on the Shapes layer - when the label menu selection changes - """ - shapes_layer.feature_defaults[label_feature] = value - shapes_layer.events.feature_defaults() - - label_menu.changed.connect(label_changed) - - return label_widget - - -# create a stack with the camera image shifted in each slice -n_slices = 5 -base_image = data.camera() -image = np.zeros((n_slices, base_image.shape[0], base_image.shape[1]), dtype=base_image.dtype) -for slice_idx in range(n_slices): - shift = 1 + 10 * slice_idx - image[slice_idx, ...] = np.pad(base_image, ((0, 0), (shift, 0)), mode='constant')[:, :-shift] - - -# create a viewer with a fake t+2D image -viewer = napari.view_image(image) - -# create an empty shapes layer initialized with -# text set to display the box label -text_kwargs = { - 'string': text_feature, - 'size': text_size, - 'color': text_color -} -shapes = viewer.add_shapes( - face_color='black', - features=features, - text=text_kwargs, - ndim=3 -) - -# create the label section gui -label_widget = create_label_menu( - shapes_layer=shapes, - label_feature=text_feature, - labels=box_annotations -) -# add the label selection gui to the viewer as a dock widget -viewer.window.add_dock_widget(label_widget, area='right', name='label_widget') - -# set the shapes layer mode to adding rectangles -shapes.mode = 'add_rectangle' - -if __name__ == '__main__': - napari.run() diff --git a/examples/clipboard_.py b/examples/clipboard_.py deleted file mode 100644 index 4312f42c7..000000000 --- a/examples/clipboard_.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Clipboard -========= - -Copy screenshot of the canvas or the whole viewer to clipboard. - -.. tags:: gui -""" - -from skimage import data -from qtpy.QtWidgets import QVBoxLayout, QPushButton, QWidget -import napari - -# create the viewer with an image -viewer = napari.view_image(data.moon()) - -class Grabber(QWidget): - def __init__(self): - super().__init__() - - self.copy_canvas_btn = QPushButton("Copy Canvas to Clipboard", self) - self.copy_canvas_btn.setToolTip("Copy screenshot of the canvas to clipboard.") - self.copy_viewer_btn = QPushButton("Copy Viewer to Clipboard", self) - self.copy_viewer_btn.setToolTip("Copy screenshot of the entire viewer to clipboard.") - - layout = QVBoxLayout(self) - layout.addWidget(self.copy_canvas_btn) - layout.addWidget(self.copy_viewer_btn) - - -def create_grabber_widget(): - """Create widget""" - widget = Grabber() - - # connect buttons - widget.copy_canvas_btn.clicked.connect(lambda: viewer.window.qt_viewer.clipboard()) - widget.copy_viewer_btn.clicked.connect(lambda: viewer.window.clipboard()) - return widget - - -widget = create_grabber_widget() -viewer.window.add_dock_widget(widget) - -if __name__ == '__main__': - napari.run() diff --git a/examples/clipping_planes_interactive_.py b/examples/clipping_planes_interactive_.py deleted file mode 100644 index d95c237ac..000000000 --- a/examples/clipping_planes_interactive_.py +++ /dev/null @@ -1,198 +0,0 @@ -""" -Clipping planes interactive -=========================== - -Display a 3D image (plus labels) with a clipping plane and interactive controls -for moving the plane - -.. tags:: experimental -""" -import napari -import numpy as np -from skimage import data -from scipy import ndimage -from vispy.geometry import create_sphere - -viewer = napari.Viewer(ndisplay=3) - -# VOLUME and LABELS -blobs = data.binary_blobs( - length=64, volume_fraction=0.1, n_dim=3 -).astype(float) - -labeled = ndimage.label(blobs)[0] - -plane_parameters = { - 'position': (32, 32, 32), - 'normal': (1, 1, 1), - 'enabled': True -} - -volume_layer = viewer.add_image( - blobs, rendering='mip', name='volume', - experimental_clipping_planes=[plane_parameters], -) - -labels_layer = viewer.add_labels( - labeled, name='labels', blending='translucent', - experimental_clipping_planes=[plane_parameters], -) - -# POINTS -points_layer = viewer.add_points( - np.random.rand(20, 3) * 64, size=5, - experimental_clipping_planes=[plane_parameters], -) - -# SPHERE -mesh = create_sphere(method='ico') -sphere_vert = mesh.get_vertices() * 20 -sphere_vert += 32 -surface_layer = viewer.add_surface( - (sphere_vert, mesh.get_faces()), - experimental_clipping_planes=[plane_parameters], -) - -# SHAPES -shapes_data = np.random.rand(3, 4, 3) * 64 - -shapes_layer = viewer.add_shapes( - shapes_data, - face_color=['magenta', 'green', 'blue'], - experimental_clipping_planes=[plane_parameters], -) - -# VECTORS -vectors = np.zeros((20, 2, 3)) -vectors[:, 0] = 32 -vectors[:, 1] = (np.random.rand(20, 3) - 0.5) * 32 - -vectors_layer = viewer.add_vectors( - vectors, - experimental_clipping_planes=[plane_parameters], -) - - -def point_in_bounding_box(point, bounding_box): - if np.all(point > bounding_box[0]) and np.all(point < bounding_box[1]): - return True - return False - - -@viewer.mouse_drag_callbacks.append -def shift_plane_along_normal(viewer, event): - """Shift a plane along its normal vector on mouse drag. - This callback will shift a plane along its normal vector when the plane is - clicked and dragged. The general strategy is to - 1) find both the plane normal vector and the mouse drag vector in canvas - coordinates - 2) calculate how far to move the plane in canvas coordinates, this is done - by projecting the mouse drag vector onto the (normalised) plane normal - vector - 3) transform this drag distance (canvas coordinates) into data coordinates - 4) update the plane position - It will also add a point to the points layer for a 'click-not-drag' event. - """ - # get layers from viewer - volume_layer = viewer.layers['volume'] - - # Calculate intersection of click with data bounding box - near_point, far_point = volume_layer.get_ray_intersections( - event.position, - event.view_direction, - event.dims_displayed, - ) - - # Calculate intersection of click with plane through data - intersection = volume_layer.experimental_clipping_planes[0].intersect_with_line( - line_position=near_point, line_direction=event.view_direction - ) - - # Check if click was on plane by checking if intersection occurs within - # data bounding box. If so, exit early. - if not point_in_bounding_box(intersection, volume_layer.extent.data): - return - - # Get plane parameters in vispy coordinates (zyx -> xyz) - plane_normal_data_vispy = np.array(volume_layer.experimental_clipping_planes[0].normal)[[2, 1, 0]] - plane_position_data_vispy = np.array(volume_layer.experimental_clipping_planes[0].position)[[2, 1, 0]] - - # Get transform which maps from data (vispy) to canvas - # note that we're using a private attribute here, which may not be present in future napari versions - visual2canvas = viewer.window._qt_viewer.layer_to_visual[volume_layer].node.get_transform( - map_from="visual", map_to="canvas" - ) - - # Find start and end positions of plane normal in canvas coordinates - plane_normal_start_canvas = visual2canvas.map(plane_position_data_vispy) - plane_normal_end_canvas = visual2canvas.map(plane_position_data_vispy + plane_normal_data_vispy) - - # Calculate plane normal vector in canvas coordinates - plane_normal_canv = (plane_normal_end_canvas - plane_normal_start_canvas)[[0, 1]] - plane_normal_canv_normalised = ( - plane_normal_canv / np.linalg.norm(plane_normal_canv) - ) - - # Disable interactivity during plane drag - volume_layer.interactive = False - labels_layer.interactive = False - labels_layer.interactive = False - points_layer.interactive = False - surface_layer.interactive = False - shapes_layer.interactive = False - vectors_layer.interactive = False - - # Store original plane position and start position in canvas coordinates - original_plane_position = volume_layer.experimental_clipping_planes[0].position - start_position_canv = event.pos - - yield - while event.type == "mouse_move": - # Get end position in canvas coordinates - end_position_canv = event.pos - - # Calculate drag vector in canvas coordinates - drag_vector_canv = end_position_canv - start_position_canv - - # Project the drag vector onto the plane normal vector - # (in canvas coorinates) - drag_projection_on_plane_normal = np.dot( - drag_vector_canv, plane_normal_canv_normalised - ) - - # Update position of plane according to drag vector - # only update if plane position is within data bounding box - drag_distance_data = drag_projection_on_plane_normal / np.linalg.norm(plane_normal_canv) - updated_position = original_plane_position + drag_distance_data * np.array( - volume_layer.experimental_clipping_planes[0].normal) - - if point_in_bounding_box(updated_position, volume_layer.extent.data): - volume_layer.experimental_clipping_planes[0].position = updated_position - labels_layer.experimental_clipping_planes[0].position = updated_position - points_layer.experimental_clipping_planes[0].position = updated_position - surface_layer.experimental_clipping_planes[0].position = updated_position - shapes_layer.experimental_clipping_planes[0].position = updated_position - vectors_layer.experimental_clipping_planes[0].position = updated_position - - yield - - # Re-enable - volume_layer.interactive = True - labels_layer.interactive = True - points_layer.interactive = True - surface_layer.interactive = True - shapes_layer.interactive = True - vectors_layer.interactive = True - - -viewer.axes.visible = True -viewer.camera.angles = (45, 45, 45) -viewer.camera.zoom = 5 -viewer.text_overlay.update(dict( - text='Drag the clipping plane surface to move it along its normal.', - font_size=20, - visible=True, -)) - -if __name__ == '__main__': - napari.run() diff --git a/examples/cursor_position.py b/examples/cursor_position.py deleted file mode 100644 index d20e9b9df..000000000 --- a/examples/cursor_position.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Cursor position -=============== - -Add small data to examine cursor positions - -.. tags:: interactivity -""" - -import numpy as np -import napari - - -viewer = napari.Viewer() -image = np.array([[1, 0, 0, 1], - [0, 0, 1, 1], - [1, 0, 3, 0], - [0, 2, 0, 0]], dtype=int) - -viewer.add_labels(image) - -points = np.array([[0, 0], [2, 0], [1, 3]]) -viewer.add_points(points, size=0.25) - -rect = np.array([[0, 0], [3, 1]]) -viewer.add_shapes(rect, shape_type='rectangle', edge_width=0.1) - -vect = np.array([[[3, 2], [-1, 1]]]) -viewer.add_vectors(vect, edge_width=0.1) - -if __name__ == '__main__': - napari.run() diff --git a/examples/cursor_ray.py b/examples/cursor_ray.py deleted file mode 100644 index 5da0f31d3..000000000 --- a/examples/cursor_ray.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -Cursor ray -========== - -Depict a ray through a layer in 3D to demonstrate interactive 3D functionality - -.. tags:: interactivity -""" -import numpy as np -import napari - -sidelength_data = 64 -n_points = 10 - -# data to depict an empty volume, its bounding box and points along a ray -# through the volume -volume = np.zeros(shape=(sidelength_data, sidelength_data, sidelength_data)) -bounding_box = np.array( - [ - [0, 0, 0], - [1, 0, 0], - [0, 1, 0], - [1, 1, 0], - [0, 0, 1], - [1, 0, 1], - [0, 1, 1], - [1, 1, 1], - ] -) * sidelength_data -points = np.zeros(shape=(n_points, 3)) - -# point sizes -point_sizes = np.linspace(0.5, 2, n_points, endpoint=True) - -# point colors -green = [0, 1, 0, 1] -magenta = [1, 0, 1, 1] -point_colors = np.linspace(green, magenta, n_points, endpoint=True) - -# create viewer and add layers for each piece of data -viewer = napari.Viewer(ndisplay=3) -bounding_box_layer = viewer.add_points( - bounding_box, face_color='cornflowerblue', name='bounding box' -) -ray_layer = viewer.add_points( - points, face_color=point_colors, size=point_sizes, name='cursor ray' -) -volume_layer = viewer.add_image(volume, blending='additive') - - -# callback function, called on mouse click when volume layer is active -@volume_layer.mouse_drag_callbacks.append -def on_click(layer, event): - near_point, far_point = layer.get_ray_intersections( - event.position, - event.view_direction, - event.dims_displayed - ) - if (near_point is not None) and (far_point is not None): - ray_points = np.linspace(near_point, far_point, n_points, endpoint=True) - if ray_points.shape[1] != 0: - ray_layer.data = ray_points - - -if __name__ == '__main__': - napari.run() diff --git a/examples/custom_key_bindings.py b/examples/custom_key_bindings.py deleted file mode 100644 index 4186b11d6..000000000 --- a/examples/custom_key_bindings.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Custom key bindings -=================== - -Display one 4-D image layer using the ``add_image`` API - -.. tags:: gui -""" - -from skimage import data -import napari - - -blobs = data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=2, volume_fraction=0.25 -).astype(float) - -viewer = napari.view_image(blobs, name='blobs') - - -@viewer.bind_key('a') -def accept_image(viewer): - msg = 'this is a good image' - viewer.status = msg - print(msg) - next(viewer) - - -@viewer.bind_key('r') -def reject_image(viewer): - msg = 'this is a bad image' - viewer.status = msg - print(msg) - next(viewer) - - -def next(viewer): - blobs = data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=2, volume_fraction=0.25 - ).astype(float) - viewer.layers[0].data = blobs - - -@napari.Viewer.bind_key('w') -def hello(viewer): - # on press - viewer.status = 'hello world!' - - yield - - # on release - viewer.status = 'goodbye world :(' - - -# change viewer title -viewer.title = 'quality control images' - -if __name__ == '__main__': - napari.run() diff --git a/examples/custom_mouse_functions.py b/examples/custom_mouse_functions.py deleted file mode 100644 index a6941fceb..000000000 --- a/examples/custom_mouse_functions.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -Custom mouse functions -====================== - -Display one 4-D image layer using the ``add_image`` API - -.. tags:: gui -""" - -from skimage import data -from skimage.morphology import binary_dilation, binary_erosion -from scipy import ndimage as ndi -import numpy as np -import napari - - -np.random.seed(1) -viewer = napari.Viewer() -blobs = data.binary_blobs(length=128, volume_fraction=0.1, n_dim=2) -labeled = ndi.label(blobs)[0] -labels_layer = viewer.add_labels(labeled, name='blob ID') - -@viewer.mouse_drag_callbacks.append -def get_event(viewer, event): - print(event) - -@viewer.mouse_drag_callbacks.append -def get_ndisplay(viewer, event): - if 'Alt' in event.modifiers: - print('viewer display ', viewer.dims.ndisplay) - -@labels_layer.mouse_drag_callbacks.append -def get_connected_component_shape(layer, event): - data_coordinates = layer.world_to_data(event.position) - cords = np.round(data_coordinates).astype(int) - val = layer.get_value(data_coordinates) - if val is None: - return - if val != 0: - data = layer.data - binary = data == val - if 'Shift' in event.modifiers: - binary_new = binary_erosion(binary) - data[binary] = 0 - else: - binary_new = binary_dilation(binary) - data[binary_new] = val - size = np.sum(binary_new) - layer.data = data - msg = ( - f'clicked at {cords} on blob {val} which is now {size} pixels' - ) - else: - msg = f'clicked at {cords} on background which is ignored' - print(msg) - -# Handle click or drag events separately -@labels_layer.mouse_drag_callbacks.append -def click_drag(layer, event): - print('mouse down') - dragged = False - yield - # on move - while event.type == 'mouse_move': - print(event.position) - dragged = True - yield - # on release - if dragged: - print('drag end') - else: - print('clicked!') - -# Handle click or drag events separately -@labels_layer.mouse_double_click_callbacks.append -def on_second_click_of_double_click(layer, event): - print('Second click of double_click', event.position) - print('note that a click event was also triggered', event.type) - - -if __name__ == '__main__': - napari.run() diff --git a/examples/dask_nD_image.py b/examples/dask_nD_image.py deleted file mode 100644 index b11bbcee3..000000000 --- a/examples/dask_nD_image.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Dask nD image -============= - -Display a dask array - -.. tags:: visualization-nD -""" - -try: - from dask import array as da -except ModuleNotFoundError: - raise ModuleNotFoundError( - """This example uses a dask array but dask is not - installed. To install try 'pip install dask'.""" - ) - -import numpy as np -from skimage import data -import napari - - -blobs = da.stack( - [ - data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=3, volume_fraction=f - ) - for f in np.linspace(0.05, 0.5, 10) - ], - axis=0, -) -viewer = napari.view_image(blobs.astype(float)) - -if __name__ == '__main__': - napari.run() diff --git a/examples/dev/demo_shape_creation.py b/examples/dev/demo_shape_creation.py deleted file mode 100644 index 718095df1..000000000 --- a/examples/dev/demo_shape_creation.py +++ /dev/null @@ -1,110 +0,0 @@ -import argparse -from timeit import default_timer - -import numpy as np - -import napari - - -def create_sample_coords(n_polys=3000, n_vertices=32): - """random circular polygons with given number of vertices""" - center = np.random.randint(0, 1000, (n_polys, 2)) - radius = ( - 1000 - / np.sqrt(n_polys) - * np.random.uniform(0.9, 1.1, (n_polys, n_vertices)) - ) - - phi = np.linspace(0, 2 * np.pi, n_vertices, endpoint=False) - rays = np.stack([np.sin(phi), np.cos(phi)], 1) - - radius = radius.reshape((-1, n_vertices, 1)) - rays = rays.reshape((1, -1, 2)) - center = center.reshape((-1, 1, 2)) - coords = center + radius * rays - return coords - - -def time_me(label, func): - # print(f'{name} start') - t = default_timer() - res = func() - t = default_timer() - t - print(f"{label}: {t:.4f} s") - return res - - -if __name__ == "__main__": - - parser = argparse.ArgumentParser(description="") - - parser.add_argument( - "-n", - "--n_polys", - type=int, - default=5000, - help='number of polygons to show', - ) - parser.add_argument( - "-t", - "--type", - type=str, - default="path", - choices=['path', 'path_concat', 'polygon', 'rectangle', 'ellipse'], - ) - parser.add_argument( - "-c", - "--concat", - action="store_true", - help='concatenate all coordinates to a single mesh', - ) - parser.add_argument( - "-v", "--view", action="store_true", help='show napari viewer' - ) - parser.add_argument( - "--properties", action="store_true", help='add dummy shape properties' - ) - - args = parser.parse_args() - - coords = create_sample_coords(args.n_polys) - - if args.type == 'rectangle': - coords = coords[:, [4, 20]] - elif args.type == 'ellipse': - coords = coords[:, [0, 8, 16,22]] - elif args.type == 'path_concat': - args.type = 'path' - coords = coords.reshape((1, -1, 2)) - - - print(f'number of polygons: {len(coords)}') - print(f'layer type: {args.type}') - print(f'properties: {args.properties}') - - properties = { - 'class': (['A', 'B', 'C', 'D'] * (len(coords) // 4 + 1))[ - : len(coords) - ], - } - color_cycle = ['blue', 'magenta', 'green'] - - kwargs = dict( - shape_type=args.type, - properties=properties if args.properties else None, - face_color='class' if args.properties else [1,1,1,1], - face_color_cycle=color_cycle, - edge_color='class' if args.properties else [1,1,1,1], - edge_color_cycle=color_cycle, - ) - - layer = time_me( - "time to create layer", - lambda: napari.layers.Shapes(coords, **kwargs), - ) - - if args.view: - # add the image - viewer = napari.Viewer() - viewer.add_layer(layer) - napari.run() diff --git a/examples/dev/grin.svg b/examples/dev/grin.svg deleted file mode 100644 index 331129895..000000000 --- a/examples/dev/grin.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/dev/gui_notifications.py b/examples/dev/gui_notifications.py deleted file mode 100644 index 41f017385..000000000 --- a/examples/dev/gui_notifications.py +++ /dev/null @@ -1,23 +0,0 @@ -import warnings -from napari._qt.widgets.qt_viewer_buttons import QtViewerPushButton -import napari - - -def raise_(): - x = 1 - y = 'a string' - import something_that_does_not_exist - - -def warn_(): - warnings.warn("warning!") - - -viewer = napari.Viewer() -layer_buttons = viewer.window._qt_viewer.layerButtons -err_btn = QtViewerPushButton('warning', 'new Error', raise_) -warn_btn = QtViewerPushButton('warning', 'new Warn', warn_) -layer_buttons.layout().insertWidget(3, warn_btn) -layer_buttons.layout().insertWidget(3, err_btn) - -napari.run() diff --git a/examples/dev/gui_notifications_threaded.py b/examples/dev/gui_notifications_threaded.py deleted file mode 100644 index ae89ee1aa..000000000 --- a/examples/dev/gui_notifications_threaded.py +++ /dev/null @@ -1,29 +0,0 @@ -import time -import warnings - -import napari -from napari._qt.widgets.qt_viewer_buttons import QtViewerPushButton -from napari.qt import thread_worker - - -@thread_worker(start_thread=True) -def make_warning(*_): - time.sleep(0.05) - warnings.warn('Warning in another thread') - - -@thread_worker(start_thread=True) -def make_error(*_): - time.sleep(0.05) - raise ValueError("Error in another thread") - - -viewer = napari.Viewer() -layer_buttons = viewer.window.qt_viewer.layerButtons -err_btn = QtViewerPushButton(None, 'warning', 'new Error', make_error) -warn_btn = QtViewerPushButton(None, 'warning', 'new Warn', make_warning) -layer_buttons.layout().insertWidget(3, warn_btn) -layer_buttons.layout().insertWidget(3, err_btn) - - -napari.run() diff --git a/examples/dev/leaking_check.py b/examples/dev/leaking_check.py deleted file mode 100644 index fb67da87b..000000000 --- a/examples/dev/leaking_check.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -import psutil -import weakref -import gc -import objgraph - -import napari -import numpy as np -import qtpy - -process = psutil.Process(os.getpid()) -viewer = napari.Viewer() - -print("mem", process.memory_info().rss) - -for _ in range(0): - print(viewer.add_image(np.random.random((60, 1000, 1000))).name) -for _ in range(2): - print(viewer.add_labels((np.random.random((2, 1000, 1000)) * 10).astype(np.uint8)).name) - -print("mem", process.memory_info().rss) - -# napari.run() - -print("controls", viewer.window.qt_viewer.controls.widgets) -li = weakref.ref(viewer.layers[0]) -data_li = weakref.ref(li()._data) -controls = weakref.ref(viewer.window.qt_viewer.controls.widgets[li()]) -objgraph.show_backrefs(li(), filename="base.png") -del viewer.layers[0] -qtpy.QtGui.QGuiApplication.processEvents() -gc.collect() -gc.collect() -print(li()) -objgraph.show_backrefs(li(), max_depth=10, filename="test.png", refcounts=True) -objgraph.show_backrefs(controls(), max_depth=10, filename="controls.png", refcounts=True) -objgraph.show_backrefs(data_li(), max_depth=10, filename="test_data.png") -print("controls", viewer.window.qt_viewer.controls.widgets) -print("controls", gc.get_referrers(controls())) -print("controls", controls().parent()) -#print("controls", controls().parent().indexOf(controls())) -print(gc.get_referrers(li())) -print(gc.get_referrers(li())[1]) -print(gc.get_referrers(gc.get_referrers(gc.get_referrers(li())[0]))) -res = gc.get_referrers(gc.get_referrers(gc.get_referrers(li())[0])[0]) -print(res) -#print(type(res[0])) diff --git a/examples/dev/plot_2d_edge_meshes.py b/examples/dev/plot_2d_edge_meshes.py deleted file mode 100644 index f7ad2b7a7..000000000 --- a/examples/dev/plot_2d_edge_meshes.py +++ /dev/null @@ -1,36 +0,0 @@ -from napari.layers.shapes._shapes_utils import ( - generate_2D_edge_meshes, -) # , old_generate_2D_edge_meshes -import matplotlib.pyplot as plt -from matplotlib.patches import Polygon - -fig, axes = plt.subplots(2, 3) -# fig.set_figwidth(15) -# fig.set_figheight(10) -colors = iter(['red', 'green', 'blue', 'yellow']) -itaxes = iter(axes.flatten()) -sup = axes.flatten()[4] -for closed in [False, True]: - for beveled in [False, True]: - ax = next(itaxes) - c = next(colors) - centers, offsets, triangles = generate_2D_edge_meshes( - [[0, 3], [1, 0], [2, 3], [5, 0], [2.5, 5]], - closed=closed, - limit=3, - bevel=beveled, - ) - points = centers + 0.3 * offsets - for t in triangles: - trp = points[t] - ax.add_patch(Polygon(trp, ec='#000000', fc=c, alpha=0.2)) - sup.add_patch(Polygon(trp, ec='#000000', fc=c, alpha=0.1)) - ax.scatter(*(points).T) - ax.scatter(*(centers).T) - ax.set_aspect('equal') - ax.set_title(f' {closed=}, {beveled=}') - ax.set_xlim(-1, 6) - ax.set_ylim(-1, 6) - sup.set_xlim(-1, 6) - sup.set_ylim(-1, 6) -plt.show() diff --git a/examples/dev/q_list_view.py b/examples/dev/q_list_view.py deleted file mode 100644 index a9bc67000..000000000 --- a/examples/dev/q_list_view.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Example of using low-level `QtListView` with SelectableEventedList - -:class:`napari.utils.events.SelectableEventedList` is a mutable sequence that -emits events when modified. It also has a selection model (tracking which -items are selected). - -:class:`napari._qt.containers.QtListView` adapts the `EventedList` to the -QAbstractItemModel/QAbstractItemView interface used by the QtFramework. This -allows you to create an interactive GUI view onto a python model that stays -up to date, and can modify the python object... while maintining the python -object as the single "source of truth". -""" -import napari -from napari.qt import get_app -from napari._qt.containers import QtListView -from napari.utils.events import SelectableEventedList - - -get_app() - - -class MyObject: - """generic object.""" - - def __init__(self, name): - self.name = name - - def __str__(self): - return self.name - - -# create our evented list -root = SelectableEventedList([MyObject(x) for x in 'abcdefg']) -# create Qt view onto the list -view = QtListView(root) -# show the view -view.show() - - -# spy on events -root.events.reordered.connect(lambda e: print("reordered to: ", e.value)) -root.selection.events.changed.connect( - lambda e: print( - f"selection changed. added: {e.added}, removed: {e.removed}" - ) -) -root.selection.events._current.connect( - lambda e: print(f"current item changed to: {e.value}") -) - - -napari.run() diff --git a/examples/dev/q_node_tree.py b/examples/dev/q_node_tree.py deleted file mode 100644 index 0a4291e60..000000000 --- a/examples/dev/q_node_tree.py +++ /dev/null @@ -1,78 +0,0 @@ -"""Example of using low-level QtNodeTreeView with Node and Group - -:class:`napari.utils.tree.Node` is a class that may be used as a mixin that -allows an object to be a member of a "tree". - -:class:`napari.utils.tree.Group` is a (nestable) mutable sequence of Nodes, and -is also itself a Node (this is the "composite" pattern): -https://refactoring.guru/design-patterns/composite/python/example - -These two classes may be used to create tree-like data structures that behave -like pure python lists of lists. - -This examples shows that :class:`napari._qt.containers.QtNodeTreeView` -is capable of providing a basic GUI for any tree structure based on -`napari.utils.tree.Group`. -""" -import napari -from napari.qt import get_app -from napari._qt.containers import QtNodeTreeView -from napari.utils.tree import Node, Group - -get_app() - -# create a group of nodes. -root = Group( - [ - Node(name='6'), - Group( - [ - Node(name='1'), - Group([Node(name='2'), Node(name='3')], name="g2"), - Node(name='4'), - Node(name='5'), - Node(name='tip'), - ], - name="g1", - ), - Node(name='7'), - Node(name='8'), - Node(name='9'), - ], - name="root", -) -# create Qt view onto the Group -view = QtNodeTreeView(root) -# show the view -view.show() - - -# pretty __str__ makes nested tree structure more interpretable -print(root) -# root -# ├──6 -# ├──g1 -# │ ├──1 -# │ ├──g2 -# │ │ ├──2 -# │ │ └──3 -# │ ├──4 -# │ ├──5 -# │ └──tip -# ├──7 -# ├──8 -# └──9 - - -# spy on events -root.events.reordered.connect(lambda e: print("reordered to: ", e.value)) -root.selection.events.changed.connect( - lambda e: print( - f"selection changed. added: {e.added}, removed: {e.removed}" - ) -) -root.selection.events._current.connect( - lambda e: print(f"current item changed to: {e.value}") -) - -napari.run() diff --git a/examples/dev/slicing/README.md b/examples/dev/slicing/README.md deleted file mode 100644 index 909cb2eb2..000000000 --- a/examples/dev/slicing/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Slicing examples - -The examples in this directory are for developers to test various aspects -of layer slicing. These are primarily designed to aid in the async effort ([NAP 4](../../../docs/naps/4-async-slicing.md)). - - -## Examples - -Examples using [pooch](https://pypi.org/project/pooch/) will cache data locally, with an [OS-dependant path](https://www.fatiando.org/pooch/latest/api/generated/pooch.os_cache.html?highlight=cache#pooch.os_cache). - - -### Examples of desirable behavior - -These are a set of examples which are easy and non-frustrating to interact in napari -without async support. We want to ensure that these examples continue to be performant. - -* ebi_empiar_3D_with_labels.py [EMPIAR-10982](https://www.ebi.ac.uk/empiar/EMPIAR-10982/) - * Real-world image & labels data (downloaded locally) -* points_example_smlm.py - * Real-world points data (downloaded locally) - -Additional examples from the main napari examples: -* add_multiscale_image.py - * Access to in-memory multi-scale data - -### Examples of undesirable behavior - -These are a set of examples which currently cause undesirable behavior in napari, typically -resulting in non-responsive user interface due to synchronous slicing on large or remote data. - -* random_shapes.py - * A large number of shapes to stress slicing on a shapes layer -* random_points.py - * A large number of random points to stress slicing on a points layer -* janelia_s3_n5_multiscale.py - * Multi-scale remote image data in zarr format - -## Performance monitoring - -The [perfmon](../../../tools/perfmon/README.md) tooling can be used to monitor the data -access performance on these examples. \ No newline at end of file diff --git a/examples/dev/slicing/ebi_empiar_3D_with_labels.py b/examples/dev/slicing/ebi_empiar_3D_with_labels.py deleted file mode 100644 index 2db53fefc..000000000 --- a/examples/dev/slicing/ebi_empiar_3D_with_labels.py +++ /dev/null @@ -1,35 +0,0 @@ -import napari -import pooch -from tifffile import imread - -""" -This data comes from the MitoNet Benchmarks. - -Six benchmark volumes of instance segmentation of mitochondria from diverse volume EM datasets -Narayan K , Conrad RW -DOI: https://dx.doi.org/10.6019/EMPIAR-10982 - -Data is stored at EMPIAR and can be explored here: https://www.ebi.ac.uk/empiar/EMPIAR-10982/ - -With respect to the napari async slicing work, this dataset is small enough that it performs well in synchronous mode. -""" - -salivary_gland_em_path = pooch.retrieve( - url='https://ftp.ebi.ac.uk/empiar/world_availability/10982/data/mito_benchmarks/salivary_gland/salivary_gland_em.tif', - known_hash='222f50dd8fd801a84f118ce71bc735f5c54f1a3ca4d98315b27721ae499bff94', - progressbar=True -) - -salivary_gland_mito_path = pooch.retrieve( - url='https://ftp.ebi.ac.uk/empiar/world_availability/10982/data/mito_benchmarks/salivary_gland/salivary_gland_mito.tif', - known_hash='95247d952a1dd0f7b37da1be95980b598b590e4777065c7cd877ab67cb63c5eb', - progressbar=True -) - -salivary_gland_em = imread(salivary_gland_em_path) -salivary_gland_mito = imread(salivary_gland_mito_path) - -viewer = napari.view_image(salivary_gland_em) -viewer.add_labels(salivary_gland_mito) - -napari.run() diff --git a/examples/dev/slicing/janelia_s3_n5_multiscale.py b/examples/dev/slicing/janelia_s3_n5_multiscale.py deleted file mode 100644 index cf0536944..000000000 --- a/examples/dev/slicing/janelia_s3_n5_multiscale.py +++ /dev/null @@ -1,30 +0,0 @@ -import zarr -import dask.array as da -import napari - -""" -The sample data here is Interphase HeLa Cell [https://openorganelle.janelia.org/datasets/jrc_hela-3], -from HHMI's OpenOrganelle [https://openorganelle.janelia.org]. - -The data are hosted by Open Data on AWS on S3. - -This tests access to multi-scale remote data. -""" - - -# access the root of the n5 container -group = zarr.open(zarr.N5FSStore('s3://janelia-cosem-datasets/jrc_hela-2/jrc_hela-2.n5', anon=True)) - -# s0 (highest resolution) through s5 (lowest resolution) are available -data = [] -for i in range(0, 5): - zarr_array = group[f'em/fibsem-uint16/s{i}'] - data.append(da.from_zarr(zarr_array, chunks=zarr_array.chunks)) - -# This order presents a better visualization, but seems to break simple async (issue #5106) -# viewer = napari.view_image(data, order=(1, 0, 2), contrast_limits=(18000, 40000), multiscale=True) -viewer = napari.view_image(data, contrast_limits=(18000, 40000), multiscale=True) - -if __name__ == '__main__': - napari.run() - diff --git a/examples/dev/slicing/points_example_smlm.py b/examples/dev/slicing/points_example_smlm.py deleted file mode 100644 index 12fbbd6b7..000000000 --- a/examples/dev/slicing/points_example_smlm.py +++ /dev/null @@ -1,31 +0,0 @@ -import napari -import pooch -import csv -import numpy as np - -""" -This data comes from the Neurocyto Lab's description of the ThunderSTORM format. -This file format is used to represent single molecule localizations. - -With respect to the napari async slicing work, this dataset is small enough that it performs well in synchronous mode. - -If someone is interested, then you can use the uncertainty_xy attribute from the STORM data to change the point size. - -More information is available here: http://www.neurocytolab.org/tscolumns/ -""" - -storm_path = pooch.retrieve( - url='http://www.neurocytolab.org/wp-content/uploads/2018/06/ThunderSTORM_TS3D.csv', - known_hash='665a28b2fad69dbfd902e4945df04667f876d33a91167614c280065212041a29', - progressbar=True -) - -with open(storm_path) as csvfile: - data = list(csv.reader(csvfile)) - -data = np.array(data[1:]).astype(float) -data = data[:, 1:4] - -viewer = napari.view_points(data, size=50) - -napari.run() diff --git a/examples/dev/slicing/random_points.py b/examples/dev/slicing/random_points.py deleted file mode 100644 index fe7a77cb1..000000000 --- a/examples/dev/slicing/random_points.py +++ /dev/null @@ -1,22 +0,0 @@ -import argparse -from skimage import data -import numpy as np -import napari - -""" -Stress the points layer by generating a large number of points. -""" - -parser = argparse.ArgumentParser() -parser.add_argument( - "n", type=int, nargs='?', default=10_000_000, help="(default: %(default)s)" -) -args = parser.parse_args() - -np.random.seed(0) -n = args.n -data = 1000 * np.random.rand(n, 3) -viewer = napari.view_points(data) - -if __name__ == '__main__': - napari.run() diff --git a/examples/dev/slicing/random_shapes.py b/examples/dev/slicing/random_shapes.py deleted file mode 100644 index 3fd756b49..000000000 --- a/examples/dev/slicing/random_shapes.py +++ /dev/null @@ -1,86 +0,0 @@ -import os -import logging -import numpy as np -import napari -import napari.viewer - - -""" -This example generates many random shapes. - -There currently is a bug in triangulation that requires this additional step of sanitizing the shape data: https://github.com/orgs/napari/projects/18/views/2 -""" - - -# logging.getLogger().setLevel(0) - - -def generate_shapes(filename): - # image_data = np.squeeze(cells3d()[:, 1, :, :]) - # delayed_image_data = DelayedArray(image_data, delay_s=1) - - # From https://github.com/napari/napari/blob/main/examples/nD_shapes.py - # create one random polygon per "plane" - - shapes_per_slice = 1000 - - all_shapes = None - - np.random.seed(0) - for k in range(shapes_per_slice): - - planes = np.tile(np.arange(128).reshape((128, 1, 1)), (1, 5, 1)) - corners = np.random.uniform(0, 128, size=(128, 5, 2)) - shapes = np.concatenate((planes, corners), axis=2) - - if all_shapes is not None: - all_shapes = np.concatenate((all_shapes, shapes), axis=0) - else: - all_shapes = shapes - - print('all_shapes', all_shapes.shape) - - from vispy.geometry.polygon import PolygonData - - good_shapes = [] - - for shape in all_shapes: - - # Use try/except to filter all bad shapes - try: - vertices, triangles = PolygonData( - vertices=shape[:, 1:] - ).triangulate() - except: - pass - else: - good_shapes.append(shape) - - print(len(good_shapes)) - np.savez(filename, shapes=good_shapes) - - -test_filename = '/tmp/napari_example_shapes.npz' - -# Create the example shapes if they do not exist -if not os.path.exists(test_filename): - print( - 'Shapes file does not exist yet. Generating shapes. This may take a couple of minutes...' - ) - generate_shapes(test_filename) - -# Load the shapes -with np.load(test_filename) as data: - shapes = data['shapes'] - -# Test shapes in viewer -viewer = napari.Viewer() -viewer.show() - -shapes_layer = viewer.add_shapes( - np.array(shapes), - shape_type='polygon', - name='sliced', -) - -napari.run() diff --git a/examples/dynamic-projections-dask.py b/examples/dynamic-projections-dask.py deleted file mode 100644 index 03a07432d..000000000 --- a/examples/dynamic-projections-dask.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -Dynamic projections dask -======================== - -Using dask array operations, one can dynamically take arbitrary slices -and computations of a source dask array and display the results in napari. -When the computation takes one or more parameters, one can tie a UI to -them using magicgui. - -.. tags:: visualization-advanced -""" - -import numpy as np -import napari -import dask.array as da -from dask.array.lib.stride_tricks import sliding_window_view -from skimage import data - -############################################################################## -# Part 1: using code to view a specific value. - -blobs = data.binary_blobs(length=64, n_dim=3) -blobs_dask = da.from_array(blobs, chunks=(1, 64, 64)) - -# original shape [60, 1, 1, 5, 64, 64], -# use squeeze to remove singleton axes -blobs_dask_windows = np.squeeze( - sliding_window_view(blobs_dask, window_shape=(5, 64, 64)), - axis=(1, 2), -) -blobs_sum = np.sum(blobs_dask_windows, axis=1) -viewer = napari.view_image(blobs_sum) - -if __name__ == '__main__': - napari.run() - -############################################################################## -# Part 2: using magicgui to vary the slice thickness. - -from magicgui import magicgui - -def sliding_window_mean( - arr: napari.types.ImageData, size: int = 1 -) -> napari.types.LayerDataTuple: - window_shape = (size,) + (arr.shape[1:]) - arr_windows = sliding_window_view(arr, window_shape=window_shape) - # as before, use squeeze to remove singleton axes - arr_windows_1d = np.squeeze( - arr_windows, axis=tuple(range(1, arr.ndim)) - ) - arr_summed = np.sum(arr_windows_1d, axis=1) / size - return ( - arr_summed, - { - 'translate': (size // 2,) + (0,) * (arr.ndim - 1), - 'name': 'mean-window', - 'colormap': 'magenta', - 'blending': 'additive', - }, - 'image', - ) - - -viewer = napari.view_image(blobs_dask, colormap='green') -viewer.window.add_dock_widget(magicgui(sliding_window_mean, auto_call=True)) -viewer.dims.current_step = (32, 0, 0) - -if __name__ == '__main__': - napari.run() diff --git a/examples/embed_ipython_.py b/examples/embed_ipython_.py deleted file mode 100644 index 232f2a7e2..000000000 --- a/examples/embed_ipython_.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Embed IPython -============= - -Start napari and land directly in an embedded ipython console with qt event loop. - -A similar effect can be achieved more simply with `viewer.update_console(locals())`, -such as shown in https://github.com/napari/napari/blob/main/examples/update_console.py. - -However, differently from `update_console`, this will start an independent -ipython console which can outlive the viewer. - -.. tags:: gui -""" - -import napari -from IPython.terminal.embed import InteractiveShellEmbed - -# any code -text = 'some text' - -# initalize viewer -viewer = napari.Viewer() - -# embed ipython and run the magic command to use the qt event loop -sh = InteractiveShellEmbed() -sh.enable_gui('qt') # equivalent to using the '%gui qt' magic -sh() # open the embedded shell - -# From there, you can access the script's scope, such as the variables `text` and `viewer` diff --git a/examples/get_current_viewer.py b/examples/get_current_viewer.py deleted file mode 100644 index 35c7af6c0..000000000 --- a/examples/get_current_viewer.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Get current viewer -================== - -Get a reference to the current napari viewer. - -Whilst this example is contrived, it can be useful to get a reference to the -viewer when the viewer is out of scope. - -.. tags:: gui -""" - -import napari - -# create viewer -viewer = napari.Viewer() - -# lose reference to viewer -viewer = 'oops no viewer here' - -# get that reference again -viewer = napari.current_viewer() diff --git a/examples/image_depth.py b/examples/image_depth.py deleted file mode 100644 index 7c4492f0f..000000000 --- a/examples/image_depth.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Image depth -=========== - -.. tags:: visualization-basic -""" - -import napari -import numpy as np - -im_data = np.zeros((50, 50, 50)) -im_data[30:40, 25:35, 25:35] = 1 -viewer = napari.view_image(im_data, colormap='magenta', rendering='iso') -viewer.add_image(im_data, colormap='green', rendering='iso', translate=(30, 0, 0)) - -points_data = [ - [50, 30, 30], - [25, 30, 30], - [75, 30, 30] -] -viewer.add_points(points_data, size=4) - -viewer.dims.ndisplay = 3 - -if __name__ == '__main__': - napari.run() diff --git a/examples/inherit_viewer_style.py b/examples/inherit_viewer_style.py deleted file mode 100644 index c4aca965d..000000000 --- a/examples/inherit_viewer_style.py +++ /dev/null @@ -1,76 +0,0 @@ -""" -Method to get napari style in magicgui based windows -==================================================== - -Example how to embed magicgui widget in dialog to inherit style -from main napari window. -""" - -from typing import Callable - -from qtpy.QtWidgets import QDialog, QWidget, QVBoxLayout, QPushButton, QGridLayout, QLabel, QSpinBox - -from magicgui import magicgui - -import napari -from napari.qt import get_stylesheet -from napari.settings import get_settings - -# The magicgui widget shown by selecting the 'Show widget' button of MyWidget -@magicgui -def sample_add(a: int, b: int) -> int: - return a + b - -def change_style(): - sample_add.native.setStyleSheet(get_stylesheet(get_settings().appearance.theme)) - - -get_settings().appearance.events.theme.connect(change_style) -change_style() - - -class MyDialog(QDialog): - def __init__(self, parent=None): - super().__init__(parent) - self.first_input = QSpinBox() - self.second_input = QSpinBox() - self.btn = QPushButton('Add') - layout = QGridLayout() - layout.addWidget(QLabel("first input"), 0, 0) - layout.addWidget(self.first_input, 0, 1) - layout.addWidget(QLabel("second input"), 1, 0) - layout.addWidget(self.second_input, 1, 1) - layout.addWidget(self.btn, 2, 0, 1, 2) - self.setLayout(layout) - self.btn.clicked.connect(self.run) - - def run(self): - print('run', self.first_input.value() + self.second_input.value()) - self.close() - -class MyWidget(QWidget): - def __init__(self): - super().__init__() - self.btn1 = QPushButton('Show dialog') - self.btn1.clicked.connect(self.show_dialog) - self.btn2 = QPushButton('Show widget') - self.btn2.clicked.connect(self.show_widget) - self.layout = QVBoxLayout() - self.layout.addWidget(self.btn1) - self.layout.addWidget(self.btn2) - self.setLayout(self.layout) - - def show_dialog(self): - dialog = MyDialog(self) - dialog.exec_() - - def show_widget(self): - sample_add.show() - - - -viewer = napari.Viewer() - -widget = MyWidget() -viewer.window.add_dock_widget(widget, area='right') -napari.run() diff --git a/examples/interaction_box_image.py b/examples/interaction_box_image.py deleted file mode 100644 index 620bdfdf9..000000000 --- a/examples/interaction_box_image.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -Interaction box image -===================== - -This example demonstrates activating 'transform' mode on the image layer. -This allows the user to manipulate the image via the interaction box -(blue box and points around the image). - -.. tags:: experimental -""" - -from skimage import data -import numpy as np -import napari -from napari.utils.transforms import Affine - -viewer = napari.view_image(data.astronaut(), rgb=True) -viewer.layers.selection.active.mode = 'transform' - -if __name__ == '__main__': - napari.run() diff --git a/examples/interaction_box_points.py b/examples/interaction_box_points.py deleted file mode 100644 index d22ee86a1..000000000 --- a/examples/interaction_box_points.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Interaction box points -====================== - -Demonstrate interaction box on points layer - -.. tags:: experimental -""" - -from skimage import data -import napari -import numpy as np -from napari.layers.points._points_utils import points_in_box - - -def on_selection_box_drag(event): - # Do selection in world coordinates so box aligns with axes (not sure if this is guaranteed) - points = viewer.layers.selection.active._data_to_world(viewer.layers.selection.active._view_data) - sel_i = points_in_box(event.value,points,viewer.layers.selection.active._view_size) - viewer.layers.selection.active.selected_data = sel_i - -def on_selection_box_final(event): - sel_i = viewer.layers.selection.active.selected_data - if len(sel_i) > 0: - viewer.overlays.interaction_box.points = viewer.layers.selection.active._data_to_world(np.array([viewer.layers.selection.active._view_data[i] for i in sel_i])) - viewer.overlays.interaction_box.show = True - viewer.overlays.interaction_box.show_vertices = True - viewer.overlays.interaction_box.show_handle = True - else: - viewer.overlays.interaction_box.points = None - viewer.layers.selection.active.selected_data = [] - -def on_transform_changed_drag(event): - sel_i = viewer.layers.selection.active.selected_data - points = viewer.overlays.interaction_box.points - - for i, index in enumerate(sel_i): - viewer.layers.selection.active._data[index] = viewer.layers.selection.active.world_to_data(event.value(points[i])) - viewer.layers.selection.active._update_dims() - viewer.layers.selection.active.events.data(value=viewer.layers.selection.active.data) - -X, Y = np.mgrid[-500:500:50, -500:500:50] -positions = np.dstack([X.ravel(), Y.ravel()]) -viewer = napari.view_points(positions[0,:,:]) -viewer.layers.selection.active.interactive = False -viewer.overlays.interaction_box.show = True -viewer.overlays.interaction_box.events.selection_box_drag.connect(on_selection_box_drag) -viewer.overlays.interaction_box.events.selection_box_final.connect(on_selection_box_final) -viewer.overlays.interaction_box.events.transform_drag.connect(on_transform_changed_drag) - -if __name__ == '__main__': - napari.run() diff --git a/examples/interactive_move_point_3d.py b/examples/interactive_move_point_3d.py deleted file mode 100644 index b4751b1d3..000000000 --- a/examples/interactive_move_point_3d.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -Interactive move point -====================== - -3D click and drag interactivity demo - -.. tags:: experimental -""" -from copy import copy - -import numpy as np - -import napari -from napari.utils.geometry import project_points_onto_plane - -# Create viewer, point to move and bounding box -viewer = napari.Viewer(ndisplay=3) - -bounding_box_data = [ - [-1, -1, -1], - [-1, -1, 1], - [-1, 1, -1], - [-1, 1, 1], - [1, -1, -1], - [1, -1, 1], - [1, 1, -1], - [1, 1, 1] -] -bounding_box_layer = viewer.add_points( - bounding_box_data, - name='bounding box', - face_color='green', - size=0.2, - edge_width=0 -) -point_layer = viewer.add_points( - [0, 0, 0], - name='point', - face_color='magenta', - size=0.2, - edge_width=0 -) - - -@point_layer.mouse_drag_callbacks.append -def drag_along_camera_plane(layer, event): - # early exit if shift isn't held - if not 'Shift' in event.modifiers: - return - - # disable interactivity during this drag event to fix the view direction - layer.interactive = False - - # store start position of point - original_position = copy(point_layer.data[0]) - - yield - while event.type == 'mouse_move': - # Calculate click position in data coords - point_to_project = np.asarray(layer.world_to_data(event.position))[ - list(event.dims_displayed) - ] - - # Calculate view direction in data coordinates - # this view direction, together with the click position, form a plane - # parallel to the canvas in data coordinates. - view_direction_data = np.asarray(layer._world_to_data_ray( - list(event.view_direction) - ))[event.dims_displayed] - - # Project click position onto plane - projected_position = project_point_onto_plane( - point=point_to_project, - plane_point=original_position, - plane_normal=view_direction_data, - ) - - # Calculate shifts to apply to point - shifts = projected_position - original_position - - # Update position - updated_position = original_position + shifts - - # Clamp updated position to bounding box - clamped = np.where(updated_position > 1, 1, updated_position) - clamped = np.where(clamped < -1, -1, clamped) - - # update - point_layer.data = clamped - yield - # reenable interactivity - layer.interactive = True - -# setup viewer -viewer.camera.angles = (45, 30, 30) -viewer.camera.zoom = 100 -viewer.text_overlay.visible = True -viewer.text_overlay.text = """'shift' + click and drag to move the pink point -normal click and drag to rotate the scene -""" - -if __name__ == '__main__': - napari.run() diff --git a/examples/interactive_move_rectangle_3d.py b/examples/interactive_move_rectangle_3d.py deleted file mode 100644 index 7678fe80a..000000000 --- a/examples/interactive_move_rectangle_3d.py +++ /dev/null @@ -1,72 +0,0 @@ -""" -Interactive move rectangle -========================== - -Shift a rectangle along its normal vector in 3D - -.. tags:: experimental -""" - -import napari -import numpy as np - -rectangle = np.array( - [ - [50, 75, 75], - [50, 125, 75], - [100, 125, 125], - [100, 75, 125] - ], - dtype=float -) - -shapes_data = np.array(rectangle) -normal_vector = np.cross( - rectangle[0] - rectangle[1], rectangle[2] - rectangle[1] -) -normal_vector /= np.linalg.norm(normal_vector) - -viewer = napari.Viewer(ndisplay=3) - -shapes_layer = viewer.add_shapes( - data=shapes_data, - face_color='blue' -) -viewer.camera.angles = (-170, -20, -170) -viewer.camera.zoom = 1.5 -viewer.text_overlay.visible = True -viewer.text_overlay.text = """'click and drag the rectangle to create copies along its normal vector -""" - - -@shapes_layer.mouse_drag_callbacks.append -def move_rectangle_along_normal(layer, event): - shape_index, _ = layer.get_value( - position=event.position, - view_direction=event.view_direction, - dims_displayed=event.dims_displayed - ) - if shape_index is None: - return - - layer.interactive = False - - start_position = np.copy(event.position) - yield - while event.type == 'mouse_move': - projected_distance = layer.projected_distance_from_mouse_drag( - start_position=start_position, - end_position=event.position, - view_direction=event.view_direction, - vector=normal_vector, - dims_displayed=event.dims_displayed, - ) - shift_data_coordinates = projected_distance * normal_vector - new_rectangle = layer.data[shape_index] + shift_data_coordinates - layer.add(new_rectangle) - yield - layer.interactive = True - - -if __name__ == '__main__': - napari.run() diff --git a/examples/interactive_scripting.py b/examples/interactive_scripting.py deleted file mode 100644 index e4f47bbc2..000000000 --- a/examples/interactive_scripting.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Interactive scripting -===================== - -.. tags:: interactivity -""" - -import numpy as np -import napari -from napari.qt import thread_worker -import time - - -# create the viewer with an image -data = np.random.random((512, 512)) -viewer = napari.Viewer() -layer = viewer.add_image(data) - -def update_layer(data): - layer.data = data - -@thread_worker(connect={'yielded': update_layer}) -def create_data(*, update_period, num_updates): - # number of times to update - for k in range(num_updates): - yield np.random.random((512, 512)) - time.sleep(update_period) - -create_data(update_period=0.05, num_updates=50) - -if __name__ == '__main__': - napari.run() diff --git a/examples/labels-2d.py b/examples/labels-2d.py deleted file mode 100644 index ab33527e8..000000000 --- a/examples/labels-2d.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Labels 2D -========= - -Display a labels layer above of an image layer using the ``add_labels`` and -``add_image`` APIs - -.. tags:: visualization-basic -""" - -from skimage import data -from skimage.color import rgb2gray -from skimage.segmentation import slic -import napari - - -astro = data.astronaut() - -# initialise viewer with astro image -viewer = napari.view_image(rgb2gray(astro), name='astronaut', rgb=False) - -# add the labels -# we add 1 because SLIC returns labels from 0, which we consider background -labels = slic(astro, multichannel=True, compactness=20) + 1 -label_layer = viewer.add_labels(labels, name='segmentation') - -# Set the labels layer mode to picker with a string -label_layer.mode = 'PICK' -print(f'The color of label 5 is {label_layer.get_color(5)}') - -if __name__ == '__main__': - napari.run() diff --git a/examples/layers.py b/examples/layers.py deleted file mode 100644 index 02de6f53b..000000000 --- a/examples/layers.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Layers -====== - -Display multiple image layers using the ``add_image`` API and then reorder them -using the layers swap method and remove one - -.. tags:: visualization-basic -""" - -from skimage import data -from skimage.color import rgb2gray -import numpy as np -import napari - - -# create the viewer with several image layers -viewer = napari.view_image(rgb2gray(data.astronaut()), name='astronaut') -viewer.add_image(data.camera(), name='photographer') -viewer.add_image(data.coins(), name='coins') -viewer.add_image(data.moon(), name='moon') -viewer.add_image(np.random.random((512, 512)), name='random') -viewer.add_image(data.binary_blobs(length=512, volume_fraction=0.2, n_dim=2), name='blobs') -viewer.grid.enabled = True - -if __name__ == '__main__': - napari.run() diff --git a/examples/linked_layers.py b/examples/linked_layers.py deleted file mode 100644 index b03148136..000000000 --- a/examples/linked_layers.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Linked layers -============= - -Demonstrates the `link_layers` function. - -This function takes a list of layers and an optional list of attributes, and -links them such that when one of the linked attributes changes on any of the -linked layers, all of the other layers follow. - -.. tags:: experimental -""" -import napari -from napari.experimental import link_layers -import numpy as np - - -viewer = napari.view_image(np.random.rand(3, 64, 64), channel_axis=0) - -# link contrast_limits and gamma between all layers in viewer -# NOTE: you may also omit the second argument to link ALL valid, common -# attributes for the set of layers provided -link_layers(viewer.layers, ('contrast_limits', 'gamma')) - -# unlinking may be done with napari.experimental.unlink_layers - -# this may also be done in a context manager: -# with napari.experimental.layers_linked([layers]): -# ... - -if __name__ == '__main__': - napari.run() diff --git a/examples/live_tiffs_.py b/examples/live_tiffs_.py deleted file mode 100644 index c6081e6d2..000000000 --- a/examples/live_tiffs_.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Live tiffs -========== - -Loads and Displays tiffs as they get generated in the specific directory. -Trying to simulate the live display of data as it gets acquired by microscope. -This script should be run together with live_tiffs_generator.py - -.. tags:: experimental -""" - -import os -import sys -import time -from skimage.io.collection import alphanumeric_key -from dask import delayed -import dask.array as da -from tifffile import imread -import napari -from napari.qt import thread_worker - - -viewer = napari.Viewer(ndisplay=3) -# pass a directory to monitor or it will monitor current directory. -path = sys.argv[1] if len(sys.argv) > 1 else '.' -path = os.path.abspath(path) -end_of_experiment = 'final.log' - - -def append(delayed_image): - """Appends the image to viewer. - - Parameters - ---------- - delayed_image : dask.delayed function object - """ - if delayed_image is None: - return - - if viewer.layers: - # layer is present, append to its data - layer = viewer.layers[0] - image_shape = layer.data.shape[1:] - image_dtype = layer.data.dtype - image = da.from_delayed( - delayed_image, shape=image_shape, dtype=image_dtype, - ).reshape((1,) + image_shape) - layer.data = da.concatenate((layer.data, image), axis=0) - else: - # first run, no layer added yet - image = delayed_image.compute() - image = da.from_delayed( - delayed_image, shape=image.shape, dtype=image.dtype, - ).reshape((1,) + image.shape) - layer = viewer.add_image(image, rendering='attenuated_mip') - - # we want to show the last file added in the viewer to do so we want to - # put the slider at the very end. But, sometimes when user is scrolling - # through the previous slide then it is annoying to jump to last - # stack as it gets added. To avoid that jump we 1st check where - # the scroll is and if its not at the last slide then don't move the slider. - if viewer.dims.point[0] >= layer.data.shape[0] - 2: - viewer.dims.set_point(0, layer.data.shape[0] - 1) - - -@thread_worker(connect={'yielded': append}) -def watch_path(path): - """Watches the path for new files and yields it once file is ready. - - Notes - ----- - Currently, there is no proper way to know if the file has written - entirely. So the workaround is we assume that files are generating - serially (in most microscopes it common), and files are name in - alphanumeric sequence We start loading the total number of minus the - last file (`total__files - last`). In other words, once we see the new - file in the directory, it means the file before it has completed so load - that file. For this example, we also assume that the microscope is - generating a `final.log` file at the end of the acquisition, this file - is an indicator to stop monitoring the directory. - - Parameters - ---------- - path : str - directory to monitor and load tiffs as they start appearing. - """ - current_files = set() - processed_files = set() - end_of_acquisition = False - while not end_of_acquisition: - files_to_process = set() - # Get the all files in the directory at this time - current_files = set(os.listdir(path)) - - # Check if the end of acquisition has reached - # if yes then remove it from the files_to_process set - # and send it to display - if end_of_experiment in current_files: - files_to_process = current_files - processed_files - files_to_process.remove(end_of_experiment) - end_of_acquisition = True - - elif len(current_files): - # get the last file from the current files based on the file names - last_file = sorted(current_files, key=alphanumeric_key)[-1] - current_files.remove(last_file) - files_to_process = current_files - processed_files - - # yield every file to process as a dask.delayed function object. - for p in sorted(files_to_process, key=alphanumeric_key): - yield delayed(imread)(os.path.join(path, p)) - else: - yield - - # add the files which we have yield to the processed list. - processed_files.update(files_to_process) - time.sleep(0.1) - - -worker = watch_path(path) -if __name__ == '__main__': - napari.run() diff --git a/examples/live_tiffs_generator_.py b/examples/live_tiffs_generator_.py deleted file mode 100644 index 185eec920..000000000 --- a/examples/live_tiffs_generator_.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Live tiffs generator -==================== - -Simulation of microscope acquisition. This code generates time series tiffs in -an output directory (must be supplied by the user). - -.. tags:: experimental -""" - - -import os -import sys -import time -import argparse - -import numpy as np -from skimage import data -import tifffile - - -parser = argparse.ArgumentParser() -parser.add_argument('outdir', help='output directory for tiffs') -parser.add_argument( - '--sleep-time', - help='how long to sleep between volumes, in seconds', - type=float, - default=1.0, -) -parser.add_argument( - '-n', help='total number of volumes', type=int, default=100 -) - - -def main(argv=sys.argv[1:]): - args = parser.parse_args(argv) - outdir = args.outdir - sleep_time = args.sleep_time - n = args.n - fractions = np.linspace(0.05, 0.5, n) - os.makedirs(outdir, exist_ok=True) - for i, f in enumerate(fractions): - # We are using skimage binary_blobs which generate's synthetic binary - # image with several rounded blob-like objects and write them into files. - curr_vol = 255 * data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=3, volume_fraction=f - ).astype(np.uint8) - tifffile.imwrite( - os.path.join(outdir, f'{i}.tiff'), curr_vol, compress=6 - ) - time.sleep(sleep_time) - # create a final.log file as an indicator for end of acquisition - final_file = open(os.path.join(outdir, 'final.log'), 'w') - final_file.close() - - -if __name__ == '__main__': - main() diff --git a/examples/magic_image_arithmetic.py b/examples/magic_image_arithmetic.py deleted file mode 100644 index 480fa4046..000000000 --- a/examples/magic_image_arithmetic.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -magicgui Image Arithmetic -========================= - -Basic example of using magicgui to create an Image Arithmetic GUI in napari. - -.. tags:: gui -""" - -import enum -import numpy as np -import napari - - -# Enums are a convenient way to get a dropdown menu -class Operation(enum.Enum): - """A set of valid arithmetic operations for image_arithmetic.""" - - add = np.add - subtract = np.subtract - multiply = np.multiply - divide = np.divide - - -# Define our image_arithmetic function. -# Note that we can use forward references for the napari type annotations. -# You can read more about them here: -# https://peps.python.org/pep-0484/#forward-references -# In this example, because we have already imported napari anyway, it doesn't -# really matter. But this syntax would let you specify that a parameter is a -# napari object type without actually importing or depending on napari. -# Note: here we use `napari.types.ImageData` as our parameter annotations, -# which means our function will be passed layer.data instead of -# the full layer instance -def image_arithmetic( - layerA: 'napari.types.ImageData', - operation: Operation, - layerB: 'napari.types.ImageData', -) -> 'napari.types.ImageData': - """Adds, subtracts, multiplies, or divides two same-shaped image layers.""" - if layerA is not None and layerB is not None: - return operation.value(layerA, layerB) - - -# create a new viewer with a couple image layers -viewer = napari.Viewer() -viewer.add_image(np.random.rand(20, 20), name="Layer 1") -viewer.add_image(np.random.rand(20, 20), name="Layer 2") - -# Add our magic function to napari -viewer.window.add_function_widget(image_arithmetic) - -if __name__ == '__main__': - napari.run() diff --git a/examples/magic_parameter_sweep.py b/examples/magic_parameter_sweep.py deleted file mode 100644 index 9f6510c96..000000000 --- a/examples/magic_parameter_sweep.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -magicgui parameter sweep -======================== - -Example showing how to accomplish a napari parameter sweep with magicgui. - -It demonstrates: -1. overriding the default widget type with a custom class -2. the `auto_call` option, which calls the function whenever a parameter changes - -.. tags:: gui -""" -import skimage.data -import skimage.filters -import napari -from typing_extensions import Annotated - -# Define our gaussian_blur function. -# Note that we can use forward references for the napari type annotations. -# You can read more about them here: -# https://peps.python.org/pep-0484/#forward-references -# In this example, because we have already imported napari anyway, it doesn't -# really matter. But this syntax would let you specify that a parameter is a -# napari object type without actually importing or depending on napari. -# We also use the `Annotated` type to pass an additional dictionary that can be used -# to aid widget generation. The keys of the dictionary are keyword arguments to -# the corresponding magicgui widget type. For more informaiton see -# https://napari.org/magicgui/api/widgets.html. -def gaussian_blur( - layer: 'napari.layers.Image', - sigma: Annotated[float, {"widget_type": "FloatSlider", "max": 6}] = 1.0, - mode: Annotated[str, {"choices": ["reflect", "constant", "nearest", "mirror", "wrap"]}]="nearest", -) -> 'napari.types.ImageData': - """Apply a gaussian blur to ``layer``.""" - if layer: - return skimage.filters.gaussian(layer.data, sigma=sigma, mode=mode) - - -# create a viewer and add some images -viewer = napari.Viewer() -viewer.add_image(skimage.data.astronaut().mean(-1), name="astronaut") -viewer.add_image(skimage.data.grass().astype("float"), name="grass") - -# Add our magic function to napari -viewer.window.add_function_widget(gaussian_blur) - -if __name__ == '__main__': - napari.run() diff --git a/examples/magic_viewer.py b/examples/magic_viewer.py deleted file mode 100644 index 95f9fbebb..000000000 --- a/examples/magic_viewer.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -magicgui viewer -=============== - -Example showing how to access the current viewer from a function widget. - -.. tags:: gui -""" - -import napari - -# annotating a paramater as `napari.Viewer` will automatically provide -# the viewer that the function is embedded in, when the function is added to -# the viewer with add_function_widget. -def my_function(viewer: napari.Viewer): - print(viewer, f"with {len(viewer.layers)} layers") - - -viewer = napari.Viewer() -# Add our magic function to napari -viewer.window.add_function_widget(my_function) - -if __name__ == '__main__': - napari.run() diff --git a/examples/mgui_dask_delayed_.py b/examples/mgui_dask_delayed_.py deleted file mode 100644 index c10bf2b7d..000000000 --- a/examples/mgui_dask_delayed_.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -magicgui dask delayed -===================== - -An example of calling a threaded function from a magicgui dock_widget. -Note: this example requires python >= 3.9 - -.. tags:: gui -""" -import time -from concurrent.futures import Future - -import dask.array as da -from magicgui import magicgui - -import napari -from napari.types import ImageData - - -def _slow_function(nz): - time.sleep(2) - return da.random.random((nz, 512, 512)) - - -if __name__ == '__main__': - from dask.distributed import Client - - client = Client() - - @magicgui(client={'bind': client}) - def widget(client, nz: int = 1000) -> Future[ImageData]: - return client.submit(_slow_function, nz) - - viewer = napari.Viewer() - viewer.window.add_dock_widget(widget, area="right") - -if __name__ == '__main__': - napari.run() diff --git a/examples/mgui_with_threadpoolexec_.py b/examples/mgui_with_threadpoolexec_.py deleted file mode 100644 index 9cc81a94c..000000000 --- a/examples/mgui_with_threadpoolexec_.py +++ /dev/null @@ -1,70 +0,0 @@ -""" -magicgui with threadpoolexec -============================ - -An example of calling a threaded function from a magicgui ``dock_widget``. - -using ``ThreadPoolExecutor`` -Note: this example requires python >= 3.9 - -.. tags:: gui -""" -import sys -from concurrent.futures import Future, ThreadPoolExecutor - -from magicgui import magic_factory -from skimage import data -from skimage.feature import blob_log - -import napari -from napari.types import ImageData, LayerDataTuple - -if sys.version_info < (3, 9): - print('This example requires python >= 3.9') - sys.exit(0) - -pool = ThreadPoolExecutor() - - -@magic_factory( - min_sigma={"min": 0.5, "max": 15, "step": 0.5}, - max_sigma={"min": 1, "max": 200, "step": 0.5}, - num_sigma={"min": 1, "max": 20}, - threshold={"min": 0, "max": 1000, "step": 0.1}, -) -def make_widget( - image: ImageData, - min_sigma: float = 5, - max_sigma: float = 30, - num_sigma: int = 10, - threshold: float = 0.3, -) -> Future[LayerDataTuple]: - - # long running function - def _make_blob(): - # skimage.feature may take a while depending on the parameters - blobs = blob_log( - image, - min_sigma=min_sigma, - max_sigma=max_sigma, - num_sigma=num_sigma, - threshold=threshold, - ) - data = blobs[:, : image.ndim] - kwargs = dict( - size=blobs[:, -1], - edge_color="red", - edge_width=2, - face_color="transparent", - ) - return (data, kwargs, 'points') - - return pool.submit(_make_blob) - - -viewer = napari.Viewer() -viewer.window.add_dock_widget(make_widget(), area="right") -viewer.add_image(data.hubble_deep_field().mean(-1)) - -napari.run() -pool.shutdown(wait=True) diff --git a/examples/mgui_with_threadworker_.py b/examples/mgui_with_threadworker_.py deleted file mode 100644 index c487e2496..000000000 --- a/examples/mgui_with_threadworker_.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -magicgui with threadworker -========================== - -An example of calling a threaded function from a magicgui ``dock_widget``. -Note: this example requires python >= 3.9 - -.. tags:: gui -""" -from magicgui import magic_factory, widgets -from skimage import data -from skimage.feature import blob_log -from typing_extensions import Annotated - -import napari -from napari.qt.threading import FunctionWorker, thread_worker -from napari.types import ImageData, LayerDataTuple - - -@magic_factory(pbar={'visible': False, 'max': 0, 'label': 'working...'}) -def make_widget( - pbar: widgets.ProgressBar, - image: ImageData, - min_sigma: Annotated[float, {"min": 0.5, "max": 15, "step": 0.5}] = 5, - max_sigma: Annotated[float, {"min": 1, "max": 200, "step": 0.5}] = 30, - num_sigma: Annotated[int, {"min": 1, "max": 20}] = 10, - threshold: Annotated[float, {"min": 0, "max": 1000, "step": 0.1}] = 6, -) -> FunctionWorker[LayerDataTuple]: - - # @thread_worker creates a worker that runs a function in another thread - # we connect the "returned" signal to the ProgressBar.hide method - @thread_worker(connect={'returned': pbar.hide}) - def detect_blobs() -> LayerDataTuple: - # this is the potentially long-running function - blobs = blob_log(image, min_sigma, max_sigma, num_sigma, threshold) - points = blobs[:, : image.ndim] - meta = dict( - size=blobs[:, -1], - edge_color="red", - edge_width=2, - face_color="transparent", - ) - # return a "LayerDataTuple" - return (points, meta, 'points') - - # show progress bar and return worker - pbar.show() - return detect_blobs() - - -viewer = napari.Viewer() -viewer.window.add_dock_widget(make_widget(), area="right") -viewer.add_image(data.hubble_deep_field().mean(-1)) - -napari.run() diff --git a/examples/minimum_blending.py b/examples/minimum_blending.py deleted file mode 100644 index 486bf6873..000000000 --- a/examples/minimum_blending.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Minimum blending -================ - -Demonstrates how to use the `minimum` blending mode with inverted colormaps. -`minimum` blending uses the minimum value of each R, G, B channel for each pixel. -`minimum` blending can be used to yield multichannel color images on a white -background, when the channels have inverted colormaps assigned. -An inverted colormap is one where white [1, 1, 1] is used to represent the lowest -values, as opposed to the more conventional black [0, 0, 0]. For example, try the -colormaps prefixed with *I*, such as *I Forest* or *I Bordeaux*, from -ChrisLUTs: https://github.com/cleterrier/ChrisLUTs . -""" - -from skimage import data -import napari - -# create a viewer -viewer = napari.Viewer() - -# Add the cells3d example image, using the two inverted colormaps -# and minimum blending mode. Note that the bottom-most layer -# must be translucent or opaque to prevent blending with the canvas. -viewer.add_image(data.cells3d(), - name=["membrane", "nuclei"], - channel_axis=1, - contrast_limits = [[1110, 23855], [1600, 50000]], - colormap = ["I Purple", "I Orange"], - blending= ["translucent_no_depth", "minimum"] - ) - -if __name__ == '__main__': - napari.run() diff --git a/examples/mixed-dimensions-labels.py b/examples/mixed-dimensions-labels.py deleted file mode 100644 index 1af5635f7..000000000 --- a/examples/mixed-dimensions-labels.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -Mixed dimensions labels -======================= - -Overlay a 3D segmentation on a 4D time series. - -Sometimes, our data have mixed dimensionality. napari "right-aligns" the -dimensions of your data, following NumPy broadcasting conventions [1]_. In this -example, we show how we can see a 3D segmentation overlaid on a 4D dataset. As -we slice through the dataset, the segmentation stays unchanged, but is visible -on every slice. - -.. [1] https://numpy.org/doc/stable/user/basics.broadcasting.html - -.. tags:: visualization-nD -""" - -from skimage.data import binary_blobs -from scipy import ndimage as ndi -import numpy as np -import napari - -blobs3d = binary_blobs(length=64, volume_fraction=0.1, n_dim=3).astype(float) - -blobs3dt = np.stack([np.roll(blobs3d, 3 * i, axis=2) for i in range(10)]) - -labels = ndi.label(blobs3dt[5])[0] - -viewer = napari.Viewer(ndisplay=3) - -image_layer = viewer.add_image(blobs3dt) -labels_layer = viewer.add_labels(labels) -viewer.dims.current_step = (5, 0, 0, 0) - -if __name__ == '__main__': - napari.run() diff --git a/examples/mouse_drag_callback.py b/examples/mouse_drag_callback.py deleted file mode 100644 index 0ca56b882..000000000 --- a/examples/mouse_drag_callback.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Mouse drag callback -=================== - -Example updating the status bar with line profile info while dragging -lines around in a shapes layer. - -.. tags:: gui -""" - -from skimage import data -from skimage import measure -import numpy as np -import napari - - -def profile_lines(image, shape_layer): - profile_data = [ - measure.profile_line(image, line[0], line[1], mode='reflect').mean() - for line in shape_layer.data - ] - print(f"profile means: [{', '.join(f'{d:.2f}' for d in profile_data)}]") - - -np.random.seed(1) -viewer = napari.Viewer() -blobs = data.binary_blobs(length=512, volume_fraction=0.1, n_dim=2) -viewer.add_image(blobs, name='blobs') -line1 = np.array([[11, 13], [111, 113]]) -line2 = np.array([[200, 200], [400, 300]]) -lines = [line1, line2] -shapes_layer = viewer.add_shapes( - lines, - shape_type='line', - edge_width=5, - edge_color='coral', - face_color='royalblue', -) -shapes_layer.mode = 'select' - - -@shapes_layer.mouse_drag_callbacks.append -def profile_lines_drag(layer, event): - profile_lines(blobs, layer) - yield - while event.type == 'mouse_move': - profile_lines(blobs, layer) - # the yield statement allows the mouse UI to keep working while - # this loop is executed repeatedly - yield - - -if __name__ == '__main__': - napari.run() diff --git a/examples/mpl_plot_.py b/examples/mpl_plot_.py deleted file mode 100644 index 2b6d1b448..000000000 --- a/examples/mpl_plot_.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Matplotlib plot -=============== - -.. tags:: gui -""" - -import matplotlib.pyplot as plt -import numpy as np -from matplotlib.backends.backend_qt5agg import FigureCanvas - -import napari - -# create image -x = np.linspace(0, 5, 256) -y = np.linspace(0, 5, 256)[:, np.newaxis] -img = np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x) - -# add it to the viewer -viewer = napari.view_image(img, colormap='viridis') -layer = viewer.layers[-1] - -# create mpl figure with subplots -mpl_fig = plt.figure() -ax = mpl_fig.add_subplot(111) -(line,) = ax.plot(layer.data[123]) # linescan through the middle of the image - -# add the figure to the viewer as a FigureCanvas widget -viewer.window.add_dock_widget(FigureCanvas(mpl_fig)) - - -# connect a callback that updates the line plot when -# the user clicks on the image -@layer.mouse_drag_callbacks.append -def profile_lines_drag(layer, event): - try: - line.set_ydata(layer.data[int(event.position[0])]) - line.figure.canvas.draw() - except IndexError: - pass - - -if __name__ == '__main__': - napari.run() diff --git a/examples/multiple_viewer_widget.py b/examples/multiple_viewer_widget.py deleted file mode 100644 index 532daf618..000000000 --- a/examples/multiple_viewer_widget.py +++ /dev/null @@ -1,458 +0,0 @@ -""" -Multiple viewer widget -====================== - -This is an example on how to have more than one viewer in the same napari window. -Additional viewers state will be synchronized with the main viewer. -Switching to 3D display will only impact the main viewer. - -This example also contain option to enable cross that will be moved to the -current dims point (`viewer.dims.point`). - -.. tags:: gui -""" - -from copy import deepcopy - -import numpy as np -from qtpy.QtCore import Qt -from qtpy.QtWidgets import ( - QCheckBox, - QDoubleSpinBox, - QPushButton, - QSplitter, - QTabWidget, - QVBoxLayout, - QWidget, -) -from superqt.utils import qthrottled -from packaging.version import parse as parse_version - -import napari -from napari.components.layerlist import Extent -from napari.components.viewer_model import ViewerModel -from napari.layers import Image, Labels, Layer, Vectors -from napari.qt import QtViewer -from napari.utils.action_manager import action_manager -from napari.utils.events.event import WarningEmitter -from napari.utils.notifications import show_info - -NAPARI_GE_4_16 = parse_version(napari.__version__) > parse_version("0.4.16") - - -def copy_layer_le_4_16(layer: Layer, name: str = ""): - res_layer = deepcopy(layer) - # this deepcopy is not optimal for labels and images layers - if isinstance(layer, (Image, Labels)): - res_layer.data = layer.data - - res_layer.metadata["viewer_name"] = name - - res_layer.events.disconnect() - res_layer.events.source = res_layer - for emitter in res_layer.events.emitters.values(): - emitter.disconnect() - emitter.source = res_layer - return res_layer - - -def copy_layer(layer: Layer, name: str = ""): - if NAPARI_GE_4_16: - return copy_layer_le_4_16(layer, name) - - res_layer = Layer.create(*layer.as_layer_data_tuple()) - res_layer.metadata["viewer_name"] = name - return res_layer - - -def get_property_names(layer: Layer): - klass = layer.__class__ - res = [] - for event_name, event_emitter in layer.events.emitters.items(): - if isinstance(event_emitter, WarningEmitter): - continue - if event_name in ("thumbnail", "name"): - continue - if ( - isinstance(getattr(klass, event_name, None), property) - and getattr(klass, event_name).fset is not None - ): - res.append(event_name) - return res - - -def center_cross_on_mouse( - viewer_model: napari.components.viewer_model.ViewerModel, -): - """move the cross to the mouse position""" - - if not getattr(viewer_model, "mouse_over_canvas", True): - # There is no way for napari 0.4.15 to check if mouse is over sending canvas. - show_info( - "Mouse is not over the canvas. You may need to click on the canvas." - ) - return - - viewer_model.dims.current_step = tuple( - np.round( - [ - max(min_, min(p, max_)) / step - for p, (min_, max_, step) in zip( - viewer_model.cursor.position, viewer_model.dims.range - ) - ] - ).astype(int) - ) - - -action_manager.register_action( - name='napari:move_point', - command=center_cross_on_mouse, - description='Move dims point to mouse position', - keymapprovider=ViewerModel, -) - -action_manager.bind_shortcut('napari:move_point', 'C') - - -class own_partial: - """ - Workaround for deepcopy not copying partial functions - (Qt widgets are not serializable) - """ - - def __init__(self, func, *args, **kwargs): - self.func = func - self.args = args - self.kwargs = kwargs - - def __call__(self, *args, **kwargs): - return self.func(*(self.args + args), **{**self.kwargs, **kwargs}) - - def __deepcopy__(self, memodict={}): - return own_partial( - self.func, - *deepcopy(self.args, memodict), - **deepcopy(self.kwargs, memodict), - ) - - -class QtViewerWrap(QtViewer): - def __init__(self, main_viewer, *args, **kwargs): - super().__init__(*args, **kwargs) - self.main_viewer = main_viewer - - def _qt_open( - self, - filenames: list, - stack: bool, - plugin: str = None, - layer_type: str = None, - **kwargs, - ): - """for drag and drop open files""" - self.main_viewer.window._qt_viewer._qt_open( - filenames, stack, plugin, layer_type, **kwargs - ) - - -class CrossWidget(QCheckBox): - """ - Widget to control the cross layer. because of the performance reason - the cross update is throttled - """ - - def __init__(self, viewer: napari.Viewer): - super().__init__("Add cross layer") - self.viewer = viewer - self.setChecked(False) - self.stateChanged.connect(self._update_cross_visibility) - self.layer = None - self.viewer.dims.events.order.connect(self.update_cross) - self.viewer.dims.events.ndim.connect(self._update_ndim) - self.viewer.dims.events.current_step.connect(self.update_cross) - self._extent = None - - self._update_extent() - self.viewer.dims.events.connect(self._update_extent) - - @qthrottled(leading=False) - def _update_extent(self): - """ - Calculate the extent of the data. - - Ignores the the cross layer itself in calculating the extent. - """ - if NAPARI_GE_4_16: - layers = [ - layer - for layer in self.viewer.layers - if layer is not self.layer - ] - self._extent = self.viewer.layers.get_extent(layers) - else: - extent_list = [ - layer.extent - for layer in self.viewer.layers - if layer is not self.layer - ] - self._extent = Extent( - data=None, - world=self.viewer.layers._get_extent_world(extent_list), - step=self.viewer.layers._get_step_size(extent_list), - ) - self.update_cross() - - def _update_ndim(self, event): - if self.layer in self.viewer.layers: - self.viewer.layers.remove(self.layer) - self.layer = Vectors(name=".cross", ndim=event.value) - self.layer.edge_width = 1.5 - self.update_cross() - - def _update_cross_visibility(self, state): - if state: - self.viewer.layers.append(self.layer) - else: - self.viewer.layers.remove(self.layer) - self.update_cross() - - def update_cross(self): - if self.layer not in self.viewer.layers: - return - - point = self.viewer.dims.current_step - vec = [] - for i, (lower, upper) in enumerate(self._extent.world.T): - if (upper - lower) / self._extent.step[i] == 1: - continue - point1 = list(point) - point1[i] = (lower + self._extent.step[i] / 2) / self._extent.step[ - i - ] - point2 = [0 for _ in point] - point2[i] = (upper - lower) / self._extent.step[i] - vec.append((point1, point2)) - if np.any(self.layer.scale != self._extent.step): - self.layer.scale = self._extent.step - self.layer.data = vec - - -class ExampleWidget(QWidget): - """ - Dummy widget showcasing how to place additional widgets to the right - of the additional viewers. - """ - - def __init__(self): - super().__init__() - self.btn = QPushButton("Perform action") - self.spin = QDoubleSpinBox() - layout = QVBoxLayout() - layout.addWidget(self.spin) - layout.addWidget(self.btn) - layout.addStretch(1) - self.setLayout(layout) - - -class MultipleViewerWidget(QSplitter): - """The main widget of the example.""" - - def __init__(self, viewer: napari.Viewer): - super().__init__() - self.viewer = viewer - self.viewer_model1 = ViewerModel(title="model1") - self.viewer_model2 = ViewerModel(title="model2") - self._block = False - self.qt_viewer1 = QtViewerWrap(viewer, self.viewer_model1) - self.qt_viewer2 = QtViewerWrap(viewer, self.viewer_model2) - self.tab_widget = QTabWidget() - w1 = ExampleWidget() - w2 = ExampleWidget() - self.tab_widget.addTab(w1, "Sample 1") - self.tab_widget.addTab(w2, "Sample 2") - viewer_splitter = QSplitter() - viewer_splitter.setOrientation(Qt.Vertical) - viewer_splitter.addWidget(self.qt_viewer1) - viewer_splitter.addWidget(self.qt_viewer2) - viewer_splitter.setContentsMargins(0, 0, 0, 0) - - self.addWidget(viewer_splitter) - self.addWidget(self.tab_widget) - - self.viewer.layers.events.inserted.connect(self._layer_added) - self.viewer.layers.events.removed.connect(self._layer_removed) - self.viewer.layers.events.moved.connect(self._layer_moved) - self.viewer.layers.selection.events.active.connect( - self._layer_selection_changed - ) - self.viewer.dims.events.current_step.connect(self._point_update) - self.viewer_model1.dims.events.current_step.connect(self._point_update) - self.viewer_model2.dims.events.current_step.connect(self._point_update) - self.viewer.dims.events.order.connect(self._order_update) - self.viewer.events.reset_view.connect(self._reset_view) - self.viewer_model1.events.status.connect(self._status_update) - self.viewer_model2.events.status.connect(self._status_update) - - def _status_update(self, event): - self.viewer.status = event.value - - def _reset_view(self): - self.viewer_model1.reset_view() - self.viewer_model2.reset_view() - - def _layer_selection_changed(self, event): - """ - update of current active layer - """ - if self._block: - return - - if event.value is None: - self.viewer_model1.layers.selection.active = None - self.viewer_model2.layers.selection.active = None - return - - self.viewer_model1.layers.selection.active = self.viewer_model1.layers[ - event.value.name - ] - self.viewer_model2.layers.selection.active = self.viewer_model2.layers[ - event.value.name - ] - - def _point_update(self, event): - for model in [self.viewer, self.viewer_model1, self.viewer_model2]: - if model.dims is event.source: - continue - model.dims.current_step = event.value - - def _order_update(self): - order = list(self.viewer.dims.order) - if len(order) <= 2: - self.viewer_model1.dims.order = order - self.viewer_model2.dims.order = order - return - - order[-3:] = order[-2], order[-3], order[-1] - self.viewer_model1.dims.order = order - order = list(self.viewer.dims.order) - order[-3:] = order[-1], order[-2], order[-3] - self.viewer_model2.dims.order = order - - def _layer_added(self, event): - """add layer to additional viewers and connect all required events""" - self.viewer_model1.layers.insert( - event.index, copy_layer(event.value, "model1") - ) - self.viewer_model2.layers.insert( - event.index, copy_layer(event.value, "model2") - ) - for name in get_property_names(event.value): - getattr(event.value.events, name).connect( - own_partial(self._property_sync, name) - ) - - if isinstance(event.value, Labels): - event.value.events.set_data.connect(self._set_data_refresh) - self.viewer_model1.layers[ - event.value.name - ].events.set_data.connect(self._set_data_refresh) - self.viewer_model2.layers[ - event.value.name - ].events.set_data.connect(self._set_data_refresh) - if event.value.name != ".cross": - self.viewer_model1.layers[event.value.name].events.data.connect( - self._sync_data - ) - self.viewer_model2.layers[event.value.name].events.data.connect( - self._sync_data - ) - - event.value.events.name.connect(self._sync_name) - - self._order_update() - - def _sync_name(self, event): - """sync name of layers""" - index = self.viewer.layers.index(event.source) - self.viewer_model1.layers[index].name = event.source.name - self.viewer_model2.layers[index].name = event.source.name - - def _sync_data(self, event): - """sync data modification from additional viewers""" - if self._block: - return - for model in [self.viewer, self.viewer_model1, self.viewer_model2]: - layer = model.layers[event.source.name] - if layer is event.source: - continue - try: - self._block = True - layer.data = event.source.data - finally: - self._block = False - - def _set_data_refresh(self, event): - """ - synchronize data refresh between layers - """ - if self._block: - return - for model in [self.viewer, self.viewer_model1, self.viewer_model2]: - layer = model.layers[event.source.name] - if layer is event.source: - continue - try: - self._block = True - layer.refresh() - finally: - self._block = False - - def _layer_removed(self, event): - """remove layer in all viewers""" - self.viewer_model1.layers.pop(event.index) - self.viewer_model2.layers.pop(event.index) - - def _layer_moved(self, event): - """update order of layers""" - dest_index = ( - event.new_index - if event.new_index < event.index - else event.new_index + 1 - ) - self.viewer_model1.layers.move(event.index, dest_index) - self.viewer_model2.layers.move(event.index, dest_index) - - def _property_sync(self, name, event): - """Sync layers properties (except the name)""" - if event.source not in self.viewer.layers: - return - try: - self._block = True - setattr( - self.viewer_model1.layers[event.source.name], - name, - getattr(event.source, name), - ) - setattr( - self.viewer_model2.layers[event.source.name], - name, - getattr(event.source, name), - ) - finally: - self._block = False - - -if __name__ == "__main__": - from qtpy import QtWidgets, QtCore - QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts) - # above two lines are needed to allow to undock the widget with - # additional viewers - view = napari.Viewer() - dock_widget = MultipleViewerWidget(view) - cross = CrossWidget(view) - - view.window.add_dock_widget(dock_widget, name="Sample") - view.window.add_dock_widget(cross, name="Cross", area="left") - - napari.run() diff --git a/examples/multiple_viewers.py b/examples/multiple_viewers.py deleted file mode 100644 index d999500d8..000000000 --- a/examples/multiple_viewers.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -Multiple viewers -================ - -Create multiple viewers from the same script - -.. tags:: gui -""" - -from skimage import data -import napari - - -# add the image -photographer = data.camera() -viewer_a = napari.view_image(photographer, name='photographer') - -# add the image in a new viewer window -astronaut = data.astronaut() -# Also view_path, view_shapes, view_points, view_labels etc. -viewer_b = napari.view_image(astronaut, name='astronaut') - -if __name__ == '__main__': - napari.run() diff --git a/examples/multithreading_simple_.py b/examples/multithreading_simple_.py deleted file mode 100644 index 37c0338bd..000000000 --- a/examples/multithreading_simple_.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Multithreading simple -===================== - -.. tags:: interactivity -""" - -from qtpy.QtWidgets import QApplication, QWidget, QHBoxLayout, QLabel -import time -from napari.qt import thread_worker - - -@thread_worker -def long_running_function(): - """Just a long running function, most like viewer.update.""" - time.sleep(2) # long function - return 'finished!' - - -def create_widget(): - widget = QWidget() - layout = QHBoxLayout() - widget.setLayout(layout) - widget.status = QLabel('ready...') - layout.addWidget(widget.status) - widget.show() - return widget - - -if __name__ == "__main__": - app = QApplication([]) - wdg = create_widget() - - # call decorated function - # By default, @thread_worker-decorated functions do not immediately start - worker = long_running_function() - # Signals are best connected *before* starting the worker. - worker.started.connect(lambda: wdg.status.setText("worker is running...")) - worker.returned.connect(lambda x: wdg.status.setText(f"returned {x}")) - - # # Connections may also be passed directly to the decorated function. - # # The above syntax is equivalent to: - # worker = long_running_function( - # _connect={ - # 'started': lambda: wdg.status.setText("worker is running..."), - # 'returned': lambda x: wdg.status.setText(f"returned {x!r}"), - # } - # ) - - worker.start() - - app.exec_() diff --git a/examples/multithreading_two_way_.py b/examples/multithreading_two_way_.py deleted file mode 100644 index bb2863f49..000000000 --- a/examples/multithreading_two_way_.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Multithreading two-way -====================== - -.. tags:: interactivity -""" -import time - -from qtpy.QtWidgets import ( - QGridLayout, - QLabel, - QProgressBar, - QPushButton, - QWidget, -) - -import napari -import numpy as np -from napari.qt.threading import thread_worker - - -@thread_worker -def two_way_communication_with_args(start, end): - """Both sends and receives values to & from the main thread. - - Accepts arguments, puts them on the worker object. - Receives values from main thread with ``incoming = yield`` - Optionally returns a value at the end - """ - - # do computationally intensive work here - i = start - while i < end: - i += 1 - time.sleep(0.1) - # incoming receives values from the main thread - # while yielding sends values back to the main thread - incoming = yield i - i = incoming if incoming is not None else i - - # do optional teardown here - return "done" - - -class Controller(QWidget): - def __init__(self): - super().__init__() - - layout = QGridLayout() - self.setLayout(layout) - self.status = QLabel('Click "Start"', self) - self.play_btn = QPushButton("Start", self) - self.abort_btn = QPushButton("Abort!", self) - self.reset_btn = QPushButton("Reset", self) - self.progress_bar = QProgressBar() - - layout.addWidget(self.play_btn, 0, 0) - layout.addWidget(self.reset_btn, 0, 1) - layout.addWidget(self.abort_btn, 0, 2) - layout.addWidget(self.status, 0, 3) - layout.setColumnStretch(3, 1) - layout.addWidget(self.progress_bar, 1, 0, 1, 4) - - -def create_connected_widget(): - """Builds a widget that can control a function in another thread.""" - w = Controller() - steps = 40 - - # the decorated function now returns a GeneratorWorker object, and the - # Qthread in which it's running. - # (optionally pass start=False to prevent immediate running) - worker = two_way_communication_with_args(0, steps) - - w.play_btn.clicked.connect(worker.start) - - # it provides signals like {started, yielded, returned, errored, finished} - worker.returned.connect(lambda x: w.status.setText(f"worker returned {x}")) - worker.errored.connect(lambda x: w.status.setText(f"worker errored {x}")) - worker.started.connect(lambda: w.status.setText("worker started...")) - worker.aborted.connect(lambda: w.status.setText("worker aborted")) - - # send values into the function (like generator.send) using worker.send - # abort thread with worker.abort() - w.abort_btn.clicked.connect(lambda: worker.quit()) - - def on_reset_button_pressed(): - # we want to avoid sending into a unstarted worker - if worker.is_running: - worker.send(0) - - def on_yield(x): - # Receive events and update widget progress - w.progress_bar.setValue(100 * x // steps) - w.status.setText(f"worker yielded {x}") - - def on_start(): - def handle_pause(): - worker.toggle_pause() - w.play_btn.setText("Pause" if worker.is_paused else "Continue") - - w.play_btn.clicked.disconnect(worker.start) - w.play_btn.setText("Pause") - w.play_btn.clicked.connect(handle_pause) - - def on_finish(): - w.play_btn.setDisabled(True) - w.reset_btn.setDisabled(True) - w.abort_btn.setDisabled(True) - w.play_btn.setText("Done") - - w.reset_btn.clicked.connect(on_reset_button_pressed) - worker.yielded.connect(on_yield) - worker.started.connect(on_start) - worker.finished.connect(on_finish) - return w - - -if __name__ == "__main__": - - viewer = napari.view_image(np.random.rand(512, 512)) - w = create_connected_widget() - viewer.window.add_dock_widget(w) - - napari.run() diff --git a/examples/nD_image.py b/examples/nD_image.py deleted file mode 100644 index e0db1f459..000000000 --- a/examples/nD_image.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -nD image -======== - -Display one 4-D image layer using the :func:`view_image` API. - -.. tags:: visualization-nD -""" - -import numpy as np -from skimage import data -import napari - - -blobs = np.stack( - [ - data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=3, volume_fraction=f - ) - for f in np.linspace(0.05, 0.5, 10) - ], - axis=0, -) -viewer = napari.view_image(blobs.astype(float)) - -if __name__ == '__main__': - napari.run() diff --git a/examples/nD_labels.py b/examples/nD_labels.py deleted file mode 100644 index ce6c596d9..000000000 --- a/examples/nD_labels.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -nD labels -========= - -Display a labels layer above of an image layer using the ``add_labels`` and -``add_image`` APIs - -.. tags:: visualization-nD -""" - -from skimage import data -from scipy import ndimage as ndi -import napari - - -blobs = data.binary_blobs(length=128, volume_fraction=0.1, n_dim=3) -viewer = napari.view_image(blobs[::2].astype(float), name='blobs', scale=(2, 1, 1)) -labeled = ndi.label(blobs)[0] -viewer.add_labels(labeled[::2], name='blob ID', scale=(2, 1, 1)) - -if __name__ == '__main__': - napari.run() diff --git a/examples/nD_multiscale_image.py b/examples/nD_multiscale_image.py deleted file mode 100644 index 0cddd7f88..000000000 --- a/examples/nD_multiscale_image.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -nD multiscale image -=================== - -Displays an nD multiscale image - -.. tags:: visualization-advanced -""" - -from skimage.transform import pyramid_gaussian -import napari -import numpy as np - - -# create multiscale from random data -base = np.random.random((1536, 1536)) -base = np.array([base * (8 - i) / 8 for i in range(8)]) -print('base shape', base.shape) -multiscale = list( - pyramid_gaussian(base, downscale=2, max_layer=2, multichannel=False) -) -print('multiscale level shapes: ', [p.shape for p in multiscale]) - -# add image multiscale -viewer = napari.view_image(multiscale, contrast_limits=[0, 1], multiscale=True) - -if __name__ == '__main__': - napari.run() diff --git a/examples/nD_multiscale_image_non_uniform.py b/examples/nD_multiscale_image_non_uniform.py deleted file mode 100644 index 2b1bc434e..000000000 --- a/examples/nD_multiscale_image_non_uniform.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -nD multiscale image non-uniform -=============================== - -Displays an nD multiscale image - -.. tags:: visualization-advanced -""" - -from skimage import data -from skimage.transform import pyramid_gaussian -import napari -import numpy as np - - -# create multiscale from astronaut image -astronaut = data.astronaut() -base = np.tile(astronaut, (3, 3, 1)) -multiscale = list( - pyramid_gaussian(base, downscale=2, max_layer=3, multichannel=True) -) -multiscale = [ - np.array([p * (abs(3 - i) + 1) / 4 for i in range(6)]) for p in multiscale -] -print('multiscale level shapes: ', [p.shape for p in multiscale]) - -# add image multiscale -viewer = napari.view_image(multiscale, multiscale=True) - -if __name__ == '__main__': - napari.run() diff --git a/examples/nD_points.py b/examples/nD_points.py deleted file mode 100644 index b42f8f028..000000000 --- a/examples/nD_points.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -nD points -========= - -Display one points layer on top of one 4-D image layer using the -add_points and add_image APIs, where the markes are visible as nD objects -across the dimensions, specified by their size - -.. tags:: visualization-nD -""" - -import numpy as np -from skimage import data -import napari - - -blobs = np.stack( - [ - data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=3, volume_fraction=f - ) - for f in np.linspace(0.05, 0.5, 10) - ], - axis=0, -) -viewer = napari.view_image(blobs.astype(float)) - -# add the points -points = np.array( - [ - [0, 0, 100, 100], - [0, 0, 50, 120], - [1, 0, 100, 40], - [2, 10, 110, 100], - [9, 8, 80, 100], - ], dtype=float -) -viewer.add_points( - points, size=[0, 6, 10, 10], face_color='blue', out_of_slice_display=True -) - -if __name__ == '__main__': - napari.run() diff --git a/examples/nD_points_with_features.py b/examples/nD_points_with_features.py deleted file mode 100644 index c90bd0d18..000000000 --- a/examples/nD_points_with_features.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -nD points with features -======================= - -Display one points layer ontop of one 4-D image layer using the -add_points and add_image APIs, where the markes are visible as nD objects -across the dimensions, specified by their size - -.. tags:: visualization-nD -""" - -import numpy as np -from skimage import data -import napari - - -blobs = data.binary_blobs( - length=100, blob_size_fraction=0.05, n_dim=3, volume_fraction=0.05 -) -viewer = napari.view_image(blobs.astype(float)) - -# create the points -points = [] -for z in range(blobs.shape[0]): - points += [[z, 25, 25], [z, 25, 75], [z, 75, 25], [z, 75, 75]] - -# create the features for setting the face and edge color. -face_feature = np.array( - [True, True, True, True, False, False, False, False] - * int(blobs.shape[0] / 2) -) -edge_feature = np.array(['A', 'B', 'C', 'D', 'E'] * int(len(points) / 5)) - -features = { - 'face_feature': face_feature, - 'edge_feature': edge_feature, -} - -points_layer = viewer.add_points( - points, - features=features, - size=3, - edge_width=5, - edge_width_is_relative=False, - edge_color='edge_feature', - face_color='face_feature', - out_of_slice_display=False, -) - -# change the face color cycle -points_layer.face_color_cycle = ['white', 'black'] - -# change the edge_color cycle. -# there are 4 colors for 5 categories, so 'c' will be recycled -points_layer.edge_color_cycle = ['c', 'm', 'y', 'k'] - -if __name__ == '__main__': - napari.run() diff --git a/examples/nD_shapes.py b/examples/nD_shapes.py deleted file mode 100644 index 5fcaad543..000000000 --- a/examples/nD_shapes.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -nD shapes -========= - -Display one 4-D image layer using the ``add_image`` API - -.. tags:: visualization-nD -""" - -import numpy as np -from skimage import data -import napari - - -blobs = data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=3, volume_fraction=0.1 -).astype(float) - -viewer = napari.view_image(blobs.astype(float)) - -# create one random polygon per "plane" -planes = np.tile(np.arange(128).reshape((128, 1, 1)), (1, 5, 1)) -np.random.seed(0) -corners = np.random.uniform(0, 128, size=(128, 5, 2)) -shapes = np.concatenate((planes, corners), axis=2) - -base_cols = ['red', 'green', 'blue', 'white', 'yellow', 'magenta', 'cyan'] -colors = np.random.choice(base_cols, size=128) - -layer = viewer.add_shapes( - np.array(shapes), - shape_type='polygon', - face_color=colors, - name='sliced', -) - -masks = layer.to_masks(mask_shape=(128, 128, 128)) -labels = layer.to_labels(labels_shape=(128, 128, 128)) -shape_array = np.array(layer.data) - -print( - f'sliced: nshapes {layer.nshapes}, mask shape {masks.shape}, ' - f'labels_shape {labels.shape}, array_shape, {shape_array.shape}' -) - -corners = np.random.uniform(0, 128, size=(2, 2)) -layer = viewer.add_shapes(corners, shape_type='rectangle', name='broadcasted') - -masks = layer.to_masks(mask_shape=(128, 128)) -labels = layer.to_labels(labels_shape=(128, 128)) -shape_array = np.array(layer.data) - -print( - f'broadcast: nshapes {layer.nshapes}, mask shape {masks.shape}, ' - f'labels_shape {labels.shape}, array_shape, {shape_array.shape}' -) - -if __name__ == '__main__': - napari.run() diff --git a/examples/nD_shapes_with_text.py b/examples/nD_shapes_with_text.py deleted file mode 100644 index 7352c82d2..000000000 --- a/examples/nD_shapes_with_text.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -nD shapes with text -=================== - -.. tags:: visualization-nD -""" -from skimage import data -import napari - - -blobs = data.binary_blobs( - length=100, blob_size_fraction=0.05, n_dim=3, volume_fraction=0.03 -).astype(float) - -viewer = napari.view_image(blobs.astype(float), ndisplay=3) - -n = 50 -shape = [[[n, 40, 40], [n, 40, 60], [n + 20, 60, 60], [n + 20, 60, 40]]] - -features = {'z_index': [n]} -text = {'string': 'z_index', 'color': 'green', 'anchor': 'upper_left'} - -shapes_layer = viewer.add_shapes( - shape, - edge_color=[0, 1, 0, 1], - face_color='transparent', - features=features, - text=text, -) - -if __name__ == '__main__': - napari.run() diff --git a/examples/nD_surface.py b/examples/nD_surface.py deleted file mode 100644 index 348d7ab9d..000000000 --- a/examples/nD_surface.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -nD surface -========== - -Display a 3D surface - -.. tags:: visualization-nD -""" - -import numpy as np -import napari - - -# create the viewer and window -viewer = napari.Viewer(ndisplay=3) - -data = np.array([[0, 0, 0], [0, 20, 10], [10, 0, -10], [10, 10, -10]]) -faces = np.array([[0, 1, 2], [1, 2, 3]]) -values = np.linspace(0, 1, len(data)) - -# add the surface -layer = viewer.add_surface((data, faces, values)) - -if __name__ == '__main__': - napari.run() diff --git a/examples/nD_vectors.py b/examples/nD_vectors.py deleted file mode 100644 index b4d947039..000000000 --- a/examples/nD_vectors.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -nD vectors -========== - -Display two vectors layers ontop of a 4-D image layer. One of the vectors -layers is 3D and "sliced" with a different set of vectors appearing on -different 3D slices. Another is 2D and "broadcast" with the same vectors -apprearing on each slice. - -.. tags:: visualization-nD -""" - -import numpy as np -from skimage import data -import napari - - -blobs = np.stack( - [ - data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=3, volume_fraction=f - ) - for f in np.linspace(0.05, 0.5, 10) - ], - axis=0, -) -viewer = napari.view_image(blobs.astype(float)) - -# sample vector coord-like data -n = 200 -pos = np.zeros((n, 2, 2), dtype=np.float32) -phi_space = np.linspace(0, 4 * np.pi, n) -radius_space = np.linspace(0, 20, n) - -# assign x-y position -pos[:, 0, 0] = radius_space * np.cos(phi_space) + 64 -pos[:, 0, 1] = radius_space * np.sin(phi_space) + 64 - -# assign x-y projection -pos[:, 1, 0] = 2 * radius_space * np.cos(phi_space) -pos[:, 1, 1] = 2 * radius_space * np.sin(phi_space) - -planes = np.round(np.linspace(0, 128, n)).astype(int) -planes = np.concatenate( - (planes.reshape((n, 1, 1)), np.zeros((n, 1, 1))), axis=1 -) -vectors = np.concatenate((planes, pos), axis=2) - -# add the sliced vectors -layer = viewer.add_vectors( - vectors, edge_width=0.4, name='sliced vectors', edge_color='blue' -) - -viewer.dims.ndisplay = 3 - -if __name__ == '__main__': - napari.run() diff --git a/examples/nD_vectors_image.py b/examples/nD_vectors_image.py deleted file mode 100644 index 137feadba..000000000 --- a/examples/nD_vectors_image.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -nD vectors image -================ - -This example generates an image of vectors -Vector data is an array of shape (M, N, P, 3) -Each vector position is defined by an (x-proj, y-proj, z-proj) element -which are vector projections centered on a pixel of the MxNxP grid - -.. tags:: visualization-nD -""" - -import napari -import numpy as np - - -# create the viewer and window -viewer = napari.Viewer() - -m = 10 -n = 20 -p = 40 - -image = 0.2 * np.random.random((m, n, p)) + 0.5 -layer = viewer.add_image(image, contrast_limits=[0, 1], name='background') - -# sample vector image-like data -# n x m grid of slanted lines -# random data on the open interval (-1, 1) -pos = np.random.uniform(-1, 1, size=(m, n, p, 3)) -print(image.shape, pos.shape) - -# add the vectors -vect = viewer.add_vectors(pos, edge_width=0.2, length=2.5) - -if __name__ == '__main__': - napari.run() diff --git a/examples/new_theme.py b/examples/new_theme.py deleted file mode 100644 index c48c65e8b..000000000 --- a/examples/new_theme.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -New theme -========= - -Displays an image and sets the theme to new custom theme. - -.. tags:: experimental -""" - -from skimage import data -import napari -from napari.utils.theme import available_themes, get_theme, register_theme - - -# create the viewer with an image -viewer = napari.view_image(data.astronaut(), rgb=True, name='astronaut') - -# List themes -print('Originally themes', available_themes()) - -blue_theme = get_theme('dark', False) -blue_theme.name = "blue" -blue_theme.icon = ( - 'rgb(0, 255, 255)' # you can provide colors as rgb(XXX, YYY, ZZZ) -) -blue_theme.background = 28, 31, 48 # or as tuples -blue_theme.foreground = [45, 52, 71] # or as list -blue_theme.primary = '#50586c' # or as hexes -blue_theme.current = 'orange' # or as color name - -register_theme('blue', blue_theme) - -# List themes -print('New themes', available_themes()) - -# Set theme -viewer.theme = 'blue' - -if __name__ == '__main__': - napari.run() diff --git a/examples/notebook.ipynb b/examples/notebook.ipynb deleted file mode 100644 index 853793eff..000000000 --- a/examples/notebook.ipynb +++ /dev/null @@ -1,72 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Display an image using Napari" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Initial setup" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from skimage import data\n", - "import napari" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Display an image" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "viewer = napari.view_image(data.moon())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/examples/paint-nd.py b/examples/paint-nd.py deleted file mode 100644 index 597907eff..000000000 --- a/examples/paint-nd.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Paint nD -======== - -Display a 4D labels layer and paint only in 3D. - -This is useful e.g. when proofreading segmentations within a time series. - -.. tags:: analysis -""" - -import numpy as np -from skimage import data -import napari - - -blobs = np.stack( - [ - data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=3, volume_fraction=f - ) - for f in np.linspace(0.05, 0.5, 10) - ], - axis=0, -) -viewer = napari.view_image(blobs.astype(float), rendering='attenuated_mip') -labels = viewer.add_labels(np.zeros_like(blobs, dtype=np.int32)) -labels.n_edit_dimensions = 3 -labels.brush_size = 15 -labels.mode = 'paint' -labels.n_dimensional = True - -if __name__ == '__main__': - napari.run() diff --git a/examples/pass_colormaps.py b/examples/pass_colormaps.py deleted file mode 100644 index f389ccf1c..000000000 --- a/examples/pass_colormaps.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Pass colormaps -============== - -Add named or unnamed vispy colormaps to existing layers. - -.. tags:: visualization-basic -""" - -import numpy as np -from skimage import data -import napari - - -histo = data.astronaut() / 255 -rch, gch, bch = np.transpose(histo, (2, 0, 1)) - -v = napari.Viewer() - -rlayer = v.add_image( - rch, name='red channel', colormap='red', blending='additive' -) -glayer = v.add_image( - gch, name='green channel', colormap='green', blending='additive' -) -blayer = v.add_image( - bch, name='blue channel', colormap='blue', blending='additive' -) - -if __name__ == '__main__': - napari.run() diff --git a/examples/points-over-time.py b/examples/points-over-time.py deleted file mode 100644 index b3b0e81f4..000000000 --- a/examples/points-over-time.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Points over time -================ - -.. tags:: visualization-advanced -""" -import napari -import numpy as np -import dask.array as da -from skimage import data - - -image4d = da.random.random( - (4000, 32, 256, 256), - chunks=(1, 32, 256, 256), - ) -pts_coordinates = np.random.random((50000, 3)) * image4d.shape[1:] -pts_values = da.random.random((50000, 4000), chunks=(50000, 1)) - -viewer = napari.Viewer(ndisplay=3) -image_layer = viewer.add_image( - image4d, opacity=0.5 - ) -pts_layer = viewer.add_points( - pts_coordinates, - features={'value': np.asarray(pts_values[:, 0])}, - face_color='value', - size=2, - ) - - -def set_pts_features(pts_layer, values_table, step): - # step is a 4D coordinate with the current slider position for each dim - column = step[0] # grab the leading ("time") coordinate - pts_layer.features['value'] = np.asarray(values_table[:, column]) - pts_layer.face_color = 'value' # force features refresh - - -viewer.dims.events.current_step.connect( - lambda event: set_pts_features(pts_layer, pts_values, event.value) - ) - - -if __name__ == '__main__': - napari.run() diff --git a/examples/progress_bar_minimal_.py b/examples/progress_bar_minimal_.py deleted file mode 100644 index 86c9346a9..000000000 --- a/examples/progress_bar_minimal_.py +++ /dev/null @@ -1,111 +0,0 @@ -""" -Progress bar minimal -==================== - -This file provides minimal working examples of progress bars in -the napari viewer. - -.. tags:: gui -""" - -import napari -from time import sleep -from napari.utils import progress -from qtpy.QtWidgets import QPushButton, QVBoxLayout, QWidget -import numpy as np -from random import choice - -def process(im_slice): - # do something with your image slice - sleep(0.4) - -def iterable(): - """using progress as a wrapper for iterables - """ - my_stacked_volume = np.random.random((5, 4, 500, 500)) - # we can wrap any iterable object in `progress` and see a progress - # bar in the viewer - for im_slice in progress(my_stacked_volume): - process(im_slice) - -def iterable_w_context(): - """using progress with a context manager - """ - my_stacked_volume = np.random.random((5, 4, 500, 500)) - # progress provides a context manager we can use for automatic - # teardown of our widget once iteration is complete. Wherever - # possible, we should *always* use progress within a context - with progress(my_stacked_volume) as pbr: - for i, im_slice in enumerate(pbr): - # using a context manager also allows us to manipulate - # the progress object e.g. by setting a description - pbr.set_description(f"Slice {i}") - - # we can group progress bars together in the viewer - # by passing a parent progress bar to new progress - # objects' nest_under attribute - for channel in progress(im_slice, nest_under=pbr): - process(channel) - -def indeterminate(): - """By passing a total of 0, we can have an indeterminate progress bar - """ - - # note progress(total=0) is equivalent to progress() - with progress(total=0) as pbr: - x = 0 - while x != 42: - pbr.set_description(f"Processing {x}") - x = choice(range(100)) - sleep(0.05) - -def arbitrary_steps(): - """We can manually control updating the value of the progress bar. - """ - with progress(total=4) as pbr: - sleep(3) - pbr.set_description("Step 1 Complete") - # manually updating the progress bar by 1 - pbr.update(1) - - sleep(1) - pbr.set_description("Step 2 Complete") - pbr.update(1) - - sleep(2) - pbr.set_description("Processing Complete!") - # we can manually update by any number of steps - pbr.update(2) - - # sleeping so we can see full completion - sleep(1) - -viewer = napari.Viewer() -button_layout = QVBoxLayout() - -iterable_btn = QPushButton("Iterable") -iterable_btn.clicked.connect(iterable) -button_layout.addWidget(iterable_btn) - -iterable_context_btn = QPushButton("Iterable With Context") -iterable_context_btn.clicked.connect(iterable_w_context) -button_layout.addWidget(iterable_context_btn) - -indeterminate_btn = QPushButton("Indeterminate") -indeterminate_btn.clicked.connect(indeterminate) -button_layout.addWidget(indeterminate_btn) - -steps_btn = QPushButton("Arbitrary Steps") -steps_btn.clicked.connect(arbitrary_steps) -button_layout.addWidget(steps_btn) - -pbar_widget = QWidget() -pbar_widget.setLayout(button_layout) -pbar_widget.setObjectName("Progress Examples") - -viewer.window.add_dock_widget(pbar_widget) -# showing the activity dock so we can see the progress bars -viewer.window._status_bar._toggle_activity_dock(True) - -if __name__ == '__main__': - napari.run() diff --git a/examples/progress_bar_segmentation_.py b/examples/progress_bar_segmentation_.py deleted file mode 100644 index d93087568..000000000 --- a/examples/progress_bar_segmentation_.py +++ /dev/null @@ -1,166 +0,0 @@ -""" -Progress bar segmentation -========================= - -Use napari's tqdm wrapper to display the progress of long-running operations -in the viewer. - -.. tags:: gui -""" -import numpy as np -import napari - -from time import sleep -from napari.utils import progress -from qtpy.QtWidgets import QPushButton, QVBoxLayout, QWidget - -from skimage.filters import ( - threshold_isodata, - threshold_li, - threshold_otsu, - threshold_triangle, - threshold_yen, -) -from skimage.measure import label - -# we will try each of these thresholds on our image -all_thresholds = [ - threshold_isodata, - threshold_li, - threshold_otsu, - threshold_triangle, - threshold_yen, -] - -viewer = napari.Viewer() - -# load cells data and take just nuclei -membrane, cell_nuclei = viewer.open_sample('napari', 'cells3d') -cell_nuclei = cell_nuclei.data - - -def try_thresholds(): - """Tries each threshold, and adds result to viewer.""" - if 'Binarised' in viewer.layers: - del viewer.layers['Binarised'] - - thresholded_nuclei = [] - - # we wrap our iterable with `progress` - # this will automatically add a progress bar to our activity dock - for threshold_func in progress(all_thresholds): - current_threshold = threshold_func(cell_nuclei) - binarised_im = cell_nuclei > current_threshold - thresholded_nuclei.append(binarised_im) - - # uncomment if processing is too fast - # sleep(0.5) - - # working with a wrapped iterable, the progress bar will be closed - # as soon as the iteration is complete - - binarised_nuclei = np.stack(thresholded_nuclei) - viewer.add_labels( - binarised_nuclei, - color={1: 'lightgreen'}, - opacity=0.7, - name="Binarised", - blending='translucent', - ) - - -# In the previous example, we were able to see the progress bar, but were not -# able to control it. By using `progress` within a context manager, we can -# manipulate the `progress` object and still get the benefit of automatic -# clean up -def segment_binarised_ims(): - """Segments each of the binarised ims. - - Uses `progress` within a context manager allowing us to manipulate - the progress bar within the loop - """ - if 'Binarised' not in viewer.layers: - raise TypeError("Cannot segment before thresholding") - if 'Segmented' in viewer.layers: - del viewer.layers['Segmented'] - binarised_data = viewer.layers['Binarised'].data - segmented_nuclei = [] - - # using the `with` keyword we can use `progress` inside a context manager - # `progress` inherits from tqdm and therefore provides the same API - # e.g. we can provide the miniters argument if we want to see the - # progress bar update with each iteration - with progress(binarised_data, miniters=0) as pbar: - for i, binarised_cells in enumerate(pbar): - # this allows us to manipulate the pbar object within the loop - # e.g. setting the description. - pbar.set_description(all_thresholds[i].__name__.split("_")[1]) - labelled_im = label(binarised_cells) - segmented_nuclei.append(labelled_im) - - # uncomment if processing is too fast - # sleep(0.5) - - # progress bar is still automatically closed - - segmented_nuclei = np.stack(segmented_nuclei) - viewer.add_labels( - segmented_nuclei, - name="Segmented", - blending='translucent', - ) - viewer.layers['Binarised'].visible = False - - -# we can also manually control `progress` objects using their -# `update` method (inherited from tqdm) -def process_ims(): - """ - First performs thresholding, then segmentation on our image. - - Manually updates a `progress` object. - """ - if 'Binarised' in viewer.layers: - del viewer.layers['Binarised'] - if 'Segmented' in viewer.layers: - del viewer.layers['Segmented'] - - # we instantiate a manually controlled `progress` object - # by just passing a total with no iterable - with progress(total=2) as pbar: - pbar.set_description("Thresholding") - try_thresholds() - # once one processing step is complete, we increment - # the value of our progress bar - pbar.update(1) - - pbar.set_description("Segmenting") - segment_binarised_ims() - pbar.update(1) - - # uncomment this line to see the 100% progress bar - # sleep(0.5) - -button_layout = QVBoxLayout() -process_btn = QPushButton("Full Process") -process_btn.clicked.connect(process_ims) -button_layout.addWidget(process_btn) - -thresh_btn = QPushButton("1.Threshold") -thresh_btn.clicked.connect(try_thresholds) -button_layout.addWidget(thresh_btn) - -segment_btn = QPushButton("2.Segment") -segment_btn.clicked.connect(segment_binarised_ims) -button_layout.addWidget(segment_btn) - -action_widget = QWidget() -action_widget.setLayout(button_layout) -action_widget.setObjectName("Segmentation") -viewer.window.add_dock_widget(action_widget) - -# showing the activity dock so we can see the progress bars -viewer.window._status_bar._toggle_activity_dock(True) - -if __name__ == '__main__': - napari.run() diff --git a/examples/progress_bar_threading_.py b/examples/progress_bar_threading_.py deleted file mode 100644 index 477b00184..000000000 --- a/examples/progress_bar_threading_.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -Progress bar threading -====================== - -This file provides a minimal working example using a progress bar alongside -``@thread_worker`` to report progress. - -.. tags:: interactivity -""" -from time import sleep -from qtpy.QtWidgets import QPushButton, QVBoxLayout, QWidget -import napari -from napari.qt import thread_worker - -viewer = napari.Viewer() - - -def handle_yields(yielded_val): - print(f"Just yielded: {yielded_val}") - - -# generator thread workers can provide progress updates on each yield -@thread_worker( - # passing a progress dictionary with the total number of expected yields - # will place a progress bar in the activity dock and increment its value - # with each yield. We can optionally pass a description for the bar - # using the 'desc' key. - progress={'total': 5, 'desc': 'thread-progress'}, - # this does not preclude us from connecting other functions to any of the - # worker signals (including `yielded`) - connect={'yielded': handle_yields}, -) -def my_long_running_thread(*_): - for i in range(5): - sleep(0.1) - yield i - - -@thread_worker( - # If we are unsure of the number of expected yields, - # we can still pass an estimate to total, - # and the progress bar will become indeterminate - # once this number is exceeded. - progress={'total': 5}, - # we can also get a simple indeterminate progress bar - # by passing progress=True - connect={'yielded': handle_yields}, -) -def my_indeterminate_thread(*_): - for i in range(10): - sleep(0.1) - yield i - - -def return_func(return_val): - print(f"Returned: {return_val}") - - -# finally, a FunctionWorker can still provide an indeterminate -# progress bar, but will not take a total>0 -@thread_worker( - progress={'total': 0, 'desc': 'FunctionWorker'}, - # can use progress=True if not passing description - connect={'returned': return_func}, -) -def my_function(*_): - sum = 0 - for i in range(10): - sum += i - sleep(0.1) - return sum - - -button_layout = QVBoxLayout() -start_btn = QPushButton("Start") -start_btn.clicked.connect(my_long_running_thread) -button_layout.addWidget(start_btn) - -start_btn2 = QPushButton("Start Indeterminate") -start_btn2.clicked.connect(my_indeterminate_thread) -button_layout.addWidget(start_btn2) - -start_btn3 = QPushButton("Start FunctionWorker") -start_btn3.clicked.connect(my_function) -button_layout.addWidget(start_btn3) - -pbar_widget = QWidget() -pbar_widget.setLayout(button_layout) -pbar_widget.setObjectName("Threading Examples") -viewer.window.add_dock_widget(pbar_widget, allowed_areas=["right"]) - -# showing the activity dock so we can see the progress bars -viewer.window._status_bar._toggle_activity_dock(True) - -if __name__ == '__main__': - napari.run() diff --git a/examples/reader_plugin.py b/examples/reader_plugin.py deleted file mode 100644 index 9505aca0a..000000000 --- a/examples/reader_plugin.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Reader plugin -============= - -Barebones reader plugin example, using ``imageio.imread``` - -.. tags:: historical -""" -from napari_plugin_engine import napari_hook_implementation -from imageio import formats, imread - - -readable_extensions = tuple({x for f in formats for x in f.extensions}) - - -@napari_hook_implementation -def napari_get_reader(path): - """A basic implementation of the napari_get_reader hook specification.""" - # if we know we cannot read the file, we immediately return None. - if not path.endswith(readable_extensions): - return None - # otherwise we return the *function* that can read ``path``. - return reader_function - - -def reader_function(path): - """Take a path and returns a list of LayerData tuples.""" - data = imread(path) - # Readers are expected to return data as a list of tuples, where each tuple - # is (data, [meta_dict, [layer_type]]) - return [(data,)] diff --git a/examples/scale_bar.py b/examples/scale_bar.py deleted file mode 100644 index 60f55c283..000000000 --- a/examples/scale_bar.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Scale bar -========= - -Display a 3D volume and the scale bar - -.. tags:: experimental -""" -import numpy as np -import napari -from skimage import data - -cells = data.cells3d() - -viewer = napari.Viewer(ndisplay=3) - -viewer.add_image( - cells, - name=('membrane', 'nuclei'), - channel_axis=1, - scale=(0.29, 0.26, 0.26), -) -viewer.scale_bar.visible = True -viewer.scale_bar.unit = "um" - -if __name__ == '__main__': - napari.run() diff --git a/examples/set_colormaps.py b/examples/set_colormaps.py deleted file mode 100644 index 44ba7003f..000000000 --- a/examples/set_colormaps.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Set colormaps -============= - -Add named or unnamed vispy colormaps to existing layers. - -.. tags:: visualization-basic -""" - -import numpy as np -import vispy.color -from skimage import data -import napari - - -histo = data.astronaut() / 255 -rch, gch, bch = np.transpose(histo, (2, 0, 1)) -red = vispy.color.Colormap([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]]) -green = vispy.color.Colormap([[0.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) -blue = vispy.color.Colormap([[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]]) - -v = napari.Viewer() - -rlayer = v.add_image(rch, name='red channel') -rlayer.blending = 'additive' -rlayer.colormap = 'red', red -glayer = v.add_image(gch, name='green channel') -glayer.blending = 'additive' -glayer.colormap = green # this will appear as [unnamed colormap] -blayer = v.add_image(bch, name='blue channel') -blayer.blending = 'additive' -blayer.colormap = {'blue': blue} - -if __name__ == '__main__': - napari.run() diff --git a/examples/set_theme.py b/examples/set_theme.py deleted file mode 100644 index f790608a9..000000000 --- a/examples/set_theme.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -Set theme -========= - -Displays an image and sets the theme to 'light'. - -.. tags:: gui -""" - -from skimage import data -import napari - - -# create the viewer with an image -viewer = napari.view_image(data.astronaut(), rgb=True, name='astronaut') - -# set the theme to 'light' -viewer.theme = 'light' - -if __name__ == '__main__': - napari.run() diff --git a/examples/shapes_to_labels.py b/examples/shapes_to_labels.py deleted file mode 100644 index f1181d7a5..000000000 --- a/examples/shapes_to_labels.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -Shapes to labels -================ - -Display one shapes layer ontop of one image layer using the ``add_shapes`` and -``add_image`` APIs. When the window is closed it will print the coordinates of -your shapes. - -.. tags:: historical -""" - -import numpy as np -from skimage import data -import napari -from vispy.color import Colormap - - -# create the viewer and window -viewer = napari.Viewer() - -# add the image -img_layer = viewer.add_image(data.camera(), name='photographer') - -# create a list of polygons -polygons = [ - np.array([[11, 13], [111, 113], [22, 246]]), - np.array( - [ - [505, 60], - [402, 71], - [383, 42], - [251, 95], - [212, 59], - [131, 137], - [126, 187], - [191, 204], - [171, 248], - [211, 260], - [273, 243], - [264, 225], - [430, 173], - [512, 160], - ] - ), - np.array( - [ - [310, 382], - [229, 381], - [209, 401], - [221, 411], - [258, 411], - [300, 412], - [306, 435], - [268, 434], - [265, 454], - [298, 461], - [307, 461], - [307, 507], - [349, 510], - [352, 369], - [330, 366], - [330, 366], - ] - ), -] - -# add polygons -layer = viewer.add_shapes( - polygons, - shape_type='polygon', - edge_width=1, - edge_color='coral', - face_color='royalblue', - name='shapes', -) - -# change some attributes of the layer -layer.selected_data = set(range(layer.nshapes)) -layer.current_edge_width = 5 -layer.opacity = 0.75 -layer.selected_data = set() - -# add an ellipse to the layer -ellipse = np.array([[59, 222], [110, 289], [170, 243], [119, 176]]) -layer.add( - ellipse, - shape_type='ellipse', - edge_width=5, - edge_color='coral', - face_color='purple', -) - -masks = layer.to_masks([512, 512]) -masks_layer = viewer.add_image(masks.astype(float), name='masks') -masks_layer.opacity = 0.7 -masks_layer.colormap = Colormap([[0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 1.0]]) - -labels = layer.to_labels([512, 512]) -labels_layer = viewer.add_labels(labels, name='labels') -labels_layer.visible = False - -if __name__ == '__main__': - napari.run() diff --git a/examples/show_points_based_on_feature.py b/examples/show_points_based_on_feature.py deleted file mode 100644 index 81b7fba13..000000000 --- a/examples/show_points_based_on_feature.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Show points based on feature -============================ - -.. tags:: visualization-advanced -""" -#!/usr/bin/env python3 - -import napari -import numpy as np -from magicgui import magicgui - - -# create points with a randomized "confidence" feature -points = np.random.rand(100, 3) * 100 -colors = np.random.rand(100, 3) -confidence = np.random.rand(100) - -viewer = napari.Viewer(ndisplay=3) -points = viewer.add_points( - points, face_color=colors, features={'confidence': confidence} - ) - - -# create a simple widget with magicgui which provides a slider that controls the visilibility -# of individual points based on their "confidence" value -@magicgui( - auto_call=True, - threshold={'widget_type': 'FloatSlider', 'min': 0, 'max': 1} -) -def confidence_slider(layer: napari.layers.Points, threshold=0.5): - layer.shown = layer.features['confidence'] > threshold - - -viewer.window.add_dock_widget(confidence_slider) - -if __name__ == '__main__': - napari.run() diff --git a/examples/spheres_.py b/examples/spheres_.py deleted file mode 100644 index ab249fdad..000000000 --- a/examples/spheres_.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Spheres -======= - -Display two spheres with Surface layers - -.. tags:: visualization-advanced -""" - -import napari -from vispy.geometry import create_sphere - -mesh = create_sphere(method='ico') - -faces = mesh.get_faces() -vert = mesh.get_vertices() * 100 - -sphere1 = (vert + 30, faces) -sphere2 = (vert - 30, faces) - -viewer = napari.Viewer(ndisplay=3) -surface1 = viewer.add_surface(sphere1) -surface2 = viewer.add_surface(sphere2) -viewer.reset_view() - -if __name__ == '__main__': - napari.run() diff --git a/examples/spherical_points.py b/examples/spherical_points.py deleted file mode 100644 index 29ab6d0c0..000000000 --- a/examples/spherical_points.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Spherical points -================ - -.. tags:: experimental -""" -import napari -import numpy as np - - -np.random.seed() - -pts = np.random.rand(100, 3) * 100 -colors = np.random.rand(100, 3) -sizes = np.random.rand(100) * 20 + 10 - -viewer = napari.Viewer(ndisplay=3) -pts_layer = viewer.add_points( - pts, - face_color=colors, - size=sizes, - shading='spherical', - edge_width=0, -) - -# antialiasing is currently a bit broken, this is especially bad in 3D so -# we turn it off here -pts_layer.antialiasing = 0 - -viewer.reset_view() - -if __name__ == '__main__': - napari.run() diff --git a/examples/surface_normals_wireframe.py b/examples/surface_normals_wireframe.py deleted file mode 100644 index 03ecca8cb..000000000 --- a/examples/surface_normals_wireframe.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -Surface normals wireframe -========================= - -Display a 3D mesh with normals and wireframe - -.. tags:: experimental -""" - -from vispy.io import read_mesh, load_data_file -import napari - - -vert, faces, _, _ = read_mesh(load_data_file('orig/triceratops.obj.gz')) - -# put the mesh right side up, scale it up (napari#3477) and fix faces handedness -vert *= -100 -faces = faces[:, ::-1] - -viewer = napari.Viewer(ndisplay=3) -surface = viewer.add_surface(data=(vert, faces)) - -# enable normals and wireframe -surface.normals.face.visible = True -surface.normals.vertex.visible = True -surface.wireframe.visible = True - -if __name__ == '__main__': - napari.run() diff --git a/examples/surface_timeseries_.py b/examples/surface_timeseries_.py deleted file mode 100644 index db7cffd07..000000000 --- a/examples/surface_timeseries_.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Surface timeseries -================== - -Display a surface timeseries using data from nilearn - -.. tags:: experimental -""" - -try: - from nilearn import datasets - from nilearn import surface -except ModuleNotFoundError: - raise ModuleNotFoundError( - "You must have nilearn installed to run this example." - ) - -import numpy as np -import napari - - -# Fetch datasets - this will download dataset if datasets are not found -nki_dataset = datasets.fetch_surf_nki_enhanced(n_subjects=1) -fsaverage = datasets.fetch_surf_fsaverage() - -# Load surface data and resting state time series from nilearn -brain_vertices, brain_faces = surface.load_surf_data(fsaverage['pial_left']) -brain_vertex_depth = surface.load_surf_data(fsaverage['sulc_left']) -timeseries = surface.load_surf_data(nki_dataset['func_left'][0]) -# nilearn provides data as n_vertices x n_timepoints, but napari requires the -# vertices axis to be placed last to match NumPy broadcasting rules -timeseries = timeseries.transpose((1, 0)) - -# create an empty viewer -viewer = napari.Viewer(ndisplay=3) - -# add the mri -viewer.add_surface((brain_vertices, brain_faces, brain_vertex_depth), name='base') -viewer.add_surface((brain_vertices, brain_faces, timeseries), - colormap='turbo', opacity=0.9, - contrast_limits=[-1.5, 3.5], name='timeseries') - -if __name__ == '__main__': - napari.run() diff --git a/examples/swap_dims.py b/examples/swap_dims.py deleted file mode 100644 index cd4fd9280..000000000 --- a/examples/swap_dims.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Swap dims -========= - -Display a 4-D image and points layer and swap the displayed dimensions - -.. tags:: visualization-nD -""" - -import numpy as np -from skimage import data -import napari - - -blobs = np.stack( - [ - data.binary_blobs( - length=128, blob_size_fraction=0.05, n_dim=3, volume_fraction=f - ) - for f in np.linspace(0.05, 0.5, 10) - ], - axis=0, -) -viewer = napari.view_image(blobs.astype(float)) - -# add the points -points = np.array( - [ - [0, 0, 0, 100], - [0, 0, 50, 120], - [1, 0, 100, 40], - [2, 10, 110, 100], - [9, 8, 80, 100], - ] -) -viewer.add_points( - points, size=[0, 6, 10, 10], face_color='blue', out_of_slice_display=True -) - -viewer.dims.order = (0, 2, 1, 3) - -if __name__ == '__main__': - napari.run() diff --git a/examples/tiled-rendering-2d_.py b/examples/tiled-rendering-2d_.py deleted file mode 100644 index b7b5673d1..000000000 --- a/examples/tiled-rendering-2d_.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Tiled rendering 2D -================== - -This example shows how to display tiled, chunked data in napari using the -experimental octree support. - -If given a large 2D image with octree support enabled, napari will only load -and display the tiles in the center of the current canvas view. (Note: napari -uses its own internal tile size that may or may not be aligned with the -underlying tiled data, but this should have only minor performance -consequences.) - -If octree support is *not* enabled, napari will try to load the entire image, -which may not fit in memory and may bring your computer to a halt. Oops! So, we -make sure that we enable octree support by setting the NAPARI_OCTREE -environment variable to 1 if it is not set by the user. - -.. tags:: experimental -""" - -import os - -# important: if this is not set, the entire ~4GB array will be created! -os.environ.setdefault('NAPARI_OCTREE', '1') - -import dask.array as da -import napari - - -ndim = 2 -data = da.random.randint( - 0, 256, (65536,) * ndim, - chunks=(256,) * ndim, - dtype='uint8' - ) - -viewer = napari.Viewer() -viewer.add_image(data, contrast_limits=[0, 255]) -# To turn off grid lines -#viewer.layers[0].display.show_grid = False - -# set small zoom so we don't try to load the whole image at once -viewer.camera.zoom = 0.75 - -# run the example — try to pan around! -if __name__ == '__main__': - napari.run() diff --git a/examples/to_screenshot.py b/examples/to_screenshot.py deleted file mode 100644 index 91fad87cc..000000000 --- a/examples/to_screenshot.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -To screenshot -============= - -Display one shapes layer ontop of one image layer using the ``add_shapes`` and -``add_image`` APIs. When the window is closed it will print the coordinates of -your shapes. - -.. tags:: visualization-advanced -""" - -import numpy as np -from skimage import data -import napari -from vispy.color import Colormap - - -# create the viewer and window -viewer = napari.Viewer() - -# add the image -img_layer = viewer.add_image(data.camera(), name='photographer') -img_layer.colormap = 'gray' - -# create a list of polygons -polygons = [ - np.array([[11, 13], [111, 113], [22, 246]]), - np.array( - [ - [505, 60], - [402, 71], - [383, 42], - [251, 95], - [212, 59], - [131, 137], - [126, 187], - [191, 204], - [171, 248], - [211, 260], - [273, 243], - [264, 225], - [430, 173], - [512, 160], - ] - ), - np.array( - [ - [310, 382], - [229, 381], - [209, 401], - [221, 411], - [258, 411], - [300, 412], - [306, 435], - [268, 434], - [265, 454], - [298, 461], - [307, 461], - [307, 507], - [349, 510], - [352, 369], - [330, 366], - [330, 366], - ] - ), -] - -# add polygons -layer = viewer.add_shapes( - polygons, - shape_type='polygon', - edge_width=1, - edge_color='coral', - face_color='royalblue', - name='shapes', -) - -# change some attributes of the layer -layer.selected_data = set(range(layer.nshapes)) -layer.current_edge_width = 5 -layer.opacity = 0.75 -layer.selected_data = set() - -# add an ellipse to the layer -ellipse = np.array([[59, 222], [110, 289], [170, 243], [119, 176]]) -layer.add( - ellipse, - shape_type='ellipse', - edge_width=5, - edge_color='coral', - face_color='purple', -) - -masks = layer.to_masks([512, 512]) -masks_layer = viewer.add_image(masks.astype(float), name='masks') -masks_layer.opacity = 0.7 -masks_layer.colormap = Colormap([[0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 1.0]]) - -labels = layer.to_labels([512, 512]) -labels_layer = viewer.add_labels(labels, name='labels') - -points = np.array([[100, 100], [200, 200], [333, 111]]) -size = np.array([10, 20, 20]) -viewer.add_points(points, size=size) - -# sample vector coord-like data -n = 100 -pos = np.zeros((n, 2, 2), dtype=np.float32) -phi_space = np.linspace(0, 4 * np.pi, n) -radius_space = np.linspace(0, 100, n) - -# assign x-y position -pos[:, 0, 0] = radius_space * np.cos(phi_space) + 350 -pos[:, 0, 1] = radius_space * np.sin(phi_space) + 256 - -# assign x-y projection -pos[:, 1, 0] = 2 * radius_space * np.cos(phi_space) -pos[:, 1, 1] = 2 * radius_space * np.sin(phi_space) - -# add the vectors -layer = viewer.add_vectors(pos, edge_width=2) - -# take screenshot -screenshot = viewer.screenshot() -viewer.add_image(screenshot, rgb=True, name='screenshot') - -# from skimage.io import imsave -# imsave('screenshot.png', screenshot) - -if __name__ == '__main__': - napari.run() diff --git a/examples/tracks_2d.py b/examples/tracks_2d.py deleted file mode 100644 index 6189567bc..000000000 --- a/examples/tracks_2d.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -Tracks 2D -========= - -.. tags:: visualization-basic -""" - -import napari -import numpy as np - - -def _circle(r, theta): - x = r * np.cos(theta) - y = r * np.sin(theta) - return x, y - - -def tracks_2d(num_tracks=10): - """ create 2d+t track data """ - tracks = [] - - for track_id in range(num_tracks): - - # space to store the track data and features - track = np.zeros((100, 6), dtype=np.float32) - - # time - timestamps = np.arange(track.shape[0]) - - radius = 20 + 30 * np.random.random() - theta = timestamps * 0.1 + np.random.random() * np.pi - x, y = _circle(radius, theta) - - track[:, 0] = track_id - track[:, 1] = timestamps - track[:, 2] = 50.0 + y - track[:, 3] = 50.0 + x - track[:, 4] = theta - track[:, 5] = radius - - tracks.append(track) - - tracks = np.concatenate(tracks, axis=0) - data = tracks[:, :4] # just the coordinate data - - features = { - 'time': tracks[:, 1], - 'theta': tracks[:, 4], - 'radius': tracks[:, 5], - } - - graph = {} - return data, features, graph - - -tracks, features, graph = tracks_2d(num_tracks=10) -vertices = tracks[:, 1:] - -viewer = napari.Viewer() -viewer.add_points(vertices, size=1, name='points', opacity=0.3) -viewer.add_tracks(tracks, features=features, name='tracks') - -if __name__ == '__main__': - napari.run() diff --git a/examples/tracks_3d.py b/examples/tracks_3d.py deleted file mode 100644 index d9de8f733..000000000 --- a/examples/tracks_3d.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Tracks 3D -========= - -.. tags:: visualization-advanced -""" - -import napari -import numpy as np - - -def lissajous(t): - a = np.random.random(size=(3,)) * 80.0 - 40.0 - b = np.random.random(size=(3,)) * 0.05 - c = np.random.random(size=(3,)) * 0.1 - return (a[i] * np.cos(b[i] * t + c[i]) for i in range(3)) - - -def tracks_3d(num_tracks=10): - """ create 3d+t track data """ - tracks = [] - - for track_id in range(num_tracks): - - # space to store the track data and features - track = np.zeros((200, 10), dtype=np.float32) - - # time - timestamps = np.arange(track.shape[0]) - x, y, z = lissajous(timestamps) - - track[:, 0] = track_id - track[:, 1] = timestamps - track[:, 2] = 50.0 + z - track[:, 3] = 50.0 + y - track[:, 4] = 50.0 + x - - # calculate the speed as a feature - gz = np.gradient(track[:, 2]) - gy = np.gradient(track[:, 3]) - gx = np.gradient(track[:, 4]) - - speed = np.sqrt(gx ** 2 + gy ** 2 + gz ** 2) - distance = np.sqrt(x ** 2 + y ** 2 + z ** 2) - - track[:, 5] = gz - track[:, 6] = gy - track[:, 7] = gx - track[:, 8] = speed - track[:, 9] = distance - - tracks.append(track) - - tracks = np.concatenate(tracks, axis=0) - data = tracks[:, :5] # just the coordinate data - - features = { - 'time': tracks[:, 1], - 'gradient_z': tracks[:, 5], - 'gradient_y': tracks[:, 6], - 'gradient_x': tracks[:, 7], - 'speed': tracks[:, 8], - 'distance': tracks[:, 9], - } - - graph = {} - return data, features, graph - - -tracks, features, graph = tracks_3d(num_tracks=100) -vertices = tracks[:, 1:] - -viewer = napari.Viewer(ndisplay=3) -viewer.add_points(vertices, size=1, name='points', opacity=0.3) -viewer.add_tracks(tracks, features=features, name='tracks') - -if __name__ == '__main__': - napari.run() diff --git a/examples/tracks_3d_with_graph.py b/examples/tracks_3d_with_graph.py deleted file mode 100644 index e807717b0..000000000 --- a/examples/tracks_3d_with_graph.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Tracks 3D with graph -==================== - -.. tags:: visualization-advanced -""" - -import napari -import numpy as np - - -def _circle(r, theta): - x = r * np.cos(theta) - y = r * np.sin(theta) - return x, y - - -def tracks_3d_merge_split(): - """Create tracks with splitting and merging.""" - - timestamps = np.arange(300) - - def _trajectory(t, r, track_id): - theta = t * 0.1 - x, y = _circle(r, theta) - z = np.zeros(x.shape) - tid = np.ones(x.shape) * track_id - return np.stack([tid, t, z, y, x], axis=1) - - trackA = _trajectory(timestamps[:100], 30.0, 0) - trackB = _trajectory(timestamps[100:200], 10.0, 1) - trackC = _trajectory(timestamps[100:200], 50.0, 2) - trackD = _trajectory(timestamps[200:], 30.0, 3) - - data = [trackA, trackB, trackC, trackD] - tracks = np.concatenate(data, axis=0) - tracks[:, 2:] += 50.0 # centre the track at (50, 50, 50) - - graph = {1: 0, 2: [0], 3: [1, 2]} - - features = {'time': tracks[:, 1]} - - return tracks, features, graph - - -tracks, features, graph = tracks_3d_merge_split() -vertices = tracks[:, 1:] - -viewer = napari.Viewer(ndisplay=3) -viewer.add_points(vertices, size=1, name='points', opacity=0.3) -viewer.add_tracks(tracks, features=features, graph=graph, name='tracks') - -if __name__ == '__main__': - napari.run() diff --git a/examples/update_console.py b/examples/update_console.py deleted file mode 100644 index 9c3b91304..000000000 --- a/examples/update_console.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Update console -============== - -Display one shapes layer ontop of one image layer using the add_shapes and -add_image APIs. When the window is closed it will print the coordinates of -your shapes. - -.. tags:: historical -""" - -import numpy as np -from skimage import data -import napari - - -# create the viewer and window -viewer = napari.Viewer() - -# add the image -photographer = data.camera() -image_layer = napari.view_image(photographer, name='photographer') - -# create a list of polygons -polygons = [ - np.array([[11, 13], [111, 113], [22, 246]]), - np.array( - [ - [505, 60], - [402, 71], - [383, 42], - [251, 95], - [212, 59], - [131, 137], - [126, 187], - [191, 204], - [171, 248], - [211, 260], - [273, 243], - [264, 225], - [430, 173], - [512, 160], - ] - ), - np.array( - [ - [310, 382], - [229, 381], - [209, 401], - [221, 411], - [258, 411], - [300, 412], - [306, 435], - [268, 434], - [265, 454], - [298, 461], - [307, 461], - [307, 507], - [349, 510], - [352, 369], - [330, 366], - [330, 366], - ] - ), -] - -# add polygons -shapes_layer = viewer.add_shapes( - polygons, - shape_type='polygon', - edge_width=5, - edge_color='coral', - face_color='royalblue', - name='shapes', -) - -# Send local variables to the console -viewer.update_console(locals()) - -if __name__ == '__main__': - napari.run() diff --git a/examples/viewer_fps_label.py b/examples/viewer_fps_label.py deleted file mode 100644 index 00222a70a..000000000 --- a/examples/viewer_fps_label.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -Viewer FPS label -================ - -Display a 3D volume and the fps label. - -.. tags:: experimental -""" -import numpy as np -import napari - - -def update_fps(fps): - """Update fps.""" - viewer.text_overlay.text = f"{fps:1.1f} FPS" - - -viewer = napari.Viewer() -viewer.add_image(np.random.random((5, 5, 5)), colormap='red', opacity=0.8) -viewer.text_overlay.visible = True -viewer.window.qt_viewer.canvas.measure_fps(callback=update_fps) - -if __name__ == '__main__': - napari.run() diff --git a/examples/viewer_loop_reproducible_screenshots.md b/examples/viewer_loop_reproducible_screenshots.md deleted file mode 100644 index 30bfbdf9c..000000000 --- a/examples/viewer_loop_reproducible_screenshots.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -jupytext: - formats: ipynb,md:myst - text_representation: - extension: .md - format_name: myst - format_version: 0.13 - jupytext_version: 1.13.8 -kernelspec: - display_name: Python 3 (ipykernel) - language: python - name: python3 ---- - -```{tags} gui -``` - -# Creating reproducible screenshots with a viewer loop - -This example captures images in three dimensions for multiple samples. -This can be e.g. useful when one has dozens of ct scans and wants to visualize them for a quick overview with napari but does not want to load them one by one. -Reproducibility is achieved by defining exact frame width and frame height. - -+++ - -The first cell takes care of the imports and data initializing, in this case a blob, a ball and an octahedron. - -```{code-cell} ipython3 -from napari.settings import get_settings -import time -import napari -from napari._qt.qthreading import thread_worker -from skimage import data -from skimage.morphology import ball, octahedron -import matplotlib.pyplot as plt - -def make_screenshot(viewer): - img = viewer.screenshot(canvas_only=True, flash=False) - plt.imshow(img) - plt.axis("off") - plt.show() - -myblob = data.binary_blobs( - length=200, volume_fraction=0.1, blob_size_fraction=0.3, n_dim=3, seed=42 -) -myoctahedron = octahedron(100) -myball = ball(100) - -# store the variables in a dict with the image name as key. -data_dict = { - "blob": myblob, - "ball": myball, - "octahedron": myoctahedron, -} -``` - -Now, the napari viewer settings can be adjusted programmatically, such as 3D rendering methods, axes visible, color maps, zoom level, and camera orientation. -Every plot will have these exact settings, while only one napari viewer instance is needed. -After setting these parameters, one should not make changes with the mouse in the napari viewer anymore, as this would rule out the reproducibility. - -```{code-cell} ipython3 -viewer = napari.Viewer() -viewer.window.resize(900, 600) - -viewer.theme = "light" -viewer.dims.ndisplay = 3 -viewer.axes.visible = True -viewer.axes.colored = False -viewer.axes.labels = False -viewer.text_overlay.visible = True -viewer.text_overlay.text = "Hello World!" - -# Not yet implemented, but can be added as soon as this feature exisits (syntax might change): -# viewer.controls.visible = False - -viewer.add_labels(myball, name="result" , opacity=1) -viewer.camera.angles = (19, -33, -121) -viewer.camera.zoom = 1.3 -``` - -Next, the loop run is defined. -The `loop_run` function reads new `image_data` and the corresponding `image_name` and yields them to napari. -The `update_layer` function gives instructions how to process the yielded data in the napari viewer. - -```{code-cell} ipython3 -@thread_worker -def loop_run(): - for image_name in data_dict: - time.sleep(0.5) - image_data = data_dict[image_name] - yield (image_data, image_name) - -def update_layer(image_text_tuple): - image, text = image_text_tuple - viewer.layers["result"].data = image - viewer.text_overlay.text = text - make_screenshot(viewer) -``` - -And finally, the loop is executed: - -```{code-cell} ipython3 -worker = loop_run() -worker.yielded.connect(update_layer) -worker.start() -``` - -```{code-cell} ipython3 - -``` diff --git a/examples/without_gui_qt.py b/examples/without_gui_qt.py deleted file mode 100644 index bf2ba5a6f..000000000 --- a/examples/without_gui_qt.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -napari without gui_qt -===================== - -Alternative to using napari.gui_qt() context manager. - -This is here for historical purposes, to the transition away from -the "gui_qt()" context manager. - -.. tags:: historical -""" - -from skimage import data -import napari -from collections import Counter - -viewer = napari.view_image(data.astronaut(), rgb=True) - -# You can do anything you would normally do with the viewer object -# like take a -screenshot = viewer.screenshot() - -print('Maximum value', screenshot.max()) - -# To see the napari viewer and interact with the graphical user interface, -# use `napari.run()`. (it's similar to `plt.show` in matplotlib) -# If you only wanted the screenshot then you could skip this entirely. -# *run* will *block execution of your script* until the window is closed. -if __name__ == '__main__': - napari.run() - - # When the window is closed, your script continues and you can still inspect - # the viewer object. For example, add click the buttons to add various layer - # types when the window is open and see the result below: - - print("Your viewer has the following layers:") - for name, n in Counter(type(x).__name__ for x in viewer.layers).most_common(): - print(f" {name:<7}: {n}") diff --git a/examples/xarray_nD_image_.py b/examples/xarray_nD_image_.py deleted file mode 100644 index 8f5751110..000000000 --- a/examples/xarray_nD_image_.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Xarray example -============== - -Displays an xarray - -.. tags:: visualization-nD -""" - -try: - import xarray as xr -except ModuleNotFoundError: - raise ModuleNotFoundError( - """This example uses a xarray but xarray is not - installed. To install try 'pip install xarray'.""" - ) - -import numpy as np -import napari - -data = np.random.random((20, 40, 50)) -xdata = xr.DataArray(data, dims=['z', 'y', 'x']) - -# create an empty viewer -viewer = napari.Viewer() - -# add the xarray -layer = viewer.add_image(xdata, name='xarray') - -if __name__ == '__main__': - napari.run() diff --git a/examples/zarr_nD_image_.py b/examples/zarr_nD_image_.py deleted file mode 100644 index 71ab1cba2..000000000 --- a/examples/zarr_nD_image_.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Zarr array -========== - -Display a zarr array - -.. tags:: visualization-nD -""" - -try: - import zarr -except ModuleNotFoundError: - raise ModuleNotFoundError( - """This example uses a zarr array but zarr is not - installed. To install try 'pip install zarr'.""" - ) - -import napari - - -data = zarr.zeros((102_0, 200, 210), chunks=(100, 200, 210)) -data[53_0:53_1, 100:110, 110:120] = 1 - -print(data.shape) -# For big data, we should specify the contrast_limits range, or napari will try -# to find the min and max of the full image. -viewer = napari.view_image(data, contrast_limits=[0, 1], rgb=False) - -if __name__ == '__main__': - napari.run()