Getting Started
Installation
For Docker worker development (includes large_image for writing TIFF files):
Connecting to a server
import nimbusimage as ni
# Option 1: Explicit credentials
client = ni.connect("http://localhost:8080/api/v1", token="your-token")
# Option 2: Username/password
client = ni.connect("http://localhost:8080/api/v1", username="admin", password="password")
# Option 3: Environment variables (NI_API_URL, NI_TOKEN)
client = ni.connect()
Working with datasets
# Get a dataset by ID
ds = client.dataset("64a1b2c3d4e5f6a7b8c9d0e1")
# Or look it up by name
ds = client.dataset(name="My Experiment")
# Explore metadata
print(f"Name: {ds.name}")
print(f"Shape: {ds.shape}") # (height, width)
print(f"Channels: {ds.channels}")
print(f"Z-slices: {ds.num_z}, Time points: {ds.num_time}")
print(f"Pixel size: {ds.pixel_size.to('um').value} um")
Fetching images
import numpy as np
# Single frame as a 2D numpy array
img = ds.images.get(channel=0, z=0, time=0)
# All channels at one location
channels = ds.images.get_all_channels(z=0, time=0)
# Z-stack as a 3D array (Z, H, W)
stack = ds.images.get_stack(channel=0, axis="z")
# Composite RGB image using layer settings
rgb = ds.images.get_composite(dtype="uint8")
Annotations
# List annotations
polygons = ds.annotations.list(shape="polygon", tags=["nucleus"])
print(f"Found {len(polygons)} nuclei")
# Create annotations
ann = ni.Annotation.from_point(
x=100.5, y=200.5,
channel=0,
tags=["spot"],
dataset_id=ds.id,
location=ni.Location(xy=0, z=0, time=0),
)
created = ds.annotations.create(ann)
print(f"Created annotation: {created.id}")
# Bulk create
annotations = [
ni.Annotation.from_point(x=x, y=y, channel=0, tags=["spot"], dataset_id=ds.id)
for x, y in zip(xs, ys)
]
ds.annotations.create_many(annotations)
# Delete
ds.annotations.delete(created.id)
Geometry helpers
Annotations have geometry methods for converting to shapely objects and numpy masks:
ann = ds.annotations.list(shape="polygon")[0]
# Shapely conversion
polygon = ann.polygon() # shapely Polygon
point = ann.point() # shapely Point (or centroid)
cx, cy = ann.centroid() # (x, y) tuple
# Numpy mask
mask = ann.get_mask(ds.shape) # boolean array
rows, cols = ann.get_pixels(ds.shape) # pixel indices
# Create from shapely/mask
from shapely.geometry import Polygon
poly = Polygon([(100, 200), (150, 200), (150, 250), (100, 250)])
ann = ni.Annotation.from_polygon(poly, channel=0, tags=["cell"], dataset_id=ds.id)
Properties
# Create or find a property definition
prop = ds.properties.get_or_create("Area", shape="polygon")
# Register it with the dataset's configuration
ds.properties.register(prop.id)
# Submit computed values
values = {}
for ann in ds.annotations.list(shape="polygon"):
mask = ann.get_mask(ds.shape)
values[ann.id] = {"Area": float(mask.sum())}
ds.properties.submit_values(prop.id, values)
Connections
# Create a connection between two annotations
conn = ds.connections.create(parent_id=parent.id, child_id=child.id, tags=["lineage"])
# Auto-connect to nearest neighbors
ds.connections.connect_to_nearest(
annotation_ids=[a.id for a in new_annotations],
tags=["nucleus"],
channel=0,
)
Running workers
Workers are Docker containers that perform computations (segmentation, measurements, image processing) on datasets.
Discover available workers
# List all worker images on the server
workers = client.list_workers()
for image, labels in workers.items():
print(f"{image}: {labels.get('interfaceName', '')}")
# Get the parameter interface for a worker
interface = client.get_worker_interface("annotations/random_squares:latest")
for param, spec in interface.items():
print(f" {param}: type={spec['type']}, default={spec.get('default', '')}")
Run an annotation worker
# Submit a worker job
job = ds.annotations.compute(
image="annotations/random_squares:latest",
channel=0,
tags=["detected"],
worker_interface={
"Number of squares": 100,
"Square size": 15,
},
)
# Wait for completion (prints progress to stderr)
success = job.wait()
print(f"Job {'succeeded' if success else 'failed'}")
# With auto-connection to nearest neighbors
job = ds.annotations.compute(
image="annotations/laplacian_of_gaussian:latest",
channel=0,
tags=["spots"],
worker_interface={"Sigma": 2.0},
connect_to={"tags": ["nucleus"], "channel": 0},
)
job.wait()
Run a property worker
# Create and register a property
prop = ds.properties.get_or_create("Blob Intensity", shape="polygon")
ds.properties.register(prop.id)
# Run the property worker
job = ds.properties.compute(
prop,
worker_interface={"Channel": 0},
scales=ds.collections.get_raw().get("meta", {}).get("scales", {}),
)
job.wait()
# Fetch the computed values
values = ds.properties.get_values()
Job tracking
# Non-blocking: check status manually
job = ds.annotations.compute(...)
while not job.finished:
job.refresh()
print(f"Status: {job.status_name}")
time.sleep(5)
# Blocking with timeout
try:
job.wait(timeout=300) # 5 minute timeout
except TimeoutError:
print("Job timed out")
Export
# JSON export
data = ds.export.to_json()
# CSV export to file
ds.export.to_csv(
property_paths=[["prop_id", "Area"]],
path="results.csv",
)
Sharing and access control
# Share with a user
ds.sharing.share("colleague@example.com", access="write")
# Make public
ds.sharing.set_public(True)
URLs and browser integration
# Open dataset in browser
ds.open(z=3, time=0)
# Get URLs without opening
print(ds.view_url())
print(ds.info_url())
print(ds.configuration_url())
Environment variables
| Variable | Description | Default |
|---|---|---|
NI_API_URL |
Girder API URL | -- |
NI_TOKEN |
Authentication token | -- |
NI_FRONTEND_URL |
Frontend URL for browser links | http://localhost:5173 |