How to delete lines on a Matplotlib chart

How can I remove the line (or lines) of the matplotlib axes so that it actually collects garbage and free up memory? The code below deletes a line but never frees up memory (even with explicit calls to 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 simply remove one row from the axes and return the memory? This potential solution also does not work.

+54
source share
4 answers

I show that the combination of lines.pop(0) l.remove() and del l does the trick.

 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 data set and the memory release is also confirmed on the system monitor.

Of course, an easier way (if not a problem) is to pull it from the list and call remove on the line object without creating a hard link to it:

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

This is a very long explanation that I typed for my colleague. I think that would be helpful here. Be patient. I get to the real question that you have towards the end. Like a teaser, this is a question about additional links to your Line2D objects hanging around.

WARNING: One more note before we dive. If you use IPython to verify this, IPython saves the links yourself, and not all of them are weak. Thus, checking garbage collection in IPython does not work. It just confuses the questions.

Ok, here we go. Each matplotlib object ( Figure , Axes , etc.) Provides access to its child artists through various attributes. The following example is quite long, but should be highlighted.

We start by creating a Figure object, and then add an Axes object to this figure. Note that ax and fig.axes[0] are the same object (same 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 applies to lines in the axis 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 will see a figure containing a set of axes and one line:

A figure containing a set of axes and a single line

Now that we have seen that the contents of lines and ax.lines the same, it is very important to note that the object referenced by the lines variable does not match the object respected by ax.lines , as can be seen from the following:

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

As a result, deleting an element from lines does nothing for the current graph, but deleting an element from ax.lines removes this row from the current graph. So:

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

So, if you would execute the second line of code, you would remove the Line2D object contained in ax.lines[0] from the current chart, and it will disappear. Note that this can also be done with ax.lines.remove() , which means that you can save an instance of Line2D in a variable and then pass it to ax.lines.remove() to remove this line, for example:

 >>> #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

All of the above works for fig.axes as well as ax.lines

Now, the real problem is here. If we save the link contained in ax.lines[0] to the weakref.ref object and then try to delete it, we will notice that it does not receive garbage collection:

 >>> #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 link is still alive! What for? This is due to the fact that there is another reference to the Line2D object pointed to by the link in wr . Remember how lines did not have the same identifier as ax.lines , but contained the same elements? Well, that problem.

 >>> #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 this story, cleanse yourself. If you expect something to collect garbage, but it isn’t, you will probably leave a link somewhere.

+46
source

I have tried many different answers in different forums. I think it depends on the machine you are developing. But I used the expression

 ax.lines = [] 

and it works great. I do not use cla () because it removes all the definitions I made for the graph

Ref.

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

but I tried many times to delete lines. Also, using weakref library to check the link to this line during deletion, but nothing worked for me.

Hope this works for someone else = D

+9
source

(using the same example as 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() 
+2
source

All Articles