Skip to content

Commit 49c9474

Browse files
committed
Merge remote-tracking branch 'upstream/main' into openmeeg
* upstream/main: Revert "Add error message when conversion of EEG locs to [circle deploy] (mne-tools#11104) MRG: Fixes for mne-tools#11090 (mne-tools#11108) add test for edf units param (mne-tools#11105) BUG: Improve logic for bti (mne-tools#11102) add spectrum class (mne-tools#10184) ENH : add units parameter to read_raw_edf in case units is missing from the file (mne-tools#11099) ENH: Add temperature and galvanic (mne-tools#11090)
2 parents 4358e01 + bc30e0e commit 49c9474

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2588
-779
lines changed

doc/_includes/channel_types.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,8 @@ ias Internal Active Shielding data
6565

6666
syst System status channel information
6767
(Triux systems only)
68+
69+
temperature Temperature Degrees Celsius
70+
71+
gsr Galvanic skin response Siemens
6872
============= ========================================= =================

doc/_static/style.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,6 @@ ul.icon-bullets {
327327
img.hidden {
328328
visibility: hidden;
329329
}
330+
td.justify {
331+
text-align-last: justify;
332+
}

doc/changes/latest.inc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ Enhancements
3434
- Add ``starting_affine`` keyword argument to :func:`mne.transforms.compute_volume_registration` to initialize an alignment with an affine (:gh:`11020` by `Alex Rockhill`_)
3535
- The ``trans`` parameter in :func:`mne.make_field_map` now accepts a :class:`~pathlib.Path` object, and uses standardised loading logic (:gh:`10784` by :newcontrib:`Andrew Quinn`)
3636
- Add HTML representation for `~mne.Evoked` in Jupyter Notebooks (:gh:`11075` by `Valerii Chirkov`_ and `Andrew Quinn`_)
37+
- Add support for ``temperature`` and ``gsr`` (galvanic skin response, i.e., electrodermal activity) channel types (:gh:`11090`, :gh:`11108` by `Eric Larson`_ and `Richard Höchenberger`_)
3738
- Allow :func:`mne.beamformer.make_dics` to take ``pick_ori='vector'`` to compute vector source estimates (:gh:`19080` by `Alex Rockhill`_)
39+
- Add ``units`` parameter to :func:`mne.io.read_raw_edf` in case units are missing from the file (:gh:`11099` by `Alex Gramfort`_)
3840
- Add ``on_missing`` functionality to all of our classes that have a ``drop_channels`` method, to control what happens when channel names are not in the object (:gh:`11077` by `Andrew Quinn`_)
3941

4042
Bugs
@@ -45,12 +47,13 @@ Bugs
4547
- Fix bug in :class:`mne.viz.Brain` constructor where the first argument was named ``subject_id`` instead of ``subject`` (:gh:`11049` by `Eric Larson`_)
4648
- Fix bug in :ref:`mne coreg` where the MEG helmet position was not updated during ICP fitting (:gh:`11084` by `Eric Larson`_)
4749
- Document ``height`` and ``weight`` keys of ``subject_info`` entry in :class:`mne.Info` (:gh:`11019` by :newcontrib:`Sena Er`)
48-
- Fixed bug in :func:`mne.viz.plot_filter` when plotting filters created using ``output='ba'`` mode with ``compensation`` turned on. (by `Marian Dovgialo`_)
4950
- Fix bug in :func:`mne.viz.plot_filter` when plotting filters created using ``output='ba'`` mode with ``compensation`` turned on. (:gh:`11040` by `Marian Dovgialo`_)
51+
- Fix bug in :func:`mne.io.read_raw_bti` where EEG, EMG, and H/VEOG channels were not detected properly, and many non-ECG channels were called ECG. The logic has been improved, and any channels of unknown type are now labeled as ``misc`` (:gh:`11102` by `Eric Larson`_)
5052
- Fix bug in :func:`mne.viz.plot_topomap` when providing ``sphere="eeglab"`` (:gh:`11081` by `Mathieu Scheltienne`_)
51-
- Applying a montage where EEG locations are not in head space (or unknown space) without fiducials will now raise an error message. (:gh:`11080` by `Marijn van Vliet`_)
5253

5354
API changes
5455
~~~~~~~~~~~
5556
- The ``bands`` parameter of :meth:`mne.Epochs.plot_psd_topomap` now accepts :class:`dict` input; legacy :class:`tuple` input is supported, but discouraged for new code (:gh:`11050` by `Daniel McCloy`_)
5657
- The ``show_toolbar`` argument to :class:`mne.viz.Brain` is being removed by deprecation (:gh:`11049` by `Eric Larson`_)
58+
- New classes :class:`~mne.time_frequency.Spectrum` and :class:`~mne.time_frequency.EpochsSpectrum`, created via new methods :meth:`Raw.compute_psd()<mne.io.Raw.compute_psd>`, :meth:`Epochs.compute_psd()<mne.Epochs.compute_psd>`, and :meth:`Evoked.compute_psd()<mne.Evoked.compute_psd>` (:gh:`10184` by `Daniel McCloy`_)
59+
- The PSD functions that operate on Raw/Epochs/Evoked instances (``mne.time_frequency.psd_welch`` and ``mne.time_frequency.psd_multitaper``) are deprecated; for equivalent functionality create :class:`~mne.time_frequency.Spectrum` or :class:`~mne.time_frequency.EpochsSpectrum` objects instead and then run ``spectrum.get_data(return_freqs=True)`` (:gh:`10184` by `Daniel McCloy`_)

doc/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@
237237
'Transform': 'mne.transforms.Transform',
238238
'Coregistration': 'mne.coreg.Coregistration',
239239
'Figure3D': 'mne.viz.Figure3D',
240+
'Spectrum': 'mne.time_frequency.Spectrum',
241+
'EpochsSpectrum': 'mne.time_frequency.EpochsSpectrum',
240242
# dipy
241243
'dipy.align.AffineMap': 'dipy.align.imaffine.AffineMap',
242244
'dipy.align.DiffeomorphicMap': 'dipy.align.imwarp.DiffeomorphicMap',

doc/references.bib

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,6 +2285,17 @@ @article{LuckGaspelin2017
22852285
doi = {10.1111/psyp.12639},
22862286
}
22872287

2288+
@article{Welch1967,
2289+
title = {The Use of Fast {{Fourier}} Transform for the Estimation of Power Spectra: {{A}} Method Based on Time Averaging over Short, Modified Periodograms},
2290+
author = {Welch, Peter D.},
2291+
year = {1967},
2292+
journal = {IEEE Transactions on Audio and Electroacoustics},
2293+
volume = {15},
2294+
number = {2},
2295+
pages = {70--73},
2296+
doi = {10.1109/TAU.1967.1161901},
2297+
}
2298+
22882299
@article{MaksymenkoEtAl2017,
22892300
title = {Strategies for statistical thresholding of source localization maps in magnetoencephalography and estimating source extent},
22902301
volume = {290},

doc/time_frequency.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Time-Frequency
1616
AverageTFR
1717
EpochsTFR
1818
CrossSpectralDensity
19+
Spectrum
20+
EpochsSpectrum
1921

2022
Functions that operate on mne-python objects:
2123

@@ -36,6 +38,7 @@ Functions that operate on mne-python objects:
3638
tfr_stockwell
3739
read_tfrs
3840
write_tfrs
41+
read_spectrum
3942

4043
Functions that operate on ``np.ndarray`` objects:
4144

mne/channels/channels.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ def equalize_channels(instances, copy=True, verbose=None):
202202
FIFF.FIFF_UNIT_T_M: 'T/m',
203203
FIFF.FIFF_UNIT_MOL: 'M',
204204
FIFF.FIFF_UNIT_NONE: 'NA',
205-
FIFF.FIFF_UNIT_CEL: 'C'}
205+
FIFF.FIFF_UNIT_CEL: 'C',
206+
FIFF.FIFF_UNIT_S: 'S'}
206207

