Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
a109ddf
refactor: move morton code logic to a higher level
william-silversmith Dec 8, 2025
69cfd87
refactor: remove py2.7 (object)
william-silversmith Dec 8, 2025
a6d880c
refactor: whitespace
william-silversmith Dec 8, 2025
b513ed6
refactor: drop meta dependency in ShardReader
william-silversmith Dec 9, 2025
557c07f
wip: add skeleton of annotation reader
william-silversmith Dec 9, 2025
80af553
wip: get something barely running
william-silversmith Dec 9, 2025
33b0f37
fix: missing import
william-silversmith Dec 9, 2025
36e7bf8
wip: getting closer to something working...
william-silversmith Dec 10, 2025
2404c3c
feat: reading points, but still seems broken
william-silversmith Dec 10, 2025
cddaaad
fix: add secrets
william-silversmith Dec 10, 2025
0599323
fix: also decode properties
william-silversmith Dec 10, 2025
67a5658
fix: concat properties
william-silversmith Dec 10, 2025
c3ab32d
fix: finally decoding properly for point clouds
william-silversmith Dec 10, 2025
6f6ed94
refactor: return spatialannotation type
william-silversmith Dec 10, 2025
d32be19
feat: add fetching by label
william-silversmith Dec 10, 2025
050999d
fix: sharded download working for spatial
william-silversmith Dec 10, 2025
623e3ea
fix: clamp bounding box for higher mips
william-silversmith Dec 10, 2025
1d4a755
fix: decoded annotation was not casted properly
william-silversmith Dec 10, 2025
40ab11f
wip: going back and forth between Forrest's impl and mine
william-silversmith Dec 15, 2025
3eaf440
fix: cropping maybe works now
william-silversmith Dec 15, 2025
aed0da4
fix: several issues
william-silversmith Dec 15, 2025
e22b74c
feat: get ids working
william-silversmith Dec 16, 2025
8deb4a2
feat: add caching to ids
william-silversmith Dec 16, 2025
aff8d6b
feat: add get_all
william-silversmith Dec 16, 2025
9798cab
fix: remove debug statement
william-silversmith Dec 16, 2025
f2b4da0
feat: support multiple points
william-silversmith Dec 16, 2025
bc808f9
refactor: remove some cruft from crop_mask
william-silversmith Dec 16, 2025
3297442
fix: correct invocation
william-silversmith Dec 16, 2025
18baec7
refactor: change crop_mask to _crop_mask
william-silversmith Dec 16, 2025
8963e65
docs: show how to use PrecomputedAnnotationSource
william-silversmith Dec 16, 2025
848b1d0
feat: add slice notation for bbox
william-silversmith Dec 16, 2025
c88a8fd
fix: ensure only bbox is allowed for slice notation
william-silversmith Dec 16, 2025
7e3bd4d
feat: add cloudvolume.create, rank, dimensions
william-silversmith Dec 16, 2025
3bbbeb7
fix: circular dependency
william-silversmith Dec 16, 2025
047a85f
refactor+docs: make some methods private, add some descriptions
william-silversmith Dec 16, 2025
59bab96
feat: add get_by_relationship
william-silversmith Dec 16, 2025
12e964f
perf: faster get_all
william-silversmith Dec 17, 2025
2889bf2
feat: add caching to unsharded spatial
william-silversmith Dec 17, 2025
17b18c1
feat: add caching to get_by_id unsharded
william-silversmith Dec 17, 2025
9feba5e
feat: add support for polylines c/o neuroglancer python code
william-silversmith Dec 17, 2025
3688b30
refactor: make interface closer to reader interface
william-silversmith Dec 17, 2025
5daa7bc
docs: add licenses for ng and precomputed_python
william-silversmith Dec 17, 2025
3528800
docs: add docstrings to annotation source methods
william-silversmith Dec 17, 2025
6c327ef
fix: better sharding check
william-silversmith Dec 17, 2025
12f07a3
feat: add caching to get_by_relationship
william-silversmith Dec 17, 2025
60700ff
docs: added credits for annotations services
william-silversmith Dec 17, 2025
1c379b3
refactor+fix: unify dtype into metadata and use padded properties code
william-silversmith Dec 18, 2025
c9aafcd
fix: change default mip to finest
william-silversmith Dec 18, 2025
f4106a5
fix: mip was still set to coarsest
william-silversmith Dec 18, 2025
612b524
fix: property enum calculation
william-silversmith Dec 18, 2025
46f5f89
wip: summary function
william-silversmith Dec 18, 2025
cbc5d36
fix: make annotation enum representation work in different configurat…
william-silversmith Jan 5, 2026
fd2d664
feat: add split_by_id to MultiLabelAnnotation
william-silversmith Jan 12, 2026
3995cc8
feat: added specialized classes for each annotation type
william-silversmith Jan 12, 2026
6da5928
feat: add viewer for points
william-silversmith Jan 12, 2026
484aaf9
feat: add bounding box viewer
william-silversmith Jan 12, 2026
3ed3d6a
fix: not covering the full grid
william-silversmith Jan 12, 2026
0d65792
feat: add len to geometry
william-silversmith Jan 12, 2026
a4081e7
refactor: remove magic get
william-silversmith Jan 12, 2026
86ff0b4
refactor: remove dead commented code
william-silversmith Jan 12, 2026
44ac18a
docs: credit forrest collman and jbms
william-silversmith Jan 12, 2026
4489899
refactor: change cloudvolume.open to cloudvolume.from_cloudpath
william-silversmith Jan 12, 2026
c38e63e
refactor: also change import
william-silversmith Jan 12, 2026
f3294b3
docs: change open to from_cloudpath
william-silversmith Jan 12, 2026
e3ebaf0
refactor: remove comments
william-silversmith Jan 12, 2026
0f30003
feat: make pandas output use enum information
william-silversmith Jan 13, 2026
6f9d318
fix: make properties enum work for LabelAnnotations too
william-silversmith Jan 13, 2026
94c0944
fix: undefined variable
william-silversmith Jan 13, 2026
e0f10cf
fix: incorrect type annotation
william-silversmith Jan 13, 2026
6e06cb1
fix: misalignment in bounding box cutout
william-silversmith Jan 14, 2026
5c9b4e7
fix: ensure unit is propagated in Bbox.from_slices
william-silversmith Jan 14, 2026
1b57e9d
perf: don't crop if working with the entire volume
william-silversmith Jan 14, 2026
f13e450
feat: print axes using known dimension names
william-silversmith Jan 14, 2026
751be49
fix: axis names and column for multilabel
william-silversmith Jan 14, 2026
2fd8454
fix: propagate enum and dimension info
william-silversmith Jan 14, 2026
1ad6763
fix: ensure SpecificLabelAnnotation is always up-to-date
william-silversmith Jan 14, 2026
a1a145d
fix: add better error for relationships
william-silversmith Jan 14, 2026
73148ec
docs: add info about summary function
william-silversmith Jan 14, 2026
f15d3c1
fix: missing dimensions in get_by_relationship
william-silversmith Jan 14, 2026
13240bf
test: basic tests for annotation reader
william-silversmith Jan 14, 2026
1fb0f65
fix: allow selecting get_all by mip
william-silversmith Jan 14, 2026
b14f03b
fix: incorrect usage of dimensions in split_by_id
william-silversmith Jan 14, 2026
fa06c77
test: basic test for split by id
william-silversmith Jan 14, 2026
f628816
docs: note that the h01 example was modified
william-silversmith Jan 14, 2026
275877d
fix: ensure orjson serialization behavior matches
william-silversmith Jan 14, 2026
7da6a96
fix: allow cloudpath to be None for ShardReader
william-silversmith Jan 14, 2026
ee0c629
fix: ensure graphene uses new ShardReader interface
william-silversmith Jan 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# CloudVolume: IO for Neuroglancer Datasets

