code: def annotate_break(
      raw,
      events=None,
      min_break_duration=15.0,
      t_start_after_previous=5.0,
      t_stop_before_next=5.0,
      ignore=("bad", "edge"),
      *,
      verbose=None,
  ):
      """Create `~mne.Annotations` for breaks in an ongoing recording.
  
      This function first searches for segments in the data that are not
      annotated or do not contain any events and are at least
      ``min_break_duration`` seconds long, and then proceeds to creating
      annotations for those break periods.
  
      Parameters
      ----------
      raw : instance of Raw
          The continuous data to analyze.
      events : None | array, shape (n_events, 3)
          If ``None`` (default), operate based solely on the annotations present
          in ``raw``. If an events array, ignore any annotations in the raw data,
          and operate based on these events only.
      min_break_duration : float
          The minimum time span in seconds between the offset of one and the
          onset of the subsequent annotation (if ``events`` is ``None``) or
          between two consecutive events (if ``events`` is an array) to consider
          this period a "break". Defaults to 15 seconds.
  
          .. note:: This value defines the minimum duration of a break period in
                    the data, **not** the minimum duration of the generated
                    annotations! See also ``t_start_after_previous`` and
                    ``t_stop_before_next`` for details.
  
      t_start_after_previous, t_stop_before_next : float
          Specifies how far the to-be-created "break" annotation extends towards
          the two annotations or events spanning the break. This can be used to
          ensure e.g. that the break annotation doesn't start and end immediately
          with a stimulation event. If, for example, your data contains a break
          of 30 seconds between two stimuli, and ``t_start_after_previous`` is
          set to ``5`` and ``t_stop_before_next`` is set to ``3``, the break
          annotation will start 5 seconds after the first stimulus, and end 3
          seconds before the second stimulus, yielding an annotated break of
          ``30 - 5 - 3 = 22`` seconds. Both default to 5 seconds.
  
          .. note:: The beginning and the end of the recording will be annotated
                    as breaks, too, if the period from recording start until the
                    first annotation or event (or from last annotation or event
                    until recording end) is at least ``min_break_duration``
                    seconds long.
  
      ignore : iterable of str
          Annotation descriptions starting with these strings will be ignored by
          the break-finding algorithm. The string comparison is case-insensitive,
          i.e., ``('bad',)`` and ``('BAD',)`` are equivalent. By default, all
          annotation descriptions starting with "bad" and annotations
          indicating "edges" (produced by data concatenation) will be
          ignored. Pass an empty list or tuple to take all existing annotations
          into account. If ``events`` is passed, this parameter has no effect.
      %(verbose)s
  
      Returns
      -------
      break_annotations : instance of Annotations
          The break annotations, each with the description ``'BAD_break'``. If
          no breaks could be found given the provided function parameters, an
          empty `~mne.Annotations` object will be returned.
  
      Notes
      -----
      .. versionadded:: 0.24
      """
      _validate_type(
          item=raw, item_name="raw", types=BaseRaw, type_name="Raw"
      )
      _validate_type(
          item=events, item_name="events", types=(None, np.ndarray)
      )
  
      if (
          min_break_duration
          - t_start_after_previous
          - t_stop_before_next
          <= 0
      ):
          annot_dur = (
              min_break_duration
              - t_start_after_previous
              - t_stop_before_next
          )
          raise ValueError(
              f"The result of "
              f"min_break_duration - t_start_after_previous - "
              f"t_stop_before_next must be greater than 0, but it is: "
              f"{annot_dur}"
          )
  
      if events is not None and events.size == 0:
          raise ValueError("The events array must not be empty.")
  
      if events is not None or not ignore:
          ignore = tuple()
      else:
          ignore = tuple(ignore)
  
      for item in ignore:
          _validate_type(
              item=item,
              types="str",
              item_name='All elements of "ignore"',
          )
  
      if events is None:
          annotations = raw.annotations.copy()
          if ignore:
              logger.info(
                  f"Ignoring annotations with descriptions starting "
                  f'with: {", ".join(ignore)}'
              )
      else:
          annotations = annotations_from_events(
              events=events,
              sfreq=raw.info["sfreq"],
              orig_time=raw.info["meas_date"],
          )
  
      if not annotations:
          raise ValueError(
              "Could not find (or generate) any annotations in "
              "your data."
          )
  
      # Only keep annotations of interest and extract annotated time periods
      # Ignore case
      ignore = tuple(i.lower() for i in ignore)
      keep_mask = [True] * len(annotations)
      for idx, description in enumerate(annotations.description):
          description = description.lower()
          if any(description.startswith(i) for i in ignore):
              keep_mask[idx] = False
  
      annotated_intervals = [
          [onset, onset + duration]
          for onset, duration in zip(
              annotations.onset[keep_mask],
              annotations.duration[keep_mask],
          )
      ]
  
      # Merge overlapping annotation intervals
      # Pre-load `merged_intervals` with the first interval to simplify
      # processing
      merged_intervals = [annotated_intervals[0]]
      for interval in annotated_intervals:
          merged_interval_stop = merged_intervals[-1][1]
          interval_start, interval_stop = interval
  
          if interval_stop < merged_interval_stop:
              # Current interval ends sooner than the merged one; skip it
              continue
          elif (
              interval_start <= merged_interval_stop
              and interval_stop >= merged_interval_stop
          ):
              # Expand duration of the merged interval
              merged_intervals[-1][1] = interval_stop
          else:
              # No overlap between the current interval and the existing merged
              # time period; proceed to the next interval
              merged_intervals.append(interval)
  
      merged_intervals = np.array(merged_intervals)
      merged_intervals -= raw.first_time  # work in zero-based time
  
      # Now extract the actual break periods
      break_onsets = []
      break_durations = []
  
      # Handle the time period up until the first annotation
      if (
          0 < merged_intervals[0][0]
          and merged_intervals[0][0] >= min_break_duration
      ):
          onset = 0  # don't add t_start_after_previous here
          offset = merged_intervals[0][0] - t_stop_before_next
          duration = offset - onset
          break_onsets.append(onset)
          break_durations.append(duration)
  
      # Handle the time period between first and last annotation
      for idx, _ in enumerate(merged_intervals[1:, :], start=1):
          this_start = merged_intervals[idx, 0]
          previous_stop = merged_intervals[idx - 1, 1]
          if this_start - previous_stop < min_break_duration:
              continue
  
          onset = previous_stop + t_start_after_previous
          offset = this_start - t_stop_before_next
          duration = offset - onset
          break_onsets.append(onset)
          break_durations.append(duration)
  
      # Handle the time period after the last annotation
      if (
          raw.times[-1] > merged_intervals[-1][1]
          and raw.times[-1] - merged_intervals[-1][1]
          >= min_break_duration
      ):
          onset = merged_intervals[-1][1] + t_start_after_previous
          offset = raw.times[
              -1
          ]  # don't subtract t_stop_before_next here
          duration = offset - onset
          break_onsets.append(onset)
          break_durations.append(duration)
  
      # Finally, create the break annotations
      break_annotations = Annotations(
          onset=break_onsets,
          duration=break_durations,
          description=["BAD_break"],
          orig_time=raw.info["meas_date"],
      )
  
      # Log some info
      n_breaks = len(break_annotations)
      break_times = [
          f"{o:.1f} – {o + d:.1f} s [{d:.1f} s]"
          for o, d in zip(
              break_annotations.onset, break_annotations.duration
          )
      ]
      break_times = "\n    ".join(break_times)
      total_break_dur = sum(break_annotations.duration)
      fraction_breaks = total_break_dur / raw.times[-1]
      logger.info(
          f"\nDetected {n_breaks} break period{_pl(n_breaks)} of >= "
          f"{min_break_duration} s duration:\n    {break_times}\n"
          f"In total, {round(100 * fraction_breaks, 1):.1f}% of the "
          f"data ({round(total_break_dur, 1):.1f} s) have been marked "
          f"as a break.\n"
      )
      _adjust_onset_meas_date(break_annotations, raw)
  
      return break_annotations
  
file_path: mne-python/mne/preprocessing/artifact_detection.py
imports: import numpy
  from scipy.ndimage import distance_transform_edt, label
  from scipy.signal import find_peaks
  from scipy.stats import zscore
  from ..annotations import Annotations, _adjust_onset_meas_date, _annotations_starts_stops, annotations_from_events
  from ..filter import filter_data
  from ..io.base import BaseRaw
  from ..transforms import Transform, _angle_between_quats, _average_quats, _quat_to_affine, apply_trans, quat_to_rot
  from ..utils import _mask_to_onsets_offsets, _pl, _validate_type, logger, verbose
label_desc: Use image node_id 5 for calling a global function with example usage: annotate_break(raw, events, min_break_duration, t_start_after_previous, t_stop_before_next, ignore) and returns: break_annotations