Skip to main content

worldarray

Chunked arrays in world coordinates, through tensorstore.

pip install worldarray

Why

Volumetric data at Janelia lives in zarr v2, zarr v3, N5 and Neuroglancer precomputed stores, on local disks, S3, GCS and HTTP. Each format records where the array sits, its voxel size, origin, units and axes, in its own dialect, and the dialects disagree on the one thing that matters most: whether a stored origin means the centre of the first voxel or its corner. Get that wrong and every object is half a voxel out of place, which is invisible in a viewer and ruinous in a measurement.

Reading such a volume correctly means parsing all those dialects, knowing the half-voxel rule for each, picking a pyramid level for a wanted resolution, and reading a region given in physical units as a plain numpy block, padded where the region leaves the data, resampled when no level matches, fast enough for a model server or a thousand cluster workers, with retries for flaky object stores and thread caps for shared hosts. No one package did all of that, so every tool here wrote its own reader, and the readers drifted apart. worldarray is that reader, written once, with the rules stated and tested.

Its dependencies are tensorstore and numpy. It is read-only in this version. The specification is the contract it is built to; every rule below is a test.

Quick start

import worldarray as wa

vol = wa.open("s3://janelia-cosem-datasets/jrc_hela-2/jrc_hela-2.zarr/recon-1/em/fibsem-uint8", level="s1")
vol.voxel_size      # (8.0, 8.0, 8.0) nm, spatial axes
vol.translation     # the centre of voxel 0, in nm
vol.corner          # the lower corner of voxel 0
vol.shape, vol.dtype, vol.axes, vol.levels

box = ((1000.0, 2000.0, 3000.0), (1512.0, 2512.0, 3512.0))   # [begin, end) in nm, half-open
arr = vol.read(box)                            # numpy, z y x; a voxel is read iff its centre lies in the box
arr = vol.read(box, padding="edge")            # a box past the data comes back padded, never raises
arr = vol.read(box, voxel_size=(16, 16, 16))   # resampled on the fly
arr, inside = vol.read(box, mask=True)         # True where the data was

# a volume at a resolution the store does not have: the best level, resampled
six = wa.open(path, voxel_size=(6, 6, 6), on_mismatch="resample")

# one volume read onto another volume's grid, for masks, contact sites, statistics
onto = raw.read(box, voxel_size=labels.voxel_size, anchor=labels.corner)

# index space, native units: what an engine or a viewer wants
vol = wa.open(path, units=None)
vol.meta            # shape, dtype, chunk_shape, axes, units, voxel_size, translation, attrs, ...
vol.ts              # the tensorstore itself, C order, origin 0
vol.read_index((0, 0, 0), (64, 64, 64), padding=0)

pyr = wa.open_pyramid(path)             # every level, opened on first use
pyr.select((16, 16, 16), mode="floor")  # the level to read at 16 nm

What it does

  • Opens zarr v2, zarr v3 (sharded or not), N5 and precomputed (sharded or not) arrays and pyramids by path, local or s3://, gs://, http(s)://, through tensorstore only. Public buckets are read anonymously first, credentials only when refused; the way in is remembered. AWS_ENDPOINT_URL points at S3-compatible stores.
  • Places every array by one written rule per format (below), reads axes and units as stored, converts only where asked (nanometres by default on spatial axes), and keeps voxel sizes as floats, never rounded.
  • Chooses a level by voxel size from the pyramid's own metadata, without opening the levels, with four policies for a size no level has: error, resample, relabel (voxel i stays voxel i, the grid rescaled), or keep the level.
  • Reads voxel boxes or world boxes as C-contiguous numpy in native byte order, padded with any value or the edge voxel, with an optional mask of what was data, a per-read transform applied before padding (or post_transform after resampling), and resampling by nearest neighbour or linear interpolation anchored where you say. Adjoining block reads agree with one read across both.
  • Behaves on a cluster: one shared tensorstore context per process or a capped one per worker, retries with backoff and size-aware timeouts on transient store errors, and a cancelled future on timeout.
  • Carries the geometry: Box with intersect, union, contains, grow, shift, snap to a grid, and the voxel indices a world box selects.

The placement rule

A translation is where the centre of voxel 0 is. Index i sits at translation + i * voxel_size; voxel i covers half a voxel either side. That is how OME-NGFF defines it and how Neuroglancer draws it. Dialects that store the corner are moved half a voxel on reading:

