# spacepy.plot.utils.EventClicker

class spacepy.plot.utils.EventClicker(ax=None, n_phases=1, interval=None, auto_interval=None, auto_scale=True, ymin=None, ymax=None, line=None)

  Presents a provided figure (normally a time series) and provides an interface to mark events shown in the plot. The user interface is explained in `analyze()` and results are returned by `get_events()`

  Other Parameters:
    ax maplotlib.axes.AxesSubplot

      The subplot to display and grab data from. If not provided, the current subplot is grabbed from gca() (Lookup of the current subplot is done when `analyze()` is called.)

    n_phases int (optional, default 1)

      number of phases to an event, i.e. number of subevents to mark. E.g. for a storm where one wants the onset and the minimum, set n_phases to 2 and double click on the onset, then minimum, and then the next double-click will be onset of the next storm.

    interval(optional)

      Size of the X window to show. This should be in units that can be added to/subtracted from individual elements of x (e.g. timedelta if x is a series of datetime.) Defaults to showing the entire plot.

    auto_interval boolean (optional)

      Automatically adjust interval based on the average distance between selected events. Default is True if interval is not specified; False if interval is specified.

    auto_scale boolean (optional, default True):

      Automatically adjust the Y axis to match the data as the X axis is panned.

    ymin(optional, default None)

      If auto_scale is True, the bottom of the autoscaled Y axis will never be above ymin (i.e. ymin will always be shown on the plot). This prevents the autoscaling from blowing up very small features in mostly flat portions of the plot. The user can still manually zoom in past this point. The autoscaler will always zoom out to show the data.

    ymax(optional, default None)

      Similar to ymin, but the top of the Y axis will never be below ymax.

    line matplotlib.lines.Line2D (optional)

      Specify the matplotlib line object to use for autoscaling the Y axis. If this is not specified, the first line object on the provided subplot will be used. This should usually be correct.

  Examples

      >>> import spacepy.plot.utils
      >>> import numpy
      >>> import matplotlib.pyplot as plt
      >>> x = numpy.arange(630) / 100.0 * numpy.pi
      >>> y = numpy.sin(x)
      >>> clicker = spacepy.plot.utils.EventClicker(
      ... n_phases=2, #Two picks per event
      ... interval=numpy.pi * 2) #Display one cycle at a time
      >>> plt.plot(x, y)
      >>> clicker.analyze() #Double-click on max and min of each cycle; close
      >>> e = clicker.get_events()
      >>> peaks = e[:, 0, 0] #x value of event starts
      >>> peaks -= 2 * numpy.pi * numpy.floor(peaks / (2 * numpy.pi)) #mod 2pi
      >>> max(numpy.abs(peaks - numpy.pi / 2)) < 0.2 #Peaks should be near pi/2
      True
      >>> troughs = e[:, 1, 0] #x value of event ends
      >>> troughs -= 2 * numpy.pi * numpy.floor(troughs / (2 * numpy.pi))
      >>> max(numpy.abs(troughs - 3 * numpy.pi / 2)) < 0.2 #troughs near 3pi/2
      True
      >>> d = clicker.get_events_data() #snap-to-data of events
      >>> peakvals = d[:, 0, 1] #y value, snapped near peaks
      >>> max(peakvals) <= 1.0 #should peak at 1
      True
      >>> min(peakvals) > 0.9 #should click near 1
      True
      >>> troughvals = d[:, 1, 1] #y value, snapped near peaks
      >>> max(troughvals) <= -0.9 #should click near -1
      True
      >>> min(troughvals) <= -1.0 #should bottom-out at -1
      True

      >>> import spacepy.plot.utils
      >>> import spacepy.time
      >>> import datetime
      >>> import matplotlib.pyplot as plt
      >>> import numpy
      >>> t = spacepy.time.tickrange('2019-01-01', #get a range of days
      ...                            '2019-12-31',
      ...                            deltadays=datetime.timedelta(days=1))
      >>> y = numpy.linspace(0, 100, 1001)
      >>> seconds = t.TAI - t.TAI[0]
      >>> seconds = numpy.asarray(seconds) #normal ndarray so reshape (in meshgrid) works
      >>> tt, yy = numpy.meshgrid(seconds, y) #use TAI to get seconds
      >>> z = 1 + (numpy.exp(-(yy - 20)**2 / 625) #something like a spectrogram
      ...          * numpy.sin(1e-7 * numpy.pi**2 * tt)**2) #pi*1e7 seconds per year
      >>> plt.pcolormesh(t.UTC, y, z)
      >>> clicker = spacepy.plot.utils.EventClicker(n_phases=1)
      >>> clicker.analyze() #double-click on center of peak; close
      >>> events = clicker.get_events() #returns an array of the things clicked
      >>> len(events) == 10 #10 if you click on the centers, including the last one
      True
      >>> clicker.get_events_data() is None #should be nothing
      True

  `analyze`() | Displays the figure provided and allows the user to select events.
  `get_events`() | Get back the list of events.
  `get_events_data`() | Get a list of events, "snapped" to the data.

  analyze()

    Displays the figure provided and allows the user to select events.

    All matplot lib controls for zooming, panning, etc. the figure remain active.

    Double left click

      Mark this point as an event phase. One-phase events are the simplest: they occur at a particular time. Two-phase events have two times associated with them; an example is any event with a distinct start and stop time. In that case, the first double-click would mark the beginning, the second one, the end; the next double-click would mark the beginning of the next event. Each phase of an event is annotated with a vertical line on the plot; the color and line style is the same for all events, but different for each phase.

      After marking the final phase of an event, the X axis will scroll and zoom to place that phase near the left of the screeen and include one full interval of data (as defined in the constructor). The Y axis will be scaled to cover the data in that X range.

    Double right click or delete button

      Remove the last marked event phase. If an entire event (i.e., the first phase of an event) is removed, the X axis will be scrolled left to the previous event and the Y axis will be scaled to cover the data in the new range.

    Space bar

      Scroll the X axis by one interval. Y axis will be scaled to cover the data.

    When finished, close the figure window (if necessary) and call `get_events()` to get the list of events.

  get_events()

    Get back the list of events.

    Call after `analyze()`.

    Returns:
      out array

        3-D array of (x, y) values clicked on. Shape is (n_events, n_phases, 2), i.e. indexed by event number, then phase of the event, then (x, y).

  get_events_data()

    Get a list of events, “snapped” to the data.

    For each point selected as a phase of an event, selects the point from the original data which is closest to the clicked point. Distance from point to data is calculated based on the screen distance, not in data coordinates.

    Note that this snaps to data points, not to the closest point on the line between points.

    Call after `analyze()`.

    Returns:
      out array

        3-D array of (x, y) values in the data which are closest to each point clicked on. Shape is (n_events, n_phases, 2), i.e. indexed by event number, then phase of the event, then (x, y).