worldarray 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,214 @@
1
+ Metadata-Version: 2.5
2
+ Name: worldarray
3
+ Version: 0.1.0
4
+ Summary: Read zarr, N5 and Neuroglancer precomputed volumes in world coordinates through tensorstore: correct voxel placement, pyramid levels, padded region reads, resampling. numpy + tensorstore only.
5
+ Project-URL: Homepage, https://janeliascicomp.github.io/worldarray/
6
+ Project-URL: Documentation, https://janeliascicomp.github.io/worldarray/
7
+ Project-URL: Source, https://github.com/JaneliaSciComp/worldarray
8
+ Project-URL: Issues, https://github.com/JaneliaSciComp/worldarray/issues
9
+ Project-URL: Changelog, https://github.com/JaneliaSciComp/worldarray/blob/main/CHANGELOG.md
10
+ Author: David Ackerman (@davidackerman)
11
+ License: BSD 3-Clause License
12
+
13
+ Copyright (c) 2026, Howard Hughes Medical Institute
14
+
15
+ Redistribution and use in source and binary forms, with or without
16
+ modification, are permitted provided that the following conditions are met:
17
+
18
+ 1. Redistributions of source code must retain the above copyright notice, this
19
+ list of conditions and the following disclaimer.
20
+
21
+ 2. Redistributions in binary form must reproduce the above copyright notice,
22
+ this list of conditions and the following disclaimer in the documentation
23
+ and/or other materials provided with the distribution.
24
+
25
+ 3. Neither the name of the copyright holder nor the names of its
26
+ contributors may be used to endorse or promote products derived from
27
+ this software without specific prior written permission.
28
+
29
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
30
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
32
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
33
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
36
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
+ License-File: LICENSE
40
+ Keywords: bioimaging,chunked-arrays,cloud-storage,connectomics,electron-microscopy,gcs,microscopy,multiscale,n5,neuroglancer,ome-ngff,ome-zarr,precomputed,pyramid,s3,tensorstore,volumetric,world-coordinates,zarr
41
+ Classifier: Development Status :: 3 - Alpha
42
+ Classifier: Intended Audience :: Science/Research
43
+ Classifier: License :: OSI Approved :: BSD License
44
+ Classifier: Operating System :: OS Independent
45
+ Classifier: Programming Language :: Python :: 3
46
+ Classifier: Programming Language :: Python :: 3.10
47
+ Classifier: Programming Language :: Python :: 3.11
48
+ Classifier: Programming Language :: Python :: 3.12
49
+ Classifier: Programming Language :: Python :: 3.13
50
+ Classifier: Topic :: Scientific/Engineering
51
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
52
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
53
+ Classifier: Topic :: Scientific/Engineering :: Visualization
54
+ Classifier: Typing :: Typed
55
+ Requires-Python: >=3.10
56
+ Requires-Dist: numpy>=1.26
57
+ Requires-Dist: tensorstore>=0.1.60
58
+ Description-Content-Type: text/markdown
59
+
60
+ # worldarray
61
+
62
+ Chunked arrays in world coordinates, through tensorstore.
63
+
64
+ ```bash
65
+ pip install worldarray
66
+ ```
67
+
68
+ ## Why
69
+
70
+ Volumetric data at Janelia lives in zarr v2, zarr v3, N5 and Neuroglancer precomputed
71
+ stores, on local disks, S3, GCS and HTTP. Each format records *where the array sits*,
72
+ its voxel size, origin, units and axes, in its own dialect, and the dialects disagree on
73
+ the one thing that matters most: whether a stored origin means the centre of the first
74
+ voxel or its corner. Get that wrong and every object is half a voxel out of place, which
75
+ is invisible in a viewer and ruinous in a measurement.
76
+
77
+ Reading such a volume correctly means parsing all those dialects, knowing the half-voxel
78
+ rule for each, picking a pyramid level for a wanted resolution, and reading a region
79
+ given in physical units as a plain numpy block, padded where the region leaves the data,
80
+ resampled when no level matches, fast enough for a model server or a thousand cluster
81
+ workers, with retries for flaky object stores and thread caps for shared hosts. No one
82
+ package did all of that, so every tool here wrote its own reader, and the readers drifted
83
+ apart. worldarray is that reader, written once, with the rules stated and tested.
84
+
85
+ Its dependencies are `tensorstore` and `numpy`. It is read-only in this version. The
86
+ [specification](https://janeliascicomp.github.io/worldarray/spec/) is the contract it is
87
+ built to; every rule below is a test.
88
+
89
+ ## Quick start
90
+
91
+ ```python
92
+ import worldarray as wa
93
+
94
+ vol = wa.open("s3://janelia-cosem-datasets/jrc_hela-2/jrc_hela-2.zarr/recon-1/em/fibsem-uint8", level="s1")
95
+ vol.voxel_size # (8.0, 8.0, 8.0) nm, spatial axes
96
+ vol.translation # the centre of voxel 0, in nm
97
+ vol.corner # the lower corner of voxel 0
98
+ vol.shape, vol.dtype, vol.axes, vol.levels
99
+
100
+ box = ((1000.0, 2000.0, 3000.0), (1512.0, 2512.0, 3512.0)) # [begin, end) in nm, half-open
101
+ arr = vol.read(box) # numpy, z y x; a voxel is read iff its centre lies in the box
102
+ arr = vol.read(box, padding="edge") # a box past the data comes back padded, never raises
103
+ arr = vol.read(box, voxel_size=(16, 16, 16)) # resampled on the fly
104
+ arr, inside = vol.read(box, mask=True) # True where the data was
105
+
106
+ # a volume at a resolution the store does not have: the best level, resampled
107
+ six = wa.open(path, voxel_size=(6, 6, 6), on_mismatch="resample")
108
+
109
+ # one volume read onto another volume's grid, for masks, contact sites, statistics
110
+ onto = raw.read(box, voxel_size=labels.voxel_size, anchor=labels.corner)
111
+
112
+ # index space, native units: what an engine or a viewer wants
113
+ vol = wa.open(path, units=None)
114
+ vol.meta # shape, dtype, chunk_shape, axes, units, voxel_size, translation, attrs, ...
115
+ vol.ts # the tensorstore itself, C order, origin 0
116
+ vol.read_index((0, 0, 0), (64, 64, 64), padding=0)
117
+
118
+ pyr = wa.open_pyramid(path) # every level, opened on first use
119
+ pyr.select((16, 16, 16), mode="floor") # the level to read at 16 nm
120
+ ```
121
+
122
+ ## What it does
123
+
124
+ - **Opens** zarr v2, zarr v3 (sharded or not), N5 and precomputed (sharded or not) arrays
125
+ and pyramids by path, local or `s3://`, `gs://`, `http(s)://`, through tensorstore only.
126
+ Public buckets are read anonymously first, credentials only when refused; the way in is
127
+ remembered. `AWS_ENDPOINT_URL` points at S3-compatible stores.
128
+ - **Places** every array by one written rule per format (below), reads axes and units as
129
+ stored, converts only where asked (nanometres by default on spatial axes), and keeps
130
+ voxel sizes as floats, never rounded.
131
+ - **Chooses a level** by voxel size from the pyramid's own metadata, without opening the
132
+ levels, with four policies for a size no level has: error, resample, relabel (voxel `i`
133
+ stays voxel `i`, the grid rescaled), or keep the level.
134
+ - **Reads** voxel boxes or world boxes as C-contiguous numpy in native byte order, padded
135
+ with any value or the edge voxel, with an optional mask of what was data, a per-read
136
+ `transform` applied before padding (or `post_transform` after resampling), and resampling by nearest neighbour or linear
137
+ interpolation anchored where you say. Adjoining block reads agree with one read across
138
+ both.
139
+ - **Behaves on a cluster**: one shared tensorstore context per process or a capped one per
140
+ worker, retries with backoff and size-aware timeouts on transient store errors, and a
141
+ cancelled future on timeout.
142
+ - **Carries the geometry**: `Box` with `intersect`, `union`, `contains`, `grow`, `shift`,
143
+ `snap` to a grid, and the voxel indices a world box selects.
144
+
145
+ ## The placement rule
146
+
147
+ A translation is where the centre of voxel 0 is. Index `i` sits at
148
+ `translation + i * voxel_size`; voxel `i` covers half a voxel either side. That is how
149
+ OME-NGFF defines it and how Neuroglancer draws it. Dialects that store the corner are
150
+ moved half a voxel on reading:
151
+
152
+ | Stored | Means | Read as `translation` |
153
+ |---|---|---|
154
+ | OME-NGFF `translation` | centre | as is |
155
+ | COSEM `transform.translate` | centre | as is |
156
+ | `offset` beside `resolution` / `voxel_size` (`offset` missing: 0) | corner | `offset + voxel_size / 2` |
157
+ | N5 `pixelResolution` or `resolution` with `downsamplingFactors f`, no offset | BigDataViewer | `(f - 1) / 2 * base` |
158
+ | precomputed `voxel_offset` | corner | `(voxel_offset + 1/2) * resolution` |
159
+ | nothing | a plain array | voxels of 1, corner at the origin |
160
+
161
+ Axes are the store's C order; N5 and precomputed are transposed to it. Unlisted or
162
+ conflicting attributes warn; a voxel size that disagrees with the OME scale raises, since
163
+ that is how stale metadata is caught. Metadata the parser did not consume stays available
164
+ raw. The full precedence per format, the half-voxel rules, and every read behaviour are
165
+ in the [specification](https://janeliascicomp.github.io/worldarray/spec/).
166
+
167
+ ## API in brief
168
+
169
+ ```python
170
+ wa.open(path, *, level=None, voxel_size=None, level_mode="floor", on_mismatch="error",
171
+ padding=0, method="nearest", select=None, units="nanometer", context=None, retries=None,
172
+ metadata_conflicts="error", base_voxel_size=None, base_units=None, anchor=None,
173
+ transform=None, strict_units=True) -> WorldArray
174
+ wa.open_pyramid(path, ...) -> Pyramid # .names .levels .by_name() .select() .placements() .metas(): no opens needed
175
+ wa.metadata(path, level=None, units=None, open=True) -> ArrayMeta # open=False: from documents alone
176
+ wa.detect(path, missing_ok=False) -> Node # format, array or group, raw attrs
177
+ wa.open_tensorstore(path, level=None, context=None)
178
+ wa.shared_context(cache_bytes=0) ; wa.capped_context(cache_bytes=0, concurrency=1, network=True) ; wa.Retry(...)
179
+ wa.list_chunk_keys(path, separator=".") # chunk indices from keys alone, no metadata needed
180
+ wa.Box ; wa.units.TABLE
181
+ ```
182
+
183
+ `WorldArray`: `ts`, `meta`, `grid`, `shape`, `dtype`, `axes`, `voxel_size`, `translation`,
184
+ `corner`, `box`, `levels`, `level_name`, `level_path`, `source_voxel_size`, `resampled`;
185
+ `read(box, voxel_size=, padding=, method=, mask=, anchor=, transform=, post_transform=, select=, strict=)`,
186
+ `read_index(begin, end, padding=, mask=, select=, transform=)`, `index_box(box)`,
187
+ `chunks_covering(begin, end)`, `list_chunks()`, `reopen(context=)`.
188
+
189
+ A box is a `(begin, end)` pair of floats in your units, half-open per axis, over the
190
+ spatial axes or every axis; any object with `.begin`/`.end` or `.offset`/`.shape` also
191
+ works. There is no `offset` attribute, because that word means the corner in some dialects
192
+ and the centre in others: `translation` and `corner` are the two names for the two things.
193
+
194
+ ## Origins
195
+
196
+ The vocabulary, an array that knows its `voxel_size`, where it sits and its axis names, and
197
+ is read by a box in world units, follows funlib.persistence's `Array`, which many of the
198
+ tools this serves were built on. The placement rules were consolidated from the readers
199
+ those tools had each written, in cellmap-flow, cellmap-analyze, mesh-n-bone and
200
+ chunkmirage, whose conventions document and conformance tests seeded this one; their
201
+ authors' sessions trialled every change here on their own data. The voxel-centre
202
+ convention is OME-NGFF's and ITK's, and is what Neuroglancer draws. tensorstore does the
203
+ work underneath.
204
+
205
+ ## Development
206
+
207
+ ```bash
208
+ uv sync --group dev --group docs
209
+ uv run pytest -q
210
+ uv run ruff check src tests && uv run ruff format src tests
211
+ uv run mkdocs serve
212
+ ```
213
+
214
+ BSD-3-Clause, Howard Hughes Medical Institute.
@@ -0,0 +1,14 @@
1
+ worldarray/__init__.py,sha256=CXIe8eEdYb9nv4byRBf133-_6UOm365QSIDJncQAfHE,1225
2
+ worldarray/array.py,sha256=5GHJRWCcVe0A_PR0pVDNXz6j5IQsOgBl63HvRCG4QBM,40394
3
+ worldarray/context.py,sha256=Q1zULJev92fKI9NbYKjGQvbHsnvx_qsAXDqk-tA5otg,2115
4
+ worldarray/geometry.py,sha256=ByQu8WrcUydKU2eDsugKwvx1LpQbETmhutfy5mv9inI,7449
5
+ worldarray/levels.py,sha256=_bIgKWdAl_5aM5jQFpF79RZfNUwZ8-ggXMtMZw-L6Es,5953
6
+ worldarray/placement.py,sha256=jaTfwAZEZEOJF8l1Tz-FNf-djmkWN1lvKUHj7dbnpRg,31664
7
+ worldarray/resample.py,sha256=nAls-m0vchrsua0q_1yx1K9-djlAnWtkgokCfXqbpIQ,10411
8
+ worldarray/retry.py,sha256=Uw4YP-tPwtg0tgpBzY0ux4F5vehdTZTp0385QH_vvrk,2766
9
+ worldarray/store.py,sha256=sqga12h5jmR-iga1I5X0HmRFd61ySmzePAqXNSoEsu4,17157
10
+ worldarray/units.py,sha256=Vky7No6aibQ4jDP_iSYFon59Q4vJ6Ft0wlXJpg6DuMk,3139
11
+ worldarray-0.1.0.dist-info/METADATA,sha256=UxiNwgPfHNwvhZebXNDCBGyJIq3ZhmhR9tweVSEbGsA,11877
12
+ worldarray-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
13
+ worldarray-0.1.0.dist-info/licenses/LICENSE,sha256=NsviVkqc3M7YUSeSNmisDSg3e3L8S4ofeIjthWm8pvk,1518
14
+ worldarray-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Howard Hughes Medical Institute
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.