Skip to content
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 mne/channels/interpolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def _interpolate_bads_nirs(inst, method='nearest', exclude=(), verbose=None):

# Returns pick of all nirs and ensures channels are correctly ordered
freqs = np.unique(_channel_frequencies(inst))
picks_nirs = _check_channels_ordered(inst, freqs)
picks_nirs = _check_channels_ordered(inst.info, freqs)
if len(picks_nirs) == 0:
return

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 @@ -35,7 +35,7 @@ def beer_lambert_law(raw, ppf=0.1):
_validate_type(raw, BaseRaw, 'raw')

freqs = np.unique(_channel_frequencies(raw))
picks = _check_channels_ordered(raw, freqs)
picks = _check_channels_ordered(raw.info, freqs)
abs_coef = _load_absorption(freqs)
distances = source_detector_distances(raw.info)

Expand All @@ -57,7 +57,7 @@ def beer_lambert_law(raw, ppf=0.1):

# Validate the format of data after transformation is valid
chroma = np.unique(_channel_chromophore(raw))
_check_channels_ordered(raw, chroma)
_check_channels_ordered(raw.info, chroma)
return raw


Expand Down
2 changes: 1 addition & 1 deletion mne/preprocessing/nirs/_optical_density.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def optical_density(raw):
"""
raw = raw.copy().load_data()
_validate_type(raw, BaseRaw, 'raw')
_check_channels_ordered(raw, np.unique(_channel_frequencies(raw)))
_check_channels_ordered(raw.info, np.unique(_channel_frequencies(raw)))

picks = _picks_to_idx(raw.info, 'fnirs_cw_amplitude')
data_means = np.mean(raw.get_data(), axis=1)
Expand Down
2 changes: 1 addition & 1 deletion mne/preprocessing/nirs/_scalp_coupling_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def scalp_coupling_index(raw, l_freq=0.7, h_freq=1.5,
'should be run on optical density data.')

freqs = np.unique(_channel_frequencies(raw))
picks = _check_channels_ordered(raw, freqs)
picks = _check_channels_ordered(raw.info, freqs)

filtered_data = filter_data(raw._data, raw.info['sfreq'], l_freq, h_freq,
picks=picks, verbose=verbose,
Expand Down
2 changes: 1 addition & 1 deletion mne/preprocessing/nirs/_tddr.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def temporal_derivative_distribution_repair(raw, *, verbose=None):
"""
raw = raw.copy().load_data()
_validate_type(raw, BaseRaw, 'raw')
_check_channels_ordered(raw, np.unique(_channel_frequencies(raw)))
_check_channels_ordered(raw.info, np.unique(_channel_frequencies(raw)))

if not len(pick_types(raw.info, fnirs='fnirs_od')):
raise RuntimeError('TDDR should be run on optical density data.')
Expand Down
38 changes: 19 additions & 19 deletions mne/preprocessing/nirs/nirs.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,16 @@ def _channel_chromophore(raw):
return chroma


def _check_channels_ordered(raw, pair_vals):
def _check_channels_ordered(info, pair_vals):
"""Check channels follow expected fNIRS format."""
# Every second channel should be same SD pair
# and have the specified light frequencies.

# All wavelength based fNIRS data.
picks_wave = _picks_to_idx(raw.info, ['fnirs_cw_amplitude', 'fnirs_od'],
picks_wave = _picks_to_idx(info, ['fnirs_cw_amplitude', 'fnirs_od'],
exclude=[], allow_empty=True)
# All chromophore fNIRS data
picks_chroma = _picks_to_idx(raw.info, ['hbo', 'hbr'],
picks_chroma = _picks_to_idx(info, ['hbo', 'hbr'],
exclude=[], allow_empty=True)
# All continuous wave fNIRS data
picks_cw = np.hstack([picks_chroma, picks_wave])
Expand All @@ -99,46 +99,46 @@ def _check_channels_ordered(raw, pair_vals):
if len(picks_cw) % 2 != 0:
raise ValueError(
'NIRS channels not ordered correctly. An even number of NIRS '
f'channels is required. {len(raw.ch_names)} channels were'
f'provided: {raw.ch_names}')
f'channels is required. {len(info.ch_names)} channels were'
f'provided: {info.ch_names}')

# Ensure wavelength info exists for waveform data
all_freqs = [raw.info["chs"][ii]["loc"][9] for ii in picks_wave]
all_freqs = [info["chs"][ii]["loc"][9] for ii in picks_wave]
if np.any(np.isnan(all_freqs)):
raise ValueError(
'NIRS channels is missing wavelength information in the'
f'info["chs"] structure. The encoded wavelengths are {all_freqs}.')

for ii in picks_cw[::2]:
ch1_name_info = re.match(r'S(\d+)_D(\d+) (\d+)',
raw.info['chs'][ii]['ch_name'])
info['chs'][ii]['ch_name'])
ch2_name_info = re.match(r'S(\d+)_D(\d+) (\d+)',
raw.info['chs'][ii + 1]['ch_name'])
info['chs'][ii + 1]['ch_name'])

