""" .. _tut-info-class: ======================= The Info data structure ======================= This tutorial describes the :class:`mne.Info` data structure, which keeps track of various recording details, and is attached to :class:`~mne.io.Raw`, :class:`~mne.Epochs`, and :class:`~mne.Evoked` objects. We will begin by loading the Python modules we need, and loading the same :ref:`example data ` we used in the :ref:`introductory tutorial `: """ # Authors: The MNE-Python contributors. # License: BSD-3-Clause # Copyright the MNE-Python contributors. # %% import mne sample_data_folder = mne.datasets.sample.data_path() sample_data_raw_file = ( sample_data_folder / "MEG" / "sample" / "sample_audvis_filt-0-40_raw.fif" ) raw = mne.io.read_raw_fif(sample_data_raw_file) # %% # As seen in the :ref:`introductory tutorial `, when a # :class:`~mne.io.Raw` object is loaded, an :class:`~mne.Info` object is # created automatically, and stored in the ``raw.info`` attribute: print(raw.info) # %% # However, it is not strictly necessary to load the :class:`~mne.io.Raw` object # in order to view or edit the :class:`~mne.Info` object; you can extract all # the relevant information into a stand-alone :class:`~mne.Info` object using # :func:`mne.io.read_info`: info = mne.io.read_info(sample_data_raw_file) print(info) # %% # As you can see, the :class:`~mne.Info` object keeps track of a lot of # information about: # # - the recording system (gantry angle, HPI details, sensor digitizations, # channel names, ...) # - the experiment (project name and ID, subject information, recording date, # experimenter name or ID, ...) # - the data (sampling frequency, applied filter frequencies, bad channels, # projectors, ...) # # The complete list of fields is given in :class:`the API documentation # `. # # # Querying the ``Info`` object # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # The fields in a :class:`~mne.Info` object act like Python :class:`dictionary # ` keys, using square brackets and strings to access the contents of a # field: print(info.keys()) print() # insert a blank line print(info["ch_names"]) # %% # Most of the fields contain :class:`int`, :class:`float`, or :class:`list` # data, but the ``chs`` field bears special mention: it contains a list of # dictionaries (one :class:`dict` per channel) containing everything there is # to know about a channel other than the data it recorded. Normally it is not # necessary to dig into the details of the ``chs`` field — various MNE-Python # functions can extract the information more cleanly than iterating over the # list of dicts yourself — but it can be helpful to know what is in there. Here # we show the keys for the first channel's :class:`dict`: print(info["chs"][0].keys()) # %% # .. _picking_channels: # # Obtaining subsets of channels # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # It is often useful to convert between channel names and the integer indices # identifying rows of the data array where those channels' measurements are # stored. The :class:`~mne.Info` object is useful for this task; two # convenience functions that rely on the :class:`mne.Info` object for picking # channels are :func:`mne.pick_channels` and :func:`mne.pick_types`. # :func:`~mne.pick_channels` minimally takes a list of all channel names and a # list of channel names to include; it is also possible to provide an empty # list to ``include`` and specify which channels to ``exclude`` instead: print(mne.pick_channels(info["ch_names"], include=["MEG 0312", "EEG 005"])) print(mne.pick_channels(info["ch_names"], include=[], exclude=["MEG 0312", "EEG 005"])) # %% # :func:`~mne.pick_types` works differently, since channel type cannot always # be reliably determined from channel name alone. Consequently, # :func:`~mne.pick_types` needs an :class:`~mne.Info` object instead of just a # list of channel names, and has boolean keyword arguments for each channel # type. Default behavior is to pick only MEG channels (and MEG reference # channels if present) and exclude any channels already marked as "bad" in the # ``bads`` field of the :class:`~mne.Info` object. Therefore, to get *all* and # *only* the EEG channel indices (including the "bad" EEG channels) we must # pass ``meg=False`` and ``exclude=[]``: print(mne.pick_types(info, meg=False, eeg=True, exclude=[])) # %% # Note that the ``meg`` and ``fnirs`` parameters of :func:`~mne.pick_types` # accept strings as well as boolean values, to allow selecting only # magnetometer or gradiometer channels (via ``meg='mag'`` or ``meg='grad'``) or # to pick only oxyhemoglobin or deoxyhemoglobin channels (via ``fnirs='hbo'`` # or ``fnirs='hbr'``, respectively). # # A third way to pick channels from an :class:`~mne.Info` object is to apply # `regular expression`_ matching to the channel names using # :func:`mne.pick_channels_regexp`. Here the ``^`` represents the beginning of # the string and ``.`` character matches any single character, so both EEG and # EOG channels will be selected: print(mne.pick_channels_regexp(info["ch_names"], "^E.G")) # %% # :func:`~mne.pick_channels_regexp` can be especially useful for channels named # according to the `10-20 `_ system (e.g., to select all channels # ending in "z" to get the midline, or all channels beginning with "O" to get # the occipital channels). Note that :func:`~mne.pick_channels_regexp` uses the # Python standard module :mod:`re` to perform regular expression matching; see # the documentation of the :mod:`re` module for implementation details. # # .. warning:: # Both :func:`~mne.pick_channels` and :func:`~mne.pick_channels_regexp` # operate on lists of channel names, so they are unaware of which channels # (if any) have been marked as "bad" in ``info['bads']``. Use caution to # avoid accidentally selecting bad channels. # # # Obtaining channel type information # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # Sometimes it can be useful to know channel type based on its index in the # data array. For this case, use :func:`mne.channel_type`, which takes # an :class:`~mne.Info` object and a single integer channel index: print(mne.channel_type(info, 25)) # %% # To obtain several channel types at once, you could embed # :func:`~mne.channel_type` in a :term:`list comprehension`, or use the # :meth:`~mne.io.Raw.get_channel_types` method of a :class:`~mne.io.Raw`, # :class:`~mne.Epochs`, or :class:`~mne.Evoked` instance: picks = (25, 76, 77, 319) print([mne.channel_type(info, x) for x in picks]) print(raw.get_channel_types(picks=picks)) # %% # Alternatively, you can get the indices of all channels of *all* channel types # present in the data, using :func:`~mne.channel_indices_by_type`, # which returns a :class:`dict` with channel types as keys, and lists of # channel indices as values: ch_idx_by_type = mne.channel_indices_by_type(info) print(ch_idx_by_type.keys()) print(ch_idx_by_type["eog"]) # %% # Dropping channels from an ``Info`` object # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # If you want to modify an :class:`~mne.Info` object by eliminating some of the # channels in it, you can use the :func:`mne.pick_info` function to pick the # channels you want to keep and omit the rest: print(info["nchan"]) eeg_indices = mne.pick_types(info, meg=False, eeg=True) print(mne.pick_info(info, eeg_indices)["nchan"]) # %% # We can also get a nice HTML representation in IPython like this: info # %% # By default, :func:`~mne.pick_info` will make a copy of the original # :class:`~mne.Info` object before modifying it; if you want to modify it # in-place, include the parameter ``copy=False``. # # # .. LINKS # # .. _`regular expression`: https://en.wikipedia.org/wiki/Regular_expression # .. _`ten-twenty`: https://en.wikipedia.org/wiki/10%E2%80%9320_system_(EEG)