Note
Go to the end to download the full example code.
Configuring MNE-Python#
This tutorial covers how to configure MNE-Python to suit your local system and your analysis preferences.
We begin by importing the necessary Python modules:
# Authors: The MNE-Python contributors.
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.
import os
import mne
Getting and setting configuration variables#
Configuration variables are read and written using the functions
mne.get_config()
and mne.set_config()
. To read a specific
configuration variable, pass its name to get_config()
as the
key
parameter (key
is the first parameter so you can pass it unnamed
if you want):
print(mne.get_config("MNE_USE_CUDA"))
print(type(mne.get_config("MNE_USE_CUDA")))
None
<class 'NoneType'>
Note that the string values read from the JSON file are not parsed in any
way, so get_config()
returns a string even for true/false config
values, rather than a Python boolean.
Similarly, set_config()
will only set string values (or None
values, to unset a variable):
try:
mne.set_config("MNE_USE_CUDA", True)
except TypeError as err:
print(err)
value must be an instance of str, path-like, or NoneType, got <class 'bool'> instead.
If you’re unsure whether a config variable has been set, there is a
convenient way to check it and provide a fallback in case it doesn’t exist:
get_config()
has a default
parameter.
print(mne.get_config("missing_config_key", default="fallback value"))
fallback value
There are also two convenience modes of get_config()
. The first
will return a dict
containing all config variables (and their
values) that have been set on your system; this is done by passing
key=None
(which is the default, so it can be omitted):
print(mne.get_config()) # same as mne.get_config(key=None)
{'MNE_BROWSER_PRECOMPUTE': 'false', 'MNE_BROWSER_THEME': 'light', 'MNE_BROWSER_OVERVIEW_MODE': 'hidden', 'MNE_BROWSER_BACKEND': 'qt', 'MNE_3D_OPTION_THEME': 'light'}
The second convenience mode will return a tuple
of all the keys that
MNE-Python recognizes and uses, regardless of whether they’ve been set on
your system. This is done by passing an empty string ''
as the key
:
print(mne.get_config(key=""))
{'MNE_3D_OPTION_ANTIALIAS': 'bool, whether to use full-screen antialiasing in 3D plots', 'MNE_3D_OPTION_DEPTH_PEELING': 'bool, whether to use depth peeling in 3D plots', 'MNE_3D_OPTION_MULTI_SAMPLES': 'int, number of samples to use for full-screen antialiasing', 'MNE_3D_OPTION_SMOOTH_SHADING': 'bool, whether to use smooth shading in 3D plots', 'MNE_3D_OPTION_THEME': 'str, the color theme (light or dark) to use for 3D plots', 'MNE_BROWSE_RAW_SIZE': 'tuple, width and height of the raw browser window (in inches)', 'MNE_BROWSER_BACKEND': 'str, the backend to use for the MNE Browse Raw window (qt or matplotlib)', 'MNE_BROWSER_OVERVIEW_MODE': 'str, the overview mode to use in the MNE Browse Raw window )(see mne.viz.plot_raw for valid options)', 'MNE_BROWSER_PRECOMPUTE': 'bool, whether to precompute raw data in the MNE Browse Raw window', 'MNE_BROWSER_THEME': 'str, the color theme (light or dark) to use for the browser', 'MNE_BROWSER_USE_OPENGL': 'bool, whether to use OpenGL for rendering in the MNE Browse Raw window', 'MNE_CACHE_DIR': 'str, path to the cache directory for parallel execution', 'MNE_COREG_ADVANCED_RENDERING': 'bool, whether to use advanced OpenGL rendering in mne coreg', 'MNE_COREG_COPY_ANNOT': 'bool, whether to copy the annotation files during warping', 'MNE_COREG_FULLSCREEN': 'bool, whether to use full-screen mode in mne coreg', 'MNE_COREG_GUESS_MRI_SUBJECT': 'bool, whether to guess the MRI subject in mne coreg', 'MNE_COREG_HEAD_HIGH_RES': 'bool, whether to use high-res head surface in mne coreg', 'MNE_COREG_HEAD_OPACITY': 'bool, the head surface opacity to use in mne coreg', 'MNE_COREG_HEAD_INSIDE': 'bool, whether to add an opaque inner scalp head surface to help occlude points behind the head in mne coreg', 'MNE_COREG_INTERACTION': 'str, interaction style in mne coreg (trackball or terrain)', 'MNE_COREG_MARK_INSIDE': 'bool, whether to mark points inside the head surface in mne coreg', 'MNE_COREG_PREPARE_BEM': 'bool, whether to prepare the BEM solution after warping in mne coreg', 'MNE_COREG_ORIENT_TO_SURFACE': 'bool, whether to orient the digitization markers to the head surface in mne coreg', 'MNE_COREG_SCALE_LABELS': 'bool, whether to scale the MRI labels during warping in mne coreg', 'MNE_COREG_SCALE_BY_DISTANCE': 'bool, whether to scale the digitization markers by their distance from the scalp in mne coreg', 'MNE_COREG_SCENE_SCALE': 'float, the scale factor of the 3D scene in mne coreg (default 0.16)', 'MNE_COREG_WINDOW_HEIGHT': 'int, window height for mne coreg', 'MNE_COREG_WINDOW_WIDTH': 'int, window width for mne coreg', 'MNE_COREG_SUBJECTS_DIR': 'str, path to the subjects directory for mne coreg', 'MNE_CUDA_DEVICE': 'int, CUDA device to use for GPU processing', 'MNE_DATA': 'str, default data directory', 'MNE_DATASETS_BRAINSTORM_PATH': 'str, path for brainstorm data', 'MNE_DATASETS_EEGBCI_PATH': 'str, path for EEGBCI data', 'MNE_DATASETS_EPILEPSY_ECOG_PATH': 'str, path for epilepsy_ecog data', 'MNE_DATASETS_HF_SEF_PATH': 'str, path for HF_SEF data', 'MNE_DATASETS_MEGSIM_PATH': 'str, path for MEGSIM data', 'MNE_DATASETS_MISC_PATH': 'str, path for misc data', 'MNE_DATASETS_MTRF_PATH': 'str, path for MTRF data', 'MNE_DATASETS_SAMPLE_PATH': 'str, path for sample data', 'MNE_DATASETS_SOMATO_PATH': 'str, path for somato data', 'MNE_DATASETS_MULTIMODAL_PATH': 'str, path for multimodal data', 'MNE_DATASETS_FNIRS_MOTOR_PATH': 'str, path for fnirs_motor data', 'MNE_DATASETS_OPM_PATH': 'str, path for OPM data', 'MNE_DATASETS_SPM_FACE_DATASETS_TESTS': 'str, path for spm_face data', 'MNE_DATASETS_SPM_FACE_PATH': 'str, path for spm_face data', 'MNE_DATASETS_TESTING_PATH': 'str, path for testing data', 'MNE_DATASETS_VISUAL_92_CATEGORIES_PATH': 'str, path for visual_92_categories data', 'MNE_DATASETS_KILOWORD_PATH': 'str, path for kiloword data', 'MNE_DATASETS_FIELDTRIP_CMC_PATH': 'str, path for fieldtrip_cmc data', 'MNE_DATASETS_PHANTOM_KIT_PATH': 'str, path for phantom_kit data', 'MNE_DATASETS_PHANTOM_4DBTI_PATH': 'str, path for phantom_4dbti data', 'MNE_DATASETS_PHANTOM_KERNEL_PATH': 'str, path for phantom_kernel data', 'MNE_DATASETS_LIMO_PATH': 'str, path for limo data', 'MNE_DATASETS_REFMEG_NOISE_PATH': 'str, path for refmeg_noise data', 'MNE_DATASETS_SSVEP_PATH': 'str, path for ssvep data', 'MNE_DATASETS_ERP_CORE_PATH': 'str, path for erp_core data', 'MNE_FORCE_SERIAL': 'bool, force serial rather than parallel execution', 'MNE_LOGGING_LEVEL': 'str or int, controls the level of verbosity of any function decorated with @verbose. See https://mne.tools/stable/auto_tutorials/intro/50_configure_mne.html#logging', 'MNE_MEMMAP_MIN_SIZE': 'str, threshold on the minimum size of arrays passed to the workers that triggers automated memory mapping, e.g., 1M or 0.5G', 'MNE_REPR_HTML': 'bool, represent some of our objects with rich HTML in a notebook environment', 'MNE_SKIP_NETWORK_TESTS': 'bool, used in a test decorator (@requires_good_network) to skip tests that include large downloads', 'MNE_SKIP_TESTING_DATASET_TESTS': 'bool, used in test decorators (@requires_spm_data, @requires_bstraw_data) to skip tests that require specific datasets', 'MNE_STIM_CHANNEL': 'string, the default channel name for mne.find_events', 'MNE_TQDM': 'str, either "tqdm", "tqdm.auto", or "off". Controls presence/absence of progress bars', 'MNE_USE_CUDA': 'bool, use GPU for filtering/resampling', 'MNE_USE_NUMBA': 'bool, use Numba just-in-time compiler for some of our intensive computations', 'SUBJECTS_DIR': 'path-like, directory of freesurfer MRI files for each subject'}
It is possible to add config variables that are not part of the recognized
list, by passing any arbitrary key to set_config()
. This will
yield a warning, however, which is a nice check in cases where you meant to
set a valid key but simply misspelled it:
mne.set_config("MNEE_USE_CUUDAA", "false")
/home/circleci/project/tutorials/intro/50_configure_mne.py:79: RuntimeWarning: Setting non-standard config type: "MNEE_USE_CUUDAA"
mne.set_config("MNEE_USE_CUUDAA", "false")
Attempting to create new mne-python configuration file:
/home/circleci/.mne/temp/.mne/mne-python.json
Let’s delete that config variable we just created. To unset a config
variable, use set_config()
with value=None
. Since we’re still
dealing with an unrecognized key (as far as MNE-Python is concerned) we’ll
still get a warning, but the key will be unset:
mne.set_config("MNEE_USE_CUUDAA", None)
assert "MNEE_USE_CUUDAA" not in mne.get_config("")
/home/circleci/project/tutorials/intro/50_configure_mne.py:87: RuntimeWarning: Setting non-standard config type: "MNEE_USE_CUUDAA"
mne.set_config("MNEE_USE_CUUDAA", None)
Where configurations are stored#
MNE-Python stores configuration variables in a JSON file. By default, this
file is located in %USERPROFILE%\.mne\mne-python.json
on Windows
and $HOME/.mne/mne-python.json
on Linux or macOS. You can get the
full path to the config file with mne.get_config_path()
.
print(mne.get_config_path())
/home/circleci/.mne/temp/.mne/mne-python.json
However it is not a good idea to directly edit files in the .mne
directory; use the getting and setting functions described in the
previous section.
If for some reason you want to load the configuration from a different
location, you can pass the home_dir
parameter to
get_config_path()
, specifying the parent directory of the
.mne
directory where the configuration file you wish to load is
stored.
Using environment variables#
For compatibility with MNE-C, MNE-Python
also reads and writes environment variables to specify configuration. This
is done with the same functions that read and write the JSON configuration,
and is controlled with the parameters use_env
and set_env
. By
default, get_config()
will check os.environ
before
checking the MNE-Python JSON file; to check only the JSON file use
use_env=False
. To demonstrate, here’s an environment variable that is not
specific to MNE-Python (and thus is not in the JSON config file):
# make sure it's not in the JSON file (no error means our assertion held):
assert mne.get_config("PATH", use_env=False) is None
# but it *is* in the environment:
print(mne.get_config("PATH"))
/home/circleci/python_env/bin:/home/circleci/.local/bin/:/home/circleci/minimal_cmds/bin:/home/circleci/.go_workspace/bin:/usr/local/go/bin:/opt/google/google-cloud-sdk/bin:/opt/circleci/.rbenv/shims:/opt/circleci/.rbenv/bin:/opt/circleci/.pyenv/shims:/opt/circleci/.pyenv/bin:/usr/local/apache-maven/bin:/home/circleci/.yarn/bin:/home/circleci/.config/yarn/global/node_modules/.bin:/home/circleci/bin:/home/circleci/.go_workspace/bin:/usr/local/go/bin:/opt/google/google-cloud-sdk/bin:/opt/circleci/.rbenv/shims:/opt/circleci/.rbenv/bin:/opt/circleci/.pyenv/shims:/opt/circleci/.pyenv/bin:/usr/local/apache-maven/bin:/home/circleci/.yarn/bin:/home/circleci/.config/yarn/global/node_modules/.bin:/opt/circleci/.nvm/versions/node/v22.11.0/bin:/home/circleci/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/usr/local/gradle-8.11/bin:/usr/local/gradle-8.11/bin
Also by default, set_config()
will set values in both the JSON
file and in os.environ
; to set a config variable only in the JSON
file use set_env=False
. Here we’ll use print()
statement to confirm
that an environment variable is being created and deleted (we could have used
the Python assert statement instead, but it doesn’t print any
output when it succeeds so it’s a little less obvious):
mne.set_config("foo", "bar", set_env=False)
print("foo" in os.environ.keys())
mne.set_config("foo", "bar")
print("foo" in os.environ.keys())
mne.set_config("foo", None) # unsetting a key deletes var from environment
print("foo" in os.environ.keys())
/home/circleci/project/tutorials/intro/50_configure_mne.py:138: RuntimeWarning: Setting non-standard config type: "foo"
mne.set_config("foo", "bar", set_env=False)
False
/home/circleci/project/tutorials/intro/50_configure_mne.py:140: RuntimeWarning: Setting non-standard config type: "foo"
mne.set_config("foo", "bar")
True
/home/circleci/project/tutorials/intro/50_configure_mne.py:142: RuntimeWarning: Setting non-standard config type: "foo"
mne.set_config("foo", None) # unsetting a key deletes var from environment
False
Logging#
One important configuration variable is MNE_LOGGING_LEVEL
. Throughout the
module, messages are generated describing the actions MNE-Python is taking
behind-the-scenes. How you set MNE_LOGGING_LEVEL
determines how many of
those messages you see. The default logging level on a fresh install of
MNE-Python is info
:
print(mne.get_config("MNE_LOGGING_LEVEL"))
None
The logging levels that can be set as config variables are debug
,
info
, warning
, error
, and critical
. Around 90% of the log
messages in MNE-Python are info
messages, so for most users the choice is
between info
(tell me what is happening) and warning
(tell me only if
something worrisome happens). The debug
logging level is intended for
MNE-Python developers.
In an earlier section we saw how
mne.set_config()
is used to change the logging level for the current
Python session and all future sessions. To change the logging level only for
the current Python session, you can use mne.set_log_level()
instead.
The set_log_level()
function takes the same five string options
that are used for the MNE_LOGGING_LEVEL
config variable; additionally, it
can accept int
or bool
values that are equivalent to those
strings. The equivalencies are given in this table:
String |
Integer |
Boolean |
---|---|---|
DEBUG |
10 |
|
INFO |
20 |
True |
WARNING |
30 |
False |
ERROR |
40 |
|
CRITICAL |
50 |
With many MNE-Python functions it is possible to change the logging level
temporarily for just that function call, by using the verbose
parameter.
To illustrate this, we’ll load some sample data with different logging levels
set. First, with log level warning
:
kit_data_path = os.path.join(
os.path.abspath(os.path.dirname(mne.__file__)),
"io",
"kit",
"tests",
"data",
"test.sqd",
)
raw = mne.io.read_raw_kit(kit_data_path, verbose="warning")
No messages were generated, because none of the messages were of severity
“warning” or worse. Next, we’ll load the same file with log level info
(the default level):
raw = mne.io.read_raw_kit(kit_data_path, verbose="info")
Extracting SQD Parameters from /home/circleci/project/mne/io/kit/tests/data/test.sqd...
Creating Raw.info structure...
Setting channel info structure...
Creating Info structure...
Ready.
This time, we got a few messages about extracting information from the file,
converting that information into the MNE-Python Info
format,
etc. Finally, if we request debug
-level information, we get even more
detail – and we do so this time using the mne.use_log_level()
context
manager, which is another way to accomplish the same thing as passing
verbose='debug'
:
with mne.use_log_level("debug"):
raw = mne.io.read_raw_kit(kit_data_path)
Extracting SQD Parameters from /home/circleci/project/mne/io/kit/tests/data/test.sqd...
Creating Raw.info structure...
KIT dir entry 0 @ 16
KIT dir entry 1 @ 32
KIT dir entry 2 @ 48
KIT dir entry 3 @ 64
KIT dir entry 4 @ 80
KIT dir entry 5 @ 96
KIT dir entry 6 @ 112
KIT dir entry 7 @ 128
KIT dir entry 8 @ 144
KIT dir entry 9 @ 160
KIT dir entry 10 @ 176
KIT dir entry 11 @ 192
KIT dir entry 12 @ 208
KIT dir entry 13 @ 224
KIT dir entry 14 @ 240
KIT dir entry 15 @ 256
KIT dir entry 16 @ 272
KIT dir entry 17 @ 288
KIT dir entry 18 @ 304
KIT dir entry 19 @ 320
KIT dir entry 20 @ 336
KIT dir entry 21 @ 352
KIT dir entry 22 @ 368
KIT dir entry 23 @ 384
KIT dir entry 24 @ 400
KIT dir entry 25 @ 416
KIT dir entry 26 @ 432
KIT dir entry 27 @ 448
KIT dir entry 28 @ 464
KIT dir entry 29 @ 480
KIT dir entry 30 @ 496
SQD file basic information:
Meg160 version = V2R004
System ID = 34
System name = NYU 160ch System since Jan24 2009
Model name = EQ1160C
Channel count = 192
Comment =
Dewar style = 2
FLL type = 10
Trigger type = 21
A/D board type = 12
ADC range = +/-5.0[V]
ADC allocate = 16[bit]
ADC bit = 12[bit]
Setting channel info structure...
Creating Info structure...
Ready.
We’ve been passing string values to the verbose
parameter, but we can see
from the table above that verbose=True
will
give us the info
messages and verbose=False
will suppress them; this
is a useful shorthand to use in scripts, so you don’t have to remember the
specific names of the different logging levels. One final note:
verbose=None
(which is the default for functions that have a verbose
parameter) will fall back on whatever logging level was most recently set by
mne.set_log_level()
, or if that hasn’t been called during the current
Python session, it will fall back to the value of
mne.get_config('MNE_LOGGING_LEVEL')
.
Getting information about your system#
You can also get information about what mne
imports as dependencies from
your system. This can be done via the command line with:
$ mne sys_info
Or you can use mne.sys_info()
directly, which prints to stdout
by
default:
Platform Linux-6.8.0-1018-aws-x86_64-with-glibc2.39
Python 3.12.3 (main, Nov 6 2024, 18:32:19) [GCC 13.2.0]
Executable /home/circleci/python_env/bin/python
CPU Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz (4 cores)
Memory 15.3 GiB
Core
├☑ mne 1.10.0.dev3+g05bd73874 (devel, latest release is 1.9.0)
├☑ numpy 2.0.2 (OpenBLAS 0.3.27 with 1 thread)
├☑ scipy 1.14.1
└☑ matplotlib 3.10.0 (backend=agg)
Numerical (optional)
├☑ sklearn 1.6.0
├☑ numba 0.60.0
├☑ nibabel 5.3.2
├☑ nilearn 0.11.0
├☑ dipy 1.10.0
├☑ openmeeg 2.5.14
├☑ pandas 2.2.3
├☑ h5io 0.2.4
├☑ h5py 3.12.1
└☐ unavailable cupy
Visualization (optional)
├☑ pyvista 0.45.dev0 (OpenGL 4.5 (Core Profile) Mesa 24.0.9-0ubuntu0.3 via llvmpipe (LLVM 17.0.6, 256 bits))
├☑ pyvistaqt 0.11.1
├☑ vtk 9.3.1
├☑ qtpy 2.4.2 (PyQt6=6.8.1)
├☑ ipympl 0.9.5
├☑ pyqtgraph 0.13.7
├☑ mne-qt-browser 0.6.3
├☑ ipywidgets 8.1.5
├☑ trame_client 3.5.0
├☑ trame_server 3.2.3
├☑ trame_vtk 2.8.12
└☑ trame_vuetify 2.7.2
Ecosystem (optional)
├☑ mne-bids 0.17.0.dev13+g46f284b
├☑ mne-nirs 0.7.1
├☑ mne-features 0.3
├☑ mne-connectivity 0.7.0
├☑ mne-icalabel 0.7.0
├☑ mne-bids-pipeline 1.9.0
├☑ neo 0.13.2
├☑ edfio 0.4.5
├☑ mffpy 0.10.0
├☑ pybv 0.7.6
└☐ unavailable eeglabio
Total running time of the script: (0 minutes 11.147 seconds)