.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_tutorials/plot_10_quality_control.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_tutorials_plot_10_quality_control.py: .. _tut-qc: Acquisition quality control =========================== Before cleaning a recording, check how well it was made: a flat channel, a loose EOG electrode, a head that moved, or a sidecar that disagrees with the data are better found the day the data were recorded than months later. :mod:`meeg_utils.qc` answers these questions without changing the data. This tutorial runs it on MNE's ``sample`` recording (Neuromag MEG and EEG). .. GENERATED FROM PYTHON SOURCE LINES 14-16 .. code-block:: Python :dedent: 1 .. GENERATED FROM PYTHON SOURCE LINES 19-31 .. code-block:: Python import mne import meeg_utils as meu from meeg_utils import qc mne.set_log_level("ERROR") data_path = mne.datasets.sample.data_path() meg_dir = data_path / "MEG" / "sample" raw = mne.io.read_raw_fif(meg_dir / "sample_audvis_raw.fif").load_data() raw.info["line_freq"] = 60.0 .. GENERATED FROM PYTHON SOURCE LINES 32-37 Run every check --------------- :func:`~meeg_utils.qc.inspect` picks the checks that apply to the data (MEG, EEG, the acquisition system, BIDS) and lists the others with the reason they were skipped: .. GENERATED FROM PYTHON SOURCE LINES 37-40 .. code-block:: Python report = qc.inspect(raw) print(report) .. rst-class:: sphx-glr-script-out .. code-block:: none ok amplitude ok bridging warn outlier_channels - outlying EEG channels (LOF > 1.5): 1 (> 0); EEG 007 warn narrowband_noise - GRAD channels with unusually strong line noise: 2 (> 0); check their contact: MEG 1033, MEG 1042 - EEG channels with unusually strong line noise: 1 (> 0); check their contact: EEG 025 info muscle info blinks info heart_rate warn squid_jumps - SQUID jumps: 8 (> 0); in ['MEG 2313']; mark the channels bad or annotate the jumps ok digitization ok events skip impedance: found no impedances in the recording (pass impedances=...) skip head_movement: found no continuous head localization (cHPI) in the recording skip chpi_snr: found no continuous head localization (cHPI) in the recording skip empty_room: needs an empty-room recording (the recording is not in a BIDS dataset) skip bids_metadata: the recording is not in a BIDS dataset .. GENERATED FROM PYTHON SOURCE LINES 41-57 Each finding has a level: ``fail`` / ``warn`` A problem by definition (a flat channel, a SQUID jump, a bridged electrode, a sidecar that disagrees with the data) or a channel that stands out from the others in this recording. ``ok`` The criterion was checked and passed. ``info`` A measurement without a verdict: head movement, blink rate, heart rate, muscle activity, ... Their normal range depends on the participants and the setup (children move more than adults, passive electrodes have higher impedances than active ones), so meeg-utils does not pretend to know it. ``report.flags`` lists the problems, worst first: .. GENERATED FROM PYTHON SOURCE LINES 57-60 .. code-block:: Python for finding in report.flags: print(f"{finding.level:4} {finding.check}: {finding.message}") .. rst-class:: sphx-glr-script-out .. code-block:: none warn outlier_channels: outlying EEG channels (LOF > 1.5): 1 (> 0); EEG 007 warn narrowband_noise: GRAD channels with unusually strong line noise: 2 (> 0); check their contact: MEG 1033, MEG 1042 warn narrowband_noise: EEG channels with unusually strong line noise: 1 (> 0); check their contact: EEG 025 warn squid_jumps: SQUID jumps: 8 (> 0); in ['MEG 2313']; mark the channels bad or annotate the jumps .. GENERATED FROM PYTHON SOURCE LINES 61-65 Look at what was measured ------------------------- Every check draws what it measured. Channels that stand out from the others (Local Outlier Factor, per channel type): .. GENERATED FROM PYTHON SOURCE LINES 65-67 .. code-block:: Python figs = report.checks["outlier_channels"].plot() .. image-sg:: /auto_tutorials/images/sphx_glr_plot_10_quality_control_001.png :alt: MAG: outlying channels [], GRAD: outlying channels [], EEG: outlying channels ['EEG 007'] :srcset: /auto_tutorials/images/sphx_glr_plot_10_quality_control_001.png, /auto_tutorials/images/sphx_glr_plot_10_quality_control_001_2_00x.png 2.00x :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 68-70 Blinks show whether the EOG electrodes work; the average blink should look like one: .. GENERATED FROM PYTHON SOURCE LINES 70-72 .. code-block:: Python figs = report.checks["blinks"].plot() .. image-sg:: /auto_tutorials/images/sphx_glr_plot_10_quality_control_002.png :alt: 46 blinks, 9.9/min, Average :srcset: /auto_tutorials/images/sphx_glr_plot_10_quality_control_002.png, /auto_tutorials/images/sphx_glr_plot_10_quality_control_002_2_00x.png 2.00x :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 73-76 Without an ECG channel, MNE builds a synthetic ECG from the magnetometers. meeg-utils judges the heartbeat detection by how regular the intervals between beats are, and does not report a rate it cannot trust: .. GENERATED FROM PYTHON SOURCE LINES 76-79 .. code-block:: Python print(report.checks["heart_rate"].metrics_) figs = report.checks["heart_rate"].plot() .. image-sg:: /auto_tutorials/images/sphx_glr_plot_10_quality_control_003.png :alt: 286 beats, 62 bpm (synthetic), Average :srcset: /auto_tutorials/images/sphx_glr_plot_10_quality_control_003.png, /auto_tutorials/images/sphx_glr_plot_10_quality_control_003_2_00x.png 2.00x :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none {'heart_rate_bpm': 62.0, 'reliable': True, 'n_beats': 286, 'rr_sd_ms': 104.6, 'irregular_fraction': 0.007, 'channel': 'synthetic'} .. GENERATED FROM PYTHON SOURCE LINES 80-81 The digitized head shape, the sphere fitted to it, and the MEG sensors: .. GENERATED FROM PYTHON SOURCE LINES 81-83 .. code-block:: Python figs = report.checks["digitization"].plot() .. image-sg:: /auto_tutorials/images/sphx_glr_plot_10_quality_control_004.png :alt: Digitization (head frame): sphere radius 91 mm, top, side, front :srcset: /auto_tutorials/images/sphx_glr_plot_10_quality_control_004.png, /auto_tutorials/images/sphx_glr_plot_10_quality_control_004_2_00x.png 2.00x :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 84-85 The events found in the recording: .. GENERATED FROM PYTHON SOURCE LINES 85-87 .. code-block:: Python figs = report.checks["events"].plot() .. image-sg:: /auto_tutorials/images/sphx_glr_plot_10_quality_control_005.png :alt: plot 10 quality control :srcset: /auto_tutorials/images/sphx_glr_plot_10_quality_control_005.png, /auto_tutorials/images/sphx_glr_plot_10_quality_control_005_2_00x.png 2.00x :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 88-93 The empty room -------------- The empty-room recording of the session shows the noise of the sensors and the room on the day. In a BIDS dataset it is found automatically; here we pass the file: .. GENERATED FROM PYTHON SOURCE LINES 93-97 .. code-block:: Python er = qc.EmptyRoom(empty_room=meg_dir / "ernoise_raw.fif").compute(raw) print(er.metrics_["mag"], er.metrics_["grad"], sep="\n") figs = er.plot() .. image-sg:: /auto_tutorials/images/sphx_glr_plot_10_quality_control_006.png :alt: Recording and empty room, MAG, GRAD :srcset: /auto_tutorials/images/sphx_glr_plot_10_quality_control_006.png, /auto_tutorials/images/sphx_glr_plot_10_quality_control_006_2_00x.png 2.00x :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none {'noise_floor': 3.989, 'unit': 'fT/√Hz', 'recording_above_db': 8.23, 'outlier_channels': ['MEG 0321', 'MEG 0411', 'MEG 0541', 'MEG 0631', 'MEG 2211', 'MEG 2441']} {'noise_floor': 2.718, 'unit': 'fT/cm/√Hz', 'recording_above_db': 1.5, 'outlier_channels': ['MEG 0613', 'MEG 1332', 'MEG 2422']} .. GENERATED FROM PYTHON SOURCE LINES 98-103 Your own thresholds ------------------- The measurements reported as ``info`` become verdicts when you give them a threshold that fits your participants and equipment. Every threshold is a parameter of its check: .. GENERATED FROM PYTHON SOURCE LINES 103-113 .. code-block:: Python report = qc.inspect( raw, checks=[ qc.Blinks(min_rate=5), # blinks per minute qc.Muscle(warn_fraction=0.05), # share of the recording qc.Events(expected={"1": 72, "2": 73, "3": 73, "4": 71}), ], ) print(report) .. rst-class:: sphx-glr-script-out .. code-block:: none ok blinks ok muscle ok events .. GENERATED FROM PYTHON SOURCE LINES 114-130 A whole dataset --------------- Across many recordings the ``info`` measurements get a reference: the rest of the dataset. :func:`~meeg_utils.qc.inspect_dataset` runs the checks on every recording of a BIDS dataset and flags the recordings that stand out on any metric (modified z-score above 3.5): .. code-block:: python result = meu.qc.inspect_dataset("bids/", n_jobs=8) result.outliers # recording, metric, value, z result.to_csv("qc/summary.csv") result.plot()["levels"] # recordings x checks or from the command line: ``meu qc bids/ --out qc/``, which also writes an HTML report per recording with :func:`meeg_utils.report.build`: .. GENERATED FROM PYTHON SOURCE LINES 130-132 .. code-block:: Python html = meu.report.build(qc=qc.inspect(raw), title="QC of sample_audvis_raw") html .. rst-class:: sphx-glr-script-out .. code-block:: none .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 49.835 seconds) .. _sphx_glr_download_auto_tutorials_plot_10_quality_control.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_10_quality_control.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_10_quality_control.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_10_quality_control.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_