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

MRG: Add support for NIRS to plot_topomap #7063

Merged
merged 16 commits into from
Nov 18, 2019
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: 2 additions & 0 deletions doc/changes/latest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ Changelog

- Allow returning vector source estimates from sparse inverse solvers through ``pick_ori='vector'`` by `Christian Brodbeck`_

- Add NIRS support to :func:`mne.viz.plot_topomap` by `Robert Luke`_

Bug
~~~

Expand Down
3 changes: 2 additions & 1 deletion mne/channels/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ def _get_ch_type(inst, ch_type, allow_ref_meg=False):
then grads, then ... to plot.
"""
if ch_type is None:
allowed_types = ['mag', 'grad', 'planar1', 'planar2', 'eeg', 'csd']
allowed_types = ['mag', 'grad', 'planar1', 'planar2', 'eeg', 'csd',
'fnirs_raw', 'fnirs_od', 'hbo', 'hbr']
allowed_types += ['ref_meg'] if allow_ref_meg else []
for type_ in allowed_types:
if isinstance(inst, Info):
Expand Down
2 changes: 1 addition & 1 deletion mne/io/nirx/nirx.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def prepend(list, str):
list = [str.format(i) for i in list]
return(list)
snames = prepend(sources[req_ind], 'S')
dnames = prepend(detectors[req_ind], '-D')
dnames = prepend(detectors[req_ind], '_D')
sdnames = [m + str(n) for m, n in zip(snames, dnames)]
sd1 = [s + ' ' + str(fnirs_wavelengths[0]) for s in sdnames]
sd2 = [s + ' ' + str(fnirs_wavelengths[1]) for s in sdnames]
Expand Down
22 changes: 11 additions & 11 deletions mne/io/nirx/tests/test_nirx.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ def test_nirx_15_2_short():
assert raw.info['sfreq'] == 12.5

# Test channel naming
assert raw.info['ch_names'][:4] == ["S1-D1 760", "S1-D1 850",
"S1-D9 760", "S1-D9 850"]
assert raw.info['ch_names'][24:26] == ["S5-D13 760", "S5-D13 850"]
assert raw.info['ch_names'][:4] == ["S1_D1 760", "S1_D1 850",
"S1_D9 760", "S1_D9 850"]
assert raw.info['ch_names'][24:26] == ["S5_D13 760", "S5_D13 850"]

# Test frequency encoding
assert raw.info['chs'][0]['loc'][9] == 760
Expand Down Expand Up @@ -123,8 +123,8 @@ def test_nirx_15_2():
assert raw.info['sfreq'] == 3.90625

# Test channel naming
assert raw.info['ch_names'][:4] == ["S1-D1 760", "S1-D1 850",
"S1-D10 760", "S1-D10 850"]
assert raw.info['ch_names'][:4] == ["S1_D1 760", "S1_D1 850",
"S1_D10 760", "S1_D10 850"]

# Test info import
assert raw.info['subject_info'] == dict(sex=1, first_name="TestRecording")
Expand Down Expand Up @@ -157,12 +157,12 @@ def test_nirx_15_0():
assert raw.info['sfreq'] == 6.25

# Test channel naming
assert raw.info['ch_names'][:12] == ["S1-D1 760", "S1-D1 850",
"S2-D2 760", "S2-D2 850",
"S3-D3 760", "S3-D3 850",
"S4-D4 760", "S4-D4 850",
"S5-D5 760", "S5-D5 850",
"S6-D6 760", "S6-D6 850"]
assert raw.info['ch_names'][:12] == ["S1_D1 760", "S1_D1 850",
"S2_D2 760", "S2_D2 850",
"S3_D3 760", "S3_D3 850",
"S4_D4 760", "S4_D4 850",
"S5_D5 760", "S5_D5 850",
"S6_D6 760", "S6_D6 850"]

# Test info import
assert raw.info['subject_info'] == {'first_name': 'NIRX',
Expand Down
4 changes: 2 additions & 2 deletions mne/preprocessing/nirs/_beer_lambert_law.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ def _check_channels_ordered(raw, freqs):
# and have the specified light frequencies.
picks = _picks_to_idx(raw.info, 'fnirs_od')
for ii in picks[::2]:
ch1_name_info = re.match(r'S(\d+)-D(\d+) (\d+)',
ch1_name_info = re.match(r'S(\d+)_D(\d+) (\d+)',
raw.info['chs'][ii]['ch_name'])
ch2_name_info = re.match(r'S(\d+)-D(\d+) (\d+)',
ch2_name_info = re.match(r'S(\d+)_D(\d+) (\d+)',
raw.info['chs'][ii + 1]['ch_name'])

if (ch1_name_info.groups()[0] != ch2_name_info.groups()[0]) or \
Expand Down
2 changes: 1 addition & 1 deletion mne/preprocessing/tests/test_beer_lambert_law.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,6 @@ def test_beer_lambert_v_matlab():
raw._data[idx])
assert mean_error < 0.1
matlab_name = ("S" + str(int(matlab_data['sources'][idx])) +
"-D" + str(int(matlab_data['detectors'][idx])) +
"_D" + str(int(matlab_data['detectors'][idx])) +
" " + matlab_data['type'][idx])
assert raw.info['ch_names'][idx] == matlab_name
3 changes: 3 additions & 0 deletions mne/viz/topomap.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ def _prepare_topo_plot(inst, ch_type, layout):
elif ch_type == 'csd':
picks = pick_types(info, meg=False, csd=True, ref_meg=False,
exclude='bads')
elif ch_type in ['hbo', 'hbr', 'fnirs_raw', 'fnirs_od']:
picks = pick_types(info, meg=False, ref_meg=False,
fnirs=ch_type, exclude='bads')
else:
picks = pick_types(info, meg=ch_type, ref_meg=False,
exclude='bads')
Expand Down
61 changes: 60 additions & 1 deletion tutorials/preprocessing/plot_70_fnirs_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
# sphinx_gallery_thumbnail_number = 3

import os
import numpy as np
import matplotlib.pyplot as plt

import mne
Expand Down Expand Up @@ -162,7 +163,7 @@
# Plot standard fNIRS response image
# ----------------------------------
#
# Finally we generate the most common visualisation of fNIRS data, plotting
# Next we generate the most common visualisation of fNIRS data, plotting
# both the HbO and HbR on the same figure to illustrate the relation between
# the two signals.

Expand All @@ -180,3 +181,61 @@

mne.viz.plot_compare_evokeds(evoked_dict, combine="mean", ci=0.95,
colors=color_dict, styles=styles_dict)


###############################################################################
# View topographic representation of activity
# -------------------------------------------
#
# Next we view how the topographic activity changes throughout the response.

times = np.arange(-3.5, 13.2, 3.0)
epochs['Tapping'].average(picks='hbo').plot_joint(times=times)


###############################################################################
# Compare tapping of left and right hands
# ---------------------------------------
#
# Finally we generate topo maps for the left and right conditions to view
# the location of activity. First we visualise the HbO activity.

times = np.arange(4.0, 11.0, 1.0)
epochs['Tapping/Left'].average(picks='hbo').plot_topomap(times=times)
epochs['Tapping/Right'].average(picks='hbo').plot_topomap(times=times)

###############################################################################
# And we also view the HbR activity for the two conditions.

epochs['Tapping/Left'].average(picks='hbr').plot_topomap(times=times)
epochs['Tapping/Right'].average(picks='hbr').plot_topomap(times=times)

###############################################################################
# And we can plot the comparison at a single time point for two conditions.

fig, axes = plt.subplots(nrows=2, ncols=4, figsize=(9, 5))
vmin, vmax, ts = -8, 8, 9.0

evoked_left = epochs['Tapping/Left'].average()
evoked_right = epochs['Tapping/Right'].average()

evoked_left.plot_topomap(ch_type='hbo', times=ts, axes=axes[0, 0],
vmin=vmin, vmax=vmax, colorbar=False)
evoked_left.plot_topomap(ch_type='hbr', times=ts, axes=axes[1, 0],
vmin=vmin, vmax=vmax, colorbar=False)
evoked_right.plot_topomap(ch_type='hbo', times=ts, axes=axes[0, 1],
vmin=vmin, vmax=vmax, colorbar=False)
evoked_right.plot_topomap(ch_type='hbr', times=ts, axes=axes[1, 1],
vmin=vmin, vmax=vmax, colorbar=False)

evoked_diff = mne.combine_evoked([evoked_left, -evoked_right], weights='equal')

evoked_diff.plot_topomap(ch_type='hbo', times=ts, axes=axes[0, 2],
vmin=vmin, vmax=vmax)
evoked_diff.plot_topomap(ch_type='hbr', times=ts, axes=axes[1, 2],
vmin=vmin, vmax=vmax, colorbar=True)

for column, condition in enumerate(
['Tapping Left', 'Tapping Right', 'Left-Right']):
for row, chroma in enumerate(['HbO', 'HbR']):
axes[row, column].set_title('{}: {}'.format(chroma, condition))