neuralib-parser 0.7.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.
- neuralib/cellpose/__init__.py +1 -0
- neuralib/cellpose/core.py +190 -0
- neuralib/deeplabcut/__init__.py +1 -0
- neuralib/deeplabcut/core.py +267 -0
- neuralib/facemap/__init__.py +1 -0
- neuralib/facemap/core.py +313 -0
- neuralib/facemap/plot.py +91 -0
- neuralib/facemap/util.py +51 -0
- neuralib/morpho/__init__.py +0 -0
- neuralib/morpho/swc.py +408 -0
- neuralib/scan/__init__.py +0 -0
- neuralib/scan/core.py +156 -0
- neuralib/scan/czi.py +209 -0
- neuralib/scan/lsm.py +155 -0
- neuralib/scanbox/__init__.py +1 -0
- neuralib/scanbox/core.py +286 -0
- neuralib/scanbox/view.py +180 -0
- neuralib/stardist/__init__.py +1 -0
- neuralib/stardist/base.py +161 -0
- neuralib/stardist/core.py +214 -0
- neuralib/stardist/run_2d.py +103 -0
- neuralib/suite2p/__init__.py +3 -0
- neuralib/suite2p/core.py +561 -0
- neuralib/suite2p/plot.py +83 -0
- neuralib/suite2p/signals.py +265 -0
- neuralib_parser-0.7.0.dist-info/METADATA +138 -0
- neuralib_parser-0.7.0.dist-info/RECORD +30 -0
- neuralib_parser-0.7.0.dist-info/WHEEL +5 -0
- neuralib_parser-0.7.0.dist-info/licenses/LICENSE +28 -0
- neuralib_parser-0.7.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .core import *
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from typing import Self
|
|
7
|
+
|
|
8
|
+
from neuralib.typing import PathLike
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
'read_cellpose',
|
|
12
|
+
'cellpose_point_roi_helper',
|
|
13
|
+
'CellposeSegmentation'
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def read_cellpose(file: PathLike) -> CellposeSegmentation:
|
|
18
|
+
"""
|
|
19
|
+
Read a cellpose segmentation result file
|
|
20
|
+
|
|
21
|
+
:param file: cellpose segmentation result ``.npy`` file
|
|
22
|
+
:return: :class:`CellposeSegmentation`
|
|
23
|
+
"""
|
|
24
|
+
return CellposeSegmentation.load(file)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def cellpose_point_roi_helper(file: PathLike, output: PathLike) -> None:
|
|
28
|
+
"""
|
|
29
|
+
Read a cellpose segmentation result and convert the segmentation result to point coordinates
|
|
30
|
+
|
|
31
|
+
:param file: cellpose segmentation result ``.npy`` file
|
|
32
|
+
:param output: ``*.roi`` output file path
|
|
33
|
+
"""
|
|
34
|
+
CellposeSegmentation.load(file).to_roi(output)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class CellposeSegmentation:
|
|
38
|
+
"""`Cellpose <https://github.com/MouseLand/cellpose>`_ segmentation results
|
|
39
|
+
|
|
40
|
+
`Dimension parameters`:
|
|
41
|
+
|
|
42
|
+
N = Number of segmented cells
|
|
43
|
+
|
|
44
|
+
W = Image width
|
|
45
|
+
|
|
46
|
+
H = Image height
|
|
47
|
+
|
|
48
|
+
.. seealso::
|
|
49
|
+
|
|
50
|
+
`Cellpose Native Doc <https://cellpose.readthedocs.io/en/latest/outputs.html#seg-npy-output>`_
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, outlines, masks, chan_choose, ismanual, flows, diameter, filename):
|
|
55
|
+
self._outlines = outlines
|
|
56
|
+
self._masks = masks
|
|
57
|
+
self._chan_choose = chan_choose
|
|
58
|
+
self._is_manual = ismanual
|
|
59
|
+
self._flows = flows
|
|
60
|
+
self._diameter = diameter
|
|
61
|
+
|
|
62
|
+
self._filename = filename
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def load(cls, file: PathLike) -> Self:
|
|
66
|
+
"""
|
|
67
|
+
Load a cellpose segmentation result
|
|
68
|
+
|
|
69
|
+
:param file: cellpose segmentation result ``.npy`` file
|
|
70
|
+
:return: :class:`CellposeSegmentation`
|
|
71
|
+
"""
|
|
72
|
+
dat = np.load(file, allow_pickle=True).item()
|
|
73
|
+
return cls(**dat)
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def n_segmentation(self) -> int:
|
|
77
|
+
"""number of segmented cells"""
|
|
78
|
+
return len(self._is_manual)
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def width(self):
|
|
82
|
+
"""image width"""
|
|
83
|
+
return self._outlines.shape[1]
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def height(self):
|
|
87
|
+
"""image height"""
|
|
88
|
+
return self._outlines.shape[0]
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def filename(self) -> Path:
|
|
92
|
+
"""filepath of image"""
|
|
93
|
+
return Path(self._filename)
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def outlines(self) -> np.ndarray:
|
|
97
|
+
"""outlines of ROIs (0 = NO outline; 1,2,… = outline labels). `Array[uint16, [H, W]]`"""
|
|
98
|
+
return self._outlines
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def masks(self) -> np.ndarray:
|
|
102
|
+
"""each pixel in the image is assigned to an ROI (0 = NO ROI; 1,2,… = ROI labels). `Array[uint16, [H, W]]` """
|
|
103
|
+
return self._masks
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def chan_choose(self) -> list[int]:
|
|
107
|
+
"""channels that you chose in GUI (0=gray/none, 1=red, 2=green, 3=blue)"""
|
|
108
|
+
return self._chan_choose
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def flows(self) -> list[np.ndarray]:
|
|
112
|
+
"""
|
|
113
|
+
flows[0] is XY flow in RGB
|
|
114
|
+
|
|
115
|
+
flows[1] is the cell probability in range 0-255 instead of -10.0 to 10.0
|
|
116
|
+
|
|
117
|
+
flows[2] is Z flow in range 0-255 (if it exists, otherwise zeros),
|
|
118
|
+
|
|
119
|
+
flows[3] is [dY, dX, cellprob] (or [dZ, dY, dX, cellprob] for 3D), flows[4] is pixel destinations (for internal use)
|
|
120
|
+
"""
|
|
121
|
+
return self._flows
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def diameter(self) -> float:
|
|
125
|
+
"""cell body diameter"""
|
|
126
|
+
return self._diameter
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def is_manual(self) -> np.ndarray:
|
|
130
|
+
"""whether or not mask k was manually drawn or computed by the cellpose algorithm. `Array[bool, N]`"""
|
|
131
|
+
return self._is_manual
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def nan_masks(self) -> np.ndarray:
|
|
135
|
+
"""value 0 in :attr:`CellposeSegmentation.masks` to nan"""
|
|
136
|
+
masks = self.masks.copy().astype(np.float_)
|
|
137
|
+
masks[masks == 0] = np.nan
|
|
138
|
+
|
|
139
|
+
return masks
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def nan_outlines(self) -> np.ndarray:
|
|
143
|
+
"""value 0 in :attr:`CellposeSegmentation.outlines` to nan"""
|
|
144
|
+
outlines = self.outlines.copy().astype(np.float_)
|
|
145
|
+
outlines[outlines == 0] = np.nan
|
|
146
|
+
|
|
147
|
+
return outlines
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def points(self) -> np.ndarray:
|
|
151
|
+
"""Calculate center of each segmented area in XY pixel. `Array[int, [N, 2]]`"""
|
|
152
|
+
centers = self._calculate_centers()
|
|
153
|
+
return np.round(centers).astype(int)
|
|
154
|
+
|
|
155
|
+
# noinspection PyTypeChecker
|
|
156
|
+
def to_roi(self, output_file: PathLike):
|
|
157
|
+
"""
|
|
158
|
+
Covert segmented roi to point roi, and save it as ``.roi`` for imageJ.
|
|
159
|
+
|
|
160
|
+
:param output_file: ``*.roi`` output file path
|
|
161
|
+
"""
|
|
162
|
+
from roifile import ImagejRoi, ROI_TYPE, ROI_OPTIONS
|
|
163
|
+
|
|
164
|
+
if Path(output_file).suffix != '.roi':
|
|
165
|
+
raise ValueError('output file must have .roi extension')
|
|
166
|
+
|
|
167
|
+
points = np.fliplr(self.points) # XY rotate in .roi format
|
|
168
|
+
roi = ImagejRoi(
|
|
169
|
+
roitype=ROI_TYPE.POINT,
|
|
170
|
+
options=ROI_OPTIONS.PROMPT_BEFORE_DELETING | ROI_OPTIONS.SUB_PIXEL_RESOLUTION,
|
|
171
|
+
n_coordinates=self.points.shape[0],
|
|
172
|
+
integer_coordinates=points,
|
|
173
|
+
subpixel_coordinates=points
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
roi.tofile(output_file)
|
|
177
|
+
|
|
178
|
+
def _calculate_centers(self):
|
|
179
|
+
"""calculate center of each segmented area in XY pixel"""
|
|
180
|
+
labels = np.unique(self.masks)
|
|
181
|
+
labels = labels[labels != 0] # remove background
|
|
182
|
+
|
|
183
|
+
n_neurons = len(labels)
|
|
184
|
+
centers = np.zeros((n_neurons, 2))
|
|
185
|
+
for i, label in enumerate(labels):
|
|
186
|
+
segment_coords = np.argwhere(self.masks == label)
|
|
187
|
+
center = segment_coords.mean(axis=0)
|
|
188
|
+
centers[i] = center
|
|
189
|
+
|
|
190
|
+
return centers
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .core import *
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pickle
|
|
6
|
+
import polars as pl
|
|
7
|
+
from typing import TypedDict
|
|
8
|
+
|
|
9
|
+
from neuralib.typing import PathLike
|
|
10
|
+
from neuralib.util.dataframe import DataFrameWrapper
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'Joint',
|
|
14
|
+
'read_dlc',
|
|
15
|
+
'DeepLabCutDataFrame',
|
|
16
|
+
'JointDataFrame',
|
|
17
|
+
'DeepLabCutMeta',
|
|
18
|
+
'DeepLabCutModelConfig'
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
Joint = str
|
|
22
|
+
"""Joint name"""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def read_dlc(file: PathLike, meta_file: PathLike | None = None) -> DeepLabCutDataFrame:
|
|
26
|
+
"""
|
|
27
|
+
load DeepLabCut result from file
|
|
28
|
+
|
|
29
|
+
:param file: DeepLabCut result filepath. supports both ``.h5`` and ``.csv``
|
|
30
|
+
:param meta_file: Optional DeepLabCut meta filepath. should be the ``.pickle``
|
|
31
|
+
:return:
|
|
32
|
+
"""
|
|
33
|
+
file = Path(file)
|
|
34
|
+
meta_file = Path(meta_file)
|
|
35
|
+
meta = _load_meta(meta_file)
|
|
36
|
+
|
|
37
|
+
match file.suffix:
|
|
38
|
+
case '.h5' | '.hdf5':
|
|
39
|
+
df = _load_dlc_h5_table(file)
|
|
40
|
+
case '.csv':
|
|
41
|
+
df = _load_dlc_csv(file)
|
|
42
|
+
case _:
|
|
43
|
+
raise ValueError(f'file: {file} is not supported')
|
|
44
|
+
|
|
45
|
+
return DeepLabCutDataFrame(df, meta=meta, filtered=('filtered' in file.name))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class DeepLabCutDataFrame(DataFrameWrapper):
|
|
49
|
+
"""
|
|
50
|
+
DeepLabCut DataFrame ::
|
|
51
|
+
|
|
52
|
+
┌───────────┬───────────┬───────────┬───────────┬───┬───────────┬───────────┬───────────┬──────────┐
|
|
53
|
+
│ Nose_x ┆ Nose_y ┆ Nose_like ┆ EarL_x ┆ … ┆ TailMid_l ┆ TailEnd_x ┆ TailEnd_y ┆ TailEnd_ │
|
|
54
|
+
│ --- ┆ --- ┆ lihood ┆ --- ┆ ┆ ikelihood ┆ --- ┆ --- ┆ likeliho │
|
|
55
|
+
│ f64 ┆ f64 ┆ --- ┆ f64 ┆ ┆ --- ┆ f64 ┆ f64 ┆ od │
|
|
56
|
+
│ ┆ ┆ f64 ┆ ┆ ┆ f64 ┆ ┆ ┆ --- │
|
|
57
|
+
│ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ f64 │
|
|
58
|
+
╞═══════════╪═══════════╪═══════════╪═══════════╪═══╪═══════════╪═══════════╪═══════════╪══════════╡
|
|
59
|
+
│ 57.907318 ┆ 512.54742 ┆ 0.999679 ┆ 77.701355 ┆ … ┆ 0.999904 ┆ 257.71426 ┆ 561.89660 ┆ 0.999961 │
|
|
60
|
+
│ ┆ 4 ┆ ┆ ┆ ┆ ┆ 4 ┆ 6 ┆ │
|
|
61
|
+
│ 57.907318 ┆ 516.79528 ┆ 0.999688 ┆ 77.701355 ┆ … ┆ 0.999923 ┆ 257.71426 ┆ 562.05725 ┆ 0.999954 │
|
|
62
|
+
│ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
|
|
63
|
+
│ 94.259621 ┆ 43.849434 ┆ 0.973851 ┆ 106.33532 ┆ … ┆ 0.998977 ┆ 87.477776 ┆ 257.11996 ┆ 0.999937 │
|
|
64
|
+
│ 94.294357 ┆ 44.340511 ┆ 0.965436 ┆ 106.45220 ┆ … ┆ 0.999604 ┆ 87.223534 ┆ 258.46600 ┆ 0.999912 │
|
|
65
|
+
└───────────┴───────────┴───────────┴───────────┴───┴───────────┴───────────┴───────────┴──────────┘
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(self, df: pl.DataFrame,
|
|
70
|
+
meta: DeepLabCutMeta | None, *,
|
|
71
|
+
filtered: bool):
|
|
72
|
+
"""
|
|
73
|
+
:param df: DeepLabCut result dataframe
|
|
74
|
+
:param meta: :attr:`~DeepLabCutMeta`
|
|
75
|
+
:param filtered: whether the results has already been filtered
|
|
76
|
+
"""
|
|
77
|
+
self._df = df
|
|
78
|
+
self._meta = meta
|
|
79
|
+
self._filtered = filtered
|
|
80
|
+
|
|
81
|
+
def __repr__(self):
|
|
82
|
+
raise repr(self.dataframe())
|
|
83
|
+
|
|
84
|
+
def dataframe(self, dataframe: pl.DataFrame = None, may_inplace=True):
|
|
85
|
+
if dataframe is None:
|
|
86
|
+
return self._df
|
|
87
|
+
else:
|
|
88
|
+
return DeepLabCutDataFrame(dataframe, meta=self._meta, filtered=self._filtered)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def default_filtered(self) -> bool:
|
|
92
|
+
"""whether default filtered when running the deeplabcut"""
|
|
93
|
+
return self._filtered
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def meta(self) -> DeepLabCutMeta:
|
|
97
|
+
""":attr:`~neuralib.tracking.deeplabcut.DeepLabCutMeta`"""
|
|
98
|
+
return self._meta
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def model_config(self) -> DeepLabCutModelConfig:
|
|
102
|
+
""":attr:`~neuralib.tracking.deeplabcut.DeepLabCutModelConfig`"""
|
|
103
|
+
return self.meta['model_config']
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def fps(self) -> float:
|
|
107
|
+
"""frame per second, meta data required"""
|
|
108
|
+
return self.meta['fps']
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def nframes(self) -> int:
|
|
112
|
+
"""number of frames"""
|
|
113
|
+
return self.meta['nframes']
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def joints(self) -> list[Joint]:
|
|
117
|
+
"""list of labelled joints"""
|
|
118
|
+
return self.meta['model_config']['all_joints_names']
|
|
119
|
+
|
|
120
|
+
def get_joint(self, joint: Joint) -> JointDataFrame:
|
|
121
|
+
"""get specific joint"""
|
|
122
|
+
cols = ('x', 'y', 'likelihood')
|
|
123
|
+
df = self.select([f'{joint}_{col}' for col in cols]).dataframe()
|
|
124
|
+
return JointDataFrame(df)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class JointDataFrame(DataFrameWrapper):
|
|
128
|
+
"""
|
|
129
|
+
Dataframe from a specific joint ::
|
|
130
|
+
|
|
131
|
+
┌───────────┬────────────┬─────────────────┐
|
|
132
|
+
│ Nose_x ┆ Nose_y ┆ Nose_likelihood │
|
|
133
|
+
│ --- ┆ --- ┆ --- │
|
|
134
|
+
│ f64 ┆ f64 ┆ f64 │
|
|
135
|
+
╞═══════════╪════════════╪═════════════════╡
|
|
136
|
+
│ 57.907318 ┆ 512.547424 ┆ 0.999679 │
|
|
137
|
+
│ 57.907318 ┆ 516.795288 ┆ 0.999688 │
|
|
138
|
+
│ 57.907318 ┆ 519.56311 ┆ 0.999449 │
|
|
139
|
+
│ 56.733799 ┆ 522.204224 ┆ 0.999161 │
|
|
140
|
+
│ 53.546089 ┆ 525.24939 ┆ 0.999518 │
|
|
141
|
+
│ … ┆ … ┆ … │
|
|
142
|
+
│ 94.259621 ┆ 43.849434 ┆ 0.973851 │
|
|
143
|
+
│ 94.294357 ┆ 44.111595 ┆ 0.980125 │
|
|
144
|
+
│ 94.8013 ┆ 44.340511 ┆ 0.963981 │
|
|
145
|
+
│ 94.294357 ┆ 44.340511 ┆ 0.947905 │
|
|
146
|
+
│ 94.294357 ┆ 44.340511 ┆ 0.965436 │
|
|
147
|
+
└───────────┴────────────┴─────────────────┘
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
def __init__(self, df: pl.DataFrame):
|
|
151
|
+
self._df = df
|
|
152
|
+
|
|
153
|
+
def __repr__(self):
|
|
154
|
+
return repr(self.dataframe())
|
|
155
|
+
|
|
156
|
+
def dataframe(self, dataframe: pl.DataFrame = None, may_inplace=True):
|
|
157
|
+
if dataframe is None:
|
|
158
|
+
return self._df
|
|
159
|
+
else:
|
|
160
|
+
return JointDataFrame(dataframe)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class DeepLabCutMeta(TypedDict):
|
|
164
|
+
"""DeepLabCut model metadata"""
|
|
165
|
+
start: float
|
|
166
|
+
stop: float
|
|
167
|
+
run_duration: float
|
|
168
|
+
Scorer: str
|
|
169
|
+
model_config: DeepLabCutModelConfig
|
|
170
|
+
fps: float
|
|
171
|
+
batch_size: int
|
|
172
|
+
frame_dimensions: tuple[int, int]
|
|
173
|
+
nframes: int
|
|
174
|
+
iteration: int
|
|
175
|
+
training_set_fraction: float
|
|
176
|
+
cropping: bool
|
|
177
|
+
cropping_parameters: list[tuple[float, float, float, float]]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class DeepLabCutModelConfig(TypedDict):
|
|
181
|
+
"""DeepLabCut model configuration"""
|
|
182
|
+
stride: float
|
|
183
|
+
weigh_part_predictions: bool
|
|
184
|
+
weigh_negatives: bool
|
|
185
|
+
fg_fraction: float
|
|
186
|
+
mean_pixel: list[float]
|
|
187
|
+
shuffle: bool
|
|
188
|
+
snapshot_prefix: str
|
|
189
|
+
log_dir: str
|
|
190
|
+
global_scale: float
|
|
191
|
+
location_refinement: bool
|
|
192
|
+
locref_stdev: float
|
|
193
|
+
locref_loss_weight: float
|
|
194
|
+
locref_huber_loss: bool
|
|
195
|
+
optimizer: str
|
|
196
|
+
intermediate_supervision: bool
|
|
197
|
+
intermediate_supervision_layer: int
|
|
198
|
+
regularize: bool
|
|
199
|
+
weight_decay: float
|
|
200
|
+
crop_pad: int
|
|
201
|
+
scoremap_dir: str
|
|
202
|
+
batch_size: int
|
|
203
|
+
dataset_type: str
|
|
204
|
+
deterministic: bool
|
|
205
|
+
mirror: bool
|
|
206
|
+
pairwise_huber_loss: bool
|
|
207
|
+
weigh_only_present_joints: bool
|
|
208
|
+
partaffinityfield_predict: bool
|
|
209
|
+
pairwise_predict: bool
|
|
210
|
+
all_joints: list[list[int]]
|
|
211
|
+
all_joints_names: list[Joint]
|
|
212
|
+
dataset: str
|
|
213
|
+
init_weights: str
|
|
214
|
+
net_type: str
|
|
215
|
+
num_joints: int
|
|
216
|
+
num_outputs: int
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _load_dlc_h5_table(file) -> pl.DataFrame:
|
|
220
|
+
import pandas as pd
|
|
221
|
+
|
|
222
|
+
df = pd.read_hdf(file)
|
|
223
|
+
|
|
224
|
+
scorers = list(df.columns.levels[0])
|
|
225
|
+
bodyparts = list(df.columns.levels[1])
|
|
226
|
+
coords = list(df.columns.levels[2])
|
|
227
|
+
|
|
228
|
+
assert len(scorers) == 1
|
|
229
|
+
scorer = scorers[0]
|
|
230
|
+
|
|
231
|
+
data = {
|
|
232
|
+
f'{b}_{c}': df[(scorer, b, c)]
|
|
233
|
+
for b in bodyparts
|
|
234
|
+
for c in coords
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
ret = pl.DataFrame(data)
|
|
238
|
+
|
|
239
|
+
return ret
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _load_dlc_csv(file) -> pl.DataFrame:
|
|
243
|
+
cols = ['']
|
|
244
|
+
with file.open() as f:
|
|
245
|
+
f.readline() # skip first line
|
|
246
|
+
parts = f.readline().strip().split(',')[1::3]
|
|
247
|
+
cols.extend([f'{p}_{it}' for p in parts for it in ('x', 'y', 'likelihood')])
|
|
248
|
+
|
|
249
|
+
df = pl.read_csv(file, skip_rows=3, has_header=False, new_columns=cols)[:, 1:]
|
|
250
|
+
|
|
251
|
+
return df
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _load_meta(meta_file) -> DeepLabCutMeta:
|
|
255
|
+
if meta_file.suffix not in ('.pkl', '.pickle'):
|
|
256
|
+
raise ValueError(f'{meta_file} is not a pickle file')
|
|
257
|
+
|
|
258
|
+
# meta
|
|
259
|
+
with meta_file.open('rb') as f:
|
|
260
|
+
meta = pickle.load(f)['data']
|
|
261
|
+
|
|
262
|
+
# copy to typeddict
|
|
263
|
+
meta['model_config'] = meta['DLC-model-config file']
|
|
264
|
+
meta['iteration'] = meta['iteration (active-learning)']
|
|
265
|
+
meta['training_set_fraction'] = meta['training set fraction']
|
|
266
|
+
|
|
267
|
+
return meta
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .core import *
|