207208

208209
def _check_set(ch, projs, ch_type):
@@ -328,7 +329,7 @@ def set_channel_types(self, mapping, verbose=None):
328329
329330
ecg, eeg, emg, eog, exci, ias, misc, resp, seeg, dbs, stim, syst,
330331
ecog, hbo, hbr, fnirs_cw_amplitude, fnirs_fd_ac_amplitude,
331-
fnirs_fd_phase, fnirs_od
332+
fnirs_fd_phase, fnirs_od, temperature, gsr
332333
333334
.. versionadded:: 0.9.0
334335
"""
@@ -586,15 +587,16 @@ def set_meas_date(self, meas_date):
586587

587588

588589
class UpdateChannelsMixin(object):
589-
"""Mixin class for Raw, Evoked, Epochs, AverageTFR."""
590+
"""Mixin class for Raw, Evoked, Epochs, Spectrum, AverageTFR."""
590591

591592
@verbose
592593
def pick_types(self, meg=False, eeg=False, stim=False, eog=False,
593-
ecg=False, emg=False, ref_meg='auto', misc=False,
594+
ecg=False, emg=False, ref_meg='auto', *, misc=False,
594595
resp=False, chpi=False, exci=False, ias=False, syst=False,
595596
seeg=False, dipole=False, gof=False, bio=False,
596-
ecog=False, fnirs=False, csd=False, dbs=False, include=(),
597-
exclude='bads', selection=None, verbose=None):
597+
ecog=False, fnirs=False, csd=False, dbs=False,
598+
temperature=False, gsr=False,
599+
include=(), exclude='bads', selection=None, verbose=None):
598600
"""Pick some channels by type and names.
599601
600602
Parameters
@@ -620,7 +622,8 @@ def pick_types(self, meg=False, eeg=False, stim=False, eog=False,
620622
ref_meg=ref_meg, misc=misc, resp=resp, chpi=chpi, exci=exci,
621623
ias=ias, syst=syst, seeg=seeg, dipole=dipole, gof=gof, bio=bio,
622624
ecog=ecog, fnirs=fnirs, csd=csd, dbs=dbs, include=include,
623-
exclude=exclude, selection=selection)
625+
exclude=exclude, selection=selection, temperature=temperature,
626+
gsr=gsr)
624627

