Skip to content

Annotations

CRUD operations for annotations.

nimbusimage.annotations.AnnotationAccessor

Access annotations for a specific dataset.

list(shape=None, tags=None, limit=0, offset=0, after_id=None, sort=None, sortdir=1)

List annotations in this dataset.

Parameters:

Name Type Description Default
shape str | None

Filter by shape ('polygon', 'point', 'line').

None
tags list[str] | None

Filter by tags (JSON-encoded array sent to server).

None
limit int

Max results. 0 = unlimited.

0
offset int

Skip this many results. NOTE: offset is positional and not stable across mutations — if you delete or add annotations between paged calls, an offset loop will skip or repeat records. Use :meth:iter_all (a stable after_id cursor) for delete/modify-as-you-go loops.

0
after_id str | None

Return only annotations whose _id is greater than this one (a stable cursor). When set, the server ignores offset. Only meaningful with sort="_id" (the server otherwise defaults to a non-_id sort); prefer :meth:iter_all, which sets this for you.

None
sort str | None

Field to sort by (e.g. "_id"). If omitted, the server uses its own default sort, which is not _id.

None
sortdir int

Sort direction, 1 ascending or -1 descending. Only applied when sort is set.

1

Returns:

Type Description
list[Annotation]

List of Annotation objects.

iter_all(shape=None, tags=None, page_size=1000)

Iterate over every matching annotation, one page at a time.

Walks the backend's stable afterId cursor: each page asks for annotations whose _id is greater than the largest _id seen so far. This is mutation-safe — unlike offset pagination, you can delete or modify annotations as you iterate without skipping records (the cursor only ever advances past IDs already yielded).

This is the recommended way to fetch large result sets and to drive delete-as-you-go cleanup loops.

The cursor's correctness requires each page to come back in ascending _id order (so page[-1] is the largest _id in the page). The server's default sort is not _id, so this explicitly requests sort="_id" on every page — without it the cursor could skip, duplicate, or loop on records.

Parameters:

Name Type Description Default
shape str | None

Filter by shape ('polygon', 'point', 'line').

None
tags list[str] | None

Filter by tags.

None
page_size int

Number of annotations to fetch per request.

1000

Yields:

Type Description
Annotation

Annotation objects, in ascending _id order.

get(annotation_id)

Get a single annotation by ID.

count(shape=None, tags=None)

Count annotations matching filters.

create(annotation)

Create a single annotation.

create_many(annotations, connect_to=None)

Create multiple annotations in bulk.

Parameters:

Name Type Description Default
annotations list[Annotation]

List of Annotation objects to create.

required
connect_to dict | None

If provided, auto-connect created annotations to nearest matching annotation. Dict with 'tags' and 'channel' keys.

None

Returns:

Type Description
list[Annotation]

List of created Annotations (with server-assigned IDs).

update(annotation_id, updates)

Update a single annotation.

Returns the updated annotation. If the server returns no body, fetches the annotation by ID to return the current state.

update_many(updates)

Update multiple annotations in a single HTTP request.

Parameters:

Name Type Description Default
updates list[tuple[str, dict]]

List of (annotation_id, updates_dict) tuples. Each updates_dict may include 'datasetId' (required only if moving the annotation to a different dataset).

required
Note

The bulk PUT endpoint returns no body, so this method does not return the updated annotations. Call get() on individual IDs if you need their fresh state.

delete(annotation_id)

Delete a single annotation.

delete_many(annotation_ids)

Delete multiple annotations.

compute(image, channel=0, tags=None, location=None, assignment=None, worker_interface=None, scales=None, connect_to=None, name='worker')

Run an annotation worker on this dataset.

Submits a Docker worker job via POST /upenn_annotation/compute. The worker container receives the parameters as a JSON string via --parameters and parses them with WorkerClient.

Parameters:

Name Type Description Default
image str

Docker image name (e.g., 'annotations/random_squares:latest').

required
channel int

Channel index for the worker to process.

0
tags list[str] | None

Tags to assign to created annotations.

None
location Location | None

Location (XY/Z/Time) for single-tile processing. Defaults to Location(). Mutually exclusive with assignment: in batch mode the worker iterates the assignment ranges and ignores location/tile, so passing both raises ValueError.

None
assignment dict | str | None

Assignment range for batch processing. Can be a dict like {'XY': '0-2', 'Z': 0, 'Time': 0} or range strings like {'XY': '0-2', 'Z': 0, 'Time': '0-4'}. Defaults to the location if not provided. Do not combine with location= (see above).

None
worker_interface dict | None

Parameter values matching the worker's interface schema (from client.get_worker_interface()). Keys must match exactly (e.g., 'Square size', not 'square_size').

None
scales dict | None

Scale metadata (pixel size, etc.). Passed through to the worker for unit-aware computations.

None
connect_to dict | None

Auto-connect created annotations to nearest neighbors. Dict with tags (list[str]) and channel (int) keys. If not provided, no connections are created.

None
name str

Job name shown in the Girder UI.

'worker'

Returns:

Type Description
Job

A Job object. Call job.wait() to block until completion.

Note

The worker container uses WorkerClient from the worker_client package, which requires all of these keys in the parameters: assignment, channel, connectTo, tags, tile, workerInterface. Missing keys cause the worker to skip initialization silently. The connectTo dict must always contain a tags key (use [] for no connections) — omitting it causes a KeyError after annotations are uploaded.