簡體   English   中英

為什么matplotlib.figure.Figure的行為與matplotlib.pyplot.figure有很大不同

[英]Why does matplotlib.figure.Figure behave so different than matplotlib.pyplot.figure

一位同事程序員提醒我一個matplotlib.pyplot和Tkinter不能很好地協同工作的問題,正如這個問題所證明的那樣Tkinter / Matplotlib后端沖突導致無限主循環

我們更改了代碼以防止鏈接問題中提到的潛在問題,如下所示:

import matplotlib.pyplot as plt
self.fig = plt.figure(figsize=(8,6))
if os.path.isfile('./UI.png'):
    image = plt.imread('./UI.png')
    plt.axis('off')
    plt.tight_layout()
    im = plt.imshow(image)
# The Canvas
self.canvas = FigureCanvasTkAgg(self.fig, master = master)
self.toolbar = NavigationToolbar2TkAgg(self.canvas, root)
self.canvas.get_tk_widget().pack(fill=BOTH,expand=YES)
self.canvas.draw()

中級(UI.png未顯示)

import matplotlib.pyplot as plt
import matplotlib
self.fig = matplotlib.figure.Figure(figsize=(8, 6))
if os.path.isfile('./UI.png'):
    image = matplotlib.image.imread('./UI.png')
    plt.axis('off')
    plt.tight_layout()
    plt.imshow(image)
# The Canvas
self.canvas = FigureCanvasTkAgg(self.fig, master=master)
self.toolbar = NavigationToolbar2TkAgg(self.canvas, root)
self.canvas.get_tk_widget().pack(fill=BOTH, expand=YES)
self.canvas.draw()

改變后的代碼不再顯示“背景”圖像,而且我大多只是嘗試隨機的事情(因為我在兩個選項之間的差異中完全迷失)才能再次顯示圖形。 這些更改涉及從tight_layout切換到set_tight_layout以避免警告,如https://github.com/matplotlib/matplotlib/issues/1852所述 結果代碼如下:

潛在的修復

import matplotlib.pyplot as plt
import matplotlib
self.fig = matplotlib.figure.Figure(figsize=(8, 6))
background_image = self.fig.add_subplot(111)
if os.path.isfile('./UI.png'):
    image = matplotlib.image.imread('./UI.png')
    background_image.axis('off')
    #self.fig.tight_layout() # This throws a warning and falls back to Agg renderer, 'avoided' by using the line below this one.
    self.fig.set_tight_layout(True)
    background_image.imshow(image)
# The Canvas
self.canvas = FigureCanvasTkAgg(self.fig, master=master)
self.toolbar = NavigationToolbar2TkAgg(self.canvas, root)
self.canvas.get_tk_widget().pack(fill=BOTH, expand=YES)
self.canvas.draw()

因此,問題是,為什么我們現在需要使用子圖(使用matplotlib.figure.Figure)而不是之前(使用matplotlib.pyplot)?

PS:我很抱歉,如果這是一個愚蠢的問題,但幾乎我在這個問題上找到的所有內容似乎都使用了matplotlib.pyplot變體。 因此,我無法找到matplotlib.figure.Figure變體的任何好文檔。

TL; DR

因此,問題是,為什么我們現在需要使用子圖(使用matplotlib.figure.Figure)而不是之前(使用matplotlib.pyplot)?

subplot創建一個Axes對象。 你之前確實有過一個,但是pyplot API“隱藏”了你的封面所以你沒有意識到它。 您現在正在嘗試直接使用這些對象,因此必須自己處理它。

更詳細的原因

您看到此行為的原因是因為matplotlib.pyplot工作原理。 引用教程一點:

matplotlib.pyplot是命令樣式函數的集合,它使matplotlib像MATLAB一樣工作.... matplotlib.pyplot是有狀態的,因為它跟蹤當前的圖形和繪圖區域,繪圖函數指向當前軸

關鍵是pyplot是有狀態的。 它正在跟蹤狀態“隱藏”並在某種程度上隱藏對象模型。 它也做了一些隱含的事情。 所以 - 如果你只是調用,例如, plt.axis() ,在封面下pyplot調用plt.gca() ,然后調用gcf() ,這將返回一個新的數字 ,因為你還沒有設置一個數字pyplot呢。 大多數對plt.some_function()調用都是如此 - 如果pyplot 在它自己的狀態中沒有一個figure對象,它將創建一個。

所以,在你的中間例子中,你已經創建了自己的Figure對象 - 這就是一個名字self.fig (我不確定你的類結構是什么,所以我不知道self是什么,但我猜它是你的tk.Frame對象或類似的東西)。

妙語

pyplot self.fig 因此,在您的中間代碼中,您在pyplot狀態下調用Figure對象上的imshow() ,但在畫布上顯示不同的圖形( self.fig )。

問題不是您需要使用subplot ,而是需要更改正確的Figure對象上的背景圖像。 你在潛在的修復代碼中使用subplot的方式就是這樣 - 雖然我建議在下面的替代方案可能會使意圖更清晰。

怎么修

更改

plt.axis('off')
plt.tight_layout()
plt.imshow(image)

self.fig.set_tight_layout(True)
ax = self.fig.gca() # You could use subplot here to get an Axes object instead
ax.axis('off')
ax.imshow(image)

關於根本原因的說明: pyplot API與直接使用對象

這有點意見,但可能有所幫助。 當我需要快速獲取原型並希望使用其中一個相當標准的情況時,我傾向於使用pyplot接口。 通常,這就足夠了。

一旦我需要做更復雜的事情,我就開始直接使用對象模型 - 維護我自己的名為FigureAxes對象等。

混合這兩者是可能的,但往往令人困惑。 您已經在中間解決方案中找到了這個。 所以我建議做一個或另一個。

暫無
暫無

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

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