Skip to content
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

[ENH] Read annotation duration from SNIRF files. #11397

Merged
merged 7 commits into from
Jan 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/changes/latest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Current (1.4.dev0)

Enhancements
~~~~~~~~~~~~
- None yet
- Added ability to read stimulus durations from SNIRF files when using :func:`mne.io.read_raw_snirf` (:gh:`11397` by `Robert Luke`_)

Bugs
~~~~
Expand Down
2 changes: 1 addition & 1 deletion doc/changes/names.inc
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@

.. _Rasmus Zetter: https://people.aalto.fi/rasmus.zetter

.. _Reza Nasri: https://github.com/0reza
.. _Reza Nasri: https://github.com/rznas

.. _Reza Shoorangiz: https://github.com/rezashr

Expand Down
2 changes: 1 addition & 1 deletion doc/install/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ in the pull request you should describe how the tests are failing and ask for
advice about how to fix them.

To learn more about git, check out the `GitHub help`_ website, the `GitHub
Learning Lab`_ tutorial series, and the `pro git book`_.
skills`_ tutorial series, and the `pro git book`_.


.. _github-ssh:
Expand Down
2 changes: 1 addition & 1 deletion doc/links.inc
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
.. _git: https://git-scm.com/
.. _github: https://github.com
.. _GitHub Help: https://help.github.com
.. _GitHub learning lab: https://lab.github.com/
.. _GitHub skills: https://skills.github.com/
.. _pro git book: https://git-scm.com/book/
.. _git bash: https://gitforwindows.org/
.. _git for Windows: https://gitforwindows.org/
Expand Down
2 changes: 1 addition & 1 deletion doc/overview/roadmap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ as well as:
Kymata atlas. The participants are healthy human adults listening to the
radio and/or watching films, and the data is comprised of (averaged) EEG
and MEG sensor data and source current reconstructions.
- `BNCI Horizon <http://bnci-horizon-2020.eu/database/data-sets>`__
- `BNCI Horizon <https://bnci-horizon-2020.eu/database/data-sets>`__
BCI datasets.

Integrate OpenMEEG via improved Python bindings
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ dependencies:
- pillow
- statsmodels
- jupyter
- ipython !=8.7.0
- joblib
- psutil
- numexpr
Expand Down
6 changes: 5 additions & 1 deletion mne/io/snirf/_snirf.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ def natural_keys(text):
verbose=verbose)

# Extract annotations
# As described at https://github.com/fNIRS/snirf/
# blob/master/snirf_specification.md#nirsistimjdata
annot = Annotations([], [], [])
for key in dat['nirs']:
if 'stim' in key:
Expand All @@ -411,7 +413,9 @@ def natural_keys(text):
if data.size > 0:
desc = _correct_shape(np.array(dat.get(
'/nirs/' + key + '/name')))[0]
annot.append(data[:, 0], 1.0, desc.decode('UTF-8'))
annot.append(data[:, 0],
data[:, 1],
desc.decode('UTF-8'))
self.set_annotations(annot, emit_warning=False)

# Validate that the fNIRS info is correctly formatted
Expand Down
37 changes: 27 additions & 10 deletions mne/io/snirf/tests/test_snirf.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,29 +153,31 @@ def test_snirf_basic():

@requires_testing_data
def test_snirf_against_nirx():
"""Test against file snirf was created from."""
raw = read_raw_snirf(sfnirs_homer_103_wShort, preload=True)
_reorder_nirx(raw)
"""Test Homer generated against file snirf was created from."""
raw_homer = read_raw_snirf(sfnirs_homer_103_wShort, preload=True)
_reorder_nirx(raw_homer)
raw_orig = read_raw_nirx(sfnirs_homer_103_wShort_original, preload=True)

# Check annotations are the same
assert_allclose(raw.annotations.onset, raw_orig.annotations.onset)
assert_allclose([float(d) for d in raw.annotations.description],
assert_allclose(raw_homer.annotations.onset, raw_orig.annotations.onset)
assert_allclose([float(d) for d in raw_homer.annotations.description],
[float(d) for d in raw_orig.annotations.description])
assert_allclose(raw.annotations.duration, raw_orig.annotations.duration)
# Homer writes durations as 5s regardless of the true duration.
# So we will not test that the nirx file stim durations equal
# the homer file stim durations.

# Check names are the same
assert raw.info['ch_names'] == raw_orig.info['ch_names']
assert raw_homer.info['ch_names'] == raw_orig.info['ch_names']

# Check frequencies are the same
num_chans = len(raw.ch_names)
new_chs = raw.info['chs']
num_chans = len(raw_homer.ch_names)
new_chs = raw_homer.info['chs']
ori_chs = raw_orig.info['chs']
assert_allclose([new_chs[idx]['loc'][9] for idx in range(num_chans)],
[ori_chs[idx]['loc'][9] for idx in range(num_chans)])

# Check data is the same
assert_allclose(raw.get_data(), raw_orig.get_data())
assert_allclose(raw_homer.get_data(), raw_orig.get_data())


@requires_testing_data
Expand Down Expand Up @@ -388,3 +390,18 @@ def test_annotation_description_from_stim_groups():
raw = read_raw_snirf(nirx_nirsport2_103_2, preload=True)
expected_descriptions = ['1', '2', '6']
assert_equal(expected_descriptions, raw.annotations.description)


@requires_testing_data
def test_annotation_duration_from_stim_groups():
"""Test annotation durations extracted correctly from stim group."""
raw = read_raw_snirf(snirf_nirsport2_20219, preload=True)
# Specify the expected SNIRF stim durations.
# We can verify these values should be 10 by using the official
# SNIRF package pysnirf2 and running the following script.
# You will see that the print statement shows the middle column,
# which represents duration, will be all 10s.
# from snirf import Snirf
# a = Snirf(snirf_nirsport2_20219, "r+"); print(a.nirs[0].stim[0].data)
expected_durations = np.full((10,), 10.)
assert_equal(expected_durations, raw.annotations.duration)