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