py-neuromodulation 0.0.2__py3-none-any.whl → 0.0.3__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 (204) hide show
  1. docs/build/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +68 -0
  2. docs/build/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +233 -0
  3. docs/build/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +219 -0
  4. docs/build/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +97 -0
  5. docs/build/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +64 -0
  6. docs/build/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +192 -0
  7. docs/build/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +210 -0
  8. docs/build/html/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +68 -0
  9. docs/build/html/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +239 -0
  10. docs/build/html/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +219 -0
  11. docs/build/html/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +97 -0
  12. docs/build/html/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +64 -0
  13. docs/build/html/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +192 -0
  14. docs/build/html/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +210 -0
  15. docs/source/_build/html/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +76 -0
  16. docs/source/_build/html/_downloads/0d0d0a76e8f648d5d3cbc47da6351932/plot_real_time_demo.py +97 -0
  17. docs/source/_build/html/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +240 -0
  18. docs/source/_build/html/_downloads/5d73cadc59a8805c47e3b84063afc157/plot_example_BIDS.py +233 -0
  19. docs/source/_build/html/_downloads/7660317fa5a6bfbd12fcca9961457fc4/plot_example_rmap_computing.py +63 -0
  20. docs/source/_build/html/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +219 -0
  21. docs/source/_build/html/_downloads/839e5b319379f7fd9e867deb00fd797f/plot_example_gridPointProjection.py +210 -0
  22. docs/source/_build/html/_downloads/ae8be19afe5e559f011fc9b138968ba0/plot_first_demo.py +192 -0
  23. docs/source/_build/html/_downloads/b8b06cacc17969d3725a0b6f1d7741c5/plot_example_sharpwave_analysis.py +219 -0
  24. docs/source/_build/html/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +121 -0
  25. docs/source/_build/html/_downloads/c31a86c0b68cb4167d968091ace8080d/plot_example_add_feature.py +68 -0
  26. docs/source/_build/html/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +64 -0
  27. docs/source/_build/html/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +189 -0
  28. docs/source/_build/html/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +210 -0
  29. docs/source/auto_examples/plot_0_first_demo.py +189 -0
  30. docs/source/auto_examples/plot_1_example_BIDS.py +240 -0
  31. docs/source/auto_examples/plot_2_example_add_feature.py +76 -0
  32. docs/source/auto_examples/plot_3_example_sharpwave_analysis.py +219 -0
  33. docs/source/auto_examples/plot_4_example_gridPointProjection.py +210 -0
  34. docs/source/auto_examples/plot_5_example_rmap_computing.py +64 -0
  35. docs/source/auto_examples/plot_6_real_time_demo.py +121 -0
  36. docs/source/conf.py +105 -0
  37. examples/plot_0_first_demo.py +189 -0
  38. examples/plot_1_example_BIDS.py +240 -0
  39. examples/plot_2_example_add_feature.py +76 -0
  40. examples/plot_3_example_sharpwave_analysis.py +219 -0
  41. examples/plot_4_example_gridPointProjection.py +210 -0
  42. examples/plot_5_example_rmap_computing.py +64 -0
  43. examples/plot_6_real_time_demo.py +121 -0
  44. packages/realtime_decoding/build/lib/realtime_decoding/__init__.py +4 -0
  45. packages/realtime_decoding/build/lib/realtime_decoding/decoder.py +104 -0
  46. packages/realtime_decoding/build/lib/realtime_decoding/features.py +163 -0
  47. packages/realtime_decoding/build/lib/realtime_decoding/helpers.py +15 -0
  48. packages/realtime_decoding/build/lib/realtime_decoding/run_decoding.py +345 -0
  49. packages/realtime_decoding/build/lib/realtime_decoding/trainer.py +54 -0
  50. packages/tmsi/build/lib/TMSiFileFormats/__init__.py +37 -0
  51. packages/tmsi/build/lib/TMSiFileFormats/file_formats/__init__.py +36 -0
  52. packages/tmsi/build/lib/TMSiFileFormats/file_formats/lsl_stream_writer.py +200 -0
  53. packages/tmsi/build/lib/TMSiFileFormats/file_formats/poly5_file_writer.py +496 -0
  54. packages/tmsi/build/lib/TMSiFileFormats/file_formats/poly5_to_edf_converter.py +236 -0
  55. packages/tmsi/build/lib/TMSiFileFormats/file_formats/xdf_file_writer.py +977 -0
  56. packages/tmsi/build/lib/TMSiFileFormats/file_readers/__init__.py +35 -0
  57. packages/tmsi/build/lib/TMSiFileFormats/file_readers/edf_reader.py +116 -0
  58. packages/tmsi/build/lib/TMSiFileFormats/file_readers/poly5reader.py +294 -0
  59. packages/tmsi/build/lib/TMSiFileFormats/file_readers/xdf_reader.py +229 -0
  60. packages/tmsi/build/lib/TMSiFileFormats/file_writer.py +102 -0
  61. packages/tmsi/build/lib/TMSiPlotters/__init__.py +2 -0
  62. packages/tmsi/build/lib/TMSiPlotters/gui/__init__.py +39 -0
  63. packages/tmsi/build/lib/TMSiPlotters/gui/_plotter_gui.py +234 -0
  64. packages/tmsi/build/lib/TMSiPlotters/gui/plotting_gui.py +440 -0
  65. packages/tmsi/build/lib/TMSiPlotters/plotters/__init__.py +44 -0
  66. packages/tmsi/build/lib/TMSiPlotters/plotters/hd_emg_plotter.py +446 -0
  67. packages/tmsi/build/lib/TMSiPlotters/plotters/impedance_plotter.py +589 -0
  68. packages/tmsi/build/lib/TMSiPlotters/plotters/signal_plotter.py +1326 -0
  69. packages/tmsi/build/lib/TMSiSDK/__init__.py +54 -0
  70. packages/tmsi/build/lib/TMSiSDK/device.py +588 -0
  71. packages/tmsi/build/lib/TMSiSDK/devices/__init__.py +34 -0
  72. packages/tmsi/build/lib/TMSiSDK/devices/saga/TMSi_Device_API.py +1764 -0
  73. packages/tmsi/build/lib/TMSiSDK/devices/saga/__init__.py +34 -0
  74. packages/tmsi/build/lib/TMSiSDK/devices/saga/saga_device.py +1366 -0
  75. packages/tmsi/build/lib/TMSiSDK/devices/saga/saga_types.py +520 -0
  76. packages/tmsi/build/lib/TMSiSDK/devices/saga/xml_saga_config.py +165 -0
  77. packages/tmsi/build/lib/TMSiSDK/error.py +95 -0
  78. packages/tmsi/build/lib/TMSiSDK/sample_data.py +63 -0
  79. packages/tmsi/build/lib/TMSiSDK/sample_data_server.py +99 -0
  80. packages/tmsi/build/lib/TMSiSDK/settings.py +45 -0
  81. packages/tmsi/build/lib/TMSiSDK/tmsi_device.py +111 -0
  82. packages/tmsi/build/lib/__init__.py +4 -0
  83. packages/tmsi/build/lib/apex_sdk/__init__.py +34 -0
  84. packages/tmsi/build/lib/apex_sdk/device/__init__.py +41 -0
  85. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API.py +1009 -0
  86. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API_enums.py +239 -0
  87. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API_structures.py +668 -0
  88. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_device.py +1611 -0
  89. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_dongle.py +38 -0
  90. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_event_reader.py +57 -0
  91. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_channel.py +44 -0
  92. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_config.py +150 -0
  93. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_const.py +36 -0
  94. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_impedance_channel.py +48 -0
  95. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_info.py +108 -0
  96. packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/dongle_info.py +39 -0
  97. packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/download_measurement.py +77 -0
  98. packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/eeg_measurement.py +150 -0
  99. packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/impedance_measurement.py +129 -0
  100. packages/tmsi/build/lib/apex_sdk/device/threads/conversion_thread.py +59 -0
  101. packages/tmsi/build/lib/apex_sdk/device/threads/sampling_thread.py +57 -0
  102. packages/tmsi/build/lib/apex_sdk/device/tmsi_channel.py +83 -0
  103. packages/tmsi/build/lib/apex_sdk/device/tmsi_device.py +201 -0
  104. packages/tmsi/build/lib/apex_sdk/device/tmsi_device_enums.py +103 -0
  105. packages/tmsi/build/lib/apex_sdk/device/tmsi_dongle.py +43 -0
  106. packages/tmsi/build/lib/apex_sdk/device/tmsi_event_reader.py +50 -0
  107. packages/tmsi/build/lib/apex_sdk/device/tmsi_measurement.py +118 -0
  108. packages/tmsi/build/lib/apex_sdk/sample_data_server/__init__.py +33 -0
  109. packages/tmsi/build/lib/apex_sdk/sample_data_server/event_data.py +44 -0
  110. packages/tmsi/build/lib/apex_sdk/sample_data_server/sample_data.py +50 -0
  111. packages/tmsi/build/lib/apex_sdk/sample_data_server/sample_data_server.py +136 -0
  112. packages/tmsi/build/lib/apex_sdk/tmsi_errors/error.py +126 -0
  113. packages/tmsi/build/lib/apex_sdk/tmsi_sdk.py +113 -0
  114. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/apex/apex_structure_generator.py +134 -0
  115. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/decorators.py +60 -0
  116. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/logger_filter.py +42 -0
  117. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/singleton.py +42 -0
  118. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/support_functions.py +72 -0
  119. packages/tmsi/build/lib/apex_sdk/tmsi_utilities/tmsi_logger.py +98 -0
  120. py_neuromodulation/{helper.py → _write_example_dataset_helper.py} +1 -1
  121. py_neuromodulation/nm_EpochStream.py +2 -3
  122. py_neuromodulation/nm_IO.py +43 -70
  123. py_neuromodulation/nm_RMAP.py +308 -11
  124. py_neuromodulation/nm_analysis.py +1 -1
  125. py_neuromodulation/nm_artifacts.py +25 -0
  126. py_neuromodulation/nm_bispectra.py +64 -29
  127. py_neuromodulation/nm_bursts.py +44 -30
  128. py_neuromodulation/nm_coherence.py +2 -1
  129. py_neuromodulation/nm_features.py +4 -2
  130. py_neuromodulation/nm_filter.py +63 -32
  131. py_neuromodulation/nm_filter_preprocessing.py +91 -0
  132. py_neuromodulation/nm_fooof.py +47 -29
  133. py_neuromodulation/nm_mne_connectivity.py +1 -1
  134. py_neuromodulation/nm_normalization.py +50 -74
  135. py_neuromodulation/nm_oscillatory.py +151 -31
  136. py_neuromodulation/nm_plots.py +13 -10
  137. py_neuromodulation/nm_rereference.py +10 -8
  138. py_neuromodulation/nm_run_analysis.py +28 -13
  139. py_neuromodulation/nm_sharpwaves.py +103 -136
  140. py_neuromodulation/nm_stats.py +44 -30
  141. py_neuromodulation/nm_stream_abc.py +18 -10
  142. py_neuromodulation/nm_stream_offline.py +181 -40
  143. py_neuromodulation/utils/_logging.py +24 -0
  144. {py_neuromodulation-0.0.2.dist-info → py_neuromodulation-0.0.3.dist-info}/METADATA +182 -142
  145. py_neuromodulation-0.0.3.dist-info/RECORD +188 -0
  146. {py_neuromodulation-0.0.2.dist-info → py_neuromodulation-0.0.3.dist-info}/WHEEL +2 -1
  147. py_neuromodulation-0.0.3.dist-info/top_level.txt +5 -0
  148. tests/__init__.py +0 -0
  149. tests/conftest.py +117 -0
  150. tests/test_all_examples.py +10 -0
  151. tests/test_all_features.py +63 -0
  152. tests/test_bispectra.py +70 -0
  153. tests/test_bursts.py +105 -0
  154. tests/test_feature_sampling_rates.py +143 -0
  155. tests/test_fooof.py +16 -0
  156. tests/test_initalization_offline_stream.py +41 -0
  157. tests/test_multiprocessing.py +58 -0
  158. tests/test_nan_values.py +29 -0
  159. tests/test_nm_filter.py +95 -0
  160. tests/test_nm_resample.py +63 -0
  161. tests/test_normalization_settings.py +146 -0
  162. tests/test_notch_filter.py +31 -0
  163. tests/test_osc_features.py +424 -0
  164. tests/test_preprocessing_filter.py +151 -0
  165. tests/test_rereference.py +171 -0
  166. tests/test_sampling.py +57 -0
  167. tests/test_settings_change_after_init.py +76 -0
  168. tests/test_sharpwave.py +165 -0
  169. tests/test_target_channel_add.py +100 -0
  170. tests/test_timing.py +80 -0
  171. py_neuromodulation/data/README +0 -6
  172. py_neuromodulation/data/dataset_description.json +0 -8
  173. py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/MOV_aligned_features_ch_ECOG_RIGHT_0_all.png +0 -0
  174. py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/all_feature_plt.pdf +0 -0
  175. py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_FEATURES.csv +0 -182
  176. py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_LM_ML_RES.p +0 -0
  177. py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_SETTINGS.json +0 -273
  178. py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_SIDECAR.json +0 -6
  179. py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_decoding_performance.png +0 -0
  180. py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_nm_channels.csv +0 -11
  181. py_neuromodulation/data/participants.json +0 -32
  182. py_neuromodulation/data/participants.tsv +0 -2
  183. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_coordsystem.json +0 -5
  184. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_electrodes.tsv +0 -11
  185. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_channels.tsv +0 -11
  186. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.eeg +0 -0
  187. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.json +0 -18
  188. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vhdr +0 -35
  189. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vmrk +0 -13
  190. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/sub-testsub_ses-EphysMedOff_scans.tsv +0 -2
  191. py_neuromodulation/grid_cortex.tsv +0 -40
  192. py_neuromodulation/grid_subcortex.tsv +0 -1429
  193. py_neuromodulation/nm_settings.json +0 -290
  194. py_neuromodulation/plots/STN_surf.mat +0 -0
  195. py_neuromodulation/plots/Vertices.mat +0 -0
  196. py_neuromodulation/plots/faces.mat +0 -0
  197. py_neuromodulation/plots/grid.mat +0 -0
  198. py_neuromodulation/py_neuromodulation.egg-info/PKG-INFO +0 -104
  199. py_neuromodulation/py_neuromodulation.egg-info/dependency_links.txt +0 -1
  200. py_neuromodulation/py_neuromodulation.egg-info/requires.txt +0 -26
  201. py_neuromodulation/py_neuromodulation.egg-info/top_level.txt +0 -1
  202. py_neuromodulation-0.0.2.dist-info/RECORD +0 -73
  203. /py_neuromodulation/{py_neuromodulation.egg-info/SOURCES.txt → utils/__init__.py} +0 -0
  204. {py_neuromodulation-0.0.2.dist-info → py_neuromodulation-0.0.3.dist-info}/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  import mne
