簡體   English   中英

可滾動的 Matplotlib 圖形不起作用

[英]Scrollable Matplotlib figure not working from function

我目前正在研究醫學圖像並編寫用於准備訓練集的代碼。 為此,我需要滾動瀏覽體數據切片。

我的主要 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))

可能是什么問題呢? 如何從函數中創建我的可滾動圖?

我自己解決了這個問題:問題是,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(fig,block=False) 它拋出一個錯誤來解決這個問題,但最終有效。 完美的!

簡答

以更簡潔的方式,您應該在主上下文中保持對跟蹤器實例的訪問。 否則,此跟蹤器將在函數結束時銷毀。

按照官方示例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 ) 未使用,必須將其保留在內存中。

這里的問題似乎完全相同,但與跟蹤器實例有關。

mpl_connect文檔的更深入閱讀確認: https : mpl_connect

FigureCanvasBase.mpl_connect 方法返回一個連接 id(一個整數),可用於通過以下方式斷開回調

筆記

畫布僅保留對用作回調的實例方法的弱引用。 因此,您需要保留對擁有此類方法的實例的引用。 否則,實例將被垃圾收集,回調將消失。 這不會影響用作回調的自由函數。

感謝您的閱讀。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM