防止Matplotlib有状态 [英] Prevent matplotlib statefulness

查看:14
本文介绍了防止Matplotlib有状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我在 matplotlib 中创建一个 Axes 对象并对其进行突变(即通过绘制一些数据),然后在不传递我的的情况下调用函数指向该函数,那么该函数仍可以使我的 Axes 变异.例如:

If I create an Axes object in matplotlib and mutate it (i.e. by plotting some data) and then I call a function without passing my Axes object to that function then that function can still mutate my Axes. For example:

import matplotlib.pyplot as plt
import numpy as np

def innocent_looking_function():
    #let's draw a red line on some unsuspecting Axes!
    plt.plot(100*np.random.rand(20), color='r')

fig, ax = plt.subplots()
ax.plot(100*np.random.rand(20), color='b') #draw blue line on ax
#ax now has a blue line, as expected

innocent_looking_function()
#ax now unexpectedly has a blue line and a red line!

我的问题是:我可以总体上防止这种全局变量行为吗?我知道我可以在调用任何 innocent_looking_function() 之前调用 plt.close() 但是有什么方法可以使它成为默认值?

My question is: can I prevent this global-variable behaviour in general? I know I can call plt.close() before calling any innocent_looking_function() but is there some way to make this the default?

推荐答案

好的!您需要做的是在制作图形时完全绕过 pyplot 状态机.

Sure! What you need to do is bypass the pyplot state machine entirely when you make your figure.

它更冗长,因为你不能只调用 fig = plt.figure().

It's more verbose, as you can't just call fig = plt.figure().

首先,让我解释一下 plt.gca()plt.gcf() 是如何工作的.使用 pyplot 接口时,matplotlib 存储所有已创建但未显示的图形管理器.图形管理器基本上是图形的 gui 包装器.

First off, let me explain how plt.gca() or plt.gcf() works. When using the pyplot interface, matplotlib stores all created-but-not-displayed figure managers. Figure managers are basically the gui wrapper for a figure.

plt._pylab_helpers.Gcf 是单例对象,用于存储图形管理器并跟踪当前处于活动状态的对象.plt.gcf()_pylab_helpers.Gcf 返回活动图形.每个 Figure 对象都跟踪它自己的轴,所以 plt.gca() 就是 plt.gcf().gca().

plt._pylab_helpers.Gcf is the singleton object that stores the figure managers and keeps track of which one is currently active. plt.gcf() returns the active figure from _pylab_helpers.Gcf. Each Figure object keeps track of it's own axes, so plt.gca() is just plt.gcf().gca().

通常,当您调用 plt.figure()时,它会:

Normally, when you call plt.figure(), it:

  1. 创建返回的图形对象
  2. 使用适当的后端为该图形创建一个 FigureManager
  3. 图形管理器创建一个 FigureCanvas、gui 窗口(根据需要)和 NavigationToolbar2(缩放按钮等)
  4. 然后将图形管理器实例添加到 _pylab_helpers.Gcf 的图形列表中.
  1. Creates the figure object that's returned
  2. Creates a FigureManager for that figure using the appropriate backend
  3. The figure manager creates a FigureCanvas, gui window (as needed), and NavigationToolbar2 (zoom buttons, etc)
  4. The figure manager instance is then added to _pylab_helpers.Gcf's list of figures.

这是我们想要绕过的最后一步.

It's this last step that we want to bypass.

这是一个使用非交互式后端的快速示例.请注意,因为我们不担心与绘图交互,所以我们可以跳过整个图形管理器,只创建一个 FigureFigureCanvas 实例.(从技术上讲,我们可以跳过 FigureCanvas,但是一旦我们想将绘图保存到图像等中,就会需要它.)

Here's a quick example using a non-interactive backend. Note that because we're not worried about interacting with the plot, we can skip the entire figure manager and just create a Figure and FigureCanvas instance. (Technically we could skip the FigureCanvas, but it will be needed as soon as we want to save the plot to an image, etc.)

import matplotlib.backends.backend_agg as backend
from matplotlib.figure import Figure

# The pylab figure manager will be bypassed in this instance. `plt.gca()`
# can't access the axes created here.
fig = Figure()
canvas = backend.FigureCanvas(fig)
ax = fig.add_subplot(111)

只是为了证明 gca 无法看到此轴:

Just to prove that gca can't see this axes:

import matplotlib.pyplot as plt
import matplotlib.backends.backend_agg as backend
from matplotlib.figure import Figure

# Independent figure/axes
fig = Figure()
canvas = backend.FigureCanvas(fig)
ax = fig.add_subplot(111)
ax.plot(range(10))

# gca() is completely unaware of this axes and will create a new one instead:
ax2 = plt.gca()
print 'Same axes?:', id(ax) == id(ax2)

# And `plt.show()` would show the blank axes of `ax2`

<小时>

有了交互式支持,触感更加复杂.不能调用plt.show(),需要自己启动gui的mainloop.您可以从头开始"完成所有操作(请参阅任何嵌入 matplotlib"示例),但 FigureManager 将支持的特定部分抽象化:


With an interactive backed, it's a touch more complicated. You can't call plt.show(), so you need to start the gui's mainloop yourself. You can do it all "from scratch" (see any of the "embedding matplotlib" examples), but the FigureManager abstracts the backed-specific parts away:

以使用 TkAgg 后端为例:

As an example using the TkAgg backend:

import matplotlib.backends.backend_tkagg as backend
from matplotlib.figure import Figure

fig = Figure()
ax = fig.add_subplot(111)

manager = backend.new_figure_manager_given_figure(1, fig)
manager.show()
backend.show.mainloop()

要使用其他后端之一,只需更改后端导入即可.例如,对于Qt4:

To use one of the other backends, just change the backend import. For example, for Qt4:

import matplotlib.backends.backend_qt4agg as backend
from matplotlib.figure import Figure

fig = Figure()
ax = fig.add_subplot(111)

manager = backend.new_figure_manager_given_figure(1, fig)
manager.show()
backend.show.mainloop()

这实际上甚至适用于 IPython 笔记本中使用的 nbagg 后端.只需将后端导入更改为 import matplotlib.backends.backend_nbagg as backend

This actually even works with the nbagg backend used in IPython notebooks. Just change the backend import to import matplotlib.backends.backend_nbagg as backend

这篇关于防止Matplotlib有状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