I keep trying to follow the examples I see for PdfPages but keep getting the value error: No such figure: None.
plot1 = Chart Generating Function(argument1, argument2,...)
from matplotlib.backends.backend_pdf import PdfPages
pp = PdfPages('sample.pdf')
pp.savefig(plot1)
plt.close()
I've tried different variations of this (i.e. pdf.savefig()) but nothing seems to work.
What solved the problem for me was removing the plt.show() command at the end of my chart generating function.
I should have added more details, but somewhere in my code I had used "fig, ax = ..." when defining the figure. The "fig" part needed to be the argument in pdf.savefig(fig) in order for it to work.
Related
I generate a lots of figures with a script which I do not display but store to harddrive. After a while I get the message
/usr/lib/pymodules/python2.7/matplotlib/pyplot.py:412: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (matplotlib.pyplot.figure) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam figure.max_num_figures).
max_open_warning, RuntimeWarning)
Thus, I tried to close or clear the figures after storing. So far, I tried all of the followings but no one works. I still get the message from above.
plt.figure().clf()
plt.figure().clear()
plt.clf()
plt.close()
plt.close('all')
plt.close(plt.figure())
And furthermore I tried to restrict the number of open figures by
plt.rcParams.update({'figure.max_num_figures':1})
Here follows a piece of sample code that behaves like described above. I added the different options I tried as comments at the places I tried them.
from pandas import DataFrame
from numpy import random
df = DataFrame(random.randint(0,10,40))
import matplotlib.pyplot as plt
plt.ioff()
#plt.rcParams.update({'figure.max_num_figures':1})
for i in range(0,30):
fig, ax = plt.subplots()
ax.hist([df])
plt.savefig("/home/userXYZ/Development/pic_test.png")
#plt.figure().clf()
#plt.figure().clear()
#plt.clf()
#plt.close() # results in an error
#plt.close('all') # also error
#plt.close(plt.figure()) # also error
To be complete, that is the error I get when using plt.close:
can't invoke "event" command: application has been destroyed
while executing "event generate $w <>"
(procedure "ttk::ThemeChanged" line 6)
invoked from within "ttk::ThemeChanged"
The correct way to close your figures would be to use plt.close(fig), as can be seen in the below edit of the code you originally posted.
from pandas import DataFrame
from numpy import random
df = DataFrame(random.randint(0,10,40))
import matplotlib.pyplot as plt
plt.ioff()
for i in range(0,30):
fig, ax = plt.subplots()
ax.hist(df)
name = 'fig'+str(i)+'.png' # Note that the name should change dynamically
plt.savefig(name)
plt.close(fig) # <-- use this line
The error that you describe at the end of your question suggests to me that your problem is not with matplotlib, but rather with another part of your code (such as ttk).
plt.show() is a blocking function, so in the above code, plt.close() will not execute until the fig windows are closed.
You can use plt.ion() at the beginning of your code to make it non-blocking. Even though this has some other implications the fig will be closed.
I was still having the same issue on Python 3.9.7, matplotlib 3.5.1, and VS Code (the issue that no combination of plt.close() closes the figure). I have three loops which the most inner loop plots more than 20 figures. The solution that is working for me is using agg as backend and del someFig after plt.close(someFig). Subsequently, the order of code would be something like:
import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt
someFig = plt.figure()
.
.
.
someFig.savefig('OUTPUT_PATH')
plt.close(someFig) # --> (Note 1)
del someFig
.
.
.
NOTE 1: If this line is removed, the output figures may not be plotted correctly! Especially when the number of elements to be rendered in the figure is high.
NOTE 2: I don't know whether this solution could backfire or not, but at least it is working and not hugging RAM or preventing plotting figures!
import tensorflow as tf
from matplotlib import pyplot as plt
sample_image = tf.io.read_file(str(PATH / 'Path to your file'))
sample_image = tf.io.decode_jpeg(sample_image)
print(sample_image.shape)
plt.figure("1 - Sample Image ")
plt.title(label="Sample Image", fontsize=12, color="red")
plt.imshow(sample_image)
plt.show(block=False)
plt.pause(3)
plt.close()
plt.show(block=False)
plt.pause(interval) do the trick
This does not really solve my problem, but it is a work-around to handle the high memory consumption I faced and I do not get any of the error messages as before:
from pandas import DataFrame
from numpy import random
df = DataFrame(random.randint(0,10,40))
import matplotlib.pyplot as plt
plt.ioff()
for i in range(0,30):
plt.close('all')
fig, ax = plt.subplots()
ax.hist([df])
plt.savefig("/home/userXYZ/Development/pic_test.png")
I am using Python and the matplotlib library.
I run through a very long code creating multiple figures along the way.
I do something like this, many many times:
plt.figure()
plt.plot(x, y)
plt.grid('on')
plt.close()
Then, at some point, I get the error:
More than 20 figures have been opened. Figures created through the pyplot interface (matplotlib.pyplot.figure) are retained until explicitly closed and may consume too much memory.
The error is clear to me, but: I do call "plt.close()".
Now that I am writing this I am realizing that maybe plt.close() has to take a specific qualifier for what figure to close? Like plt.close(1) etc. I guess I can use plt.close('all'), but what if I just want to close the most recent figure?
The code from the question should work fine. Since you close the figure in every loop step, there will only ever be one single figure open.
Minimal example, which does not produce any error:
import matplotlib.pyplot as plt
for i in range(30):
plt.figure()
plt.plot(range(i+3), range(i+3))
plt.grid('on')
plt.close()
plt.show() # doesn't show anything since no figure is open
So the reason for the error must be somewhere else in the code.
You should operate on matplotlib objects directly. It's so much less ambiguous:
fig, ax = plt.subplots()
ax.plot(x, y)
...
plt.close(fig)
Try to do a graph using python matplotlib: but keep getting the following waring message:
"UserWaring: tight_layout: falling back to Agg renderer warnings.warn("tight_layout: falling back to Agg renderer")
My code is below:
plt.legend(loc='upper left',prop = {'size':7},bbox_to_anchor=(1,1))
plt.tight_layout(pad=7)
plt.xlabel ('Build')
plt.ylabel ('Time/Sec')
plt.title ('Performance Test')
plt.grid()
plt.show()
How to fix that warning message?
Are you using MacOSX? It seems to be a known and open issue
https://github.com/matplotlib/matplotlib/issues/1852
I will suggest to reorganize the code such that you will use Figure instead of pyplot. You can get the Figure from plt.figure() method. Then, on the Figure instance call set_tight_layout(True).
Try this example code:
import matplotlib
matplotlib.use('pdf')
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
fig.set_tight_layout(True)
fig.savefig('asd.pdf') # No warning now
As a side note, have a look at matplotlib documentation
tight_layout() can take keyword arguments of pad, w_pad and h_pad. These control the extra padding around the figure border and between subplots. The pads are specified in fraction of fontsize.
http://matplotlib.org/users/tight_layout_guide.html
This suggest that your code
plt.tight_layout(pad=7)
is wrong, as the value of pad should be between 0 and 1.
I want to create a log-log plot using pyplot, but have trouble when calling plt.show():
import matplotlib.pyplot as plt
xVec = [...]
yVec = [...]
plt.figure()
plt.loglog(xVec,yVec,'.',label='This is my test plot')
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.show()
I am running this code from C++ via:
Py_Initialize();
Py_SimpleString(pythonCode.str().c_str());
Py_Exit(0);
where pythonCode is a stringstream containing the Python code above. The code runs if I don't include the plt.show() line, but of course no plot shows up.
The matplotlibrc config file shows that the backend is TkAgg, which shouldn't give problems as indicated here or here. I've tried adding plt.close() after the last line in the code above, but the error persists.
Perhaps the most surprising thing is this: I've also tried running the code in a separate Python script (with plt.show()), and the plot appears correctly! Does anyone have any idea about what's going on? Thanks in advance!
EDIT: I have also tried pylab instead of pyplot, with the same results. Do I need to compile the program with a certain python module to link the libraries properly?
I have a strange problem with matplotlib that I can not seem to figure out. When using the ipython notebook with the pylab flag, ipython notebook --pylab inline I have a line of code that looks like this that is used to generate a colorbar with matplotlib:
im = ax.imshow(df, vmin=vmin, vmax=vmax)
The code works correctly and I get a nice colorbar. When I run this code as a python file I get an error, NameError: name 'ax' is not defined. I understand that the ipython notebook --pylab inline automatically imports a bunch of stuff into the notebook, but I cannot figure out what I need to import to fix the problem. print type(ax) gives:
<class 'matplotlib.axes.AxesSubplot'>
Can anyone point out why my code works in ipython but not a plain python file? Thanks in advance.
I had the same problem.
Per this entry:
How to abbreviate xtick labels years to 2 digits in a matplotlib plot
try defining 'ax' by adding (before the line causing the error):
ax = plt.gca()
I'm not quite sure what you've done, because aX isn't defined by default as part of pylab.
Normally, ax refers to an axis object. There are a few ways you can get one:
matplotlib.pyplot.gca() # gca = get current axis
matplotlib.pyplot.subplot(2,1,1) # For creating multiple plots in one figure
fig.get_axes()[x] # Where fig is a Figure object