【问题标题】:Why does matplotlib.figure.Figure behave so different than matplotlib.pyplot.figure为什么 matplotlib.figure.Figure 的行为与 matplotlib.pyplot.figure 如此不同
【发布时间】:2015-10-15 03:57:47
【问题描述】:

一位程序员同事提醒我注意一个问题,即 matplotlib.pyplot 和 Tkinter 不能很好地协同工作,正如这个问题所证明的那样 Tkinter/Matplotlib backend conflict causes infinite mainloop

我们更改了代码以防止链接问题中提到的潜在问题,如下所示:

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 变体找到任何好的文档。

【问题讨论】:

    标签: python matplotlib tkinter


    【解决方案1】:

    TL;DR

    因此问题是,为什么我们现在需要使用子图(使用 matplotlib.figure.Figure)而之前不需要(使用 matplotlib.pyplot)?

    subplot 创建一个 Axes 对象。您之前确实有一个,但是pyplot API 将它“隐藏”在了被子下,所以您没有意识到它。您现在正在尝试直接使用对象,因此必须自己处理。

    更详细的原因

    您看到这种行为的原因是matplotlib.pyplot 的工作原理。引用the tutorial一点:

    matplotlib.pyplot 是使 matplotlib 像 MATLAB 一样工作的命令样式函数的集合......matplotlib.pyplot 是有状态的,因为它跟踪当前图形和绘图区域,并且绘图函数被定向到当前坐标区

    关键是pyplot 是有状态的。它“在幕后”跟踪状态并在某种程度上对您隐藏对象模型。它还做了一些隐含的事情。所以 - 如果你只是简单地打电话,例如,plt.axis(),在 pyplot calls plt.gca()calls gcf() 后面会 return a new figure,因为你还没有通过 pyplot 设置一个数字。大多数对plt.some_function() 的调用都是如此 - 如果pyplot 还没有一个图形对象处于它自己的状态,它会创建一个。

    因此,在您的中间示例中,您创建了自己的 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对象等。

    将两者混合是可能的,但常常令人困惑。您已经在中间解决方案中找到了这一点。所以我建议做一个或另一个。

    【讨论】:

    • 很好的答案。您认为哪个更好,使用 subplot 变体(我偶然发现)或 fig.gca()(您在修复中列出)?
    • 我认为gca() 在这种情况下更容易阅读 - 我一直认为子情节让我认为可能不止一个。然而,这真的取决于个人喜好——两者都可以。如果在gca() 之后执行print(type(ax)),您将看到它的具体类型实际上是AxesSubplotAxes 的子类)——与add_subplot() 返回的完全相同
    猜你喜欢
    • 2021-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多