if bool(ch2_name_info) & bool(ch1_name_info):

if raw.info['chs'][ii]['loc'][9] != \
if info['chs'][ii]['loc'][9] != \
float(ch1_name_info.groups()[2]) or \
raw.info['chs'][ii + 1]['loc'][9] != \
info['chs'][ii + 1]['loc'][9] != \
float(ch2_name_info.groups()[2]):
raise ValueError(
'NIRS channels not ordered correctly. '
'Channel name and NIRS'
' frequency do not match: %s -> %s & %s -> %s'
% (raw.info['chs'][ii]['ch_name'],
raw.info['chs'][ii]['loc'][9],
raw.info['chs'][ii + 1]['ch_name'],
raw.info['chs'][ii + 1]['loc'][9]))
% (info['chs'][ii]['ch_name'],
info['chs'][ii]['loc'][9],
info['chs'][ii + 1]['ch_name'],
info['chs'][ii + 1]['loc'][9]))

first_value = int(ch1_name_info.groups()[2])
second_value = int(ch2_name_info.groups()[2])
error_word = "frequencies"

else:
ch1_name_info = re.match(r'S(\d+)_D(\d+) (\w+)',
raw.info['chs'][ii]['ch_name'])
info['chs'][ii]['ch_name'])
ch2_name_info = re.match(r'S(\d+)_D(\d+) (\w+)',
raw.info['chs'][ii + 1]['ch_name'])
info['chs'][ii + 1]['ch_name'])

if bool(ch2_name_info) & bool(ch1_name_info):

Expand All @@ -152,14 +152,14 @@ def _check_channels_ordered(raw, pair_vals):
"NIRS channels have specified naming conventions."
"Chromophore data must be labeled either hbo or hbr."
"Failing channels are "
f"{raw.info['chs'][ii]['ch_name']}, "
f"{raw.info['chs'][ii + 1]['ch_name']}")
f"{info['chs'][ii]['ch_name']}, "
f"{info['chs'][ii + 1]['ch_name']}")

else:
raise ValueError(
'NIRS channels have specified naming conventions.'
'The provided channel names can not be parsed.'
f'Channels are {raw.ch_names}')
f'Channels are {info.ch_names}')

if (ch1_name_info.groups()[0] != ch2_name_info.groups()[0]) or \
(ch1_name_info.groups()[1] != ch2_name_info.groups()[1]) or \
Expand Down
46 changes: 23 additions & 23 deletions mne/preprocessing/nirs/tests/test_nirs.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,32 +162,32 @@ def test_fnirs_channel_naming_and_order_readers(fname):
chroma = np.unique(_channel_chromophore(raw))
assert len(chroma) == 0

picks = _check_channels_ordered(raw, freqs)
picks = _check_channels_ordered(raw.info, freqs)
assert len(picks) == len(raw.ch_names) # as all fNIRS only data

# Check that dropped channels are detected
# For each source detector pair there must be two channels,
# removing one should throw an error.
raw_dropped = raw.copy().drop_channels(raw.ch_names[4])
with pytest.raises(ValueError, match='not ordered correctly'):
_check_channels_ordered(raw_dropped, freqs)
_check_channels_ordered(raw_dropped.info, freqs)

