Skip to content

Commit 3b07223

Browse files
authored
Add mag from existing zarr array (#1151)
* Add first implementation for * Update changelog.
1 parent 7e554c5 commit 3b07223

File tree

4 files changed

+71
-2
lines changed

4 files changed

+71
-2
lines changed

webknossos/Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ For upgrade instructions, please check the respective _Breaking Changes_ section
1515
### Breaking Changes
1616

1717
### Added
18+
- Added `add_mag_from_zarrarray` to `Layer` class, to add existing Zarr arrays as a mag of a layer. [#1151](https://github.com/scalableminds/webknossos-libs/pull/1151)
1819

1920
### Changed
2021

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from pathlib import Path
2+
3+
import webknossos as wk
4+
5+
OUTPUT_PATH = Path(__file__).parent.parent / "testoutput"
6+
ARRAY_PATH = (
7+
Path(__file__).parent.parent / "testdata" / "simple_zarr3_dataset" / "color" / "1"
8+
)
9+
10+
11+
def main() -> None:
12+
ds = wk.Dataset(OUTPUT_PATH, voxel_size=(10, 10, 10))
13+
layer = ds.add_layer("color", category="color", data_format="zarr3")
14+
15+
layer.add_mag_from_zarrarray(1, ARRAY_PATH)
16+
17+
18+
if __name__ == "__main__":
19+
main()

webknossos/webknossos/dataset/layer.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from upath import UPath
1515

1616
from ..geometry import Mag, NDBoundingBox, Vec3Int, Vec3IntLike
17-
from ._array import ArrayException, BaseArray, DataFormat
17+
from ._array import ArrayException, BaseArray, DataFormat, ZarritaArray
1818
from ._downsampling_utils import (
1919
calculate_default_coarsest_mag,
2020
calculate_mags_to_downsample,
@@ -44,6 +44,7 @@
4444
get_executor_for_args,
4545
is_fs_path,
4646
is_remote_path,
47+
movetree,
4748
named_partial,
4849
rmtree,
4950
strip_trailing_slash,
@@ -753,6 +754,50 @@ def add_fs_copy_mag(
753754

754755
return mag
755756

757+
def add_mag_from_zarrarray(
758+
self,
759+
mag: Union[int, str, list, tuple, np.ndarray, Mag],
760+
path: PathLike,
761+
move: bool = False,
762+
extend_layer_bounding_box: bool = True,
763+
) -> MagView:
764+
"""
765+
Copies the data at `path` to the current layer of the dataset
766+
via the filesystem and adds it as `mag`. When `move` flag is set
767+
the array is moved, otherwise a copy of the zarrarray is created.
768+
"""
769+
self.dataset._ensure_writable()
770+
source_path = Path(path)
771+
772+
try:
773+
ZarritaArray.open(source_path)
774+
except ArrayException as e:
775+
raise ValueError(
776+
"The given path does not lead to a valid Zarr Array: "
777+
) from e
778+
else:
779+
mag = Mag(mag)
780+
self._assert_mag_does_not_exist_yet(mag)
781+
if move:
782+
movetree(source_path, self.path / str(mag))
783+
else:
784+
copytree(source_path, self.path / str(mag))
785+
786+
mag_view = self.add_mag_for_existing_files(mag)
787+
788+
if extend_layer_bounding_box:
789+
# assumption: the topleft of the bounding box is still the same, the size might differ
790+
# axes of the layer and the zarr array provided are the same
791+
zarray_size = (
792+
mag_view.info.shape[mag_view.info.dimension_names.index(axis)]
793+
for axis in self.bounding_box.axes
794+
if axis != "c"
795+
)
796+
size = self.bounding_box.size.pairmax(zarray_size)
797+
self.bounding_box = self.bounding_box.with_size(size)
798+
799+
return mag_view
800+
756801
def _create_dir_for_mag(
757802
self, mag: Union[int, str, list, tuple, np.ndarray, Mag]
758803
) -> None:

webknossos/webknossos/utils.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from multiprocessing import cpu_count
1414
from os.path import relpath
1515
from pathlib import Path
16-
from shutil import copyfileobj
16+
from shutil import copyfileobj, move
1717
from typing import (
1818
Any,
1919
Callable,
@@ -346,6 +346,10 @@ def _append(path: Path, parts: Tuple[str, ...]) -> Path:
346346
copyfileobj(in_file, out_file)
347347

348348

349+
def movetree(in_path: Path, out_path: Path) -> None:
350+
move(in_path, out_path)
351+
352+
349353
K = TypeVar("K") # key
350354
V = TypeVar("V") # value
351355
C = TypeVar("C") # cache

0 commit comments

Comments
 (0)