Try Live
Add Docs
Rankings
Pricing
Docs
Install
Theme
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Napari
https://github.com/napari/napari
Admin
napari is a fast, interactive, multi-dimensional image viewer for Python, designed for browsing,
...
Tokens:
4,230
Snippets:
48
Trust Score:
8.1
Update:
1 month ago
Context
Skills
Chat
Benchmark
53.9
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# napari ## Introduction napari is a fast, interactive, multi-dimensional image viewer for Python designed for browsing, annotating, and analyzing large multi-dimensional images. Built on Qt for the GUI, vispy for performant GPU-based rendering, and the scientific Python stack (numpy, scipy), it provides a powerful platform for n-dimensional visualization with support for six main layer types: Image, Labels, Points, Vectors, Shapes, and Surface. The viewer supports both 2D and 3D visualization with real-time interaction capabilities. The project is built as a modular framework with a plugin ecosystem that enables extensibility through the npe2 plugin engine. napari provides both programmatic access via Python APIs and an interactive GUI application, making it suitable for both automated workflows and manual image analysis tasks. The architecture separates the core viewer model from the Qt-based window implementation, allowing for flexible integration into various scientific computing environments including Jupyter notebooks. ## APIs and Key Functions ### Creating a Viewer Initialize a napari viewer window for interactive visualization. ```python import napari from skimage import data # Create a basic 2D viewer viewer = napari.Viewer() # Create a 3D viewer with custom title viewer = napari.Viewer(title='My Analysis', ndisplay=3) # Create viewer with custom axis labels viewer = napari.Viewer( title='Time Series', axis_labels=['time', 'y', 'x'] ) # Start the event loop (required when running as a script) napari.run() ``` ### Adding Image Layers Display single or multi-dimensional image data as layers in the viewer. ```python import napari import numpy as np from skimage import data viewer = napari.Viewer() # Add a 2D RGB image rgb_image = data.astronaut() viewer.add_image(rgb_image, rgb=True, name='astronaut') # Add a grayscale image with custom colormap gray_image = data.camera() viewer.add_image( gray_image, colormap='viridis', contrast_limits=[0, 255], name='photographer' ) # Add 3D volumetric data volume = np.random.rand(32, 64, 64) viewer.add_image( volume, name='3D volume', rendering='mip', # maximum intensity projection blending='additive' ) # Add multi-channel image by splitting channels cells3d = data.cells3d() # shape (60, 2, 256, 256) viewer, layers = napari.imshow( cells3d, channel_axis=1, name=['nuclei', 'membrane'], colormap=['blue', 'green'] ) napari.run() ``` ### Adding Labels Layers Display segmentation or labeled regions with categorical colormaps. ```python import napari from skimage import data from skimage.filters import threshold_otsu from skimage.measure import label from skimage.morphology import closing, square, remove_small_objects from skimage.segmentation import clear_border viewer = napari.Viewer() # Load and segment an image image = data.coins()[50:-50, 50:-50] viewer.add_image(image, name='coins', rgb=False) # Create labeled regions thresh = threshold_otsu(image) bw = closing(image > thresh, square(4)) cleared = remove_small_objects(clear_border(bw), 20) label_image = label(cleared).astype('uint8') # Add labels layer label_layer = viewer.add_labels( label_image, name='segmentation', opacity=0.7 ) # Interactively paint labels label_layer.mode = 'paint' # Switch to paint mode label_layer.brush_size = 10 napari.run() ``` ### Adding Points Layers Display and annotate point locations in 2D or 3D space. ```python import napari import numpy as np from scipy import ndimage as ndi from skimage import data # Create 3D viewer with labeled volume viewer = napari.Viewer(ndisplay=3) blobs = data.binary_blobs( length=128, volume_fraction=0.1, n_dim=3 )[::2].astype(float) labeled = ndi.label(blobs)[0] viewer.add_image(blobs, name='blobs', scale=(2, 1, 1)) viewer.add_labels(labeled, name='blob ID', scale=(2, 1, 1)) # Add interactive points layer points = viewer.add_points( name='annotations', size=5, face_color='red', edge_color='white', edge_width=2 ) # Set to add mode for manual annotation points.mode = 'add' viewer.camera.angles = (0, -65, 85) # Programmatically add points coords = np.array([[32, 64, 64], [16, 32, 32], [48, 80, 80]]) viewer.add_points( coords, name='detected_centers', size=8, face_color='cyan' ) napari.run() ``` ### Adding Shapes Layers Draw and manipulate geometric shapes like rectangles, ellipses, and polygons. ```python import napari import numpy as np from skimage import data viewer = napari.Viewer() viewer.add_image(data.camera(), name='photographer') # Define polygon vertices 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] ]) ] # Add shapes as a layer shapes_layer = viewer.add_shapes( polygons, shape_type='polygon', edge_width=2, edge_color='coral', face_color='royalblue', opacity=0.6, name='regions' ) # Add individual shapes to existing layer ellipse = np.array([[59, 222], [110, 289], [170, 243], [119, 176]]) shapes_layer.add( ellipse, shape_type='ellipse', edge_width=5, edge_color='coral', face_color='purple' ) # Select and modify shapes shapes_layer.selected_data = {0, 1} shapes_layer.current_edge_width = 5 napari.run() ``` ### Adding Vectors Layers Display vector field data with directional arrows. ```python import napari import numpy as np from skimage import data viewer = napari.Viewer() viewer.add_image(data.camera(), name='photographer') # Create vector data: (N, 2, 2) array # Each vector: [[y_center, x_center], [y_projection, x_projection]] n = 200 vectors = np.zeros((n, 2, 2), dtype=np.float32) phi_space = np.linspace(0, 4 * np.pi, n) radius_space = np.linspace(0, 100, n) # Center positions vectors[:, 0, 0] = radius_space * np.sin(phi_space) + 256 vectors[:, 0, 1] = radius_space * np.cos(phi_space) + 300 # Vector projections vectors[:, 1, 0] = 2 * radius_space * np.sin(phi_space) vectors[:, 1, 1] = 2 * radius_space * np.cos(phi_space) # Add vectors to viewer vector_layer = viewer.add_vectors( vectors, edge_width=3, edge_color='red', length=1.5, name='flow_field' ) napari.run() ``` ### Working with Dask Arrays Efficiently handle large datasets using lazy-loaded dask arrays. ```python import napari import numpy as np from skimage import data try: from dask import array as da except ModuleNotFoundError: raise ModuleNotFoundError( "Install dask with: pip install dask[array]" ) # Create a large lazy-loaded 4D dask array 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, ) # napari will only load visible chunks viewer = napari.Viewer() viewer.add_image( blobs.astype(float), name='lazy_blobs', cache=True # Enable chunk caching ) # Visualize the data shape print(f"Data shape: {blobs.shape}") # (10, 128, 128, 128) print(f"Data type: {type(blobs)}") # dask.array.core.Array napari.run() ``` ### Quick Visualization with imshow Rapidly display images with automatic layer and viewer creation. ```python import napari from skimage import data import numpy as np # Quick display of 2D image viewer, image_layer = napari.imshow(data.astronaut(), rgb=True) # Display 3D volume with channel splitting cells3d = data.cells3d() # shape (60, 2, 256, 256) viewer, layers = napari.imshow( cells3d, channel_axis=1, ndisplay=3, name=['nuclei', 'membrane'], colormap=['blue', 'green'], blending='additive' ) # layers is a tuple of Image layers nuclei_layer, membrane_layer = layers # Adjust layer properties nuclei_layer.contrast_limits = (0, 500) membrane_layer.opacity = 0.7 napari.run() ``` ### Layer Manipulation and Access Programmatically access and modify layers in the viewer. ```python import napari from skimage import data viewer = napari.Viewer() # Add multiple layers layer1 = viewer.add_image(data.camera(), name='camera') layer2 = viewer.add_image(data.coins(), name='coins') layer3 = viewer.add_image(data.astronaut(), rgb=True, name='astronaut') # Access layers by index or name first_layer = viewer.layers[0] camera_layer = viewer.layers['camera'] # Get the currently selected layer active = viewer.layers.selection.active # Iterate through all layers for layer in viewer.layers: print(f"Layer: {layer.name}, Type: {type(layer).__name__}") layer.opacity = 0.8 # Remove a layer viewer.layers.remove('coins') # Reorder layers (move to top) viewer.layers.move(0, 2) # Clear all layers # viewer.layers.clear() napari.run() ``` ### Saving Layers and Screenshots Export layer data and viewer screenshots to various formats. ```python import napari from skimage import data import numpy as np viewer = napari.Viewer() # Add some content viewer.add_image(data.camera(), name='image') shapes_data = np.array([[[100, 100], [200, 100], [200, 200], [100, 200]]]) viewer.add_shapes(shapes_data, shape_type='rectangle', name='roi') # Save screenshot viewer.screenshot('/tmp/screenshot.png') # Save screenshot with specific canvas size viewer.screenshot('/tmp/large_screenshot.png', canvas_only=True, scale=2) # Save individual layer data image_layer = viewer.layers['image'] # Save as numpy array np.save('/tmp/image_data.npy', image_layer.data) # Save shapes to SVG (requires napari-svg plugin) try: viewer.layers['roi'].save('/tmp/shapes.svg', plugin='svg') except Exception as e: print(f"SVG export not available: {e}") # Save all layers from napari.plugins.io import save_layers save_layers('/tmp/layers.zarr', [viewer.layers['image']]) napari.run() ``` ### Custom Keybindings and Callbacks Extend viewer functionality with custom keyboard shortcuts and event handlers. ```python import napari from skimage import data import numpy as np viewer = napari.Viewer() viewer.add_image(data.camera()) # Add a custom keybinding @viewer.bind_key('Shift-I') def invert_image(viewer): """Invert the active image layer.""" layer = viewer.layers.selection.active if hasattr(layer, 'data'): layer.data = 255 - layer.data print("Image inverted!") # Bind a function to add random points @viewer.bind_key('r') def add_random_points(viewer): """Add 10 random points to the viewer.""" shape = viewer.dims.range[0][1], viewer.dims.range[1][1] points = np.random.rand(10, 2) * np.array(shape) viewer.add_points(points, size=10, face_color='red') # Layer-specific events points_layer = viewer.add_points(name='interactive') @points_layer.events.data.connect def on_points_changed(event): """Called when points are added/removed/modified.""" print(f"Points layer now has {len(points_layer.data)} points") # Mouse callback @viewer.mouse_drag_callbacks.append def on_drag(viewer, event): """Print coordinates during mouse drag.""" if event.type == 'mouse_move': print(f"Position: {event.position}") napari.run() ``` ### Opening Files Load images from various file formats using built-in or plugin readers. ```python import napari viewer = napari.Viewer() # Open a single file viewer.open('/path/to/image.tif') # Open multiple files viewer.open(['/path/to/image1.tif', '/path/to/image2.tif']) # Open with specific plugin viewer.open('/path/to/special.format', plugin='my-reader-plugin') # Open programmatically using imread from napari import Viewer from skimage import io viewer = Viewer() image = io.imread('/path/to/image.png') viewer.add_image(image, name='loaded_image') # Open from URL (if supported by reader) try: viewer.open('https://example.com/data.tif') except Exception as e: print(f"URL loading failed: {e}") napari.run() ``` ### Using the Built-in Console Access the embedded IPython console for interactive debugging and scripting. ```python import napari from skimage import data viewer = napari.Viewer() viewer.add_image(data.astronaut(), rgb=True, name='astronaut') # The console provides access to: # - viewer: the Viewer instance # - np: numpy # - Any layers added to the viewer # In the console, you can type: # >>> viewer.layers[0].contrast_limits = (0, 200) # >>> new_layer = viewer.add_points(np.random.rand(10, 2) * 512) # >>> print([layer.name for layer in viewer.layers]) # Enable console programmatically viewer.window._qt_viewer.dockConsole.setVisible(True) napari.run() ``` ### Multiscale Image Pyramids Display large images efficiently using multiscale pyramids. ```python import napari import numpy as np # Create a multiscale pyramid (list of arrays) base_image = np.random.rand(2048, 2048) pyramid = [ base_image, base_image[::2, ::2], # 1024x1024 base_image[::4, ::4], # 512x512 base_image[::8, ::8], # 256x256 base_image[::16, ::16], # 128x128 ] viewer = napari.Viewer() # Add multiscale image viewer.add_image( pyramid, name='large_image', multiscale=True, contrast_limits=[0, 1] ) # napari automatically selects appropriate resolution level based on zoom # For dask arrays with multiscale from dask import array as da dask_pyramid = [da.from_array(level) for level in pyramid] viewer.add_image( dask_pyramid, name='dask_pyramid', multiscale=True, cache=True ) napari.run() ``` ## Use Cases and Integration napari is designed for scientific visualization workflows in biology, microscopy, medical imaging, and general n-dimensional data analysis. Common use cases include exploring large microscopy datasets with automatic lazy-loading through dask integration, manual annotation of structures using interactive Points and Shapes layers with persistent modifications, quantitative analysis through programmatic layer data access, and custom image processing pipelines with real-time visualization. The viewer supports both manual exploration via GUI and automated batch processing through Python scripts. Integration patterns include embedding napari in Jupyter notebooks for interactive analysis sessions, extending functionality through the npe2 plugin system for custom readers and writers, creating custom widgets using magicgui for domain-specific analysis tools, and building complete applications by combining napari's Viewer with custom Qt widgets. The separation between ViewerModel (core logic) and Window (Qt implementation) enables flexible deployment scenarios. Developers can leverage napari's event system for reactive programming patterns, where layer modifications trigger custom callbacks for automated analysis workflows. The architecture supports both standalone desktop applications and integration as a component in larger scientific computing environments.