# The ordering must match the passed in argument
raw_names_reversed = raw.copy().ch_names
raw_names_reversed.reverse()
raw_reversed = raw.copy().pick_channels(raw_names_reversed, ordered=True)
with pytest.raises(ValueError, match='not ordered .* frequencies'):
_check_channels_ordered(raw_reversed, freqs)
_check_channels_ordered(raw_reversed.info, freqs)
# So if we flip the second argument it should pass again
_check_channels_ordered(raw_reversed, [850, 760])
_check_channels_ordered(raw_reversed.info, [850, 760])

# Check on OD data
raw = optical_density(raw)
freqs = np.unique(_channel_frequencies(raw))
assert_array_equal(freqs, [760, 850])
chroma = np.unique(_channel_chromophore(raw))
assert len(chroma) == 0
picks = _check_channels_ordered(raw, freqs)
picks = _check_channels_ordered(raw.info, freqs)
assert len(picks) == len(raw.ch_names) # as all fNIRS only data

# Check on haemoglobin data
Expand All @@ -197,10 +197,10 @@ def test_fnirs_channel_naming_and_order_readers(fname):
assert len(_channel_chromophore(raw)) == len(raw.ch_names)
chroma = np.unique(_channel_chromophore(raw))
assert_array_equal(chroma, ["hbo", "hbr"])
picks = _check_channels_ordered(raw, chroma)
picks = _check_channels_ordered(raw.info, chroma)
assert len(picks) == len(raw.ch_names)
with pytest.raises(ValueError, match='not ordered .* chromophore'):
_check_channels_ordered(raw, ["hbx", "hbr"])
_check_channels_ordered(raw.info, ["hbx", "hbr"])


def test_fnirs_channel_naming_and_order_custom_raw():
Expand All @@ -219,7 +219,7 @@ def test_fnirs_channel_naming_and_order_custom_raw():
raw.info["chs"][idx]["loc"][9] = f

freqs = np.unique(_channel_frequencies(raw))
picks = _check_channels_ordered(raw, freqs)
picks = _check_channels_ordered(raw.info, freqs)
assert len(picks) == len(raw.ch_names)
assert len(picks) == 6

Expand All @@ -233,7 +233,7 @@ def test_fnirs_channel_naming_and_order_custom_raw():
for idx, f in enumerate(freqs):
raw.info["chs"][idx]["loc"][9] = f

picks = _check_channels_ordered(raw, [920, 850])
picks = _check_channels_ordered(raw.info, [920, 850])
assert len(picks) == len(raw.ch_names)
assert len(picks) == 6

Expand All @@ -249,7 +249,7 @@ def test_fnirs_channel_naming_and_order_custom_raw():
for idx, f in enumerate(freqs):
raw.info["chs"][idx]["loc"][9] = f
with pytest.raises(ValueError, match='name and NIRS frequency do not'):
_check_channels_ordered(raw, [920, 850])
_check_channels_ordered(raw.info, [920, 850])

