一位程序员同事提醒我注意一个问题,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变体找到任何好的文档。
发布于 2015-07-27 11:00:57
TL;DR
因此,问题是,为什么我们现在需要使用一个子图(使用matplotlib.figure.Figure),而之前我们没有使用(使用matplotlib.pyplot)?
subplot创建一个Axes对象。你以前也有过,但是pyplot API“隐藏”了它,所以你没有意识到这一点。您现在正在尝试直接使用对象,所以必须自己处理。
更详细的理由
您之所以看到这种行为是因为matplotlib.pyplot是如何工作的。引用一下本教程的话:
matplotlib.pyplot是命令样式函数的集合,它使matplotlib像MATLAB一样工作.matplotlib.pyplot是有状态的,它跟踪当前图形和绘图区域,并将绘图功能定向到当前轴。
关键的一点是pyplot是有状态的。它跟踪状态“隐藏”,并在一定程度上向您隐藏对象模型。它也做了一些隐含的事情。因此-如果您只是简单地调用,例如,plt.axis(),在封面下调用plt.gca(),然后调用gcf(),这将是返回一个新数字,因为您还没有通过pyplot设置一个数字。对于大多数对plt.some_function()的调用来说,这都是正确的--如果pyplot在它自己的状态中没有一个图形对象,它将创建一个。
因此,在您的中间示例中,您已经创建了自己的Figure对象--将其命名为self.fig (我不确定您的类结构是什么,所以我不知道self是什么,但我猜它是您的tk.Frame对象或类似的东西)。
这句话
pyplot 对一无所知因此,在中间代码中,在处于imshow()状态的Figure对象上调用pyplot,但在画布上显示一个不同的图形(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接口。通常,这就足够了。
当我需要做更复杂的事情时,我就开始直接使用对象模型--维护我自己的名为Figure和Axes对象等等。
混合两者是可能的,但往往令人困惑。你在中间解决方案中找到了这个。所以我建议你做一个或另一个。
https://stackoverflow.com/questions/31611188
复制相似问题