braindecode 1.3.2.dev173417708__tar.gz → 1.3.2.dev173801889__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.
- {braindecode-1.3.2.dev173417708/braindecode.egg-info → braindecode-1.3.2.dev173801889}/PKG-INFO +1 -1
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/base.py +150 -2
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bids/hub.py +161 -76
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bids/hub_io.py +29 -6
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datautil/hub_formats.py +16 -3
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/__init__.py +2 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/base.py +28 -17
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/bendr.py +69 -19
- braindecode-1.3.2.dev173801889/braindecode/models/dgcnn.py +500 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eegsym.py +1 -1
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/sstdpn.py +1 -1
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/summary.csv +1 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/util.py +13 -11
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/attention.py +2 -1
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/preprocessing/mne_preprocess.py +2 -1
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/preprocessing/preprocess.py +62 -32
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/util.py +34 -4
- braindecode-1.3.2.dev173801889/braindecode/version.py +1 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889/braindecode.egg-info}/PKG-INFO +1 -1
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode.egg-info/SOURCES.txt +1 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/api.rst +11 -9
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/conf.py +18 -6
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/categorization/gnn.rst +9 -1
- braindecode-1.3.2.dev173801889/docs/models/categorization/spd.rst +103 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/models_categorization.rst +59 -60
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/whats_new.rst +37 -4
- braindecode-1.3.2.dev173417708/braindecode/version.py +0 -1
- braindecode-1.3.2.dev173417708/docs/models/categorization/spd.rst +0 -35
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/LICENSE.txt +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/MANIFEST.in +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/NOTICE.txt +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/README.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/augmentation/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/augmentation/base.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/augmentation/functional.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/augmentation/transforms.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/classifier.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bbci.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bcicomp.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bids/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bids/datasets.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bids/format.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bids/hub_format.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bids/hub_validation.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bids/iterable.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/chb_mit.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/mne.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/moabb.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/nmt.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/registry.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/siena.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/sleep_physionet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/tuh.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/utils.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/xy.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datautil/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datautil/channel_utils.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datautil/serialization.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datautil/util.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/eegneuralnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/functional/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/functional/functions.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/functional/initialization.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/atcnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/attentionbasenet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/attn_sleep.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/biot.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/brainmodule.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/cbramod.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/config.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/contrawr.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/ctnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/deep4.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/deepsleepnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eegconformer.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eeginception_erp.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eeginception_mi.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eegitnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eegminer.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eegnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eegnex.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eegpt.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eegsimpleconv.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/eegtcnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/fbcnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/fblightconvnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/fbmsnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/hybrid.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/ifnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/labram.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/luna.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/medformer.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/msvtnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/patchedtransformer.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/reve.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/sccnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/shallow_fbcsp.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/signal_jepa.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/sinc_shallow.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/sparcnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/syncnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/tcn.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/tidnet.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/tsinception.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/models/usleep.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/activation.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/blocks.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/convolution.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/filter.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/layers.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/linear.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/parametrization.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/stats.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/util.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/modules/wrapper.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/preprocessing/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/preprocessing/util.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/preprocessing/windowers.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/regressor.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/samplers/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/samplers/base.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/samplers/ssl.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/training/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/training/callbacks.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/training/losses.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/training/scoring.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/visualization/__init__.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/visualization/confusion_matrices.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/visualization/gradients.py +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode.egg-info/dependency_links.txt +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode.egg-info/requires.txt +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode.egg-info/top_level.txt +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/Makefile +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/_templates/autosummary/class.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/_templates/autosummary/function.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/cite.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/help.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/index.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/install/install.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/install/install_pip.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/install/install_source.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/categorization/attention.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/categorization/channel.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/categorization/convolution.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/categorization/filterbank.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/categorization/interpretable.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/categorization/lbm.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/categorization/recurrent.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/models.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/models_table.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/models/models_visualization.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/docs/sg_execution_times.rst +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/pyproject.toml +0 -0
- {braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/setup.cfg +0 -0
{braindecode-1.3.2.dev173417708/braindecode.egg-info → braindecode-1.3.2.dev173801889}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: braindecode
|
|
3
|
-
Version: 1.3.2.
|
|
3
|
+
Version: 1.3.2.dev173801889
|
|
4
4
|
Summary: Deep learning software to decode EEG, ECG or MEG signals
|
|
5
5
|
Author-email: Robin Tibor Schirrmeister <robintibor@gmail.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Alexandre Gramfort <agramfort@meta.com>
|
|
6
6
|
Maintainer-email: Alexandre Gramfort <agramfort@meta.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Robin Tibor Schirrmeister <robintibor@gmail.com>
|
{braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/base.py
RENAMED
|
@@ -579,6 +579,89 @@ class EEGWindowsDataset(RecordDataset):
|
|
|
579
579
|
self.metadata,
|
|
580
580
|
)
|
|
581
581
|
|
|
582
|
+
def to_epochs_dataset(self) -> WindowsDataset:
|
|
583
|
+
"""Converts this :class:`EEGWindowsDataset` to :class:`WindowsDataset` with ``mne.Epochs``.
|
|
584
|
+
|
|
585
|
+
In Braindecode, the data can either be stored as ``mne.io.Raw`` (in :class:`EEGWindowsDataset`)
|
|
586
|
+
or as ``mne.Epochs`` (in :class:`WindowsDataset`). This function converts from the first type to the second,
|
|
587
|
+
which can be useful for reducing disk space when you want to save a dataset.
|
|
588
|
+
|
|
589
|
+
Returns
|
|
590
|
+
-------
|
|
591
|
+
WindowsDataset
|
|
592
|
+
A new :class:`WindowsDataset` with ``mne.Epochs``.
|
|
593
|
+
|
|
594
|
+
Raises
|
|
595
|
+
------
|
|
596
|
+
ValueError
|
|
597
|
+
If the dataset is not compatible with conversion. This includes:
|
|
598
|
+
- If targets are not obtained from metadata
|
|
599
|
+
- If windows have inconsistent sizes or there are no windows to convert
|
|
600
|
+
- If raw.first_samp!=0 (not supported for simplicity)
|
|
601
|
+
"""
|
|
602
|
+
# Check the targets:
|
|
603
|
+
if self.targets_from != "metadata":
|
|
604
|
+
raise ValueError(
|
|
605
|
+
"to_epochs_dataset only works if targets are obtained from metadata."
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
# Check and get window sizes:
|
|
609
|
+
i_start_in_trial = self.crop_inds[:, 1]
|
|
610
|
+
i_stop_in_trial = self.crop_inds[:, 2]
|
|
611
|
+
sizes = np.unique(i_stop_in_trial - i_start_in_trial)
|
|
612
|
+
if len(sizes) > 1:
|
|
613
|
+
raise ValueError("Windows have inconsistent sizes.")
|
|
614
|
+
if len(sizes) != 1:
|
|
615
|
+
raise ValueError("No windows to convert.")
|
|
616
|
+
input_window_seconds = (sizes[0] - 1) / self.raw.info["sfreq"]
|
|
617
|
+
|
|
618
|
+
# Check raw.first_samp:
|
|
619
|
+
if self.raw.first_samp != 0:
|
|
620
|
+
raise ValueError(
|
|
621
|
+
f"to_epochs_dataset only works if raw.first_samp is 0, found {self.raw.first_samp=}"
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
# Create events and epochs:
|
|
625
|
+
events = np.zeros((len(self), 3), dtype=int)
|
|
626
|
+
events[:, 0] = i_start_in_trial
|
|
627
|
+
events[:, 2] = 1
|
|
628
|
+
epochs = mne.Epochs(
|
|
629
|
+
raw=self.raw,
|
|
630
|
+
events=events,
|
|
631
|
+
event_id={"window": 1},
|
|
632
|
+
tmin=0,
|
|
633
|
+
tmax=input_window_seconds,
|
|
634
|
+
metadata=self.metadata.copy(),
|
|
635
|
+
baseline=None,
|
|
636
|
+
)
|
|
637
|
+
# we skip dropping bads to be consistent with EEGWindowsDataset:
|
|
638
|
+
epochs._bad_dropped = True
|
|
639
|
+
|
|
640
|
+
# Populate new WindowsDataset:
|
|
641
|
+
windows = WindowsDataset(
|
|
642
|
+
epochs,
|
|
643
|
+
description=self.description,
|
|
644
|
+
transform=self.transform,
|
|
645
|
+
targets_from=self.targets_from,
|
|
646
|
+
last_target_only=self.last_target_only,
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
window_kwargs = list(getattr(self, "window_kwargs", []))
|
|
650
|
+
window_kwargs.append((self.to_epochs_dataset.__name__, {}))
|
|
651
|
+
setattr(windows, "window_kwargs", window_kwargs)
|
|
652
|
+
if hasattr(self, "raw_preproc_kwargs"):
|
|
653
|
+
setattr(
|
|
654
|
+
windows, "raw_preproc_kwargs", list(getattr(self, "raw_preproc_kwargs"))
|
|
655
|
+
)
|
|
656
|
+
if hasattr(self, "window_preproc_kwargs"):
|
|
657
|
+
setattr(
|
|
658
|
+
windows,
|
|
659
|
+
"window_preproc_kwargs",
|
|
660
|
+
list(getattr(self, "window_preproc_kwargs")),
|
|
661
|
+
)
|
|
662
|
+
|
|
663
|
+
return windows
|
|
664
|
+
|
|
582
665
|
|
|
583
666
|
@register_dataset
|
|
584
667
|
class WindowsDataset(RecordDataset):
|
|
@@ -617,6 +700,15 @@ class WindowsDataset(RecordDataset):
|
|
|
617
700
|
last_target_only: bool = True,
|
|
618
701
|
):
|
|
619
702
|
super().__init__(description, transform)
|
|
703
|
+
self._fast_disk = self._can_use_fast_get_epoch_from_raw(windows)
|
|
704
|
+
if not (self._fast_disk or windows.preload):
|
|
705
|
+
warnings.warn(
|
|
706
|
+
"The provided mne.Epochs object does not meet the requirements for "
|
|
707
|
+
"fast epoch access. This may lead to slow data loading from disk. "
|
|
708
|
+
"Consider preloading the epochs or checking the conditions in "
|
|
709
|
+
"WindowsDataset._can_use_fast_get_epoch_from_raw.",
|
|
710
|
+
UserWarning,
|
|
711
|
+
)
|
|
620
712
|
self.windows = windows
|
|
621
713
|
self.last_target_only = last_target_only
|
|
622
714
|
if targets_from not in ("metadata", "channels"):
|
|
@@ -633,6 +725,20 @@ class WindowsDataset(RecordDataset):
|
|
|
633
725
|
self.raw_preproc_kwargs: list[dict[str, Any]] = []
|
|
634
726
|
self.window_preproc_kwargs: list[dict[str, Any]] = []
|
|
635
727
|
|
|
728
|
+
@staticmethod
|
|
729
|
+
def _can_use_fast_get_epoch_from_raw(epochs: mne.BaseEpochs) -> bool:
|
|
730
|
+
"""Check if we can use the fast _get_epoch_from_raw method,
|
|
731
|
+
or if we need to use the slow get_data method."""
|
|
732
|
+
return (
|
|
733
|
+
not epochs.preload
|
|
734
|
+
and epochs._bad_dropped
|
|
735
|
+
and epochs.detrend is None
|
|
736
|
+
and not epochs._do_baseline # baseline is None
|
|
737
|
+
and (epochs._decim == 1)
|
|
738
|
+
and epochs._offset is None
|
|
739
|
+
and epochs._projector is None
|
|
740
|
+
)
|
|
741
|
+
|
|
636
742
|
def __getitem__(self, index: int):
|
|
637
743
|
"""Get a window and its target.
|
|
638
744
|
|
|
@@ -650,7 +756,10 @@ class WindowsDataset(RecordDataset):
|
|
|
650
756
|
np.ndarray
|
|
651
757
|
Crop indices.
|
|
652
758
|
"""
|
|
653
|
-
|
|
759
|
+
if self._fast_disk:
|
|
760
|
+
X = self.windows._get_epoch_from_raw(index).astype("float32")
|
|
761
|
+
else:
|
|
762
|
+
X = self.windows.get_data(item=index)[0].astype("float32")
|
|
654
763
|
if self.transform is not None:
|
|
655
764
|
X = self.transform(X)
|
|
656
765
|
if self.targets_from == "metadata":
|
|
@@ -706,7 +815,9 @@ class BaseConcatDataset(ConcatDataset, HubDatasetMixin, Generic[T]):
|
|
|
706
815
|
|
|
707
816
|
def __init__(
|
|
708
817
|
self,
|
|
709
|
-
list_of_ds:
|
|
818
|
+
list_of_ds: (
|
|
819
|
+
list[T] | list[BaseConcatDataset[T]] | list[T | BaseConcatDataset[T]]
|
|
820
|
+
),
|
|
710
821
|
target_transform: Callable | None = None,
|
|
711
822
|
*,
|
|
712
823
|
lazy: bool = False,
|
|
@@ -1283,3 +1394,40 @@ class BaseConcatDataset(ConcatDataset, HubDatasetMixin, Generic[T]):
|
|
|
1283
1394
|
|
|
1284
1395
|
def _repr_html_(self):
|
|
1285
1396
|
return self._build_repr().to_html()
|
|
1397
|
+
|
|
1398
|
+
def to_epochs_dataset(self) -> BaseConcatDataset[WindowsDataset]:
|
|
1399
|
+
"""Converts this :class:`BaseConcatDataset` such that all datasets are :class:`WindowsDataset` with ``mne.Epochs``.
|
|
1400
|
+
|
|
1401
|
+
In Braindecode, the data can either be stored as ``mne.io.Raw`` (in :class:`EEGWindowsDataset`)
|
|
1402
|
+
or as ``mne.Epochs`` (in :class:`WindowsDataset`). This function converts all the underlying datasets to
|
|
1403
|
+
:class:`WindowsDataset` with ``mne.Epochs``.
|
|
1404
|
+
This can be useful for reducing disk space when you want to save a dataset.
|
|
1405
|
+
|
|
1406
|
+
Returns
|
|
1407
|
+
-------
|
|
1408
|
+
BaseConcatDataset[WindowsDataset]
|
|
1409
|
+
A new :class:`BaseConcatDataset` where all datasets are :class:`WindowsDataset` with ``mne.Epochs``.
|
|
1410
|
+
|
|
1411
|
+
Raises
|
|
1412
|
+
------
|
|
1413
|
+
ValueError
|
|
1414
|
+
If any of the underlying datasets is a :class:`RawDataset` or any other type that is not
|
|
1415
|
+
:class:`EEGWindowsDataset` or :class:`WindowsDataset`, as they cannot be converted to epochs.
|
|
1416
|
+
"""
|
|
1417
|
+
datasets = self.datasets
|
|
1418
|
+
if not all(
|
|
1419
|
+
isinstance(ds, (EEGWindowsDataset, WindowsDataset)) for ds in datasets
|
|
1420
|
+
):
|
|
1421
|
+
raise ValueError(
|
|
1422
|
+
"All datasets must be EEGWindowsDataset or WindowsDataset to convert to WindowsDataset."
|
|
1423
|
+
)
|
|
1424
|
+
new_datasets: list[WindowsDataset] = []
|
|
1425
|
+
for ds in datasets:
|
|
1426
|
+
if isinstance(ds, EEGWindowsDataset):
|
|
1427
|
+
new_ds = ds.to_epochs_dataset()
|
|
1428
|
+
new_datasets.append(new_ds)
|
|
1429
|
+
elif isinstance(ds, WindowsDataset):
|
|
1430
|
+
new_datasets.append(ds)
|
|
1431
|
+
return BaseConcatDataset(
|
|
1432
|
+
new_datasets, target_transform=self.target_transform, lazy=self._lazy
|
|
1433
|
+
)
|
{braindecode-1.3.2.dev173417708 → braindecode-1.3.2.dev173801889}/braindecode/datasets/bids/hub.py
RENAMED
|
@@ -27,6 +27,7 @@ The format follows a BIDS-inspired sourcedata structure:
|
|
|
27
27
|
#
|
|
28
28
|
# License: BSD (3-clause)
|
|
29
29
|
|
|
30
|
+
import contextlib
|
|
30
31
|
import json
|
|
31
32
|
import logging
|
|
32
33
|
import tempfile
|
|
@@ -69,6 +70,8 @@ huggingface_hub = _soft_import(
|
|
|
69
70
|
|
|
70
71
|
log = logging.getLogger(__name__)
|
|
71
72
|
|
|
73
|
+
_LOCK_FILE = "format_info.json"
|
|
74
|
+
|
|
72
75
|
|
|
73
76
|
class HubDatasetMixin:
|
|
74
77
|
"""
|
|
@@ -84,7 +87,6 @@ class HubDatasetMixin:
|
|
|
84
87
|
>>> dataset = NMT(path=path, preload=True)
|
|
85
88
|
>>> dataset.push_to_hub(
|
|
86
89
|
... repo_id="username/nmt-dataset",
|
|
87
|
-
... commit_message="Add NMT dataset"
|
|
88
90
|
... )
|
|
89
91
|
>>>
|
|
90
92
|
>>> # Load dataset from Hub
|
|
@@ -96,13 +98,14 @@ class HubDatasetMixin:
|
|
|
96
98
|
def push_to_hub(
|
|
97
99
|
self,
|
|
98
100
|
repo_id: str,
|
|
99
|
-
commit_message: Optional[str] = None,
|
|
100
101
|
private: bool = False,
|
|
101
102
|
token: Optional[str] = None,
|
|
102
|
-
create_pr: bool = False,
|
|
103
103
|
compression: str = "blosc",
|
|
104
104
|
compression_level: int = 5,
|
|
105
105
|
pipeline_name: str = "braindecode",
|
|
106
|
+
chunk_size: int = 5_000_000,
|
|
107
|
+
local_cache_dir: str | Path | None = None,
|
|
108
|
+
**kwargs,
|
|
106
109
|
) -> str:
|
|
107
110
|
"""
|
|
108
111
|
Upload the dataset to the Hugging Face Hub in BIDS-like Zarr format.
|
|
@@ -116,20 +119,41 @@ class HubDatasetMixin:
|
|
|
116
119
|
----------
|
|
117
120
|
repo_id : str
|
|
118
121
|
Repository ID on the Hugging Face Hub (e.g., "username/dataset-name").
|
|
119
|
-
commit_message : str | None
|
|
120
|
-
Commit message. If None, a default message is generated.
|
|
121
122
|
private : bool, default=False
|
|
122
123
|
Whether to create a private repository.
|
|
123
124
|
token : str | None
|
|
124
125
|
Hugging Face API token. If None, uses cached token.
|
|
125
|
-
create_pr : bool, default=False
|
|
126
|
-
Whether to create a Pull Request instead of directly committing.
|
|
127
126
|
compression : str, default="blosc"
|
|
128
127
|
Compression algorithm for Zarr. Options: "blosc", "zstd", "gzip", None.
|
|
129
128
|
compression_level : int, default=5
|
|
130
129
|
Compression level (0-9). Level 5 provides optimal balance.
|
|
131
130
|
pipeline_name : str, default="braindecode"
|
|
132
131
|
Name of the processing pipeline for BIDS sourcedata.
|
|
132
|
+
chunk_size : int, default=5_000_000
|
|
133
|
+
Number of samples per chunk in Zarr along the time/window dimension.
|
|
134
|
+
Larger chunk sizes create fewer but larger chunks/files. This parameter
|
|
135
|
+
is used for both continuous data (e.g., RawDataset, EEGWindowsDataset)
|
|
136
|
+
and pre-cut windows (WindowsDataset). For WindowsDataset, multiple
|
|
137
|
+
windows may be stored in a single chunk depending on their duration
|
|
138
|
+
and the chosen ``chunk_size``.
|
|
139
|
+
local_cache_dir : str | Path | None
|
|
140
|
+
Local directory to use for temporary files during upload. If None, uses
|
|
141
|
+
the system temp directory and cleans it up after upload. If provided,
|
|
142
|
+
the directory is used as a persistent cache:
|
|
143
|
+
|
|
144
|
+
- If the directory is empty (or does not exist), the cache is built
|
|
145
|
+
there and a lock file (``format_info.json``) is written once
|
|
146
|
+
the cache is complete, before the upload starts. The file
|
|
147
|
+
contains the zarr conversion parameters as JSON.
|
|
148
|
+
- If the lock file is present and its JSON parameters match the
|
|
149
|
+
current call, cache creation is skipped and the upload resumes
|
|
150
|
+
directly (useful for retrying interrupted uploads).
|
|
151
|
+
- If the lock file is present but its JSON parameters differ from
|
|
152
|
+
the current call, a ``ValueError`` is raised.
|
|
153
|
+
- If the directory is non-empty but the lock file is absent, a
|
|
154
|
+
``ValueError`` is raised listing the files found.
|
|
155
|
+
**kwargs
|
|
156
|
+
Additional arguments passed to huggingface_hub.upload_large_folder().
|
|
133
157
|
|
|
134
158
|
Returns
|
|
135
159
|
-------
|
|
@@ -149,7 +173,6 @@ class HubDatasetMixin:
|
|
|
149
173
|
>>> # Upload with BIDS-like structure
|
|
150
174
|
>>> url = dataset.push_to_hub(
|
|
151
175
|
... repo_id="myusername/nmt-dataset",
|
|
152
|
-
... commit_message="Upload NMT EEG dataset"
|
|
153
176
|
... )
|
|
154
177
|
"""
|
|
155
178
|
if huggingface_hub is False or zarr is False:
|
|
@@ -159,13 +182,12 @@ class HubDatasetMixin:
|
|
|
159
182
|
)
|
|
160
183
|
|
|
161
184
|
# Create API instance
|
|
162
|
-
|
|
185
|
+
hf_api = huggingface_hub.HfApi(token=token)
|
|
163
186
|
|
|
164
187
|
# Create repository if it doesn't exist
|
|
165
188
|
try:
|
|
166
|
-
|
|
189
|
+
hf_api.create_repo(
|
|
167
190
|
repo_id=repo_id,
|
|
168
|
-
token=token,
|
|
169
191
|
private=private,
|
|
170
192
|
repo_type="dataset",
|
|
171
193
|
exist_ok=True,
|
|
@@ -173,74 +195,68 @@ class HubDatasetMixin:
|
|
|
173
195
|
except Exception as e:
|
|
174
196
|
raise RuntimeError(f"Failed to create repository: {e}")
|
|
175
197
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
# Save dataset_description.json
|
|
188
|
-
bids_layout.save_dataset_description()
|
|
189
|
-
|
|
190
|
-
# Save participants.tsv
|
|
191
|
-
descriptions = [ds.description for ds in self.datasets]
|
|
192
|
-
bids_layout.save_participants(descriptions)
|
|
193
|
-
|
|
194
|
-
# Save BIDS sidecar files for each recording
|
|
195
|
-
self._save_bids_sidecar_files(bids_layout)
|
|
196
|
-
|
|
197
|
-
# Convert dataset to Zarr format inside sourcedata
|
|
198
|
-
log.info("Converting dataset to Zarr format...")
|
|
199
|
-
dataset_path = sourcedata_dir / "dataset.zarr"
|
|
200
|
-
|
|
201
|
-
self._convert_to_zarr_inline(
|
|
202
|
-
dataset_path,
|
|
203
|
-
compression,
|
|
204
|
-
compression_level,
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
# Save dataset metadata (README.md)
|
|
208
|
-
self._save_dataset_card(tmp_path)
|
|
209
|
-
|
|
210
|
-
# Save format info
|
|
211
|
-
format_info_path = tmp_path / "format_info.json"
|
|
212
|
-
with open(format_info_path, "w", encoding="utf-8") as f:
|
|
213
|
-
format_info = self._get_format_info_inline()
|
|
214
|
-
json.dump(
|
|
215
|
-
{
|
|
216
|
-
"format": "zarr",
|
|
217
|
-
"pipeline_name": pipeline_name,
|
|
218
|
-
"compression": compression,
|
|
219
|
-
"compression_level": compression_level,
|
|
220
|
-
"braindecode_version": braindecode.__version__,
|
|
221
|
-
**format_info,
|
|
222
|
-
},
|
|
223
|
-
f,
|
|
224
|
-
indent=2,
|
|
225
|
-
)
|
|
198
|
+
format_info = self._get_format_info_inline()
|
|
199
|
+
format_info_lock = {
|
|
200
|
+
"format": "zarr",
|
|
201
|
+
"pipeline_name": pipeline_name,
|
|
202
|
+
"compression": compression,
|
|
203
|
+
"compression_level": compression_level,
|
|
204
|
+
"chunk_size": chunk_size,
|
|
205
|
+
"braindecode_version": braindecode.__version__,
|
|
206
|
+
**format_info,
|
|
207
|
+
}
|
|
226
208
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
209
|
+
# Determine upload directory and whether to build the cache
|
|
210
|
+
with contextlib.ExitStack() as stack:
|
|
211
|
+
if local_cache_dir is None:
|
|
212
|
+
tmpdir = stack.enter_context(tempfile.TemporaryDirectory())
|
|
213
|
+
tmp_path = Path(tmpdir)
|
|
214
|
+
build_cache = True
|
|
215
|
+
else:
|
|
216
|
+
tmp_path = Path(local_cache_dir)
|
|
217
|
+
lock_path = tmp_path / _LOCK_FILE
|
|
218
|
+
if lock_path.exists():
|
|
219
|
+
with open(lock_path, "r", encoding="utf-8") as _f:
|
|
220
|
+
_lock_params = json.load(_f)
|
|
221
|
+
if _lock_params != format_info_lock:
|
|
222
|
+
raise ValueError(
|
|
223
|
+
f"Lock file found at '{lock_path}' but its "
|
|
224
|
+
f"parameters {_lock_params} differ from the "
|
|
225
|
+
f"current call parameters {format_info_lock}. "
|
|
226
|
+
"Provide an empty directory or match the "
|
|
227
|
+
"original parameters."
|
|
228
|
+
)
|
|
229
|
+
log.info(
|
|
230
|
+
f"Lock file found at '{lock_path}', skipping cache "
|
|
231
|
+
"creation and resuming upload."
|
|
232
|
+
)
|
|
233
|
+
build_cache = False
|
|
234
|
+
else:
|
|
235
|
+
if tmp_path.exists():
|
|
236
|
+
existing = list(tmp_path.iterdir())
|
|
237
|
+
if existing:
|
|
238
|
+
entries = ", ".join(p.name for p in existing)
|
|
239
|
+
raise ValueError(
|
|
240
|
+
f"local_cache_dir '{tmp_path}' is not empty and "
|
|
241
|
+
f"has no lock file. Found: {entries}. Provide an "
|
|
242
|
+
"empty directory or one previously prepared by "
|
|
243
|
+
"push_to_hub()."
|
|
244
|
+
)
|
|
245
|
+
else:
|
|
246
|
+
tmp_path.mkdir(parents=True)
|
|
247
|
+
build_cache = True
|
|
248
|
+
|
|
249
|
+
if build_cache:
|
|
250
|
+
self._build_local_cache(tmp_path, format_info_lock)
|
|
233
251
|
|
|
234
252
|
# Upload folder to Hub
|
|
235
253
|
log.info(f"Uploading to Hugging Face Hub ({repo_id})...")
|
|
236
254
|
try:
|
|
237
|
-
url =
|
|
255
|
+
url = hf_api.upload_large_folder(
|
|
238
256
|
repo_id=repo_id,
|
|
239
257
|
folder_path=str(tmp_path),
|
|
240
258
|
repo_type="dataset",
|
|
241
|
-
|
|
242
|
-
token=token,
|
|
243
|
-
create_pr=create_pr,
|
|
259
|
+
**kwargs,
|
|
244
260
|
)
|
|
245
261
|
log.info(f"Dataset uploaded successfully to {repo_id}")
|
|
246
262
|
log.info(f"URL: https://huggingface.co/datasets/{repo_id}")
|
|
@@ -248,6 +264,55 @@ class HubDatasetMixin:
|
|
|
248
264
|
except Exception as e:
|
|
249
265
|
raise RuntimeError(f"Failed to upload dataset: {e}")
|
|
250
266
|
|
|
267
|
+
def _build_local_cache(
|
|
268
|
+
self,
|
|
269
|
+
tmp_path,
|
|
270
|
+
format_info_lock,
|
|
271
|
+
):
|
|
272
|
+
"""Build the local cache directory with the dataset in Zarr format and BIDS-like structure.
|
|
273
|
+
This folder will be uploaded to the Hub"""
|
|
274
|
+
compression = format_info_lock["compression"]
|
|
275
|
+
compression_level = format_info_lock["compression_level"]
|
|
276
|
+
pipeline_name = format_info_lock["pipeline_name"]
|
|
277
|
+
chunk_size = format_info_lock["chunk_size"]
|
|
278
|
+
|
|
279
|
+
# Create BIDS-like sourcedata structure
|
|
280
|
+
log.info("Creating BIDS-like sourcedata structure...")
|
|
281
|
+
bids_layout = hub_format.BIDSSourcedataLayout(
|
|
282
|
+
tmp_path, pipeline_name=pipeline_name
|
|
283
|
+
)
|
|
284
|
+
sourcedata_dir = bids_layout.create_structure()
|
|
285
|
+
|
|
286
|
+
# Save dataset_description.json
|
|
287
|
+
bids_layout.save_dataset_description()
|
|
288
|
+
|
|
289
|
+
# Save participants.tsv
|
|
290
|
+
descriptions = [ds.description for ds in self.datasets]
|
|
291
|
+
bids_layout.save_participants(descriptions)
|
|
292
|
+
|
|
293
|
+
# Save BIDS sidecar files for each recording
|
|
294
|
+
self._save_bids_sidecar_files(bids_layout)
|
|
295
|
+
|
|
296
|
+
# Convert dataset to Zarr format inside sourcedata
|
|
297
|
+
log.info("Converting dataset to Zarr format...")
|
|
298
|
+
dataset_path = sourcedata_dir / "dataset.zarr"
|
|
299
|
+
|
|
300
|
+
self._convert_to_zarr_inline(
|
|
301
|
+
dataset_path,
|
|
302
|
+
compression,
|
|
303
|
+
compression_level,
|
|
304
|
+
chunk_size,
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
# Save dataset metadata (README.md)
|
|
308
|
+
self._save_dataset_card(tmp_path)
|
|
309
|
+
|
|
310
|
+
# Save format info
|
|
311
|
+
# This marks the cache as complete
|
|
312
|
+
format_info_path = tmp_path / _LOCK_FILE
|
|
313
|
+
with open(format_info_path, "w", encoding="utf-8") as f:
|
|
314
|
+
json.dump(format_info_lock, f, indent=2)
|
|
315
|
+
|
|
251
316
|
def _save_dataset_card(self, path: Path, bids_inspired: bool = True) -> None:
|
|
252
317
|
"""Generate and save a dataset card (README.md) with metadata.
|
|
253
318
|
|
|
@@ -465,7 +530,7 @@ class HubDatasetMixin:
|
|
|
465
530
|
)
|
|
466
531
|
|
|
467
532
|
# Load format info
|
|
468
|
-
format_info_path = Path(dataset_dir) /
|
|
533
|
+
format_info_path = Path(dataset_dir) / _LOCK_FILE
|
|
469
534
|
if format_info_path.exists():
|
|
470
535
|
with open(format_info_path, "r") as f:
|
|
471
536
|
format_info = json.load(f)
|
|
@@ -595,6 +660,7 @@ class HubDatasetMixin:
|
|
|
595
660
|
output_path: Path,
|
|
596
661
|
compression: str,
|
|
597
662
|
compression_level: int,
|
|
663
|
+
chunk_size: int = 5_000_000,
|
|
598
664
|
) -> None:
|
|
599
665
|
"""Convert dataset to Zarr format (inline implementation)."""
|
|
600
666
|
|
|
@@ -660,7 +726,14 @@ class HubDatasetMixin:
|
|
|
660
726
|
|
|
661
727
|
# Save using inlined function
|
|
662
728
|
_save_windows_to_zarr(
|
|
663
|
-
grp,
|
|
729
|
+
grp,
|
|
730
|
+
data,
|
|
731
|
+
metadata,
|
|
732
|
+
description,
|
|
733
|
+
info_dict,
|
|
734
|
+
compressor,
|
|
735
|
+
target_name,
|
|
736
|
+
chunk_size,
|
|
664
737
|
)
|
|
665
738
|
|
|
666
739
|
elif dataset_type == "EEGWindowsDataset":
|
|
@@ -682,6 +755,7 @@ class HubDatasetMixin:
|
|
|
682
755
|
targets_from,
|
|
683
756
|
last_target_only,
|
|
684
757
|
compressor,
|
|
758
|
+
chunk_size,
|
|
685
759
|
)
|
|
686
760
|
|
|
687
761
|
elif dataset_type == "RawDataset":
|
|
@@ -693,7 +767,13 @@ class HubDatasetMixin:
|
|
|
693
767
|
|
|
694
768
|
# Save using inlined function
|
|
695
769
|
_save_raw_to_zarr(
|
|
696
|
-
grp,
|
|
770
|
+
grp,
|
|
771
|
+
raw,
|
|
772
|
+
description,
|
|
773
|
+
info_dict,
|
|
774
|
+
target_name,
|
|
775
|
+
compressor,
|
|
776
|
+
chunk_size,
|
|
697
777
|
)
|
|
698
778
|
|
|
699
779
|
def _get_format_info_inline(self):
|
|
@@ -765,11 +845,16 @@ class HubDatasetMixin:
|
|
|
765
845
|
|
|
766
846
|
# Convert to MNE objects and create dataset
|
|
767
847
|
info = Info.from_json_dict(info_dict)
|
|
848
|
+
targets = metadata["target"].values
|
|
849
|
+
if np.issubdtype(targets.dtype, np.integer):
|
|
850
|
+
event_ids = targets
|
|
851
|
+
else:
|
|
852
|
+
event_ids = np.ones(len(metadata), dtype=int)
|
|
768
853
|
events = np.column_stack(
|
|
769
854
|
[
|
|
770
|
-
metadata["i_start_in_trial"].values,
|
|
855
|
+
metadata["i_start_in_trial"].values.astype(int),
|
|
771
856
|
np.zeros(len(metadata), dtype=int),
|
|
772
|
-
|
|
857
|
+
event_ids,
|
|
773
858
|
]
|
|
774
859
|
)
|
|
775
860
|
epochs = mne.EpochsArray(data, info, events=events, metadata=metadata)
|
|
@@ -45,16 +45,25 @@ def _restore_nan_from_json(obj):
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def _save_windows_to_zarr(
|
|
48
|
-
grp, data, metadata, description, info, compressor, target_name
|
|
48
|
+
grp, data, metadata, description, info, compressor, target_name, chunk_size
|
|
49
49
|
):
|
|
50
50
|
"""Save windowed data to Zarr group (low-level function)."""
|
|
51
51
|
data_array = data.astype(np.float32)
|
|
52
52
|
compressors_list = [compressor] if compressor is not None else None
|
|
53
53
|
|
|
54
|
+
max_windows_per_chunk = max(
|
|
55
|
+
1, chunk_size // (data_array.shape[1] * data_array.shape[2])
|
|
56
|
+
)
|
|
57
|
+
n_windows_per_chunk = min(data_array.shape[0], max_windows_per_chunk)
|
|
58
|
+
|
|
54
59
|
grp.create_array(
|
|
55
60
|
"data",
|
|
56
61
|
data=data_array,
|
|
57
|
-
chunks=(
|
|
62
|
+
chunks=(
|
|
63
|
+
n_windows_per_chunk,
|
|
64
|
+
data_array.shape[1],
|
|
65
|
+
data_array.shape[2],
|
|
66
|
+
),
|
|
58
67
|
compressors=compressors_list,
|
|
59
68
|
)
|
|
60
69
|
|
|
@@ -70,17 +79,28 @@ def _save_windows_to_zarr(
|
|
|
70
79
|
|
|
71
80
|
|
|
72
81
|
def _save_eegwindows_to_zarr(
|
|
73
|
-
grp,
|
|
82
|
+
grp,
|
|
83
|
+
raw,
|
|
84
|
+
metadata,
|
|
85
|
+
description,
|
|
86
|
+
info,
|
|
87
|
+
targets_from,
|
|
88
|
+
last_target_only,
|
|
89
|
+
compressor,
|
|
90
|
+
chunk_size,
|
|
74
91
|
):
|
|
75
92
|
"""Save EEG continuous raw data to Zarr group (low-level function)."""
|
|
76
93
|
continuous_data = raw.get_data()
|
|
77
94
|
continuous_float = continuous_data.astype(np.float32)
|
|
78
95
|
compressors_list = [compressor] if compressor is not None else None
|
|
79
96
|
|
|
97
|
+
max_samples_per_chunk = max(1, chunk_size // continuous_float.shape[0])
|
|
98
|
+
n_samples_per_chunk = min(continuous_float.shape[1], max_samples_per_chunk)
|
|
99
|
+
|
|
80
100
|
grp.create_array(
|
|
81
101
|
"data",
|
|
82
102
|
data=continuous_float,
|
|
83
|
-
chunks=(continuous_float.shape[0],
|
|
103
|
+
chunks=(continuous_float.shape[0], n_samples_per_chunk),
|
|
84
104
|
compressors=compressors_list,
|
|
85
105
|
)
|
|
86
106
|
|
|
@@ -143,16 +163,19 @@ def _load_eegwindows_from_zarr(grp, preload):
|
|
|
143
163
|
return data, metadata, description, info_dict, targets_from, last_target_only
|
|
144
164
|
|
|
145
165
|
|
|
146
|
-
def _save_raw_to_zarr(grp, raw, description, info, target_name, compressor):
|
|
166
|
+
def _save_raw_to_zarr(grp, raw, description, info, target_name, compressor, chunk_size):
|
|
147
167
|
"""Save RawDataset continuous raw data to Zarr group (low-level function)."""
|
|
148
168
|
continuous_data = raw.get_data()
|
|
149
169
|
continuous_float = continuous_data.astype(np.float32)
|
|
150
170
|
compressors_list = [compressor] if compressor is not None else None
|
|
151
171
|
|
|
172
|
+
max_samples_per_chunk = max(1, chunk_size // continuous_float.shape[0])
|
|
173
|
+
n_samples_per_chunk = min(continuous_float.shape[1], max_samples_per_chunk)
|
|
174
|
+
|
|
152
175
|
grp.create_array(
|
|
153
176
|
"data",
|
|
154
177
|
data=continuous_float,
|
|
155
|
-
chunks=(continuous_float.shape[0],
|
|
178
|
+
chunks=(continuous_float.shape[0], n_samples_per_chunk),
|
|
156
179
|
compressors=compressors_list,
|
|
157
180
|
)
|
|
158
181
|
|