Python 如何删除 Matplotlib 图中的线条
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4981815/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to remove lines in a Matplotlib plot
提问by David Morton
How can I remove a line (or lines) of a matplotlib axes in such a way as it actually gets garbage collected and releases the memory back? The below code appears to delete the line, but never releases the memory (even with explicit calls to gc.collect())
如何以这样的方式删除 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.
So is there a way to just delete one line from an axes and get the memory back? This potential solutionalso does not work.
那么有没有办法从轴中删除一行并取回内存? 这种潜在的解决方案也不起作用。
采纳答案by Paul
I'm showing that a combination of lines.pop(0)l.remove()and del ldoes the trick.
我示出色的组合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)
I checked your large dataset and the release of the memory is confirmed on the system monitor as well.
我检查了你的大数据集,并且在系统监视器上也确认了内存的释放。
Of course the simpler way (when not trouble-shooting) would be to pop it from the list and call removeon the line object without creating a hard reference to it:
当然,更简单的方法(当不排除故障时)是将它从列表中弹出并调用removeline 对象而不创建对它的硬引用:
lines.pop(0).remove()
回答by Jeronimo
(using the same example as the guy above)
(使用与上面那个人相同的例子)
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()
回答by Jeronimo Schreyer
I've tried lots of different answers in different forums. I guess it depends on the machine your developing. But I haved used the statement
我在不同的论坛上尝试了很多不同的答案。我想这取决于您开发的机器。但我已经使用了声明
ax.lines = []
and works perfectly. I don't use cla() cause it deletes all the definitions I've made to the plot
并且完美运行。我不使用 cla() 因为它删除了我对情节所做的所有定义
Ex.
前任。
pylab.setp(_self.ax.get_yticklabels(), fontsize=8)
but I've tried deleting the lines many times. Also using the weakref library to check the reference to that line while I was deleting but nothing worked for me.
但我试过多次删除这些行。在我删除时还使用weakref 库来检查对该行的引用,但对我没有任何作用。
Hope this works for someone else =D
希望这对其他人有用 =D
回答by Vorticity
This is a very long explanation that I typed up for a coworker of mine. I think it would be helpful here as well. Be patient, though. I get to the real issue that you are having toward the end. Just as a teaser, it's an issue of having extra references to your Line2Dobjects hanging around.
这是我为我的同事输入的很长的解释。我认为这也会有帮助。不过要有耐心。我谈到了你在最后遇到的真正问题。就像预告片一样,这是一个对Line2D周围对象有额外引用的问题。
WARNING:One other note before we dive in. If you are using IPython to test this out, IPython keeps references of its own and not all of them are weakrefs. So, testing garbage collection in IPython does not work. It just confuses matters.
警告:在我们深入研究之前的另一个注意事项。如果您使用 IPython 来测试这一点,IPython 会保留自己的引用,而不是所有引用都是弱引用。因此,在 IPython 中测试垃圾收集不起作用。它只是混淆了事情。
Okay, here we go. Each matplotlibobject (Figure, Axes, etc) provides access to its child artists via various attributes. The following example is getting quite long, but should be illuminating.
好的,我们开始。每个matplotlib对象(Figure、Axes等)都通过各种属性提供对其子艺术家的访问。下面的例子很长,但应该很有启发性。
We start out by creating a Figureobject, then add an Axesobject to that figure. Note that axand fig.axes[0]are the same object (same id()).
我们首先创建一个Figure对象,然后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
This also extends to lines in an axes object:
这也扩展到轴对象中的线:
>>> #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)
If you were to call plt.show()using what was done above, you would see a figure containing a set of axes and a single line:
如果你plt.show()使用上面所做的调用,你会看到一个包含一组轴和一条线的图形:


Now, while we have seen that the contents of linesand ax.linesis the same, it is very important to note that the object referenced by the linesvariable is not the same as the object reverenced by ax.linesas can be seen by the following:
现在,虽然我们已经看到的内容lines和ax.lines是一样的,但要注意的是在引用的对象是非常重要的lines变量是不一样的尊崇对象ax.lines为可通过以下所见:
>>> id(lines), id(ax.lines)
(212754584, 211335288)
As a consequence, removing an element from linesdoes nothing to the current plot, but removing an element from ax.linesremoves that line from the current plot. So:
因此,从 fromlines中删除元素对当前绘图没有任何影响,但从 from 中ax.lines删除元素会从当前绘图中删除该行。所以:
>>> #THIS DOES NOTHING:
>>> lines.pop(0)
>>> #THIS REMOVES THE FIRST LINE:
>>> ax.lines.pop(0)
So, if you were to run the second line of code, you would remove the Line2Dobject contained in ax.lines[0]from the current plot and it would be gone. Note that this can also be done via ax.lines.remove()meaning that you can save a Line2Dinstance in a variable, then pass it to ax.lines.remove()to delete that line, like so:
因此,如果您要运行第二行代码,您将从当前图中删除Line2D包含的对象ax.lines[0],它就会消失。请注意,这也可以通过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>]


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


All of the above works for fig.axesjust as well as it works for ax.lines
以上所有内容都fig.axes适用ax.lines
Now, the real problem here. If we store the reference contained in ax.lines[0]into a weakref.refobject, then attempt to delete it, we will notice that it doesn't get garbage collected:
现在,真正的问题在这里。如果我们将其中包含的引用存储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>
The reference is still live! Why? This is because there is still another reference to the Line2Dobject that the reference in wrpoints to. Remember how linesdidn't have the same ID as ax.linesbut contained the same elements? Well, that's the problem.
参考文献还在!为什么?这是因为仍然存在另一个对引用指向的Line2D对象的引用wr。还记得为什么lines没有相同的 IDax.lines但包含相同的元素吗?嗯,这就是问题所在。
>>> #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>
So, the moral of the story is, clean up after yourself. If you expect something to be garbage collected but it isn't, you are likely leaving a reference hanging out somewhere.
所以,这个故事的寓意是,清理自己。如果您希望某些东西被垃圾收集,但事实并非如此,您可能会在某处留下一个引用。

