如何使用matplotlib中的“blit”编写一个可以使用“拖动”移动查看图像不同部分的程序

2024-09-30 22:10:47 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图使用matplotlib编写一个程序,在缩放plt.figure对象上显示的图像后,当我进行鼠标“单击并拖动”移动时,显示部分将向我的拖动方向移动,以便通过设置x/y限制可以看到缩放图像的不同部分

我知道最简单的方法是在重置x/y限制后使用canvas.draw()函数,如下所示

ax.set_xlim([x1,x2])
ax.set_ylim([y1,y2])
ax.figure.canvas.draw()

但在我的正式程序中,图形上不仅会有图像,还会有很多其他对象,如文本或线条,如果我使用canvas.draw(),它会重新绘制所有对象,包括那些完全不变的对象,并会严重损害程序的性能。为了使用最少的资源来执行拖动功能,我决定使用“blit”函数,下面是我的玩具示例

import matplotlib.pyplot as plt

class toy(object):
 def dragstart(self, event):
    # 'button_press_event'

    if not event.inaxes:
        return
    if event.button == 1:
        self.dragstate = 'move'
        x, y = event.xdata, event.ydata
        self.mouseloc = [x, y]


 def dragstop(self, event):
    # 'button_release_event'
    if event.button == 1:
        self.dragstate = 'stop'


 def drag(self, event):
    #Prevent multiple event happening
    if self.dragprocessing:
        return
    self.dragprocessing = True


    if not event.inaxes or self.dragstate != 'move':

        self.dragprocessing = False
        return


    #Calculate the displacement
    xloc, yloc = event.xdata, event.ydata
    xdelta = -(xloc - self.mouseloc[0])
    ydelta = -(yloc - self.mouseloc[1])
    self.mouseloc = [xloc, yloc]

    newxleft = self.last[0] + xdelta
    newxright = self.last[1] + xdelta
    newyup = self.last[2] + ydelta
    newydown = self.last[3] + ydelta

    #Border check
    if newxright > self.limit[0] - 0.5:
        over = newxright - (self.limit[0] - 0.5)
        newxright = self.limit[0] - 0.5
        newxleft -= over

    if newxleft < -0.5:
        over = -0.5 - newxleft
        newxleft = -0.5
        newxright += over


    if newydown > self.limit[1] - 0.5:
        over = newydown - (self.limit[1] - 0.5)
        newydown = self.limit[1] - 0.5
        newyup -= over

    if newyup < -0.5:
        over = -0.5 - newyup
        newyup = -0.5
        newydown += over
    newposition = [newxleft, newxright, newyup, newydown]


    #Set new limit
    self.ax.set_xlim([newxleft, newxright])
    self. ax.set_ylim([newydown, newyup])


    #Only draw the changing part
    #The formal project contents lots of other objects such as text or line, redraw everything will be slow
    self.ax.draw_artist(self.ax.images[0])
    self.ax.draw_artist(self.ax.yaxis)
    self.ax.draw_artist(self.ax.xaxis)
    self.ax.figure.canvas.blit()


    self.last = newposition
    self.mouseloc = [xloc + xdelta, yloc + ydelta]
    self.dragprocessing = False

  def __call__(self, images):


    fig, ax = plt.subplots()
    ax.imshow(images)
    h = images.shape[0]
    w = images.shape[1]
    self.limit = [w, h]
    ax.set_ylim([400, 200])#just an example
    ax.set_xlim([200, 400])#just an example

    self.dragprocessing = False
    self.last = [200, 400, 200, 400]#present x/y limit
    self.dragstate = 'stop'

    self.ax=ax
    self.fig=fig
    fig.canvas.mpl_connect('button_press_event', self.dragstart)
    fig.canvas.mpl_connect('button_release_event', self.dragstop)
    fig.canvas.mpl_connect('motion_notify_event', self.drag)

    plt.show()


 imagenow = plt.imread("path/to/my/image")
 test=toy()
 test(imagenow)

请注意,我使用“self.ax.figure.canvas.blit()”而不是“self.ax.figure.canvas.blit(self.ax.bbox)”,因为后者不会更新轴上的任何内容。
问题是,每次更新x/y限制时,x/y轴的杆都会覆盖,如下所示 Example of dragging "up"

在我的玩具“blit”示例中是否存在导致问题的任何误用?如何修复它,或者有没有更好的方法来完成这项工作


Tags: selfeventifbuttonaxovercanvaslast