py-neuromodulation 0.0.5__py3-none-any.whl → 0.0.7__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/__init__.py +16 -10
- py_neuromodulation/{nm_RMAP.py → analysis/RMAP.py} +2 -2
- py_neuromodulation/analysis/__init__.py +4 -0
- py_neuromodulation/{nm_decode.py → analysis/decode.py} +4 -4
- py_neuromodulation/{nm_analysis.py → analysis/feature_reader.py} +21 -20
- py_neuromodulation/{nm_plots.py → analysis/plots.py} +54 -12
- py_neuromodulation/{nm_stats.py → analysis/stats.py} +2 -8
- py_neuromodulation/{nm_settings.yaml → default_settings.yaml} +7 -9
- py_neuromodulation/features/__init__.py +31 -0
- py_neuromodulation/features/bandpower.py +165 -0
- py_neuromodulation/{nm_bispectra.py → features/bispectra.py} +11 -12
- py_neuromodulation/{nm_bursts.py → features/bursts.py} +14 -9
- py_neuromodulation/{nm_coherence.py → features/coherence.py} +28 -19
- py_neuromodulation/{nm_features.py → features/feature_processor.py} +30 -53
- py_neuromodulation/{nm_fooof.py → features/fooof.py} +11 -8
- py_neuromodulation/{nm_hjorth_raw.py → features/hjorth_raw.py} +10 -5
- py_neuromodulation/{nm_linelength.py → features/linelength.py} +1 -1
- py_neuromodulation/{nm_mne_connectivity.py → features/mne_connectivity.py} +5 -6
- py_neuromodulation/{nm_nolds.py → features/nolds.py} +5 -7
- py_neuromodulation/{nm_oscillatory.py → features/oscillatory.py} +7 -181
- py_neuromodulation/{nm_sharpwaves.py → features/sharpwaves.py} +13 -4
- py_neuromodulation/filter/__init__.py +3 -0
- py_neuromodulation/{nm_kalmanfilter.py → filter/kalman_filter.py} +67 -71
- py_neuromodulation/filter/kalman_filter_external.py +1890 -0
- py_neuromodulation/{nm_filter.py → filter/mne_filter.py} +128 -219
- py_neuromodulation/filter/notch_filter.py +93 -0
- py_neuromodulation/processing/__init__.py +10 -0
- py_neuromodulation/{nm_artifacts.py → processing/artifacts.py} +2 -3
- py_neuromodulation/{nm_preprocessing.py → processing/data_preprocessor.py} +19 -25
- py_neuromodulation/{nm_filter_preprocessing.py → processing/filter_preprocessing.py} +3 -4
- py_neuromodulation/{nm_normalization.py → processing/normalization.py} +9 -7
- py_neuromodulation/{nm_projection.py → processing/projection.py} +14 -14
- py_neuromodulation/{nm_rereference.py → processing/rereference.py} +13 -13
- py_neuromodulation/{nm_resample.py → processing/resample.py} +1 -4
- py_neuromodulation/stream/__init__.py +3 -0
- py_neuromodulation/{nm_run_analysis.py → stream/data_processor.py} +42 -42
- py_neuromodulation/stream/generator.py +53 -0
- py_neuromodulation/{nm_mnelsl_generator.py → stream/mnelsl_player.py} +10 -6
- py_neuromodulation/{nm_mnelsl_stream.py → stream/mnelsl_stream.py} +13 -9
- py_neuromodulation/{nm_settings.py → stream/settings.py} +27 -24
- py_neuromodulation/{nm_stream.py → stream/stream.py} +217 -188
- py_neuromodulation/utils/__init__.py +2 -0
- py_neuromodulation/{nm_define_nmchannels.py → utils/channels.py} +14 -9
- py_neuromodulation/{nm_database.py → utils/database.py} +2 -2
- py_neuromodulation/{nm_IO.py → utils/io.py} +42 -77
- py_neuromodulation/utils/keyboard.py +52 -0
- py_neuromodulation/{nm_logger.py → utils/logging.py} +3 -3
- py_neuromodulation/{nm_types.py → utils/types.py} +72 -14
- {py_neuromodulation-0.0.5.dist-info → py_neuromodulation-0.0.7.dist-info}/METADATA +12 -29
- py_neuromodulation-0.0.7.dist-info/RECORD +89 -0
- py_neuromodulation/FieldTrip.py +0 -589
- py_neuromodulation/_write_example_dataset_helper.py +0 -83
- py_neuromodulation/nm_generator.py +0 -45
- py_neuromodulation/nm_stream_abc.py +0 -166
- py_neuromodulation-0.0.5.dist-info/RECORD +0 -83
- {py_neuromodulation-0.0.5.dist-info → py_neuromodulation-0.0.7.dist-info}/WHEEL +0 -0
- {py_neuromodulation-0.0.5.dist-info → py_neuromodulation-0.0.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,34 +3,32 @@ from pathlib import PurePath, Path
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
|
-
import pandas as pd
|
|
7
6
|
|
|
8
|
-
from py_neuromodulation.
|
|
7
|
+
from py_neuromodulation.utils.types import _PathLike
|
|
9
8
|
from py_neuromodulation import logger, PYNM_DIR
|
|
10
9
|
|
|
11
10
|
if TYPE_CHECKING:
|
|
12
11
|
from mne_bids import BIDSPath
|
|
13
12
|
from mne import io as mne_io
|
|
13
|
+
import pandas as pd
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def
|
|
17
|
-
|
|
16
|
+
def load_channels(
|
|
17
|
+
channels: "pd.DataFrame | _PathLike",
|
|
18
18
|
) -> "pd.DataFrame":
|
|
19
|
-
"""Read
|
|
19
|
+
"""Read channels from path or specify via BIDS arguments.
|
|
20
20
|
Necessary parameters are then ch_names (list), ch_types (list), bads (list), used_types (list),
|
|
21
21
|
target_keywords (list) and reference Union[list, str].
|
|
22
22
|
"""
|
|
23
|
+
import pandas as pd
|
|
23
24
|
|
|
24
|
-
if isinstance(
|
|
25
|
-
|
|
26
|
-
elif nm_channels:
|
|
27
|
-
if not Path(nm_channels).is_file():
|
|
28
|
-
raise ValueError(
|
|
29
|
-
"PATH_NM_CHANNELS is not a valid file. Got: " f"{nm_channels}"
|
|
30
|
-
)
|
|
31
|
-
nm_ch_return = pd.read_csv(nm_channels)
|
|
25
|
+
if isinstance(channels, pd.DataFrame):
|
|
26
|
+
return channels
|
|
32
27
|
|
|
33
|
-
|
|
28
|
+
if not Path(channels).is_file():
|
|
29
|
+
raise ValueError("PATH_CHANNELS is not a valid file. Got: " f"{channels}")
|
|
30
|
+
|
|
31
|
+
return pd.read_csv(channels)
|
|
34
32
|
|
|
35
33
|
|
|
36
34
|
def read_BIDS_data(
|
|
@@ -150,7 +148,7 @@ def get_coord_list(
|
|
|
150
148
|
return coord_list, coord_names
|
|
151
149
|
|
|
152
150
|
|
|
153
|
-
def read_grid(PATH_GRIDS: _PathLike | None, grid_str: str) -> pd.DataFrame:
|
|
151
|
+
def read_grid(PATH_GRIDS: _PathLike | None, grid_str: str) -> "pd.DataFrame":
|
|
154
152
|
"""Read grid file from path or PYNM_DIR
|
|
155
153
|
|
|
156
154
|
Parameters
|
|
@@ -165,6 +163,8 @@ def read_grid(PATH_GRIDS: _PathLike | None, grid_str: str) -> pd.DataFrame:
|
|
|
165
163
|
pd.DataFrame
|
|
166
164
|
pd.DataFrame including mni x,y,z coordinates for each grid point
|
|
167
165
|
"""
|
|
166
|
+
import pandas as pd
|
|
167
|
+
|
|
168
168
|
if PATH_GRIDS is None:
|
|
169
169
|
grid = pd.read_csv(PYNM_DIR / ("grid_" + grid_str.lower() + ".tsv"), sep="\t")
|
|
170
170
|
else:
|
|
@@ -190,46 +190,6 @@ def get_annotations(PATH_ANNOTATIONS: str, PATH_RUN: str, raw_arr: "mne_io.RawAr
|
|
|
190
190
|
return annot, annot_data, raw_arr
|
|
191
191
|
|
|
192
192
|
|
|
193
|
-
def read_plot_modules(
|
|
194
|
-
PATH_PLOT: _PathLike = PYNM_DIR / "plots",
|
|
195
|
-
):
|
|
196
|
-
"""Read required .mat files for plotting
|
|
197
|
-
|
|
198
|
-
Parameters
|
|
199
|
-
----------
|
|
200
|
-
PATH_PLOT : regexp, optional
|
|
201
|
-
path to plotting files, by default
|
|
202
|
-
"""
|
|
203
|
-
|
|
204
|
-
faces = loadmat(PurePath(PATH_PLOT, "faces.mat"))
|
|
205
|
-
vertices = loadmat(PurePath(PATH_PLOT, "Vertices.mat"))
|
|
206
|
-
grid = loadmat(PurePath(PATH_PLOT, "grid.mat"))["grid"]
|
|
207
|
-
stn_surf = loadmat(PurePath(PATH_PLOT, "STN_surf.mat"))
|
|
208
|
-
x_ver = stn_surf["vertices"][::2, 0]
|
|
209
|
-
y_ver = stn_surf["vertices"][::2, 1]
|
|
210
|
-
x_ecog = vertices["Vertices"][::1, 0]
|
|
211
|
-
y_ecog = vertices["Vertices"][::1, 1]
|
|
212
|
-
z_ecog = vertices["Vertices"][::1, 2]
|
|
213
|
-
x_stn = stn_surf["vertices"][::1, 0]
|
|
214
|
-
y_stn = stn_surf["vertices"][::1, 1]
|
|
215
|
-
z_stn = stn_surf["vertices"][::1, 2]
|
|
216
|
-
|
|
217
|
-
return (
|
|
218
|
-
faces,
|
|
219
|
-
vertices,
|
|
220
|
-
grid,
|
|
221
|
-
stn_surf,
|
|
222
|
-
x_ver,
|
|
223
|
-
y_ver,
|
|
224
|
-
x_ecog,
|
|
225
|
-
y_ecog,
|
|
226
|
-
z_ecog,
|
|
227
|
-
x_stn,
|
|
228
|
-
y_stn,
|
|
229
|
-
z_stn,
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
|
|
233
193
|
def write_csv(df, path_out):
|
|
234
194
|
"""
|
|
235
195
|
Function to save Pandas dataframes to disk as CSV using
|
|
@@ -242,31 +202,31 @@ def write_csv(df, path_out):
|
|
|
242
202
|
csv.write_csv(Table.from_pandas(df), path_out)
|
|
243
203
|
|
|
244
204
|
|
|
245
|
-
def
|
|
246
|
-
nmchannels: pd.DataFrame,
|
|
247
|
-
out_dir: _PathLike,
|
|
205
|
+
def save_channels(
|
|
206
|
+
nmchannels: "pd.DataFrame",
|
|
207
|
+
out_dir: _PathLike = "",
|
|
248
208
|
prefix: str = "",
|
|
249
209
|
) -> None:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
write_csv(nmchannels,
|
|
253
|
-
logger.info(f"
|
|
210
|
+
out_dir = Path.cwd() if not out_dir else Path(out_dir)
|
|
211
|
+
filename = "channels.csv" if not prefix else prefix + "_channels.csv"
|
|
212
|
+
write_csv(nmchannels, out_dir / filename)
|
|
213
|
+
logger.info(f"{filename} saved to {out_dir}")
|
|
254
214
|
|
|
255
215
|
|
|
256
216
|
def save_features(
|
|
257
|
-
df_features: pd.DataFrame,
|
|
258
|
-
out_dir: _PathLike,
|
|
217
|
+
df_features: "pd.DataFrame",
|
|
218
|
+
out_dir: _PathLike = "",
|
|
259
219
|
prefix: str = "",
|
|
260
220
|
) -> None:
|
|
221
|
+
out_dir = Path.cwd() if not out_dir else Path(out_dir)
|
|
261
222
|
filename = f"{prefix}_FEATURES.csv" if prefix else "_FEATURES.csv"
|
|
262
|
-
out_dir
|
|
263
|
-
|
|
264
|
-
logger.info(f"FEATURES.csv saved to {str(out_dir)}")
|
|
223
|
+
write_csv(df_features, out_dir / filename)
|
|
224
|
+
logger.info(f"{filename} saved to {str(out_dir)}")
|
|
265
225
|
|
|
266
226
|
|
|
267
227
|
def save_sidecar(
|
|
268
228
|
sidecar: dict,
|
|
269
|
-
out_dir: _PathLike,
|
|
229
|
+
out_dir: _PathLike = "",
|
|
270
230
|
prefix: str = "",
|
|
271
231
|
) -> None:
|
|
272
232
|
save_general_dict(sidecar, out_dir, prefix, "_SIDECAR.json")
|
|
@@ -274,15 +234,14 @@ def save_sidecar(
|
|
|
274
234
|
|
|
275
235
|
def save_general_dict(
|
|
276
236
|
dict_: dict,
|
|
277
|
-
out_dir: _PathLike,
|
|
237
|
+
out_dir: _PathLike = "",
|
|
278
238
|
prefix: str = "",
|
|
279
239
|
str_add: str = "",
|
|
280
240
|
) -> None:
|
|
281
|
-
|
|
241
|
+
out_dir = Path.cwd() if not out_dir else Path(out_dir)
|
|
242
|
+
filename = f"{prefix}{str_add}"
|
|
282
243
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
with open(path_out, "w") as f:
|
|
244
|
+
with open(out_dir / filename, "w") as f:
|
|
286
245
|
json.dump(
|
|
287
246
|
dict_,
|
|
288
247
|
f,
|
|
@@ -290,10 +249,12 @@ def save_general_dict(
|
|
|
290
249
|
indent=4,
|
|
291
250
|
separators=(",", ": "),
|
|
292
251
|
)
|
|
293
|
-
logger.info(f"{
|
|
252
|
+
logger.info(f"{filename} saved to {out_dir}")
|
|
294
253
|
|
|
295
254
|
|
|
296
255
|
def default_json_convert(obj) -> list | float:
|
|
256
|
+
import pandas as pd
|
|
257
|
+
|
|
297
258
|
if isinstance(obj, np.ndarray):
|
|
298
259
|
return obj.tolist()
|
|
299
260
|
if isinstance(obj, pd.DataFrame):
|
|
@@ -310,12 +271,16 @@ def read_sidecar(PATH: _PathLike) -> dict:
|
|
|
310
271
|
return json.load(f)
|
|
311
272
|
|
|
312
273
|
|
|
313
|
-
def read_features(PATH: _PathLike) -> pd.DataFrame:
|
|
274
|
+
def read_features(PATH: _PathLike) -> "pd.DataFrame":
|
|
275
|
+
import pandas as pd
|
|
276
|
+
|
|
314
277
|
return pd.read_csv(str(PATH) + "_FEATURES.csv", engine="pyarrow")
|
|
315
278
|
|
|
316
279
|
|
|
317
|
-
def
|
|
318
|
-
|
|
280
|
+
def read_channels(PATH: _PathLike) -> "pd.DataFrame":
|
|
281
|
+
import pandas as pd
|
|
282
|
+
|
|
283
|
+
return pd.read_csv(str(PATH) + "_channels.csv")
|
|
319
284
|
|
|
320
285
|
|
|
321
286
|
def get_run_list_indir(PATH: _PathLike) -> list:
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import sys
|
|
3
|
+
from typing import Callable
|
|
4
|
+
|
|
5
|
+
if sys.platform.startswith("win"):
|
|
6
|
+
import msvcrt
|
|
7
|
+
else:
|
|
8
|
+
import termios
|
|
9
|
+
import tty
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class KeyboardListener:
|
|
13
|
+
def __init__(self, event_callback: tuple[str, Callable] | None = None):
|
|
14
|
+
self.callbacks = {}
|
|
15
|
+
self.running = False
|
|
16
|
+
|
|
17
|
+
if event_callback is not None:
|
|
18
|
+
self.on_press(*event_callback)
|
|
19
|
+
|
|
20
|
+
def on_press(self, key, callback):
|
|
21
|
+
self.callbacks[key] = callback
|
|
22
|
+
|
|
23
|
+
async def _windows_listener(self):
|
|
24
|
+
while self.running:
|
|
25
|
+
if msvcrt.kbhit():
|
|
26
|
+
key = msvcrt.getch().decode("utf-8").lower()
|
|
27
|
+
if key in self.callbacks:
|
|
28
|
+
await self.callbacks[key]()
|
|
29
|
+
await asyncio.sleep(0.01)
|
|
30
|
+
|
|
31
|
+
async def _unix_listener(self):
|
|
32
|
+
fd = sys.stdin.fileno()
|
|
33
|
+
old_settings = termios.tcgetattr(fd)
|
|
34
|
+
try:
|
|
35
|
+
tty.setraw(fd)
|
|
36
|
+
while self.running:
|
|
37
|
+
key = sys.stdin.read(1).lower()
|
|
38
|
+
if key in self.callbacks:
|
|
39
|
+
await self.callbacks[key]()
|
|
40
|
+
await asyncio.sleep(0.01)
|
|
41
|
+
finally:
|
|
42
|
+
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
43
|
+
|
|
44
|
+
async def start(self):
|
|
45
|
+
self.running = True
|
|
46
|
+
if sys.platform.startswith("win"):
|
|
47
|
+
await self._windows_listener()
|
|
48
|
+
else:
|
|
49
|
+
await self._unix_listener()
|
|
50
|
+
|
|
51
|
+
def stop(self):
|
|
52
|
+
self.running = False
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from py_neuromodulation.
|
|
2
|
+
from py_neuromodulation.utils.types import _PathLike
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
INFOFORMAT = "%(name)s:\t%(message)s"
|
|
@@ -52,12 +52,12 @@ class NMLogger(logging.Logger):
|
|
|
52
52
|
path = Path(path)
|
|
53
53
|
path.mkdir(parents=True, exist_ok=True)
|
|
54
54
|
|
|
55
|
-
self.debug_file_handler = logging.FileHandler(path / "
|
|
55
|
+
self.debug_file_handler = logging.FileHandler(path / "logfile_pydebug.log")
|
|
56
56
|
self.debug_file_handler.setLevel(logging.DEBUG)
|
|
57
57
|
self.debug_file_handler.setFormatter(logging.Formatter(DEBUGFORMAT))
|
|
58
58
|
|
|
59
59
|
self.info_file_handler = logging.FileHandler(
|
|
60
|
-
path / "
|
|
60
|
+
path / "logfile_pyinfo.log", mode=mode
|
|
61
61
|
)
|
|
62
62
|
self.info_file_handler.setLevel(logging.INFO)
|
|
63
63
|
self.info_file_handler.setFormatter(logging.Formatter(INFOFORMAT))
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
from os import PathLike
|
|
2
2
|
from math import isnan
|
|
3
|
-
from typing import
|
|
4
|
-
from importlib import import_module
|
|
3
|
+
from typing import Any, Literal, Protocol, TYPE_CHECKING, runtime_checkable
|
|
5
4
|
from pydantic import ConfigDict, Field, model_validator, BaseModel
|
|
5
|
+
from pydantic_core import ValidationError, InitErrorDetails
|
|
6
6
|
from pprint import pformat
|
|
7
7
|
from collections.abc import Sequence
|
|
8
8
|
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
import numpy as np
|
|
11
|
+
from py_neuromodulation import NMSettings
|
|
12
|
+
|
|
9
13
|
###################################
|
|
10
14
|
########## TYPE ALIASES ##########
|
|
11
15
|
###################################
|
|
@@ -48,20 +52,37 @@ NormMethod = Literal[
|
|
|
48
52
|
"minmax",
|
|
49
53
|
]
|
|
50
54
|
|
|
51
|
-
|
|
52
55
|
###################################
|
|
53
|
-
|
|
56
|
+
######## PROTOCOL CLASSES ########
|
|
54
57
|
###################################
|
|
55
|
-
class ImportDetails(NamedTuple):
|
|
56
|
-
module_name: str
|
|
57
|
-
class_name: str
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
)
|
|
60
|
+
@runtime_checkable
|
|
61
|
+
class NMFeature(Protocol):
|
|
62
|
+
def __init__(
|
|
63
|
+
self, settings: "NMSettings", ch_names: Sequence[str], sfreq: int | float
|
|
64
|
+
) -> None: ...
|
|
65
|
+
|
|
66
|
+
def calc_feature(self, data: "np.ndarray") -> dict:
|
|
67
|
+
"""
|
|
68
|
+
Feature calculation method. Each method needs to loop through all channels
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
data : 'np.ndarray'
|
|
73
|
+
(channels, time)
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
dict
|
|
78
|
+
"""
|
|
79
|
+
...
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class NMPreprocessor(Protocol):
|
|
83
|
+
def __init__(self, sfreq: float, settings: "NMSettings") -> None: ...
|
|
84
|
+
|
|
85
|
+
def process(self, data: "np.ndarray") -> "np.ndarray": ...
|
|
65
86
|
|
|
66
87
|
|
|
67
88
|
###################################
|
|
@@ -99,8 +120,8 @@ class NMBaseModel(BaseModel):
|
|
|
99
120
|
|
|
100
121
|
|
|
101
122
|
class FrequencyRange(NMBaseModel):
|
|
102
|
-
frequency_low_hz: float = Field(
|
|
103
|
-
frequency_high_hz: float = Field(
|
|
123
|
+
frequency_low_hz: float = Field(gt=0)
|
|
124
|
+
frequency_high_hz: float = Field(gt=0)
|
|
104
125
|
|
|
105
126
|
def __init__(self, *args, **kwargs) -> None:
|
|
106
127
|
super().__init__(*args, **kwargs)
|
|
@@ -191,3 +212,40 @@ class BoolSelector(NMBaseModel):
|
|
|
191
212
|
@classmethod
|
|
192
213
|
def get_fields(cls):
|
|
193
214
|
return cls.model_fields
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def create_validation_error(
|
|
218
|
+
error_message: str,
|
|
219
|
+
loc: list[str | int] = None,
|
|
220
|
+
title: str = "Validation Error",
|
|
221
|
+
input_type: Literal["python", "json"] = "python",
|
|
222
|
+
hide_input: bool = False,
|
|
223
|
+
) -> ValidationError:
|
|
224
|
+
"""
|
|
225
|
+
Factory function to create a Pydantic v2 ValidationError instance from a single error message.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
error_message (str): The error message for the ValidationError.
|
|
229
|
+
loc (List[str | int], optional): The location of the error. Defaults to None.
|
|
230
|
+
title (str, optional): The title of the error. Defaults to "Validation Error".
|
|
231
|
+
input_type (Literal["python", "json"], optional): Whether the error is for a Python object or JSON. Defaults to "python".
|
|
232
|
+
hide_input (bool, optional): Whether to hide the input value in the error message. Defaults to False.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
ValidationError: A Pydantic ValidationError instance.
|
|
236
|
+
"""
|
|
237
|
+
if loc is None:
|
|
238
|
+
loc = []
|
|
239
|
+
|
|
240
|
+
line_errors = [
|
|
241
|
+
InitErrorDetails(
|
|
242
|
+
type="value_error", loc=tuple(loc), input=None, ctx={"error": error_message}
|
|
243
|
+
)
|
|
244
|
+
]
|
|
245
|
+
|
|
246
|
+
return ValidationError.from_exception_data(
|
|
247
|
+
title=title,
|
|
248
|
+
line_errors=line_errors,
|
|
249
|
+
input_type=input_type,
|
|
250
|
+
hide_input=hide_input,
|
|
251
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: py_neuromodulation
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.7
|
|
4
4
|
Summary: Real-time analysis of intracranial neurophysiology recordings.
|
|
5
5
|
Project-URL: bugtracker, https://github.com/neuromodulation/py_neuromodulation/issues
|
|
6
6
|
Project-URL: repository, https://github.com/neuromodulation/py_neuromodulation
|
|
@@ -33,35 +33,28 @@ Classifier: Development Status :: 2 - Pre-Alpha
|
|
|
33
33
|
Classifier: License :: OSI Approved :: MIT License
|
|
34
34
|
Classifier: Programming Language :: Python
|
|
35
35
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
36
|
-
Requires-Python: >=3.
|
|
37
|
-
Requires-Dist: filterpy>=1.4.5
|
|
36
|
+
Requires-Python: >=3.11
|
|
38
37
|
Requires-Dist: fooof
|
|
39
|
-
Requires-Dist: hatch>=1.9.4
|
|
40
|
-
Requires-Dist: imbalanced-learn
|
|
41
38
|
Requires-Dist: joblib>=1.3.2
|
|
39
|
+
Requires-Dist: llvmlite>=0.43.0
|
|
42
40
|
Requires-Dist: matplotlib>=3.9.0
|
|
43
41
|
Requires-Dist: mne
|
|
44
42
|
Requires-Dist: mne-bids>=0.8
|
|
45
43
|
Requires-Dist: mne-connectivity
|
|
46
44
|
Requires-Dist: mne-lsl>=1.2.0
|
|
47
45
|
Requires-Dist: mrmr-selection
|
|
48
|
-
Requires-Dist:
|
|
49
|
-
Requires-Dist:
|
|
46
|
+
Requires-Dist: nolds>=0.6.1
|
|
47
|
+
Requires-Dist: numba>=0.60.0
|
|
50
48
|
Requires-Dist: numpy>=1.21.2
|
|
51
49
|
Requires-Dist: pandas>=2.0.0
|
|
52
|
-
Requires-Dist: pip>=24.2
|
|
53
50
|
Requires-Dist: pyarrow>=14.0.2
|
|
54
|
-
Requires-Dist: pybispectra>=1.
|
|
51
|
+
Requires-Dist: pybispectra>=1.2.0
|
|
55
52
|
Requires-Dist: pydantic>=2.7.3
|
|
56
|
-
Requires-Dist: pynput
|
|
57
53
|
Requires-Dist: pyparrm
|
|
58
|
-
Requires-Dist: pyqt5
|
|
59
|
-
Requires-Dist: scikit-image
|
|
60
54
|
Requires-Dist: scikit-learn>=0.24.2
|
|
61
55
|
Requires-Dist: scikit-optimize
|
|
62
56
|
Requires-Dist: scipy>=1.7.1
|
|
63
57
|
Requires-Dist: seaborn>=0.11
|
|
64
|
-
Requires-Dist: statsmodels
|
|
65
58
|
Provides-Extra: dev
|
|
66
59
|
Requires-Dist: notebook; extra == 'dev'
|
|
67
60
|
Requires-Dist: pytest-cov; extra == 'dev'
|
|
@@ -116,7 +109,7 @@ The original intention for writing this toolbox was movement decoding from invas
|
|
|
116
109
|
The application however could be any neural decoding problem.
|
|
117
110
|
*py_neuromodulation* offers wrappers around common practice machine learning methods for efficient analysis.
|
|
118
111
|
|
|
119
|
-
Find the documentation here
|
|
112
|
+
Find the documentation here neuromodulation.github.io/py_neuromodulation/ for example usage and parametrization.
|
|
120
113
|
|
|
121
114
|
Installation
|
|
122
115
|
============
|
|
@@ -127,25 +120,15 @@ py_neuromodulation requires at least python 3.10. For installation you can use p
|
|
|
127
120
|
|
|
128
121
|
pip install py-neuromodulation
|
|
129
122
|
|
|
130
|
-
Alternatively you can also
|
|
123
|
+
Alternatively you can also clone the pacakge and install it using `uv <https://docs.astral.sh/uv/>`_:
|
|
131
124
|
|
|
132
125
|
.. code-block::
|
|
133
126
|
|
|
134
|
-
|
|
135
|
-
|
|
127
|
+
uv python install 3.10
|
|
128
|
+
uv venv
|
|
129
|
+
. .venv/bin/activate
|
|
130
|
+
uv sync
|
|
136
131
|
|
|
137
|
-
Then install the packages listed in the `pyproject.toml`:
|
|
138
|
-
|
|
139
|
-
.. code-block::
|
|
140
|
-
|
|
141
|
-
pip install .
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
Optionally the ipython kernel can be specified for the installed pynm-test conda environment:
|
|
145
|
-
|
|
146
|
-
.. code-block::
|
|
147
|
-
|
|
148
|
-
ipython kernel install --user --name=pynm-test
|
|
149
132
|
|
|
150
133
|
Then *py_neuromodulation* can be imported via:
|
|
151
134
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
py_neuromodulation/__init__.py,sha256=MaOF7mCNRjR9MgcCnk9b7dYJICVJthiWlZVf365lXOo,2831
|
|
2
|
+
py_neuromodulation/default_settings.yaml,sha256=06KzRz8eLAa5--gmrYsr_bn9UOzSMIpuktrPKNaSc4A,5568
|
|
3
|
+
py_neuromodulation/grid_cortex.tsv,sha256=k2QOkHY1ej3lJ33LD6DOPVlTynzB3s4BYaoQaoUCyYc,643
|
|
4
|
+
py_neuromodulation/grid_subcortex.tsv,sha256=oCQDYLDdYSa1DAI9ybwECfuzWulFzXqKHyf7oZ1oDBM,25842
|
|
5
|
+
py_neuromodulation/ConnectivityDecoding/Automated Anatomical Labeling 3 (Rolls 2020).nii,sha256=Sp-cjF_AuT0Tlilb5s8lB14hVgkXJiR2uKMS9nOQOeg,902981
|
|
6
|
+
py_neuromodulation/ConnectivityDecoding/_get_grid_hull.m,sha256=2RPDGotbLsCzDJLFB2JXatJtfOMno9UUBCBnsOuse8A,714
|
|
7
|
+
py_neuromodulation/ConnectivityDecoding/_get_grid_whole_brain.py,sha256=VsInAIADIf9d3unxUSN0B50aU472IQocGZ-kyG8A7Fc,3066
|
|
8
|
+
py_neuromodulation/ConnectivityDecoding/_helper_write_connectome.py,sha256=1DNrccrJqrH5PIW2yp24xbyqRrsRz98Gof5aPQZUUUE,3423
|
|
9
|
+
py_neuromodulation/ConnectivityDecoding/mni_coords_cortical_surface.mat,sha256=AZc0mgiAiqXVAxAnfxwICeh-dQX62RfTeRN_knS-i60,11622
|
|
10
|
+
py_neuromodulation/ConnectivityDecoding/mni_coords_whole_brain.mat,sha256=YxT9nrXZ2IECheEhN1SgSsqNyihHUTLuZQ7o5yP4Q-c,29864
|
|
11
|
+
py_neuromodulation/ConnectivityDecoding/rmap_func_all.nii,sha256=WjVA02B2cGNi670_45fdNssspf8GKbkKgRStZ2d4_FU,7221384
|
|
12
|
+
py_neuromodulation/ConnectivityDecoding/rmap_struc.nii,sha256=XsEMjsCxjAsMFvw1_jpQ-wIU2BUuZ_lISPwMa7zDmDk,7221384
|
|
13
|
+
py_neuromodulation/analysis/RMAP.py,sha256=e5qTZ680NkLZbI0cpVpsIqDy7OEhsoabedv5pVq6bG0,15001
|
|
14
|
+
py_neuromodulation/analysis/__init__.py,sha256=x9lKfCnOaawYdil39CWszpDNNtXFckF__RxbE0HnwKA,116
|
|
15
|
+
py_neuromodulation/analysis/decode.py,sha256=eK-jfrHmfthVQbpYCM8E2DbYOUD-AyLSSumXrrXt67E,33167
|
|
16
|
+
py_neuromodulation/analysis/feature_reader.py,sha256=Nyb2OLLX-jCVrFy_CI0FWzd7mCeqUG-MdHT4gj3bR3Y,35596
|
|
17
|
+
py_neuromodulation/analysis/plots.py,sha256=B625WZaLOm4Z6oQ5nrqnM77WaU9C1Ezn8UGggHAfIF8,17728
|
|
18
|
+
py_neuromodulation/analysis/stats.py,sha256=ZZIXTGh6r9gfiJV1RwZpLzDgqyia9mIDt8yNEN8cSw8,15094
|
|
19
|
+
py_neuromodulation/data/README,sha256=8PhEkUm8F2NgL7A5co1CgfumAMB14v5XPIbk54SvtAE,708
|
|
20
|
+
py_neuromodulation/data/dataset_description.json,sha256=HMHtmF0bbw9XO79GAyRt8urpEyxRJ5A1REcYos8D2s0,122
|
|
21
|
+
py_neuromodulation/data/participants.json,sha256=S4rrcSAmLcL_jLk9IY_cwJBipl8OwwCvouZ7tsgdldw,756
|
|
22
|
+
py_neuromodulation/data/participants.tsv,sha256=-dg_i5N4I-Cp1l21433z1lDjXUmcuTn8S3UqkxPvgdI,77
|
|
23
|
+
py_neuromodulation/data/sub-testsub/ses-EphysMedOff/sub-testsub_ses-EphysMedOff_scans.tsv,sha256=iz6Nvf_E5jChjacmO_eAxX7Y8rR8v03-gGdUeBlyDVY,89
|
|
24
|
+
py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_coordsystem.json,sha256=dq0Vc2fIR-YvbCEqBb7lq3P_YkOOzkKe1Hh-a1gd46E,118
|
|
25
|
+
py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_electrodes.tsv,sha256=Kr9vKh1qnnwFQE0Cet7PkeVuuGx1u-CT_xXs4qucezg,722
|
|
26
|
+
py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_channels.tsv,sha256=ZSixrfpSlNEfmv0diaJ96usFPwPtO_dA6CCDYDp85KY,779
|
|
27
|
+
py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.eeg,sha256=NnQeMDrKpeK3lctIZ5Bzh85UMTs5OCUCaivn_NU5rc4,760040
|
|
28
|
+
py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.json,sha256=nRPEWAa0isyDKbeW1IPhL9ECWkzqfQw1sKwJkZU3vbk,474
|
|
29
|
+
py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vhdr,sha256=-QEHwQjJb9Hp9yudEawqhQl8vrD8bYqiuvlF4cyPNg0,988
|
|
30
|
+
py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vmrk,sha256=BD-VmcKe7dR0vGzzkv4c09QnSwc3zYeAWDGJIzWEOI0,540
|
|
31
|
+
py_neuromodulation/features/__init__.py,sha256=zpulQ3IaKh6yNSnCBIRa5IC3SZ7FlKNQxHLF50yTdQU,1567
|
|
32
|
+
py_neuromodulation/features/bandpower.py,sha256=rpkY2dNayXYng1BmZxyKTxgrJFnrslPaKVUpoNXE6EA,6152
|
|
33
|
+
py_neuromodulation/features/bispectra.py,sha256=BzI0UsMnBWal6qtqmTmLOR20IA_Wly7EIy0wCK0QgVQ,5272
|
|
34
|
+
py_neuromodulation/features/bursts.py,sha256=7-I81RYSZEm5pbIKc6wXmfxmJ4Q6V41CfJXebqkGGDw,11467
|
|
35
|
+
py_neuromodulation/features/coherence.py,sha256=j1J7GHTElVuAl7x2NsGVpoQLQ9npxyznJ6HM7Nzb49k,9040
|
|
36
|
+
py_neuromodulation/features/feature_processor.py,sha256=CT05jNks681LOcyr2yHe1KaUryJXm52_53hNmEhuWnM,3972
|
|
37
|
+
py_neuromodulation/features/fooof.py,sha256=RouqFikiKf_JSiEel569lfjzfYRE7CEvBlgvuj53Xj4,5016
|
|
38
|
+
py_neuromodulation/features/hjorth_raw.py,sha256=mRPioPHJdN73AGErRbJ5S1Vz__qEQ89jAKaeN5k8eXo,1845
|
|
39
|
+
py_neuromodulation/features/linelength.py,sha256=8BTctvr9Zj8TEK2HLJqi73j_y2Xgt8lKK-mJhv8eAsM,641
|
|
40
|
+
py_neuromodulation/features/mne_connectivity.py,sha256=3d5U16E1Tu7f2Djs1TS1cjKlKnLHJV-jDP7fY4QeksU,5699
|
|
41
|
+
py_neuromodulation/features/nolds.py,sha256=jNCKQlIfmcAhmzjTAJMbFPhRuPtYZF5BDzR4qHlLp1k,3374
|
|
42
|
+
py_neuromodulation/features/oscillatory.py,sha256=9TIUWd_G1E4KSMbhjVjlD7mJlA0rT87qCdB24g7PjEw,7695
|
|
43
|
+
py_neuromodulation/features/sharpwaves.py,sha256=1-l0WWzz7De4rAel5j8tiUHK-H9E3MqbspGPwwUKtfw,16677
|
|
44
|
+
py_neuromodulation/filter/__init__.py,sha256=ut1q8daCZoN7lhTKURGpk1X5oKiS3eSNqR7SkZyGDJw,128
|
|
45
|
+
py_neuromodulation/filter/kalman_filter.py,sha256=wy-coztc0dAX8Rqow5s-Fv4rvub33Sv52FdkNu9y6uA,1871
|
|
46
|
+
py_neuromodulation/filter/kalman_filter_external.py,sha256=_7FFq-1GQY9mNA0EvmaM4wQ46DVkHC9bYFIgiw9b6nY,61367
|
|
47
|
+
py_neuromodulation/filter/mne_filter.py,sha256=S3Swv8xY-yLIsNkYC6WHRL5T3EaNAM5a3Gx0BYSRqzY,4496
|
|
48
|
+
py_neuromodulation/filter/notch_filter.py,sha256=CF4VTMMt9bzl1hvp7Rk9H1Ui4buMkn4uNelxDF_9uKk,3284
|
|
49
|
+
py_neuromodulation/liblsl/libpugixml.so.1.12,sha256=_bCOHUjcnGpDiROg1qjgty8ZQhcKHSnaCIP6SMgw6SY,240248
|
|
50
|
+
py_neuromodulation/liblsl/linux/bionic_amd64/liblsl.1.16.2.so,sha256=YXFbA23CQqWg6mWhk-73WY9gSx79NtgnBr6UFVByC2I,1033592
|
|
51
|
+
py_neuromodulation/liblsl/linux/bookworm_amd64/liblsl.1.16.2.so,sha256=3gKI0HsheWJvFgZdnT27Ev824y7rkOOCVRiHdAlKHUM,791688
|
|
52
|
+
py_neuromodulation/liblsl/linux/focal_amd46/liblsl.1.16.2.so,sha256=OCVevlOtKPblu7lWFN_x4HIibxfihgoPzQtGjsYEXUo,923264
|
|
53
|
+
py_neuromodulation/liblsl/linux/jammy_amd64/liblsl.1.16.2.so,sha256=MSmfv900ShdCj3-ipsADxmbiTg3WoZ_SvUrByeZB45g,935392
|
|
54
|
+
py_neuromodulation/liblsl/linux/jammy_x86/liblsl.1.16.2.so,sha256=MSmfv900ShdCj3-ipsADxmbiTg3WoZ_SvUrByeZB45g,935392
|
|
55
|
+
py_neuromodulation/liblsl/linux/noble_amd64/liblsl.1.16.2.so,sha256=-p_sEh6LuxDKKVVcT5Y0Loeq7FK11LoE34RmMIKqdaw,3009496
|
|
56
|
+
py_neuromodulation/liblsl/macos/amd64/liblsl.1.16.2.dylib,sha256=7BLTPGbq7ISuG3ZdLUem7fER6ZXrYYryY477b3j4lNw,807896
|
|
57
|
+
py_neuromodulation/liblsl/macos/arm64/liblsl.1.16.0.dylib,sha256=UD228wOmdFIY9WKmpYgWKeJuVQ6wqI6K2EWWk1G3vM8,758048
|
|
58
|
+
py_neuromodulation/liblsl/windows/amd64/liblsl.1.16.2.dll,sha256=M4tzeUOkvXv5_3GZheWJJ74q1AAIIGmcEZLugJIHxGo,804864
|
|
59
|
+
py_neuromodulation/liblsl/windows/x86/liblsl.1.16.2.dll,sha256=UBdyYfWp7CpydLo1I0nsCSM1uHnnbNrF2FF1fHuOops,599040
|
|
60
|
+
py_neuromodulation/plots/STN_surf.mat,sha256=Hh2nfQRmP0TYIt8SWV-ajKnC8yk7EmBoAj1c6RMoi9g,124526
|
|
61
|
+
py_neuromodulation/plots/Vertices.mat,sha256=k72WB8-0Datt-bRScxcfpp38LBPHV34zzodS49kQAgs,3709780
|
|
62
|
+
py_neuromodulation/plots/faces.mat,sha256=gWSr-9qNxsAPoG8q-muNnaFZHVHGKqnKN0j3Q1JfMk4,2859245
|
|
63
|
+
py_neuromodulation/plots/grid.mat,sha256=G3MYIVcvk8lbf_kKWIe3lZZ4d0QV6HkoLsOFN1A2vhE,775
|
|
64
|
+
py_neuromodulation/processing/__init__.py,sha256=nYPHBltTEOvJi7MrNCgcT0BGbCo2bCjwBhaLXPxlFg4,548
|
|
65
|
+
py_neuromodulation/processing/artifacts.py,sha256=lrEpNwnFPz8GzDy6RWXk_aqroUz7eGPHdolOo5RPv1I,850
|
|
66
|
+
py_neuromodulation/processing/data_preprocessor.py,sha256=L2r7jkvGoTGxv4Q0YFfFsVrR2lYysTVDZJHWMNZHtu0,2989
|
|
67
|
+
py_neuromodulation/processing/filter_preprocessing.py,sha256=_I5dXwA9GDVKv8EY-ONcJeJ7OcRu0BxJwZTFfkjPVzc,2823
|
|
68
|
+
py_neuromodulation/processing/normalization.py,sha256=k1vW4yQJ70Xu-9eMJeX210eV9poLRmSyA71lvzZg_6g,5457
|
|
69
|
+
py_neuromodulation/processing/projection.py,sha256=esPQfS7-oXFXkzRvEIEyl5skWk9KVcdoIKRNLwvBjbk,14700
|
|
70
|
+
py_neuromodulation/processing/rereference.py,sha256=n9zLNDkuqeP7zwrP5bhsiXF9eYVPwqI4hZvvQzZ5cks,3304
|
|
71
|
+
py_neuromodulation/processing/resample.py,sha256=YwgGq900kGHhg1avmn-ju9M0mx9FvXQ06qj5-Ztv9Qk,1230
|
|
72
|
+
py_neuromodulation/stream/__init__.py,sha256=R4Fm4ApFdnbG9x13fQm1uhslVf3P0mdtnexzDohEWF0,124
|
|
73
|
+
py_neuromodulation/stream/data_processor.py,sha256=lODMA3DFxBfJPm4AeMLG6-e71pxj_6_EqevMrQmUSYY,11107
|
|
74
|
+
py_neuromodulation/stream/generator.py,sha256=UKLuM8gz2YLBuVQnQNkkOOKhwsyW27ZgvRJ_5BK7Glo,1588
|
|
75
|
+
py_neuromodulation/stream/mnelsl_player.py,sha256=e8l5ufEeCBljjl-oogi43TOmP7s_xQeVdpCREvtfWvk,2992
|
|
76
|
+
py_neuromodulation/stream/mnelsl_stream.py,sha256=hsqkgo0mEzvP40M3vps4Ma7BX6R3wXx07TQpPSjnmUw,4603
|
|
77
|
+
py_neuromodulation/stream/settings.py,sha256=19tRmjHDkkmgzdocBIa9tb-LyMPFlcoopuU7zsvrWZQ,10072
|
|
78
|
+
py_neuromodulation/stream/stream.py,sha256=cstSVfmfJwReocAI88Pf-4VKMY0Qv53eJ1JyZMFe5zI,15599
|
|
79
|
+
py_neuromodulation/utils/__init__.py,sha256=Ok3STMpsflCTclJC9C1iQgdT-3HNGMM7U45w5Oespr4,46
|
|
80
|
+
py_neuromodulation/utils/channels.py,sha256=Y8hrJxEY_2MJEBlicRkJk04XsBUXEZ2NYYb1toEaDek,10632
|
|
81
|
+
py_neuromodulation/utils/database.py,sha256=VEFsmbYDQWwaoZKmJCG8oyWoDTbfSiT_p0n7da9_Pn4,4755
|
|
82
|
+
py_neuromodulation/utils/io.py,sha256=-qAwtFSsumfzY6dkYSKGySE8_RH1c2M1NDxC_ZQrUVM,10387
|
|
83
|
+
py_neuromodulation/utils/keyboard.py,sha256=swoxYhf4Q3pj50EKALUFt6hREfXnoXq2Z2q01IahPe8,1505
|
|
84
|
+
py_neuromodulation/utils/logging.py,sha256=eIBFBRaAMb3KJnoxNFiCkMrTGzWwgfeDs8m5iq6FxN8,2178
|
|
85
|
+
py_neuromodulation/utils/types.py,sha256=QVq3wAgMcw5zKPa_Kj2QQ2Gt2CYavO_PAka3RAZdfwo,7310
|
|
86
|
+
py_neuromodulation-0.0.7.dist-info/METADATA,sha256=GnkK958mbJYayCTmPLr9c1lYj3s0cXg4LCqL0SHSQdw,7045
|
|
87
|
+
py_neuromodulation-0.0.7.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
88
|
+
py_neuromodulation-0.0.7.dist-info/licenses/LICENSE,sha256=EMBwuBRPBo-WkHSjqxZ55E6j95gKNBZ8x30pt-VGfrM,1118
|
|
89
|
+
py_neuromodulation-0.0.7.dist-info/RECORD,,
|