```python
from cloudvolume import CloudVolume
from cloudvolume import CloudVolume, from_cloudpath, Bbox

vol = CloudVolume('gs://mylab/mouse/image', parallel=True, progress=True)
image = vol[:,:,:] # Download a whole image stack into a numpy array from the cloud
Expand All @@ -12,6 +12,9 @@ vol[:,:,:] = image # Upload an entire image stack from a numpy array to the clou
label = 1
mesh = vol.mesh.get(label)
skel = vol.skeleton.get(label)

asrc = from_cloudpath("gs://mylab/mouse/annotation/synapses")
annotations = asrc.get(label)
```

CloudVolume is a serverless Python client for random access reading and writing of [Neuroglancer](https://github.com/google/neuroglancer/) volumes in "[Precomputed](https://github.com/google/neuroglancer/tree/master/src/datasource/precomputed#readme)" format, a set of representations for arbitrarily large volumetric images, meshes, and skeletons. CloudVolume is typically paired with [Igneous](https://github.com/seung-lab/igneous), a Kubernetes compatible system for generating image hierarchies, meshes, skeletons, and other dependency free jobs that can be applied to petavoxel scale images.
Expand Down Expand Up @@ -344,6 +347,22 @@ skel = skel.average_smoothing(3) # rolling average, n=3
skel1 == skel2 # check if contents of internal arrays match
Skeleton.equivalent(skel1, skel2) # ...even if there are differences like differently numbered edges

# Annotations
import cloudvolume

asrc = cloudvolume.from_cloudpath("gs://mybucket/retina/annotations", cache=True, progress=True, mip=3)

print(asrc.summary()) # get basic info about annotation set

annotations = asrc.get([1,2,3,]) # tries to interpret input to mean get_by_id or get_by_bbox
annotations = asrc.get_by_id([1,2,3,])
annotations = asrc.get(bbox, mip=3)
annotations = asrc.get_all()
annotations = asrc.get_by_bbox(bbox, mip=3)
annotations = asrc[bbox] # can use slice notation
annotations = asrc.get_by_relationship("synapses", 1231)
ids = asrc.ids()

# Parallel Operation
vol = CloudVolume('gs://mybucket/retina/image', parallel=True) # Use all cores
vol.parallel = 4 # e.g. any number > 1, use this many cores
Expand Down Expand Up @@ -709,7 +728,7 @@ Python 2.7 is no longer supported by CloudVolume. Updated versions of `pip` will

Thank you to everyone that has contributed past or current to CloudVolume or the ecosystem it serves. We love you!

Jeremy Maitin-Shepard created [Neuroglancer](https://github.com/google/neuroglancer) and defined the Precomputed format. Yann Leprince provided a [pure Python codec](https://github.com/HumanBrainProject/neuroglancer-scripts) for the compressed_segmentation format. Jeremy Maitin-Shepard and Stephen Plaza created C++ code defining the compression and decompression (respectively) protocol for [compressed_segmentation](https://github.com/janelia-flyem/compressedseg). Peter Lindstrom et al. created [the fpzip algorithm](https://computation.llnl.gov/projects/floating-point-compression), and contributed a C++ implementation and advice. Nico Kemnitz adapted our data to fpzip using the "Kempression" protocol (we named it, not him). Dan Bumbarger contributed code and information helpful for getting CloudVolume working on Windows. Fredrik Kihlander's [pure python implementation](https://github.com/wc-duck/pymmh3) of murmurhash3 and [Austin Appleby](https://github.com/aappleby/smhasher) developed murmurhash3 which is necessary for the sharded format. Ben Falk advocated for and did the bulk of the work on brotli compression. Some of the ideas in CloudVolume are based on work by Jingpeng Wu in [BigArrays.jl](https://github.com/seung-lab/BigArrays.jl). Sven Dorkenwald, Manuel Castro, and Akhilesh Halageri contributed advice and code towards implementing the graphene interface. Oluwaseun Ogedengbe contributed documentation for the sharded format. Eric Perlman wrote the reader for Neuroglancer Multi-LOD meshes. Ignacio Tartavull and William Silversmith wrote the initial version of CloudVolume.
Jeremy Maitin-Shepard created [Neuroglancer](https://github.com/google/neuroglancer) and defined the Precomputed format. Yann Leprince provided a [pure Python codec](https://github.com/HumanBrainProject/neuroglancer-scripts) for the compressed_segmentation format. Jeremy Maitin-Shepard and Stephen Plaza created C++ code defining the compression and decompression (respectively) protocol for [compressed_segmentation](https://github.com/janelia-flyem/compressedseg). Peter Lindstrom et al. created [the fpzip algorithm](https://computation.llnl.gov/projects/floating-point-compression), and contributed a C++ implementation and advice. Nico Kemnitz adapted our data to fpzip using the "Kempression" protocol (we named it, not him). Dan Bumbarger contributed code and information helpful for getting CloudVolume working on Windows. Fredrik Kihlander's [pure python implementation](https://github.com/wc-duck/pymmh3) of murmurhash3 and [Austin Appleby](https://github.com/aappleby/smhasher) developed murmurhash3 which is necessary for the sharded format. Ben Falk advocated for and did the bulk of the work on brotli compression. Some of the ideas in CloudVolume are based on work by Jingpeng Wu in [BigArrays.jl](https://github.com/seung-lab/BigArrays.jl). Sven Dorkenwald, Manuel Castro, and Akhilesh Halageri contributed advice and code towards implementing the graphene interface. Oluwaseun Ogedengbe contributed documentation for the sharded format. Eric Perlman wrote the reader for Neuroglancer Multi-LOD meshes. Forrest Collman and Jeremy Maitin-Shepard both wrote the versions of the annotations service that was then adapted to CloudVolume by William Silversmith. Ignacio Tartavull and William Silversmith wrote the initial version of CloudVolume.

## Citation
Please cite the Igneous paper if you used this package in your research:
Expand Down
9 changes: 7 additions & 2 deletions cloudvolume/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
skel = vol.skeletons.get(label)
"""

from .cloudvolume import CloudVolume, register_plugin
from .cloudvolume import CloudVolume, from_cloudpath, register_plugin

from .connectionpools import ConnectionPool
from .lib import Bbox, Vec
Expand All @@ -68,15 +68,20 @@
__version__ = '12.8.0'

# Register plugins
from .datasource.precomputed import register as register_precomputed
from .datasource.precomputed import (
register as register_precomputed,
register_annotation as register_precomputed_annotation,
)
from .datasource.graphene import register as register_graphene
from .datasource.n5 import register as register_n5
from .datasource.zarr import register as register_zarr
from .datasource.zarr2 import register as register_zarr2
from .datasource.zarr3 import register as register_zarr3

register_precomputed()
register_precomputed_annotation()
register_graphene()

register_n5()
register_zarr()
register_zarr2()
Expand Down
32 changes: 26 additions & 6 deletions cloudvolume/cloudvolume.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import sys
import time
from typing import Optional, Union, Tuple
from typing import Optional, Union, Tuple, Any

import multiprocessing as mp
import numpy as np
from tqdm import tqdm

from cloudfiles import CloudFiles
from cloudfiles.paths import normalize

from .exceptions import UnsupportedFormatError, DimensionError, InfoUnavailableError
Expand All @@ -21,9 +22,13 @@
except AttributeError:
INTERACTIVE = bool(sys.flags.interactive)

REGISTERED_PLUGINS = {}
REGISTERED_IMAGE_PLUGINS = {}
def register_plugin(key, creation_function):
REGISTERED_PLUGINS[key.lower()] = creation_function
REGISTERED_IMAGE_PLUGINS[key.lower()] = creation_function

REGISTERED_ANNOTATION_PLUGINS = {}
def register_annotation_plugin(key, creation_function):
REGISTERED_ANNOTATION_PLUGINS[key.lower()] = creation_function

def compute_num_threads(num_threads:ParallelType) -> int:
if isinstance(num_threads, bool):
Expand Down Expand Up @@ -268,9 +273,9 @@ def __new__(cls,

def init(cloudpath):
path = strict_extract(cloudpath)
if path.format in REGISTERED_PLUGINS:
if path.format in REGISTERED_IMAGE_PLUGINS:
kwargs["cloudpath"] = normalize(cloudpath)
return REGISTERED_PLUGINS[path.format](**kwargs)
return REGISTERED_IMAGE_PLUGINS[path.format](**kwargs)
else:
raise UnsupportedFormatError(
"Unknown format {}".format(path.format)
Expand All @@ -287,7 +292,6 @@ def init(cloudpath):
else:
raise err


@classmethod
def create_new_info(cls, *args, **kwargs):
from .frontends import CloudVolumePrecomputed
Expand Down Expand Up @@ -413,3 +417,19 @@ def from_numpy(cls,
# save the numpy array
vol[:,:,:] = arr
return vol

def from_cloudpath(cloudpath:str, *args, **kwargs) -> Any:
"""Create the appropriate object for the given cloudpath."""
path = strict_extract(cloudpath)

if path.format != "precomputed":
return CloudVolume(cloudpath, *args, **kwargs)

info = CloudFiles(cloudpath).get_json("info")
kwargs["info"] = info

if info["@type"] == "neuroglancer_annotations_v1":
return REGISTERED_ANNOTATION_PLUGINS['precomputed'](cloudpath, *args, **kwargs)

return CloudVolume(cloudpath, *args, **kwargs)

2 changes: 1 addition & 1 deletion cloudvolume/datasource/graphene/mesh/sharded.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(self, mesh_meta, cache, config, readonly):
self.readers = {}
for level, sharding in self.meta.info['sharding'].items(): # { level: std sharding, ... }
spec = ShardingSpecification.from_dict(sharding)
self.readers[int(level)] = GrapheneShardReader(self.meta, self.cache, spec)
self.readers[int(level)] = GrapheneShardReader(self.meta.cloudpath, self.cache, spec)

def initial_path(self, level):
return self.meta.join(self.meta.mesh_path, self.meta.sharded_mesh_dir, str(level))
Expand Down
29 changes: 28 additions & 1 deletion cloudvolume/datasource/precomputed/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from typing import Optional, Union

from .annotation import PrecomputedAnnotationSource
from .image import PrecomputedImageSource
from .metadata import PrecomputedMetadata
from .mesh import PrecomputedMeshSource
from .skeleton import PrecomputedSkeletonSource

from .. import get_cache_path
from ...cloudvolume import (
register_plugin, SharedConfiguration,
register_plugin, register_annotation_plugin,
SharedConfiguration,
CompressType, ParallelType, CacheType,
SecretsType
)
Expand Down Expand Up @@ -116,6 +118,31 @@ def create_precomputed(

return cv

def create_precomputed_annotation(
cloudpath:str,
cache:CacheType = False,
info:Optional[dict] = None,
mip:int = -1,
progress:bool = False,
secrets:SecretsType = None,
use_https:bool = False,
) -> PrecomputedAnnotationSource:
"""
Note: for annotations, mips are coarsest to finest, so -1
means pick the finest (i.e. the scientifically useful one).
"""
return PrecomputedAnnotationSource(
cloudpath,
cache=cache,
info=info,
mip=mip,
progress=progress,
secrets=secrets,
use_https=use_https,
)

def register_annotation():
register_annotation_plugin('precomputed', create_precomputed_annotation)

def register():
register_plugin('precomputed', create_precomputed)
Loading