2011-02-13 611 views
54

如何刪除matplotlib軸的一行(或多行),方法如下:實際上它會收集垃圾並釋放內存?下面的代碼似乎刪除行,但從來沒有釋放內存(甚至顯式調用GC.Collect的())如何刪除Matplotlib圖中的線

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. 

那麼,有沒有辦法只是刪除從軸一行,並獲取內存背部? This potential solution也不起作用。

回答

40

我正在展示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) 

我檢查了您的大型數據集,並在系統監視器上也確認了內存的釋放。

。當然,更簡單的方法(如果不是故障排除)會從列表中彈出並調用行對象remove,而無需創建一個硬參考吧:

lines.pop(0).remove() 
+0

我運行了你的代碼,得到了: [8:37 pm] @flattop:〜/ Desktop/sandbox> python delete_lines.py 我在ubuntu 10.04中使用matplotlib版本0.99.1.1 – 2011-02-13 02:31:28

+1

@David Morton我剛降級到0.99.1,現在我重現了你的問題。我想我只能推薦升級到1.0.1。自0.99.x以來有很多錯誤修正。 – Paul 2011-02-13 03:31:03

+0

謝謝!非常感謝你的幫助。 – 2011-02-13 05:07:56

2

(使用相同的作爲上面的傢伙的例子)

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() 
9

我已經在不同論壇嘗試了很多不同的答案。我想這取決於你正在開發的機器。但我已經使用的聲明

ax.lines = [] 

和完美的作品。我不使用cla()導致它刪除我對劇情所做的所有定義。

Ex。

pylab.setp(_self.ax.get_yticklabels(), fontsize=8) 

但我試過多次刪除這些行。當我正在刪除時,還使用weakref庫檢查對該行的引用,但沒有任何工作適合我。

希望這個作品給別人= d

46

這是我輸入了我的一個同事很長的解釋。我認爲這也會有所幫助。不過,請耐心等待。我接觸到最後的真正問題。就像一個傳情,這是一個問題,有額外的參考你的Line2D對象。

警告:另一個需要注意的地方是,如果你使用IPython來測試這個,IPython會保留它自己的引用,而不是所有的都是weakrefs。因此,在IPython中測試垃圾收集不起作用。它只是混淆了事情。

好的,我們走吧。每個matplotlib對象(FigureAxes等)通過各種屬性提供對其子藝術家的訪問。下面的例子變得相當長,但應該照亮。

我們首先創建一個Figure對象,然後將一個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(),你會看到一個包含組軸和一個線圖:

A figure containing a set of axes and a single line

現在,雖然我們已經看到的linesax.lines內容是

>>> id(lines), id(ax.lines) 
(212754584, 211335288) 

作爲結果,從移除元素:同樣,必須指出,由lines變量引用的對象是不一樣的由ax.lines尊崇的對象作爲可以由以下可以看出是很重要lines對當前繪圖沒有任何影響,但從ax.lines中刪除元素會從當前繪圖中刪除該線條。所以:

>>> #THIS DOES NOTHING: 
>>> lines.pop(0) 

>>> #THIS REMOVES THE FIRST LINE: 
>>> ax.lines.pop(0) 

所以,如果你運行代碼的第二行,你會要從當前情節ax.lines[0]包含Line2D對象,它會消失。請注意,這也可以通過ax.lines.remove()意義來做到這一點,你可以在一個變量保存Line2D實例,然後將它傳遞給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>] 

A figure containing a set of axes and two lines

>>> #Remove that new line 
>>> ax.lines.remove(lines[0]) 
>>> ax.lines 
[<matplotlib.lines.Line2D object at 0xce84dx3>] 

A figure containing a set of axes and only the second line

以上所有作品都適用於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> 

因此,故事的寓意是,自己清理。如果你期望有東西被垃圾收集,但事實並非如此,那麼你可能會在某處留下一個參考。