如何删除Matplotlib图中的行
我怎样才能删除matplotlib轴的一行(或多行),使得它实际上被垃圾回收并释放内存? 下面的代码似乎删除行,但从不释放内存(即使显式调用gc.collect())
from matplotlib import pyplot import numpy a = numpy.arange(int(1e7)) # large so you can easily see the memory footprint on the system monitor. fig = pyplot.Figure() ax = pyplot.add_subplot(1, 1, 1) lines = ax.plot(a) # this uses up an additional 230 Mb of memory. # can I get the memory back? l = lines[0] l.remove() del l del lines # not releasing memory ax.cla() # this does release the memory, but also wipes out all other lines.
那么有没有办法从轴上删除一行,然后把内存回来? 这个潜在的解决scheme也不起作用。
我展示了lines.pop(0)
l.remove()
和del l
的组合。
from matplotlib import pyplot import numpy, weakref a = numpy.arange(int(1e3)) fig = pyplot.Figure() ax = fig.add_subplot(1, 1, 1) lines = ax.plot(a) l = lines.pop(0) wl = weakref.ref(l) # create a weak reference to see if references still exist # to this object print wl # not dead l.remove() print wl # not dead del l print wl # dead (remove either of the steps above and this is still live)
我检查了你的大数据集,并且在系统监视器上也确认了内存的释放。
当然,更简单的方法(当不是故障排除时)是从列表中popup它,并调用remove
线对象而不创build一个硬引用:
lines.pop(0).remove()
这是我为我的一个同事打字的一个很长的解释。 我认为这也是有帮助的。 不过,要有耐心。 我明白你到底是真正的问题。 就像一个传情,这是一个额外的引用到你的Line2D
对象的问题。
警告:在我们介入之前,还有一点需要注意。如果你正在使用IPython来testing,IPython会保留自己的引用,而不是所有的都是弱引用。 所以,在IPython中testing垃圾回收不起作用。 这只是混淆事情。
好的,我们走吧。 每个matplotlib
对象( Figure
, Axes
等)通过各种属性提供对其子艺术家的访问。 下面的例子变得相当长,但应该照亮。
我们首先创build一个Figure
对象,然后为该graphics添加一个Axes
对象。 请注意, ax
和fig.axes[0]
是相同的对象(相同的id()
)。
>>> #Create a figure >>> fig = plt.figure() >>> fig.axes [] >>> #Add an axes object >>> ax = fig.add_subplot(1,1,1) >>> #The object in ax is the same as the object in fig.axes[0], which is >>> # a list of axes objects attached to fig >>> print ax Axes(0.125,0.1;0.775x0.8) >>> print fig.axes[0] Axes(0.125,0.1;0.775x0.8) #Same as "print ax" >>> id(ax), id(fig.axes[0]) (212603664, 212603664) #Same ids => same objects
这也延伸到轴对象中的行:
>>> #Add a line to ax >>> lines = ax.plot(np.arange(1000)) >>> #Lines and ax.lines contain the same line2D instances >>> print lines [<matplotlib.lines.Line2D object at 0xce84bd0>] >>> print ax.lines [<matplotlib.lines.Line2D object at 0xce84bd0>] >>> print lines[0] Line2D(_line0) >>> print ax.lines[0] Line2D(_line0) >>> #Same ID => same object >>> id(lines[0]), id(ax.lines[0]) (216550352, 216550352)
如果您使用上面所做的操作调用plt.show()
,则会看到一个包含一组轴和一行的graphics:
现在,虽然我们已经看到了lines
和ax.lines
的内容是一样的,但是需要注意的是,由lines
variables引用的对象与ax.lines
所引用的对象是不一样的下列:
>>> id(lines), id(ax.lines) (212754584, 211335288)
因此,从lines
中移除元素对当前的绘图没有任何作用,但是从ax.lines
移除元素将从当前绘图中移除该行。 所以:
>>> #THIS DOES NOTHING: >>> lines.pop(0) >>> #THIS REMOVES THE FIRST LINE: >>> ax.lines.pop(0)
所以,如果你要运行第二行代码,你将从当前的plot中ax.lines[0]
包含的Line2D
对象,它将会消失。 请注意,这也可以通过ax.lines.remove()
来完成,这意味着您可以将Line2D
实例保存到variables中,然后将其传递给ax.lines.remove()
以删除该行,如下所示:
>>> #Create a new line >>> lines.append(ax.plot(np.arange(1000)/2.0)) >>> ax.lines [<matplotlib.lines.Line2D object at 0xce84bd0>, <matplotlib.lines.Line2D object at 0xce84dx3>]
>>> #Remove that new line >>> ax.lines.remove(lines[0]) >>> ax.lines [<matplotlib.lines.Line2D object at 0xce84dx3>]
以上所有的工作都适用于fig.axes
就像ax.lines
现在,真正的问题在这里。 如果我们将包含在ax.lines[0]
的引用存储到weakref.ref
对象中,然后尝试删除它,我们将注意到它不会被垃圾收集:
>>> #Create weak reference to Line2D object >>> from weakref import ref >>> wr = ref(ax.lines[0]) >>> print wr <weakref at 0xb758af8; to 'Line2D' at 0xb757fd0> >>> print wr() <matplotlib.lines.Line2D at 0xb757fd0> >>> #Delete the line from the axes >>> ax.lines.remove(wr()) >>> ax.lines [] >>> #Test weakref again >>> print wr <weakref at 0xb758af8; to 'Line2D' at 0xb757fd0> >>> print wr() <matplotlib.lines.Line2D at 0xb757fd0>
参考仍然是活的! 为什么? 这是因为还有另一个引用wr
指向的Line2D
对象的引用。 还记得lines
和ax.lines
没有相同的ID,但包含相同的元素? 那么,这是问题。
>>> #Print out lines >>> print lines [<matplotlib.lines.Line2D object at 0xce84bd0>, <matplotlib.lines.Line2D object at 0xce84dx3>] To fix this problem, we simply need to delete `lines`, empty it, or let it go out of scope. >>> #Reinitialize lines to empty list >>> lines = [] >>> print lines [] >>> print wr <weakref at 0xb758af8; dead>
所以,这个故事的寓意是,自己清理。 如果你期望有东西被垃圾收集,但事实并非如此,你可能会在某处留下一个参考。
我在不同的论坛尝试了很多不同的答案。 我想这取决于你的发展机器。 但我已经使用了这个说法
ax.lines = []
并完美地工作。 我不使用cla()导致它删除了我对这个图所做的所有定义
防爆。
pylab.setp(_self.ax.get_yticklabels(), fontsize=8)
但是我已经试过多次删除这些行了。 当我正在删除,但也没有为我工作的同时使用weakref库检查对该行的引用。
希望这适用于其他人= D
(使用与上面的人相同的例子)
from matplotlib import pyplot import numpy a = numpy.arange(int(1e3)) fig = pyplot.Figure() ax = fig.add_subplot(1, 1, 1) lines = ax.plot(a) for i, line in enumerate(ax.lines): ax.lines.pop(i) line.remove()