如何删除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对象( FigureAxes等)通过各种属性提供对其子艺术家的访问。 下面的例子变得相当长,但应该照亮。

我们首先创build一个Figure对象,然后为该graphics添加一个Axes对象。 请注意, axfig.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:

包含一组轴和一条线的图

现在,虽然我们已经看到了linesax.lines的内容是一样的,但是需要注意的是,由linesvariables引用的对象与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对象的引用。 还记得linesax.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()