code: def _annotation_helper(raw, browse_backend, events=False):
      """Test interactive annotations."""
      ismpl = browse_backend.name == "matplotlib"
      # Some of our checks here require modern mpl to work properly
      n_anns = len(raw.annotations)
      browse_backend._close_all()
  
      if events:
          events = np.array(
              [
                  [raw.first_samp + 100, 0, 1],
                  [raw.first_samp + 300, 0, 3],
              ]
          )
          n_events = len(events)
      else:
          events = None
          n_events = 0
      fig = raw.plot(events=events)
      if ismpl:
          assert browse_backend._get_n_figs() == 1
  
      fig._fake_keypress("a")  # annotation mode
      ann_fig = fig.mne.fig_annotation
      if ismpl:
          assert browse_backend._get_n_figs() == 2
          # +3 from the scale bars
          n_scale = 3
          assert (
              len(fig.mne.ax_main.texts) == n_anns + n_events + n_scale
          )
      else:
          assert ann_fig.isVisible()
  
      # modify description to create label "BAD test"
      # semicolon is ignored
      if ismpl:
          for key in ["backspace"] + list(" test;") + ["enter"]:
              fig._fake_keypress(key, fig=ann_fig)
          # change annotation label
          for ix in (-1, 0):
              xy = _get_button_xy(ann_fig.mne.radio_ax.buttons, ix)
              fig._fake_click(
                  xy, fig=ann_fig, ax=ann_fig.mne.radio_ax, xform="data"
              )
      else:
          # The modal dialogs of the Qt-backend would block the test,
          # thus a new description will be added programmatically.
          ann_fig._add_description("BAD test")
  
      # draw annotation
      fig._fake_click(
          (1.0, 1.0),
          add_points=[(5.0, 1.0)],
          xform="data",
          button=1,
          kind="drag",
      )
      if ismpl:
          assert (
              len(fig.mne.ax_main.texts)
              == n_anns + 1 + n_events + n_scale
          )
          # test hover event
          fig._fake_keypress("p")  # first turn on draggable mode
          assert fig.mne.draggable_annotations
          hover_kwargs = dict(xform="data", button=None, kind="motion")
          fig._fake_click(
              (4.6, 1.0), **hover_kwargs
          )  # well inside ann.
          fig._fake_click((4.9, 1.0), **hover_kwargs)  # almost at edge
          assert fig.mne.annotation_hover_line is not None
          fig._fake_click(
              (5.5, 1.0), **hover_kwargs
          )  # well outside ann.
          assert fig.mne.annotation_hover_line is None
          # more tests of hover line
          fig._fake_click(
              (4.6, 1.0), **hover_kwargs
          )  # well inside ann.
          fig._fake_click((4.9, 1.0), **hover_kwargs)  # almost at edge
          assert fig.mne.annotation_hover_line is not None
          fig._fake_keypress(
              "p"
          )  # turn off draggable mode, then move a bit
          fig._fake_click((4.95, 1.0), **hover_kwargs)
          assert fig.mne.annotation_hover_line is None
          fig._fake_keypress("p")  # turn draggable mode back on
      assert len(raw.annotations.onset) == n_anns + 1
      assert len(raw.annotations.duration) == n_anns + 1
      assert len(raw.annotations.description) == n_anns + 1
      assert raw.annotations.description[n_anns] == "BAD test"
      onset = raw.annotations.onset[n_anns]
      want_onset = _sync_onset(raw, 1.0, inverse=True)
      # pyqtgraph: during the transformation from pixel-coordinates
      # to scene-coordinates when the click is simulated on QGraphicsView
      # with QTest, there seems to happen a rounding of pixels to integers
      # internally. This deviatian also seems to change between runs
      # (maybe device-dependent?).
      atol = 1e-10 if ismpl else 2e-2
      assert_allclose(onset, want_onset, atol=atol)
      assert_allclose(raw.annotations.duration[n_anns], 4.0, atol=atol)
      # modify annotation from end (duration 4 → 1.5)
      fig._fake_click(
          (4.9, 1.0), xform="data", button=1, kind="motion"
      )  # ease up to it
      fig._fake_click(
          (5.0, 1.0),
          add_points=[(2.5, 1.0)],
          xform="data",
          button=1,
          kind="drag",
      )
      assert raw.annotations.onset[n_anns] == onset
      # 4 → 1.5
      assert_allclose(raw.annotations.duration[n_anns], 1.5, atol=atol)
      # modify annotation from beginning (duration 1.5 → 2.0)
      fig._fake_click(
          (1.0, 1.0),
          add_points=[(0.5, 1.0)],
          xform="data",
          button=1,
          kind="drag",
      )
      assert_allclose(
          raw.annotations.onset[n_anns], onset - 0.5, atol=atol
      )
      # 1.5 → 2.0
      assert_allclose(raw.annotations.duration[n_anns], 2.0, atol=atol)
      assert len(raw.annotations.onset) == n_anns + 1
      assert len(raw.annotations.duration) == n_anns + 1
      assert len(raw.annotations.description) == n_anns + 1
      assert raw.annotations.description[n_anns] == "BAD test"
      if ismpl:
          assert (
              len(fig.axes[0].texts) == n_anns + 1 + n_events + n_scale
          )
          fig._fake_keypress("shift+right")
          assert len(fig.axes[0].texts) == n_scale
          fig._fake_keypress("shift+left")
          assert (
              len(fig.axes[0].texts) == n_anns + 1 + n_events + n_scale
          )
  
      # draw another annotation merging the two
      fig._fake_click(
          (5.5, 1.0),
          add_points=[(2.0, 1.0)],
          xform="data",
          button=1,
          kind="drag",
      )
      # delete the annotation
      assert len(raw.annotations.onset) == n_anns + 1
      assert len(raw.annotations.duration) == n_anns + 1
      assert len(raw.annotations.description) == n_anns + 1
      assert_allclose(
          raw.annotations.onset[n_anns], onset - 0.5, atol=atol
      )
      assert_allclose(raw.annotations.duration[n_anns], 5.0, atol=atol)
      if ismpl:
          assert (
              len(fig.axes[0].texts) == n_anns + 1 + n_events + n_scale
          )
      # Delete
      fig._fake_click((1.5, 1.0), xform="data", button=3, kind="press")
      # exit, re-enter, then exit a different way
      fig._fake_keypress("a")  # exit
      fig._fake_keypress("a")  # enter
      assert len(raw.annotations.onset) == n_anns
      if ismpl:
          fig._fake_keypress(
              "escape", fig=fig.mne.fig_annotation
          )  # exit again
          assert len(fig.axes[0].texts) == n_anns + n_events + n_scale
          fig._fake_keypress("shift+right")
          assert len(fig.axes[0].texts) == n_scale
          fig._fake_keypress("shift+left")
          assert len(fig.axes[0].texts) == n_anns + n_events + n_scale
  
imports: import itertools
  import os
  from copy import deepcopy
  import matplotlib.pyplot
  import numpy
  import pytest
  from matplotlib import backend_bases
  from numpy.testing import assert_allclose
  from mne import Annotations, create_info, pick_types
  from mne._fiff.pick import _DATA_CH_TYPES_ORDER_DEFAULT, _PICK_TYPES_DATA_DICT
  from mne.annotations import _sync_onset
  from mne.datasets import testing
  from mne.io import RawArray
  from mne.utils import _assert_no_instances, _dt_to_stamp, _record_warnings, check_version, get_config, set_config
  from mne.viz import plot_raw, plot_sensors
  from mne.viz.utils import _fake_click, _fake_keypress
label_desc: Use image node_id 2 for calling a global function with example usage: _annotation_helper(raw, browse_backend, events) without return types