Skip to content

Commit 890fb1a

Browse files
committed
Add initial drop_t_dimension task
1 parent d4d09e8 commit 890fb1a

File tree

3 files changed

+204
-0
lines changed

3 files changed

+204
-0
lines changed

examples/run_drop_t_dimension.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""Dev script to test the Drop T dimension task."""
2+
from fractal_helper_tasks.drop_t_dimension import drop_t_dimension
3+
4+
input_paths = [
5+
"/Users/joel/Desktop/dyn_CHX_pos1_mmIntOrg_121z_0-2um_640-1000ms-200g_561-1000ms-200g__488-1000ms-200g_405-100ms-200g_11.zarr"
6+
]
7+
output_path = ""
8+
component = "0"
9+
10+
drop_t_dimension(
11+
input_paths=input_paths,
12+
output_path=output_path,
13+
component=component,
14+
metadata={},
15+
suffix="no_T",
16+
overwrite_input=False,
17+
)

src/fractal_helper_tasks/__FRACTAL_MANIFEST__.json

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,59 @@
131131
"mem": 1000
132132
},
133133
"docs_info": "Workaround task to manually change the hard-coded metadata components\nA fractal workflow sets them to the mip.zarr components after running the\nmaximum intensity projection task. This resets them to the 3D components."
134+
},
135+
{
136+
"name": "Drop T dimension",
137+
"executable": "drop_t_dimension.py",
138+
"input_type": "zarr",
139+
"output_type": "zarr",
140+
"meta": {
141+
"cpus_per_task": 2,
142+
"mem": 8000
143+
},
144+
"docs_info": "Drops singleton t dimension.",
145+
"args_schema": {
146+
"title": "DropTDimension",
147+
"type": "object",
148+
"properties": {
149+
"input_paths": {
150+
"title": "Input Paths",
151+
"type": "array",
152+
"items": {
153+
"type": "string"
154+
},
155+
"description": "This parameter is not used by this task. This task only supports a single input path. (standard argument for Fractal tasks, managed by Fractal server)."
156+
},
157+
"output_path": {
158+
"title": "Output Path",
159+
"type": "string",
160+
"description": "Path were the output of this task is stored. Example: `\"/some/path/\"` => puts the new OME-Zarr file in that folder. (standard argument for Fractal tasks, managed by Fractal server)."
161+
},
162+
"component": {
163+
"title": "Component",
164+
"type": "string",
165+
"description": "Path to the OME-Zarr image in the OME-Zarr plate that is processed. Component is typically changed by the `copy_ome_zarr` task before, to point to a new mip Zarr file. Example: `\"some_plate_mip.zarr/B/03/0\"`. (standard argument for Fractal tasks, managed by Fractal server)."
166+
},
167+
"metadata": {
168+
"title": "Metadata",
169+
"type": "object",
170+
"description": "Dictionary containing metadata about the OME-Zarr. This task requires the key `copy_ome_zarr` to be present in the metadata (as defined in `copy_ome_zarr` task). (standard argument for Fractal tasks, managed by Fractal server)."
171+
},
172+
"suffix": {
173+
"title": "Suffix",
174+
"default": "no_T",
175+
"type": "string",
176+
"description": "Suffix to be used for the new Zarr image. If overwrite_input is True, this file is only temporary."
177+
}
178+
},
179+
"required": [
180+
"input_paths",
181+
"output_path",
182+
"component",
183+
"metadata"
184+
],
185+
"additionalProperties": false
186+
}
134187
}
135188
],
136189
"has_args_schemas": true,
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Copyright 2024 (C) BioVisionCenter, University of Zurich
2+
#
3+
# Original authors:
4+
# Joel Lüthi <[email protected]>
5+
#
6+
# This file is derived from a Fractal task core task developed by
7+
# Tommaso Comparin & Marco Franzon
8+
"""Task to remove singelton T dimension from an OME-Zarr."""
9+
import logging
10+
from pathlib import Path
11+
from typing import Any, Sequence
12+
13+
import dask.array as da
14+
import zarr
15+
from fractal_tasks_core.ngff import load_NgffImageMeta
16+
from fractal_tasks_core.pyramids import build_pyramid
17+
from pydantic.decorator import validate_arguments
18+
19+
logger = logging.getLogger(__name__)
20+
21+
22+
def get_attrs_without_t(zarr_url: str):
23+
"""
24+
Generate zattrs without the t dimension.
25+
26+
Args:
27+
zarr_url: Path to the zarr image
28+
"""
29+
image_group = zarr.open_group(zarr_url)
30+
zattrs = image_group.attrs.asdict()
31+
# print(zattrs)
32+
for multiscale in zattrs["multiscales"]:
33+
# Update axes
34+
multiscale["axes"] = multiscale["axes"][1:]
35+
# Update coordinate Transforms
36+
for dataset in multiscale["datasets"]:
37+
for transform in dataset["coordinateTransformations"]:
38+
if transform["type"] == "scale":
39+
transform["scale"] = transform["scale"][1:]
40+
return zattrs
41+
42+
43+
@validate_arguments
44+
def drop_t_dimension(
45+
*,
46+
input_paths: Sequence[str],
47+
output_path: str,
48+
component: str,
49+
metadata: dict[str, Any],
50+
suffix: str = "no_T",
51+
# overwrite_input: bool = False,
52+
) -> dict[str, Any]:
53+
"""
54+
Drops singleton t dimension.
55+
56+
Args:
57+
input_paths: This parameter is not used by this task.
58+
This task only supports a single input path.
59+
(standard argument for Fractal tasks, managed by Fractal server).
60+
output_path: Path were the output of this task is stored.
61+
Example: `"/some/path/"` => puts the new OME-Zarr file in that
62+
folder.
63+
(standard argument for Fractal tasks, managed by Fractal server).
64+
component: Path to the OME-Zarr image in the OME-Zarr plate that
65+
is processed. Component is typically changed by the `copy_ome_zarr`
66+
task before, to point to a new mip Zarr file.
67+
Example: `"some_plate_mip.zarr/B/03/0"`.
68+
(standard argument for Fractal tasks, managed by Fractal server).
69+
metadata: Dictionary containing metadata about the OME-Zarr.
70+
This task requires the key `copy_ome_zarr` to be present in the
71+
metadata (as defined in `copy_ome_zarr` task).
72+
(standard argument for Fractal tasks, managed by Fractal server).
73+
suffix: Suffix to be used for the new Zarr image. If overwrite_input
74+
is True, this file is only temporary.
75+
"""
76+
# Preliminary checks
77+
if len(input_paths) > 1:
78+
raise NotImplementedError
79+
80+
zarrurl_old = (Path(input_paths[0]).resolve() / component).as_posix()
81+
new_component = component + "_" + suffix
82+
zarrurl_new = (Path(input_paths[0]).resolve() / new_component).as_posix()
83+
logger.info(f"{zarrurl_old=}")
84+
logger.info(f"{zarrurl_new=}")
85+
86+
# Read some parameters from metadata
87+
ngff_image = load_NgffImageMeta(zarrurl_old)
88+
89+
# Check that T axis is the first axis:
90+
if not ngff_image.multiscale.axes[0].name == "t":
91+
logger.warning(
92+
f"The Zarr image {zarrurl_old} did not contain a T axis as its "
93+
f"first axis. The axes were: {ngff_image.multiscale.axes} \n"
94+
"The Drop T axis task is skipped"
95+
)
96+
return {}
97+
98+
# TODO: Generate attrs without the T dimension
99+
new_attrs = get_attrs_without_t(zarrurl_old)
100+
new_image_group = zarr.group(zarrurl_new)
101+
new_image_group.attrs.put(new_attrs)
102+
103+
# TODO: Check if image contains labels & raise error (or even copy them)
104+
# FIXME: Check if image contains ROI tables & copy them
105+
106+
# Load 0-th level
107+
data_tczyx = da.from_zarr(zarrurl_old + "/0")
108+
new_data = data_tczyx[0, ...]
109+
# Write to disk (triggering execution)
110+
logger.debug(f"Writing Zarr without T dimension to {zarrurl_new}")
111+
new_data.to_zarr(
112+
f"{zarrurl_new}/0",
113+
overwrite=True,
114+
dimension_separator="/",
115+
write_empty_chunks=False,
116+
)
117+
logger.debug(f"Finished writing Zarr without T dimension to {zarrurl_new}")
118+
build_pyramid(
119+
zarrurl=zarrurl_new,
120+
overwrite=True,
121+
num_levels=ngff_image.num_levels,
122+
coarsening_xy=ngff_image.coarsening_xy,
123+
chunksize=new_data.chunksize,
124+
)
125+
return {}
126+
127+
128+
if __name__ == "__main__":
129+
from fractal_tasks_core.tasks._utils import run_fractal_task
130+
131+
run_fractal_task(
132+
task_function=drop_t_dimension,
133+
logger_name=logger.name,
134+
)

0 commit comments

Comments
 (0)