Skip to content

Commit ecdc498

Browse files
virvwautofix-ci[bot]larsoner
authored
Implementation of the meanlogratio for TFR (#14205)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Larson <larson.eric.d@gmail.com>
1 parent 3b6725a commit ecdc498

10 files changed

Lines changed: 161 additions & 95 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added ``meanlogratio`` baselining mode to :meth:`mne.time_frequency.EpochsTFR.apply_baseline` and related functions, by :newcontrib:`Virginie van Wassenhove`.

doc/changes/names.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@
476476
.. _Victor Férat: https://github.com/vferat
477477
.. _Victoria Peterson: https://github.com/vpeterson
478478
.. _Vincent Gao: https://github.com/gaoflow
479+
.. _Virginie van Wassenhove: https://brainthemind.com/virginie-van-wassenhove
479480
.. _Wei Xu: https://github.com/psyxw
480481
.. _Will Turner: https://bootstrapbill.github.io
481482
.. _Wouter Kroot: https://github.com/WouterKroot

doc/references.bib

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,15 @@ @unpublished{KingEtAl2018
10251025
note = {hal-01848442}
10261026
}
10271027

1028+
@article{KinleyEtAl2026,
1029+
author={Kinley, Isaac and Roberts, Reece P and Meltzer, Jed A and Addis, Donna Rose},
1030+
title={Spectral change or Jensen gap? Log-ratio baseline correction for time-frequency M/EEG is negatively biased},
1031+
journal={Journal of Neuroscience Methods},
1032+
pages={110826},
1033+
year={2026},
1034+
publisher={Elsevier}
1035+
}
1036+
10281037
@article{KnuutilaEtAl1993,
10291038
author = {Knuutila, Jukka E. T. and Ahonen, Antti I. and Hämäläinen, Matti S. and Kajola, Matti J. and Laine, P. P. and Lounasmaa, Olli V. and Parkkonen, Lauri T. and Simola, Juha T. A. and Tesche, Claudia D.},
10301039
doi = {10.1109/20.281163},

mne/baseline.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ def _log_rescale(baseline, mode="mean"):
1515
_check_option(
1616
"mode",
1717
mode,
18-
["logratio", "ratio", "zscore", "mean", "percent", "zlogratio"],
18+
[
19+
"logratio",
20+
"ratio",
21+
"zscore",
22+
"mean",
23+
"percent",
24+
"zlogratio",
25+
"meanlogratio",
26+
],
1927
)
2028
msg = f"Applying baseline correction (mode: {mode})"
2129
else:
@@ -35,21 +43,7 @@ def rescale(data, times, baseline, mode="mean", copy=True, picks=None, verbose=N
3543
times : 1D array
3644
Time instants is seconds.
3745
%(baseline_rescale)s
38-
mode : 'mean' | 'ratio' | 'logratio' | 'percent' | 'zscore' | 'zlogratio'
39-
Perform baseline correction by
40-
41-
- subtracting the mean of baseline values ('mean')
42-
- dividing by the mean of baseline values ('ratio')
43-
- dividing by the mean of baseline values and taking the log
44-
('logratio')
45-
- subtracting the mean of baseline values followed by dividing by
46-
the mean of baseline values ('percent')
47-
- subtracting the mean of baseline values and dividing by the
48-
standard deviation of baseline values ('zscore')
49-
- dividing by the mean of baseline values, taking the log, and
50-
dividing by the standard deviation of log baseline values
51-
('zlogratio')
52-
46+
%(baseline_mode)s
5347
copy : bool
5448
Whether to return a new instance or modify in place.
5549
picks : list of int | None
@@ -60,6 +54,10 @@ def rescale(data, times, baseline, mode="mean", copy=True, picks=None, verbose=N
6054
-------
6155
data_scaled: array
6256
Array of same shape as data after rescaling.
57+
58+
References
59+
----------
60+
.. footbibliography::
6361
"""
6462
if copy:
6563
data = data.copy()
@@ -114,6 +112,13 @@ def fun(d, m):
114112
d /= m
115113
np.log10(d, out=d)
116114

115+
elif mode == "meanlogratio":
116+
117+
def fun(d, m):
118+
d /= m
119+
np.log10(d, out=d)
120+
d -= np.mean(d[..., imin:imax], axis=-1, keepdims=True)
121+
117122
elif mode == "percent":
118123

119124
def fun(d, m):

mne/minimum_norm/time_frequency.py

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -220,21 +220,7 @@ def source_band_induced_power(
220220
If a is None the beginning of the data is used and if b is None then b
221221
is set to the end of the interval. If baseline is equal to (None, None)
222222
all the time interval is used.
223-
baseline_mode : 'mean' | 'ratio' | 'logratio' | 'percent' | 'zscore' | 'zlogratio'
224-
Perform baseline correction by
225-
226-
- subtracting the mean of baseline values ('mean')
227-
- dividing by the mean of baseline values ('ratio')
228-
- dividing by the mean of baseline values and taking the log
229-
('logratio')
230-
- subtracting the mean of baseline values followed by dividing by
231-
the mean of baseline values ('percent')
232-
- subtracting the mean of baseline values and dividing by the
233-
standard deviation of baseline values ('zscore')
234-
- dividing by the mean of baseline values, taking the log, and
235-
dividing by the standard deviation of log baseline values
236-
('zlogratio')
237-
223+
%(baseline_mode_mn)s
238224
pca : bool
239225
If True, the true dimension of data is estimated before running
240226
the time-frequency transforms. It reduces the computation times
@@ -258,6 +244,10 @@ def source_band_induced_power(
258244
(n_vertices, n_frequencies, n_samples) if label=None or label=label.
259245
For lists of one or more labels, the induced power estimate has shape
260246
(n_labels, n_frequencies, n_samples).
247+
248+
References
249+
----------
250+
.. footbibliography::
261251
""" # noqa: E501
262252
_check_option("method", method, INVERSE_METHODS)
263253

@@ -648,21 +638,7 @@ def source_induced_power(
648638
and if b is None then b is set to the end of the interval.
649639
If baseline is equal to (None, None) all the time
650640
interval is used.
651-
baseline_mode : 'mean' | 'ratio' | 'logratio' | 'percent' | 'zscore' | 'zlogratio'
652-
Perform baseline correction by
653-
654-
- subtracting the mean of baseline values ('mean')
655-
- dividing by the mean of baseline values ('ratio')
656-
- dividing by the mean of baseline values and taking the log
657-
('logratio')
658-
- subtracting the mean of baseline values followed by dividing by
659-
the mean of baseline values ('percent')
660-
- subtracting the mean of baseline values and dividing by the
661-
standard deviation of baseline values ('zscore')
662-
- dividing by the mean of baseline values, taking the log, and
663-
dividing by the standard deviation of log baseline values
664-
('zlogratio')
665-
641+
%(baseline_mode_mn)s
666642
pca : bool
667643
If True, the true dimension of data is estimated before running
668644
the time-frequency transforms. It reduces the computation times
@@ -692,6 +668,10 @@ def source_induced_power(
692668
plv : array
693669
The phase-locking value array with shape (n_sources, n_freqs,
694670
n_samples). Only returned if ``return_plv=True``.
671+
672+
References
673+
----------
674+
.. footbibliography::
695675
""" # noqa: E501
696676
_check_option("method", method, INVERSE_METHODS)
697677
_check_ori(pick_ori, inverse_operator["source_ori"], inverse_operator["src"])

mne/time_frequency/tests/test_tfr.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1723,7 +1723,8 @@ def test_tfr_copy(average_tfr):
17231723

17241724

17251725
@pytest.mark.parametrize(
1726-
"mode", ("mean", "ratio", "logratio", "percent", "zscore", "zlogratio")
1726+
"mode",
1727+
("mean", "ratio", "logratio", "meanlogratio", "percent", "zscore", "zlogratio"),
17271728
)
17281729
def test_tfr_apply_baseline(average_tfr, mode):
17291730
"""Test TFR baselining."""

mne/time_frequency/tfr.py

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,26 +1793,17 @@ def apply_baseline(self, baseline, mode="mean", verbose=None):
17931793
%(baseline_rescale)s
17941794
17951795
How baseline is computed is determined by the ``mode`` parameter.
1796-
mode : 'mean' | 'ratio' | 'logratio' | 'percent' | 'zscore' | 'zlogratio'
1797-
Perform baseline correction by
1798-
1799-
- subtracting the mean of baseline values ('mean')
1800-
- dividing by the mean of baseline values ('ratio')
1801-
- dividing by the mean of baseline values and taking the log
1802-
('logratio')
1803-
- subtracting the mean of baseline values followed by dividing by
1804-
the mean of baseline values ('percent')
1805-
- subtracting the mean of baseline values and dividing by the
1806-
standard deviation of baseline values ('zscore')
1807-
- dividing by the mean of baseline values, taking the log, and
1808-
dividing by the standard deviation of log baseline values
1809-
('zlogratio')
1796+
%(baseline_mode)s
18101797
%(verbose)s
18111798
18121799
Returns
18131800
-------
18141801
%(inst_tfr)s
18151802
The modified instance.
1803+
1804+
References
1805+
----------
1806+
.. footbibliography::
18161807
"""
18171808
self._baseline = _check_baseline(baseline, times=self.times, sfreq=self.sfreq)
18181809
rescale(self.data, self.times, self.baseline, mode, copy=False, verbose=verbose)
@@ -1950,7 +1941,7 @@ def plot(
19501941
%(baseline_rescale)s
19511942
19521943
How baseline is computed is determined by the ``mode`` parameter.
1953-
%(mode_tfr_plot)s
1944+
%(baseline_mode)s
19541945
%(dB_tfr_plot)s
19551946
%(combine_tfr_plot)s
19561947
@@ -2216,7 +2207,7 @@ def plot_joint(
22162207
%(baseline_rescale)s
22172208
22182209
How baseline is computed is determined by the ``mode`` parameter.
2219-
%(mode_tfr_plot)s
2210+
%(baseline_mode)s
22202211
%(dB_tfr_plot)s
22212212
%(yscale_tfr_plot)s
22222213
%(vlim_tfr_plot_joint)s
@@ -2514,7 +2505,7 @@ def plot_topo(
25142505
%(baseline_rescale)s
25152506
25162507
How baseline is computed is determined by the ``mode`` parameter.
2517-
%(mode_tfr_plot)s
2508+
%(baseline_mode)s
25182509
%(tmin_tmax_psd)s
25192510
%(fmin_fmax_tfr)s
25202511
%(vmin_vmax_tfr_plot_topo)s

mne/utils/docs.py

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,37 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75):
511511
2. Subtract this mean from the **entire** ``Evoked``.
512512
513513
"""
514+
_baseline_mode_desc = """\
515+
Perform baseline correction by:
516+
517+
``"mean"``
518+
Subtracting the mean of baseline values
519+
``"ratio"``
520+
Dividing by the mean of baseline values
521+
``"logratio"``
522+
Dividing by the mean of baseline values and taking the log
523+
``"meanlogratio"``
524+
Dividing by the mean of baseline values, taking the log and then
525+
subtracting the mean (:footcite:`KinleyEtAl2026`)
526+
527+
.. note:: this baseline mode has not been tested at the source-level!
528+
``"percent"``
529+
Subtracting the mean of baseline values followed by dividing by
530+
the mean of baseline values
531+
``"zscore"``
532+
Subtracting the mean of baseline values and dividing by the
533+
standard deviation of baseline values
534+
``"zlogratio"``
535+
Dividing by the mean of baseline values, taking the log, and
536+
dividing by the standard deviation of log baseline values
537+
"""
538+
539+
docdict["baseline_mode"] = f"""\
540+
mode : 'mean' | 'ratio' | 'logratio' | 'meanlogratio' | 'percent' | 'zscore' | 'zlogratio'
541+
{_baseline_mode_desc}""" # noqa: E501
542+
docdict["baseline_mode_mn"] = f"""\
543+
baseline_mode : 'mean' | 'ratio' | 'logratio' | 'meanlogratio' | 'percent' | 'zscore' | 'zlogratio'
544+
{_baseline_mode_desc}""" # noqa: E501
514545

515546
docdict["baseline_report"] = f"""{_baseline_rescale_base}
516547
Correction is applied in the following way **to each channel:**
@@ -2825,23 +2856,6 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75):
28252856
* 'sum' : Sum of PSFs/CTFs across vertices.
28262857
"""
28272858

2828-
docdict["mode_tfr_plot"] = """
2829-
mode : 'mean' | 'ratio' | 'logratio' | 'percent' | 'zscore' | 'zlogratio'
2830-
Perform baseline correction by
2831-
2832-
- subtracting the mean of baseline values ('mean') (default)
2833-
- dividing by the mean of baseline values ('ratio')
2834-
- dividing by the mean of baseline values and taking the log
2835-
('logratio')
2836-
- subtracting the mean of baseline values followed by dividing by
2837-
the mean of baseline values ('percent')
2838-
- subtracting the mean of baseline values and dividing by the
2839-
standard deviation of baseline values ('zscore')
2840-
- dividing by the mean of baseline values, taking the log, and
2841-
dividing by the standard deviation of log baseline values
2842-
('zlogratio')
2843-
"""
2844-
28452859
docdict["montage"] = """
28462860
montage : None | str | DigMontage
28472861
A montage containing channel positions. If a string or

mne/viz/topomap.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,20 +2065,7 @@ def plot_tfr_topomap(
20652065
"b (s)". If a is None the beginning of the data is used and if b is
20662066
None then b is set to the end of the interval. If baseline is equal to
20672067
(None, None) the whole time interval is used.
2068-
mode : 'mean' | 'ratio' | 'logratio' | 'percent' | 'zscore' | 'zlogratio' | None
2069-
Perform baseline correction by
2070-
2071-
- subtracting the mean baseline power ('mean')
2072-
- dividing by the mean baseline power ('ratio')
2073-
- dividing by the mean baseline power and taking the log ('logratio')
2074-
- subtracting the mean baseline power followed by dividing by the
2075-
mean baseline power ('percent')
2076-
- subtracting the mean baseline power and dividing by the standard
2077-
deviation of the baseline power ('zscore')
2078-
- dividing by the mean baseline power, taking the log, and dividing
2079-
by the standard deviation of the baseline power ('zlogratio')
2080-
2081-
If None no baseline correction is applied.
2068+
%(baseline_mode)s
20822069
%(sensors_topomap)s
20832070
%(show_names_topomap)s
20842071
%(mask_evoked_topomap)s
@@ -2119,6 +2106,10 @@ def plot_tfr_topomap(
21192106
-------
21202107
fig : matplotlib.figure.Figure
21212108
The figure containing the topography.
2109+
2110+
References
2111+
----------
2112+
.. footbibliography::
21222113
""" # noqa: E501
21232114
import matplotlib.pyplot as plt
21242115

0 commit comments

Comments
 (0)