senoquant 1.0.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- senoquant/__init__.py +6 -0
- senoquant/_reader.py +7 -0
- senoquant/_widget.py +33 -0
- senoquant/napari.yaml +83 -0
- senoquant/reader/__init__.py +5 -0
- senoquant/reader/core.py +369 -0
- senoquant/tabs/__init__.py +15 -0
- senoquant/tabs/batch/__init__.py +10 -0
- senoquant/tabs/batch/backend.py +641 -0
- senoquant/tabs/batch/config.py +270 -0
- senoquant/tabs/batch/frontend.py +1283 -0
- senoquant/tabs/batch/io.py +326 -0
- senoquant/tabs/batch/layers.py +86 -0
- senoquant/tabs/quantification/__init__.py +1 -0
- senoquant/tabs/quantification/backend.py +228 -0
- senoquant/tabs/quantification/features/__init__.py +80 -0
- senoquant/tabs/quantification/features/base.py +142 -0
- senoquant/tabs/quantification/features/marker/__init__.py +5 -0
- senoquant/tabs/quantification/features/marker/config.py +69 -0
- senoquant/tabs/quantification/features/marker/dialog.py +437 -0
- senoquant/tabs/quantification/features/marker/export.py +879 -0
- senoquant/tabs/quantification/features/marker/feature.py +119 -0
- senoquant/tabs/quantification/features/marker/morphology.py +285 -0
- senoquant/tabs/quantification/features/marker/rows.py +654 -0
- senoquant/tabs/quantification/features/marker/thresholding.py +46 -0
- senoquant/tabs/quantification/features/roi.py +346 -0
- senoquant/tabs/quantification/features/spots/__init__.py +5 -0
- senoquant/tabs/quantification/features/spots/config.py +62 -0
- senoquant/tabs/quantification/features/spots/dialog.py +477 -0
- senoquant/tabs/quantification/features/spots/export.py +1292 -0
- senoquant/tabs/quantification/features/spots/feature.py +112 -0
- senoquant/tabs/quantification/features/spots/morphology.py +279 -0
- senoquant/tabs/quantification/features/spots/rows.py +241 -0
- senoquant/tabs/quantification/frontend.py +815 -0
- senoquant/tabs/segmentation/__init__.py +1 -0
- senoquant/tabs/segmentation/backend.py +131 -0
- senoquant/tabs/segmentation/frontend.py +1009 -0
- senoquant/tabs/segmentation/models/__init__.py +5 -0
- senoquant/tabs/segmentation/models/base.py +146 -0
- senoquant/tabs/segmentation/models/cpsam/details.json +65 -0
- senoquant/tabs/segmentation/models/cpsam/model.py +150 -0
- senoquant/tabs/segmentation/models/default_2d/details.json +69 -0
- senoquant/tabs/segmentation/models/default_2d/model.py +664 -0
- senoquant/tabs/segmentation/models/default_3d/details.json +69 -0
- senoquant/tabs/segmentation/models/default_3d/model.py +682 -0
- senoquant/tabs/segmentation/models/hf.py +71 -0
- senoquant/tabs/segmentation/models/nuclear_dilation/__init__.py +1 -0
- senoquant/tabs/segmentation/models/nuclear_dilation/details.json +26 -0
- senoquant/tabs/segmentation/models/nuclear_dilation/model.py +96 -0
- senoquant/tabs/segmentation/models/perinuclear_rings/__init__.py +1 -0
- senoquant/tabs/segmentation/models/perinuclear_rings/details.json +34 -0
- senoquant/tabs/segmentation/models/perinuclear_rings/model.py +132 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/__init__.py +2 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/__init__.py +3 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/__init__.py +6 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/generate.py +470 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/prepare.py +273 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/rawdata.py +112 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/data/transform.py +384 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/__init__.py +0 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/blocks.py +184 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/losses.py +79 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/nets.py +165 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/predict.py +467 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/probability.py +67 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/internals/train.py +148 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/io/__init__.py +163 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/__init__.py +52 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/base_model.py +329 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_isotropic.py +160 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_projection.py +178 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_standard.py +446 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/care_upsampling.py +54 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/config.py +254 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/models/pretrained.py +119 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/scripts/__init__.py +0 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/scripts/care_predict.py +180 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/__init__.py +5 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/plot_utils.py +159 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/six.py +18 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/tf.py +644 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/utils/utils.py +272 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/csbdeep/version.py +1 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/docs/source/conf.py +368 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/setup.py +68 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tests/test_datagen.py +169 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tests/test_models.py +462 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tests/test_utils.py +166 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_csbdeep/tools/create_zip_contents.py +34 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/__init__.py +30 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/big.py +624 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/bioimageio_utils.py +494 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/data/__init__.py +39 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/geometry/__init__.py +10 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/geometry/geom2d.py +215 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/geometry/geom3d.py +349 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/matching.py +483 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/__init__.py +28 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/base.py +1217 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/model2d.py +594 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/models/model3d.py +696 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/nms.py +384 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/plot/__init__.py +2 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/plot/plot.py +74 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/plot/render.py +298 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/rays3d.py +373 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/sample_patches.py +65 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/scripts/__init__.py +0 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/scripts/predict2d.py +90 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/scripts/predict3d.py +93 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/utils.py +408 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/_stardist/version.py +1 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/__init__.py +45 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/convert/__init__.py +17 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/convert/cli.py +55 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/convert/core.py +285 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/__init__.py +15 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/cli.py +36 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/divisibility.py +193 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/probe.py +100 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/receptive_field.py +182 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/rf_cli.py +48 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/inspect/valid_sizes.py +278 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/post/__init__.py +8 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/post/core.py +157 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/pre/__init__.py +17 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/pre/core.py +226 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/predict/__init__.py +5 -0
- senoquant/tabs/segmentation/stardist_onnx_utils/onnx_framework/predict/core.py +401 -0
- senoquant/tabs/settings/__init__.py +1 -0
- senoquant/tabs/settings/backend.py +29 -0
- senoquant/tabs/settings/frontend.py +19 -0
- senoquant/tabs/spots/__init__.py +1 -0
- senoquant/tabs/spots/backend.py +139 -0
- senoquant/tabs/spots/frontend.py +800 -0
- senoquant/tabs/spots/models/__init__.py +5 -0
- senoquant/tabs/spots/models/base.py +94 -0
- senoquant/tabs/spots/models/rmp/details.json +61 -0
- senoquant/tabs/spots/models/rmp/model.py +499 -0
- senoquant/tabs/spots/models/udwt/details.json +103 -0
- senoquant/tabs/spots/models/udwt/model.py +482 -0
- senoquant/utils.py +25 -0
- senoquant-1.0.0b1.dist-info/METADATA +193 -0
- senoquant-1.0.0b1.dist-info/RECORD +148 -0
- senoquant-1.0.0b1.dist-info/WHEEL +5 -0
- senoquant-1.0.0b1.dist-info/entry_points.txt +2 -0
- senoquant-1.0.0b1.dist-info/licenses/LICENSE +28 -0
- senoquant-1.0.0b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""Batch job configuration and serialization helpers.
|
|
2
|
+
|
|
3
|
+
This module defines dataclasses used to capture batch settings from the UI
|
|
4
|
+
and persist them to JSON. The serialization format keeps feature configs
|
|
5
|
+
portable across sessions and mirrors the Quantification tab structures.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field, asdict
|
|
11
|
+
from typing import Iterable
|
|
12
|
+
import json
|
|
13
|
+
|
|
14
|
+
from senoquant.tabs.quantification.features import FeatureConfig
|
|
15
|
+
from senoquant.tabs.quantification.features.base import FeatureData
|
|
16
|
+
from senoquant.tabs.quantification.features.marker.config import (
|
|
17
|
+
MarkerChannelConfig,
|
|
18
|
+
MarkerFeatureData,
|
|
19
|
+
MarkerSegmentationConfig,
|
|
20
|
+
)
|
|
21
|
+
from senoquant.tabs.quantification.features.spots.config import (
|
|
22
|
+
SpotsChannelConfig,
|
|
23
|
+
SpotsFeatureData,
|
|
24
|
+
SpotsSegmentationConfig,
|
|
25
|
+
)
|
|
26
|
+
from senoquant.tabs.quantification.features.roi import ROIConfig
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(slots=True)
|
|
30
|
+
class BatchChannelConfig:
|
|
31
|
+
"""Channel mapping configuration.
|
|
32
|
+
|
|
33
|
+
Attributes
|
|
34
|
+
----------
|
|
35
|
+
name : str
|
|
36
|
+
User-facing channel name (used in UI and exports).
|
|
37
|
+
index : int
|
|
38
|
+
Zero-based channel index in the input image.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
name: str
|
|
42
|
+
index: int
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(slots=True)
|
|
46
|
+
class BatchSegmentationConfig:
|
|
47
|
+
"""Segmentation configuration for a single task."""
|
|
48
|
+
enabled: bool = False
|
|
49
|
+
model: str = ""
|
|
50
|
+
channel: str = ""
|
|
51
|
+
settings: dict = field(default_factory=dict)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(slots=True)
|
|
55
|
+
class BatchCytoplasmicConfig:
|
|
56
|
+
"""Cytoplasmic segmentation configuration."""
|
|
57
|
+
enabled: bool = False
|
|
58
|
+
model: str = ""
|
|
59
|
+
channel: str = ""
|
|
60
|
+
nuclear_channel: str = ""
|
|
61
|
+
settings: dict = field(default_factory=dict)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass(slots=True)
|
|
65
|
+
class BatchSpotsConfig:
|
|
66
|
+
"""Spot detection configuration."""
|
|
67
|
+
enabled: bool = False
|
|
68
|
+
detector: str = ""
|
|
69
|
+
channels: list[str] = field(default_factory=list)
|
|
70
|
+
settings: dict = field(default_factory=dict)
|
|
71
|
+
min_size: int = 0
|
|
72
|
+
max_size: int = 0
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@dataclass(slots=True)
|
|
76
|
+
class BatchQuantificationConfig:
|
|
77
|
+
"""Quantification configuration."""
|
|
78
|
+
enabled: bool = False
|
|
79
|
+
format: str = "xlsx"
|
|
80
|
+
features: list[FeatureConfig] = field(default_factory=list)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass(slots=True)
|
|
84
|
+
class BatchJobConfig:
|
|
85
|
+
"""Top-level batch configuration.
|
|
86
|
+
|
|
87
|
+
This structure is the single payload passed from the UI to the backend.
|
|
88
|
+
It is also the serialized representation used in batch profiles.
|
|
89
|
+
"""
|
|
90
|
+
input_path: str = ""
|
|
91
|
+
output_path: str = ""
|
|
92
|
+
extensions: list[str] = field(default_factory=list)
|
|
93
|
+
include_subfolders: bool = False
|
|
94
|
+
process_all_scenes: bool = False
|
|
95
|
+
overwrite: bool = False
|
|
96
|
+
output_format: str = "tif"
|
|
97
|
+
channel_map: list[BatchChannelConfig] = field(default_factory=list)
|
|
98
|
+
nuclear: BatchSegmentationConfig = field(default_factory=BatchSegmentationConfig)
|
|
99
|
+
cytoplasmic: BatchCytoplasmicConfig = field(default_factory=BatchCytoplasmicConfig)
|
|
100
|
+
spots: BatchSpotsConfig = field(default_factory=BatchSpotsConfig)
|
|
101
|
+
quantification: BatchQuantificationConfig = field(default_factory=BatchQuantificationConfig)
|
|
102
|
+
|
|
103
|
+
def to_dict(self) -> dict:
|
|
104
|
+
"""Serialize the job config to a JSON-friendly dictionary.
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
dict
|
|
109
|
+
JSON-compatible representation of the batch config.
|
|
110
|
+
"""
|
|
111
|
+
payload = asdict(self)
|
|
112
|
+
payload["quantification"]["features"] = [
|
|
113
|
+
_serialize_feature(feature)
|
|
114
|
+
for feature in self.quantification.features
|
|
115
|
+
]
|
|
116
|
+
return payload
|
|
117
|
+
|
|
118
|
+
@classmethod
|
|
119
|
+
def from_dict(cls, payload: dict) -> "BatchJobConfig":
|
|
120
|
+
"""Hydrate a job config from a JSON payload.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
payload : dict
|
|
125
|
+
JSON-compatible representation of the batch config.
|
|
126
|
+
|
|
127
|
+
Returns
|
|
128
|
+
-------
|
|
129
|
+
BatchJobConfig
|
|
130
|
+
Parsed configuration instance.
|
|
131
|
+
"""
|
|
132
|
+
channel_map = [
|
|
133
|
+
BatchChannelConfig(**item)
|
|
134
|
+
for item in payload.get("channel_map", [])
|
|
135
|
+
]
|
|
136
|
+
nuclear = BatchSegmentationConfig(
|
|
137
|
+
**payload.get("nuclear", {})
|
|
138
|
+
)
|
|
139
|
+
cytoplasmic = BatchCytoplasmicConfig(
|
|
140
|
+
**payload.get("cytoplasmic", {})
|
|
141
|
+
)
|
|
142
|
+
spots = BatchSpotsConfig(
|
|
143
|
+
**payload.get("spots", {})
|
|
144
|
+
)
|
|
145
|
+
quant_payload = payload.get("quantification", {})
|
|
146
|
+
features = [
|
|
147
|
+
_deserialize_feature(item)
|
|
148
|
+
for item in quant_payload.get("features", [])
|
|
149
|
+
]
|
|
150
|
+
quantification = BatchQuantificationConfig(
|
|
151
|
+
enabled=bool(quant_payload.get("enabled", False)),
|
|
152
|
+
format=quant_payload.get("format", "xlsx"),
|
|
153
|
+
features=features,
|
|
154
|
+
)
|
|
155
|
+
return cls(
|
|
156
|
+
input_path=payload.get("input_path", ""),
|
|
157
|
+
output_path=payload.get("output_path", ""),
|
|
158
|
+
extensions=list(payload.get("extensions", [])),
|
|
159
|
+
include_subfolders=bool(payload.get("include_subfolders", False)),
|
|
160
|
+
process_all_scenes=bool(payload.get("process_all_scenes", False)),
|
|
161
|
+
overwrite=bool(payload.get("overwrite", False)),
|
|
162
|
+
output_format=payload.get("output_format", "tif"),
|
|
163
|
+
channel_map=channel_map,
|
|
164
|
+
nuclear=nuclear,
|
|
165
|
+
cytoplasmic=cytoplasmic,
|
|
166
|
+
spots=spots,
|
|
167
|
+
quantification=quantification,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def save(self, path: str) -> None:
|
|
171
|
+
"""Persist the configuration to disk.
|
|
172
|
+
|
|
173
|
+
Parameters
|
|
174
|
+
----------
|
|
175
|
+
path : str
|
|
176
|
+
Destination file path for the JSON profile.
|
|
177
|
+
"""
|
|
178
|
+
with open(path, "w", encoding="utf-8") as handle:
|
|
179
|
+
json.dump(self.to_dict(), handle, indent=2)
|
|
180
|
+
|
|
181
|
+
@classmethod
|
|
182
|
+
def load(cls, path: str) -> "BatchJobConfig":
|
|
183
|
+
"""Load a configuration from disk.
|
|
184
|
+
|
|
185
|
+
Parameters
|
|
186
|
+
----------
|
|
187
|
+
path : str
|
|
188
|
+
Source JSON profile file.
|
|
189
|
+
|
|
190
|
+
Returns
|
|
191
|
+
-------
|
|
192
|
+
BatchJobConfig
|
|
193
|
+
Loaded configuration instance.
|
|
194
|
+
"""
|
|
195
|
+
with open(path, "r", encoding="utf-8") as handle:
|
|
196
|
+
payload = json.load(handle)
|
|
197
|
+
return cls.from_dict(payload)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _serialize_feature(feature: FeatureConfig) -> dict:
|
|
201
|
+
"""Serialize a Quantification feature into a JSON payload."""
|
|
202
|
+
return {
|
|
203
|
+
"feature_id": feature.feature_id,
|
|
204
|
+
"name": feature.name,
|
|
205
|
+
"type_name": feature.type_name,
|
|
206
|
+
"data": _serialize_feature_data(feature.data),
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _serialize_feature_data(data_obj: object) -> dict:
|
|
211
|
+
"""Serialize feature-specific data payloads."""
|
|
212
|
+
if isinstance(data_obj, MarkerFeatureData):
|
|
213
|
+
return {
|
|
214
|
+
"type": "Markers",
|
|
215
|
+
"payload": asdict(data_obj),
|
|
216
|
+
}
|
|
217
|
+
if isinstance(data_obj, SpotsFeatureData):
|
|
218
|
+
return {
|
|
219
|
+
"type": "Spots",
|
|
220
|
+
"payload": asdict(data_obj),
|
|
221
|
+
}
|
|
222
|
+
return {"type": "Unknown", "payload": {}}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _deserialize_feature(payload: dict) -> FeatureConfig:
|
|
226
|
+
"""Deserialize a feature payload into a FeatureConfig."""
|
|
227
|
+
feature_id = payload.get("feature_id", "")
|
|
228
|
+
name = payload.get("name", "")
|
|
229
|
+
type_name = payload.get("type_name", "")
|
|
230
|
+
data_payload = payload.get("data", {})
|
|
231
|
+
data_type = data_payload.get("type")
|
|
232
|
+
data_obj = _deserialize_feature_data(data_type, data_payload.get("payload", {}))
|
|
233
|
+
if feature_id:
|
|
234
|
+
return FeatureConfig(
|
|
235
|
+
feature_id=feature_id,
|
|
236
|
+
name=name,
|
|
237
|
+
type_name=type_name,
|
|
238
|
+
data=data_obj,
|
|
239
|
+
)
|
|
240
|
+
return FeatureConfig(name=name, type_name=type_name, data=data_obj)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _deserialize_feature_data(data_type: str, payload: dict):
|
|
244
|
+
"""Deserialize feature payloads into feature data objects."""
|
|
245
|
+
if data_type == "Markers":
|
|
246
|
+
return MarkerFeatureData(
|
|
247
|
+
segmentations=[
|
|
248
|
+
MarkerSegmentationConfig(**item)
|
|
249
|
+
for item in payload.get("segmentations", [])
|
|
250
|
+
],
|
|
251
|
+
channels=[
|
|
252
|
+
MarkerChannelConfig(**item)
|
|
253
|
+
for item in payload.get("channels", [])
|
|
254
|
+
],
|
|
255
|
+
rois=[ROIConfig(**item) for item in payload.get("rois", [])],
|
|
256
|
+
)
|
|
257
|
+
if data_type == "Spots":
|
|
258
|
+
return SpotsFeatureData(
|
|
259
|
+
segmentations=[
|
|
260
|
+
SpotsSegmentationConfig(**item)
|
|
261
|
+
for item in payload.get("segmentations", [])
|
|
262
|
+
],
|
|
263
|
+
channels=[
|
|
264
|
+
SpotsChannelConfig(**item)
|
|
265
|
+
for item in payload.get("channels", [])
|
|
266
|
+
],
|
|
267
|
+
rois=[ROIConfig(**item) for item in payload.get("rois", [])],
|
|
268
|
+
export_colocalization=bool(payload.get("export_colocalization", False)),
|
|
269
|
+
)
|
|
270
|
+
return FeatureData()
|