-
Notifications
You must be signed in to change notification settings - Fork 98
add support for EMG data #1129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
add support for EMG data #1129
Changes from 21 commits
d81ead8
e214d25
1e9fde4
b3f8b98
2019f40
eb4a3f3
a0532a8
c84882c
f345306
9026973
347dab7
acdcc18
97397a7
c1d70c5
28a4c78
39c745b
a27a7a2
3977590
f4e0a03
8cf38c3
bfbdf1d
7432aba
571f7c2
50388b4
44ce4cc
08e6939
b89c159
31ee317
f53a4e2
7d6b576
ad30c6a
14f4a71
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,18 +13,20 @@ | |
|
|
||
| DOI = """https://doi.org/10.21105/joss.01896""" | ||
|
|
||
| EPHY_ALLOWED_DATATYPES = ["meg", "eeg", "ieeg", "nirs"] | ||
| EPHY_ALLOWED_DATATYPES = ["eeg", "emg", "ieeg", "meg", "nirs"] | ||
|
|
||
| ALLOWED_DATATYPES = EPHY_ALLOWED_DATATYPES + ["anat", "beh", "motion"] | ||
|
|
||
| MEG_CONVERT_FORMATS = ["FIF", "auto"] | ||
| EEG_CONVERT_FORMATS = ["BrainVision", "auto"] | ||
| EMG_CONVERT_FORMATS = ["EDF", "BDF", "auto"] | ||
| IEEG_CONVERT_FORMATS = ["BrainVision", "auto"] | ||
| NIRS_CONVERT_FORMATS = ["auto"] | ||
| MOTION_CONVERT_FORMATS = ["tsv", "auto"] | ||
| CONVERT_FORMATS = { | ||
| "meg": MEG_CONVERT_FORMATS, | ||
| "eeg": EEG_CONVERT_FORMATS, | ||
| "emg": EMG_CONVERT_FORMATS, | ||
| "ieeg": IEEG_CONVERT_FORMATS, | ||
| "nirs": NIRS_CONVERT_FORMATS, | ||
| "motion": MOTION_CONVERT_FORMATS, | ||
|
|
@@ -86,6 +88,13 @@ | |
| ".EEG": "Nihon Kohden", | ||
| } | ||
|
|
||
| emg_manufacturers = { | ||
| ".edf": "n/a", | ||
| ".EDF": "n/a", | ||
| ".bdf": "Biosemi", | ||
| ".BDF": "Biosemi", | ||
| } | ||
|
|
||
| nirs_manufacturers = {".snirf": "SNIRF"} | ||
|
|
||
| # file-extension map to mne-python readers | ||
|
|
@@ -117,6 +126,7 @@ | |
| MANUFACTURERS = dict() | ||
| MANUFACTURERS.update(meg_manufacturers) | ||
| MANUFACTURERS.update(eeg_manufacturers) | ||
| MANUFACTURERS.update(emg_manufacturers) | ||
| MANUFACTURERS.update(ieeg_manufacturers) | ||
| MANUFACTURERS.update(nirs_manufacturers) | ||
|
|
||
|
|
@@ -137,6 +147,11 @@ | |
| ".set", # EEGLAB, potentially accompanied by .fdt | ||
| ] | ||
|
|
||
| allowed_extensions_emg = [ | ||
| ".edf", # European Data Format | ||
| ".bdf", # Biosemi | ||
| ] | ||
|
|
||
| allowed_extensions_ieeg = [ | ||
| ".vhdr", # BrainVision, accompanied by .vmrk, .eeg | ||
| ".edf", # European Data Format | ||
|
|
@@ -157,6 +172,7 @@ | |
| ALLOWED_DATATYPE_EXTENSIONS = { | ||
| "meg": allowed_extensions_meg, | ||
| "eeg": allowed_extensions_eeg, | ||
| "emg": allowed_extensions_emg, | ||
| "ieeg": allowed_extensions_ieeg, | ||
| "nirs": allowed_extensions_nirs, | ||
| "motion": allowed_extensions_motion, | ||
|
|
@@ -165,39 +181,48 @@ | |
| # allow additional extensions that are not BIDS | ||
| # compliant, but we will convert to the | ||
| # recommended formats | ||
| ALLOWED_INPUT_EXTENSIONS = ( | ||
| allowed_extensions_meg | ||
| + allowed_extensions_eeg | ||
| + allowed_extensions_ieeg | ||
| + allowed_extensions_nirs | ||
| + [".lay", ".EEG", ".cnt", ".CNT", ".bin", ".cdt"] | ||
| ALLOWED_INPUT_EXTENSIONS = sorted( | ||
| set( | ||
| allowed_extensions_meg | ||
| + allowed_extensions_eeg | ||
| + allowed_extensions_emg | ||
| + allowed_extensions_ieeg | ||
| + allowed_extensions_nirs | ||
| + [".lay", ".EEG", ".cnt", ".CNT", ".bin", ".cdt"] | ||
| ) | ||
| ) | ||
|
|
||
|
|
||
| # allowed suffixes (i.e. last "_" delimiter in the BIDS filenames before | ||
| # the extension) | ||
| ALLOWED_FILENAME_SUFFIX = [ | ||
| # datatypes: | ||
| "meg", | ||
| "markers", | ||
| "eeg", | ||
| "ieeg", | ||
| "emg", | ||
| "nirs", | ||
| "T1w", | ||
| "T2w", | ||
| "FLASH", # datatype | ||
| "FLASH", | ||
| # sidecars: | ||
| "participants", | ||
| "scans", | ||
| "sessions", | ||
| "electrodes", | ||
| "optodes", | ||
| "channels", | ||
| "coordsystem", | ||
| "events", # sidecars | ||
| "events", | ||
| # MEG-specific sidecars: | ||
| "headshape", | ||
| "digitizer", # meg-specific sidecars | ||
| "digitizer", | ||
| # behavioral: | ||
| "beh", | ||
| "physio", | ||
| "stim", # behavioral | ||
| "nirs", | ||
| "motion", # motion | ||
| "stim", | ||
| "motion", | ||
| ] | ||
|
|
||
| # converts suffix to known path modalities | ||
|
|
@@ -208,6 +233,7 @@ | |
| "markers": "meg", | ||
| "eeg": "eeg", | ||
| "ieeg": "ieeg", | ||
| "emg": "emg", | ||
| "T1w": "anat", | ||
| "FLASH": "anat", | ||
| } | ||
|
|
@@ -216,9 +242,9 @@ | |
| ALLOWED_FILENAME_EXTENSIONS = ( | ||
| ALLOWED_INPUT_EXTENSIONS | ||
| + [".json", ".tsv", ".tsv.gz", ".nii", ".nii.gz"] | ||
| + [".pos", ".eeg", ".vmrk"] | ||
| + [".dat", ".EEG"] # extra datatype-specific metadata files. | ||
| + [".mrk"] # extra eeg extensions # KIT/Yokogawa/Ricoh marker coil | ||
| + [".pos", ".eeg", ".vmrk"] # extra datatype-specific metadata files. | ||
| + [".dat", ".EEG"] # extra eeg extensions | ||
| + [".mrk"] # KIT/Yokogawa/Ricoh marker coil | ||
|
Comment on lines
+246
to
+248
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. another unrelated-to-EMG fix of bad autoformatter comment placement |
||
| ) | ||
|
|
||
| # allowed BIDSPath entities | ||
|
|
@@ -317,13 +343,26 @@ | |
| + coordsys_wildcard | ||
| ) | ||
|
|
||
|
|
||
| # EMG allows arbitrary (user-defined) coord frames | ||
| class EmgCoordFrames(list): | ||
| """Container for arbitrary (user-defined) coordinate frames (spaces).""" | ||
|
|
||
| def __contains__(self, item): | ||
| """Pretends to contain any non-empty string.""" | ||
| return isinstance(item, str) and len(item) | ||
|
|
||
|
|
||
| BIDS_EMG_COORDINATE_FRAMES = EmgCoordFrames() | ||
|
Comment on lines
+348
to
+357
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this may be a bit too clever; EMG-BIDS allows coordsys spaces to have arbitrary (user-defined) names, and this is a way to make that possible (avoid "space entity is not valid for datatype EMG" errors) without disabling the existing checking mechanisms. Open to other approaches if this doesn't sit well with somebody. |
||
|
|
||
| ALLOWED_SPACES = dict() | ||
| ALLOWED_SPACES["meg"] = ALLOWED_SPACES["eeg"] = ( | ||
| BIDS_SHARED_COORDINATE_FRAMES | ||
| + BIDS_MEG_COORDINATE_FRAMES | ||
| + BIDS_EEG_COORDINATE_FRAMES | ||
| ) | ||
| ALLOWED_SPACES["ieeg"] = BIDS_SHARED_COORDINATE_FRAMES + BIDS_IEEG_COORDINATE_FRAMES | ||
| ALLOWED_SPACES["emg"] = BIDS_EMG_COORDINATE_FRAMES | ||
| ALLOWED_SPACES["anat"] = None | ||
| ALLOWED_SPACES["beh"] = None | ||
| ALLOWED_SPACES["motion"] = None | ||
|
|
@@ -463,9 +502,9 @@ | |
| for sym in ("Sym", "Asym"): | ||
| BIDS_COORD_FRAME_DESCRIPTIONS[f"mni152nlin2009{letter}{sym}"] = ( | ||
| "Also known as ICBM (non-linear coregistration with 40 iterations," | ||
| " released in 2009). It comes in three different flavours " | ||
| "each in symmetric or asymmetric version." | ||
|
Comment on lines
+506
to
+507
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. another unrelated autoformatter snafu fix |
||
| ) | ||
| " released in 2009). It comes in either three different flavours " | ||
| "each in symmetric or asymmetric version." | ||
|
|
||
| REFERENCES = { | ||
| "mne-bids": "Appelhoff, S., Sanderson, M., Brooks, T., Vliet, M., " | ||
|
|
@@ -499,6 +538,7 @@ | |
| "Pollonini, L. (2023). fNIRS-BIDS, the Brain Imaging Data Structure " | ||
| "Extended to Functional Near-Infrared Spectroscopy. PsyArXiv. " | ||
| "https://doi.org/10.31219/osf.io/7nmcp", | ||
| "emg": "In preparation", | ||
| } | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1939,7 +1939,18 @@ def get_datatypes(root, verbose=None): | |
| # Take all possible data types from "entity" table | ||
| # (Appendix in BIDS spec) | ||
| # https://bids-specification.readthedocs.io/en/latest/appendices/entity-table.html | ||
| datatype_list = ("anat", "func", "dwi", "fmap", "beh", "meg", "eeg", "ieeg", "nirs") | ||
| datatype_list = ( | ||
| "anat", | ||
| "beh", | ||
| "dwi", | ||
| "eeg", | ||
| "emg", | ||
| "fmap", | ||
| "func", | ||
| "ieeg", | ||
| "meg", | ||
| "nirs", | ||
|
Comment on lines
+1945
to
+1954
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added EMG and also sorted the entries |
||
| ) | ||
| datatypes = list() | ||
| for root, dirs, files in os.walk(root): | ||
| for _dir in dirs: | ||
|
|
@@ -2301,7 +2312,7 @@ def _infer_datatype(*, root, sub, ses): | |
| modalities = _get_datatypes_for_sub(root=root, sub=sub, ses=ses) | ||
|
|
||
| # We only want to handle electrophysiological data here. | ||
| allowed_recording_modalities = ["meg", "eeg", "ieeg"] | ||
| allowed_recording_modalities = ["eeg", "emg", "ieeg", "meg"] | ||
| modalities = list(set(modalities) & set(allowed_recording_modalities)) | ||
| if not modalities: | ||
| raise ValueError("No electrophysiological data found.") | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the only new line here; the rest of the changes to this list are just un-doing some bad comment placement arising from a past autoformatter snafu