Skip to content

Commit 31ebf4b

Browse files
authored
Merge branch 'main' into pre-commit-ci-update-config
2 parents 5f47d34 + 3c1be20 commit 31ebf4b

7 files changed

Lines changed: 63 additions & 87 deletions

File tree

doc/changes/names.inc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@
9595
.. _Evgenii Kalenkovich: https://github.com/kalenkovich
9696
.. _Evgeny Goldstein: https://github.com/evgenygoldstein
9797
.. _Ezequiel Mikulan: https://github.com/ezemikulan
98-
.. _Ezequiel Mikulan: https://github.com/ezemikulan
9998
.. _Fahimeh Mamashli: https://github.com/fmamashli
10099
.. _Famous077: https://github.com/Famous077
101100
.. _Farzin Negahbani: https://github.com/Farzin-Negahbani

doc/conf.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,15 @@
180180
"picard": ("https://mind-inria.github.io/picard/", None),
181181
"eeglabio": ("https://eeglabio.readthedocs.io/en/latest", None),
182182
"pybv": ("https://pybv.readthedocs.io/en/latest", None),
183+
# should go back below after https://github.com/dipy/dipy/issues/3870 is fixed
184+
"dipy": ("https://docs.dipy.org/1.12.0", None),
183185
}
184186
intersphinx_mapping.update(
185187
get_intersphinx_mapping(
186188
packages=set(
187189
"""
188190
imageio matplotlib numpy pandas python scipy statsmodels sklearn numba joblib nibabel
189-
seaborn patsy pyvista dipy nilearn pyqtgraph
191+
seaborn patsy pyvista nilearn pyqtgraph
190192
""".strip().split()
191193
),
192194
)

doc/install/check_installation.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ MNE-Python and its dependencies. Typical output looks like this::
4242
Visualization (optional)
4343
├☑ pyvista 0.41.1 (OpenGL 3.3 (Core Profile) Mesa 10.2.4 (git-d92815a) via Gallium 0.4 on llvmpipe (LLVM 3.4, 256 bits))
4444
├☑ pyvistaqt 0.0.0
45-
├☑ ipyvtklink 0.2.2
4645
├☑ vtk 9.2.6
4746
├☑ qtpy 2.4.0 (PyQt5=5.15.8)
4847
├☑ ipympl 0.9.3

mne/coreg.py

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,13 @@
6464
translation,
6565
)
6666
from .utils import (
67+
_check_freesurfer_home,
6768
_check_option,
6869
_check_subject,
6970
_import_nibabel,
7071
_validate_type,
72+
_verbose_safe_false,
7173
fill_doc,
72-
get_config,
7374
get_subjects_dir,
7475
logger,
7576
pformat,
@@ -206,15 +207,9 @@ def create_default_subject(fs_home=None, update=False, subjects_dir=None, verbos
206207
files from FreeSurfer into the current subjects_dir, and also adds the
207208
auxiliary files provided by MNE.
208209
"""
209-
subjects_dir = str(get_subjects_dir(subjects_dir, raise_error=True))
210+
subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
210211
if fs_home is None:
211-
fs_home = get_config("FREESURFER_HOME", fs_home)
212-
if fs_home is None:
213-
raise ValueError(
214-
"FREESURFER_HOME environment variable not found. Please "
215-
"specify the fs_home parameter in your call to "
216-
"create_default_subject()."
217-
)
212+
fs_home = _check_freesurfer_home()
218213

219214
# make sure FreeSurfer files exist
220215
fs_src = os.path.join(fs_home, "subjects", "fsaverage")
@@ -231,15 +226,15 @@ def create_default_subject(fs_home=None, update=False, subjects_dir=None, verbos
231226
)
232227

233228
# make sure destination does not already exist
234-
dest = os.path.join(subjects_dir, "fsaverage")
229+
dest = subjects_dir / "fsaverage"
235230
if dest == fs_src:
236231
raise OSError(
237232
"Your subjects_dir points to the FreeSurfer subjects_dir "
238233
f"({repr(subjects_dir)}). The default subject can not be created in the "
239234
"FreeSurfer installation directory; please specify a different "
240235
"subjects_dir."
241236
)
242-
elif (not update) and os.path.exists(dest):
237+
elif (not update) and dest.exists():
243238
raise OSError(
244239
'Can not create fsaverage because "fsaverage" already exists in '
245240
f"subjects_dir {repr(subjects_dir)}. Delete or rename the existing "
@@ -248,17 +243,16 @@ def create_default_subject(fs_home=None, update=False, subjects_dir=None, verbos
248243

249244
# copy fsaverage from FreeSurfer
250245
logger.info("Copying fsaverage subject from FreeSurfer directory...")
251-
if (not update) or not os.path.exists(dest):
246+
if (not update) or not dest.exists():
252247
shutil.copytree(fs_src, dest)
253248
_make_writable_recursive(dest)
254249

255250
# copy files from mne
256251
source_fname = os.path.join(
257252
os.path.dirname(__file__), "data", "fsaverage", "fsaverage-%s.fif"
258253
)
259-
dest_bem = os.path.join(dest, "bem")
260-
if not os.path.exists(dest_bem):
261-
os.mkdir(dest_bem)
254+
dest_bem = dest / "bem"
255+
dest_bem.mkdir(exist_ok=True)
262256
logger.info("Copying auxiliary fsaverage files from mne...")
263257
dest_fname = os.path.join(dest_bem, "fsaverage-%s.fif")
264258
_make_writable_recursive(dest_bem)
@@ -601,7 +595,7 @@ def _find_mri_paths(subject, skip_fiducials, subjects_dir):
601595
Dictionary whose keys are relevant file type names (str), and whose
602596
values are lists of paths.
603597
"""
604-
subjects_dir = str(get_subjects_dir(subjects_dir, raise_error=True))
598+
subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
605599
paths = {}
606600

607601
# directories to create
@@ -753,7 +747,7 @@ def _is_mri_subject(subject, subjects_dir=None):
753747
is_mri_subject : bool
754748
Whether ``subject`` is an mri subject.
755749
"""
756-
subjects_dir = str(get_subjects_dir(subjects_dir, raise_error=True))
750+
subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
757751
return bool(
758752
_find_head_bem(subject, subjects_dir)
759753
or _find_head_bem(subject, subjects_dir, high_res=True)
@@ -775,7 +769,7 @@ def _mri_subject_has_bem(subject, subjects_dir=None):
775769
has_bem_file : bool
776770
Whether ``subject`` has a bem file.
777771
"""
778-
subjects_dir = str(get_subjects_dir(subjects_dir, raise_error=True))
772+
subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
779773
pattern = bem_fname.format(subjects_dir=subjects_dir, subject=subject, name="*-bem")
780774
fnames = glob(pattern)
781775
return bool(len(fnames))
@@ -952,13 +946,16 @@ def scale_bem(
952946
write_bem_surfaces(dst, surfs)
953947

954948

949+
@verbose
955950
def scale_labels(
956951
subject_to,
957952
pattern=None,
958953
overwrite=False,
959954
subject_from=None,
955+
*,
960956
scale=None,
961957
subjects_dir=None,
958+
verbose=None,
962959
):
963960
r"""Scale labels to match a brain that was previously created by scaling.
964961
@@ -982,6 +979,7 @@ def scale_labels(
982979
file.
983980
subjects_dir : None | path-like
984981
Override the ``SUBJECTS_DIR`` environment variable.
982+
%(verbose)s
985983
"""
986984
subjects_dir, subject_from, scale, _ = _scale_params(
987985
subject_to, subject_from, scale, subjects_dir
@@ -1079,7 +1077,7 @@ def scale_mri(
10791077
:func:`scale_labels`, and :func:`scale_source_space` based on expected
10801078
filename patterns in the subject directory.
10811079
"""
1082-
subjects_dir = str(get_subjects_dir(subjects_dir, raise_error=True))
1080+
subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
10831081
paths = _find_mri_paths(subject_from, skip_fiducials, subjects_dir)
10841082
scale = np.atleast_1d(scale)
10851083
if scale.shape == (3,):
@@ -1119,24 +1117,25 @@ def scale_mri(
11191117
)
11201118
shutil.rmtree(dest)
11211119

1122-
logger.debug("create empty directory structure")
1120+
logger.debug("Creating empty directory structure ...")
11231121
for dirname in paths["dirs"]:
11241122
dir_ = dirname.format(subject=subject_to, subjects_dir=subjects_dir)
11251123
os.makedirs(dir_)
11261124

1127-
logger.debug("save MRI scaling parameters")
1125+
logger.info("Saving MRI scaling parameters ...")
11281126
fname = os.path.join(dest, "MRI scaling parameters.cfg")
11291127
_write_mri_config(fname, subject_from, subject_to, scale)
11301128

1131-
logger.debug("surf files [in mm]")
1129+
logger.info("Scaling surface files ...")
11321130
for fname in paths["surf"]:
11331131
src = fname.format(subject=subject_from, subjects_dir=subjects_dir)
11341132
src = os.path.realpath(src)
11351133
dest = fname.format(subject=subject_to, subjects_dir=subjects_dir)
11361134
pts, tri = read_surface(src)
11371135
write_surface(dest, pts * scale, tri)
11381136

1139-
logger.debug("BEM files [in m]")
1137+
logger.info("Scaling BEM files ...")
1138+
vb_f = _verbose_safe_false()
11401139
for bem_name in paths["bem"]:
11411140
scale_bem(
11421141
subject_to,
@@ -1145,18 +1144,18 @@ def scale_mri(
11451144
scale,
11461145
subjects_dir,
11471146
on_defects=on_defects,
1148-
verbose=False,
1147+
verbose=vb_f,
11491148
)
11501149

1151-
logger.debug("fiducials [in m]")
1150+
logger.info("Scaling fiducials ...")
11521151
for fname in paths["fid"]:
11531152
src = fname.format(subject=subject_from, subjects_dir=subjects_dir)
11541153
src = os.path.realpath(src)
1155-
pts, cframe = read_fiducials(src, verbose=False)
1154+
pts, cframe = read_fiducials(src, verbose=vb_f)
11561155
for pt in pts:
11571156
pt["r"] = pt["r"] * scale
11581157
dest = fname.format(subject=subject_to, subjects_dir=subjects_dir)
1159-
write_fiducials(dest, pts, cframe, overwrite=True, verbose=False)
1158+
write_fiducials(dest, pts, cframe, overwrite=True, verbose=vb_f)
11601159

11611160
# It is redundant to put this after the paths["fid"] loop, but it's simple, faster
11621161
# enough, and cleaner to just write it here (rather than adding conditionals to find
@@ -1170,16 +1169,16 @@ def scale_mri(
11701169
for fid in use_mri_fiducials:
11711170
fid["r"] = fid["r"] * scale
11721171
write_fiducials(
1173-
dest, use_mri_fiducials, FIFF.FIFFV_COORD_MRI, overwrite=True, verbose=False
1172+
dest, use_mri_fiducials, FIFF.FIFFV_COORD_MRI, overwrite=True, verbose=vb_f
11741173
)
11751174

1176-
logger.debug("MRIs [nibabel]")
1175+
logger.info("Scaling MRIs [nibabel] ...")
11771176
os.mkdir(mri_dirname.format(subjects_dir=subjects_dir, subject=subject_to))
11781177
for fname in paths["mri"]:
11791178
mri_name = os.path.basename(fname)
11801179
_scale_mri(subject_to, mri_name, subject_from, scale, subjects_dir)
11811180

1182-
logger.debug("Transforms")
1181+
logger.info("Scaling transforms ...")
11831182
for mri_name in paths["mri"]:
11841183
if mri_name.endswith("T1.mgz"):
11851184
os.mkdir(
@@ -1194,36 +1193,44 @@ def scale_mri(
11941193
)
11951194
break
11961195

1197-
logger.debug("duplicate files")
1196+
logger.info(
1197+
"Copying %s file(s) that do not need scaling ...",
1198+
len(paths["duplicate"]),
1199+
)
11981200
for fname in paths["duplicate"]:
11991201
src = fname.format(subject=subject_from, subjects_dir=subjects_dir)
12001202
dest = fname.format(subject=subject_to, subjects_dir=subjects_dir)
12011203
shutil.copyfile(src, dest)
12021204

1203-
logger.debug("source spaces")
1204-
for fname in paths["src"]:
1205-
src_name = os.path.basename(fname)
1206-
scale_source_space(
1207-
subject_to, src_name, subject_from, scale, subjects_dir, verbose=False
1208-
)
1209-
1210-
logger.debug("labels [in m]")
1211-
os.mkdir(os.path.join(subjects_dir, subject_to, "label"))
1205+
label_dir = subjects_dir / subject_to / "label"
1206+
if annot or labels:
1207+
label_dir.mkdir()
1208+
if annot:
1209+
logger.info("Copying annotations ...")
1210+
src_dir = subjects_dir / subject_from / "label"
1211+
dst_dir = subjects_dir / subject_to / "label"
1212+
for src_file in src_dir.glob("*.annot"):
1213+
shutil.copy(src_dir / src_file, dst_dir)
12121214
if labels:
1215+
logger.info("Scaling labels ...")
12131216
scale_labels(
12141217
subject_to,
12151218
subject_from=subject_from,
12161219
scale=scale,
12171220
subjects_dir=subjects_dir,
1221+
verbose=vb_f,
12181222
)
12191223

1220-
logger.debug("copy *.annot files")
1221-
# they don't contain scale-dependent information
1222-
if annot:
1223-
src_pattern = os.path.join(subjects_dir, subject_from, "label", "*.annot")
1224-
dst_dir = os.path.join(subjects_dir, subject_to, "label")
1225-
for src_file in iglob(src_pattern):
1226-
shutil.copy(src_file, dst_dir)
1224+
logger.info(
1225+
"Scaling %s source space(s) (this can take a while) ...",
1226+
len(paths["src"]),
1227+
)
1228+
for fname in paths["src"]:
1229+
src_name = os.path.basename(fname)
1230+
scale_source_space(
1231+
subject_to, src_name, subject_from, scale, subjects_dir, verbose=vb_f
1232+
)
1233+
logger.info("[done]")
12271234

12281235

12291236
@verbose
@@ -1496,7 +1503,7 @@ def __init__(
14961503
_validate_type(info, (Info, None), "info")
14971504
self._info = info
14981505
self._subject = _check_subject(subject, subject)
1499-
self._subjects_dir = str(get_subjects_dir(subjects_dir, raise_error=True))
1506+
self._subjects_dir = get_subjects_dir(subjects_dir, raise_error=True)
15001507
self._scale_mode = None
15011508
self._on_defects = on_defects
15021509

mne/preprocessing/tests/test_fine_cal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def test_fine_cal_systems(system, tmp_path):
242242
err_limit = 15
243243
int_order = 5
244244
corrs = (0.13, 0.0, 0.12)
245-
sfs = [4, 5, 125, 159]
245+
sfs = [4, 5, 120, 159]
246246
corr_tol = 0.38
247247
else:
248248
assert system == "triux", f"Unknown system {system}"

mne/viz/backends/_notebook.py

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import os
88
import os.path as op
9-
import re
109
from contextlib import contextmanager, nullcontext
1110

1211
from ipyevents import Event
@@ -37,7 +36,7 @@
3736
link,
3837
)
3938

40-
from ...utils import _soft_import, check_version
39+
from ...utils import _soft_import
4140
from ._abstract import (
4241
_AbstractAction,
4342
_AbstractAppWindow,
@@ -110,11 +109,7 @@
110109
_BASE_MIN_SIZE = "20px"
111110
_BASE_KWARGS = dict(layout=Layout(min_width=_BASE_MIN_SIZE, min_height=_BASE_MIN_SIZE))
112111

113-
# TODO: We can drop ipyvtklink once we support PyVista 0.38.1+
114-
if check_version("pyvista", "0.38.1"):
115-
_JUPYTER_BACKEND = "trame"
116-
else:
117-
_JUPYTER_BACKEND = "ipyvtklink"
112+
_JUPYTER_BACKEND = "trame"
118113

119114
# %%
120115
# Widgets
@@ -786,13 +781,6 @@ def __init__(self, *args, **kwargs):
786781
if "show" in kwargs and kwargs["show"]:
787782
self.show()
788783

789-
def _update(self):
790-
if _JUPYTER_BACKEND == "ipyvtklink":
791-
if self.figure.display is not None:
792-
self.figure.display.update_canvas()
793-
else:
794-
super()._update()
795-
796784
@contextmanager
797785
def _ensure_minimum_sizes(self):
798786
yield
@@ -1559,13 +1547,6 @@ def __init__(self, *args, **kwargs):
15591547
super().__init__(*args, **kwargs)
15601548
self._window_initialize(fullscreen=fullscreen)
15611549

1562-
def _update(self):
1563-
if _JUPYTER_BACKEND == "ipyvtklink":
1564-
if self.figure.display is not None:
1565-
self.figure.display.update_canvas()
1566-
else:
1567-
super()._update()
1568-
15691550
def _display_default_tool_bar(self):
15701551
self._tool_bar_initialize()
15711552
self._tool_bar_add_file_button(
@@ -1586,19 +1567,6 @@ def show(self):
15861567
self._display_default_tool_bar()
15871568
# viewer
15881569
viewer = self.plotter.show(jupyter_backend=_JUPYTER_BACKEND, return_viewer=True)
1589-
if _JUPYTER_BACKEND == "trame":
1590-
# Remove scrollbars, see https://github.com/pyvista/pyvista/pull/4847
1591-
# which adds this to the iframe PyVista creates. Once that's merged, this
1592-
# workaround just becomes a redundant but is still safe. And in a worst
1593-
# (realistic) case, this regex will fail to do any substitution and we just
1594-
# live with the ugly 90's-style borders. We can probably remove once we
1595-
# require PyVista 0.43 (assuming the above PR is merged).
1596-
viewer.value = re.sub(
1597-
r" style=[\"'](.+)[\"']></iframe>",
1598-
# value taken from matplotlib's widget
1599-
r" style='\1; border: 1px solid rgb(221,221,221);' scrolling='no'></iframe>", # noqa: E501
1600-
viewer.value,
1601-
)
16021570
rendering_row = list()
16031571
if self._docks is not None and "left" in self._docks:
16041572
rendering_row.append(self._docks["left"][0])

0 commit comments

Comments
 (0)