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.
- worldarray/__init__.py +43 -0
- worldarray/array.py +935 -0
- worldarray/context.py +53 -0
- worldarray/geometry.py +173 -0
- worldarray/levels.py +147 -0
- worldarray/placement.py +739 -0
- worldarray/resample.py +229 -0
- worldarray/retry.py +76 -0
- worldarray/store.py +427 -0
- worldarray/units.py +77 -0
- worldarray-0.1.0.dist-info/METADATA +214 -0
- worldarray-0.1.0.dist-info/RECORD +14 -0
- worldarray-0.1.0.dist-info/WHEEL +4 -0
- worldarray-0.1.0.dist-info/licenses/LICENSE +28 -0
|
@@ -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,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.
|