【问题标题】:Scrollable Matplotlib figure not working from function可滚动的 Matplotlib 图形不能从函数中工作
【发布时间】:2020-05-25 15:23:53
【问题描述】:

我目前正在处理医学图像并编写代码以准备训练集。 为此,我需要滚动浏览体积数据。

我的主要 IDE 是 Spyder,但 IndexTracker 对象的标准实现在函数内对我不起作用。

这个标准实现对我有用: https://matplotlib.org/gallery/animation/image_slices_viewer.html

但是一旦我将绘图的创建放入一个函数中,创建的绘图就不再是可滚动的:

import numpy as np
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt

class IndexTracker(object):
    def __init__(self, ax, X):
        self.ax = ax
        ax.set_title('use scroll wheel to navigate images')

        self.X = X
        rows, cols, self.slices = X.shape
        self.ind = self.slices//2

        self.im = ax.imshow(self.X[:, :, self.ind])
        self.update()

    def onscroll(self, event):
        print("%s %s" % (event.button, event.step))
        if event.button == 'up':
            self.ind = (self.ind + 1) % self.slices
        else:
            self.ind = (self.ind - 1) % self.slices
        self.update()

    def update(self):
        self.im.set_data(self.X[:, :, self.ind])
        self.ax.set_ylabel('slice %s' % self.ind)
        self.im.axes.figure.canvas.draw()

def plot(X):
    fig, ax = plt.subplots(1, 1)
    tracker = IndexTracker(ax, X)
    fig.canvas.mpl_connect('scroll_event', tracker.onscroll)
    plt.show()

plot(np.random.rand(200, 200, 500))

可能是什么问题?如何从函数中创建可滚动绘图?

【问题讨论】:

    标签: python function matplotlib jupyter spyder


    【解决方案1】:

    我自己解决了这个问题: 问题是,matplotlib 不能正确识别绘图实例,因此必须在函数中设置它。 一个基本的而非通用或实用的应用程序如下:

    figList,axList=[],[]
    def plotSlices(image, view):
        fig, ax = plt.subplots(1, 1)
        figList.append(fig)
        axList.append(ax)
        axList[-1].set_title(view)
        tracker = IndexTracker(axList[-1], image)
        figList[-1].canvas.mpl_connect('scroll_event', tracker.onscroll)
        plt.show(figList[-1],block=False)
    

    其中一个numpy数组与图像的透视图一起被读取。这仅用于标题,因此您可以删除它/对标题进行硬编码。 fig 和 ax 对象被附加到各自的列表中,从中只有最后添加的元素被提供给 matplotlib 进行绘图。

    这样,滚动浏览函数中定义的图就可以了。 一个问题是我显然重载了 .show() 方法,它应该只接受一个 block=False/True 参数,但实际上正确地识别出正确的情节,如下所示: plt.show(图,块=假) 它会抛出一个错误来解决这个问题,但最终会起作用。完美!

    【讨论】:

      【解决方案2】:

      简答

      以更简洁的方式,您应该在主上下文中保持对跟踪器实例的访问。否则,这个跟踪器在函数结束时被销毁。

      按照官方示例https://matplotlib.org/stable/gallery/event_handling/image_slices_viewer.html?highlight=slice%20viewer,我已经适应将情节包装在一个函数中。

      def ShowSlice():
          fig, ax = plt.subplots(1, 1)
          X = np.random.rand(20, 20, 40)
          tracker = IndexTracker(ax, X)
          fig.canvas.mpl_connect('scroll_event', tracker.on_scroll)
          plt.show()
          return tracker
          
      # ShowSlice()  # Does not works    
      tr = ShowSlice()  # Works
      

      我的调查

      感谢您的提问,这正是我目前的问题。您自己的回答对我找到这种行为的真正原因有很大帮助。

      您提出的解决方案强调了了解至少与图形或轴相关的某些变量的问题。

      我已经遇到过类似的问题,在 matplotlib 中使用动画。这个问题的解决方案是在主上下文中保留一个动画实例,如下例所示: https://matplotlib.org/2.1.2/gallery/animation/basic_example.html,即使动画对象(line_aniim_ani)没有被使用,也需要将then保存在内存中。

      这里的问题似乎完全相同,但与跟踪器实例有关。

      深入阅读mpl_connect 的文档确认: https://matplotlib.org/stable/users/event_handling.html#event-connections

      FigureCanvasBase.mpl_connect 方法返回一个连接 id(一个 integer),可用于断开回调通过

      注意

      画布仅保留对用作实例方法的弱引用 回调。因此,您需要保留对实例的引用 拥有这样的方法。否则实例将被垃圾回收 并且回调将消失。这不会影响使用的免费功能 作为回调。

      感谢您的阅读。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-24
        • 2018-05-28
        • 2017-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多