繁体   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