code: def plot_epochs(
      epochs,
      picks=None,
      scalings=None,
      n_epochs=20,
      n_channels=20,
      title=None,
      events=False,
      event_color=None,
      order=None,
      show=True,
      block=False,
      decim="auto",
      noise_cov=None,
      butterfly=False,
      show_scrollbars=True,
      show_scalebars=True,
      epoch_colors=None,
      event_id=None,
      group_by="type",
      precompute=None,
      use_opengl=None,
      *,
      theme=None,
      overview_mode=None,
      splash=True,
  ):
      """Visualize epochs.
  
      Bad epochs can be marked with a left click on top of the epoch. Bad
      channels can be selected by clicking the channel name on the left side of
      the main axes. Calling this function drops all the selected bad epochs as
      well as bad epochs marked beforehand with rejection parameters.
  
      Parameters
      ----------
      epochs : instance of Epochs
          The epochs object.
      %(picks_good_data)s
      %(scalings)s
      n_epochs : int
          The number of epochs per view. Defaults to 20.
      n_channels : int
          The number of channels per view. Defaults to 20.
      title : str | None
          The title of the window. If None, the event names (from
          ``epochs.event_id``) will be displayed. Defaults to None.
      events : bool | array, shape (n_events, 3)
          Events to show with vertical bars. You can use `~mne.viz.plot_events`
          as a legend for the colors. By default, the coloring scheme is the
          same. ``True`` plots ``epochs.events``. Defaults to ``False`` (do not
          plot events).
  
          .. warning::  If the epochs have been resampled, the events no longer
              align with the data.
  
          .. versionadded:: 0.14.0
  
          .. versionchanged:: 1.6
              Passing ``events=None`` was disallowed.
              The new equivalent is ``events=False``.
      %(event_color)s
          Defaults to ``None``.
      order : array of str | None
          Order in which to plot channel types.
  
          .. versionadded:: 0.18.0
      show : bool
          Show figure if True. Defaults to True.
      block : bool
          Whether to halt program execution until the figure is closed.
          Useful for rejecting bad trials on the fly by clicking on an epoch.
          Defaults to False.
      decim : int | 'auto'
          Amount to decimate the data during display for speed purposes.
          You should only decimate if the data are sufficiently low-passed,
          otherwise aliasing can occur. The 'auto' mode (default) uses
          the decimation that results in a sampling rate at least three times
          larger than ``info['lowpass']`` (e.g., a 40 Hz lowpass will result in
          at least a 120 Hz displayed sample rate).
  
          .. versionadded:: 0.15.0
      noise_cov : instance of Covariance | str | None
          Noise covariance used to whiten the data while plotting.
          Whitened data channels are scaled by ``scalings['whitened']``,
          and their channel names are shown in italic.
          Can be a string to load a covariance from disk.
          See also :meth:`mne.Evoked.plot_white` for additional inspection
          of noise covariance properties when whitening evoked data.
          For data processed with SSS, the effective dependence between
          magnetometers and gradiometers may introduce differences in scaling,
          consider using :meth:`mne.Evoked.plot_white`.
  
          .. versionadded:: 0.16.0
      butterfly : bool
          Whether to directly call the butterfly view.
  
          .. versionadded:: 0.18.0
      %(show_scrollbars)s
      %(show_scalebars)s
  
          .. versionadded:: 0.24.0
      epoch_colors : list of (n_epochs) list (of n_channels) | None
          Colors to use for individual epochs. If None, use default colors.
      event_id : bool | dict
          Determines to label the event markers on the plot. If ``True``, uses
          ``epochs.event_id``. If ``False``, uses integer event codes instead of IDs.
          If a ``dict`` is passed, uses its *keys* as event labels on the plot for
          entries whose *values* are integer codes for events being drawn. Ignored if
          ``events=False``.
  
          .. versionadded:: 0.20
      %(group_by_browse)s
      %(precompute)s
      %(use_opengl)s
      %(theme_pg)s
  
          .. versionadded:: 1.0
      %(overview_mode)s
  
          .. versionadded:: 1.1
      %(splash)s
  
          .. versionadded:: 1.6
  
      Returns
      -------
      %(browser)s
  
      Notes
      -----
      The arrow keys (up/down/left/right) can be used to navigate between
      channels and epochs and the scaling can be adjusted with - and + (or =)
      keys, but this depends on the backend matplotlib is configured to use
      (e.g., mpl.use(``TkAgg``) should work). Full screen mode can be toggled
      with f11 key. The amount of epochs and channels per view can be adjusted
      with home/end and page down/page up keys. ``h`` key plots a histogram of
      peak-to-peak values along with the used rejection thresholds. Butterfly
      plot can be toggled with ``b`` key. Left mouse click adds a vertical line
      to the plot. Click 'help' button at bottom left corner of the plotter to
      view all the options.
  
      %(notes_2d_backend)s
  
      .. versionadded:: 0.10.0
      """
      from ._figure import _get_browser
  
      epochs._handle_empty("raise", "plot")
      epochs.drop_bad()
      info = epochs.info.copy()
      sfreq = info["sfreq"]
      projs = info["projs"]
      projs_on = np.full_like(projs, epochs.proj, dtype=bool)
      if not epochs.proj:
          with info._unlock():
              info["projs"] = list()
  
      # handle defaults / check arg validity
      color = _handle_default("color", None)
      scalings = _compute_scalings(scalings, epochs)
      scalings = _handle_default("scalings_plot_raw", scalings)
      if scalings["whitened"] == "auto":
          scalings["whitened"] = 1.0
      units = _handle_default("units", None)
      unit_scalings = _handle_default("scalings", None)
      decim, picks_data = _handle_decim(epochs.info.copy(), decim, None)
      noise_cov = _check_cov(noise_cov, epochs.info)
      _check_option(
          "group_by",
          group_by,
          ("selection", "position", "original", "type"),
      )
      # handle event labels
      _validate_type(event_id, (bool, dict, None), "event_id")
      if not event_id:  # False or None
          event_id = dict()
      else:
          # make our own copy of the dict
          event_id = (
              dict() if event_id is True else event_id.copy()
          )  # to dict
          # TODO: when min py=3.9, change to `epochs.event_id | event_id` (maybe).
          # Passed-in event_id should take precedence, i.e., not replace existing
          # keys *or* repeat existing values. For example, if epochs.event_id has
          # a=1 and passed-in event_id has f=1, the second takes precedence.
          event_values = set(event_id.values())
          event_id.update(
              (k, v)
              for k, v in epochs.event_id.items()
              if k not in event_id and v not in event_values
          )
      event_id_rev = {v: k for k, v in event_id.items()}
      # validate epoch_colors
      _validate_type(epoch_colors, (list, None), "epoch_colors")
      if epoch_colors is not None:
          if len(epoch_colors) != len(epochs.events):
              msg = (
                  "epoch_colors must have length equal to the number of "
                  f"epochs ({len(epochs)}); got length {len(epoch_colors)}."
              )
              raise ValueError(msg)
          for ix, this_colors in enumerate(epoch_colors):
              _validate_type(this_colors, list, f"epoch_colors[{ix}]")
              if len(this_colors) != len(epochs.ch_names):
                  msg = (
                      f"epoch colors for epoch {ix} has length "
                      f"{len(this_colors)}, expected {len(epochs.ch_names)}."
                  )
                  raise ValueError(msg)
  
      # handle time dimension
      n_epochs = min(n_epochs, len(epochs))
      n_times = len(epochs) * len(epochs.times)
      duration = n_epochs * len(epochs.times) / sfreq
      # NB: this includes start and end of data:
      boundary_times = (
          np.arange(len(epochs) + 1) * len(epochs.times) / sfreq
      )
  
      # events
      _validate_type(events, (bool, np.ndarray), "events")
      if events is False:
          event_nums = None
          event_times = None
      else:  # True or ndarray
          if events is True:  # use epochs.events
              events = epochs.events
          event_nums = events[:, 2]
          event_samps = events[:, 0]
          epoch_n_samps = len(epochs.times)
          # handle overlapping epochs (each event may show up in multiple places)
          boundaries = epochs.events[:, [0]] + np.array(
              [-1, 1]
          ) * epochs.time_as_index([0, epochs.tmax])
          in_bounds = np.logical_and(
              boundaries[:, [0]] <= event_samps,
              event_samps < boundaries[:, [1]],
          )
          event_ixs = [np.nonzero(a)[0] for a in in_bounds.T]
          warned = False
          event_times = list()
          event_numbers = list()
          for samp, num, _ixs in zip(
              event_samps, event_nums, event_ixs
          ):
              relevant_epoch_events = epochs.events[:, 0][_ixs]
              if len(relevant_epoch_events) > 1 and not warned:
                  logger.info(
                      "You seem to have overlapping epochs. Some event "
                      "lines may be duplicated in the plot."
                  )
                  warned = True
              offsets = (
                  samp - relevant_epoch_events + epochs.time_as_index(0)
              )
              this_event_times = (
                  _ixs * epoch_n_samps + offsets
              ) / sfreq
              event_times.extend(this_event_times)
              event_numbers.extend([num] * len(_ixs))
          event_nums = np.array(event_numbers)
          event_times = np.array(event_times)
  
      event_color_dict = _make_event_color_dict(
          event_color, events, event_id
      )
  
      # determine trace order
      picks = _picks_to_idx(info, picks)
      n_channels = min(n_channels, len(picks))
      ch_names = np.array(epochs.ch_names)
      ch_types = np.array(epochs.get_channel_types())
      order = _get_channel_plotting_order(order, ch_types, picks)
      selections = None
      if group_by in ("selection", "position"):
          selections = _setup_channel_selections(
              epochs, group_by, order
          )
          order = np.concatenate(list(selections.values()))
          default_selection = list(selections)[0]
          n_channels = len(selections[default_selection])
  
      # generate window title
      if title is None:
          title = epochs._get_name(count="total", sep="•", ms=None)
          if title is None or len(title) == 0:
              title = "Epochs"
      elif not isinstance(title, str):
          raise TypeError(
              f"title must be None or a string, got a {type(title)}"
          )
  
      precompute = _handle_precompute(precompute)
      params = dict(
          inst=epochs,
          info=info,
          n_epochs=n_epochs,
          # channels and channel order
          ch_names=ch_names,
          ch_types=ch_types,
          ch_order=order,
          picks=order[:n_channels],
          n_channels=n_channels,
          picks_data=picks_data,
          group_by=group_by,
          ch_selections=selections,
          # time
          t_start=0,
          duration=duration,
          n_times=n_times,
          first_time=0,
          time_format="float",
          decim=decim,
          boundary_times=boundary_times,
          # events
          event_id_rev=event_id_rev,
          event_color_dict=event_color_dict,
          event_nums=event_nums,
          event_times=event_times,
          # preprocessing
          projs=projs,
          projs_on=projs_on,
          apply_proj=epochs.proj,
          remove_dc=True,
          filter_coefs=None,
          filter_bounds=None,
          noise_cov=noise_cov,
          use_noise_cov=noise_cov is not None,
          # scalings
          scalings=scalings,
          units=units,
          unit_scalings=unit_scalings,
          # colors
          ch_color_bad="lightgray",
          ch_color_dict=color,
          epoch_color_bad=(1, 0, 0),
          epoch_colors=epoch_colors,
          # display
          butterfly=butterfly,
          clipping=None,
          scrollbars_visible=show_scrollbars,
          scalebars_visible=show_scalebars,
          window_title=title,
          xlabel="Epoch number",
          # pyqtgraph-specific
          precompute=precompute,
          use_opengl=use_opengl,
          theme=theme,
          overview_mode=overview_mode,
          splash=splash,
      )
  
      fig = _get_browser(show=show, block=block, **params)
  
      return fig
  
file_path: mne-python/mne/viz/epochs.py
imports: from collections import Counter
  from copy import deepcopy
  import numpy
  from scipy.ndimage import gaussian_filter1d
  from .._fiff.meas_info import create_info
  from .._fiff.pick import _DATA_CH_TYPES_SPLIT, _VALID_CHANNEL_TYPES, _picks_to_idx
  from ..defaults import _handle_default
  from ..fixes import _sharex
  from ..utils import _check_option, fill_doc, legacy, logger, verbose, warn
  from ..utils.spectrum import _split_psd_kwargs
  from .raw import _setup_channel_selections
  from .utils import DraggableColorbar, _check_cov, _compute_scalings, _get_channel_plotting_order, _handle_decim, _handle_precompute, _make_combine_callable, _make_event_color_dict, _set_title_multiple_electrodes, _set_window_title, _setup_cmap, _setup_vmin_vmax, _validate_type, plt_show
label_desc: Use image node_id 6 for calling a global function with example usage: plot_epochs(epochs, picks, scalings, n_epochs, n_channels, title, events, event_color, order, show, block, decim, noise_cov, butterfly, show_scrollbars, show_scalebars, epoch_colors, event_id, group_by, precompute, use_opengl) and returns: fig