2
2
  import mne_bids
3
- import pybv
3
+ import pybv # pip install pybv
4
4
  import os
5
5
 
6
6
 
@@ -4,11 +4,11 @@ import pickle
4
4
  import numpy as np
5
5
  import pandas as pd
6
6
 
7
- import py_neuromodulation as py_nm
7
+ import py_neuromodulation as nm
8
8
  from py_neuromodulation import nm_generator
9
9
 
10
10
 
11
- class EpochStream(py_nm.nm_stream.PNStream):
11
+ class EpochStream(nm.nm_stream.PNStream):
12
12
  def __init__(self) -> None:
13
13
  super().__init__()
14
14
 
@@ -43,7 +43,6 @@ class EpochStream(py_nm.nm_stream.PNStream):
43
43
  def run(
44
44
  self,
45
45
  ):
46
-
47
46
  self._set_run()
48
47
  # shape is n, channels=7, 800 Hz
49
48
 
@@ -2,6 +2,10 @@ import json
2
2
  import os
3
3
  import sys
4
4
  from pathlib import Path
5
+ import logging
6
+
7
+ logger = logging.getLogger("PynmLogger")
8
+
5
9
 
6
10
  import mne
7
11
  import mne_bids
@@ -9,6 +13,9 @@ import numpy as np
9
13
  import pandas as pd
