py-neuromodulation 0.0.4__py3-none-any.whl → 0.0.6__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.
- py_neuromodulation/ConnectivityDecoding/_get_grid_hull.m +34 -34
- py_neuromodulation/ConnectivityDecoding/_get_grid_whole_brain.py +95 -106
- py_neuromodulation/ConnectivityDecoding/_helper_write_connectome.py +107 -119
- py_neuromodulation/__init__.py +80 -13
- py_neuromodulation/{nm_RMAP.py → analysis/RMAP.py} +496 -531
- py_neuromodulation/analysis/__init__.py +4 -0
- py_neuromodulation/{nm_decode.py → analysis/decode.py} +918 -992
- py_neuromodulation/{nm_analysis.py → analysis/feature_reader.py} +994 -1074
- py_neuromodulation/{nm_plots.py → analysis/plots.py} +627 -612
- py_neuromodulation/{nm_stats.py → analysis/stats.py} +458 -480
- py_neuromodulation/data/README +6 -6
- py_neuromodulation/data/dataset_description.json +8 -8
- py_neuromodulation/data/participants.json +32 -32
- py_neuromodulation/data/participants.tsv +2 -2
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_coordsystem.json +5 -5
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_electrodes.tsv +11 -11
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_channels.tsv +11 -11
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.json +18 -18
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vhdr +35 -35
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vmrk +13 -13
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/sub-testsub_ses-EphysMedOff_scans.tsv +2 -2
- py_neuromodulation/default_settings.yaml +241 -0
- py_neuromodulation/features/__init__.py +31 -0
- py_neuromodulation/features/bandpower.py +165 -0
- py_neuromodulation/features/bispectra.py +157 -0
- py_neuromodulation/features/bursts.py +297 -0
- py_neuromodulation/features/coherence.py +255 -0
- py_neuromodulation/features/feature_processor.py +121 -0
- py_neuromodulation/features/fooof.py +142 -0
- py_neuromodulation/features/hjorth_raw.py +57 -0
- py_neuromodulation/features/linelength.py +21 -0
- py_neuromodulation/features/mne_connectivity.py +148 -0
- py_neuromodulation/features/nolds.py +94 -0
- py_neuromodulation/features/oscillatory.py +249 -0
- py_neuromodulation/features/sharpwaves.py +432 -0
- py_neuromodulation/filter/__init__.py +3 -0
- py_neuromodulation/filter/kalman_filter.py +67 -0
- py_neuromodulation/filter/kalman_filter_external.py +1890 -0
- py_neuromodulation/filter/mne_filter.py +128 -0
- py_neuromodulation/filter/notch_filter.py +93 -0
- py_neuromodulation/grid_cortex.tsv +40 -40
- py_neuromodulation/liblsl/libpugixml.so.1.12 +0 -0
- py_neuromodulation/liblsl/linux/bionic_amd64/liblsl.1.16.2.so +0 -0
- py_neuromodulation/liblsl/linux/bookworm_amd64/liblsl.1.16.2.so +0 -0
- py_neuromodulation/liblsl/linux/focal_amd46/liblsl.1.16.2.so +0 -0
- py_neuromodulation/liblsl/linux/jammy_amd64/liblsl.1.16.2.so +0 -0
- py_neuromodulation/liblsl/linux/jammy_x86/liblsl.1.16.2.so +0 -0
- py_neuromodulation/liblsl/linux/noble_amd64/liblsl.1.16.2.so +0 -0
- py_neuromodulation/liblsl/macos/amd64/liblsl.1.16.2.dylib +0 -0
- py_neuromodulation/liblsl/macos/arm64/liblsl.1.16.0.dylib +0 -0
- py_neuromodulation/liblsl/windows/amd64/liblsl.1.16.2.dll +0 -0
- py_neuromodulation/liblsl/windows/x86/liblsl.1.16.2.dll +0 -0
- py_neuromodulation/processing/__init__.py +10 -0
- py_neuromodulation/{nm_artifacts.py → processing/artifacts.py} +29 -25
- py_neuromodulation/processing/data_preprocessor.py +77 -0
- py_neuromodulation/processing/filter_preprocessing.py +78 -0
- py_neuromodulation/processing/normalization.py +175 -0
- py_neuromodulation/{nm_projection.py → processing/projection.py} +370 -394
- py_neuromodulation/{nm_rereference.py → processing/rereference.py} +97 -95
- py_neuromodulation/{nm_resample.py → processing/resample.py} +56 -50
- py_neuromodulation/stream/__init__.py +3 -0
- py_neuromodulation/stream/data_processor.py +325 -0
- py_neuromodulation/stream/generator.py +53 -0
- py_neuromodulation/stream/mnelsl_player.py +94 -0
- py_neuromodulation/stream/mnelsl_stream.py +120 -0
- py_neuromodulation/stream/settings.py +292 -0
- py_neuromodulation/stream/stream.py +427 -0
- py_neuromodulation/utils/__init__.py +2 -0
- py_neuromodulation/{nm_define_nmchannels.py → utils/channels.py} +305 -302
- py_neuromodulation/utils/database.py +149 -0
- py_neuromodulation/utils/io.py +378 -0
- py_neuromodulation/utils/keyboard.py +52 -0
- py_neuromodulation/utils/logging.py +66 -0
- py_neuromodulation/utils/types.py +251 -0
- {py_neuromodulation-0.0.4.dist-info → py_neuromodulation-0.0.6.dist-info}/METADATA +28 -33
- py_neuromodulation-0.0.6.dist-info/RECORD +89 -0
- {py_neuromodulation-0.0.4.dist-info → py_neuromodulation-0.0.6.dist-info}/WHEEL +1 -1
- {py_neuromodulation-0.0.4.dist-info → py_neuromodulation-0.0.6.dist-info}/licenses/LICENSE +21 -21
- py_neuromodulation/FieldTrip.py +0 -589
- py_neuromodulation/_write_example_dataset_helper.py +0 -65
- py_neuromodulation/nm_EpochStream.py +0 -92
- py_neuromodulation/nm_IO.py +0 -417
- py_neuromodulation/nm_across_patient_decoding.py +0 -927
- py_neuromodulation/nm_bispectra.py +0 -168
- py_neuromodulation/nm_bursts.py +0 -198
- py_neuromodulation/nm_coherence.py +0 -205
- py_neuromodulation/nm_cohortwrapper.py +0 -435
- py_neuromodulation/nm_eval_timing.py +0 -239
- py_neuromodulation/nm_features.py +0 -116
- py_neuromodulation/nm_features_abc.py +0 -39
- py_neuromodulation/nm_filter.py +0 -219
- py_neuromodulation/nm_filter_preprocessing.py +0 -91
- py_neuromodulation/nm_fooof.py +0 -159
- py_neuromodulation/nm_generator.py +0 -37
- py_neuromodulation/nm_hjorth_raw.py +0 -73
- py_neuromodulation/nm_kalmanfilter.py +0 -58
- py_neuromodulation/nm_linelength.py +0 -33
- py_neuromodulation/nm_mne_connectivity.py +0 -112
- py_neuromodulation/nm_nolds.py +0 -93
- py_neuromodulation/nm_normalization.py +0 -214
- py_neuromodulation/nm_oscillatory.py +0 -448
- py_neuromodulation/nm_run_analysis.py +0 -435
- py_neuromodulation/nm_settings.json +0 -338
- py_neuromodulation/nm_settings.py +0 -68
- py_neuromodulation/nm_sharpwaves.py +0 -401
- py_neuromodulation/nm_stream_abc.py +0 -218
- py_neuromodulation/nm_stream_offline.py +0 -359
- py_neuromodulation/utils/_logging.py +0 -24
- py_neuromodulation-0.0.4.dist-info/RECORD +0 -72
|
@@ -1,435 +0,0 @@
|
|
|
1
|
-
"""This module contains the class to process a given batch of data."""
|
|
2
|
-
|
|
3
|
-
from enum import Enum
|
|
4
|
-
import math
|
|
5
|
-
import os
|
|
6
|
-
from time import time
|
|
7
|
-
from typing import Protocol, Type
|
|
8
|
-
import logging
|
|
9
|
-
|
|
10
|
-
logger = logging.getLogger("PynmLogger")
|
|
11
|
-
|
|
12
|
-
import numpy as np
|
|
13
|
-
import pandas as pd
|
|
14
|
-
|
|
15
|
-
from py_neuromodulation import (
|
|
16
|
-
nm_features,
|
|
17
|
-
nm_filter,
|
|
18
|
-
nm_IO,
|
|
19
|
-
nm_normalization,
|
|
20
|
-
nm_projection,
|
|
21
|
-
nm_rereference,
|
|
22
|
-
nm_resample,
|
|
23
|
-
nm_filter_preprocessing,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
_PathLike = str | os.PathLike
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class Preprocessor(Protocol):
|
|
30
|
-
def process(self, data: np.ndarray) -> np.ndarray:
|
|
31
|
-
pass
|
|
32
|
-
|
|
33
|
-
def test_settings(self, settings: dict): ...
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
_PREPROCESSING_CONSTRUCTORS = [
|
|
37
|
-
"notch_filter",
|
|
38
|
-
"re_referencing",
|
|
39
|
-
"raw_normalization",
|
|
40
|
-
"raw_resample",
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class GRIDS(Enum):
|
|
45
|
-
"""Definition of possible projection grid types"""
|
|
46
|
-
|
|
47
|
-
CORTEX = "cortex"
|
|
48
|
-
SUBCORTEX = "subcortex"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class DataProcessor:
|
|
52
|
-
def __init__(
|
|
53
|
-
self,
|
|
54
|
-
sfreq: int | float,
|
|
55
|
-
settings: dict | _PathLike,
|
|
56
|
-
nm_channels: pd.DataFrame | _PathLike,
|
|
57
|
-
coord_names: list | None = None,
|
|
58
|
-
coord_list: list | None = None,
|
|
59
|
-
line_noise: int | float | None = None,
|
|
60
|
-
path_grids: _PathLike | None = None,
|
|
61
|
-
verbose: bool = True,
|
|
62
|
-
) -> None:
|
|
63
|
-
"""Initialize run class.
|
|
64
|
-
|
|
65
|
-
Parameters
|
|
66
|
-
----------
|
|
67
|
-
features : features.py object
|
|
68
|
-
Feature_df object (needs to be initialized beforehand)
|
|
69
|
-
settings : dict
|
|
70
|
-
dictionary of settings such as "seglengths" or "frequencyranges"
|
|
71
|
-
reference : reference.py object
|
|
72
|
-
Rereference object (needs to be initialized beforehand), by default None
|
|
73
|
-
projection : projection.py object
|
|
74
|
-
projection object (needs to be initialized beforehand), by default None
|
|
75
|
-
resample : resample.py object
|
|
76
|
-
Resample object (needs to be initialized beforehand), by default None
|
|
77
|
-
notch_filter : nm_filter.NotchFilter,
|
|
78
|
-
Notch Filter object, needs to be instantiated beforehand
|
|
79
|
-
verbose : boolean
|
|
80
|
-
if True, log signal processed and computation time
|
|
81
|
-
"""
|
|
82
|
-
self.settings = self._load_settings(settings)
|
|
83
|
-
self.nm_channels = self._load_nm_channels(nm_channels)
|
|
84
|
-
|
|
85
|
-
self.sfreq_features = self.settings["sampling_rate_features_hz"]
|
|
86
|
-
self._sfreq_raw_orig = sfreq
|
|
87
|
-
self.sfreq_raw = math.floor(sfreq)
|
|
88
|
-
self.line_noise = line_noise
|
|
89
|
-
self.path_grids = path_grids
|
|
90
|
-
self.verbose = verbose
|
|
91
|
-
|
|
92
|
-
self.features_previous = None
|
|
93
|
-
|
|
94
|
-
(self.ch_names_used, _, self.feature_idx, _) = self._get_ch_info()
|
|
95
|
-
|
|
96
|
-
self.preprocessors: list[Preprocessor] = []
|
|
97
|
-
for preprocessing_method in self.settings["preprocessing"]:
|
|
98
|
-
settings_str = f"{preprocessing_method}_settings"
|
|
99
|
-
match preprocessing_method:
|
|
100
|
-
case "raw_resampling":
|
|
101
|
-
preprocessor = nm_resample.Resampler(
|
|
102
|
-
sfreq=self.sfreq_raw, **self.settings[settings_str]
|
|
103
|
-
)
|
|
104
|
-
self.sfreq_raw = preprocessor.sfreq_new
|
|
105
|
-
self.preprocessors.append(preprocessor)
|
|
106
|
-
case "notch_filter":
|
|
107
|
-
preprocessor = nm_filter.NotchFilter(
|
|
108
|
-
sfreq=self.sfreq_raw,
|
|
109
|
-
line_noise=self.line_noise,
|
|
110
|
-
**self.settings.get(settings_str, {}),
|
|
111
|
-
)
|
|
112
|
-
self.preprocessors.append(preprocessor)
|
|
113
|
-
case "re_referencing":
|
|
114
|
-
preprocessor = nm_rereference.ReReferencer(
|
|
115
|
-
sfreq=self.sfreq_raw,
|
|
116
|
-
nm_channels=self.nm_channels,
|
|
117
|
-
)
|
|
118
|
-
self.preprocessors.append(preprocessor)
|
|
119
|
-
case "raw_normalization":
|
|
120
|
-
preprocessor = nm_normalization.RawNormalizer(
|
|
121
|
-
sfreq=self.sfreq_raw,
|
|
122
|
-
sampling_rate_features_hz=self.sfreq_features,
|
|
123
|
-
**self.settings.get(settings_str, {}),
|
|
124
|
-
)
|
|
125
|
-
self.preprocessors.append(preprocessor)
|
|
126
|
-
case "preprocessing_filter":
|
|
127
|
-
preprocessor = nm_filter_preprocessing.PreprocessingFilter(
|
|
128
|
-
settings=self.settings,
|
|
129
|
-
sfreq=self.sfreq_raw,
|
|
130
|
-
)
|
|
131
|
-
self.preprocessors.append(preprocessor)
|
|
132
|
-
case _:
|
|
133
|
-
raise ValueError(
|
|
134
|
-
"Invalid preprocessing method. Must be one of"
|
|
135
|
-
f" {_PREPROCESSING_CONSTRUCTORS}. Got"
|
|
136
|
-
f" {preprocessing_method}"
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
if self.settings["postprocessing"]["feature_normalization"]:
|
|
140
|
-
settings_str = "feature_normalization_settings"
|
|
141
|
-
self.feature_normalizer = nm_normalization.FeatureNormalizer(
|
|
142
|
-
sampling_rate_features_hz=self.sfreq_features,
|
|
143
|
-
**self.settings.get(settings_str, {}),
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
self.features = nm_features.Features(
|
|
147
|
-
s=self.settings,
|
|
148
|
-
ch_names=self.ch_names_used,
|
|
149
|
-
sfreq=self.sfreq_raw,
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
if coord_list is not None and coord_names is not None:
|
|
153
|
-
self.coords = self._set_coords(
|
|
154
|
-
coord_names=coord_names, coord_list=coord_list
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
self.projection = self._get_projection(self.settings, self.nm_channels)
|
|
158
|
-
|
|
159
|
-
self.cnt_samples = 0
|
|
160
|
-
|
|
161
|
-
@staticmethod
|
|
162
|
-
def _add_coordinates(coord_names: list[str], coord_list: list) -> dict:
|
|
163
|
-
"""Write cortical and subcortical coordinate information in joint dictionary
|
|
164
|
-
|
|
165
|
-
Parameters
|
|
166
|
-
----------
|
|
167
|
-
coord_names : list[str]
|
|
168
|
-
list of coordinate names
|
|
169
|
-
coord_list : list
|
|
170
|
-
list of list of 3D coordinates
|
|
171
|
-
|
|
172
|
-
Returns
|
|
173
|
-
-------
|
|
174
|
-
dict with (sub)cortex_left and (sub)cortex_right ch_names and positions
|
|
175
|
-
"""
|
|
176
|
-
|
|
177
|
-
def is_left_coord(val: int | float, coord_region: str) -> bool:
|
|
178
|
-
if coord_region.split("_")[1] == "left":
|
|
179
|
-
return val < 0
|
|
180
|
-
return val > 0
|
|
181
|
-
|
|
182
|
-
coords = {}
|
|
183
|
-
|
|
184
|
-
for coord_region in [
|
|
185
|
-
coord_loc + "_" + lat
|
|
186
|
-
for coord_loc in ["cortex", "subcortex"]
|
|
187
|
-
for lat in ["left", "right"]
|
|
188
|
-
]:
|
|
189
|
-
coords[coord_region] = {}
|
|
190
|
-
|
|
191
|
-
ch_type = (
|
|
192
|
-
"ECOG" if "cortex" == coord_region.split("_")[0] else "LFP"
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
coords[coord_region]["ch_names"] = [
|
|
196
|
-
coord_name
|
|
197
|
-
for coord_name, ch in zip(coord_names, coord_list)
|
|
198
|
-
if is_left_coord(ch[0], coord_region)
|
|
199
|
-
and (ch_type in coord_name)
|
|
200
|
-
]
|
|
201
|
-
|
|
202
|
-
# multiply by 1000 to get m instead of mm
|
|
203
|
-
positions = []
|
|
204
|
-
for coord, coord_name in zip(coord_list, coord_names):
|
|
205
|
-
if is_left_coord(coord[0], coord_region) and (
|
|
206
|
-
ch_type in coord_name
|
|
207
|
-
):
|
|
208
|
-
positions.append(coord)
|
|
209
|
-
positions = np.array(positions, dtype=np.float64) * 1000
|
|
210
|
-
coords[coord_region]["positions"] = positions
|
|
211
|
-
|
|
212
|
-
return coords
|
|
213
|
-
|
|
214
|
-
def _get_ch_info(
|
|
215
|
-
self,
|
|
216
|
-
) -> tuple[list[str], list[str], list[int], np.ndarray]:
|
|
217
|
-
"""Get used feature and label info from nm_channels"""
|
|
218
|
-
nm_channels = self.nm_channels
|
|
219
|
-
ch_names_used = nm_channels[nm_channels["used"] == 1][
|
|
220
|
-
"new_name"
|
|
221
|
-
].tolist()
|
|
222
|
-
ch_types_used = nm_channels[nm_channels["used"] == 1]["type"].tolist()
|
|
223
|
-
|
|
224
|
-
# used channels for feature estimation
|
|
225
|
-
feature_idx = np.where(nm_channels["used"] & ~nm_channels["target"])[
|
|
226
|
-
0
|
|
227
|
-
].tolist()
|
|
228
|
-
|
|
229
|
-
# If multiple targets exist, select only the first
|
|
230
|
-
label_idx = np.where(nm_channels["target"] == 1)[0]
|
|
231
|
-
|
|
232
|
-
return ch_names_used, ch_types_used, feature_idx, label_idx
|
|
233
|
-
|
|
234
|
-
@staticmethod
|
|
235
|
-
def _get_grids(
|
|
236
|
-
settings: dict,
|
|
237
|
-
path_grids: str | _PathLike | None,
|
|
238
|
-
grid_type: Type[GRIDS],
|
|
239
|
-
) -> tuple[pd.DataFrame | None, pd.DataFrame | None]:
|
|
240
|
-
"""Read settings specified grids
|
|
241
|
-
|
|
242
|
-
Parameters
|
|
243
|
-
----------
|
|
244
|
-
settings : dict
|
|
245
|
-
path_grids : str
|
|
246
|
-
grid_type : GRIDS
|
|
247
|
-
|
|
248
|
-
Returns
|
|
249
|
-
-------
|
|
250
|
-
Tuple
|
|
251
|
-
grid_cortex, grid_subcortex,
|
|
252
|
-
might be None if not specified in settings
|
|
253
|
-
"""
|
|
254
|
-
if settings["postprocessing"]["project_cortex"] is True:
|
|
255
|
-
grid_cortex = nm_IO.read_grid(path_grids, grid_type.CORTEX.name)
|
|
256
|
-
else:
|
|
257
|
-
grid_cortex = None
|
|
258
|
-
if settings["postprocessing"]["project_subcortex"] is True:
|
|
259
|
-
grid_subcortex = nm_IO.read_grid(
|
|
260
|
-
path_grids, grid_type.SUBCORTEX.name
|
|
261
|
-
)
|
|
262
|
-
else:
|
|
263
|
-
grid_subcortex = None
|
|
264
|
-
return grid_cortex, grid_subcortex
|
|
265
|
-
|
|
266
|
-
def _get_projection(
|
|
267
|
-
self, settings: dict, nm_channels: pd.DataFrame
|
|
268
|
-
) -> nm_projection.Projection | None:
|
|
269
|
-
"""Return projection of used coordinated and grids"""
|
|
270
|
-
|
|
271
|
-
if not any(
|
|
272
|
-
(
|
|
273
|
-
settings["postprocessing"]["project_cortex"],
|
|
274
|
-
settings["postprocessing"]["project_subcortex"],
|
|
275
|
-
)
|
|
276
|
-
):
|
|
277
|
-
return None
|
|
278
|
-
|
|
279
|
-
grid_cortex, grid_subcortex = self._get_grids(
|
|
280
|
-
self.settings, self.path_grids, GRIDS
|
|
281
|
-
)
|
|
282
|
-
projection = nm_projection.Projection(
|
|
283
|
-
settings=settings,
|
|
284
|
-
grid_cortex=grid_cortex,
|
|
285
|
-
grid_subcortex=grid_subcortex,
|
|
286
|
-
coords=self.coords,
|
|
287
|
-
nm_channels=nm_channels,
|
|
288
|
-
plot_projection=False,
|
|
289
|
-
)
|
|
290
|
-
return projection
|
|
291
|
-
|
|
292
|
-
@staticmethod
|
|
293
|
-
def _load_nm_channels(
|
|
294
|
-
nm_channels: pd.DataFrame | _PathLike,
|
|
295
|
-
) -> pd.DataFrame:
|
|
296
|
-
if not isinstance(nm_channels, pd.DataFrame):
|
|
297
|
-
return nm_IO.load_nm_channels(nm_channels)
|
|
298
|
-
return nm_channels
|
|
299
|
-
|
|
300
|
-
@staticmethod
|
|
301
|
-
def _load_settings(settings: dict | _PathLike) -> dict:
|
|
302
|
-
if not isinstance(settings, dict):
|
|
303
|
-
return nm_IO.read_settings(str(settings))
|
|
304
|
-
return settings
|
|
305
|
-
|
|
306
|
-
def _set_coords(
|
|
307
|
-
self, coord_names: list[str] | None, coord_list: list | None
|
|
308
|
-
) -> dict:
|
|
309
|
-
if not any(
|
|
310
|
-
(
|
|
311
|
-
self.settings["postprocessing"]["project_cortex"],
|
|
312
|
-
self.settings["postprocessing"]["project_subcortex"],
|
|
313
|
-
)
|
|
314
|
-
):
|
|
315
|
-
return {}
|
|
316
|
-
|
|
317
|
-
if any((coord_list is None, coord_names is None)):
|
|
318
|
-
raise ValueError(
|
|
319
|
-
"No coordinates could be loaded. Please provide coord_list and"
|
|
320
|
-
f" coord_names. Got: {coord_list=}, {coord_names=}."
|
|
321
|
-
)
|
|
322
|
-
|
|
323
|
-
return self._add_coordinates(
|
|
324
|
-
coord_names=coord_names, coord_list=coord_list
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
def process(self, data: np.ndarray) -> pd.Series:
|
|
328
|
-
"""Given a new data batch, calculate and return features.
|
|
329
|
-
|
|
330
|
-
Parameters
|
|
331
|
-
----------
|
|
332
|
-
data : np.ndarray
|
|
333
|
-
Current batch of raw data
|
|
334
|
-
|
|
335
|
-
Returns
|
|
336
|
-
-------
|
|
337
|
-
pandas Series
|
|
338
|
-
Features calculated from current data
|
|
339
|
-
"""
|
|
340
|
-
start_time = time()
|
|
341
|
-
|
|
342
|
-
nan_channels = np.isnan(data).any(axis=1)
|
|
343
|
-
|
|
344
|
-
data = np.nan_to_num(data)[self.feature_idx, :]
|
|
345
|
-
|
|
346
|
-
for processor in self.preprocessors:
|
|
347
|
-
data = processor.process(data)
|
|
348
|
-
|
|
349
|
-
# calculate features
|
|
350
|
-
features_dict = self.features.estimate_features(data)
|
|
351
|
-
|
|
352
|
-
# normalize features
|
|
353
|
-
if self.settings["postprocessing"]["feature_normalization"]:
|
|
354
|
-
normed_features = self.feature_normalizer.process(
|
|
355
|
-
np.fromiter(features_dict.values(), dtype="float")
|
|
356
|
-
)
|
|
357
|
-
features_dict = {
|
|
358
|
-
key: normed_features[idx]
|
|
359
|
-
for idx, key in enumerate(features_dict.keys())
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
features_current = pd.Series(
|
|
363
|
-
data=list(features_dict.values()),
|
|
364
|
-
index=list(features_dict.keys()),
|
|
365
|
-
dtype=np.float64,
|
|
366
|
-
)
|
|
367
|
-
|
|
368
|
-
# project features to grid
|
|
369
|
-
if self.projection:
|
|
370
|
-
features_current = self.projection.project_features(
|
|
371
|
-
features_current
|
|
372
|
-
)
|
|
373
|
-
|
|
374
|
-
# check for all features, where the channel had a NaN, that the feature is also put to NaN
|
|
375
|
-
if nan_channels.sum() > 0:
|
|
376
|
-
for ch in list(np.array(self.ch_names_used)[nan_channels]):
|
|
377
|
-
features_current.loc[
|
|
378
|
-
features_current.index.str.contains(ch)
|
|
379
|
-
] = np.nan
|
|
380
|
-
|
|
381
|
-
if self.verbose is True:
|
|
382
|
-
logger.info(
|
|
383
|
-
"Last batch took: "
|
|
384
|
-
+ str(np.round(time() - start_time, 2))
|
|
385
|
-
+ " seconds"
|
|
386
|
-
)
|
|
387
|
-
|
|
388
|
-
return features_current
|
|
389
|
-
|
|
390
|
-
def save_sidecar(
|
|
391
|
-
self,
|
|
392
|
-
out_path_root: _PathLike,
|
|
393
|
-
folder_name: str,
|
|
394
|
-
additional_args: dict | None = None,
|
|
395
|
-
) -> None:
|
|
396
|
-
"""Save sidecar incuding fs, coords, sess_right to
|
|
397
|
-
out_path_root and subfolder 'folder_name'.
|
|
398
|
-
"""
|
|
399
|
-
sidecar = {
|
|
400
|
-
"original_fs": self._sfreq_raw_orig,
|
|
401
|
-
"final_fs": self.sfreq_raw,
|
|
402
|
-
"sfreq": self.sfreq_features,
|
|
403
|
-
}
|
|
404
|
-
if self.projection:
|
|
405
|
-
sidecar["coords"] = self.projection.coords
|
|
406
|
-
if self.settings["postprocessing"]["project_cortex"]:
|
|
407
|
-
sidecar["grid_cortex"] = self.projection.grid_cortex
|
|
408
|
-
sidecar["proj_matrix_cortex"] = (
|
|
409
|
-
self.projection.proj_matrix_cortex
|
|
410
|
-
)
|
|
411
|
-
if self.settings["postprocessing"]["project_subcortex"]:
|
|
412
|
-
sidecar["grid_subcortex"] = self.projection.grid_subcortex
|
|
413
|
-
sidecar["proj_matrix_subcortex"] = (
|
|
414
|
-
self.projection.proj_matrix_subcortex
|
|
415
|
-
)
|
|
416
|
-
if additional_args is not None:
|
|
417
|
-
sidecar = sidecar | additional_args
|
|
418
|
-
|
|
419
|
-
nm_IO.save_sidecar(sidecar, out_path_root, folder_name)
|
|
420
|
-
|
|
421
|
-
def save_settings(self, out_path_root: _PathLike, folder_name: str) -> None:
|
|
422
|
-
nm_IO.save_settings(self.settings, out_path_root, folder_name)
|
|
423
|
-
|
|
424
|
-
def save_nm_channels(
|
|
425
|
-
self, out_path_root: _PathLike, folder_name: str
|
|
426
|
-
) -> None:
|
|
427
|
-
nm_IO.save_nm_channels(self.nm_channels, out_path_root, folder_name)
|
|
428
|
-
|
|
429
|
-
def save_features(
|
|
430
|
-
self,
|
|
431
|
-
out_path_root: _PathLike,
|
|
432
|
-
folder_name: str,
|
|
433
|
-
feature_arr: pd.DataFrame,
|
|
434
|
-
) -> None:
|
|
435
|
-
nm_IO.save_features(feature_arr, out_path_root, folder_name)
|