Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a matplotlib equivalent of MATLAB's datacursormode?

In MATLAB, one can use datacursormode to add annotation to a graph when user mouses over. Is there such thing in matplotlib? Or I need to write my own event using matplotlib.text.Annotation?

like image 561
Ping C Avatar asked Jan 10 '11 22:01

Ping C


People also ask

Is PyLab and matplotlib same?

PyLab is a procedural interface to the Matplotlib object-oriented plotting library. Matplotlib is the whole package; matplotlib. pyplot is a module in Matplotlib; and PyLab is a module that gets installed alongside Matplotlib. PyLab is a convenience module that bulk imports matplotlib.

Can matplotlib plot real time graphs in Python?

To create a real-time plot, we need to use the animation module in matplotlib. We set up the figure and axes in the usual way, but we draw directly to the axes, ax , when we want to create a new frame in the animation.

Does Replit have matplotlib?

Although the console only supports text output, Replit allows you to create plots and charts using matplotlib (and other libraries). Here, we will show you the basics of generating plots using Python3 and matplotlib.


1 Answers

Late Edit / Shameless Plug: This is now available (with much more functionality) as mpldatacursor. Calling mpldatacursor.datacursor() will enable it for all matplotlib artists (including basic support for z-values in images, etc).


As far as I know, there isn't one already implemented, but it's not too hard to write something similar:

import matplotlib.pyplot as plt  class DataCursor(object):     text_template = 'x: %0.2f\ny: %0.2f'     x, y = 0.0, 0.0     xoffset, yoffset = -20, 20     text_template = 'x: %0.2f\ny: %0.2f'      def __init__(self, ax):         self.ax = ax         self.annotation = ax.annotate(self.text_template,                  xy=(self.x, self.y), xytext=(self.xoffset, self.yoffset),                  textcoords='offset points', ha='right', va='bottom',                 bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),                 arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0')                 )         self.annotation.set_visible(False)      def __call__(self, event):         self.event = event         # xdata, ydata = event.artist.get_data()         # self.x, self.y = xdata[event.ind], ydata[event.ind]         self.x, self.y = event.mouseevent.xdata, event.mouseevent.ydata         if self.x is not None:             self.annotation.xy = self.x, self.y             self.annotation.set_text(self.text_template % (self.x, self.y))             self.annotation.set_visible(True)             event.canvas.draw()  fig = plt.figure() line, = plt.plot(range(10), 'ro-') fig.canvas.mpl_connect('pick_event', DataCursor(plt.gca())) line.set_picker(5) # Tolerance in points 

Datacursor-ish thing in matplotlib

As it seems like at least a few people are using this, I've added an updated version below.

The new version has a simpler usage and a lot more documentation (i.e. a tiny bit, at least).

Basically you'd use it similar to this:

plt.figure() plt.subplot(2,1,1) line1, = plt.plot(range(10), 'ro-') plt.subplot(2,1,2) line2, = plt.plot(range(10), 'bo-')  DataCursor([line1, line2])  plt.show() 

The main differences are that a) there's no need to manually call line.set_picker(...), b) there's no need to manually call fig.canvas.mpl_connect, and c) this version handles multiple axes and multiple figures.

from matplotlib import cbook  class DataCursor(object):     """A simple data cursor widget that displays the x,y location of a     matplotlib artist when it is selected."""     def __init__(self, artists, tolerance=5, offsets=(-20, 20),                   template='x: %0.2f\ny: %0.2f', display_all=False):         """Create the data cursor and connect it to the relevant figure.         "artists" is the matplotlib artist or sequence of artists that will be              selected.          "tolerance" is the radius (in points) that the mouse click must be             within to select the artist.         "offsets" is a tuple of (x,y) offsets in points from the selected             point to the displayed annotation box         "template" is the format string to be used. Note: For compatibility             with older versions of python, this uses the old-style (%)              formatting specification.         "display_all" controls whether more than one annotation box will             be shown if there are multiple axes.  Only one will be shown             per-axis, regardless.          """         self.template = template         self.offsets = offsets         self.display_all = display_all         if not cbook.iterable(artists):             artists = [artists]         self.artists = artists         self.axes = tuple(set(art.axes for art in self.artists))         self.figures = tuple(set(ax.figure for ax in self.axes))          self.annotations = {}         for ax in self.axes:             self.annotations[ax] = self.annotate(ax)          for artist in self.artists:             artist.set_picker(tolerance)         for fig in self.figures:             fig.canvas.mpl_connect('pick_event', self)      def annotate(self, ax):         """Draws and hides the annotation box for the given axis "ax"."""         annotation = ax.annotate(self.template, xy=(0, 0), ha='right',                 xytext=self.offsets, textcoords='offset points', va='bottom',                 bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),                 arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0')                 )         annotation.set_visible(False)         return annotation      def __call__(self, event):         """Intended to be called through "mpl_connect"."""         # Rather than trying to interpolate, just display the clicked coords         # This will only be called if it's within "tolerance", anyway.         x, y = event.mouseevent.xdata, event.mouseevent.ydata         annotation = self.annotations[event.artist.axes]         if x is not None:             if not self.display_all:                 # Hide any other annotation boxes...                 for ann in self.annotations.values():                     ann.set_visible(False)             # Update the annotation in the current axis..             annotation.xy = x, y             annotation.set_text(self.template % (x, y))             annotation.set_visible(True)             event.canvas.draw()  if __name__ == '__main__':     import matplotlib.pyplot as plt     plt.figure()     plt.subplot(2,1,1)     line1, = plt.plot(range(10), 'ro-')     plt.subplot(2,1,2)     line2, = plt.plot(range(10), 'bo-')      DataCursor([line1, line2])      plt.show() 
like image 128
Joe Kington Avatar answered Sep 22 '22 13:09

Joe Kington