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.
Files changed (57) hide show
  1. py_neuromodulation/__init__.py +16 -10
  2. py_neuromodulation/{nm_RMAP.py → analysis/RMAP.py} +2 -2
  3. py_neuromodulation/analysis/__init__.py +4 -0
  4. py_neuromodulation/{nm_decode.py → analysis/decode.py} +4 -4
  5. py_neuromodulation/{nm_analysis.py → analysis/feature_reader.py} +21 -20
  6. py_neuromodulation/{nm_plots.py → analysis/plots.py} +54 -12
  7. py_neuromodulation/{nm_stats.py → analysis/stats.py} +2 -8
  8. py_neuromodulation/{nm_settings.yaml → default_settings.yaml} +7 -9
  9. py_neuromodulation/features/__init__.py +31 -0
  10. py_neuromodulation/features/bandpower.py +165 -0
  11. py_neuromodulation/{nm_bispectra.py → features/bispectra.py} +11 -12
  12. py_neuromodulation/{nm_bursts.py → features/bursts.py} +14 -9
  13. py_neuromodulation/{nm_coherence.py → features/coherence.py} +28 -19
  14. py_neuromodulation/{nm_features.py → features/feature_processor.py} +30 -53
  15. py_neuromodulation/{nm_fooof.py → features/fooof.py} +11 -8
  16. py_neuromodulation/{nm_hjorth_raw.py → features/hjorth_raw.py} +10 -5
  17. py_neuromodulation/{nm_linelength.py → features/linelength.py} +1 -1
  18. py_neuromodulation/{nm_mne_connectivity.py → features/mne_connectivity.py} +5 -6
  19. py_neuromodulation/{nm_nolds.py → features/nolds.py} +5 -7
  20. py_neuromodulation/{nm_oscillatory.py → features/oscillatory.py} +7 -181
  21. py_neuromodulation/{nm_sharpwaves.py → features/sharpwaves.py} +13 -4
  22. py_neuromodulation/filter/__init__.py +3 -0
  23. py_neuromodulation/{nm_kalmanfilter.py → filter/kalman_filter.py} +67 -71
  24. py_neuromodulation/filter/kalman_filter_external.py +1890 -0
  25. py_neuromodulation/{nm_filter.py → filter/mne_filter.py} +128 -219
  26. py_neuromodulation/filter/notch_filter.py +93 -0
  27. py_neuromodulation/processing/__init__.py +10 -0
  28. py_neuromodulation/{nm_artifacts.py → processing/artifacts.py} +2 -3
  29. py_neuromodulation/{nm_preprocessing.py → processing/data_preprocessor.py} +19 -25
  30. py_neuromodulation/{nm_filter_preprocessing.py → processing/filter_preprocessing.py} +3 -4
  31. py_neuromodulation/{nm_normalization.py → processing/normalization.py} +9 -7
  32. py_neuromodulation/{nm_projection.py → processing/projection.py} +14 -14
  33. py_neuromodulation/{nm_rereference.py → processing/rereference.py} +13 -13
  34. py_neuromodulation/{nm_resample.py → processing/resample.py} +1 -4
  35. py_neuromodulation/stream/__init__.py +3 -0
  36. py_neuromodulation/{nm_run_analysis.py → stream/data_processor.py} +42 -42
  37. py_neuromodulation/stream/generator.py +53 -0
  38. py_neuromodulation/{nm_mnelsl_generator.py → stream/mnelsl_player.py} +10 -6
  39. py_neuromodulation/{nm_mnelsl_stream.py → stream/mnelsl_stream.py} +13 -9
  40. py_neuromodulation/{nm_settings.py → stream/settings.py} +27 -24
  41. py_neuromodulation/{nm_stream.py → stream/stream.py} +217 -188
  42. py_neuromodulation/utils/__init__.py +2 -0
  43. py_neuromodulation/{nm_define_nmchannels.py → utils/channels.py} +14 -9
  44. py_neuromodulation/{nm_database.py → utils/database.py} +2 -2
  45. py_neuromodulation/{nm_IO.py → utils/io.py} +42 -77
  46. py_neuromodulation/utils/keyboard.py +52 -0
  47. py_neuromodulation/{nm_logger.py → utils/logging.py} +3 -3
  48. py_neuromodulation/{nm_types.py → utils/types.py} +72 -14
  49. {py_neuromodulation-0.0.5.dist-info → py_neuromodulation-0.0.7.dist-info}/METADATA +12 -29
  50. py_neuromodulation-0.0.7.dist-info/RECORD +89 -0
  51. py_neuromodulation/FieldTrip.py +0 -589
  52. py_neuromodulation/_write_example_dataset_helper.py +0 -83
  53. py_neuromodulation/nm_generator.py +0 -45
  54. py_neuromodulation/nm_stream_abc.py +0 -166
  55. py_neuromodulation-0.0.5.dist-info/RECORD +0 -83
  56. {py_neuromodulation-0.0.5.dist-info → py_neuromodulation-0.0.7.dist-info}/WHEEL +0 -0
  57. {py_neuromodulation-0.0.5.dist-info → py_neuromodulation-0.0.7.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,11 @@
1
1
  import numpy as np
2
- import pandas as pd
3
2
  from pydantic import Field
4
- from py_neuromodulation.nm_types import NMBaseModel
3
+ from py_neuromodulation.utils.types import NMBaseModel
5
4
  from typing import TYPE_CHECKING
6
5
 
7
6
  if TYPE_CHECKING:
8
- from py_neuromodulation.nm_settings import NMSettings
7
+ from py_neuromodulation import NMSettings
8
+ import pandas as pd
9
9
 
10
10
 
11
11
  class ProjectionSettings(NMBaseModel):
@@ -16,16 +16,16 @@ class Projection:
16
16
  def __init__(
17
17
  self,
18
18
  settings: "NMSettings",
19
- grid_cortex: pd.DataFrame,
20
- grid_subcortex: pd.DataFrame,
19
+ grid_cortex: "pd.DataFrame",
20
+ grid_subcortex: "pd.DataFrame",
21
21
  coords: dict,
22
- nm_channels: pd.DataFrame,
22
+ channels: "pd.DataFrame",
23
23
  plot_projection: bool = False,
24
24
  ) -> None:
25
25
  self.grid_cortex = grid_cortex
26
26
  self.grid_subcortex = grid_subcortex
27
27
  self.coords = coords
28
- self.nm_channels = nm_channels
28
+ self.channels = channels
29
29
  self.project_cortex = settings.postprocessing.project_cortex
30
30
  self.project_subcortex = settings.postprocessing.project_subcortex
31
31
  self.max_dist_cortex = settings.project_cortex_settings.max_dist_mm
@@ -78,7 +78,7 @@ class Projection:
78
78
  )[0]
