Created
January 22, 2012 22:15
-
-
Save joferkington/1659108 to your computer and use it in GitHub Desktop.
Matplotlib data cursor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
# Hide the annotation box until clicked... | |
self.annotations[ax].set_visible(False) | |
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 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') | |
) | |
return annotation | |
def __call__(self, event): | |
"""Update and draw the annotation box for the pick event *event*.""" | |
# 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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment