eegdash 0.4.0.dev153__tar.gz → 0.4.0.dev171__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.
Potentially problematic release.
This version of eegdash might be problematic. Click here for more details.
- {eegdash-0.4.0.dev153/eegdash.egg-info → eegdash-0.4.0.dev171}/PKG-INFO +1 -1
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/api/api_core.rst +1 -1
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/conf.py +6 -3
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/dataset_summary/bubble.rst +2 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/dataset_summary/kde.rst +3 -1
- eegdash-0.4.0.dev171/docs/source/dataset_summary/sankey.rst +20 -0
- eegdash-0.4.0.dev171/docs/source/dataset_summary/table.rst +27 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/dataset_summary.rst +10 -6
- eegdash-0.4.0.dev171/docs/source/index.rst +86 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/__init__.py +1 -1
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/api.py +180 -86
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/bids_eeg_metadata.py +139 -39
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/const.py +25 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/data_utils.py +239 -173
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/dataset/dataset.py +35 -13
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/dataset/dataset_summary.csv +255 -255
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/dataset/registry.py +69 -4
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/downloader.py +95 -9
- eegdash-0.4.0.dev171/eegdash/features/datasets.py +677 -0
- eegdash-0.4.0.dev171/eegdash/features/decorators.py +136 -0
- eegdash-0.4.0.dev171/eegdash/features/extractors.py +357 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/features/feature_bank/complexity.py +7 -3
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/features/feature_bank/dimensionality.py +1 -1
- eegdash-0.4.0.dev171/eegdash/features/inspect.py +123 -0
- eegdash-0.4.0.dev171/eegdash/features/serialization.py +115 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/features/utils.py +75 -8
- eegdash-0.4.0.dev171/eegdash/hbn/preprocessing.py +105 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/hbn/windows.py +145 -32
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/logging.py +19 -0
- eegdash-0.4.0.dev171/eegdash/mongodb.py +97 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/paths.py +14 -5
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/utils.py +16 -1
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171/eegdash.egg-info}/PKG-INFO +1 -1
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash.egg-info/SOURCES.txt +2 -0
- eegdash-0.4.0.dev171/tests/test_features.py +67 -0
- eegdash-0.4.0.dev153/docs/source/dataset_summary/table.rst +0 -174
- eegdash-0.4.0.dev153/docs/source/index.rst +0 -60
- eegdash-0.4.0.dev153/eegdash/features/datasets.py +0 -493
- eegdash-0.4.0.dev153/eegdash/features/decorators.py +0 -51
- eegdash-0.4.0.dev153/eegdash/features/extractors.py +0 -209
- eegdash-0.4.0.dev153/eegdash/features/inspect.py +0 -48
- eegdash-0.4.0.dev153/eegdash/features/serialization.py +0 -87
- eegdash-0.4.0.dev153/eegdash/hbn/preprocessing.py +0 -72
- eegdash-0.4.0.dev153/eegdash/mongodb.py +0 -80
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/LICENSE +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/MANIFEST.in +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/README.md +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/Makefile +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/_templates/autosummary/module.rst +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/api/api.rst +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/api/api_features.rst +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/install/install.rst +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/install/install_pip.rst +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/install/install_source.rst +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/sg_execution_times.rst +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/docs/source/user_guide.rst +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/dataset/__init__.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/features/__init__.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/features/feature_bank/__init__.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/features/feature_bank/connectivity.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/features/feature_bank/csp.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/features/feature_bank/signal.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/features/feature_bank/spectral.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/features/feature_bank/utils.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash/hbn/__init__.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash.egg-info/dependency_links.txt +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash.egg-info/requires.txt +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/eegdash.egg-info/top_level.txt +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/pyproject.toml +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/setup.cfg +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_api.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_bids_dependencies.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_cache_folder_suffix.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_challenge_kwargs.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_correctness.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_dataset.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_dataset_registration.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_downloader.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_eegdash.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_init.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_minirelease.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_mongo_connection.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_offline.py +0 -0
- {eegdash-0.4.0.dev153 → eegdash-0.4.0.dev171}/tests/test_query.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: eegdash
|
|
3
|
-
Version: 0.4.0.
|
|
3
|
+
Version: 0.4.0.dev171
|
|
4
4
|
Summary: EEG data for machine learning
|
|
5
5
|
Author-email: Young Truong <dt.young112@gmail.com>, Arnaud Delorme <adelorme@gmail.com>, Aviv Dotan <avivd220@gmail.com>, Oren Shriki <oren70@gmail.com>, Bruno Aristimunha <b.aristimunha@gmail.com>
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -12,13 +12,15 @@ from sphinx.util import logging
|
|
|
12
12
|
from sphinx_gallery.sorting import ExplicitOrder, FileNameSortKey
|
|
13
13
|
from tabulate import tabulate
|
|
14
14
|
|
|
15
|
+
sys.path.insert(0, os.path.abspath(".."))
|
|
16
|
+
|
|
15
17
|
import eegdash
|
|
16
18
|
|
|
17
19
|
# -- Project information -----------------------------------------------------
|
|
18
20
|
|
|
19
21
|
project = "EEG Dash"
|
|
20
22
|
copyright = f"2025–{datetime.now(tz=timezone.utc).year}, {project} Developers"
|
|
21
|
-
author = "Arnaud Delorme"
|
|
23
|
+
author = "Bruno Aristimunha and Arnaud Delorme"
|
|
22
24
|
release = eegdash.__version__
|
|
23
25
|
version = ".".join(release.split(".")[:2])
|
|
24
26
|
|
|
@@ -44,6 +46,7 @@ extensions = [
|
|
|
44
46
|
"sphinx_sitemap",
|
|
45
47
|
"sphinx_copybutton",
|
|
46
48
|
"sphinx.ext.graphviz",
|
|
49
|
+
"sphinx_time_estimation",
|
|
47
50
|
]
|
|
48
51
|
|
|
49
52
|
templates_path = ["_templates"]
|
|
@@ -103,8 +106,8 @@ html_theme_options = {
|
|
|
103
106
|
"navbar_end": ["theme-switcher", "navbar-icon-links"],
|
|
104
107
|
"footer_start": ["copyright"],
|
|
105
108
|
"logo": {
|
|
106
|
-
"image_light": "_static/
|
|
107
|
-
"image_dark": "_static/
|
|
109
|
+
"image_light": "_static/eegdash_long_white.svg",
|
|
110
|
+
"image_dark": "_static/eegdash_long_dark.svg",
|
|
108
111
|
"alt_text": "EEG Dash Logo",
|
|
109
112
|
},
|
|
110
113
|
"external_links": [
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.. title:: Dataset flow
|
|
2
|
+
|
|
3
|
+
.. rubric:: Sankey diagrams of EEGDash Datasets by Population, Modality, and Cognitive Domain
|
|
4
|
+
|
|
5
|
+
.. raw:: html
|
|
6
|
+
|
|
7
|
+
<figure class="eegdash-figure" style="margin: 0 0 1.25rem 0;">
|
|
8
|
+
|
|
9
|
+
.. raw:: html
|
|
10
|
+
:file: ../_static/dataset_generated/dataset_sankey.html
|
|
11
|
+
|
|
12
|
+
.. raw:: html
|
|
13
|
+
|
|
14
|
+
<figcaption class="eegdash-caption">
|
|
15
|
+
Figure: Dataset flow across population, modality, and cognitive domain.
|
|
16
|
+
Link thickness is proportional to the total number of subjects, and the tooltip
|
|
17
|
+
reports both subject and dataset counts. Hover and click legend entries to
|
|
18
|
+
explore specific segments.
|
|
19
|
+
</figcaption>
|
|
20
|
+
</figure>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
.. title:: EEG Datasets Table
|
|
2
|
+
|
|
3
|
+
.. rubric:: EEG Datasets Table
|
|
4
|
+
|
|
5
|
+
The data in EEG-DaSh originates from a collaboration involving 25 laboratories, encompassing 27,053 participants. This extensive collection includes M-EEG data, which is a combination of EEG and MEG signals. The data is sourced from various studies conducted by these labs,
|
|
6
|
+
involving both healthy subjects and clinical populations with conditions such as ADHD, depression, schizophrenia, dementia, autism, and psychosis. Additionally, data spans different mental states like sleep, meditation, and cognitive tasks.
|
|
7
|
+
|
|
8
|
+
In addition, EEG-DaSh will incorporate a subset of the data converted from `NEMAR <https://nemar.org/>`__, which includes 330 MEEG BIDS-formatted datasets, further expanding the archive with well-curated, standardized neuroelectromagnetic data.
|
|
9
|
+
|
|
10
|
+
.. raw:: html
|
|
11
|
+
|
|
12
|
+
<figure class="eegdash-figure" style="margin: 0 0 1.25rem 0;">
|
|
13
|
+
|
|
14
|
+
.. raw:: html
|
|
15
|
+
:file: ../_static/dataset_generated/dataset_summary_table.html
|
|
16
|
+
|
|
17
|
+
.. raw:: html
|
|
18
|
+
|
|
19
|
+
<figcaption class="eegdash-caption">
|
|
20
|
+
Table: Sortable catalogue of EEG‑DaSh datasets. Use the “Filters” button to open column filters;
|
|
21
|
+
click a column header to jump directly to a filter pane. The Total row is pinned at the bottom.
|
|
22
|
+
* means that we use the median value across multiple recordings in the dataset, and empty cells
|
|
23
|
+
when the metainformation is not extracted yet.
|
|
24
|
+
</figcaption>
|
|
25
|
+
</figure>
|
|
26
|
+
|
|
27
|
+
Pathology, modality, and dataset type now surface as consistent color-coded tags so you can scan the table at a glance.
|
|
@@ -10,13 +10,11 @@
|
|
|
10
10
|
|
|
11
11
|
.. rst-class:: dataset-summary-article
|
|
12
12
|
|
|
13
|
-
Datasets
|
|
14
|
-
|
|
13
|
+
Datasets Catalog
|
|
14
|
+
================
|
|
15
15
|
|
|
16
16
|
To leverage recent and ongoing advancements in large-scale computational methods and to ensure the preservation of scientific data generated from publicly funded research, the EEG-DaSh data archive will create a data-sharing resource for MEEG (EEG, MEG) data contributed by collaborators for machine learning (ML) and deep learning (DL) applications.
|
|
17
17
|
|
|
18
|
-
The archive is currently still in :bdg-danger:`beta testing` mode, so be kind.
|
|
19
|
-
|
|
20
18
|
.. raw:: html
|
|
21
19
|
|
|
22
20
|
<script src="https://cdn.plot.ly/plotly-3.1.0.min.js"></script>
|
|
@@ -27,10 +25,16 @@ The archive is currently still in :bdg-danger:`beta testing` mode, so be kind.
|
|
|
27
25
|
|
|
28
26
|
.. include:: dataset_summary/table.rst
|
|
29
27
|
|
|
30
|
-
.. tab-item:: Participant
|
|
28
|
+
.. tab-item:: Participant Distribution
|
|
31
29
|
|
|
32
30
|
.. include:: dataset_summary/kde.rst
|
|
33
31
|
|
|
34
|
-
.. tab-item::
|
|
32
|
+
.. tab-item:: Dataset Flow
|
|
33
|
+
|
|
34
|
+
.. include:: dataset_summary/sankey.rst
|
|
35
|
+
|
|
36
|
+
.. tab-item:: Scatter of Sample Size vs. Recording Duration
|
|
35
37
|
|
|
36
38
|
.. include:: dataset_summary/bubble.rst
|
|
39
|
+
|
|
40
|
+
The archive is currently still in :bdg-danger:`beta testing` mode, so be kind.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
:html_theme.sidebar_secondary.remove: true
|
|
2
|
+
|
|
3
|
+
EEGDASH Homepage
|
|
4
|
+
=================
|
|
5
|
+
|
|
6
|
+
.. title:: EEG Dash
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
EEG Dash Homepage
|
|
10
|
+
==================
|
|
11
|
+
|
|
12
|
+
.. raw:: html
|
|
13
|
+
|
|
14
|
+
<style type="text/css">h1 {display:none;}</style>
|
|
15
|
+
|
|
16
|
+
.. raw:: html
|
|
17
|
+
|
|
18
|
+
<h1 class="eegdash-hero__title">EEG Dash</h1>
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
.. image:: _static/logos/eegdash.svg
|
|
22
|
+
:alt: EEG Dash Logo
|
|
23
|
+
:class: logo mainlogo only-dark
|
|
24
|
+
:align: center
|
|
25
|
+
:scale: 50%
|
|
26
|
+
|
|
27
|
+
.. image:: _static/logos/eegdash.svg
|
|
28
|
+
:alt: EEG Dash Logo
|
|
29
|
+
:class: logo mainlogo only-light
|
|
30
|
+
:align: center
|
|
31
|
+
:scale: 50%
|
|
32
|
+
|
|
33
|
+
.. rst-class:: h4 text-center font-weight-light my-4
|
|
34
|
+
|
|
35
|
+
The EEG-DaSh data archive is a data-sharing resource for MEEG (EEG, MEG) data, enabling
|
|
36
|
+
large-scale computational advancements to preserve and share scientific data from publicly funded
|
|
37
|
+
research for machine learning and deep learning applications.
|
|
38
|
+
|
|
39
|
+
.. rst-class:: text-center
|
|
40
|
+
|
|
41
|
+
The "DaSh" in EEG-DaSh stands for **Data Share**.
|
|
42
|
+
|
|
43
|
+
The EEG-DaSh data archive is a collaborative effort led by the University of California, San Diego (UCSD) and Ben-Gurion University of the Negev (BGU) and partially funded by the National Science Foundation (NSF). All are welcome to contribute to the https://github.com/sccn/EEGDash project.
|
|
44
|
+
|
|
45
|
+
The archive is currently still in :bdg-danger:`beta testing` mode, so be kind.
|
|
46
|
+
|
|
47
|
+
.. raw:: html
|
|
48
|
+
|
|
49
|
+
<h2 style="text-align: center;">Institutions</h2>
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
.. image:: _static/logos/ucsd_white.svg
|
|
53
|
+
:alt: UCSD
|
|
54
|
+
:class: logo mainlogo only-dark flex-logo
|
|
55
|
+
:width: 45%
|
|
56
|
+
:align: left
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
.. image:: _static/logos/ucsd_dark.svg
|
|
60
|
+
:alt: UCSD
|
|
61
|
+
:class: logo mainlogo only-light flex-logo
|
|
62
|
+
:align: left
|
|
63
|
+
:width: 45%
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
.. image:: _static/logos/bgu_dark.svg
|
|
67
|
+
:alt: Ben-Gurion University of the Negev (BGU)
|
|
68
|
+
:class: logo mainlogo only-dark flex-logo
|
|
69
|
+
:align: right
|
|
70
|
+
:width: 40%
|
|
71
|
+
|
|
72
|
+
.. image:: _static/logos/bgu_white.svg
|
|
73
|
+
:alt: Ben-Gurion University of the Negev (BGU)
|
|
74
|
+
:class: logo mainlogo only-light flex-logo
|
|
75
|
+
:align: right
|
|
76
|
+
:width: 40%
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
.. toctree::
|
|
80
|
+
:hidden:
|
|
81
|
+
|
|
82
|
+
Installing <install/install>
|
|
83
|
+
User Guide <user_guide>
|
|
84
|
+
API <api/api>
|
|
85
|
+
Dataset Catalog <dataset_summary>
|
|
86
|
+
Examples <generated/auto_examples/index>
|
|
@@ -212,17 +212,22 @@ class EEGDash:
|
|
|
212
212
|
return doc is not None
|
|
213
213
|
|
|
214
214
|
def _validate_input(self, record: dict[str, Any]) -> dict[str, Any]:
|
|
215
|
-
"""
|
|
215
|
+
"""Validate the input record against the expected schema.
|
|
216
216
|
|
|
217
217
|
Parameters
|
|
218
218
|
----------
|
|
219
|
-
record: dict
|
|
219
|
+
record : dict
|
|
220
220
|
A dictionary representing the EEG data record to be validated.
|
|
221
221
|
|
|
222
222
|
Returns
|
|
223
223
|
-------
|
|
224
|
-
dict
|
|
225
|
-
|
|
224
|
+
dict
|
|
225
|
+
The record itself on success.
|
|
226
|
+
|
|
227
|
+
Raises
|
|
228
|
+
------
|
|
229
|
+
ValueError
|
|
230
|
+
If the record is missing required keys or has values of the wrong type.
|
|
226
231
|
|
|
227
232
|
"""
|
|
228
233
|
input_types = {
|
|
@@ -252,20 +257,44 @@ class EEGDash:
|
|
|
252
257
|
return record
|
|
253
258
|
|
|
254
259
|
def _build_query_from_kwargs(self, **kwargs) -> dict[str, Any]:
|
|
255
|
-
"""
|
|
260
|
+
"""Build a validated MongoDB query from keyword arguments.
|
|
261
|
+
|
|
262
|
+
This delegates to the module-level builder used across the package.
|
|
263
|
+
|
|
264
|
+
Parameters
|
|
265
|
+
----------
|
|
266
|
+
**kwargs
|
|
267
|
+
Keyword arguments to convert into a MongoDB query.
|
|
268
|
+
|
|
269
|
+
Returns
|
|
270
|
+
-------
|
|
271
|
+
dict
|
|
272
|
+
A MongoDB query dictionary.
|
|
256
273
|
|
|
257
|
-
This delegates to the module-level builder used across the package and
|
|
258
|
-
is exposed here for testing and convenience.
|
|
259
274
|
"""
|
|
260
275
|
return build_query_from_kwargs(**kwargs)
|
|
261
276
|
|
|
262
|
-
|
|
263
|
-
|
|
277
|
+
def _extract_simple_constraint(
|
|
278
|
+
self, query: dict[str, Any], key: str
|
|
279
|
+
) -> tuple[str, Any] | None:
|
|
264
280
|
"""Extract a simple constraint for a given key from a query dict.
|
|
265
281
|
|
|
266
|
-
Supports
|
|
267
|
-
|
|
268
|
-
|
|
282
|
+
Supports top-level equality (e.g., ``{'subject': '01'}``) and ``$in``
|
|
283
|
+
(e.g., ``{'subject': {'$in': ['01', '02']}}``) constraints.
|
|
284
|
+
|
|
285
|
+
Parameters
|
|
286
|
+
----------
|
|
287
|
+
query : dict
|
|
288
|
+
The MongoDB query dictionary.
|
|
289
|
+
key : str
|
|
290
|
+
The key for which to extract the constraint.
|
|
291
|
+
|
|
292
|
+
Returns
|
|
293
|
+
-------
|
|
294
|
+
tuple or None
|
|
295
|
+
A tuple of (kind, value) where kind is "eq" or "in", or None if the
|
|
296
|
+
constraint is not present or unsupported.
|
|
297
|
+
|
|
269
298
|
"""
|
|
270
299
|
if not isinstance(query, dict) or key not in query:
|
|
271
300
|
return None
|
|
@@ -275,16 +304,28 @@ class EEGDash:
|
|
|
275
304
|
return ("in", list(val["$in"]))
|
|
276
305
|
return None # unsupported operator shape for conflict checking
|
|
277
306
|
else:
|
|
278
|
-
return
|
|
307
|
+
return "eq", val
|
|
279
308
|
|
|
280
309
|
def _raise_if_conflicting_constraints(
|
|
281
310
|
self, raw_query: dict[str, Any], kwargs_query: dict[str, Any]
|
|
282
311
|
) -> None:
|
|
283
|
-
"""Raise ValueError if
|
|
312
|
+
"""Raise ValueError if query sources have incompatible constraints.
|
|
313
|
+
|
|
314
|
+
Checks for mutually exclusive constraints on the same field to avoid
|
|
315
|
+
silent empty results.
|
|
316
|
+
|
|
317
|
+
Parameters
|
|
318
|
+
----------
|
|
319
|
+
raw_query : dict
|
|
320
|
+
The raw MongoDB query dictionary.
|
|
321
|
+
kwargs_query : dict
|
|
322
|
+
The query dictionary built from keyword arguments.
|
|
323
|
+
|
|
324
|
+
Raises
|
|
325
|
+
------
|
|
326
|
+
ValueError
|
|
327
|
+
If conflicting constraints are found.
|
|
284
328
|
|
|
285
|
-
We conservatively check only top-level fields with simple equality or $in
|
|
286
|
-
constraints. If a field appears in both queries and constraints are mutually
|
|
287
|
-
exclusive, raise an explicit error to avoid silent empty result sets.
|
|
288
329
|
"""
|
|
289
330
|
if not raw_query or not kwargs_query:
|
|
290
331
|
return
|
|
@@ -388,12 +429,31 @@ class EEGDash:
|
|
|
388
429
|
logger.info("Upserted: %s", result.upserted_count)
|
|
389
430
|
logger.info("Errors: %s ", result.bulk_api_result.get("writeErrors", []))
|
|
390
431
|
|
|
391
|
-
def _add_request(self, record: dict):
|
|
392
|
-
"""
|
|
432
|
+
def _add_request(self, record: dict) -> InsertOne:
|
|
433
|
+
"""Create a MongoDB insertion request for a record.
|
|
434
|
+
|
|
435
|
+
Parameters
|
|
436
|
+
----------
|
|
437
|
+
record : dict
|
|
438
|
+
The record to insert.
|
|
439
|
+
|
|
440
|
+
Returns
|
|
441
|
+
-------
|
|
442
|
+
InsertOne
|
|
443
|
+
A PyMongo ``InsertOne`` object.
|
|
444
|
+
|
|
445
|
+
"""
|
|
393
446
|
return InsertOne(record)
|
|
394
447
|
|
|
395
|
-
def add(self, record: dict):
|
|
396
|
-
"""Add a single record to the MongoDB collection.
|
|
448
|
+
def add(self, record: dict) -> None:
|
|
449
|
+
"""Add a single record to the MongoDB collection.
|
|
450
|
+
|
|
451
|
+
Parameters
|
|
452
|
+
----------
|
|
453
|
+
record : dict
|
|
454
|
+
The record to add.
|
|
455
|
+
|
|
456
|
+
"""
|
|
397
457
|
try:
|
|
398
458
|
self.__collection.insert_one(record)
|
|
399
459
|
except ValueError as e:
|
|
@@ -405,11 +465,23 @@ class EEGDash:
|
|
|
405
465
|
)
|
|
406
466
|
logger.debug("Add operation failed", exc_info=exc)
|
|
407
467
|
|
|
408
|
-
def _update_request(self, record: dict):
|
|
409
|
-
"""
|
|
468
|
+
def _update_request(self, record: dict) -> UpdateOne:
|
|
469
|
+
"""Create a MongoDB update request for a record.
|
|
470
|
+
|
|
471
|
+
Parameters
|
|
472
|
+
----------
|
|
473
|
+
record : dict
|
|
474
|
+
The record to update.
|
|
475
|
+
|
|
476
|
+
Returns
|
|
477
|
+
-------
|
|
478
|
+
UpdateOne
|
|
479
|
+
A PyMongo ``UpdateOne`` object.
|
|
480
|
+
|
|
481
|
+
"""
|
|
410
482
|
return UpdateOne({"data_name": record["data_name"]}, {"$set": record})
|
|
411
483
|
|
|
412
|
-
def update(self, record: dict):
|
|
484
|
+
def update(self, record: dict) -> None:
|
|
413
485
|
"""Update a single record in the MongoDB collection.
|
|
414
486
|
|
|
415
487
|
Parameters
|
|
@@ -429,58 +501,81 @@ class EEGDash:
|
|
|
429
501
|
logger.debug("Update operation failed", exc_info=exc)
|
|
430
502
|
|
|
431
503
|
def exists(self, query: dict[str, Any]) -> bool:
|
|
432
|
-
"""
|
|
504
|
+
"""Check if at least one record matches the query.
|
|
505
|
+
|
|
506
|
+
This is an alias for :meth:`exist`.
|
|
507
|
+
|
|
508
|
+
Parameters
|
|
509
|
+
----------
|
|
510
|
+
query : dict
|
|
511
|
+
MongoDB query to check for existence.
|
|
512
|
+
|
|
513
|
+
Returns
|
|
514
|
+
-------
|
|
515
|
+
bool
|
|
516
|
+
True if a matching record exists, False otherwise.
|
|
517
|
+
|
|
518
|
+
"""
|
|
433
519
|
return self.exist(query)
|
|
434
520
|
|
|
435
|
-
def remove_field(self, record, field):
|
|
436
|
-
"""Remove a
|
|
521
|
+
def remove_field(self, record: dict, field: str) -> None:
|
|
522
|
+
"""Remove a field from a specific record in the MongoDB collection.
|
|
437
523
|
|
|
438
524
|
Parameters
|
|
439
525
|
----------
|
|
440
526
|
record : dict
|
|
441
|
-
Record
|
|
527
|
+
Record-identifying object with a ``data_name`` key.
|
|
442
528
|
field : str
|
|
443
|
-
|
|
529
|
+
The name of the field to remove.
|
|
444
530
|
|
|
445
531
|
"""
|
|
446
532
|
self.__collection.update_one(
|
|
447
533
|
{"data_name": record["data_name"]}, {"$unset": {field: 1}}
|
|
448
534
|
)
|
|
449
535
|
|
|
450
|
-
def remove_field_from_db(self, field):
|
|
451
|
-
"""Remove a field from all records
|
|
536
|
+
def remove_field_from_db(self, field: str) -> None:
|
|
537
|
+
"""Remove a field from all records in the database.
|
|
538
|
+
|
|
539
|
+
.. warning::
|
|
540
|
+
This is a destructive operation and cannot be undone.
|
|
452
541
|
|
|
453
542
|
Parameters
|
|
454
543
|
----------
|
|
455
544
|
field : str
|
|
456
|
-
|
|
545
|
+
The name of the field to remove from all documents.
|
|
457
546
|
|
|
458
547
|
"""
|
|
459
548
|
self.__collection.update_many({}, {"$unset": {field: 1}})
|
|
460
549
|
|
|
461
550
|
@property
|
|
462
551
|
def collection(self):
|
|
463
|
-
"""
|
|
464
|
-
return self.__collection
|
|
552
|
+
"""The underlying PyMongo ``Collection`` object.
|
|
465
553
|
|
|
466
|
-
|
|
467
|
-
|
|
554
|
+
Returns
|
|
555
|
+
-------
|
|
556
|
+
pymongo.collection.Collection
|
|
557
|
+
The collection object used for database interactions.
|
|
468
558
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
Connections are managed by :class:`MongoConnectionManager`. Use
|
|
472
|
-
:meth:`close_all_connections` to explicitly close all clients.
|
|
559
|
+
"""
|
|
560
|
+
return self.__collection
|
|
473
561
|
|
|
562
|
+
def close(self) -> None:
|
|
563
|
+
"""Close the MongoDB connection.
|
|
564
|
+
|
|
565
|
+
.. deprecated:: 0.1
|
|
566
|
+
Connections are now managed globally by :class:`MongoConnectionManager`.
|
|
567
|
+
This method is a no-op and will be removed in a future version.
|
|
568
|
+
Use :meth:`EEGDash.close_all_connections` to close all clients.
|
|
474
569
|
"""
|
|
475
570
|
# Individual instances no longer close the shared client
|
|
476
571
|
pass
|
|
477
572
|
|
|
478
573
|
@classmethod
|
|
479
|
-
def close_all_connections(cls):
|
|
480
|
-
"""Close all MongoDB client connections managed by the singleton."""
|
|
574
|
+
def close_all_connections(cls) -> None:
|
|
575
|
+
"""Close all MongoDB client connections managed by the singleton manager."""
|
|
481
576
|
MongoConnectionManager.close_all()
|
|
482
577
|
|
|
483
|
-
def __del__(self):
|
|
578
|
+
def __del__(self) -> None:
|
|
484
579
|
"""Destructor; no explicit action needed due to global connection manager."""
|
|
485
580
|
# No longer needed since we're using singleton pattern
|
|
486
581
|
pass
|
|
@@ -775,45 +870,30 @@ class EEGDashDataset(BaseConcatDataset, metaclass=NumpyDocstringInheritanceInitM
|
|
|
775
870
|
) -> list[dict]:
|
|
776
871
|
"""Discover local BIDS EEG files and build minimal records.
|
|
777
872
|
|
|
778
|
-
|
|
779
|
-
``mne_bids.find_matching_paths`` and applies entity filters to produce
|
|
780
|
-
|
|
781
|
-
|
|
873
|
+
Enumerates EEG recordings under ``dataset_root`` using
|
|
874
|
+
``mne_bids.find_matching_paths`` and applies entity filters to produce
|
|
875
|
+
records suitable for :class:`EEGDashBaseDataset`. No network access is
|
|
876
|
+
performed, and files are not read.
|
|
782
877
|
|
|
783
878
|
Parameters
|
|
784
879
|
----------
|
|
785
880
|
dataset_root : Path
|
|
786
|
-
Local dataset directory
|
|
787
|
-
|
|
788
|
-
``
|
|
789
|
-
|
|
790
|
-
Query filters. Must include ``'dataset'`` with the dataset id (without
|
|
791
|
-
local suffixes). May include BIDS entities ``'subject'``,
|
|
792
|
-
``'session'``, ``'task'``, and ``'run'``. Each value can be a scalar
|
|
793
|
-
or a sequence of scalars.
|
|
881
|
+
Local dataset directory (e.g., ``/path/to/cache/ds005509``).
|
|
882
|
+
filters : dict
|
|
883
|
+
Query filters. Must include ``'dataset'`` and may include BIDS
|
|
884
|
+
entities like ``'subject'``, ``'session'``, etc.
|
|
794
885
|
|
|
795
886
|
Returns
|
|
796
887
|
-------
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
- ``'data_name'``
|
|
801
|
-
- ``'dataset'`` (dataset id, without suffixes)
|
|
802
|
-
- ``'bidspath'`` (normalized to start with the dataset id)
|
|
803
|
-
- ``'subject'``, ``'session'``, ``'task'``, ``'run'`` (may be None)
|
|
804
|
-
- ``'bidsdependencies'`` (empty list)
|
|
805
|
-
- ``'modality'`` (``"eeg"``)
|
|
806
|
-
- ``'sampling_frequency'``, ``'nchans'``, ``'ntimes'`` (minimal
|
|
807
|
-
defaults for offline usage)
|
|
888
|
+
list of dict
|
|
889
|
+
A list of records, one for each matched EEG file. Each record
|
|
890
|
+
contains BIDS entities, paths, and minimal metadata for offline use.
|
|
808
891
|
|
|
809
892
|
Notes
|
|
810
893
|
-----
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
first path component is the dataset id (without local cache suffixes).
|
|
815
|
-
- Minimal defaults are set for ``sampling_frequency``, ``nchans``, and
|
|
816
|
-
``ntimes`` to satisfy dataset length requirements offline.
|
|
894
|
+
Matching is performed for ``datatypes=['eeg']`` and ``suffixes=['eeg']``.
|
|
895
|
+
The ``bidspath`` is normalized to ensure it starts with the dataset ID,
|
|
896
|
+
even for suffixed cache directories.
|
|
817
897
|
|
|
818
898
|
"""
|
|
819
899
|
dataset_id = filters["dataset"]
|
|
@@ -875,10 +955,22 @@ class EEGDashDataset(BaseConcatDataset, metaclass=NumpyDocstringInheritanceInitM
|
|
|
875
955
|
return records_out
|
|
876
956
|
|
|
877
957
|
def _find_key_in_nested_dict(self, data: Any, target_key: str) -> Any:
|
|
878
|
-
"""Recursively search for
|
|
958
|
+
"""Recursively search for a key in nested dicts/lists.
|
|
959
|
+
|
|
960
|
+
Performs a case-insensitive and underscore/hyphen-agnostic search.
|
|
961
|
+
|
|
962
|
+
Parameters
|
|
963
|
+
----------
|
|
964
|
+
data : Any
|
|
965
|
+
The nested data structure (dicts, lists) to search.
|
|
966
|
+
target_key : str
|
|
967
|
+
The key to search for.
|
|
968
|
+
|
|
969
|
+
Returns
|
|
970
|
+
-------
|
|
971
|
+
Any
|
|
972
|
+
The value of the first matching key, or None if not found.
|
|
879
973
|
|
|
880
|
-
This makes lookups tolerant to naming differences like "p-factor" vs "p_factor".
|
|
881
|
-
Returns the first match or None.
|
|
882
974
|
"""
|
|
883
975
|
norm_target = normalize_key(target_key)
|
|
884
976
|
if isinstance(data, dict):
|
|
@@ -901,23 +993,25 @@ class EEGDashDataset(BaseConcatDataset, metaclass=NumpyDocstringInheritanceInitM
|
|
|
901
993
|
description_fields: list[str],
|
|
902
994
|
base_dataset_kwargs: dict,
|
|
903
995
|
) -> list[EEGDashBaseDataset]:
|
|
904
|
-
"""
|
|
905
|
-
|
|
996
|
+
"""Find and construct datasets from a MongoDB query.
|
|
997
|
+
|
|
998
|
+
Queries the database, then creates a list of
|
|
999
|
+
:class:`EEGDashBaseDataset` objects from the results.
|
|
906
1000
|
|
|
907
1001
|
Parameters
|
|
908
1002
|
----------
|
|
909
|
-
query : dict
|
|
910
|
-
The query
|
|
911
|
-
description_fields : list
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
constructor.
|
|
1003
|
+
query : dict, optional
|
|
1004
|
+
The MongoDB query to execute.
|
|
1005
|
+
description_fields : list of str
|
|
1006
|
+
Fields to extract from each record for the dataset description.
|
|
1007
|
+
base_dataset_kwargs : dict
|
|
1008
|
+
Additional keyword arguments to pass to the
|
|
1009
|
+
:class:`EEGDashBaseDataset` constructor.
|
|
916
1010
|
|
|
917
1011
|
Returns
|
|
918
1012
|
-------
|
|
919
|
-
list
|
|
920
|
-
A list of
|
|
1013
|
+
list of EEGDashBaseDataset
|
|
1014
|
+
A list of dataset objects matching the query.
|
|
921
1015
|
|
|
922
1016
|
"""
|
|
923
1017
|
datasets: list[EEGDashBaseDataset] = []
|