py-neuromodulation 0.0.3__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.
Files changed (233) hide show
  1. py_neuromodulation/ConnectivityDecoding/Automated Anatomical Labeling 3 (Rolls 2020).nii +0 -0
  2. py_neuromodulation/ConnectivityDecoding/_get_grid_hull.m +34 -0
  3. py_neuromodulation/ConnectivityDecoding/_get_grid_whole_brain.py +95 -0
  4. py_neuromodulation/ConnectivityDecoding/_helper_write_connectome.py +107 -0
  5. py_neuromodulation/ConnectivityDecoding/mni_coords_cortical_surface.mat +0 -0
  6. py_neuromodulation/ConnectivityDecoding/mni_coords_whole_brain.mat +0 -0
  7. py_neuromodulation/ConnectivityDecoding/rmap_func_all.nii +0 -0
  8. py_neuromodulation/ConnectivityDecoding/rmap_struc.nii +0 -0
  9. py_neuromodulation/FieldTrip.py +589 -589
  10. py_neuromodulation/__init__.py +74 -13
  11. py_neuromodulation/_write_example_dataset_helper.py +83 -65
  12. py_neuromodulation/data/README +6 -0
  13. py_neuromodulation/data/dataset_description.json +8 -0
  14. py_neuromodulation/data/participants.json +32 -0
  15. py_neuromodulation/data/participants.tsv +2 -0
  16. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_coordsystem.json +5 -0
  17. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_electrodes.tsv +11 -0
  18. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_channels.tsv +11 -0
  19. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.eeg +0 -0
  20. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.json +18 -0
  21. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vhdr +35 -0
  22. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vmrk +13 -0
  23. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/sub-testsub_ses-EphysMedOff_scans.tsv +2 -0
  24. py_neuromodulation/grid_cortex.tsv +40 -0
  25. py_neuromodulation/grid_subcortex.tsv +1429 -0
  26. py_neuromodulation/liblsl/libpugixml.so.1.12 +0 -0
  27. py_neuromodulation/liblsl/linux/bionic_amd64/liblsl.1.16.2.so +0 -0
  28. py_neuromodulation/liblsl/linux/bookworm_amd64/liblsl.1.16.2.so +0 -0
  29. py_neuromodulation/liblsl/linux/focal_amd46/liblsl.1.16.2.so +0 -0
  30. py_neuromodulation/liblsl/linux/jammy_amd64/liblsl.1.16.2.so +0 -0
  31. py_neuromodulation/liblsl/linux/jammy_x86/liblsl.1.16.2.so +0 -0
  32. py_neuromodulation/liblsl/linux/noble_amd64/liblsl.1.16.2.so +0 -0
  33. py_neuromodulation/liblsl/macos/amd64/liblsl.1.16.2.dylib +0 -0
  34. py_neuromodulation/liblsl/macos/arm64/liblsl.1.16.0.dylib +0 -0
  35. py_neuromodulation/liblsl/windows/amd64/liblsl.1.16.2.dll +0 -0
  36. py_neuromodulation/liblsl/windows/x86/liblsl.1.16.2.dll +0 -0
  37. py_neuromodulation/nm_IO.py +413 -417
  38. py_neuromodulation/nm_RMAP.py +496 -531
  39. py_neuromodulation/nm_analysis.py +993 -1074
  40. py_neuromodulation/nm_artifacts.py +30 -25
  41. py_neuromodulation/nm_bispectra.py +154 -168
  42. py_neuromodulation/nm_bursts.py +292 -198
  43. py_neuromodulation/nm_coherence.py +251 -205
  44. py_neuromodulation/nm_database.py +149 -0
  45. py_neuromodulation/nm_decode.py +918 -992
  46. py_neuromodulation/nm_define_nmchannels.py +300 -302
  47. py_neuromodulation/nm_features.py +144 -116
  48. py_neuromodulation/nm_filter.py +219 -219
  49. py_neuromodulation/nm_filter_preprocessing.py +79 -91
  50. py_neuromodulation/nm_fooof.py +139 -159
  51. py_neuromodulation/nm_generator.py +45 -37
  52. py_neuromodulation/nm_hjorth_raw.py +52 -73
  53. py_neuromodulation/nm_kalmanfilter.py +71 -58
  54. py_neuromodulation/nm_linelength.py +21 -33
  55. py_neuromodulation/nm_logger.py +66 -0
  56. py_neuromodulation/nm_mne_connectivity.py +149 -112
  57. py_neuromodulation/nm_mnelsl_generator.py +90 -0
  58. py_neuromodulation/nm_mnelsl_stream.py +116 -0
  59. py_neuromodulation/nm_nolds.py +96 -93
  60. py_neuromodulation/nm_normalization.py +173 -214
  61. py_neuromodulation/nm_oscillatory.py +423 -448
  62. py_neuromodulation/nm_plots.py +585 -612
  63. py_neuromodulation/nm_preprocessing.py +83 -0
  64. py_neuromodulation/nm_projection.py +370 -394
  65. py_neuromodulation/nm_rereference.py +97 -95
  66. py_neuromodulation/nm_resample.py +59 -50
  67. py_neuromodulation/nm_run_analysis.py +325 -435
  68. py_neuromodulation/nm_settings.py +289 -68
  69. py_neuromodulation/nm_settings.yaml +244 -0
  70. py_neuromodulation/nm_sharpwaves.py +423 -401
  71. py_neuromodulation/nm_stats.py +464 -480
  72. py_neuromodulation/nm_stream.py +398 -0
  73. py_neuromodulation/nm_stream_abc.py +166 -218
  74. py_neuromodulation/nm_types.py +193 -0
  75. py_neuromodulation/plots/STN_surf.mat +0 -0
  76. py_neuromodulation/plots/Vertices.mat +0 -0
  77. py_neuromodulation/plots/faces.mat +0 -0
  78. py_neuromodulation/plots/grid.mat +0 -0
  79. {py_neuromodulation-0.0.3.dist-info → py_neuromodulation-0.0.5.dist-info}/METADATA +185 -182
  80. py_neuromodulation-0.0.5.dist-info/RECORD +83 -0
  81. {py_neuromodulation-0.0.3.dist-info → py_neuromodulation-0.0.5.dist-info}/WHEEL +1 -2
  82. {py_neuromodulation-0.0.3.dist-info → py_neuromodulation-0.0.5.dist-info/licenses}/LICENSE +21 -21
  83. docs/build/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +0 -68
  84. docs/build/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +0 -233
  85. docs/build/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +0 -219
  86. docs/build/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +0 -97
  87. docs/build/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +0 -64
  88. docs/build/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +0 -192
  89. docs/build/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +0 -210
  90. docs/build/html/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +0 -68
  91. docs/build/html/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +0 -239
  92. docs/build/html/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +0 -219
  93. docs/build/html/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +0 -97
  94. docs/build/html/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +0 -64
  95. docs/build/html/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +0 -192
  96. docs/build/html/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +0 -210
  97. docs/source/_build/html/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +0 -76
  98. docs/source/_build/html/_downloads/0d0d0a76e8f648d5d3cbc47da6351932/plot_real_time_demo.py +0 -97
  99. docs/source/_build/html/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +0 -240
  100. docs/source/_build/html/_downloads/5d73cadc59a8805c47e3b84063afc157/plot_example_BIDS.py +0 -233
  101. docs/source/_build/html/_downloads/7660317fa5a6bfbd12fcca9961457fc4/plot_example_rmap_computing.py +0 -63
  102. docs/source/_build/html/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +0 -219
  103. docs/source/_build/html/_downloads/839e5b319379f7fd9e867deb00fd797f/plot_example_gridPointProjection.py +0 -210
  104. docs/source/_build/html/_downloads/ae8be19afe5e559f011fc9b138968ba0/plot_first_demo.py +0 -192
  105. docs/source/_build/html/_downloads/b8b06cacc17969d3725a0b6f1d7741c5/plot_example_sharpwave_analysis.py +0 -219
  106. docs/source/_build/html/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +0 -121
  107. docs/source/_build/html/_downloads/c31a86c0b68cb4167d968091ace8080d/plot_example_add_feature.py +0 -68
  108. docs/source/_build/html/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +0 -64
  109. docs/source/_build/html/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +0 -189
  110. docs/source/_build/html/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +0 -210
  111. docs/source/auto_examples/plot_0_first_demo.py +0 -189
  112. docs/source/auto_examples/plot_1_example_BIDS.py +0 -240
  113. docs/source/auto_examples/plot_2_example_add_feature.py +0 -76
  114. docs/source/auto_examples/plot_3_example_sharpwave_analysis.py +0 -219
  115. docs/source/auto_examples/plot_4_example_gridPointProjection.py +0 -210
  116. docs/source/auto_examples/plot_5_example_rmap_computing.py +0 -64
  117. docs/source/auto_examples/plot_6_real_time_demo.py +0 -121
  118. docs/source/conf.py +0 -105
  119. examples/plot_0_first_demo.py +0 -189
  120. examples/plot_1_example_BIDS.py +0 -240
  121. examples/plot_2_example_add_feature.py +0 -76
  122. examples/plot_3_example_sharpwave_analysis.py +0 -219
  123. examples/plot_4_example_gridPointProjection.py +0 -210
  124. examples/plot_5_example_rmap_computing.py +0 -64
  125. examples/plot_6_real_time_demo.py +0 -121
  126. packages/realtime_decoding/build/lib/realtime_decoding/__init__.py +0 -4
  127. packages/realtime_decoding/build/lib/realtime_decoding/decoder.py +0 -104
  128. packages/realtime_decoding/build/lib/realtime_decoding/features.py +0 -163
  129. packages/realtime_decoding/build/lib/realtime_decoding/helpers.py +0 -15
  130. packages/realtime_decoding/build/lib/realtime_decoding/run_decoding.py +0 -345
  131. packages/realtime_decoding/build/lib/realtime_decoding/trainer.py +0 -54
  132. packages/tmsi/build/lib/TMSiFileFormats/__init__.py +0 -37
  133. packages/tmsi/build/lib/TMSiFileFormats/file_formats/__init__.py +0 -36
  134. packages/tmsi/build/lib/TMSiFileFormats/file_formats/lsl_stream_writer.py +0 -200
  135. packages/tmsi/build/lib/TMSiFileFormats/file_formats/poly5_file_writer.py +0 -496
  136. packages/tmsi/build/lib/TMSiFileFormats/file_formats/poly5_to_edf_converter.py +0 -236
  137. packages/tmsi/build/lib/TMSiFileFormats/file_formats/xdf_file_writer.py +0 -977
  138. packages/tmsi/build/lib/TMSiFileFormats/file_readers/__init__.py +0 -35
  139. packages/tmsi/build/lib/TMSiFileFormats/file_readers/edf_reader.py +0 -116
  140. packages/tmsi/build/lib/TMSiFileFormats/file_readers/poly5reader.py +0 -294
  141. packages/tmsi/build/lib/TMSiFileFormats/file_readers/xdf_reader.py +0 -229
  142. packages/tmsi/build/lib/TMSiFileFormats/file_writer.py +0 -102
  143. packages/tmsi/build/lib/TMSiPlotters/__init__.py +0 -2
  144. packages/tmsi/build/lib/TMSiPlotters/gui/__init__.py +0 -39
  145. packages/tmsi/build/lib/TMSiPlotters/gui/_plotter_gui.py +0 -234
  146. packages/tmsi/build/lib/TMSiPlotters/gui/plotting_gui.py +0 -440
  147. packages/tmsi/build/lib/TMSiPlotters/plotters/__init__.py +0 -44
  148. packages/tmsi/build/lib/TMSiPlotters/plotters/hd_emg_plotter.py +0 -446
  149. packages/tmsi/build/lib/TMSiPlotters/plotters/impedance_plotter.py +0 -589
  150. packages/tmsi/build/lib/TMSiPlotters/plotters/signal_plotter.py +0 -1326
  151. packages/tmsi/build/lib/TMSiSDK/__init__.py +0 -54
  152. packages/tmsi/build/lib/TMSiSDK/device.py +0 -588
  153. packages/tmsi/build/lib/TMSiSDK/devices/__init__.py +0 -34
  154. packages/tmsi/build/lib/TMSiSDK/devices/saga/TMSi_Device_API.py +0 -1764
  155. packages/tmsi/build/lib/TMSiSDK/devices/saga/__init__.py +0 -34
  156. packages/tmsi/build/lib/TMSiSDK/devices/saga/saga_device.py +0 -1366
  157. packages/tmsi/build/lib/TMSiSDK/devices/saga/saga_types.py +0 -520
  158. packages/tmsi/build/lib/TMSiSDK/devices/saga/xml_saga_config.py +0 -165
  159. packages/tmsi/build/lib/TMSiSDK/error.py +0 -95
  160. packages/tmsi/build/lib/TMSiSDK/sample_data.py +0 -63
  161. packages/tmsi/build/lib/TMSiSDK/sample_data_server.py +0 -99
  162. packages/tmsi/build/lib/TMSiSDK/settings.py +0 -45
  163. packages/tmsi/build/lib/TMSiSDK/tmsi_device.py +0 -111
  164. packages/tmsi/build/lib/__init__.py +0 -4
  165. packages/tmsi/build/lib/apex_sdk/__init__.py +0 -34
  166. packages/tmsi/build/lib/apex_sdk/device/__init__.py +0 -41
  167. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API.py +0 -1009
  168. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API_enums.py +0 -239
  169. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API_structures.py +0 -668
  170. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_device.py +0 -1611
  171. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_dongle.py +0 -38
  172. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_event_reader.py +0 -57
  173. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_channel.py +0 -44
  174. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_config.py +0 -150
  175. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_const.py +0 -36
  176. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_impedance_channel.py +0 -48
  177. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_info.py +0 -108
  178. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/dongle_info.py +0 -39
  179. packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/download_measurement.py +0 -77
  180. packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/eeg_measurement.py +0 -150
  181. packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/impedance_measurement.py +0 -129
  182. packages/tmsi/build/lib/apex_sdk/device/threads/conversion_thread.py +0 -59
  183. packages/tmsi/build/lib/apex_sdk/device/threads/sampling_thread.py +0 -57
  184. packages/tmsi/build/lib/apex_sdk/device/tmsi_channel.py +0 -83
  185. packages/tmsi/build/lib/apex_sdk/device/tmsi_device.py +0 -201
  186. packages/tmsi/build/lib/apex_sdk/device/tmsi_device_enums.py +0 -103
  187. packages/tmsi/build/lib/apex_sdk/device/tmsi_dongle.py +0 -43
  188. packages/tmsi/build/lib/apex_sdk/device/tmsi_event_reader.py +0 -50
  189. packages/tmsi/build/lib/apex_sdk/device/tmsi_measurement.py +0 -118
  190. packages/tmsi/build/lib/apex_sdk/sample_data_server/__init__.py +0 -33
  191. packages/tmsi/build/lib/apex_sdk/sample_data_server/event_data.py +0 -44
  192. packages/tmsi/build/lib/apex_sdk/sample_data_server/sample_data.py +0 -50
  193. packages/tmsi/build/lib/apex_sdk/sample_data_server/sample_data_server.py +0 -136
  194. packages/tmsi/build/lib/apex_sdk/tmsi_errors/error.py +0 -126
  195. packages/tmsi/build/lib/apex_sdk/tmsi_sdk.py +0 -113
  196. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/apex/apex_structure_generator.py +0 -134
  197. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/decorators.py +0 -60
  198. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/logger_filter.py +0 -42
  199. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/singleton.py +0 -42
  200. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/support_functions.py +0 -72
  201. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/tmsi_logger.py +0 -98
  202. py_neuromodulation/nm_EpochStream.py +0 -92
  203. py_neuromodulation/nm_across_patient_decoding.py +0 -927
  204. py_neuromodulation/nm_cohortwrapper.py +0 -435
  205. py_neuromodulation/nm_eval_timing.py +0 -239
  206. py_neuromodulation/nm_features_abc.py +0 -39
  207. py_neuromodulation/nm_stream_offline.py +0 -358
  208. py_neuromodulation/utils/_logging.py +0 -24
  209. py_neuromodulation-0.0.3.dist-info/RECORD +0 -188
  210. py_neuromodulation-0.0.3.dist-info/top_level.txt +0 -5
  211. tests/__init__.py +0 -0
  212. tests/conftest.py +0 -117
  213. tests/test_all_examples.py +0 -10
  214. tests/test_all_features.py +0 -63
  215. tests/test_bispectra.py +0 -70
  216. tests/test_bursts.py +0 -105
  217. tests/test_feature_sampling_rates.py +0 -143
  218. tests/test_fooof.py +0 -16
  219. tests/test_initalization_offline_stream.py +0 -41
  220. tests/test_multiprocessing.py +0 -58
  221. tests/test_nan_values.py +0 -29
  222. tests/test_nm_filter.py +0 -95
  223. tests/test_nm_resample.py +0 -63
  224. tests/test_normalization_settings.py +0 -146
  225. tests/test_notch_filter.py +0 -31
  226. tests/test_osc_features.py +0 -424
  227. tests/test_preprocessing_filter.py +0 -151
  228. tests/test_rereference.py +0 -171
  229. tests/test_sampling.py +0 -57
  230. tests/test_settings_change_after_init.py +0 -76
  231. tests/test_sharpwave.py +0 -165
  232. tests/test_target_channel_add.py +0 -100
  233. tests/test_timing.py +0 -80
