Skip to content

Commit f51a54b

Browse files
authored
feat: pretty tree view (#29)
* wip * cleaner code * feat: add prefetching for plate hierarchy and rich representation for ZarrGroup * fix: update OME-zarr icons for consistency in tree representation * fix: add LabelsGroup to exports in __all__ for consistency * fix: update tree icons for improved representation of Zarr nodes * typos
1 parent bcd0087 commit f51a54b

8 files changed

Lines changed: 856 additions & 5 deletions

File tree

docs/index.md

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ write.v05.Bf2RawBuilder(...)
278278
### CLI validation
279279

280280
The CLI command provides a quick way to validate any zarr store as an OME-Zarr
281-
store. Here, "store" here refers to any URI (local path, http(s) url, or s3 url.
281+
store. Here, "store" refers to any URI (local path, http(s) url, or s3 url.
282282

283283
!!!important
284284
Requires `fsspec`. install with `pip install yaozarrs[io]`
@@ -301,9 +301,44 @@ store. Here, "store" here refers to any URI (local path, http(s) url, or s3 url
301301
Type: Image
302302
```
303303

304+
### CLI tree view
305+
306+
Visualize the hierarchy of any OME-Zarr store with `yaozarrs tree`:
307+
308+
=== "with uvx"
309+
310+
```sh
311+
uvx "yaozarrs[io]" tree https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.5/idr0062A/6001240_labels.zarr
312+
```
313+
314+
=== "from installed package"
315+
316+
```sh
317+
yaozarrs tree https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.5/idr0062A/6001240_labels.zarr
318+
```
319+
320+
```
321+
🖼️ 6001240_labels.zarr
322+
├── zarr.json <- v05.Image
323+
├── 📦 0 (uint16, (2, 236, 275, 271))
324+
├── 📦 1 (uint16, (2, 236, 137, 135))
325+
├── 📦 2 (uint16, (2, 236, 68, 67))
326+
└── 🏷️ labels
327+
├── zarr.json <- v05.LabelsGroup
328+
└── 🖼️ 0
329+
├── zarr.json <- v05.LabelImage
330+
├── 📦 0 (int8, (1, 236, 275, 271))
331+
├── 📦 1 (int8, (1, 236, 137, 135))
332+
├── 📦 2 (int8, (1, 236, 68, 67))
333+
└── 📦 3 (int8, (1, 236, 34, 33))
334+
```
335+
336+
Use `--depth` / `-d` to limit traversal depth, and `--max-per-level` / `-n` to
337+
cap the number of children shown at each level.
338+
304339
### Loading OME-Zarr Stores
305340

306-
[`yaozarrs.open_group`][] teturns a small wrapper around a zarr group with
341+
[`yaozarrs.open_group`][] returns a small wrapper around a zarr group with
307342
minimal functionality: [`yaozarrs.ZarrGroup`][]. Requires the [`yaozarrs[io]`
308343
extra](./installation.md#structural-validation) to support remote URIs. This
309344
class is used behind the scenes for structural validation, but can also be used
@@ -324,6 +359,13 @@ child = group["0"] # (2)!
324359
2. Access arrays and sub-groups using standard dictionary-like syntax. Returns
325360
[`ZarrArray`][yaozarrs._zarr.ZarrArray] or [`ZarrGroup`][yaozarrs._zarr.ZarrGroup]
326361

362+
You can also get a tree view of the hierarchy programmatically with
363+
[`ZarrGroup.tree()`][yaozarrs._zarr.ZarrGroup.tree]:
364+
365+
```python
366+
print(group.tree(depth=2))
367+
```
368+
327369
#### Access array data
328370

329371
This package does *not* depend on `zarr` or `tensorstore`, even for validating
@@ -363,7 +405,7 @@ Zarr itself is a *specification* with multiple implementations: There are many
363405
ways to read and write Zarr stores (e.g. `zarr-python`, `tensorstore`,
364406
`acquire-zarr`, `zarrs`, etc..) and **yaozarrs makes no assumptions about which
365407
implementation you may want to use**. Similarly, OME NGFF is a *metadata
366-
sepcification*, defining what JSON documents and hierarchy structure must look
408+
specification*, defining what JSON documents and hierarchy structure must look
367409
like.
368410

369411
1. At its core, **yaozarrs provides pydantic models for OME-Zarr metadata

docs/ome_zarr_guide.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ icon: material/book-open-variant
33
title: Guide to OME-Zarr
44
---
55

6-
# Yaozzars Guide to OME-Zarr
6+
# Yaozarrs Guide to OME-Zarr
77

88
<script type="module" src="/javascripts/ome_explorer.js"></script>
99

@@ -56,7 +56,7 @@ title: Guide to OME-Zarr
5656
spec takes precedence!
5757

5858
OME-Zarr is a file format specification used by the bioimaging community for
59-
storing multi-dimensional data. It is a "meta-specication", based on the
59+
storing multi-dimensional data. It is a "meta-specification", based on the
6060
pre-existing Zarr format, which is designed for the storage of chunked,
6161
compressed, N-dimensional arrays. OME-Zarr **extends** Zarr by adding metadata
6262
conventions specific to bioimaging, making it easier to store and share complex

src/yaozarrs/_cli.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,33 @@ def validate_command(args: argparse.Namespace) -> int:
6262
return 2
6363

6464

65+
def tree_command(args: argparse.Namespace) -> int:
66+
"""Execute the tree subcommand.
67+
68+
Parameters
69+
----------
70+
args : argparse.Namespace
71+
Parsed command-line arguments
72+
73+
Returns
74+
-------
75+
int
76+
Exit code (0 for success, 2 for errors)
77+
"""
78+
from yaozarrs._tree import print_tree
79+
80+
try:
81+
group = open_group(args.path)
82+
print_tree(group, depth=args.depth, max_per_level=args.max_per_level)
83+
return 0
84+
except ImportError as e: # pragma: no cover
85+
print(f"ImportError: {e}", file=sys.stderr)
86+
return 2
87+
except Exception as e:
88+
print(f"✗ Error: {e}", file=sys.stderr)
89+
return 2
90+
91+
6592
def main(argv: list[str] | None = None) -> int:
6693
"""Main entry point for the CLI.
6794
@@ -98,6 +125,32 @@ def main(argv: list[str] | None = None) -> int:
98125
)
99126
validate_parser.set_defaults(func=validate_command)
100127

128+
# Tree subcommand
129+
tree_parser = subparsers.add_parser(
130+
"tree",
131+
help="Display the hierarchy of an OME-Zarr store as a tree",
132+
)
133+
tree_parser.add_argument(
134+
"path",
135+
help="Path or URI to the OME-Zarr store",
136+
)
137+
tree_parser.add_argument(
138+
"-d",
139+
"--depth",
140+
type=int,
141+
default=None,
142+
help="Maximum depth to traverse (default: unlimited)",
143+
)
144+
tree_parser.add_argument(
145+
"-n",
146+
"--max-per-level",
147+
type=int,
148+
default=None,
149+
dest="max_per_level",
150+
help="Maximum children to show per level (default: unlimited)",
151+
)
152+
tree_parser.set_defaults(func=tree_command)
153+
101154
# Parse arguments
102155
args = parser.parse_args(argv)
103156

0 commit comments

Comments
 (0)