625628
self._pick_drop_channels(idx)
626629

@@ -789,6 +792,7 @@ def _pick_drop_channels(self, idx, *, verbose=None):
789792
# avoid circular imports
790793
from ..io import BaseRaw
791794
from ..time_frequency import AverageTFR, EpochsTFR
795+
from ..time_frequency.spectrum import BaseSpectrum
792796

793797
msg = 'adding, dropping, or reordering channels'
794798
if isinstance(self, BaseRaw):
@@ -813,8 +817,12 @@ def _pick_drop_channels(self, idx, *, verbose=None):
813817
if mat is not None:
814818
setattr(self, key, mat[idx][:, idx])
815819

816-
# All others (Evoked, Epochs, Raw) have chs axis=-2
817-
axis = -3 if isinstance(self, (AverageTFR, EpochsTFR)) else -2
820+
if isinstance(self, BaseSpectrum):
821+
axis = self._dims.index('channel')
822+
elif isinstance(self, (AverageTFR, EpochsTFR)):
823+
axis = -3
824+
else: # All others (Evoked, Epochs, Raw) have chs axis=-2
825+
axis = -2
818826
if hasattr(self, '_data'): # skip non-preloaded Raw
819827
self._data = self._data.take(idx, axis=axis)
820828
else:

mne/channels/montage.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -668,19 +668,11 @@ def transform_to_head(montage):
668668
# Get fiducial points and their coord_frame
669669
native_head_t = compute_native_head_t(montage)
670670
montage = montage.copy() # to avoid inplace modification
671-
672671
if native_head_t['from'] != FIFF.FIFFV_COORD_HEAD:
673672
for d in montage.dig:
674673
if d['coord_frame'] == native_head_t['from']:
675674
d['r'] = apply_trans(native_head_t, d['r'])
676675
d['coord_frame'] = FIFF.FIFFV_COORD_HEAD
677-
elif d['kind'] == FIFF.FIFFV_POINT_EEG:
678-
raise RuntimeError(
679-
f'Could not transform EEG channel {d["ident"]} position '
680-
f'from {_verbose_frames[d["coord_frame"]]} to head '
681-
'coordinates. Fiducial points are either missing or '
682-
'specified in a different coordinate frame than the EEG '
683-
'channel locations.')
684676
return montage
685677

686678

mne/channels/tests/test_montage.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,17 +1210,6 @@ def test_transform_to_head_and_compute_dev_head_t():
12101210
montage_polhemus
12111211
))
12121212

1213-
# Test errors when transforming without fiducials explicitly where points
1214-
# are tagged to be not in head or unknown coord space.
1215-
montage_without_fids = make_dig_montage(
1216-
ch_pos={"ch_1": np.array([1, 2, 3]),
1217-
"ch_2": np.array([4, 5, 6]),
1218-
"ch_3": np.array([7, 8, 9])},
1219-
coord_frame="mri") # MRI coordinate space
1220-
with pytest.raises(RuntimeError, match='Could not transform EEG channel'):
1221-
with pytest.warns(RuntimeWarning, match='Fiducial point .* not found'):
1222-
transform_to_head(montage_without_fids)
1223-
12241213

12251214
def test_set_montage_with_mismatching_ch_names():
12261215
"""Test setting a DigMontage with mismatching ch_names."""

mne/cov.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ def plot_topomap(self, info, ch_type=None, vmin=None,
267267
----------
268268
%(info_not_none)s
269269
%(ch_type_topomap)s
270+
271+
.. versionadded:: 0.21
270272
%(vmin_vmax_topomap)s
271273
%(cmap_topomap)s
272274
%(sensors_topomap)s

0 commit comments

Comments
 (0)