@@ -1,218 +1,166 @@
1
- """Module that contains PNStream ABC."""
2
-
3
- from abc import ABC, abstractmethod
4
- import os
5
- import pathlib
6
- import _pickle as cPickle
7
-
8
- from .utils import _logging # logger initialization
9
-
10
- # Logger use in different modules: logger = logging.getLogger("PynmLogger")
11
-
12
-
13
- import pandas as pd
14
- from sklearn import base
15
-
16
- from py_neuromodulation import (
17
- nm_features,
18
- nm_IO,
19
- nm_plots,
20
- nm_run_analysis,
21
- nm_settings,
22
- )
23
-
24
- _PathLike = str | os.PathLike
25
-
26
-
27
- class PNStream(ABC):
28
-
29
- settings: dict
30
- nm_channels: pd.DataFrame
31
- run_analysis: nm_run_analysis.DataProcessor
32
- features: nm_features.Features
33
- coords: dict
34
- sfreq: int | float
35
- sfreq_feature: int | float = None
36
- path_grids: _PathLike | None
37
- model: base.BaseEstimator | None
38
- sess_right: bool | None
39
- verbose: bool
40
- PATH_OUT: _PathLike | None
41
- PATH_OUT_folder_name: _PathLike | None
42
-
43
- def __init__(
44
- self,
45
- sfreq: int | float,
46
- nm_channels: pd.DataFrame | _PathLike,
47
- settings: dict | _PathLike | None = None,
48
- line_noise: int | float | None = 50,
49
- sampling_rate_features_hz: int | float | None = None,
50
- path_grids: _PathLike | None = None,
51
- coord_names: list | None = None,
52
- coord_list: list | None = None,
53
- verbose: bool = True,
54
- ) -> None:
55
- """Stream initialization
56
-
57
- Parameters
58
- ----------
59
- sfreq : int | float
60
- sampling frequency of data in Hertz
61
- nm_channels : pd.DataFrame | _PathLike
62
- parametrization of channels (see nm_define_channels.py for initialization)
63
- settings : dict | _PathLike | None, optional
64
- features settings can be a dictionary or path to the nm_settings.json, by default the py_neuromodulation/nm_settings.json are read
65
- line_noise : int | float | None, optional
66
- line noise, by default 50
67
- sampling_rate_features_hz : int | float | None, optional
68
- feature sampling rate, by default None
69
- path_grids : _PathLike | None, optional
70
- path to grid_cortex.tsv and/or gird_subcortex.tsv, by default Non
71
- coord_names : list | None, optional
72
- coordinate name in the form [coord_1_name, coord_2_name, etc], by default None
73
- coord_list : list | None, optional
74
- coordinates in the form [[coord_1_x, coord_1_y, coord_1_z], [coord_2_x, coord_2_y, coord_2_z],], by default None
75
- verbose : bool, optional
76
- print out stream computation time information, by default True
77
- """
78
- self.settings = self._load_settings(settings)
79
-
80
- if sampling_rate_features_hz is not None:
81
- self.settings["sampling_rate_features_hz"] = (
82
- sampling_rate_features_hz
83
- )
84
-
85
- self.nm_channels = self._load_nm_channels(nm_channels)
86
- if path_grids is None:
87
- path_grids = pathlib.Path(__file__).parent.resolve()
88
- self.path_grids = path_grids
89
- self.verbose = verbose
90
- self.sfreq = sfreq
91
- self.line_noise = line_noise
92
- self.coord_names = coord_names
93
- self.coord_list = coord_list
94
- self.sess_right = None
95
- self.projection = None
96
- self.model = None
97
-
98
- self.run_analysis = nm_run_analysis.DataProcessor(
99
- sfreq=self.sfreq,
100
- settings=self.settings,
101
- nm_channels=self.nm_channels,
102
- path_grids=self.path_grids,
103
- coord_names=coord_names,
104
- coord_list=coord_list,
105
- line_noise=line_noise,
106
- verbose=self.verbose,
107
- )
108
-
109
- @abstractmethod
110
- def run(self):
111
- """Reinitialize the stream
112
- This might be handy in case the nm_channels or nm_settings changed
113
- """
114
-
115
- self.run_analysis = nm_run_analysis.DataProcessor(
116
- sfreq=self.sfreq,
117
- settings=self.settings,
118
- nm_channels=self.nm_channels,
119
- path_grids=self.path_grids,
120
- coord_names=self.coord_names,
121
- coord_list=self.coord_list,
122
- line_noise=self.line_noise,
123
- verbose=self.verbose,
124
- )
125
-
126
- @abstractmethod
127
- def _add_timestamp(
128
- self, feature_series: pd.Series, idx: int | None = None
129
- ) -> pd.Series:
130
- """Add to feature_series "time" keyword
131
- For Bids specify with fs_features, for real time analysis with current time stamp
132
- """
133
-
134
- @staticmethod
135
- def _get_sess_lat(coords: dict) -> bool:
136
- if len(coords["cortex_left"]["positions"]) == 0:
137
- return True
138
- if len(coords["cortex_right"]["positions"]) == 0:
139
- return False
140
- raise ValueError(
141
- "Either cortex_left or cortex_right positions must be provided."
142
- )
143
-
144
- @staticmethod
145
- def _load_nm_channels(
146
- nm_channels: pd.DataFrame | _PathLike,
147
- ) -> pd.DataFrame:
148
- if not isinstance(nm_channels, pd.DataFrame):
149
- nm_channels = nm_IO.load_nm_channels(nm_channels)
150
-
151
- if nm_channels.query("used == 1 and target == 0").shape[0] == 0:
152
- raise ValueError(
153
- "No channels selected for analysis that have column 'used' = 1 and 'target' = 0. Please check your nm_channels"
154
- )
155
-
156
- return nm_channels
157
-
158
- @staticmethod
159
- def _load_settings(settings: dict | _PathLike | None) -> dict:
160
- if isinstance(settings, dict):
161
- return settings
162
- if settings is None:
163
- return nm_settings.get_default_settings()
164
- return nm_IO.read_settings(str(settings))
165
-
166
- def load_model(self, model_name: _PathLike) -> None:
167
- """Load sklearn model, that utilizes predict"""
168
- with open(model_name, "rb") as fid:
169
- self.model = cPickle.load(fid)
170
-
171
- def save_after_stream(
172
- self,
173
- out_path_root: _PathLike | None = None,
174
- folder_name: str = "sub",
175
- feature_arr: pd.DataFrame | None = None,
176
- ) -> None:
177
- """Save features, settings, nm_channels and sidecar after run"""
178
-
179
- if out_path_root is None:
180
- out_path_root = os.getcwd()
181
- # create derivate folder_name output folder if doesn't exist
182
- if os.path.exists(os.path.join(out_path_root, folder_name)) is False:
183
- os.makedirs(os.path.join(out_path_root, folder_name))
184
-
185
- self.PATH_OUT = out_path_root
186
- self.PATH_OUT_folder_name = folder_name
187
- self.save_sidecar(out_path_root, folder_name)
188
-
189
- if feature_arr is not None:
190
- self.save_features(out_path_root, folder_name, feature_arr)
191
-
192
- self.save_settings(out_path_root, folder_name)
193
-
194
- self.save_nm_channels(out_path_root, folder_name)
195
-
196
- def save_features(
197
- self,
198
- out_path_root: _PathLike,
199
- folder_name: str,
200
- feature_arr: pd.DataFrame,
201
- ) -> None:
202
- nm_IO.save_features(feature_arr, out_path_root, folder_name)
203
-
204
- def save_nm_channels(
205
- self, out_path_root: _PathLike, folder_name: str
206
- ) -> None:
207
- self.run_analysis.save_nm_channels(out_path_root, folder_name)
208
-
209
- def save_settings(self, out_path_root: _PathLike, folder_name: str) -> None:
210
- self.run_analysis.save_settings(out_path_root, folder_name)
211
-
212
- def save_sidecar(self, out_path_root: _PathLike, folder_name: str) -> None:
213
- """Save sidecar incduing fs, coords, sess_right to
214
- out_path_root and subfolder 'folder_name'"""
215
- additional_args = {"sess_right": self.sess_right}
216
- self.run_analysis.save_sidecar(
217
- out_path_root, folder_name, additional_args
218
- )
1
+ """Module that contains NMStream ABC."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+ import pandas as pd
6
+
7
+ from py_neuromodulation.nm_run_analysis import DataProcessor
8
+ from py_neuromodulation.nm_settings import NMSettings
9
+ from py_neuromodulation.nm_types import _PathLike, FeatureName
10
+ from py_neuromodulation import nm_IO, PYNM_DIR
11
+
12
+
13
+ class NMStream(ABC):
14
+ def __init__(
15
+ self,
16
+ sfreq: float,
17
+ nm_channels: pd.DataFrame | _PathLike,
18
+ settings: "NMSettings | _PathLike | None" = None,
19
+ line_noise: float | None = 50,
20
+ sampling_rate_features_hz: float | None = None,
21
+ path_grids: _PathLike | None = None,
22
+ coord_names: list | None = None,
23
+ stream_name: str
24
+ | None = "example_stream", # Timon: do we need those in the nmstream_abc?
25
+ stream_lsl: bool = False,
26
+ coord_list: list | None = None,
27
+ verbose: bool = True,
28
+ ) -> None:
29
+ """Stream initialization
30
+
31
+ Parameters
32
+ ----------
33
+ sfreq : float
34
+ sampling frequency of data in Hertz
35
+ nm_channels : pd.DataFrame | _PathLike
36
+ parametrization of channels (see nm_define_channels.py for initialization)
37
+ settings : NMSettings | _PathLike | None, optional
38
+ Initialized nm_settings.NMSettings object, by default the py_neuromodulation/nm_settings.yaml are read
39
+ and passed into a settings object
40
+ line_noise : float | None, optional
41
+ line noise, by default 50
42
+ sampling_rate_features_hz : float | None, optional
43
+ feature sampling rate, by default None
44
+ path_grids : _PathLike | None, optional
45
+ path to grid_cortex.tsv and/or gird_subcortex.tsv, by default Non
46
+ coord_names : list | None, optional
47
+ coordinate name in the form [coord_1_name, coord_2_name, etc], by default None
48
+ coord_list : list | None, optional
49
+ coordinates in the form [[coord_1_x, coord_1_y, coord_1_z], [coord_2_x, coord_2_y, coord_2_z],], by default None
50
+ verbose : bool, optional
51
+ print out stream computation time information, by default True
52
+ """
53
+ self.settings: NMSettings = NMSettings.load(settings)
54
+
55
+ # If features that use frequency ranges are on, test them against nyquist frequency
56
+ use_freq_ranges: list[FeatureName] = [
57
+ "bandpass_filter",
58
+ "stft",
59
+ "fft",
60
+ "welch",
61
+ "bursts",
62
+ "coherence",
63
+ "nolds",
64
+ "bispectrum",
65
+ ]
66
+
67
+ need_nyquist_check = any(
68
+ (f in use_freq_ranges for f in self.settings.features.get_enabled())
69
+ )
70
+
71
+ if need_nyquist_check:
72
+ assert all(
73
+ fb.frequency_high_hz < sfreq / 2
74
+ for fb in self.settings.frequency_ranges_hz.values()
75
+ ), (
76
+ "If a feature that uses frequency ranges is selected, "
77
+ "the frequency band ranges need to be smaller than the nyquist frequency.\n"
78
+ f"Got sfreq = {sfreq} and fband ranges:\n {self.settings.frequency_ranges_hz}"
79
+ )
80
+
81
+ if sampling_rate_features_hz is not None:
82
+ self.settings.sampling_rate_features_hz = sampling_rate_features_hz
83
+
84
+ self.nm_channels = self._load_nm_channels(nm_channels)
85
+ if path_grids is None:
86
+ path_grids = PYNM_DIR
87
+ self.path_grids = path_grids
88
+ self.verbose = verbose
89
+ self.sfreq = sfreq
90
+ self.line_noise = line_noise
91
+ self.coord_names = coord_names
92
+ self.coord_list = coord_list
93
+ self.sess_right = None
94
+ self.projection = None
95
+ self.model = None
96
+
97
+ self.data_processor = DataProcessor(
98
+ sfreq=self.sfreq,
99
+ settings=self.settings,
100
+ nm_channels=self.nm_channels,
101
+ path_grids=self.path_grids,
102
+ coord_names=coord_names,
103
+ coord_list=coord_list,
104
+ line_noise=line_noise,
105
+ verbose=self.verbose,
106
+ )
107
+
108
+ @abstractmethod
109
+ def run(self) -> pd.DataFrame:
110
+ """Reinitialize the stream
111
+ This might be handy in case the nm_channels or nm_settings changed
112
+ """
113
+
114
+ self.data_processor = DataProcessor(
115
+ sfreq=self.sfreq,
116
+ settings=self.settings,
117
+ nm_channels=self.nm_channels,
118
+ path_grids=self.path_grids,
119
+ coord_names=self.coord_names,
120
+ coord_list=self.coord_list,
121
+ line_noise=self.line_noise,
122
+ verbose=self.verbose,
123
+ )
124
+
125
+ @staticmethod
126
+ def _load_nm_channels(
127
+ nm_channels: pd.DataFrame | _PathLike,
128
+ ) -> pd.DataFrame:
129
+ if not isinstance(nm_channels, pd.DataFrame):
130
+ nm_channels = nm_IO.load_nm_channels(nm_channels)
131
+
132
+ if nm_channels.query("used == 1 and target == 0").shape[0] == 0:
133
+ raise ValueError(
134
+ "No channels selected for analysis that have column 'used' = 1 and 'target' = 0. Please check your nm_channels"
135
+ )
136
+
137
+ return nm_channels
138
+
139
+ def save_after_stream(
140
+ self,
141
+ out_dir: _PathLike = "",
142
+ prefix: str = "",
143
+ feature_arr: pd.DataFrame | None = None,
144
+ ) -> None:
145
+ """Save features, settings, nm_channels and sidecar after run"""
146
+
147
+ self.save_sidecar(out_dir, prefix)
148
+
149
+ if feature_arr is not None:
150
+ nm_IO.save_features(feature_arr, out_dir, prefix)
151
+
152
+ self.save_settings(out_dir, prefix)
153
+
154
+ self.save_nm_channels(out_dir, prefix)
155
+
156
+ def save_nm_channels(self, out_dir: _PathLike, prefix: str = "") -> None:
157
+ self.data_processor.save_nm_channels(out_dir, prefix)
158
+
159
+ def save_settings(self, out_dir: _PathLike, prefix: str = "") -> None:
160
+ self.data_processor.save_settings(out_dir, prefix)
161
+
162
+ def save_sidecar(self, out_dir: _PathLike, prefix: str = "") -> None:
163
+ """Save sidecar incduing fs, coords, sess_right to
164
+ out_path_root and subfolder 'folder_name'"""
165
+ additional_args = {"sess_right": self.sess_right}
166
+ self.data_processor.save_sidecar(out_dir, prefix, additional_args)
@@ -0,0 +1,193 @@
1
+ from os import PathLike
2
+ from math import isnan
3
+ from typing import NamedTuple, Type, Any, Literal
4
+ from importlib import import_module
5
+ from pydantic import ConfigDict, Field, model_validator, BaseModel
6
+ from pprint import pformat
7
+ from collections.abc import Sequence
8
+
9
+ ###################################
10
+ ########## TYPE ALIASES ##########
11
+ ###################################
12
+
13
+ _PathLike = str | PathLike
14
+
15
+ FeatureName = Literal[
16
+ "raw_hjorth",
17
+ "return_raw",
18
+ "bandpass_filter",
19
+ "stft",
20
+ "fft",
21
+ "welch",
22
+ "sharpwave_analysis",
23
+ "fooof",
24
+ "nolds",
25
+ "coherence",
26
+ "bursts",
27
+ "linelength",
28
+ "mne_connectivity",
29
+ "bispectrum",
30
+ ]
31
+
32
+ PreprocessorName = Literal[
33
+ "preprocessing_filter",
34
+ "notch_filter",
35
+ "raw_resampling",
36
+ "re_referencing",
37
+ "raw_normalization",
38
+ ]
39
+
40
+ NormMethod = Literal[
41
+ "mean",
42
+ "median",
43
+ "zscore",
44
+ "zscore-median",
45
+ "quantile",
46
+ "power",
47
+ "robust",
48
+ "minmax",
49
+ ]
50
+
51
+
52
+ ###################################
53
+ ###### LAZY MODULE IMPORTS #######
54
+ ###################################
55
+ class ImportDetails(NamedTuple):
56
+ module_name: str
57
+ class_name: str
58
+
59
+
60
+ def get_class(module_details: ImportDetails) -> Type[Any]:
61
+ return getattr(
62
+ import_module("py_neuromodulation." + module_details.module_name),
63
+ module_details.class_name,
64
+ )
65
+
66
+
67
+ ###################################
68
+ ######## PYDANTIC CLASSES ########
69
+ ###################################
70
+
71
+
72
+ class NMBaseModel(BaseModel):
73
+ model_config = ConfigDict(validate_assignment=False, extra="allow")
74
+
75
+ def __init__(self, *args, **kwargs) -> None:
76
+ if kwargs:
77
+ super().__init__(**kwargs)
78
+ else:
79
+ field_names = list(self.model_fields.keys())
80
+ kwargs = {}
81
+ for i in range(len(args)):
82
+ kwargs[field_names[i]] = args[i]
83
+ super().__init__(**kwargs)
84
+
85
+ def __str__(self):
86
+ return pformat(self.model_dump())
87
+
88
+ def __repr__(self):
89
+ return pformat(self.model_dump())
90
+
91
+ def validate(self) -> Any: # type: ignore
92
+ return self.model_validate(self.model_dump())
93
+
94
+ def __getitem__(self, key):
95
+ return getattr(self, key)
96
+
97
+ def __setitem__(self, key, value) -> None:
98
+ setattr(self, key, value)
99
+
100
+
101
+ class FrequencyRange(NMBaseModel):
102
+ frequency_low_hz: float = Field(default=0, gt=0)
103
+ frequency_high_hz: float = Field(default=0, gt=0)
104
+
105
+ def __init__(self, *args, **kwargs) -> None:
106
+ super().__init__(*args, **kwargs)
107
+
108
+ def __getitem__(self, item: int):
109
+ match item:
110
+ case 0:
111
+ return self.frequency_low_hz
112
+ case 1:
113
+ return self.frequency_high_hz
114
+ case _:
115
+ raise IndexError(f"Index {item} out of range")
116
+
117
+ def as_tuple(self) -> tuple[float, float]:
118
+ return (self.frequency_low_hz, self.frequency_high_hz)
119
+
120
+ def __iter__(self): # type: ignore
121
+ return iter(self.as_tuple())
122
+
123
+ @model_validator(mode="after")
124
+ def validate_range(self):
125
+ if not (isnan(self.frequency_high_hz) or isnan(self.frequency_low_hz)):
126
+ assert (
127
+ self.frequency_high_hz > self.frequency_low_hz
128
+ ), "Frequency high must be greater than frequency low"
129
+ return self
130
+
131
+ @classmethod
132
+ def create_from(cls, input) -> "FrequencyRange":
133
+ match input:
134
+ case FrequencyRange():
135
+ return input
136
+ case dict() if "frequency_low_hz" in input and "frequency_high_hz" in input:
137
+ return FrequencyRange(
138
+ input["frequency_low_hz"], input["frequency_high_hz"]
139
+ )
140
+ case Sequence() if len(input) == 2:
141
+ return FrequencyRange(input[0], input[1])
142
+ case _:
143
+ raise ValueError("Invalid input for FrequencyRange creation.")
144
+
145
+ @model_validator(mode="before")
146
+ @classmethod
147
+ def check_input(cls, input):
148
+ match input:
149
+ case dict() if "frequency_low_hz" in input and "frequency_high_hz" in input:
150
+ return input
151
+ case Sequence() if len(input) == 2:
152
+ return {"frequency_low_hz": input[0], "frequency_high_hz": input[1]}
153
+ case _:
154
+ raise ValueError(
155
+ "Value for FrequencyRange must be a dictionary, "
156
+ "or a sequence of 2 numeric values, "
157
+ f"but got {input} instead."
158
+ )
159
+
160
+
161
+ class BoolSelector(NMBaseModel):
162
+ def get_enabled(self):
163
+ return [
164
+ f
165
+ for f in self.model_fields.keys()
166
+ if (isinstance(self[f], bool) and self[f])
167
+ ]
168
+
169
+ def enable_all(self):
170
+ for f in self.model_fields.keys():
171
+ if isinstance(self[f], bool):
172
+ self[f] = True
173
+
174
+ def disable_all(self):
175
+ for f in self.model_fields.keys():
176
+ if isinstance(self[f], bool):
177
+ self[f] = False
178
+
179
+ def __iter__(self): # type: ignore
180
+ return iter(self.model_dump().keys())
181
+
182
+ @classmethod
183
+ def list_all(cls):
184
+ return list(cls.model_fields.keys())
185
+
186
+ @classmethod
187
+ def print_all(cls):
188
+ for f in cls.list_all():
189
+ print(f)
190
+
191
+ @classmethod
192
+ def get_fields(cls):
193
+ return cls.model_fields
Binary file
Binary file
Binary file
Binary file