# Catch if someone doesn't set the info field
ch_names = ['S1_D1 760', 'S1_D1 850', 'S2_D1 760', 'S2_D1 850',
Expand All @@ -258,7 +258,7 @@ def test_fnirs_channel_naming_and_order_custom_raw():
info = create_info(ch_names=ch_names, ch_types=ch_types, sfreq=1.0)
raw = RawArray(data, info, verbose=True)
with pytest.raises(ValueError, match='missing wavelength information'):
_check_channels_ordered(raw, [920, 850])
_check_channels_ordered(raw.info, [920, 850])

# I have seen data encoded not in alternating frequency, but blocked.
ch_names = ['S1_D1 760', 'S2_D1 760', 'S3_D1 760',
Expand All @@ -270,10 +270,10 @@ def test_fnirs_channel_naming_and_order_custom_raw():
for idx, f in enumerate(freqs):
raw.info["chs"][idx]["loc"][9] = f
with pytest.raises(ValueError, match='channels not ordered correctly'):
_check_channels_ordered(raw, [760, 850])
_check_channels_ordered(raw.info, [760, 850])
# and this is how you would fix the ordering, then it should pass
raw.pick(picks=[0, 3, 1, 4, 2, 5])
_check_channels_ordered(raw, [760, 850])
_check_channels_ordered(raw.info, [760, 850])


def test_fnirs_channel_naming_and_order_custom_optical_density():
Expand All @@ -292,7 +292,7 @@ def test_fnirs_channel_naming_and_order_custom_optical_density():
raw.info["chs"][idx]["loc"][9] = f

freqs = np.unique(_channel_frequencies(raw))
picks = _check_channels_ordered(raw, freqs)
picks = _check_channels_ordered(raw.info, freqs)
assert len(picks) == len(raw.ch_names)
assert len(picks) == 6

Expand All @@ -306,10 +306,10 @@ def test_fnirs_channel_naming_and_order_custom_optical_density():
for idx, f in enumerate(freqs):
raw.info["chs"][idx]["loc"][9] = f
with pytest.raises(ValueError, match='channels not ordered correctly'):
_check_channels_ordered(raw, [760, 850])
_check_channels_ordered(raw.info, [760, 850])
# and this is how you would fix the ordering, then it should pass
raw.pick(picks=[0, 3, 1, 4, 2, 5])
_check_channels_ordered(raw, [760, 850])
_check_channels_ordered(raw.info, [760, 850])

# Check that if you mix types you get an error
ch_names = ['S1_D1 hbo', 'S1_D1 hbr', 'S2_D1 hbo', 'S2_D1 hbr',
Expand All @@ -319,7 +319,7 @@ def test_fnirs_channel_naming_and_order_custom_optical_density():
raw2 = RawArray(data, info, verbose=True)
raw.add_channels([raw2])
with pytest.raises(ValueError, match='does not support a combination'):
_check_channels_ordered(raw, [760, 850])
_check_channels_ordered(raw.info, [760, 850])


def test_fnirs_channel_naming_and_order_custom_chroma():
Expand All @@ -335,7 +335,7 @@ def test_fnirs_channel_naming_and_order_custom_chroma():
raw = RawArray(data, info, verbose=True)

chroma = np.unique(_channel_chromophore(raw))
picks = _check_channels_ordered(raw, chroma)
picks = _check_channels_ordered(raw.info, chroma)
assert len(picks) == len(raw.ch_names)
assert len(picks) == 6

Expand All @@ -346,13 +346,13 @@ def test_fnirs_channel_naming_and_order_custom_chroma():
info = create_info(ch_names=ch_names, ch_types=ch_types, sfreq=1.0)
raw = RawArray(data, info, verbose=True)
with pytest.raises(ValueError, match='not ordered .* chromophore'):
_check_channels_ordered(raw, ["hbo", "hbr"])
_check_channels_ordered(raw.info, ["hbo", "hbr"])
# Reordering should fix
raw.pick(picks=[0, 3, 1, 4, 2, 5])
_check_channels_ordered(raw, ["hbo", "hbr"])
_check_channels_ordered(raw.info, ["hbo", "hbr"])
# Wrong names should fail
with pytest.raises(ValueError, match='not ordered .* chromophore'):
_check_channels_ordered(raw, ["hbb", "hbr"])
_check_channels_ordered(raw.info, ["hbb", "hbr"])

# Test weird naming
ch_names = ['S1_D1 hbb', 'S1_D1 hbr', 'S2_D1 hbb', 'S2_D1 hbr',
Expand All @@ -361,7 +361,7 @@ def test_fnirs_channel_naming_and_order_custom_chroma():
info = create_info(ch_names=ch_names, ch_types=ch_types, sfreq=1.0)
raw = RawArray(data, info, verbose=True)
with pytest.raises(ValueError, match='naming conventions'):
_check_channels_ordered(raw, ["hbb", "hbr"])
_check_channels_ordered(raw.info, ["hbb", "hbr"])

# Check more weird naming
ch_names = ['S1_DX hbo', 'S1_DX hbr', 'S2_D1 hbo', 'S2_D1 hbr',
Expand All @@ -370,4 +370,4 @@ def test_fnirs_channel_naming_and_order_custom_chroma():
info = create_info(ch_names=ch_names, ch_types=ch_types, sfreq=1.0)
raw = RawArray(data, info, verbose=True)
with pytest.raises(ValueError, match='can not be parsed'):
_check_channels_ordered(raw, ["hbo", "hbr"])
_check_channels_ordered(raw.info, ["hbo", "hbr"])