10
14
  from scipy import io
11
15
 
16
+ import pyarrow
17
+ from pyarrow import csv
18
+
12
19
  import py_neuromodulation
13
20
 
14
21
  _PathLike = str | os.PathLike
@@ -27,7 +34,6 @@ def load_nm_channels(
27
34
  reference Union[list, str]
28
35
  """
29
36
 
30
-
31
37
  if isinstance(nm_channels, pd.DataFrame):
32
38
  nm_ch_return = nm_channels
33
39
  elif nm_channels:
@@ -39,6 +45,7 @@ def load_nm_channels(
39
45
 
40
46
  return nm_ch_return
41
47
 
48
+
42
49
  def read_BIDS_data(
43
50
  PATH_RUN: _PathLike | mne_bids.BIDSPath,
44
51
  BIDS_PATH: _PathLike | None = None,
@@ -70,10 +77,8 @@ def read_BIDS_data(
70
77
  if raw_arr.info["line_freq"] is not None:
71
78
  line_noise = int(raw_arr.info["line_freq"])
72
79
  else:
73
- print(
74
- "Line noise is not available in the data, using value of {} Hz.".format(
75
- line_noise
76
- )
80
+ logger.info(
81
+ f"Line noise is not available in the data, using value of {line_noise} Hz."
77
82
  )
78
83
  return (
79
84
  raw_arr,
@@ -120,7 +125,6 @@ def read_grid(PATH_GRIDS: _PathLike | None, grid_str: str) -> pd.DataFrame:
120
125
  def get_annotations(
121
126
  PATH_ANNOTATIONS: str, PATH_RUN: str, raw_arr: mne.io.RawArray
122
127
  ):
123
-
124
128
  try:
125
129
  annot = mne.read_annotations(
126
130
  Path(PATH_ANNOTATIONS) / (os.path.basename(PATH_RUN)[:-5] + ".txt")
@@ -130,18 +134,19 @@ def get_annotations(
130
134
  # annotations starting with "BAD" are omitted with reject_by_annotations 'omit' param
131
135
  annot_data = raw_arr.get_data(reject_by_annotation="omit")
132
136
  except FileNotFoundError:
133
- print("Annotations file could not be found")
134
- print(
135
- "expected location: "
137
+ logger.critical(
138
+ "Annotations file could not be found"
139
+ + "expected location: "
136
140
  + str(
137
- Path(PATH_ANNOTATIONS) / (os.path.basename(PATH_RUN)[:-5] + ".txt")
141
+ Path(PATH_ANNOTATIONS)
142
+ / (os.path.basename(PATH_RUN)[:-5] + ".txt")
138
143
  )
139
144
  )
140
145
  return annot, annot_data, raw_arr
141
146
 
142
147
 
143
148
  def read_plot_modules(
144
- PATH_PLOT: _PathLike = Path(__file__).absolute().parent / "plots"
149
+ PATH_PLOT: _PathLike = Path(__file__).absolute().parent / "plots",
145
150
  ):
146
151
  """Read required .mat files for plotting
147
152
 
@@ -180,55 +185,6 @@ def read_plot_modules(
180
185
  )
181
186
 
182
187
 
183
- def add_labels(
184
- features: pd.DataFrame,
185
- settings: dict,
186
- nm_channels: pd.DataFrame,
187
- raw_arr_data: np.ndarray,
188
- fs: int | float,
189
- ) -> pd.DataFrame | None:
190
- """Given a constructed feature data frame, resample the target labels and add to dataframe
191
-
192
- Parameters
193
- ----------
194
- features : pd.DataFrame
195
- computed feature dataframe
196
- settings_wrapper : settings.py
197
- initialized settings used for feature estimation
198
- raw_arr_data : np.ndarray
199
- raw data including target
200
-
201
- Returns
202
- -------
203
- pd.DataFrame | None
204
- computed feature dataframe including resampled features
205
- """
206
- # resample_label
207
- ind_label = np.where(nm_channels.target == 1)[0]
208
- if ind_label.shape[0] == 0:
209
- print("no target specified")
210
- return None
211
-
212
- offset_time = settings["segment_length_features_ms"]
213
-
214
- offset_start = np.ceil(offset_time / 1000 * fs).astype(int)
215
- data = raw_arr_data[ind_label, offset_start:]
216
- if data.ndim == 1:
217
- data = np.expand_dims(data, axis=0)
218
- label_downsampled = data[
219
- :,
220
- :: int(np.ceil(fs / settings["sampling_rate_features_hz"])),
221
- ]
222
-
223
- # and add to df
224
- if features.shape[0] == label_downsampled.shape[1]:
225
- for idx, label_ch in enumerate(nm_channels.name[ind_label]):
226
- features[label_ch] = label_downsampled[idx, :]
227
- else:
228
- print("label dimensions don't match, saving downsampled label extra")
229
- return features
230
-
231
-
232
188
  def save_features_and_settings(
233
189
  df_features,
234
190
  run_analysis,
@@ -256,7 +212,7 @@ def save_features_and_settings(
256
212
 
257
213
  # create out folder if doesn't exist
258
214
  if not os.path.exists(os.path.join(out_path, folder_name)):
259
- print("Creating output folder: " + str(folder_name))
215
+ logger.Info(f"Creating output folder: {folder_name}")
260
216
  os.makedirs(os.path.join(out_path, folder_name))
261
217
 
262
218
  dict_sidecar = {"fs": fs, "coords": coords, "line_noise": line_noise}
@@ -267,6 +223,16 @@ def save_features_and_settings(
267
223
  save_nm_channels(nm_channels, out_path, folder_name)
268
224
 
269
225
 
226
+ def write_csv(df, path_out):
227
+ """
228
+ Function to save Pandas dataframes to disk as CSV using
229
+ PyArrow (almost 10x faster than Pandas)
230
+ Difference with pandas.df.to_csv() is that it does not
231
+ write an index column by default
232
+ """
233
+ csv.write_csv(pyarrow.Table.from_pandas(df), path_out)
234
+
235
+
270
236
  def save_settings(
271
237
  settings: dict, path_out: _PathLike, folder_name: str | None = None
272
238
  ) -> None:
@@ -278,7 +244,7 @@ def save_settings(
278
244
 
279
245
  with open(path_out, "w") as f:
280
246
  json.dump(settings, f, indent=4)
281
- print("settings.json saved to " + path_out)
247
+ logger.info(f"settings.json saved to {path_out}")
282
248
 
283
249
 
284
250
  def save_nm_channels(
@@ -291,8 +257,8 @@ def save_nm_channels(
291
257
  path_out = os.path.join(
292
258
  path_out, folder_name, folder_name + "_nm_channels.csv"
293
259
  )
294
- nmchannels.to_csv(path_out)
295
- print("nm_channels.csv saved to " + path_out)
260
+ write_csv(nmchannels, path_out)
261
+ logger.info(f"nm_channels.csv saved to {path_out}")
296
262
 
297
263
 
298
264
  def save_features(
@@ -305,8 +271,8 @@ def save_features(
305
271
  path_out = os.path.join(
306
272
  path_out, folder_name, folder_name + "_FEATURES.csv"
307
273
  )
308
- df_features.to_csv(path_out)
309
- print("FEATURES.csv saved to " + str(path_out))
274
+ write_csv(df_features, path_out)
275
+ logger.info(f"FEATURES.csv saved to {str(path_out)}")
310
276
 
311
277
 
312
278
  def save_sidecar(
@@ -333,7 +299,7 @@ def save_general_dict(
333
299
  indent=4,
334
300
  separators=(",", ": "),
335
301
  )
336
- print(f"{str_add} saved to " + str(path_out))
302
+ logger.info(f"{str_add} saved to " + str(path_out))
337
303
 
338
304
 
339
305
  def default_json_convert(obj) -> list | int | float:
@@ -359,11 +325,11 @@ def read_settings(PATH: str) -> dict:
359
325
 
360
326
 
361
327
  def read_features(PATH: str) -> pd.DataFrame:
362
- return pd.read_csv(PATH + "_FEATURES.csv", index_col=0)
328
+ return pd.read_csv(PATH + "_FEATURES.csv", engine="pyarrow")
363
329
 
364
330
 
365
331
  def read_nm_channels(PATH: str) -> pd.DataFrame:
366
- return pd.read_csv(PATH + "_nm_channels.csv", index_col=0)
332
+ return pd.read_csv(PATH + "_nm_channels.csv")
367
333
 
368
334
 
369
335
  def get_run_list_indir(PATH: str) -> list:
@@ -405,7 +371,14 @@ def get_paths_example_data():
405
371
 
406
372
  PATH_BIDS = Path(SCRIPT_DIR) / "data"
407
373
 
408
- PATH_RUN = Path(SCRIPT_DIR) / "data" / f"sub-{sub}" / f"ses-{ses}" / datatype / RUN_NAME
374
+ PATH_RUN = (
375
+ Path(SCRIPT_DIR)
376
+ / "data"
377
+ / f"sub-{sub}"
378
+ / f"ses-{ses}"
379
+ / datatype
380
+ / RUN_NAME
381
+ )
409
382
 
410
383
  # Provide a path for the output data.
411
384
  PATH_OUT = PATH_BIDS / "derivatives"
@@ -1,14 +1,304 @@
1
- import enum
2
- import nibabel as nib
3
1
  import numpy as np
4
2
  import os
5
- #from numba import jit
3
+ import wget
4
+
5
+
6
+ # from numba import jit
6
7
  from scipy import stats
8
+ import scipy.io as sio
7
9
  import pandas as pd
10
+ from typing import Union, Tuple, List
11
+ import nibabel as nib
12
+ from matplotlib import pyplot as plt
13
+
14
+ import py_neuromodulation
8
15
 
9
16
  from py_neuromodulation import nm_plots
10
17
 
11
- class RMAPChannelSelector:
18
+ LIST_STRUC_UNCONNECTED_GRIDPOINTS_HULL = [256, 385, 417, 447, 819, 914]
19
+ LIST_STRUC_UNCONNECTED_GRIDPOINTS_WHOLEBRAIN = [
20
+ 1,
21
+ 8,
22
+ 16,
23
+ 33,
24
+ 34,
25
+ 35,
26
+ 36,
27
+ 37,
28
+ 51,
29
+ 75,
30
+ 77,
31
+ 78,
32
+ 99,
33
+ 109,
34
+ 115,
35
+ 136,
36
+ 155,
37
+ 170,
38
+ 210,
39
+ 215,
40
+ 243,
41
+ 352,
42
+ 359,
43
+ 361,
44
+ 415,
45
+ 416,
46
+ 422,
47
+ 529,
48
+ 567,
49
+ 569,
50
+ 622,
51
+ 623,
52
+ 625,
53
+ 627,
54
+ 632,
55
+ 633,
56
+ 634,
57
+ 635,
58
+ 639,
59
+ 640,
60
+ 641,
61
+ 643,
62
+ 644,
63
+ 650,
64
+ 661,
65
+ 663,
66
+ 667,
67
+ 683,
68
+ 684,
69
+ 685,
70
+ 704,
71
+ 708,
72
+ 722,
73
+ 839,
74
+ 840,
75
+ 905,
76
+ 993,
77
+ 1011,
78
+ ]
79
+
80
+
81
+ class ConnectivityChannelSelector:
82
+
83
+ def __init__(
84
+ self,
85
+ whole_brain_connectome: bool = True,
86
+ func_connectivity: bool = True,
87
+ ) -> None:
88
+ """ConnectivityChannelSelector
89
+
90
+ Parameters
91
+ ----------
92
+ whole_brain_connectome : bool, optional
93
+ if True a 1236 whole-brain point grid is chosen,
94
+ if False, a 1025 point grid of the cortical hull is loaded,
95
+ by default True
96
+ func_connectivity : bool, optional
97
+ if true, functional connectivity fMRI is loaded,
98
+ if false structural dMRIby, default True
99
+ """
100
+
101
+ self.connectome_name = self._get_connectome_name(
102
+ whole_brain_connectome, func_connectivity
103
+ )
104
+
105
+ self.whole_brain_connectome = whole_brain_connectome
106
+ self.func_connectivity = func_connectivity
107
+
108
+ self.PATH_CONN_DECODING = os.path.join(
109
+ py_neuromodulation.__path__[0],
110
+ "ConnectivityDecoding",
111
+ )
112
+
113
+ if whole_brain_connectome:
114
+ self.PATH_GRID = os.path.join(
115
+ self.PATH_CONN_DECODING,
116
+ "mni_coords_whole_brain.mat",
117
+ )
118
+ self.grid = sio.loadmat(self.PATH_GRID)["downsample_ctx"]
119
+ if func_connectivity is False:
120
+ # reduce the grid to only valid points that are not in LIST_STRUC_UNCONNECTED_GRIDPOINTS_WHOLEBRAIN
121
+ self.grid = np.delete(
122
+ self.grid,
123
+ LIST_STRUC_UNCONNECTED_GRIDPOINTS_WHOLEBRAIN,
124
+ axis=0,
125
+ )
126
+ else:
127
+ self.PATH_GRID = os.path.join(
128
+ self.PATH_CONN_DECODING,
129
+ "mni_coords_cortical_surface.mat",
130
+ )
131
+ self.grid = sio.loadmat(self.PATH_GRID)["downsample_ctx"]
132
+ if func_connectivity is False:
133
+ # reduce the grid to only valid points that are not in LIST_STRUC_UNCONNECTED_GRIDPOINTS_HULL
134
+ self.grid = np.delete(
135
+ self.grid, LIST_STRUC_UNCONNECTED_GRIDPOINTS_HULL, axis=0
136
+ )
137
+
138
+ if func_connectivity:
139
+ self.RMAP_arr = nib.load(
140
+ os.path.join(self.PATH_CONN_DECODING, "RMAP_func_all.nii")
141
+ ).get_fdata()
142
+ else:
143
+ self.RMAP_arr = nib.load(
144
+ os.path.join(self.PATH_CONN_DECODING, "RMAP_struc.nii")
145
+ ).get_fdata()
146
+
147
+ def _get_connectome_name(
148
+ self, whole_brain_connectome: str, func_connectivity: str
149
+ ):
150
+
151
+ connectome_name = "connectome_"
152
+ if whole_brain_connectome:
153
+ connectome_name += "whole_brain_"
154
+ else:
155
+ connectome_name += "hull_"
156
+ if func_connectivity:
157
+ connectome_name += "func"
158
+ else:
159
+ connectome_name += "struc"
160
+ return connectome_name
161
+
162
+ def get_available_connectomes(self) -> list:
163
+ """Return list of saved connectomes in the
164
+ package folder/ConnectivityDecoding/connectome_folder/ folder.
165
+
166
+ Returns
167
+ -------
168
+ list_connectomes: list
169
+ """
170
+ return os.listdir(
171
+ os.path.join(
172
+ self.PATH_CONN_DECODING,
173
+ "connectome_folder",
174
+ )
175
+ )
176
+
177
+ def plot_grid(self) -> None:
178
+ """Plot the loaded template grid that passed coordinates are matched to."""
179
+
180
+ fig = plt.figure()
181
+ ax = fig.add_subplot(111, projection="3d")
182
+ ax.scatter(
183
+ self.grid[:, 0], self.grid[:, 1], self.grid[:, 2], s=50, alpha=0.2
184
+ )
185
+ plt.show()
186
+
187
+ def get_closest_node(
188
+ self, coord: Union[List, np.array]
189
+ ) -> Tuple[List, List]:
190
+ """Given a list or np.array of coordinates, return the closest nodes in the
191
+ grid and their indices.
192
+
193
+ Parameters
194
+ ----------
195
+ coord : np.array
196
+ MNI coordinates with shape (num_channels, 3)
197
+
198
+ Returns
199
+ -------
200
+ Tuple[List, List]
201
+ Grid coordinates, grid indices
202
+ """
203
+
204
+ idx_ = []
205
+ for c in coord:
206
+ dist = np.linalg.norm(self.grid - c, axis=1)
207
+ idx_.append(np.argmin(dist))
208
+
209
+ return [self.grid[idx] for idx in idx_], idx_
210
+
211
+ def get_rmap_correlations(
212
+ self, fps: Union[list, np.array], RMAP_use: np.array = None
213
+ ) -> List:
214
+ """Calculate correlations of passed fingerprints with the RMAP
215
+
216
+ Parameters
217
+ ----------
218
+ fps : Union[list, np.array]
219
+ List of fingerprints
220
+ RMAP_use : np.array, optional
221
+ Passed RMAP, by default None
222
+
223
+ Returns
224
+ -------
225
+ List
226
+ correlation values
227
+ """
228
+
229
+ RMAP_ = self.RMAP_arr if RMAP_use is None else RMAP_use
230
+ RMAP_ = RMAP_.flatten()
231
+ corrs = []
232
+ for fp in fps:
233
+ corrs.append(np.corrcoef(RMAP_, fp.flatten())[0][1])
234
+ return corrs
235
+
236
+ def load_connectome(
237
+ self,
238
+ whole_brain_connectome: bool = None,
239
+ func_connectivity: bool = None,
240
+ ) -> None:
241
+ """Load connectome, if not available download connectome from
242
+ Zenodo.
243
+
244
+ Parameters
245
+ ----------
246
+ whole_brain_connectome : bool, optional
247
+ if true whole brain connectome
248
+ if false cortical hull grid connectome, by default None
249
+ func_connectivity : bool, optional
250
+ if true fMRI if false dMRI, by default None
251
+ """
252
+
253
+ if whole_brain_connectome is not None:
254
+ self.whole_brain_connectome = whole_brain_connectome
255
+ if func_connectivity is not None:
256
+ self.func_connectivity = func_connectivity
257
+
258
+ self.connectome_name = self._get_connectome_name(
259
+ self.whole_brain_connectome, self.func_connectivity
260
+ )
261
+
262
+ PATH_CONNECTOME = os.path.join(
263
+ self.PATH_CONN_DECODING,
264
+ "connectome_folder",
265
+ self.connectome_name + ".mat",
266
+ )
267
+
268
+ if os.path.exists(PATH_CONNECTOME) is False:
269
+ user_input = input(
270
+ "Do you want to download the connectome? (yes/no): "
271
+ ).lower()
272
+ if user_input == "yes":
273
+ self._download_connectome()
274
+ elif user_input == "no":
275
+ print("Connectome missing, has to be downloaded")
276
+
277
+ self.connectome = sio.loadmat(PATH_CONNECTOME)
278
+
279
+ def get_grid_fingerprints(self, grid_idx: Union[list, np.array]) -> list:
280
+ return [self.connectome[str(grid_idx)] for grid_idx in grid_idx]
281
+
282
+ def download_connectome(
283
+ self,
284
+ ):
285
+ # download the connectome from the Zenodo API
286
+ print("Downloading the connectome...")
287
+
288
+ record_id = "10804702"
289
+ file_name = self.connectome_name
290
+
291
+ wget.download(
292
+ f"https://zenodo.org/api/records/{record_id}/files/{file_name}/content",
293
+ out=os.path.join(
294
+ self.PATH_CONN_DECODING,
295
+ "connectome_folder",
296
+ f"{self.connectome_name}.mat",
297
+ ),
298
+ )
299
+
300
+
301
+ class RMAPCross_Val_ChannelSelector:
12
302
 
13
303
  def __init__(self) -> None:
14
304
  pass
@@ -90,7 +380,7 @@ class RMAPChannelSelector:
90
380
  return r
91
381
 
92
382
  @staticmethod
93
- #@jit(nopython=True)
383
+ # @jit(nopython=True)
94
384
  def calculate_RMap_numba(fp, performances):
95
385
  # The RMap also needs performances; for every fingerprint / channel
96
386
  # Save the corresponding performance
@@ -112,7 +402,7 @@ class RMAPChannelSelector:
112
402
  return RMAP
113
403
 
114
404
  @staticmethod
115
- #@jit(nopython=True)
405
+ # @jit(nopython=True)
116
406
  def get_corr_numba(fp, fp_test):
117
407
  val = np.corrcoef(fp_test, fp)[0][1]
118
408
  return val
@@ -126,7 +416,7 @@ class RMAPChannelSelector:
126
416
  per_predict = []
127
417
 
128
418
  for idx_left_out, f_left_out in enumerate(l_fps_names):
129
- print(idx_left_out)
419
+ # print(idx_left_out)
130
420
  l_cv = l_fps_dat.copy()
131
421
  per_cv = l_per.copy()
132
422
 
@@ -160,7 +450,7 @@ class RMAPChannelSelector:
160
450
  per_left_out = []
161
451
 
162
452
  for subject_test in sub_list:
163
- print(subject_test)
453
+ # print(subject_test)
164
454
  idx_test = [
165
455
  idx for idx, f in enumerate(l_fps_names) if subject_test in f
166
456
  ]
@@ -224,11 +514,18 @@ class RMAPChannelSelector:
224
514
  idx_max = np.argmax(np.array(fp_pairs)[:, 3])
225
515
  return fp_pairs[idx_max][0:3]
226
516
 
227
- def plot_performance_prediction_correlation(per_left_out, per_predict, out_path_save: str = None):
517
+ def plot_performance_prediction_correlation(
518
+ per_left_out, per_predict, out_path_save: str = None
519
+ ):
228
520
  df_plt_corr = pd.DataFrame()
229
521
  df_plt_corr["test_performance"] = per_left_out
230
- df_plt_corr["struct_conn_predict"] = per_predict # change "struct" with "funct" for functional connectivity
522
+ df_plt_corr["struct_conn_predict"] = (
523
+ per_predict # change "struct" with "funct" for functional connectivity
524
+ )
231
525
 
232
526
  nm_plots.reg_plot(
233
- x_col="test_performance", y_col="struct_conn_predict", data=df_plt_corr, out_path_save=out_path_save
527
+ x_col="test_performance",
528
+ y_col="struct_conn_predict",
529
+ data=df_plt_corr,
530
+ out_path_save=out_path_save,
234
531
  )
@@ -221,7 +221,7 @@ class Feature_Reader:
221
221
  pd.DataFrame: z-scored feature_arr
222
222
  """
223
223
  cols_norm = [c for c in self.feature_arr.columns if "time" not in c]
224
- feature_arr_norm = stats.zscore(self.feature_arr[cols_norm])
224
+ feature_arr_norm = stats.zscore(self.feature_arr[cols_norm], nan_policy="omit")
225
225
  feature_arr_norm["time"] = self.feature_arr["time"]
226
226
  return feature_arr_norm
227
227
 
@@ -0,0 +1,25 @@
1
+ from pyparrm import PARRM
2
+
3
+
4
+ class PARRMArtifactRejection:
5
+ def __init__(self, data, sampling_freq, artefact_freq, verbose=False):
6
+ self.data = data
7
+ self.sampling_freq = sampling_freq
8
+ self.artefact_freq = artefact_freq
9
+ self.verbose = verbose
10
+
11
+ self.parrm = PARRM(
12
+ data=data,
13
+ sampling_freq=sampling_freq,
14
+ artefact_freq=artefact_freq,
15
+ verbose=False,
16
+ )
17
+
18
+ def filter_data(self):
19
+ self.parrm.find_period()
20
+ self.parrm.create_filter(
21
+ filter_direction="both",
22
+ )
23
+ filtered_data = self.parrm.filter_data()
24
+
25
+ return filtered_data