【问题标题】:Is there a matplotlib equivalent of MATLAB's datacursormode?是否有与 MATLAB 的 datacursormode 等效的 matplotlib?
【发布时间】:2011-06-06 20:24:07
【问题描述】:

在 MATLAB 中,当用户将鼠标悬停在图形上时,可以使用 datacursormode 向图形添加注释。 matplotlib中有这样的东西吗?或者我需要使用matplotlib.text.Annotation 编写自己的事件?

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    后期编辑/无耻插件:现在可以使用mpldatacursor(具有更多功能)。调用 mpldatacursor.datacursor() 将为所有 matplotlib 艺术家启用它(包括对图像中 z 值的基本支持等)。


    据我所知,目前还没有实现,但编写类似的东西并不难:

    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
    

    似乎至少有几个人在使用它,所以我在下面添加了一个更新版本。

    新版本的用法更简单,文档也更多(即,至少一点点)。

    基本上你会像这样使用它:

    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()
    

    主要区别是 a) 不需要手动调用line.set_picker(...),b) 不需要手动调用fig.canvas.mpl_connect,c) 这个版本可以处理多轴多图形。

    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()
    

    【讨论】:

    • 乔,我注释掉了xdata, ydata = event.artist.get_data(),因为它似乎没有被使用,并提出了question。希望没关系。
    • 当然,谢谢!我不应该把它留在里面。另外,我可能应该更新这个......传递一个特定的艺术家而不是一个轴会更有意义。
    • 我很想看看你的想法。难道你不需要轴来调用ax.annotate吗?
    • 您可以使用artist.axes 访问它。给我一点,我会补充的。如果人们觉得它有用,我可能会尝试提交新的、经过清理的版本以包含在 matplotlib.widgets 中。我不知道开发人员是否认为这是个好主意,但我想我会问的。
    • 这是否适用于imshow 显示的二维图像?即它是否显示所显示图像的 z 值?目前,查看器只显示 x 和 y 坐标,这有点不幸...
    猜你喜欢
    • 2021-04-22
    • 1970-01-01
    • 2016-10-20
    • 2018-10-14
    • 1970-01-01
    • 1970-01-01
    • 2013-06-28
    • 2014-08-05
    • 1970-01-01
    相关资源
    最近更新 更多