单击外部绘图边界时如何使matplotlib注释消失?

时间:2015-08-25 19:01:24

标签: python matplotlib plot

当我点击数据点时,我使用unutbu中的DataCursor代码在matplotlib figure上显示注释。 (在我的生活中,我无法找到与此相关的链接,我以前在我的代码中引用的那个并没有指向正确的位置......)问题是,我希望他们当我在剧情外点击时离开。

def fmt(x, xlabel, y, ylabel)
    return xlabel+': {x:0.0f}\n'.format(x = x)+ylabel+': {y:0.3f}'.format(y = y)

class DataCursor(object):
    """A data cursor widget that displays the x,y of a matplotlib artist/plot when it is selected"""

    def annotate(self, ax)
        """ Draws and hides the annotations box for the given axis "ax". """
        annotation = ax.annotate(self.formatter, 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 __init__(self, artists, x, xlabel, y, ylabel, tolerance = 5, offsets = (-20,20), formatter = fmt, 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.
        "formatter" is a callback function which takes 2 numeric arguments and returns a string.
        "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._points = np.column_stack((x,y))
        self.xlabel = xlabel
        self.ylabel = ylabel

        self.formatter = formatter
        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 snap(self, x, y):
        """ Return the value of in self._points closest to (x,y). """
        values = self.points
        idx = np.nanargmin(((values - (x,y))**2).sum(axis = -1)
        return self._points[idx,:]


    def __call__(self, event):
        """ Intended to be called through "mpl_connect" above. """
        x, y = event.mouseevent.xdata, event.mouseevent.ydata
        annotation = self.annotations[event.artist.axes]

        if x is None:
            for ann in self.annotations.values():
                ann.set_visible(False)
                event.canvas.draw()

        if x is not None:
            if not self.display_all:
                for ann in self.annotations.values():
                    ann.set_visible(False)

            x, y = self.snap(x, y)

            annotation.xy = x, y
            annotation.set_text(self.formatter(x, self.xlabel, y, self.ylabel))
            annotation.set_visible(True)
            annotation.draggable(True)
            event.canvas.draw()

根据文档,我可以使用artist.set_picker(tolerance)中的函数而不是tolerance。这是如何运作的?文档没有很好地解释这一点,而且我在查找示例时遇到了困难。

现在代码的工作方式,如果我在框外单击,但在数据点的容差范围内,它将使注释消失。如果边缘的容差范围内没有数据,这会让我失去运气。如何点击绘图的灰色区域中的任何位置注释将消失?

我会让它消失的代码:

    def __call__(self, event):
        """ Intended to be called through "mpl_connect" above. """
        x, y = event.mouseevent.xdata, event.mouseevent.ydata
        annotation = self.annotations[event.artist.axes]

        if x is None:
            for ann in self.annotations.values():
                ann.set_visible(False)
                event.canvas.draw()

1 个答案:

答案 0 :(得分:0)

您的问题是您的事件处理功能仅侦听与艺术家(AFAIK)本质上相关联的'pick_event'

要实现您的目标,您应该添加另一个处理'button_press_event'

的侦听器

这是未经测试的代码,但它应该给你一个想法:

# in the __init__ code, add:
fig.canvas.mpl_connect('button_press_event', self.clearAnn)

# in the class body:
def clearAnn(self, event):
    if event.inaxes is None:  # event.inaxes returns None if you click outside of the plot area, i.e. in the grey part surrounding the axes
        for ann in self.annotations.values():
            ann.set_visible(False)
            event.canvas.draw()