Skip to content

Commit 0de6974

Browse files
authored
arbitrary number of imaging layers in zarr (#76)
* arbitrary number of imaging layers in zarr * descriptive error message when layer names list does not match number of channels in zarr
1 parent 7b30fed commit 0de6974

15 files changed

+618
-3063
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ cython_debug/
166166

167167
# vscode files
168168
.history
169+
.vscode/
170+
CLAUDE.md
169171

170172
# Ignore examples files
171173
examples/*/*

pixi.lock

Lines changed: 527 additions & 3018 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ extra-dependencies = [
3939
"mypy>=1.0.0",
4040
]
4141
[tool.hatch.envs.types.scripts]
42-
check = "mypy --install-types --non-interactive {args:trackedit tests}"
42+
check = "mypy --install-types --non-interactive {args:trackedit trackedit/_tests}"
4343

4444
[tool.coverage.run]
45-
source_pkgs = ["trackedit", "tests"]
45+
source_pkgs = ["trackedit", "trackedit/_tests"]
4646
branch = true
4747
parallel = true
4848
omit = [
@@ -51,7 +51,7 @@ omit = [
5151

5252
[tool.coverage.paths]
5353
trackedit = ["trackedit", "*/trackedit/trackedit"]
54-
tests = ["tests", "*/trackedit/tests"]
54+
tests = ["trackedit/_tests", "*/trackedit/trackedit/_tests"]
5555

5656
[tool.coverage.report]
5757
exclude_lines = [
@@ -90,6 +90,7 @@ pyqt = ">=5.15.9,<6"
9090
numpy = "<2.2"
9191
pre-commit = ">=4.1.0,<5"
9292
dask = ">=2025.2.0,<2026"
93+
pytest = ">=8.4.2,<9"
9394

9495
[tool.pixi.feature.test.dependencies]
9596
pytest = "*"

scripts/script_cropped_fov.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
# OPTIONAL: imaging data
2929
imaging_zarr_file = (
30-
"/hpc/projects/intracellular_dashboard/organelle_dynamics/rerun/"
30+
"/hpc/projects/intracellular_dashboard/organelle_dynamics/"
3131
"2025_07_24_A549_SEC61_TOMM20_G3BP1_ZIKV/2-assemble/"
3232
"2025_07_24_A549_SEC61_TOMM20_G3BP1_ZIKV.zarr/A/1/000000/"
3333
)

trackedit/DatabaseHandler.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def __init__(
5858
image_translate: tuple = None,
5959
coordinate_filters: list = None,
6060
default_start_annotation: int = None, # Make it optional
61+
imaging_layer_names: list = None,
6162
):
6263

6364
# inputs
@@ -75,8 +76,11 @@ def __init__(
7576
self.imaging_channel = imaging_channel
7677
self.image_z_slice = image_z_slice
7778
self.image_translate = image_translate
78-
self.imaging_flag = True if self.imaging_zarr_file is not None else False
79+
self.imaging_flag = (
80+
True if self.imaging_zarr_file and self.imaging_zarr_file != "" else False
81+
)
7982
self.coordinate_filters = coordinate_filters
83+
self.imaging_layer_names = imaging_layer_names
8084

8185
# Filenames / directories
8286
self.extension_string = ""
@@ -175,6 +179,7 @@ def __init__(
175179
channel=self.imaging_channel,
176180
time_window=self.time_window,
177181
image_z_slice=self.image_z_slice,
182+
imaging_layer_names=self.imaging_layer_names,
178183
)
179184
self.df_full = self.db_to_df(entire_database=True)
180185

trackedit/TrackEditClass.py

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -72,27 +72,28 @@ def __init__(
7272
color_dict=self.databasehandler.color_mapping
7373
)
7474

75-
# Add Imaging layer to viewer
75+
# Add Imaging layers to viewer
7676
if self.databasehandler.imaging_flag:
77-
layer_nuc = self.viewer.add_image(
78-
self.databasehandler.imagingArray.nuclear,
79-
name="im_nuclear",
80-
colormap="green",
81-
scale=self.databasehandler.scale,
82-
visible=False,
83-
translate=self.databasehandler.image_translate,
84-
)
85-
layer_nuc.reset_contrast_limits()
86-
layer_mem = self.viewer.add_image(
87-
self.databasehandler.imagingArray.membrane,
88-
name="im_membrane",
89-
colormap="red",
90-
opacity=0.5,
91-
scale=self.databasehandler.scale,
92-
visible=False,
93-
translate=self.databasehandler.image_translate,
94-
)
95-
layer_mem.reset_contrast_limits()
77+
# Define colormap sequence
78+
colormaps = ["green", "red", "blue", "magenta", "cyan", "yellow"]
79+
80+
for i, layer_name in enumerate(
81+
self.databasehandler.imagingArray.layer_names
82+
):
83+
channel_data = self.databasehandler.imagingArray.get_channel_data(i)
84+
colormap = colormaps[i % len(colormaps)]
85+
opacity = 1.0 if i == 0 else 0.5 # First layer full opacity, others 0.5
86+
87+
layer = self.viewer.add_image(
88+
channel_data,
89+
name=f"im_{layer_name}",
90+
colormap=colormap,
91+
opacity=opacity,
92+
scale=self.databasehandler.scale,
93+
visible=False,
94+
translate=self.databasehandler.image_translate,
95+
)
96+
layer.reset_contrast_limits()
9697

9798
tabwidget_bottom = QTabWidget()
9899
tabwidget_bottom.addTab(self.TreeWidget, "TreeWidget")
@@ -188,12 +189,11 @@ def update_chunk_from_button(self, direction: str):
188189
self.databasehandler.set_time_chunk(new_chunk)
189190
self.update_hierarchy_layer()
190191
if self.databasehandler.imaging_flag:
191-
self.viewer.layers[
192-
"im_nuclear"
193-
].data = self.databasehandler.imagingArray.nuclear
194-
self.viewer.layers[
195-
"im_membrane"
196-
].data = self.databasehandler.imagingArray.membrane
192+
for i, layer_name in enumerate(
193+
self.databasehandler.imagingArray.layer_names
194+
):
195+
channel_data = self.databasehandler.imagingArray.get_channel_data(i)
196+
self.viewer.layers[f"im_{layer_name}"].data = channel_data
197197

198198
self.add_tracks()
199199

@@ -244,12 +244,11 @@ def update_chunk_from_frame(self, frame: int):
244244
self.databasehandler.set_time_chunk(new_chunk)
245245
self.update_hierarchy_layer()
246246
if self.databasehandler.imaging_flag:
247-
self.viewer.layers[
248-
"im_nuclear"
249-
].data = self.databasehandler.imagingArray.nuclear
250-
self.viewer.layers[
251-
"im_membrane"
252-
].data = self.databasehandler.imagingArray.membrane
247+
for i, layer_name in enumerate(
248+
self.databasehandler.imagingArray.layer_names
249+
):
250+
channel_data = self.databasehandler.imagingArray.get_channel_data(i)
251+
self.viewer.layers[f"im_{layer_name}"].data = channel_data
253252

254253
# Update tracks if chunks are different OR if this was triggered by a Tmax change
255254
# TODO: not sure this is the best way to do this

0 commit comments

Comments
 (0)