py-neuromodulation 0.0.4__py3-none-any.whl → 0.0.5__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/FieldTrip.py +589 -589
- py_neuromodulation/__init__.py +74 -13
- py_neuromodulation/_write_example_dataset_helper.py +83 -65
- 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/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/nm_IO.py +413 -417
- py_neuromodulation/nm_RMAP.py +496 -531
- py_neuromodulation/nm_analysis.py +993 -1074
- py_neuromodulation/nm_artifacts.py +30 -25
- py_neuromodulation/nm_bispectra.py +154 -168
- py_neuromodulation/nm_bursts.py +292 -198
- py_neuromodulation/nm_coherence.py +251 -205
- py_neuromodulation/nm_database.py +149 -0
- py_neuromodulation/nm_decode.py +918 -992
- py_neuromodulation/nm_define_nmchannels.py +300 -302
- py_neuromodulation/nm_features.py +144 -116
- py_neuromodulation/nm_filter.py +219 -219
- py_neuromodulation/nm_filter_preprocessing.py +79 -91
- py_neuromodulation/nm_fooof.py +139 -159
- py_neuromodulation/nm_generator.py +45 -37
- py_neuromodulation/nm_hjorth_raw.py +52 -73
- py_neuromodulation/nm_kalmanfilter.py +71 -58
- py_neuromodulation/nm_linelength.py +21 -33
- py_neuromodulation/nm_logger.py +66 -0
- py_neuromodulation/nm_mne_connectivity.py +149 -112
- py_neuromodulation/nm_mnelsl_generator.py +90 -0
- py_neuromodulation/nm_mnelsl_stream.py +116 -0
- py_neuromodulation/nm_nolds.py +96 -93
- py_neuromodulation/nm_normalization.py +173 -214
- py_neuromodulation/nm_oscillatory.py +423 -448
- py_neuromodulation/nm_plots.py +585 -612
- py_neuromodulation/nm_preprocessing.py +83 -0
- py_neuromodulation/nm_projection.py +370 -394
- py_neuromodulation/nm_rereference.py +97 -95
- py_neuromodulation/nm_resample.py +59 -50
- py_neuromodulation/nm_run_analysis.py +325 -435
- py_neuromodulation/nm_settings.py +289 -68
- py_neuromodulation/nm_settings.yaml +244 -0
- py_neuromodulation/nm_sharpwaves.py +423 -401
- py_neuromodulation/nm_stats.py +464 -480
- py_neuromodulation/nm_stream.py +398 -0
- py_neuromodulation/nm_stream_abc.py +166 -218
- py_neuromodulation/nm_types.py +193 -0
- {py_neuromodulation-0.0.4.dist-info → py_neuromodulation-0.0.5.dist-info}/METADATA +29 -26
- py_neuromodulation-0.0.5.dist-info/RECORD +83 -0
- {py_neuromodulation-0.0.4.dist-info → py_neuromodulation-0.0.5.dist-info}/WHEEL +1 -1
- {py_neuromodulation-0.0.4.dist-info → py_neuromodulation-0.0.5.dist-info}/licenses/LICENSE +21 -21
- py_neuromodulation/nm_EpochStream.py +0 -92
- py_neuromodulation/nm_across_patient_decoding.py +0 -927
- py_neuromodulation/nm_cohortwrapper.py +0 -435
- py_neuromodulation/nm_eval_timing.py +0 -239
- py_neuromodulation/nm_features_abc.py +0 -39
- py_neuromodulation/nm_settings.json +0 -338
- 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,302 +1,300 @@
|
|
|
1
|
-
"""Module for handling nm_channels."""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import pandas as pd
|
|
5
|
-
import numpy as np
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
_LFP_TYPES = ["seeg", "dbs", "lfp"] # must be lower-case
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def set_channels(
|
|
12
|
-
ch_names: list[str],
|
|
13
|
-
ch_types: list[str],
|
|
14
|
-
reference:
|
|
15
|
-
bads:
|
|
16
|
-
new_names:
|
|
17
|
-
ecog_only: bool = False,
|
|
18
|
-
used_types:
|
|
19
|
-
target_keywords:
|
|
20
|
-
) -> pd.DataFrame:
|
|
21
|
-
"""Return dataframe with channel-specific settings in nm_channels format.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
"""
|
|
68
|
-
if not (len(ch_names) == len(ch_types)):
|
|
69
|
-
raise ValueError(
|
|
70
|
-
"Number of `ch_names` and `ch_types` must match."
|
|
71
|
-
f"Got: {len(ch_names)} `ch_names` and {len(ch_types)} `ch_types`."
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
df = pd.DataFrame(
|
|
75
|
-
data=None,
|
|
76
|
-
columns=[
|
|
77
|
-
"name",
|
|
78
|
-
"rereference",
|
|
79
|
-
"used",
|
|
80
|
-
"target",
|
|
81
|
-
"type",
|
|
82
|
-
"status",
|
|
83
|
-
"new_name",
|
|
84
|
-
],
|
|
85
|
-
)
|
|
86
|
-
df["name"] = ch_names
|
|
87
|
-
|
|
88
|
-
if used_types:
|
|
89
|
-
if
|
|
90
|
-
used_types = [
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
):
|
|
96
|
-
used_list.append(1)
|
|
97
|
-
else:
|
|
98
|
-
used_list.append(0)
|
|
99
|
-
df["used"] = used_list
|
|
100
|
-
else:
|
|
101
|
-
df["used"] = 0
|
|
102
|
-
|
|
103
|
-
if target_keywords:
|
|
104
|
-
if
|
|
105
|
-
target_keywords = [target_keywords]
|
|
106
|
-
targets = []
|
|
107
|
-
for ch_name in ch_names:
|
|
108
|
-
if any(kw.lower() in ch_name.lower() for kw in target_keywords):
|
|
109
|
-
targets.append(1)
|
|
110
|
-
else:
|
|
111
|
-
targets.append(0)
|
|
112
|
-
df["target"] = targets
|
|
113
|
-
else:
|
|
114
|
-
df["target"] = 0
|
|
115
|
-
|
|
116
|
-
# note: BIDS types are in caps, mne.io.RawArray types lower case
|
|
117
|
-
# so that 'type' will be in lower case here
|
|
118
|
-
df["type"] = ch_types
|
|
119
|
-
|
|
120
|
-
if ecog_only:
|
|
121
|
-
df.loc[(df["type"] == "seeg") | (df["type"] == "dbs"), "used"] = 0
|
|
122
|
-
|
|
123
|
-
if isinstance(reference, str):
|
|
124
|
-
if reference.lower() == "default":
|
|
125
|
-
df = _get_default_references(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
df["rereference"] =
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
] =
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
"
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
new_names.append(name + "
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
"
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
lfp_ch
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
lfp_ch
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
]
|
|
228
|
-
lfp_r
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
-
|
|
270
|
-
-
|
|
271
|
-
-
|
|
272
|
-
-
|
|
273
|
-
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
""
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
df =
|
|
294
|
-
df["
|
|
295
|
-
df["
|
|
296
|
-
df["
|
|
297
|
-
df["
|
|
298
|
-
df["
|
|
299
|
-
|
|
300
|
-
df
|
|
301
|
-
|
|
302
|
-
return df
|
|
1
|
+
"""Module for handling nm_channels."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
_LFP_TYPES = ["seeg", "dbs", "lfp"] # must be lower-case
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def set_channels(
|
|
12
|
+
ch_names: list[str],
|
|
13
|
+
ch_types: list[str],
|
|
14
|
+
reference: list | str = "default",
|
|
15
|
+
bads: list[str] | None = None,
|
|
16
|
+
new_names: str | list[str] = "default",
|
|
17
|
+
ecog_only: bool = False,
|
|
18
|
+
used_types: Iterable[str] | None = ("ecog", "dbs", "seeg"),
|
|
19
|
+
target_keywords: Iterable[str] | None = ("mov", "squared", "label"),
|
|
20
|
+
) -> pd.DataFrame:
|
|
21
|
+
"""Return dataframe with channel-specific settings in nm_channels format.
|
|
22
|
+
|
|
23
|
+
Return an nm_channels dataframe with the columns: "name", "rereference",
|
|
24
|
+
"used", "target", "type", "status", "new_name"]. "name" is set to ch_names,
|
|
25
|
+
"rereference" can be specified individually. "used" is set to 1 for all
|
|
26
|
+
channel types specified in `used_types`, else to 0. "target" is set to 1
|
|
27
|
+
for all channels containing any of the `target_keywords`, else to 0.
|
|
28
|
+
|
|
29
|
+
Possible channel types:
|
|
30
|
+
https://github.com/mne-tools/mne-python/blob/6ae3b22033c745cce5cd5de9b92da54c13c36484/doc/_includes/channel_types.rst
|
|
31
|
+
|
|
32
|
+
Arguments
|
|
33
|
+
---------
|
|
34
|
+
ch_names : list
|
|
35
|
+
list of channel names.
|
|
36
|
+
ch_types : list
|
|
37
|
+
list of channel types. Should optimally be of the types: "ECOG",
|
|
38
|
+
"DBS" or "SEEG".
|
|
39
|
+
reference : str | list of str | None, default: 'default'
|
|
40
|
+
re-referencing scheme. Default is "default". This sets ECOG channel
|
|
41
|
+
references to "average" and creates a bipolar referencing scheme
|
|
42
|
+
for LFP/DBS/SEEG channels, where each channel is referenced to
|
|
43
|
+
the adjacent lower channel, split by left and right hemisphere.
|
|
44
|
+
For this, the channel names must contain the substring "_L_" and/or
|
|
45
|
+
"_R_" (lower or upper case). CAVE: Adjacent channels will be
|
|
46
|
+
determined using the sort() function.
|
|
47
|
+
bads : str | list of str, default: None
|
|
48
|
+
channels that should be marked as bad and not be used for
|
|
49
|
+
average re-referencing etc.
|
|
50
|
+
new_names : list of str | None, default: 'default'
|
|
51
|
+
new channel names that should be used when writing out the
|
|
52
|
+
features and results. Useful when applying re-referencing. Set to
|
|
53
|
+
'None' if no renaming should be performed. 'default' will infer
|
|
54
|
+
channel renaming from re-referencing information. If a list is
|
|
55
|
+
given, it should be in the same order as 'ch_names'.
|
|
56
|
+
ecog_only : boolean, default: False
|
|
57
|
+
if True, set only 'ecog' channel type to used
|
|
58
|
+
used_types : iterable of str | None, default : ("ecog", "dbs", "seeg")
|
|
59
|
+
data channel types to be used. Set to `None` to use no channel
|
|
60
|
+
types.
|
|
61
|
+
target_keywords : iterable of str | None, default : ("ecog", "dbs", "seeg")
|
|
62
|
+
keywords for target channels
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
df: DataFrame in nm_channels format
|
|
67
|
+
"""
|
|
68
|
+
if not (len(ch_names) == len(ch_types)):
|
|
69
|
+
raise ValueError(
|
|
70
|
+
"Number of `ch_names` and `ch_types` must match."
|
|
71
|
+
f"Got: {len(ch_names)} `ch_names` and {len(ch_types)} `ch_types`."
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
df = pd.DataFrame(
|
|
75
|
+
data=None,
|
|
76
|
+
columns=[
|
|
77
|
+
"name",
|
|
78
|
+
"rereference",
|
|
79
|
+
"used",
|
|
80
|
+
"target",
|
|
81
|
+
"type",
|
|
82
|
+
"status",
|
|
83
|
+
"new_name",
|
|
84
|
+
],
|
|
85
|
+
)
|
|
86
|
+
df["name"] = ch_names
|
|
87
|
+
|
|
88
|
+
if used_types:
|
|
89
|
+
if isinstance(used_types, str):
|
|
90
|
+
used_types = [
|
|
91
|
+
used_types
|
|
92
|
+
] # Even if the user passes only ("ecog"), the if statement bellow will work
|
|
93
|
+
used_list = []
|
|
94
|
+
for ch_type in ch_types:
|
|
95
|
+
if any(use_type.lower() == ch_type.lower() for use_type in used_types):
|
|
96
|
+
used_list.append(1)
|
|
97
|
+
else:
|
|
98
|
+
used_list.append(0)
|
|
99
|
+
df["used"] = used_list
|
|
100
|
+
else:
|
|
101
|
+
df["used"] = 0
|
|
102
|
+
|
|
103
|
+
if target_keywords:
|
|
104
|
+
if isinstance(target_keywords, str):
|
|
105
|
+
target_keywords = [target_keywords]
|
|
106
|
+
targets = []
|
|
107
|
+
for ch_name in ch_names:
|
|
108
|
+
if any(kw.lower() in ch_name.lower() for kw in target_keywords):
|
|
109
|
+
targets.append(1)
|
|
110
|
+
else:
|
|
111
|
+
targets.append(0)
|
|
112
|
+
df["target"] = targets
|
|
113
|
+
else:
|
|
114
|
+
df["target"] = 0
|
|
115
|
+
|
|
116
|
+
# note: BIDS types are in caps, mne.io.RawArray types lower case
|
|
117
|
+
# so that 'type' will be in lower case here
|
|
118
|
+
df["type"] = ch_types
|
|
119
|
+
|
|
120
|
+
if ecog_only:
|
|
121
|
+
df.loc[(df["type"] == "seeg") | (df["type"] == "dbs"), "used"] = 0
|
|
122
|
+
|
|
123
|
+
if isinstance(reference, str):
|
|
124
|
+
if reference.lower() == "default":
|
|
125
|
+
df = _get_default_references(df=df, ch_names=ch_names, ch_types=ch_types)
|
|
126
|
+
else:
|
|
127
|
+
raise ValueError(
|
|
128
|
+
"`reference` must be either `default`, `None` or "
|
|
129
|
+
"an iterable of new reference channel names. "
|
|
130
|
+
f"Got: {reference}."
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
elif isinstance(reference, list):
|
|
134
|
+
if len(ch_names) != len(reference):
|
|
135
|
+
raise ValueError(
|
|
136
|
+
"Number of `ch_names` and `reference` must match."
|
|
137
|
+
f"Got: {len(ch_names)} `ch_names` and {len(reference)}"
|
|
138
|
+
" `references`."
|
|
139
|
+
)
|
|
140
|
+
df["rereference"] = reference
|
|
141
|
+
elif not reference:
|
|
142
|
+
df.loc[:, "rereference"] = "None"
|
|
143
|
+
else:
|
|
144
|
+
raise ValueError(
|
|
145
|
+
"`reference` must be either `default`, None or "
|
|
146
|
+
"an iterable of new reference channel names. "
|
|
147
|
+
f"Got: {reference}."
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if bads:
|
|
151
|
+
if isinstance(bads, str):
|
|
152
|
+
bads = [bads]
|
|
153
|
+
df["status"] = ["bad" if ch in bads else "good" for ch in ch_names]
|
|
154
|
+
df.loc[df["status"] == "bad", "used"] = (
|
|
155
|
+
0 # setting bad channels to not being used
|
|
156
|
+
)
|
|
157
|
+
else:
|
|
158
|
+
df["status"] = "good"
|
|
159
|
+
|
|
160
|
+
if not new_names:
|
|
161
|
+
df["new_name"] = ch_names
|
|
162
|
+
elif isinstance(new_names, str):
|
|
163
|
+
if new_names.lower() != "default":
|
|
164
|
+
raise ValueError(
|
|
165
|
+
"`new_names` must be either `default`, None or "
|
|
166
|
+
"an iterable of new channel names. Got: "
|
|
167
|
+
f"{new_names}."
|
|
168
|
+
)
|
|
169
|
+
new_names = []
|
|
170
|
+
for name, ref in zip(df["name"], df["rereference"]):
|
|
171
|
+
if ref == "None":
|
|
172
|
+
new_names.append(name)
|
|
173
|
+
elif isinstance(ref, float):
|
|
174
|
+
if np.isnan(ref):
|
|
175
|
+
new_names.append(name)
|
|
176
|
+
elif ref == "average":
|
|
177
|
+
new_names.append(name + "_avgref")
|
|
178
|
+
else:
|
|
179
|
+
new_names.append(name + "_" + ref)
|
|
180
|
+
df["new_name"] = new_names
|
|
181
|
+
elif hasattr(new_names, "__iter__"):
|
|
182
|
+
if len(new_names) != len(ch_names):
|
|
183
|
+
raise ValueError(
|
|
184
|
+
"Number of `ch_names` and `new_names` must match."
|
|
185
|
+
f" Got: {len(ch_names)} `ch_names` and {len(new_names)}"
|
|
186
|
+
" `new_names`."
|
|
187
|
+
)
|
|
188
|
+
else:
|
|
189
|
+
df["new_name"] = ch_names
|
|
190
|
+
else:
|
|
191
|
+
raise ValueError(
|
|
192
|
+
"`new_names` must be either `default`, None or"
|
|
193
|
+
f" an iterable of new channel names. Got: {new_names}."
|
|
194
|
+
)
|
|
195
|
+
return df
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _get_default_references(
|
|
199
|
+
df: pd.DataFrame, ch_names: list[str], ch_types: list[str]
|
|
200
|
+
) -> pd.DataFrame:
|
|
201
|
+
"""Add references with default settings (ECOG CAR, LFP bipolar)."""
|
|
202
|
+
ecog_chs = []
|
|
203
|
+
lfp_chs = []
|
|
204
|
+
other_chs = []
|
|
205
|
+
for ch_name, ch_type in zip(ch_names, ch_types):
|
|
206
|
+
if "ecog" in ch_type.lower() or "ecog" in ch_name.lower():
|
|
207
|
+
ecog_chs.append(ch_name)
|
|
208
|
+
elif any(
|
|
209
|
+
lfp_type in ch_type.lower() or lfp_type in ch_name.lower()
|
|
210
|
+
for lfp_type in _LFP_TYPES
|
|
211
|
+
):
|
|
212
|
+
lfp_chs.append(ch_name)
|
|
213
|
+
else:
|
|
214
|
+
other_chs.append(ch_name)
|
|
215
|
+
lfp_l = [
|
|
216
|
+
lfp_ch
|
|
217
|
+
for lfp_ch in lfp_chs
|
|
218
|
+
if ("_l_" in lfp_ch.lower()) or ("_left_" in lfp_ch.lower())
|
|
219
|
+
]
|
|
220
|
+
lfp_l.sort()
|
|
221
|
+
lfp_r = [
|
|
222
|
+
lfp_ch
|
|
223
|
+
for lfp_ch in lfp_chs
|
|
224
|
+
if ("_r_" in lfp_ch.lower()) or ("_right_" in lfp_ch.lower())
|
|
225
|
+
]
|
|
226
|
+
lfp_r.sort()
|
|
227
|
+
lfp_l_refs = [lfp_l[i - 1] if i > 0 else lfp_l[-1] for i, _ in enumerate(lfp_l)]
|
|
228
|
+
lfp_r_refs = [lfp_r[i - 1] if i > 0 else lfp_r[-1] for i, _ in enumerate(lfp_r)]
|
|
229
|
+
ref_idx = list(df.columns).index("rereference")
|
|
230
|
+
if len(ecog_chs) > 1:
|
|
231
|
+
for ecog_ch in ecog_chs:
|
|
232
|
+
df.iloc[df[df["name"] == ecog_ch].index[0], ref_idx] = "average"
|
|
233
|
+
if (
|
|
234
|
+
len(lfp_l) > 1
|
|
235
|
+
): # if there is only a single channel, the channel would be subtracted from itself
|
|
236
|
+
for i, lfp in enumerate(lfp_l):
|
|
237
|
+
df.iloc[df[df["name"] == lfp].index[0], ref_idx] = lfp_l_refs[i]
|
|
238
|
+
if len(lfp_r) > 1:
|
|
239
|
+
for i, lfp in enumerate(lfp_r):
|
|
240
|
+
df.iloc[df[df["name"] == lfp].index[0], ref_idx] = lfp_r_refs[i]
|
|
241
|
+
for other_ch in other_chs:
|
|
242
|
+
df.iloc[df[df["name"] == other_ch].index[0], ref_idx] = "None"
|
|
243
|
+
|
|
244
|
+
df = df.replace(np.nan, "None")
|
|
245
|
+
|
|
246
|
+
return df
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def get_default_channels_from_data(
|
|
250
|
+
data: np.ndarray,
|
|
251
|
+
car_rereferencing: bool = True,
|
|
252
|
+
):
|
|
253
|
+
"""Return default nm_channels dataframe with
|
|
254
|
+
ecog datatype, no bad channels, no targets, common average rereferencing
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
data : np.ndarray
|
|
259
|
+
Data array in shape (n_channels, n_time)
|
|
260
|
+
car_rereferencing : bool, optional
|
|
261
|
+
use common average rereferencing, by default True
|
|
262
|
+
|
|
263
|
+
Returns
|
|
264
|
+
-------
|
|
265
|
+
pd.DataFrame
|
|
266
|
+
nm_channel dataframe containing columns:
|
|
267
|
+
- name
|
|
268
|
+
- rereference
|
|
269
|
+
- used
|
|
270
|
+
- target
|
|
271
|
+
- type
|
|
272
|
+
- status
|
|
273
|
+
- new_name
|
|
274
|
+
"""
|
|
275
|
+
|
|
276
|
+
ch_name = [f"ch{idx}" for idx in range(data.shape[0])]
|
|
277
|
+
status = ["good" for _ in range(data.shape[0])]
|
|
278
|
+
type_nm = ["ecog" for _ in range(data.shape[0])]
|
|
279
|
+
|
|
280
|
+
if car_rereferencing:
|
|
281
|
+
rereference = ["average" for _ in range(data.shape[0])]
|
|
282
|
+
new_name = [f"{ch}_avgref" for ch in ch_name]
|
|
283
|
+
else:
|
|
284
|
+
rereference = ["None" for _ in range(data.shape[0])]
|
|
285
|
+
new_name = ch_name
|
|
286
|
+
|
|
287
|
+
new_name = [f"{ch}_avgref" for ch in ch_name]
|
|
288
|
+
target = np.array([0 for _ in range(data.shape[0])])
|
|
289
|
+
used = np.array([1 for _ in range(data.shape[0])])
|
|
290
|
+
|
|
291
|
+
df = pd.DataFrame()
|
|
292
|
+
df["name"] = ch_name
|
|
293
|
+
df["rereference"] = rereference
|
|
294
|
+
df["used"] = used
|
|
295
|
+
df["target"] = target
|
|
296
|
+
df["type"] = type_nm
|
|
297
|
+
df["status"] = status
|
|
298
|
+
df["new_name"] = new_name
|
|
299
|
+
|
|
300
|
+
return df
|