Skip to content

Commit 9b14298

Browse files
HansujaBpre-commit-ci[bot]autofix-ci[bot]larsoner
authored
ENH: Add initial BCI2000 .dat reader (preload-only) (#13699)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Larson <larson.eric.d@gmail.com>
1 parent 93fb1c8 commit 9b14298

14 files changed

Lines changed: 422 additions & 6 deletions

File tree

doc/api/reading_raw_data.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Reading raw data
1616
read_raw
1717
read_raw_ant
1818
read_raw_artemis123
19+
read_raw_bci2k
1920
read_raw_bdf
2021
read_raw_boxy
2122
read_raw_brainvision
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add support for reading BCI2000 ``.dat`` files via :func:`mne.io.read_raw_bci2k`, and an example :file:`examples/io/read_bci2k.py` for downloading and visualizing BCI2000 data, by :newcontrib:`Hansuja Budhiraja`.

doc/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@
291291
"EpochsEEGLAB": "mne.Epochs",
292292
"EpochsKIT": "mne.Epochs",
293293
"RawANT": "mne.io.Raw",
294+
"RawBCI2k": "mne.io.Raw",
294295
"RawBOXY": "mne.io.Raw",
295296
"RawBrainVision": "mne.io.Raw",
296297
"RawBTi": "mne.io.Raw",

doc/sphinxext/related_software_nodeps.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ cross-domain-saliency-maps
33
fsleyes
44
mne-kit-gui
55
mne-videobrowser
6+
hedtools # because it limits our Pandas version currently

examples/io/read_bci2k.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""
2+
======================
3+
Reading BCI2000 files
4+
======================
5+
6+
In this example, we use MNE-Python to read a BCI2000 ``.dat`` file.
7+
BCI2000 is a general-purpose brain-computer interface (BCI) system widely
8+
used in EEG research. The file is downloaded from the MNE testing data
9+
repository using ``pooch``.
10+
""" # noqa: D205 D400
11+
12+
# Authors: The MNE-Python contributors.
13+
# License: BSD-3-Clause
14+
# Copyright the MNE-Python contributors.
15+
16+
import pooch
17+
18+
import mne
19+
20+
# %%
21+
# First, we download the sample BCI2000 ``.dat`` file using ``pooch``.
22+
23+
data_dir = mne.datasets.default_path() / "bci2k_data"
24+
data_dir.mkdir(exist_ok=True)
25+
26+
fname = pooch.retrieve(
27+
url="https://raw.githubusercontent.com/mne-tools/mne-testing-data/master/BCI2k/bci2k_test.dat",
28+
known_hash="sha256:8efc7b5f700660a044086cb1449806ca408c2e6d32d9338c32e1bf31ce3ca9cb",
29+
path=data_dir,
30+
)
31+
32+
# %%
33+
# Now we can read the file using :func:`mne.io.read_raw_bci2k`.
34+
# Note that ``preload=True`` is required for BCI2000 files.
35+
36+
raw = mne.io.read_raw_bci2k(fname, preload=True)
37+
print(raw.info)
38+
39+
# %%
40+
# We can inspect the object representation, channel names, types, sampling
41+
# frequency, and recording duration.
42+
43+
print(raw)
44+
print(f"Channel names : {raw.ch_names}")
45+
print(f"Channel types : {raw.get_channel_types()}")
46+
print(f"Sampling freq : {raw.info['sfreq']} Hz")
47+
print(f"Duration : {raw.times[-1]:.2f} s")
48+
print(f"n_channels : {raw.info['nchan']}")
49+
print(f"Data shape : {raw.get_data().shape} (n_channels, n_samples)")
50+
51+
# %%
52+
# If the BCI2000 file contains a ``StimulusCode`` state, it is automatically
53+
# mapped to a ``STI 014`` stim channel. We can extract events from it using
54+
# :func:`mne.find_events`.
55+
56+
if "STI 014" in raw.ch_names:
57+
events = mne.find_events(raw, shortest_event=1)
58+
print(f"Found {len(events)} events")
59+
print(mne.count_events(events))
60+
else:
61+
print("No stim channel found in this file.")
62+
63+
# %%
64+
# Finally, we can visualize the raw data.
65+
66+
raw.plot(duration=5, n_channels=len(raw.ch_names), scalings="auto")

mne/datasets/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
# update the checksum in the MNE_DATASETS dict below, and change version
8888
# here: ↓↓↓↓↓↓↓↓
8989
RELEASES = dict(
90-
testing="0.172",
90+
testing="0.173",
9191
misc="0.27",
9292
phantom_kit="0.2",
9393
ucl_opm_auditory="0.2",
@@ -115,7 +115,7 @@
115115
# Testing and misc are at the top as they're updated most often
116116
MNE_DATASETS["testing"] = dict(
117117
archive_name=f"{TESTING_VERSIONED}.tar.gz",
118-
hash="md5:9d031f1a91d2bd903a9464ca2cd7dc09",
118+
hash="md5:0973c25cd0e3ca43a75ea6953ace1daa",
119119
url=(
120120
"https://codeload.github.com/mne-tools/mne-testing-data/"
121121
f"tar.gz/{RELEASES['testing']}"

mne/io/__init__.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ __all__ = [
1919
"read_raw",
2020
"read_raw_ant",
2121
"read_raw_artemis123",
22+
"read_raw_bci2k",
2223
"read_raw_bdf",
2324
"read_raw_boxy",
2425
"read_raw_brainvision",
@@ -65,6 +66,7 @@ from .ant import read_raw_ant
6566
from .array import RawArray
6667
from .artemis123 import read_raw_artemis123
6768
from .base import BaseRaw, concatenate_raws, match_channel_orders
69+
from .bci2k import read_raw_bci2k
6870
from .besa import read_evoked_besa
6971
from .boxy import read_raw_boxy
7072
from .brainvision import read_raw_brainvision

mne/io/_read_raw.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def _get_supported():
2626
from . import (
2727
read_raw_ant,
2828
read_raw_artemis123,
29+
read_raw_bci2k,
2930
read_raw_bdf,
3031
read_raw_boxy,
3132
read_raw_brainvision,
@@ -79,7 +80,10 @@ def _get_supported():
7980
".ds": dict(CTF=read_raw_ctf),
8081
".txt": dict(BOXY=read_raw_boxy),
8182
# Curry
82-
".dat": dict(CURRY=read_raw_curry),
83+
".dat": dict(
84+
CURRY=read_raw_curry,
85+
BCI2K=read_raw_bci2k,
86+
),
8387
".dap": dict(CURRY=read_raw_curry),
8488
".rs3": dict(CURRY=read_raw_curry),
8589
".cdt": dict(CURRY=read_raw_curry),
@@ -130,6 +134,7 @@ def read_raw(fname, *, preload=False, verbose=None, **kwargs) -> BaseRaw:
130134
131135
* `~mne.io.read_raw_ant`
132136
* `~mne.io.read_raw_artemis123`
137+
* `~mne.io.read_raw_bci2k`
133138
* `~mne.io.read_raw_bdf`
134139
* `~mne.io.read_raw_boxy`
135140
* `~mne.io.read_raw_brainvision`

mne/io/bci2k/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Authors: The MNE-Python contributors.
2+
# License: BSD-3-Clause
3+
# Copyright the MNE-Python contributors.
4+
5+
from .bci2k import read_raw_bci2k, RawBCI2k

0 commit comments

Comments
 (0)