Stored Means Read as translation
OME-NGFF translation centre as is
COSEM transform.translate centre as is
offset beside resolution / voxel_size (offset missing: 0) corner offset + voxel_size / 2
N5 pixelResolution or resolution with downsamplingFactors f, no offset BigDataViewer (f - 1) / 2 * base
precomputed voxel_offset corner (voxel_offset + 1/2) * resolution
nothing a plain array voxels of 1, corner at the origin

Axes are the store's C order; N5 and precomputed are transposed to it. Unlisted or conflicting attributes warn; a voxel size that disagrees with the OME scale raises, since that is how stale metadata is caught. Metadata the parser did not consume stays available raw. The full precedence per format, the half-voxel rules, and every read behaviour are in the specification.

API in brief

wa.open(path, *, level=None, voxel_size=None, level_mode="floor", on_mismatch="error",
        padding=0, method="nearest", select=None, units="nanometer", context=None, retries=None,
        metadata_conflicts="error", base_voxel_size=None, base_units=None, anchor=None,
        transform=None, strict_units=True) -> WorldArray
wa.open_pyramid(path, ...) -> Pyramid          # .names .levels .by_name() .select() .placements() .metas(): no opens needed
wa.metadata(path, level=None, units=None, open=True) -> ArrayMeta   # open=False: from documents alone
wa.detect(path, missing_ok=False) -> Node      # format, array or group, raw attrs
wa.open_tensorstore(path, level=None, context=None)
wa.shared_context(cache_bytes=0) ; wa.capped_context(cache_bytes=0, concurrency=1, network=True) ; wa.Retry(...)
wa.list_chunk_keys(path, separator=".")        # chunk indices from keys alone, no metadata needed
wa.Box ; wa.units.TABLE

WorldArray: ts, meta, grid, shape, dtype, axes, voxel_size, translation, corner, box, levels, level_name, level_path, source_voxel_size, resampled; read(box, voxel_size=, padding=, method=, mask=, anchor=, transform=, post_transform=, select=, strict=), read_index(begin, end, padding=, mask=, select=, transform=), index_box(box), chunks_covering(begin, end), list_chunks(), reopen(context=).

A box is a (begin, end) pair of floats in your units, half-open per axis, over the spatial axes or every axis; any object with .begin/.end or .offset/.shape also works. There is no offset attribute, because that word means the corner in some dialects and the centre in others: translation and corner are the two names for the two things.

Origins

The vocabulary, an array that knows its voxel_size, where it sits and its axis names, and is read by a box in world units, follows funlib.persistence's Array, which many of the tools this serves were built on. The placement rules were consolidated from the readers those tools had each written, in cellmap-flow, cellmap-analyze, mesh-n-bone and chunkmirage, whose conventions document and conformance tests seeded this one; their authors' sessions trialled every change here on their own data. The voxel-centre convention is OME-NGFF's and ITK's, and is what Neuroglancer draws. tensorstore does the work underneath.

Development

uv sync --group dev --group docs
uv run pytest -q
uv run ruff check src tests && uv run ruff format src tests
uv run mkdocs serve

BSD-3-Clause, Howard Hughes Medical Institute.

Metadata

Release files for worldarray 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for worldarray 0.1.0
File Size Uploaded Provenance
worldarray-0.1.0.tar.gz 160.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for worldarray 0.1.0
File Interpreter ABI Platform
worldarray-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 206.0 kB

Release files / worldarray-0.1.0.tar.gz

Download URL worldarray-0.1.0.tar.gz
Size 160.1 kB
Tags Source
SHA-256 checksum
How to use checksums
7d0bec45b5af0bb58510f84abefa8f299d6185a992b8c3ab05abf382000ba1e6
BLAKE2b-256 checksum
How to use checksums
2d1db46c69a9ec7589797f7dbb9262933916f72db55b6580f93c515c335dc074
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Release files / worldarray-0.1.0-py3-none-any.whl

Download URL worldarray-0.1.0-py3-none-any.whl
Size 45.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8fbfda0a9f3258746f771b848dc5638c30ae410c5a73a861d75f46705d7d84ed
BLAKE2b-256 checksum
How to use checksums
41ed6bde11ecc2756cb5e4cb57b0c5ac7594d7b93e24863aa1d5a96576e34ec7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Security for worldarray 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for worldarray-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page