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.
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/.github/workflows/tests.yml +7 -11
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/PKG-INFO +10 -1
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/README.rst +9 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/index.rst +8 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/default_settings.yaml +5 -4
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/fooof.py +9 -5
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/sharpwaves.py +16 -8
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/rereference.py +6 -1
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/data_processor.py +7 -2
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/channels.py +5 -1
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/pydantic_extensions.py +9 -18
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/types.py +3 -3
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/pyproject.toml +1 -1
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/conftest.py +61 -1
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_all_features.py +8 -5
- py_neuromodulation-0.1.7/tests/test_bad_channels.py +22 -0
- py_neuromodulation-0.1.7/tests/test_fooof.py +52 -0
- py_neuromodulation-0.1.7/tests/test_nan_values.py +68 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_rereference.py +49 -0
- py_neuromodulation-0.1.4/tests/test_fooof.py +0 -21
- py_neuromodulation-0.1.4/tests/test_nan_values.py +0 -27
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/.gitattributes +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/.github/workflows/docs_pages.yml +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/.github/workflows/python-publish.yml +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/.gitignore +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/LICENSE +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/Makefile +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/make.bat +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/RMAP.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/CEBRA_embedding.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/RMAP_figure.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/channelselection.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/css/RMAP_figure.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/css/project-template.css +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/decoding.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/fileselection.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/graphs.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/lslselection.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/pydantic.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/settings.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_static/sourceselection.png +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_templates/custom-class-template.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/_templates/custom-module-template.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/api_documentation.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/artifacts.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/bandpower.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/bispectra.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/bursts.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/channels.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/coherence.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/conf.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/contributing.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/database.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/decode.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/feature_reader.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/fooof.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/generator.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/gui.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/hjorth.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/installation.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/io.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/linelength.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/logging.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/mne_connectivity.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/mne_filter.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/mnelsl_player.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/mnelsl_stream.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/nolds.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/normalization.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/notch_filter.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/oscillatory.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/plots.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/projection.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/rereference.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/resample.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/settings.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/sharpwaves.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/stats.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/stream.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/types.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/docs/source/usage.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/README.rst +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/example_cebra_decoding.html +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/example_cebra_decoding.ipynb +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/example_rmap.ipynb +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_2_example_add_feature.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_3_example_sharpwave_analysis.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_4_example_gridPointProjection.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_5_example_rmap_computing.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_6_real_time_demo.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_7_lsl_example.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/examples/plot_8_cebra_example.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/.eslintrc.cjs +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/.gitattributes +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/.gitignore +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/bun.lock +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/eslint.config.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/index.html +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/jsconfig.json +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/package.json +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/public/charite.svg +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/scripts/wdyr.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/App.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/assets/fonts/figtree/Figtree-Italic-VariableFont_wght.ttf +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/assets/fonts/figtree/Figtree-VariableFont_wght.ttf +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/assets/fonts/figtree/OFL.txt +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/assets/fonts/figtree/README.txt +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/AppBar/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/AppBar.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/AppInfoModal.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/BandPowerGraph.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/CollapsibleBox.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/DecodingGraph.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Drawer/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/FileBrowser/FileBrowser.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/FileBrowser/QuickAccess.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Graph/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/HeatmapGraph.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/PSDGraph.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/RawDataGraph.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Settings/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Sidebar/Sidebar.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Sidebar/Sidebar.module.css +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Sidebar/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/ResizeHandle.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/ResizeHandle.module.css +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/SocketStatus.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/StatusBar.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/StatusBar.module.css +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/WebviewStatus.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/StatusBar/resize_handle.svg +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/Switch/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/TitledBox.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/WindowButtons.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/components/utils.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/main.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Channels/Channels.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Dashboard.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Settings/Settings.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Settings/components/FrequencyRange.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Settings/components/OrderableLiteralListField.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/Settings/components/PrimitiveComponents.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/SourceSelection/DecodingModel.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/SourceSelection/FileSelector.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/SourceSelection/SourceSelection.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/SourceSelection/StreamParameters.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/SourceSelection/StreamSelector.jsx +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/pages/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/appInfoStore.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/createStore.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/dragAndDropStore.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/sessionStore.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/settingsStore.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/socketStore.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/uiStore.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/stores/webviewStore.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/styles/reset.css +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/theme.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/DataBuffer.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/FileInfo.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/FileManager.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/debounced_sync.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/index.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/src/utils/utils.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/gui_dev/vite.config.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/Automated Anatomical Labeling 3 (Rolls 2020).nii +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/_get_grid_hull.m +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/_get_grid_whole_brain.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/_helper_write_connectome.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/mni_coords_cortical_surface.mat +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/mni_coords_whole_brain.mat +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/rmap_func_all.nii +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/ConnectivityDecoding/rmap_struc.nii +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/__init__.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/RMAP.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/__init__.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/decode.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/feature_reader.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/plots.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/analysis/stats.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/README +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/dataset_description.json +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/participants.json +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/data/participants.tsv +0 -0
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/__init__.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/bandpower.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/bispectra.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/bursts.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/coherence.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/feature_processor.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/hjorth_raw.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/linelength.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/mne_connectivity.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/nolds.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/oscillatory.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/filter/__init__.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/filter/kalman_filter.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/filter/kalman_filter_external.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/filter/mne_filter.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/filter/notch_filter.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/grid_cortex.tsv +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/grid_subcortex.tsv +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/__init__.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_backend.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_manager.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_pynm.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_socket.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_utils.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/backend/app_window.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/frontend/assets/Figtree-VariableFont_wght-CkXbWBDP.ttf +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/frontend/assets/index-B53U6dwc.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/frontend/assets/plotly-DTCwMlpS.js +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/frontend/charite.svg +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/frontend/index.html +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/gui/window_api.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/libpugixml.so.1.12 +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/bionic_amd64/liblsl.1.16.2.so +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/bookworm_amd64/liblsl.1.16.2.so +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/focal_amd46/liblsl.1.16.2.so +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/jammy_amd64/liblsl.1.16.2.so +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/jammy_x86/liblsl.1.16.2.so +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/linux/noble_amd64/liblsl.1.16.2.so +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/macos/amd64/liblsl.1.16.2.dylib +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/macos/arm64/liblsl.1.16.0.dylib +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/windows/amd64/liblsl.1.16.2.dll +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/liblsl/windows/x86/liblsl.1.16.2.dll +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/lsl_api.cfg +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/plots/STN_surf.mat +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/plots/Vertices.mat +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/plots/faces.mat +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/plots/grid.mat +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/__init__.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/artifacts.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/data_preprocessor.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/filter_preprocessing.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/normalization.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/projection.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/resample.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/run_gui.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/__init__.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/backend_interface.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/generator.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/mnelsl_player.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/mnelsl_stream.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/settings.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/stream.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/__init__.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/database.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/file_writer.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/io.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/keyboard.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/logging.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/utils/perf.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation.code-workspace +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/__init__.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_all_examples.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_bispectra.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_bursts.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_coherence.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_database.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_feature_sampling_rates.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_initalization_offline_stream.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_lsl_stream.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_mne_connectivity.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_nm_filter.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_nm_resample.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_normalization_settings.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_notch_filter.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_osc_features.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_preprocessing_filter.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_sampling.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_settings_change_after_init.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_sharpwave.py +0 -0
- {py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/tests/test_target_channel_add.py +0 -0
- {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@
|
|
46
|
+
uses: astral-sh/setup-uv@v7
|
|
47
47
|
with:
|
|
48
|
-
version: "
|
|
49
|
-
enable-cache:
|
|
48
|
+
python-version: "${{ matrix.python }}"
|
|
49
|
+
enable-cache: auto
|
|
50
|
+
activate-environment: "true"
|
|
50
51
|
cache-dependency-glob: "**/pyproject.toml"
|
|
51
|
-
- name: Install
|
|
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.
|
|
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
|
|
{py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/default_settings.yaml
RENAMED
|
@@ -54,10 +54,10 @@ raw_normalization_settings:
|
|
|
54
54
|
clip: 3
|
|
55
55
|
|
|
56
56
|
preprocessing_filter:
|
|
57
|
-
bandstop_filter:
|
|
58
|
-
lowpass_filter:
|
|
59
|
-
highpass_filter:
|
|
60
|
-
bandpass_filter:
|
|
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
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
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]}"
|
{py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/features/sharpwaves.py
RENAMED
|
@@ -85,16 +85,16 @@ class SharpwaveSettings(NMBaseModel):
|
|
|
85
85
|
self.estimator[est] = []
|
|
86
86
|
|
|
87
87
|
@model_validator(mode="after")
|
|
88
|
-
def test_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
|
|
90
|
+
estimator_list = [est for list_ in self.estimator.values() for est in list_]
|
|
91
91
|
|
|
92
|
-
for used_feature in
|
|
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
|
|
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 = [
|
|
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[
|
|
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(
|
|
321
|
-
|
|
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():
|
{py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/processing/rereference.py
RENAMED
|
@@ -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.
|
{py_neuromodulation-0.1.4 → py_neuromodulation-0.1.7}/py_neuromodulation/stream/data_processor.py
RENAMED
|
@@ -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
|
|
147
|
-
ch_types_used = channels
|
|
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__(
|
|
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[
|
|
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[
|
|
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
|
|
|
@@ -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 #
|
|
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
|
-
|
|
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 #
|
|
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."
|