79
79
 
80
80
  if plot_projection:
81
- from py_neuromodulation.nm_plots import NM_Plot
81
+ from py_neuromodulation.analysis.plots import NM_Plot
82
82
 
83
83
  nmplotter = NM_Plot(
84
84
  ecog_strip=self.ecog_strip,
@@ -90,7 +90,7 @@ class Projection:
90
90
  nmplotter.plot_cortex()
91
91
 
92
92
  def remove_not_used_ch_from_coords(self):
93
- ch_not_used = self.nm_channels.query('(used==0) or (status=="bad")').name
93
+ ch_not_used = self.channels.query('(used==0) or (status=="bad")').name
94
94
  if len(ch_not_used) > 0:
95
95
  for ch in ch_not_used:
96
96
  for key_ in self.coords:
@@ -196,7 +196,7 @@ class Projection:
196
196
  """Initialize channel names via nm_channel new_name column"""
197
197
 
198
198
  if self.project_cortex:
199
- self.ecog_channels = self.nm_channels.query(
199
+ self.ecog_channels = self.channels.query(
200
200
  '(type=="ecog") and (used == 1) and (status=="good")'
201
201
  ).name.to_list()
202
202
 
@@ -206,11 +206,11 @@ class Projection:
206
206
  self.ecog_channels.remove(ecog_channel)
207
207
  # write ecog_channels to be new_name
208
208
  self.ecog_channels = list(
209
- self.nm_channels.query("name == @self.ecog_channels").new_name
209
+ self.channels.query("name == @self.ecog_channels").new_name
210
210
  )
211
211
 
212
212
  if self.project_subcortex:
213
- self.lfp_channels = self.nm_channels.query(
213
+ self.lfp_channels = self.channels.query(
214
214
  '(type=="lfp" or type=="seeg" or type=="dbs") \
215
215
  and (used == 1) and (status=="good")'
216
216
  ).name.to_list()
@@ -222,11 +222,11 @@ class Projection:
222
222
  self.lfp_channels.remove(lfp_channel)
223
223
  # write lfp_channels to be new_name
224
224
  self.lfp_channels = list(
225
- self.nm_channels.query("name == @self.lfp_channels").new_name
225
+ self.channels.query("name == @self.lfp_channels").new_name
226
226
  )
227
227
 
228
228
  def init_projection_run(self, feature_dict: dict) -> None:
229
- """Initialize indexes for respective channels in feature series computed by nm_features.py"""
229
+ """Initialize indexes for respective channels in feature series computed by features.py"""
230
230
  # here it is assumed that only one hemisphere is recorded at a time!
231
231
  if self.project_cortex:
232
232
  for ecog_channel in self.ecog_channels:
@@ -3,14 +3,14 @@
3
3
  import numpy as np
4
4
  import pandas as pd
5
5
 
6
- from py_neuromodulation.nm_preprocessing import NMPreprocessor
6
+ from py_neuromodulation.utils.types import NMPreprocessor
7
7
 
8
8
 
9
9
  class ReReferencer(NMPreprocessor):
10
10
  def __init__(
11
11
  self,
12
12
  sfreq: float,
13
- nm_channels: pd.DataFrame,
13
+ channels: pd.DataFrame,
14
14
  ) -> None:
15
15
  """Initialize real-time rereference information.
16
16
 
@@ -18,9 +18,9 @@ class ReReferencer(NMPreprocessor):
18
18
  ----------
19
19
  sfreq : float
20
20
  Sampling frequency. Is not used, only kept for compatibility.
21
- nm_channels : Pandas DataFrame
21
+ channels : Pandas DataFrame
22
22
  Dataframe containing information about rereferencing, as
23
- specified in nm_channels.csv.
23
+ specified in channels.csv.
24
24
 
25
25
 
26
26
  Raises:
@@ -30,27 +30,27 @@ class ReReferencer(NMPreprocessor):
30
30
 
31
31
  self.ref_matrix: np.ndarray | None
32
32
 
33
- nm_channels = nm_channels[nm_channels["used"] == 1].reset_index(drop=True)
34
- # (channels_used,) = np.where((nm_channels.used == 1))
33
+ channels = channels[channels["used"] == 1].reset_index(drop=True)
34
+ # (channels_used,) = np.where((channels.used == 1))
35
35
 
36
- ch_names = nm_channels["name"].tolist()
36
+ ch_names = channels["name"].tolist()
37
37
 
38
38
  # no re-referencing is being performed when there is a single channel present only
39
- if nm_channels.shape[0] in (0, 1):
39
+ if channels.shape[0] in (0, 1):
40
40
  self.ref_matrix = None
41
41
  return
42
42
 
43
- ch_types = nm_channels["type"]
44
- refs = nm_channels["rereference"]
43
+ ch_types = channels["type"]
44
+ refs = channels["rereference"]
45
45
 
46
46
  type_map = {}
47
47
  for ch_type in ch_types.unique():
48
48
  type_map[ch_type] = np.where(
49
- (ch_types == ch_type) & (nm_channels["status"] == "good")
49
+ (ch_types == ch_type) & (channels["status"] == "good")
50
50
  )[0]
51
51
 
52
- ref_matrix = np.zeros((len(nm_channels), len(nm_channels)))
53
- for ind in range(len(nm_channels)):
52
+ ref_matrix = np.zeros((len(channels), len(channels)))
53
+ for ind in range(len(channels)):
54
54
  ref_matrix[ind, ind] = 1
55
55
  # if ind not in channels_used:
56
56
  # continue
@@ -1,10 +1,7 @@
1
1
  """Module for resampling."""
2
2
 
3
3
  import numpy as np
4
- from py_neuromodulation.nm_types import NMBaseModel, Field
5
-
6
-
7
- from py_neuromodulation.nm_preprocessing import NMPreprocessor
4
+ from py_neuromodulation.utils.types import NMBaseModel, Field, NMPreprocessor
8
5
 
9
6
 
10
7
  class ResamplerSettings(NMBaseModel):
@@ -0,0 +1,3 @@
1
+ from .generator import RawDataGenerator
2
+ from .mnelsl_player import LSLOfflinePlayer
3
+ from .mnelsl_stream import LSLStream
@@ -1,15 +1,18 @@
1
1
  """This module contains the class to process a given batch of data."""
2
2
 
3
3
  from time import time
4
+ from typing import TYPE_CHECKING
4
5
  import numpy as np
5
- import pandas as pd
6
6
 
7
- from py_neuromodulation import nm_IO, logger
8
- from py_neuromodulation.nm_types import _PathLike
9
- from py_neuromodulation.nm_features import FeatureProcessors
10
- from py_neuromodulation.nm_preprocessing import NMPreprocessors
11
- from py_neuromodulation.nm_projection import Projection
12
- from py_neuromodulation.nm_settings import NMSettings
7
+ from py_neuromodulation import logger
8
+ from py_neuromodulation.utils.types import _PathLike
9
+ from py_neuromodulation.features import FeatureProcessors
10
+ from py_neuromodulation.utils import io
11
+ from py_neuromodulation.stream.settings import NMSettings
12
+
13
+ if TYPE_CHECKING:
14
+ from py_neuromodulation.processing.projection import Projection
15
+ import pandas as pd
13
16
 
14
17
 
15
18
  class DataProcessor:
@@ -17,21 +20,23 @@ class DataProcessor:
17
20
  self,
18
21
  sfreq: float,
19
22
  settings: NMSettings | _PathLike,
20
- nm_channels: pd.DataFrame | _PathLike,
23
+ channels: "pd.DataFrame | _PathLike",
21
24
  coord_names: list | None = None,
22
25
  coord_list: list | None = None,
23
26
  line_noise: float | None = None,
24
27
  path_grids: _PathLike | None = None,
25
28
  verbose: bool = True,
26
29
  ) -> None:
30
+ from py_neuromodulation.processing import DataPreprocessor
31
+
27
32
  """Initialize run class.
28
33
 
29
34
  Parameters
30
35
  ----------
31
- settings : nm_settings.NMSettings object
32
- nm_channels : pd.DataFrame | _PathLike
36
+ settings : settings.NMSettings object
37
+ channels : pd.DataFrame | _PathLike
33
38
  Initialized pd.DataFrame with channel specific information.
34
- The path to a nm_channels.csv can be also passed.
39
+ The path to a channels.csv can be also passed.
35
40
  coord_names : list | None
36
41
  list of coordinate names
37
42
  coord_list : list | None
@@ -41,8 +46,9 @@ class DataProcessor:
41
46
  verbose : boolean
42
47
  if True, log signal processed and computation time
43
48
  """
49
+
44
50
  self.settings = NMSettings.load(settings)
45
- self.nm_channels = self._load_nm_channels(nm_channels)
51
+ self.channels = io.load_channels(channels)
46
52
 
47
53
  self.sfreq_features: float = self.settings.sampling_rate_features_hz
48
54
  self._sfreq_raw_orig: float = sfreq
@@ -55,15 +61,15 @@ class DataProcessor:
55
61
 
56
62
  (self.ch_names_used, _, self.feature_idx, _) = self._get_ch_info()
57
63
 
58
- self.preprocessors = NMPreprocessors(
64
+ self.preprocessors = DataPreprocessor(
59
65
  settings=self.settings,
60
- nm_channels=self.nm_channels,
66
+ channels=self.channels,
61
67
  sfreq=self.sfreq_raw,
62
68
  line_noise=self.line_noise,
63
69
  )
64
70
 
65
71
  if self.settings.postprocessing.feature_normalization:
66
- from py_neuromodulation.nm_normalization import FeatureNormalizer
72
+ from py_neuromodulation.processing.normalization import FeatureNormalizer
67
73
 
68
74
  self.feature_normalizer = FeatureNormalizer(self.settings)
69
75
 
@@ -78,7 +84,7 @@ class DataProcessor:
78
84
  coord_names=coord_names, coord_list=coord_list
79
85
  )
80
86
 
81
- self.projection = self._get_projection(self.settings, self.nm_channels)
87
+ self.projection = self._get_projection(self.settings, self.channels)
82
88
 
83
89
  self.cnt_samples = 0
84
90
 
@@ -134,16 +140,16 @@ class DataProcessor:
134
140
  def _get_ch_info(
135
141
  self,
136
142
  ) -> tuple[list[str], list[str], list[int], np.ndarray]:
137
- """Get used feature and label info from nm_channels"""
138
- nm_channels = self.nm_channels
139
- ch_names_used = nm_channels[nm_channels["used"] == 1]["new_name"].tolist()
140
- ch_types_used = nm_channels[nm_channels["used"] == 1]["type"].tolist()
143
+ """Get used feature and label info from channels"""
144
+ channels = self.channels
145
+ ch_names_used = channels[channels["used"] == 1]["new_name"].tolist()
146
+ ch_types_used = channels[channels["used"] == 1]["type"].tolist()
141
147
 
142
148
  # used channels for feature estimation
143
- feature_idx = np.where(nm_channels["used"] & ~nm_channels["target"])[0].tolist()
149
+ feature_idx = np.where(channels["used"] & ~channels["target"])[0].tolist()
144
150
 
145
151
  # If multiple targets exist, select only the first
146
- label_idx = np.where(nm_channels["target"] == 1)[0]
152
+ label_idx = np.where(channels["target"] == 1)[0]
147
153
 
148
154
  return ch_names_used, ch_types_used, feature_idx, label_idx
149
155
 
@@ -151,12 +157,12 @@ class DataProcessor:
151
157
  def _get_grids(
152
158
  settings: "NMSettings",
153
159
  path_grids: _PathLike | None,
154
- ) -> tuple[pd.DataFrame | None, pd.DataFrame | None]:
160
+ ) -> "tuple[pd.DataFrame | None, pd.DataFrame | None]":
155
161
  """Read settings specified grids
156
162
 
157
163
  Parameters
158
164
  ----------
159
- settings : nm_settings.NMSettings object
165
+ settings : settings.NMSettings object
160
166
  path_grids : _PathLike | str
161
167
 
162
168
  Returns
@@ -166,18 +172,20 @@ class DataProcessor:
166
172
  might be None if not specified in settings
167
173
  """
168
174
  if settings.postprocessing.project_cortex:
169
- grid_cortex = nm_IO.read_grid(path_grids, "cortex")
175
+ grid_cortex = io.read_grid(path_grids, "cortex")
170
176
  else:
171
177
  grid_cortex = None
172
178
  if settings.postprocessing.project_subcortex:
173
- grid_subcortex = nm_IO.read_grid(path_grids, "subcortex")
179
+ grid_subcortex = io.read_grid(path_grids, "subcortex")
174
180
  else:
175
181
  grid_subcortex = None
176
182
  return grid_cortex, grid_subcortex
177
183
 
178
184
  def _get_projection(
179
- self, settings: "NMSettings", nm_channels: pd.DataFrame
180
- ) -> Projection | None:
185
+ self, settings: "NMSettings", channels: "pd.DataFrame"
186
+ ) -> "Projection | None":
187
+ from py_neuromodulation.processing.projection import Projection
188
+
181
189
  """Return projection of used coordinated and grids"""
182
190
 
183
191
  if not any(
@@ -194,19 +202,11 @@ class DataProcessor:
194
202
  grid_cortex=grid_cortex,
195
203
  grid_subcortex=grid_subcortex,
196
204
  coords=self.coords,
197
- nm_channels=nm_channels,
205
+ channels=channels,
198
206
  plot_projection=False,
199
207
  )
200
208
  return projection
201
209
 
202
- @staticmethod
203
- def _load_nm_channels(
204
- nm_channels: pd.DataFrame | _PathLike,
205
- ) -> pd.DataFrame:
206
- if not isinstance(nm_channels, pd.DataFrame):
207
- return nm_IO.load_nm_channels(nm_channels)
208
- return nm_channels
209
-
210
210
  def _set_coords(
211
211
  self, coord_names: list[str] | None, coord_list: list | None
212
212
  ) -> dict:
@@ -308,18 +308,18 @@ class DataProcessor:
308
308
  if additional_args is not None:
309
309
  sidecar = sidecar | additional_args
310
310
 
311
- nm_IO.save_sidecar(sidecar, out_dir, prefix)
311
+ io.save_sidecar(sidecar, out_dir, prefix)
312
312
 
313
313
  def save_settings(self, out_dir: _PathLike, prefix: str = "") -> None:
314
314
  self.settings.save(out_dir, prefix)
315
315
 
316
- def save_nm_channels(self, out_dir: _PathLike, prefix: str = "") -> None:
317
- nm_IO.save_nm_channels(self.nm_channels, out_dir, prefix)
316
+ def save_channels(self, out_dir: _PathLike, prefix: str) -> None:
317
+ io.save_channels(self.channels, out_dir, prefix)
318
318
 
319
319
  def save_features(
320
320
  self,
321
- feature_arr: pd.DataFrame,
321
+ feature_arr: "pd.DataFrame",
322
322
  out_dir: _PathLike = "",
323
323
  prefix: str = "",
324
324
  ) -> None:
325
- nm_IO.save_features(feature_arr, out_dir, prefix)
325
+ io.save_features(feature_arr, out_dir, prefix)
@@ -0,0 +1,53 @@
1
+ import numpy as np
2
+
3
+
4
+ class RawDataGenerator:
5
+ """
6
+ This generator function mimics online data acquisition.
7
+ The data are iteratively sampled with settings.sampling_rate_features_hz
8
+ """
9
+
10
+ def __init__(
11
+ self,
12
+ data: np.ndarray,
13
+ sfreq: float,
14
+ sampling_rate_features_hz: float,
15
+ segment_length_features_ms: float,
16
+ ) -> None:
17
+ """
18
+ Arguments
19
+ ---------
20
+ data (np array): shape (channels, time)
21
+ settings (settings.NMSettings): settings object
22
+ sfreq (float): sampling frequency of the data
23
+
24
+ Returns
25
+ -------
26
+ np.array: 1D array of time stamps
27
+ np.array: new batch for run function of full segment length shape
28
+ """
29
+ self.batch_counter: int = 0 # counter for the batches
30
+
31
+ self.data = data
32
+ self.sfreq = sfreq
33
+ # Width, in data points, of the moving window used to calculate features
34
+ self.segment_length = segment_length_features_ms / 1000 * sfreq
35
+ # Ratio of the sampling frequency of the input data to the sampling frequency
36
+ self.stride = sfreq / sampling_rate_features_hz
37
+
38
+ def __iter__(self):
39
+ return self
40
+
41
+ def __next__(self):
42
+ start = self.stride * self.batch_counter
43
+ end = start + self.segment_length
44
+
45
+ self.batch_counter += 1
46
+
47
+ start_idx = int(start)
48
+ end_idx = int(end)
49
+
50
+ if end_idx > self.data.shape[1]:
51
+ raise StopIteration
52
+
53
+ return np.arange(start, end) / self.sfreq, self.data[:, start_idx:end_idx]
@@ -2,14 +2,16 @@ import numpy as np
2
2
  import mne
3
3
  from pathlib import Path
4
4
 
5
- from py_neuromodulation import logger, nm_types, nm_IO
5
+ from py_neuromodulation.utils.types import _PathLike
6
+ from py_neuromodulation.utils import io
7
+ from py_neuromodulation import logger
6
8
 
7
- class LSLOfflinePlayer:
8
9
 
10
+ class LSLOfflinePlayer:
9
11
  def __init__(
10
12
  self,
11
13
  stream_name: str | None = "lsl_offline_player",
12
- f_name: str | nm_types.PathLike = None,
14
+ f_name: str | _PathLike = None,
13
15
  raw: mne.io.Raw | None = None,
14
16
  sfreq: int | float | None = None,
15
17
  data: np.ndarray | None = None,
@@ -49,10 +51,12 @@ class LSLOfflinePlayer:
49
51
  logger.critical(error_msg)
50
52
  raise ValueError(error_msg)
51
53
 
52
- if got_fname:
53
- (self._path_raw, data, sfreq, line_noise, coord_list, coord_names) = nm_IO.read_BIDS_data(f_name)
54
+ if got_fname:
55
+ (self._path_raw, data, sfreq, line_noise, coord_list, coord_names) = (
56
+ io.read_BIDS_data(f_name)
57
+ )
54
58
 
55
- elif got_raw:
59
+ elif got_raw:
56
60
  self._path_raw = raw
57
61
 
58
62
  elif got_sfreq_data:
@@ -8,7 +8,7 @@ import os
8
8
 
9
9
  if TYPE_CHECKING:
10
10
  from py_neuromodulation import NMSettings
11
-
11
+
12
12
 
13
13
  class LSLStream:
14
14
  """
@@ -21,7 +21,7 @@ class LSLStream:
21
21
 
22
22
  Parameters:
23
23
  -----------
24
- settings : nm_settings.NMSettings object
24
+ settings : settings.NMSettings object
25
25
  stream_name : str, optional
26
26
  Name of the stream to connect to. If not provided, the first available stream is used.
27
27
 
@@ -32,8 +32,10 @@ class LSLStream:
32
32
  under the same name.
33
33
  """
34
34
  from mne_lsl.stream import StreamLSL
35
+
35
36
  self.stream: StreamLSL
36
-
37
+ self.keyboard_interrupt = False
38
+
37
39
  self.settings = settings
38
40
  self._n_seconds_wait_before_disconnect = 3
39
41
  try:
@@ -50,18 +52,16 @@ class LSLStream:
50
52
 
51
53
  if self.stream.sinfo is None:
52
54
  raise RuntimeError("Stream info is None. Check if the stream is running.")
53
-
55
+
54
56
  self.winsize = settings.segment_length_features_ms / self.stream.sinfo.sfreq
55
57
  self.sampling_interval = 1 / self.settings.sampling_rate_features_hz
56
58
 
57
59
  # If not running the generator when the escape key is pressed.
58
60
  self.headless: bool = not os.environ.get("DISPLAY")
59
61
  if not self.headless:
60
- from pynput import keyboard
62
+ from py_neuromodulation.utils.keyboard import KeyboardListener
61
63
 
62
- self.listener = keyboard.Listener(
63
- on_press=lambda key: key != keyboard.Key.esc # type: ignore
64
- )
64
+ self.listener = KeyboardListener(("esc", self.set_keyboard_interrupt))
65
65
  self.listener.start()
66
66
 
67
67
  def get_next_batch(self) -> Iterator[tuple[np.ndarray, np.ndarray]]:
@@ -111,6 +111,10 @@ class LSLStream:
111
111
 
112
112
  logger.info(f"Stream time: {timestamp[-1] - stream_start_time}")
113
113
 
114
- if not self.headless and not self.listener.running:
114
+ if not self.headless and self.keyboard_interrupt:
115
115
  logger.info("Keyboard interrupt")
116
+ self.listener.stop()
116
117
  self.stream.disconnect()
118
+
119
+ def set_keyboard_interrupt(self):
120
+ self.keyboard_interrupt = True
@@ -5,27 +5,30 @@ from typing import ClassVar
5
5
  from pydantic import Field, model_validator
6
6
 
7
7
  from py_neuromodulation import PYNM_DIR, logger, user_features
8
- from py_neuromodulation.nm_types import (
8
+
9
+ from py_neuromodulation.utils.types import (
9
10
  BoolSelector,
10
11
  FrequencyRange,
11
12
  PreprocessorName,
12
13
  _PathLike,
14
+ NMBaseModel,
15
+ NormMethod,
13
16
  )
14
17
 
15
- from py_neuromodulation.nm_types import NMBaseModel
16
- from py_neuromodulation.nm_filter_preprocessing import FilterSettings
17
- from py_neuromodulation.nm_kalmanfilter import KalmanSettings
18
- from py_neuromodulation.nm_projection import ProjectionSettings
19
- from py_neuromodulation.nm_bispectra import BispectraSettings
20
- from py_neuromodulation.nm_nolds import NoldsSettings
21
- from py_neuromodulation.nm_mne_connectivity import MNEConnectivitySettings
22
- from py_neuromodulation.nm_fooof import FooofSettings
23
- from py_neuromodulation.nm_coherence import CoherenceSettings
24
- from py_neuromodulation.nm_sharpwaves import SharpwaveSettings
25
- from py_neuromodulation.nm_oscillatory import OscillatorySettings, BandpassSettings
26
- from py_neuromodulation.nm_bursts import BurstSettings
27
- from py_neuromodulation.nm_normalization import NormMethod, NormalizationSettings
28
- from py_neuromodulation.nm_resample import ResamplerSettings
18
+ from py_neuromodulation.processing.filter_preprocessing import FilterSettings
19
+ from py_neuromodulation.processing.normalization import NormalizationSettings
20
+ from py_neuromodulation.processing.resample import ResamplerSettings
21
+ from py_neuromodulation.processing.projection import ProjectionSettings
22
+
23
+ from py_neuromodulation.filter import KalmanSettings
24
+ from py_neuromodulation.features import BispectraSettings
25
+ from py_neuromodulation.features import NoldsSettings
26
+ from py_neuromodulation.features import MNEConnectivitySettings
27
+ from py_neuromodulation.features import FooofSettings
28
+ from py_neuromodulation.features import CoherenceSettings
29
+ from py_neuromodulation.features import SharpwaveSettings
30
+ from py_neuromodulation.features import OscillatorySettings, BandPowerSettings
31
+ from py_neuromodulation.features import BurstsSettings
29
32
 
30
33
 
31
34
  class FeatureSelection(BoolSelector):
@@ -90,15 +93,15 @@ class NMSettings(NMBaseModel):
90
93
  fft_settings: OscillatorySettings = OscillatorySettings()
91
94
  welch_settings: OscillatorySettings = OscillatorySettings()
92
95
  stft_settings: OscillatorySettings = OscillatorySettings()
93
- bandpass_filter_settings: BandpassSettings = BandpassSettings()
96
+ bandpass_filter_settings: BandPowerSettings = BandPowerSettings()
94
97
  kalman_filter_settings: KalmanSettings = KalmanSettings()
95
- burst_settings: BurstSettings = BurstSettings()
98
+ burst_settings: BurstsSettings = BurstsSettings()
96
99
  sharpwave_analysis_settings: SharpwaveSettings = SharpwaveSettings()
97
- mne_connectivity: MNEConnectivitySettings = MNEConnectivitySettings()
98
- coherence: CoherenceSettings = CoherenceSettings()
99
- fooof: FooofSettings = FooofSettings()
100
- nolds_features: NoldsSettings = NoldsSettings()
101
- bispectrum: BispectraSettings = BispectraSettings()
100
+ mne_connectivity_settings: MNEConnectivitySettings = MNEConnectivitySettings()
101
+ coherence_settings: CoherenceSettings = CoherenceSettings()
102
+ fooof_settings: FooofSettings = FooofSettings()
103
+ nolds_settings: NoldsSettings = NoldsSettings()
104
+ bispectrum_settings: BispectraSettings = BispectraSettings()
102
105
 
103
106
  def __init__(self, *args, **kwargs) -> None:
104
107
  super().__init__(*args, **kwargs)
@@ -247,7 +250,7 @@ class NMSettings(NMBaseModel):
247
250
 
248
251
  @staticmethod
249
252
  def get_default() -> "NMSettings":
250
- return NMSettings.from_file(PYNM_DIR / "nm_settings.yaml")
253
+ return NMSettings.from_file(PYNM_DIR / "default_settings.yaml")
251
254
 
252
255
  @staticmethod
253
256
  def list_normalization_methods() -> list[NormMethod]:
@@ -281,7 +284,7 @@ def reset_settings(settings: NMSettings) -> NMSettings:
281
284
  return settings.reset()
282
285
 
283
286
 
284
- def set_settings_fast_compute() -> NMSettings:
287
+ def get_fast_compute() -> NMSettings:
285
288
  return NMSettings.get_fast_compute()
286
289
 
287
290