py-neuromodulation 0.1.4__tar.gz → 0.1.7__tar.gz

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 (286) hide show
  1. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/.github/workflows/tests.yml +7 -11
  2. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/PKG-INFO +10 -1
  3. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/README.rst +9 -0
  4. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/index.rst +8 -0
  5. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/default_settings.yaml +5 -4
  6. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/fooof.py +9 -5
  7. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/sharpwaves.py +16 -8
  8. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/rereference.py +6 -1
  9. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/data_processor.py +7 -2
  10. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/channels.py +5 -1
  11. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/pydantic_extensions.py +9 -18
  12. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/types.py +3 -3
  13. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/pyproject.toml +1 -1
  14. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/conftest.py +61 -1
  15. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_all_features.py +8 -5
  16. py_neuromodulation-0.1.7/tests/test_bad_channels.py +22 -0
  17. py_neuromodulation-0.1.7/tests/test_fooof.py +52 -0
  18. py_neuromodulation-0.1.7/tests/test_nan_values.py +68 -0
  19. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_rereference.py +49 -0
  20. py_neuromodulation-0.1.4/tests/test_fooof.py +0 -21
  21. py_neuromodulation-0.1.4/tests/test_nan_values.py +0 -27
  22. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/.gitattributes +0 -0
  23. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/.github/workflows/docs_pages.yml +0 -0
  24. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/.github/workflows/python-publish.yml +0 -0
  25. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/.gitignore +0 -0
  26. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/LICENSE +0 -0
  27. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/Makefile +0 -0
  28. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/make.bat +0 -0
  29. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/RMAP.rst +0 -0
  30. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/CEBRA_embedding.png +0 -0
  31. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/RMAP_figure.png +0 -0
  32. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/channelselection.png +0 -0
  33. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/css/RMAP_figure.png +0 -0
  34. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/css/project-template.css +0 -0
  35. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/decoding.png +0 -0
  36. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/fileselection.png +0 -0
  37. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/graphs.png +0 -0
  38. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/lslselection.png +0 -0
  39. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/pydantic.png +0 -0
  40. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/settings.png +0 -0
  41. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/sourceselection.png +0 -0
  42. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_templates/custom-class-template.rst +0 -0
  43. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_templates/custom-module-template.rst +0 -0
  44. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/api_documentation.rst +0 -0
  45. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/artifacts.rst +0 -0
  46. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/bandpower.rst +0 -0
  47. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/bispectra.rst +0 -0
  48. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/bursts.rst +0 -0
  49. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/channels.rst +0 -0
  50. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/coherence.rst +0 -0
  51. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/conf.py +0 -0
  52. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/contributing.rst +0 -0
  53. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/database.rst +0 -0
  54. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/decode.rst +0 -0
  55. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/feature_reader.rst +0 -0
  56. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/fooof.rst +0 -0
  57. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/generator.rst +0 -0
  58. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/gui.rst +0 -0
  59. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/hjorth.rst +0 -0
  60. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/installation.rst +0 -0
  61. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/io.rst +0 -0
  62. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/linelength.rst +0 -0
  63. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/logging.rst +0 -0
  64. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/mne_connectivity.rst +0 -0
  65. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/mne_filter.rst +0 -0
  66. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/mnelsl_player.rst +0 -0
  67. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/mnelsl_stream.rst +0 -0
  68. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/nolds.rst +0 -0
  69. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/normalization.rst +0 -0
  70. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/notch_filter.rst +0 -0
  71. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/oscillatory.rst +0 -0
  72. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/plots.rst +0 -0
  73. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/projection.rst +0 -0
  74. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/rereference.rst +0 -0
  75. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/resample.rst +0 -0
  76. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/settings.rst +0 -0
  77. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/sharpwaves.rst +0 -0
  78. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/stats.rst +0 -0
  79. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/stream.rst +0 -0
  80. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/types.rst +0 -0
  81. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/usage.rst +0 -0
  82. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/README.rst +0 -0
  83. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/example_cebra_decoding.html +0 -0
  84. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/example_cebra_decoding.ipynb +0 -0
  85. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/example_rmap.ipynb +0 -0
  86. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_2_example_add_feature.py +0 -0
  87. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_3_example_sharpwave_analysis.py +0 -0
  88. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_4_example_gridPointProjection.py +0 -0
  89. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_5_example_rmap_computing.py +0 -0
  90. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_6_real_time_demo.py +0 -0
  91. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_7_lsl_example.py +0 -0
  92. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_8_cebra_example.py +0 -0
  93. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/.eslintrc.cjs +0 -0
  94. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/.gitattributes +0 -0
  95. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/.gitignore +0 -0
  96. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/bun.lock +0 -0
  97. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/eslint.config.js +0 -0
  98. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/index.html +0 -0
  99. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/jsconfig.json +0 -0
  100. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/package.json +0 -0
  101. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/public/charite.svg +0 -0
  102. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/scripts/wdyr.js +0 -0
  103. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/App.jsx +0 -0
  104. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/assets/fonts/figtree/Figtree-Italic-VariableFont_wght.ttf +0 -0
  105. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/assets/fonts/figtree/Figtree-VariableFont_wght.ttf +0 -0
  106. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/assets/fonts/figtree/OFL.txt +0 -0
  107. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/assets/fonts/figtree/README.txt +0 -0
  108. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/AppBar/index.js +0 -0
  109. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/AppBar.jsx +0 -0
  110. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/AppInfoModal.jsx +0 -0
  111. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/BandPowerGraph.jsx +0 -0
  112. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/CollapsibleBox.jsx +0 -0
  113. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/DecodingGraph.jsx +0 -0
  114. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Drawer/index.js +0 -0
  115. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/FileBrowser/FileBrowser.jsx +0 -0
  116. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/FileBrowser/QuickAccess.jsx +0 -0
  117. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Graph/index.js +0 -0
  118. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/HeatmapGraph.jsx +0 -0
  119. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/PSDGraph.jsx +0 -0
  120. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/RawDataGraph.jsx +0 -0
  121. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Settings/index.js +0 -0
  122. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Sidebar/Sidebar.jsx +0 -0
  123. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Sidebar/Sidebar.module.css +0 -0
  124. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Sidebar/index.js +0 -0
  125. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/ResizeHandle.jsx +0 -0
  126. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/ResizeHandle.module.css +0 -0
  127. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/SocketStatus.jsx +0 -0
  128. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/StatusBar.jsx +0 -0
  129. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/StatusBar.module.css +0 -0
  130. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/WebviewStatus.jsx +0 -0
  131. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/index.js +0 -0
  132. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/resize_handle.svg +0 -0
  133. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Switch/index.js +0 -0
  134. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/TitledBox.jsx +0 -0
  135. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/WindowButtons.jsx +0 -0
  136. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/index.js +0 -0
  137. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/utils.jsx +0 -0
  138. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/main.jsx +0 -0
  139. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Channels/Channels.jsx +0 -0
  140. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Dashboard.jsx +0 -0
  141. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Settings/Settings.jsx +0 -0
  142. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Settings/components/FrequencyRange.jsx +0 -0
  143. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Settings/components/OrderableLiteralListField.jsx +0 -0
  144. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Settings/components/PrimitiveComponents.jsx +0 -0
  145. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/SourceSelection/DecodingModel.jsx +0 -0
  146. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/SourceSelection/FileSelector.jsx +0 -0
  147. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/SourceSelection/SourceSelection.jsx +0 -0
  148. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/SourceSelection/StreamParameters.jsx +0 -0
  149. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/SourceSelection/StreamSelector.jsx +0 -0
  150. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/index.js +0 -0
  151. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/appInfoStore.js +0 -0
  152. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/createStore.js +0 -0
  153. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/dragAndDropStore.js +0 -0
  154. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/index.js +0 -0
  155. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/sessionStore.js +0 -0
  156. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/settingsStore.js +0 -0
  157. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/socketStore.js +0 -0
  158. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/uiStore.js +0 -0
  159. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/webviewStore.js +0 -0
  160. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/styles/reset.css +0 -0
  161. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/theme.js +0 -0
  162. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/DataBuffer.js +0 -0
  163. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/FileInfo.js +0 -0
  164. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/FileManager.js +0 -0
  165. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/debounced_sync.js +0 -0
  166. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/index.js +0 -0
  167. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/utils.js +0 -0
  168. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/vite.config.js +0 -0
  169. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/Automated Anatomical Labeling 3 (Rolls 2020).nii +0 -0
  170. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/_get_grid_hull.m +0 -0
  171. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/_get_grid_whole_brain.py +0 -0
  172. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/_helper_write_connectome.py +0 -0
  173. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/mni_coords_cortical_surface.mat +0 -0
  174. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/mni_coords_whole_brain.mat +0 -0
  175. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/rmap_func_all.nii +0 -0
  176. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/rmap_struc.nii +0 -0
  177. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/__init__.py +0 -0
  178. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/RMAP.py +0 -0
  179. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/__init__.py +0 -0
  180. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/decode.py +0 -0
  181. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/feature_reader.py +0 -0
  182. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/plots.py +0 -0
  183. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/stats.py +0 -0
  184. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/README +0 -0
  185. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/dataset_description.json +0 -0
  186. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/participants.json +0 -0
  187. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/participants.tsv +0 -0
  188. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_coordsystem.json +0 -0
  189. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_electrodes.tsv +0 -0
  190. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_channels.tsv +0 -0
  191. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.eeg +0 -0
  192. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.json +0 -0
  193. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vhdr +0 -0
  194. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vmrk +0 -0
  195. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/sub-testsub/ses-EphysMedOff/sub-testsub_ses-EphysMedOff_scans.tsv +0 -0
  196. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/__init__.py +0 -0
  197. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/bandpower.py +0 -0
  198. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/bispectra.py +0 -0
  199. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/bursts.py +0 -0
  200. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/coherence.py +0 -0
  201. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/feature_processor.py +0 -0
  202. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/hjorth_raw.py +0 -0
  203. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/linelength.py +0 -0
  204. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/mne_connectivity.py +0 -0
  205. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/nolds.py +0 -0
  206. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/oscillatory.py +0 -0
  207. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/filter/__init__.py +0 -0
  208. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/filter/kalman_filter.py +0 -0
  209. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/filter/kalman_filter_external.py +0 -0
  210. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/filter/mne_filter.py +0 -0
  211. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/filter/notch_filter.py +0 -0
  212. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/grid_cortex.tsv +0 -0
  213. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/grid_subcortex.tsv +0 -0
  214. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/__init__.py +0 -0
  215. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_backend.py +0 -0
  216. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_manager.py +0 -0
  217. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_pynm.py +0 -0
  218. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_socket.py +0 -0
  219. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_utils.py +0 -0
  220. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_window.py +0 -0
  221. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/frontend/assets/Figtree-VariableFont_wght-CkXbWBDP.ttf +0 -0
  222. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/frontend/assets/index-B53U6dwc.js +0 -0
  223. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/frontend/assets/plotly-DTCwMlpS.js +0 -0
  224. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/frontend/charite.svg +0 -0
  225. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/frontend/index.html +0 -0
  226. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/window_api.py +0 -0
  227. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/libpugixml.so.1.12 +0 -0
  228. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/bionic_amd64/liblsl.1.16.2.so +0 -0
  229. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/bookworm_amd64/liblsl.1.16.2.so +0 -0
  230. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/focal_amd46/liblsl.1.16.2.so +0 -0
  231. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/jammy_amd64/liblsl.1.16.2.so +0 -0
  232. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/jammy_x86/liblsl.1.16.2.so +0 -0
  233. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/noble_amd64/liblsl.1.16.2.so +0 -0
  234. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/macos/amd64/liblsl.1.16.2.dylib +0 -0
  235. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/macos/arm64/liblsl.1.16.0.dylib +0 -0
  236. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/windows/amd64/liblsl.1.16.2.dll +0 -0
  237. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/windows/x86/liblsl.1.16.2.dll +0 -0
  238. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/lsl_api.cfg +0 -0
  239. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/plots/STN_surf.mat +0 -0
  240. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/plots/Vertices.mat +0 -0
  241. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/plots/faces.mat +0 -0
  242. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/plots/grid.mat +0 -0
  243. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/__init__.py +0 -0
  244. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/artifacts.py +0 -0
  245. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/data_preprocessor.py +0 -0
  246. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/filter_preprocessing.py +0 -0
  247. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/normalization.py +0 -0
  248. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/projection.py +0 -0
  249. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/resample.py +0 -0
  250. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/run_gui.py +0 -0
  251. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/__init__.py +0 -0
  252. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/backend_interface.py +0 -0
  253. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/generator.py +0 -0
  254. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/mnelsl_player.py +0 -0
  255. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/mnelsl_stream.py +0 -0
  256. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/settings.py +0 -0
  257. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/stream.py +0 -0
  258. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/__init__.py +0 -0
  259. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/database.py +0 -0
  260. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/file_writer.py +0 -0
  261. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/io.py +0 -0
  262. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/keyboard.py +0 -0
  263. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/logging.py +0 -0
  264. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/perf.py +0 -0
  265. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation.code-workspace +0 -0
  266. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/__init__.py +0 -0
  267. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_all_examples.py +0 -0
  268. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_bispectra.py +0 -0
  269. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_bursts.py +0 -0
  270. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_coherence.py +0 -0
  271. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_database.py +0 -0
  272. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_feature_sampling_rates.py +0 -0
  273. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_initalization_offline_stream.py +0 -0
  274. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_lsl_stream.py +0 -0
  275. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_mne_connectivity.py +0 -0
  276. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_nm_filter.py +0 -0
  277. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_nm_resample.py +0 -0
  278. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_normalization_settings.py +0 -0
  279. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_notch_filter.py +0 -0
  280. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_osc_features.py +0 -0
  281. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_preprocessing_filter.py +0 -0
  282. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_sampling.py +0 -0
  283. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_settings_change_after_init.py +0 -0
  284. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_sharpwave.py +0 -0
  285. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_target_channel_add.py +0 -0
  286. {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_timing.py +0 -0
@@ -43,17 +43,13 @@ jobs:
43
43
  with:
44
44
  packages: binutils qtbase5-dev qt5-qmake libpugixml1v5
45
45
  - name: Install uv
46
- uses: astral-sh/setup-uv@v3
46
+ uses: astral-sh/setup-uv@v7
47
47
  with:
48
- version: "0.4.12"
49
- enable-cache: true
48
+ python-version: "${{ matrix.python }}"
49
+ enable-cache: auto
50
+ activate-environment: "true"
50
51
  cache-dependency-glob: "**/pyproject.toml"
51
- - name: Install Python and dependencies
52
- run: |
53
- uv python install ${{ matrix.python }}
54
- uv venv
55
- uv pip install .[test]
52
+ - name: Install dependencies
53
+ run: uv pip install .[test]
56
54
  - name: Run tests
57
- run: |
58
- ${{ (runner.os == 'Windows' && '.venv\Scripts\activate') || 'source .venv/bin/activate' }}
59
- pytest -n auto tests/
55
+ run: pytest -n auto tests/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py_neuromodulation
3
- Version: 0.1.4
3
+ Version: 0.1.7
4
4
  Summary: Real-time analysis of intracranial neurophysiology recordings.
5
5
  Project-URL: Homepage, https://neuromodulation.github.io/py_neuromodulation/
6
6
  Project-URL: Documentation, https://neuromodulation.github.io/py_neuromodulation/
@@ -92,9 +92,18 @@ Requires-Dist: pytest-xdist; extra == 'test'
92
92
  Requires-Dist: pytest>=8.0.2; extra == 'test'
93
93
  Description-Content-Type: text/x-rst
94
94
 
95
+
96
+
95
97
  py_neuromodulation
96
98
  ==================
97
99
 
100
+ Journal of Open Source Science publication:
101
+
102
+ .. image:: https://joss.theoj.org/papers/10.21105/joss.08258/status.svg
103
+ :target: https://doi.org/10.21105/joss.08258
104
+
105
+
106
+
98
107
  Documentation: https://neuromodulation.github.io/py_neuromodulation/
99
108
 
100
109
  Analyzing neural data can be a troublesome, trial and error prone,
@@ -1,6 +1,15 @@
1
+
2
+
1
3
  py_neuromodulation
2
4
  ==================
3
5
 
6
+ Journal of Open Source Science publication:
7
+
8
+ .. image:: https://joss.theoj.org/papers/10.21105/joss.08258/status.svg
9
+ :target: https://doi.org/10.21105/joss.08258
10
+
11
+
12
+
4
13
  Documentation: https://neuromodulation.github.io/py_neuromodulation/
5
14
 
6
15
  Analyzing neural data can be a troublesome, trial and error prone,
@@ -51,6 +51,14 @@ The original intention for writing this toolbox was movement decoding from invas
51
51
  The application however could be any neural decoding and analysis problem.
52
52
  *py_neuromodulation* offers wrappers around common practice machine learning methods for efficient analysis.
53
53
 
54
+
55
+ Journal of Open Source Software publication
56
+ -------------------------------------------
57
+
58
+ .. image:: https://joss.theoj.org/papers/10.21105/joss.08258/status.svg
59
+ :target: https://doi.org/10.21105/joss.08258
60
+
61
+
54
62
  References
55
63
  ----------
56
64
 
@@ -54,10 +54,10 @@ raw_normalization_settings:
54
54
  clip: 3
55
55
 
56
56
  preprocessing_filter:
57
- bandstop_filter: true
58
- lowpass_filter: true
59
- highpass_filter: true
60
- bandpass_filter: true
57
+ bandstop_filter: false
58
+ lowpass_filter: false
59
+ highpass_filter: false
60
+ bandpass_filter: false
61
61
  bandstop_filter_settings: [100, 160] # [low_hz, high_hz]
62
62
  bandpass_filter_settings: [3, 200] # [hz, _hz]
63
63
  lowpass_filter_cutoff_hz: 200
@@ -245,3 +245,4 @@ bispectrum_settings:
245
245
  mean: true
246
246
  sum: true
247
247
  var: true
248
+
@@ -87,17 +87,21 @@ class FooofAnalyzer(NMFeature):
87
87
 
88
88
  spectra = np.abs(rfft(data[:, -self.num_samples :])) # type: ignore
89
89
 
90
- self.fm.fit(self.f_vec, spectra, self.settings.freq_range_hz)
90
+ try:
91
+ self.fm.fit(self.f_vec, spectra, self.settings.freq_range_hz)
92
+ except:
93
+ failed_fits = list(range(len(self.ch_names)))
91
94
 
92
95
  if not self.fm.has_model or self.fm.null_inds_ is None:
93
- raise RuntimeError("FOOOF failed to fit model to data.")
94
-
95
- failed_fits: list[int] = self.fm.null_inds_
96
+ failed_fits = list(range(len(self.ch_names)))
97
+ else:
98
+ failed_fits: list[int] = self.fm.null_inds_
96
99
 
97
100
  feature_results = {}
98
101
  for ch_idx, ch_name in enumerate(self.ch_names):
99
102
  FIT_PASSED = ch_idx not in failed_fits
100
- exp = self.fm.get_params("aperiodic_params", "exponent")[ch_idx]
103
+ if FIT_PASSED:
104
+ exp = self.fm.get_params("aperiodic_params", "exponent")[ch_idx]
101
105
 
102
106
  for feat in self.settings.aperiodic.get_enabled():
103
107
  f_name = f"{ch_name}_fooof_a_{self.feat_name_map[feat]}"
@@ -85,16 +85,16 @@ class SharpwaveSettings(NMBaseModel):
85
85
  self.estimator[est] = []
86
86
 
87
87
  @model_validator(mode="after")
88
- def test_settings(cls, settings):
88
+ def test_settings(self):
89
89
  # check if all features are also enabled via an estimator
90
- estimator_list = [est for list_ in settings.estimator.values() for est in list_]
90
+ estimator_list = [est for list_ in self.estimator.values() for est in list_]
91
91
 
92
- for used_feature in settings.sharpwave_features.get_enabled():
92
+ for used_feature in self.sharpwave_features.get_enabled():
93
93
  assert (
94
94
  used_feature in estimator_list
95
95
  ), f"Add estimator key for {used_feature}"
96
96
 
97
- return settings
97
+ return self
98
98
 
99
99
 
100
100
  class SharpwaveAnalyzer(NMFeature):
@@ -151,7 +151,9 @@ class SharpwaveAnalyzer(NMFeature):
151
151
  self.filters = np.vstack([f for _, f in self.list_filter])
152
152
  self.filters = np.tile(self.filters[None, :, :], (len(self.ch_names), 1, 1))
153
153
  else:
154
- self.filters = [np.tile(f, (len(self.ch_names), 1)) for _, f in self.list_filter]
154
+ self.filters = [
155
+ np.tile(f, (len(self.ch_names), 1)) for _, f in self.list_filter
156
+ ]
155
157
 
156
158
  self.used_features = self.sw_settings.sharpwave_features.get_enabled()
157
159
 
@@ -282,7 +284,9 @@ class SharpwaveAnalyzer(NMFeature):
282
284
  if feature_name == "num_peaks":
283
285
  key_name = f"{ch_name}_Sharpwave_{feature_name}_{filter_name}"
284
286
  if len(waveform_results[feature_name]) == 1:
285
- dict_ch_features[key_name][key_name_pt] = waveform_results[feature_name][0]
287
+ dict_ch_features[key_name][key_name_pt] = waveform_results[
288
+ feature_name
289
+ ][0]
286
290
  continue
287
291
  else:
288
292
  raise ValueError("num_peaks should be a list with length 1")
@@ -317,8 +321,12 @@ class SharpwaveAnalyzer(NMFeature):
317
321
  for ch_name in self.ch_names:
318
322
  for filter_name in self.filter_names:
319
323
  key_name = f"{ch_name}_Sharpwave_num_peaks_{filter_name}"
320
- feature_results[key_name] = np_mean([dict_ch_features[key_name]["Peak"],
321
- dict_ch_features[key_name]["Trough"]])
324
+ feature_results[key_name] = np_mean(
325
+ [
326
+ dict_ch_features[key_name]["Peak"],
327
+ dict_ch_features[key_name]["Trough"],
328
+ ]
329
+ )
322
330
  else:
323
331
  # otherwise, save all write all "flattened" key value pairs in feature_results
324
332
  for key, subdict in dict_ch_features.items():
@@ -55,7 +55,7 @@ class ReReferencer(NMPreprocessor):
55
55
  # if ind not in channels_used:
56
56
  # continue
57
57
  ref = refs[ind]
58
- if ref.lower() == "none" or pd.isnull(ref):
58
+ if ref.lower() == "none" or pd.isnull(ref) or channels["status"][ind] != "good":
59
59
  ref_idx = None
60
60
  continue
61
61
  if ref.lower() == "average":
@@ -78,7 +78,12 @@ class ReReferencer(NMPreprocessor):
78
78
  )
