TwoPy 0.1.0__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.
- twopy/__init__.py +168 -0
- twopy/_segments.py +53 -0
- twopy/analysis/__init__.py +101 -0
- twopy/analysis/background_subtraction.py +672 -0
- twopy/analysis/dff.py +524 -0
- twopy/analysis/epoch_mapping.py +223 -0
- twopy/analysis/motion.py +66 -0
- twopy/analysis/persistence.py +975 -0
- twopy/analysis/response_processing/__init__.py +55 -0
- twopy/analysis/response_processing/apply.py +298 -0
- twopy/analysis/response_processing/options.py +192 -0
- twopy/analysis/response_processing/qc.py +270 -0
- twopy/analysis/response_processing/signals.py +200 -0
- twopy/analysis/responses.py +345 -0
- twopy/analysis/trials.py +341 -0
- twopy/analysis/workflow.py +457 -0
- twopy/api.py +78 -0
- twopy/config.py +200 -0
- twopy/conversion/__init__.py +40 -0
- twopy/conversion/alignment_crop.py +329 -0
- twopy/conversion/api.py +113 -0
- twopy/conversion/frame_ranges.py +35 -0
- twopy/conversion/hdf5_writing.py +362 -0
- twopy/conversion/matlab_values.py +123 -0
- twopy/conversion/source_loading.py +403 -0
- twopy/conversion/stimulus_code.py +248 -0
- twopy/conversion/types.py +295 -0
- twopy/converted.py +681 -0
- twopy/database/__init__.py +33 -0
- twopy/database/cache.py +166 -0
- twopy/database/catalog.py +90 -0
- twopy/database/connection.py +27 -0
- twopy/database/generic.py +254 -0
- twopy/database/modeled.py +419 -0
- twopy/database/sql.py +46 -0
- twopy/database/types.py +116 -0
- twopy/inspection.py +492 -0
- twopy/matlab.py +398 -0
- twopy/napari/__init__.py +27 -0
- twopy/napari/__main__.py +10 -0
- twopy/napari/constants.py +13 -0
- twopy/napari/controls.py +739 -0
- twopy/napari/display.py +181 -0
- twopy/napari/display_paths.py +197 -0
- twopy/napari/interactive.py +310 -0
- twopy/napari/launcher.py +175 -0
- twopy/napari/layout.py +147 -0
- twopy/napari/loading.py +207 -0
- twopy/napari/movie.py +71 -0
- twopy/napari/paths.py +181 -0
- twopy/napari/plotting/__init__.py +21 -0
- twopy/napari/plotting/data.py +266 -0
- twopy/napari/plotting/docks.py +1052 -0
- twopy/napari/plotting/export.py +803 -0
- twopy/napari/plotting/export_controls.py +209 -0
- twopy/napari/plotting/label_visibility.py +260 -0
- twopy/napari/plotting/options.py +269 -0
- twopy/napari/plotting/panels.py +119 -0
- twopy/napari/plotting/widgets.py +767 -0
- twopy/napari/protocols.py +90 -0
- twopy/napari/responses.py +91 -0
- twopy/napari/roi.py +238 -0
- twopy/napari/session.py +381 -0
- twopy/napari/state.py +106 -0
- twopy/napari/text.py +26 -0
- twopy/napari/types.py +39 -0
- twopy/napari/viewer.py +405 -0
- twopy/parity/__init__.py +30 -0
- twopy/parity/dff.py +399 -0
- twopy/parity/roi.py +145 -0
- twopy/parity/saved_analysis.py +174 -0
- twopy/photodiode.py +375 -0
- twopy/photodiode_classification.py +484 -0
- twopy/roi.py +462 -0
- twopy/session.py +167 -0
- twopy/spatial.py +154 -0
- twopy/stimulus.py +233 -0
- twopy/synchronization.py +235 -0
- twopy/typing_guards.py +255 -0
- twopy-0.1.0.dist-info/METADATA +311 -0
- twopy-0.1.0.dist-info/RECORD +84 -0
- twopy-0.1.0.dist-info/WHEEL +5 -0
- twopy-0.1.0.dist-info/entry_points.txt +2 -0
- twopy-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Tiny napari protocols used by tests and GUI adapter code.
|
|
2
|
+
|
|
3
|
+
Inputs: napari viewer, window, and layer objects.
|
|
4
|
+
Outputs: structural types for the small subset of napari behavior twopy uses.
|
|
5
|
+
|
|
6
|
+
These protocols keep the adapter testable without importing or starting napari
|
|
7
|
+
in unit tests.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Protocol
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class NapariWindow(Protocol):
|
|
14
|
+
"""Small protocol for adding dock widgets to a napari viewer.
|
|
15
|
+
|
|
16
|
+
Inputs: widget objects.
|
|
17
|
+
Outputs: dock widgets owned by napari.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def add_dock_widget(
|
|
21
|
+
self,
|
|
22
|
+
widget: object,
|
|
23
|
+
*,
|
|
24
|
+
name: str,
|
|
25
|
+
area: str,
|
|
26
|
+
) -> object:
|
|
27
|
+
"""Add a dock widget to the viewer window.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
widget: Widget object to dock.
|
|
31
|
+
name: Dock title shown by napari.
|
|
32
|
+
area: Napari dock area name.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
The dock widget created by napari.
|
|
36
|
+
"""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class NapariViewer(Protocol):
|
|
41
|
+
"""Small viewer protocol used to keep tests independent from napari.
|
|
42
|
+
|
|
43
|
+
Inputs: image or label layer data.
|
|
44
|
+
Outputs: napari layer objects.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def window(self) -> NapariWindow:
|
|
49
|
+
"""Return the viewer window used to add dock widgets.
|
|
50
|
+
|
|
51
|
+
Inputs: viewer object.
|
|
52
|
+
Outputs: napari window object.
|
|
53
|
+
"""
|
|
54
|
+
...
|
|
55
|
+
|
|
56
|
+
def add_image(self, data: object, *, name: str, **kwargs: object) -> object:
|
|
57
|
+
"""Add an image layer to the viewer.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
data: Array-like image data.
|
|
61
|
+
name: Layer name shown in napari.
|
|
62
|
+
kwargs: napari image-layer options.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
The layer object created by napari.
|
|
66
|
+
"""
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
def add_labels(self, data: object, *, name: str, **kwargs: object) -> object:
|
|
70
|
+
"""Add a labels layer to the viewer.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
data: Two-dimensional integer label image.
|
|
74
|
+
name: Layer name shown in napari.
|
|
75
|
+
kwargs: napari label-layer options.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
The layer object created by napari.
|
|
79
|
+
"""
|
|
80
|
+
...
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class NapariLayerWithData(Protocol):
|
|
84
|
+
"""Small protocol for napari layers that expose array-like data.
|
|
85
|
+
|
|
86
|
+
Inputs: a napari layer object.
|
|
87
|
+
Outputs: access to its ``data`` attribute.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
data: object
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Response-computation helpers for the twopy napari adapter.
|
|
2
|
+
|
|
3
|
+
Inputs: a loaded converted recording and the active napari Labels ROI layer.
|
|
4
|
+
Outputs: plot-ready response data computed from the current labels.
|
|
5
|
+
|
|
6
|
+
This module is the small boundary between GUI ROI editing and core analysis.
|
|
7
|
+
It translates editable Labels pixels into a ``RoiSet`` and then calls the
|
|
8
|
+
GUI-independent in-memory response workflow.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import numpy as np
|
|
14
|
+
|
|
15
|
+
from twopy.analysis.workflow import compute_recording_responses
|
|
16
|
+
from twopy.converted import RecordingData
|
|
17
|
+
from twopy.napari.plotting.data import (
|
|
18
|
+
ResponsePlotData,
|
|
19
|
+
response_plot_data_from_grouped,
|
|
20
|
+
)
|
|
21
|
+
from twopy.napari.roi import roi_label_image_from_layer_for_recording
|
|
22
|
+
from twopy.roi import RoiSet, make_roi_set_from_label_image
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"compute_response_plot_data_from_labels",
|
|
26
|
+
"compute_response_plot_data_from_roi_set",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def compute_response_plot_data_from_labels(
|
|
31
|
+
recording: RecordingData,
|
|
32
|
+
roi_labels_layer: object,
|
|
33
|
+
*,
|
|
34
|
+
source_path: Path | None = None,
|
|
35
|
+
) -> ResponsePlotData:
|
|
36
|
+
"""Compute plot-ready ROI responses from the current napari Labels layer.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
recording: Loaded converted recording shown in napari.
|
|
40
|
+
roi_labels_layer: Active napari Labels layer containing ROI pixels.
|
|
41
|
+
source_path: Optional display path attached to the plot data.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Plot-ready response means and SEMs grouped by stimulus epoch.
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
ValueError: If the layer shape is not the crop-native display shape, if
|
|
48
|
+
no ROI labels are present, or if analysis inputs are invalid.
|
|
49
|
+
|
|
50
|
+
The helper deliberately does not save analysis files. Live ROI editing can
|
|
51
|
+
call it repeatedly without creating HDF5 churn; explicit save/export actions
|
|
52
|
+
remain separate user decisions.
|
|
53
|
+
"""
|
|
54
|
+
label_image = roi_label_image_from_layer_for_recording(roi_labels_layer, recording)
|
|
55
|
+
if not np.any(label_image > 0):
|
|
56
|
+
msg = "No ROI labels to analyze."
|
|
57
|
+
raise ValueError(msg)
|
|
58
|
+
|
|
59
|
+
roi_set = make_roi_set_from_label_image(label_image)
|
|
60
|
+
return compute_response_plot_data_from_roi_set(
|
|
61
|
+
recording,
|
|
62
|
+
roi_set,
|
|
63
|
+
source_path=source_path,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def compute_response_plot_data_from_roi_set(
|
|
68
|
+
recording: RecordingData,
|
|
69
|
+
roi_set: RoiSet,
|
|
70
|
+
*,
|
|
71
|
+
source_path: Path | None = None,
|
|
72
|
+
) -> ResponsePlotData:
|
|
73
|
+
"""Compute plot-ready ROI responses from a prepared ROI set.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
recording: Loaded converted recording shown in napari.
|
|
77
|
+
roi_set: ROI masks created from the current Labels layer.
|
|
78
|
+
source_path: Optional display path attached to the plot data.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Plot-ready response means and SEMs grouped by stimulus epoch.
|
|
82
|
+
|
|
83
|
+
This helper receives a prepared ROI set so live napari updates can copy
|
|
84
|
+
label pixels on the GUI thread, then run the heavier movie streaming work in
|
|
85
|
+
a worker thread.
|
|
86
|
+
"""
|
|
87
|
+
computation = compute_recording_responses(recording, roi_set)
|
|
88
|
+
return response_plot_data_from_grouped(
|
|
89
|
+
computation.grouped_responses,
|
|
90
|
+
source_path=source_path,
|
|
91
|
+
)
|
twopy/napari/roi.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"""ROI helpers for the twopy napari adapter.
|
|
2
|
+
|
|
3
|
+
Inputs: napari Labels layers, label images, ROI HDF5 files, and converted
|
|
4
|
+
recording metadata.
|
|
5
|
+
Outputs: twopy ``RoiSet`` objects, label images for display, and validated ROI
|
|
6
|
+
save/load paths.
|
|
7
|
+
|
|
8
|
+
This module is the only napari-facing layer that translates between editable
|
|
9
|
+
Labels data and core ROI masks.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import cast
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
import numpy.typing as npt
|
|
17
|
+
|
|
18
|
+
from twopy.converted import RecordingData
|
|
19
|
+
from twopy.napari.display import (
|
|
20
|
+
display_image_from_movie_image,
|
|
21
|
+
display_labels_from_movie_labels,
|
|
22
|
+
movie_labels_from_display_layer,
|
|
23
|
+
)
|
|
24
|
+
from twopy.napari.protocols import NapariLayerWithData
|
|
25
|
+
from twopy.roi import (
|
|
26
|
+
RoiSet,
|
|
27
|
+
load_roi_set,
|
|
28
|
+
make_roi_set_from_label_image,
|
|
29
|
+
roi_set_to_label_image,
|
|
30
|
+
save_roi_set,
|
|
31
|
+
)
|
|
32
|
+
from twopy.spatial import SpatialCrop, full_frame_crop
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"roi_label_image_from_layer",
|
|
36
|
+
"roi_label_image_from_layer_for_recording",
|
|
37
|
+
"save_napari_label_rois",
|
|
38
|
+
"validate_roi_layer_matches_recording_crop",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def roi_label_image_from_layer(layer: object) -> npt.NDArray[np.int64]:
|
|
43
|
+
"""Read integer label data from a napari Labels layer.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
layer: Napari Labels layer, or a test object with a ``data`` attribute.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Full-frame movie-coordinate integer label image.
|
|
50
|
+
|
|
51
|
+
This small helper keeps scripts from reaching into napari layer internals
|
|
52
|
+
in several different ways. The label image can be passed directly to
|
|
53
|
+
``save_napari_label_rois``. When twopy opened a cropped/transposed display
|
|
54
|
+
layer, crop metadata on the layer is used to restore movie coordinates.
|
|
55
|
+
"""
|
|
56
|
+
if hasattr(layer, "metadata") or hasattr(layer, "options"):
|
|
57
|
+
return movie_labels_from_display_layer(layer)
|
|
58
|
+
data = cast(NapariLayerWithData, layer).data
|
|
59
|
+
return np.asarray(data, dtype=np.int64)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def roi_label_image_from_layer_for_recording(
|
|
63
|
+
layer: object,
|
|
64
|
+
recording: RecordingData,
|
|
65
|
+
) -> npt.NDArray[np.int64]:
|
|
66
|
+
"""Return full-frame movie-coordinate ROI labels from a crop-native layer.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
layer: Napari Labels layer, or a test layer with ``data``.
|
|
70
|
+
recording: Loaded converted recording that defines the displayed crop.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
Full-frame movie-coordinate label image with zeros outside the crop.
|
|
74
|
+
|
|
75
|
+
Raises:
|
|
76
|
+
ValueError: If the Labels layer is not shaped like the recording's
|
|
77
|
+
displayed alignment-valid crop.
|
|
78
|
+
|
|
79
|
+
Napari ROI editing is intentionally crop-native: users see and edit only
|
|
80
|
+
the pixels that analysis accepts by default. Persisted ROI files stay
|
|
81
|
+
full-frame so core scripts and analysis have one stable mask shape.
|
|
82
|
+
"""
|
|
83
|
+
validate_roi_layer_matches_recording_crop(layer, recording)
|
|
84
|
+
display_labels = np.asarray(cast(NapariLayerWithData, layer).data, dtype=np.int64)
|
|
85
|
+
crop = recording.alignment_valid_crop
|
|
86
|
+
movie_crop_labels = display_image_from_movie_image(display_labels)
|
|
87
|
+
full_frame = np.zeros(crop.original_shape, dtype=np.int64)
|
|
88
|
+
full_frame[
|
|
89
|
+
crop.axis0_start : crop.axis0_stop,
|
|
90
|
+
crop.axis1_start : crop.axis1_stop,
|
|
91
|
+
] = movie_crop_labels
|
|
92
|
+
return full_frame
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def validate_roi_layer_matches_recording_crop(
|
|
96
|
+
layer: object,
|
|
97
|
+
recording: RecordingData,
|
|
98
|
+
) -> None:
|
|
99
|
+
"""Validate that a napari Labels layer matches the displayed recording crop.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
layer: Napari Labels layer, or a test layer with ``data``.
|
|
103
|
+
recording: Loaded converted recording that defines the displayed crop.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
None.
|
|
107
|
+
|
|
108
|
+
Raises:
|
|
109
|
+
ValueError: If the Labels layer does not have the cropped display
|
|
110
|
+
shape.
|
|
111
|
+
"""
|
|
112
|
+
display_labels = np.asarray(cast(NapariLayerWithData, layer).data)
|
|
113
|
+
crop = recording.alignment_valid_crop
|
|
114
|
+
expected_shape = (crop.shape[1], crop.shape[0])
|
|
115
|
+
if display_labels.shape != expected_shape:
|
|
116
|
+
msg = (
|
|
117
|
+
"ROI Labels layer must use the cropped recording view. "
|
|
118
|
+
f"Expected display shape {expected_shape} from "
|
|
119
|
+
f"{crop.source}; got {display_labels.shape}."
|
|
120
|
+
)
|
|
121
|
+
raise ValueError(msg)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def save_napari_label_rois(
|
|
125
|
+
label_image: npt.ArrayLike,
|
|
126
|
+
path: Path,
|
|
127
|
+
*,
|
|
128
|
+
labels: tuple[str, ...] | None = None,
|
|
129
|
+
label_prefix: str = "roi",
|
|
130
|
+
) -> RoiSet:
|
|
131
|
+
"""Save a napari labels-layer image as a twopy ROI set.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
label_image: Two-dimensional labels-layer data where ``0`` is
|
|
135
|
+
background and positive integers are ROIs.
|
|
136
|
+
path: Destination ROI HDF5 file.
|
|
137
|
+
labels: Optional text labels matching positive ROI values.
|
|
138
|
+
label_prefix: Prefix for generated ROI labels when ``labels`` is
|
|
139
|
+
omitted.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Saved ``RoiSet``.
|
|
143
|
+
|
|
144
|
+
This keeps napari editing output in the same HDF5 format that scripts and
|
|
145
|
+
analysis functions already load.
|
|
146
|
+
"""
|
|
147
|
+
roi_set = make_roi_set_from_label_image(
|
|
148
|
+
np.asarray(label_image),
|
|
149
|
+
labels=labels,
|
|
150
|
+
label_prefix=label_prefix,
|
|
151
|
+
)
|
|
152
|
+
save_roi_set(roi_set, path)
|
|
153
|
+
return roi_set
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def roi_label_image_for_display(
|
|
157
|
+
roi_set: RoiSet | Path | None,
|
|
158
|
+
recording: RecordingData,
|
|
159
|
+
*,
|
|
160
|
+
spatial_crop: SpatialCrop | None = None,
|
|
161
|
+
) -> npt.NDArray[np.int64]:
|
|
162
|
+
"""Create the label image shown in napari for ROI drawing/editing.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
roi_set: Optional existing ROI set or saved ROI HDF5 path.
|
|
166
|
+
recording: Loaded converted recording.
|
|
167
|
+
spatial_crop: Optional crop shown in napari. When omitted, the full
|
|
168
|
+
movie frame is displayed.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Integer label image in napari display coordinates.
|
|
172
|
+
"""
|
|
173
|
+
crop = spatial_crop
|
|
174
|
+
if crop is None:
|
|
175
|
+
crop = full_frame_crop(recording.movie.shape[1:])
|
|
176
|
+
if roi_set is None:
|
|
177
|
+
return np.zeros((crop.shape[1], crop.shape[0]), dtype=np.int64)
|
|
178
|
+
loaded_roi_set = resolve_roi_set(roi_set)
|
|
179
|
+
validate_roi_shape(loaded_roi_set, recording)
|
|
180
|
+
return display_labels_from_movie_labels(
|
|
181
|
+
roi_set_to_label_image(loaded_roi_set),
|
|
182
|
+
crop,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def resolve_roi_save_file(
|
|
187
|
+
*,
|
|
188
|
+
recording_data_path: Path,
|
|
189
|
+
roi_set: RoiSet | Path | None,
|
|
190
|
+
explicit_roi_save_file: Path | None,
|
|
191
|
+
) -> Path:
|
|
192
|
+
"""Resolve the default path used by the magicgui Save ROIs button.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
recording_data_path: Converted recording manifest path.
|
|
196
|
+
roi_set: Optional ROI object or path opened in napari.
|
|
197
|
+
explicit_roi_save_file: Optional caller-provided save path.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Path for saving ROI HDF5 files.
|
|
201
|
+
"""
|
|
202
|
+
if explicit_roi_save_file is not None:
|
|
203
|
+
return explicit_roi_save_file.expanduser()
|
|
204
|
+
if isinstance(roi_set, Path):
|
|
205
|
+
return roi_set.expanduser()
|
|
206
|
+
return recording_data_path.expanduser().parent / "rois.h5"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def resolve_roi_set(roi_set: RoiSet | Path) -> RoiSet:
|
|
210
|
+
"""Return a ROI set object from either an object or HDF5 path.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
roi_set: Existing ``RoiSet`` or saved ROI HDF5 path.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
Loaded ``RoiSet``.
|
|
217
|
+
"""
|
|
218
|
+
if isinstance(roi_set, Path):
|
|
219
|
+
return load_roi_set(roi_set)
|
|
220
|
+
return roi_set
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def validate_roi_shape(roi_set: RoiSet, recording: RecordingData) -> None:
|
|
224
|
+
"""Validate that ROI labels can be displayed over the recording.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
roi_set: ROI masks to display.
|
|
228
|
+
recording: Loaded converted recording.
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
None.
|
|
232
|
+
"""
|
|
233
|
+
if roi_set.masks.shape[1:] != recording.movie.shape[1:]:
|
|
234
|
+
msg = (
|
|
235
|
+
f"ROI mask shape {roi_set.masks.shape[1:]} does not match movie "
|
|
236
|
+
f"shape {recording.movie.shape[1:]}"
|
|
237
|
+
)
|
|
238
|
+
raise ValueError(msg)
|