79
79
  ref_idx.append(ch_names.index(ref_chan))
80
80
  ref_matrix[ind, ref_idx] = -1 / len(ref_idx)
81
+
81
82
  self.ref_matrix = ref_matrix
83
+
84
+ # only index good channels
85
+ good_idxs = np.where(channels["status"] == "good")[0]
86
+ self.ref_matrix = self.ref_matrix[good_idxs, :][:, good_idxs]
82
87
 
83
88
  def process(self, data: np.ndarray) -> np.ndarray:
84
89
  """Rereference data according to the initialized ReReferencer class.
@@ -143,12 +143,17 @@ class DataProcessor:
143
143
  ) -> tuple[list[str], list[str], list[int], np.ndarray]:
144
144
  """Get used feature and label info from channels"""
145
145
  channels = self.channels
146
- ch_names_used = channels[channels["used"] == 1]["new_name"].tolist()
147
- ch_types_used = channels[channels["used"] == 1]["type"].tolist()
146
+ ch_names_used = channels.query("used == 1 and status == 'good'")["new_name"].tolist()
147
+ ch_types_used = channels.query("used == 1 and status == 'good'")["type"].tolist()
148
148
 
149
149
  # used channels for feature estimation
150
150
  feature_idx = np.where(channels["used"] & ~channels["target"])[0].tolist()
151
151
 
152
+ # remove the idxs of status == "bad"
153
+ feature_idx = [
154
+ idx for idx in feature_idx if channels.loc[idx, "status"] == "good"
155
+ ]
156
+
152
157
  # If multiple targets exist, select only the first
153
158
  label_idx = np.where(channels["target"] == 1)[0]
154
159
 
@@ -46,6 +46,7 @@ def set_channels(
46
46
  For this, the channel names must contain the substring "_L_" and/or
47
47
  "_R_" (lower or upper case). CAVE: Adjacent channels will be
48
48
  determined using the sort() function.
49
+ Re-reference can be also "average" for common-average-referencing
49
50
  bads : str | list of str, default: None
50
51
  channels that should be marked as bad and not be used for
51
52
  average re-referencing etc.
@@ -127,9 +128,12 @@ def set_channels(
127
128
  if isinstance(reference, str):
128
129
  if reference.lower() == "default":
129
130
  df = _get_default_references(df=df, ch_names=ch_names, ch_types=ch_types)
131
+ elif reference.lower() == "average":
132
+ df["rereference"] = ["average" if df["used"][ch_idx] == 1 else "None"
133
+ for ch_idx in range(len(ch_names))]
130
134
  else:
131
135
  raise ValueError(
132
- "`reference` must be either `default`, `None` or "
136
+ "`reference` must be either `default`, `None`, `average` or "
133
137
  "an iterable of new reference channel names. "
134
138
  f"Got: {reference}."
135
139
  )
@@ -5,10 +5,11 @@ from typing import (
5
5
  get_args,
6
6
  get_type_hints,
7
7
  Literal,
8
+ Unpack,
9
+ TypedDict,
8
10
  cast,
9
11
  Sequence,
10
12
  )
11
- from typing_extensions import Unpack, TypedDict
12
13
  from pydantic import BaseModel, GetCoreSchemaHandler, ConfigDict
13
14
 
14
15
  from pydantic_core import (
@@ -118,23 +119,13 @@ class _NMExtraFieldInputs(TypedDict, total=False):
118
119
  custom_metadata: dict[str, Any]
119
120
 
120
121
 
121
- class _NMFieldInfoInputs(_FieldInfoInputs, _NMExtraFieldInputs, total=False):
122
- """Combine pydantic FieldInfo inputs with PyNM additional inputs"""
123
-
124
- pass
125
-
126
-
127
- class _NMFromFieldInfoInputs(_FromFieldInfoInputs, _NMExtraFieldInputs, total=False):
128
- """Combine pydantic FieldInfo.from_field inputs with PyNM additional inputs"""
129
-
130
- pass
131
-
132
-
133
122
  class NMFieldInfo(FieldInfo):
134
123
  # Add default values for any other custom fields here
135
124
  _default_values = {}
136
125
 
137
- def __init__(self, **kwargs: Unpack[_NMFieldInfoInputs]) -> None:
126
+ def __init__(
127
+ self, **kwargs: Unpack[_FieldInfoInputs | _NMExtraFieldInputs]
128
+ ) -> None:
138
129
  self.sequence: bool = kwargs.pop("sequence", False) # type: ignore
139
130
  self.custom_metadata: dict[str, Any] = kwargs.pop("custom_metadata", {})
140
131
  super().__init__(**kwargs)
@@ -162,7 +153,7 @@ class NMFieldInfo(FieldInfo):
162
153
  @staticmethod
163
154
  def from_field(
164
155
  default: Any = PydanticUndefined,
165
- **kwargs: Unpack[_NMFromFieldInfoInputs],
156
+ **kwargs: Unpack[_FromFieldInfoInputs | _NMExtraFieldInputs],
166
157
  ) -> "NMFieldInfo":
167
158
  if "annotation" in kwargs:
168
159
  raise TypeError('"annotation" is not permitted as a Field keyword argument')
@@ -178,7 +169,7 @@ class NMFieldInfo(FieldInfo):
178
169
 
179
170
  def NMField(
180
171
  default: Any = PydanticUndefined,
181
- **kwargs: Unpack[_NMFromFieldInfoInputs],
172
+ **kwargs: Unpack[_FromFieldInfoInputs | _NMExtraFieldInputs],
182
173
  ) -> Any:
183
174
  return NMFieldInfo.from_field(default=default, **kwargs)
184
175
 
@@ -197,7 +188,7 @@ class NMBaseModel(BaseModel):
197
188
  super().__init__(*args, **kwargs)
198
189
  return
199
190
 
200
- field_names = list(self.model_fields.keys())
191
+ field_names = list(self.__class__.model_fields.keys())
201
192
  # If we have more positional args than fields, that's an error
202
193
  if len(args) > len(field_names):
203
194
  raise ValueError(
@@ -238,7 +229,7 @@ class NMBaseModel(BaseModel):
238
229
 
239
230
  @property
240
231
  def fields(self) -> dict[str, FieldInfo | NMFieldInfo]:
241
- return self.model_fields # type: ignore
232
+ return self.__class__.model_fields # type: ignore
242
233
 
243
234
  def serialize_with_metadata(self):
244
235
  result: dict[str, Any] = {"__field_type__": self.__class__.__name__}
@@ -135,17 +135,17 @@ class BoolSelector(NMBaseModel):
135
135
  def get_enabled(self):
136
136
  return [
137
137
  f
138
- for f in self.model_fields.keys()
138
+ for f in self.__class__.model_fields.keys()
139
139
  if (isinstance(self[f], bool) and self[f])
140
140
  ]
141
141
 
142
142
  def enable_all(self):
143
- for f in self.model_fields.keys():
143
+ for f in self.__class__.model_fields.keys():
144
144
  if isinstance(self[f], bool):
145
145
  self[f] = True
146
146
 
147
147
  def disable_all(self):
148
- for f in self.model_fields.keys():
148
+ for f in self.__class__.model_fields.keys():
149
149
  if isinstance(self[f], bool):
150
150
  self[f] = False
151
151
 
@@ -4,7 +4,7 @@ requires = ["hatchling"]
4
4
 
5
5
  [project]
6
6
  name = "py_neuromodulation"
7
- version = "0.1.4"
7
+ version = "0.1.7"
8
8
  authors = [{ name = "Timon Merk", email = "timon.merk@charite.de" }]
9
9
  classifiers = [
10
10
  "Development Status :: 2 - Pre-Alpha",
@@ -28,7 +28,67 @@ def setup_default_data():
28
28
 
29
29
  @pytest.fixture
30
30
  def setup_default_stream_fast_compute() -> tuple[np.ndarray, nm.Stream]:
31
- """This test function sets a data batch and automatic initialized M1 dataframe
31
+ """This test function sets a data batch and automatic initialized M1 dataframe.
32
+ Only fft features is enabled.
33
+
34
+ Args:
35
+ PATH_PYNEUROMODULATION (string): Path to py_neuromodulation repository
36
+
37
+ Returns:
38
+ ieeg_batch (np.ndarray): (channels, samples)
39
+ df_M1 (pd Dataframe): auto intialized table for rereferencing
40
+ settings_wrapper (settings.py): settings.json
41
+ fs (float): example sampling frequency
42
+ """
43
+
44
+ (
45
+ RUN_NAME,
46
+ PATH_RUN,
47
+ PATH_BIDS,
48
+ PATH_OUT,
49
+ datatype,
50
+ ) = nm.io.get_paths_example_data()
51
+
52
+ (
53
+ raw,
54
+ data,
55
+ sfreq,
56
+ line_noise,
57
+ coord_list,
58
+ coord_names,
59
+ ) = nm.io.read_BIDS_data(PATH_RUN=PATH_RUN)
60
+
61
+ channels = nm.utils.set_channels(
62
+ ch_names=raw.ch_names,
63
+ ch_types=raw.get_channel_types(),
64
+ reference="default",
65
+ bads=raw.info["bads"],
66
+ new_names="default",
67
+ used_types=("ecog", "dbs", "seeg"),
68
+ target_keywords=("MOV_RIGHT_CLEAN",),
69
+ )
70
+
71
+ settings = nm.NMSettings.get_default()
72
+ settings.reset()
73
+ settings.features.fft = True
74
+
75
+ stream = nm.Stream(
76
+ settings=settings,
77
+ channels=channels,
78
+ path_grids=None,
79
+ verbose=True,
80
+ sfreq=sfreq,
81
+ line_noise=line_noise,
82
+ coord_list=coord_list,
83
+ coord_names=coord_names,
84
+ )
85
+
86
+ return data, stream
87
+
88
+ @pytest.fixture
89
+ def setup_default_stream_fooof() -> tuple[np.ndarray, nm.Stream]:
90
+ """This test function sets a data batch and automatic initialized M1 dataframe.
91
+ Only fooof feature is enabled.
32
92
 
33
93
  Args:
34
94
  PATH_PYNEUROMODULATION (string): Path to py_neuromodulation repository
@@ -25,20 +25,23 @@ def test_all_features_random_array():
25
25
  arr, out_dir="./test_data", experiment_name="test_all_features_random_array"
26
26
  )
27
27
 
28
- assert df.shape[0] != 0 # terrible test
28
+ assert df.shape[0] != 0 # check if not exception was raised
29
29
 
30
30
 
31
31
  def test_all_features_zero_array():
32
32
  arr = np.zeros([2, 2000])
33
33
 
34
34
  stream = get_example_stream(arr)
35
- stream.settings.features.fooof = False # Can't use fooof with 0s (log(0) undefined)
35
+ #stream.settings.features.fooof = False # Can't use fooof with 0s (log(0) undefined)
36
36
 
37
37
  df = stream.run(
38
38
  arr, out_dir="./test_data", experiment_name="test_all_features_zero_array"
39
39
  )
40
40
 
41
- assert df.shape[0] != 0 # terrible test
41
+ # the issue is here that some features, like bandpass activity will be very high
42
+ # negative values,
43
+ # TODO: think about how to check that
44
+ assert df.shape[0] != 0 # check if not exception was raised
42
45
 
43
46
 
44
47
  def test_all_features_NaN_array():
@@ -46,10 +49,10 @@ def test_all_features_NaN_array():
46
49
  arr[:] = np.nan
47
50
 
48
51
  stream = get_example_stream(arr)
49
- stream.settings.features.fooof = False # Can't use fooof nan values
52
+ #stream.settings.features.fooof = False # Can't use fooof nan values
50
53
 
51
54
  df = stream.run(
52
55
  arr, out_dir="./test_data", experiment_name="test_all_features_NaN_array"
53
56
  )
54
57
 
55
- assert df.shape[0] != 0 # terrible test
58
+ assert df.shape[0] != 0 # check if not exception was raised
@@ -0,0 +1,22 @@
1
+ # create a test with two channels, one bad, check then if
2
+ # features are only calculated for the good channel
3
+
4
+ import numpy as np
5
+ import pandas as pd
6
+ import pytest
7
+ from numpy.testing import assert_allclose
8
+ import py_neuromodulation as nm
9
+
10
+ def test_bad_channels_feature_extraction(setup_default_stream_fast_compute):
11
+ default_stream: tuple[np.ndarray, nm.Stream] = setup_default_stream_fast_compute
12
+ data, stream = default_stream
13
+
14
+ # make ecog channels status bad, else good
15
+ stream.channels["status"] = ["bad" if ch == "ecog" else "good" for ch in stream.channels["type"]]
16
+
17
+ features = stream.run(data, out_dir="./test_data",
18
+ experiment_name="test_bad_channels_feature_extraction")
19
+
20
+ # check if features were only computed for channels starting with LFP, no ECoG
21
+ assert all([f.startswith("LFP") for f in list(features.columns) if f != "time"]), \
22
+ "Features were computed for non-DBS channels, which should not happen."
@@ -0,0 +1,52 @@
1
+ import py_neuromodulation as nm
2
+ import numpy as np
3
+
4
+
5
+ def test_fooof_features(setup_default_stream_fooof):
6
+ default_stream: tuple[np.ndarray, nm.Stream] = setup_default_stream_fooof
7
+ data, stream = default_stream
8
+
9
+ generator = nm.stream.RawDataGenerator(
10
+ data,
11
+ stream.sfreq,
12
+ stream.settings.sampling_rate_features_hz,
13
+ stream.settings.segment_length_features_ms,
14
+ )
15
+
16
+ _, data_batch = next(generator, None)
17
+ feature_series = stream.data_processor.process(data_batch)
18
+ # since the settings can define searching for "max_n_peaks" peaks
19
+ # there can be None's in the feature_series
20
+ # with a non successful fit, aperiodic features can also be None
21
+ assert feature_series is not None
22
+
23
+ def test_fooof_zero_values(setup_default_stream_fooof):
24
+ default_stream: tuple[np.ndarray, nm.Stream] = setup_default_stream_fooof
25
+ data, stream = default_stream
26
+ data_zeros = np.zeros_like(data)
27
+
28
+ generator = nm.stream.RawDataGenerator(
29
+ data_zeros,
30
+ stream.sfreq,
31
+ stream.settings.sampling_rate_features_hz,
32
+ stream.settings.segment_length_features_ms,
33
+ )
34
+
35
+ _, data_batch = next(generator, None)
36
+ feature_series = stream.data_processor.process(data_batch)
37
+
38
+ assert all(value is None for value in feature_series.values()), \
39
+ "Expected all feature values to be None for zero input data."
40
+
41
+ def test_fooof_zero_values_multiple_iterations(setup_default_stream_fooof):
42
+ default_stream: tuple[np.ndarray, nm.Stream] = setup_default_stream_fooof
43
+ data, stream = default_stream
44
+ stream.settings.postprocessing["feature_normalization"] = True
45
+ data_zeros = np.zeros_like(data)
46
+
47
+ features = stream.run(data_zeros, out_dir="./test_data",
48
+ experiment_name="test_fooof_zero_values_multiple_iterations")
49
+
50
+ # convert all None values to zero, and check sum of all features except time column
51
+ assert np.nan_to_num(features.iloc[:, :-1]).sum().sum() == 0, \
52
+ "Expected all feature values to be zero for zero input data."
@@ -0,0 +1,68 @@
1
+ import numpy as np
2
+
3
+ import py_neuromodulation as nm
4
+
5
+
6
+ def test_stream_with_none_data():
7
+ """Test if passing None as the data to a Stream object results in None features."""
8
+
9
+ fs = 1000
10
+ data = np.random.random([2, 2000])
11
+ data[0, :] = None
12
+
13
+ stream = nm.Stream(sfreq=fs, data=data)
14
+
15
+ features = stream.run(
16
+ data, out_dir="./test_data", experiment_name="test_stream_with_none_data"
17
+ )
18
+
19
+ # assert if all features if name ch0 are None
20
+ assert len(
21
+ [f for f in features.columns if "ch0" in f and features[f].isna().all()]
22
+ ) == len([f for f in features if "ch0" in f])
23
+
24
+ # and check if all features of the second channel are not None
25
+ assert len(
26
+ [f for f in features.columns if "ch1" in f and features[f].notna().all()]
27
+ ) == len([f for f in features if "ch1" in f])
28
+
29
+ def test_stream_with_nan_and_non_nan_data_in_one_channel():
30
+ """Test if passing a mix of NaN and non-NaN data to a Stream object results in correct features."""
31
+
32
+ fs = 1000
33
+ data = np.random.random([2, 3000])
34
+ nan_start = 1000
35
+ nan_end = 2000
36
+ data[0, nan_start:nan_end] = None # Introduce NaNs in the first channel
37
+
38
+ stream = nm.Stream(sfreq=fs, data=data)
39
+
40
+ features = stream.run(
41
+ data, out_dir="./test_data", experiment_name="test_stream_with_nan_and_non_nan_data"
42
+ )
43
+
44
+ idx_nan_features = (features["time"] > nan_start) & (features["time"] < nan_end + stream.settings.segment_length_features_ms)
45
+ idx_not_nan_features = ~idx_nan_features
46
+
47
+ features_not_time = features.drop(columns=["time"])
48
+ features_ch0 = features_not_time.filter(like="ch0")
49
+
50
+ assert features_ch0[idx_nan_features].isna().all().all(), \
51
+ "Expected all features to be NaN in the time range with NaN data."
52
+ assert features_ch0[idx_not_nan_features].notna().all().all(), \
53
+ "Expected all features to be non-NaN in the time range with non-NaN data."
54
+
55
+ def test_stream_with_only_nan_data():
56
+ """Test if passing only NaN data to a Stream object results in all features being None."""
57
+
58
+ fs = 1000
59
+ data = np.random.random([2, 2000])
60
+ data[:] = None # Set all data to NaN
61
+
62
+ stream = nm.Stream(sfreq=fs, data=data)
63
+
64
+ features = stream.run(
65
+ data, out_dir="./test_data", experiment_name="test_stream_with_only_nan_data"
66
+ )
67
+
68
+ assert features.filter(like="ch").isna().all().all(), "Expected all features to be NaN."