I'm new to Python (I used MATLAB before), and I find that I cannot call show() after close some figures by close(). My goal is closing figures freely and then show the rest plots at last. Could anyone help me? Thank you.
My system: Python 3.6 on Windows 10. The matplotlib version is 2.2.2. I run my code through Eclipse.
Here is the code:
# Original code
import matplotlib.pyplot as plt
figA = plt.figure('aa')
figB = plt.figure('bb')
plt.close('aa')
plt.plot([2,3],[1,1],color='green')
plt.show()
When I run it, I get the following error in the Eclipse console.
Traceback (most recent call last):
File "D:\a project for testing dionysus\test_pythonPractice.py", line 26, in
plt.show()
File "C:\Users\hanlin\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\pyplot.py", line 253, in show
return _show(*args, **kw)
File "C:\Users\hanlin\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backend_bases.py", line 208, in show
cls.mainloop()
File "C:\Users\hanlin\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backends_backend_tk.py", line 1073, in mainloop
Tk.mainloop()
File "C:\Users\hanlin\AppData\Local\Programs\Python\Python36\lib\tkinter__init__.py", line 557, in mainloop
_default_root.tk.mainloop(n)
AttributeError: 'NoneType' object has no attribute 'tk'
However, if I change the code to either of the following two versions, there is no error.
# Revised ver.1
import matplotlib.pyplot as plt
figA = plt.figure('aa')
figB = plt.figure('bb')
plt.close('bb')
plt.plot([2,3],[1,1],color='green')
plt.show()
or
# Revised ver.2
import matplotlib.pyplot as plt
figA = plt.figure('aa')
figB = plt.figure('bb')
plt.close('aa')
plt.plot([2,3],[1,1],color='green')
plt.show(block=False)
plt.pause(3)
From revised ver.1, my guess is that close() only works on the last added figure. If we remove the previous figure, there will be an "empty" element in the list recording those figures. But this assumption violates the revised ver.2... Does anyone know why and how to solve this problem? Thank you.
Thanks to #Mr.T and #DavidG, I figure it out. Now the code becomes
# Revised original code
import matplotlib
matplotlib.use("Qt5Agg")
import matplotlib.pyplot as plt
figA = plt.figure('aa')
figB = plt.figure('bb')
plt.close('aa')
plt.plot([2,3],[1,1],color='green')
plt.show()
The culprit is the backend (default: "TkAgg"), and I set it as "Qt5Agg" now. I install the package pyqt5 by
pip install pyqt5==5.10.1
Note that the pyqt5 version needs to be 5.10.1. The latest one (5.11.2) would cause another error. For details, please read the webpage.
Related
I want to turn a series of matplotlib figures into an animation. However, whatever I do, I always receive error. I use Enthought Canopy 1.6.2 and Python 2.7.13 on Windows 10.
I have tried using videofig package. While it was good, I could not manage to save the mp4 file. Also, I believe using the source directly, i.e., matplotlib animation package would be more versatile for future uses. I checked a few answers, including 1, 2 and 3, yet none of them solved my problem.
The function I call is structured as follows.
def some_plotter(self, path, start_value, image_array)
some_unrelated_fig_functions()
im=plt.savefig(path, animated=True)
image_array.append([im])
plt.close("all")
The main code is as follows:
import matplotlib.animation as animation
image_array=[]
while(something):
some_obj.some_plotter(path, start_value, image_array)
fig = plt.figure()
ani = animation.ArtistAnimation(fig, image_array, interval=50, blit=True, repeat_delay=1000)
I receive the following error:
Traceback (most recent call last):
File "C:\Users\kocac\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\matplotlib\cbook__init__.py", line 387, in process
proxy(*args, **kwargs)
File "C:\Users\kocac\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\matplotlib\cbook__init__.py", line 227, in call
return mtd(*args, **kwargs)
File "C:\Users\kocac\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\matplotlib\animation.py", line 1026, in _start
self._init_draw()
File "C:\Users\kocac\AppData\Local\Enthought\Canopy\edm\envs\User\lib\site-packages\matplotlib\animation.py", line 1557, in _init_draw
artist.set_visible(False)
AttributeError: 'NoneType' object has no attribute 'set_visible'
I had more similar lines to this, yet updating Matplotlib, following the suggestion at 3 reduced the error lines to 4. Yet I cannot proceed any longer. Note that saved images are perfectly fine so I am probably not doing anything wrong in the image creation.
How can I get rid of these errors? Where am I going wrong?
When creating an animation using matplotlib.animation and saving it, an error appears when trying to close the figure window via plt.close:
Python version:
Python 2.7.12 |Anaconda custom (64-bit)| (default, Jul 2 2016, 17:42:40)
IPython 4.1.2 -- An enhanced Interactive Python
Currently I switched to using PyCharm 2017.1 Community Edition. The error message can be reproduced both directly in IPython and within PyCharm when running from %cpaste or %paste in IPython or running in PyCharm's interactive console using Shift+Alt+E. The movie encoder used is mencoder as integrated in mplayer, since this is the default one installed at my work place.
Note:
in IPython use plt.ion() first to turn on interactive mode (already switched on in PyCharm by default)
code exits without error in IPython when pasted using the middle mouse button directly into the IPython screen
code exits without error in IPython or PyCharm when typing all commands separately and also when pasting (%cpaste, %paste) all commands except for plt.close() and then typing plt.close() manually
code exits without error when replacing plt.close() with plt.clf(), but I need plt.close(), e.g. for creating animations in a loop with different parameters where the graph needs to be recreated from scratch
code exits without error when running the code in a script from start to end (non-interactive mode)
code exits without error when closing the figure window clicking with the mouse on the window button
code exits with error when inserting time.sleep(1) before plt.close(), so the problem likely does not relate to time conflicts in the code
A minimal, complete and (hopefully) verifiable example is given below:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# animation function for random image data
def animate_random_data(i):
new_data = np.random.rand(10, 10)
# update the data
im.set_data(new_data)
# initialize the graph
first_data = np.random.rand(10,10)
im = plt.imshow(first_data,interpolation='none')
myfig = plt.gcf()
# create the animation and save it
ani = animation.FuncAnimation(myfig, animate_random_data, range(10),
interval=100)
ani.save('animation_random_data.mpg', writer='mencoder')
plt.close()
Error traceback (from PyCharm):
Traceback (most recent call last):
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/backends/backend_qt5agg.py", line 176, in __draw_idle_agg
FigureCanvasAgg.draw(self)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py", line 474, in draw
self.figure.draw(self.renderer)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/artist.py", line 61, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/figure.py", line 1165, in draw
self.canvas.draw_event(renderer)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/backend_bases.py", line 1809, in draw_event
self.callbacks.process(s, event)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/cbook.py", line 563, in process
proxy(*args, **kwargs)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/cbook.py", line 430, in __call__
return mtd(*args, **kwargs)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/animation.py", line 652, in _start
self.event_source.add_callback(self._step)
AttributeError: 'NoneType' object has no attribute 'add_callback'
Although the program continues without error when closing the windows manually as written in the list above, it is an annoying bug (think of multiple animations in a loop). The error appears also for e.g. 1D line plots. Thanks for any help (and clarification on what this error message exactly means)!
The error comes from the animation still running while closing the figure. While in most cases it is automatically taken care of to stop the animation when closing the figure, it seems not to be the case in interactive mode.
A solution can be to explicitely stop the animation and delete it before closing the figure.
ani = animation.FuncAnimation(...)
ani.save(...)
ani.event_source.stop()
del ani
plt.close()
in this case you could just exit the program with exit()
I was trying to update a figure in matplotlib after each time step of a simulation.
I have managed to do this with:
import time, math
import matplotlib
matplotlib.use(u'Qt4Agg') # use some backend
# (c.f. http://stackoverflow.com/a/21836184 for .use())
import matplotlib.pyplot as plt
plt.ion()
fig = plt.figure()
sub = fig.add_subplot(1, 1, 1)
x = [i/100. for i in range(-500, 500)]
sin = lambda x : [math.sin(i) for i in x]
axis, = sub.plot(x, sin(x), 'r')
shift = 0.1
while shift < 5:
shift += 0.01
x = [i+shift for i in x]
axis.set_ydata(sin(x))
plt.pause(0.0001) # was plt.draw()
During the course of coming up with this solution I was almost getting mad because the Qt4Agg backend did now work properly with the draw() command where now there is a plt.pause(0.0001) command.
Now it works, but I get the following warning:
``/usr/local/lib/python2.7/dist-packages/matplotlib/backend_bases.py:2399: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented
warnings.warn(str, mplDeprecation)``
I also tried the GTK3Agg backend, but I am not sure if the computers where we want to run the project support it. Most surprisingly this backend worked with plt.draw() (except for the fact that the window freezes) but throws the following warnings and errors when running it with plt.pause(0.0001):
/usr/local/lib/python2.7/dist-packages/matplotlib/backend_bases.py:2399: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented
warnings.warn(str, mplDeprecation)
Traceback (most recent call last):
File "subplot_demo.py", line 24, in <module>
plt.pause(0.0001) # was plt.draw()
File "/usr/local/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 199, in pause
canvas.start_event_loop(interval)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_gtk3.py", line 370, in start_event_loop
FigureCanvasBase.start_event_loop_default(self,timeout)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/backend_bases.py", line 2407, in start_event_loop_default
self.flush_events()
File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_gtk3.py", line 365, in flush_events
Gtk.main_iteration(True)
File "/usr/lib/python2.7/dist-packages/gi/types.py", line 43, in function
return info.invoke(*args, **kwargs)
TypeError: main_iteration() takes exactly 0 arguments (1 given)
I assume now that pause() is deprecated (as it proved also difficult to find some useful documentation about it) but still stick to it with the Qt4Agg backend as I am sure that PyQt4 will be installed on the target systems.
I now wonder: How do I correctly draw() with the Qt4Agg? The draw() call is not working, pause() deprecated - what can I do? (On a side note: What exactly went wrong in the pause()-call of the GTK3Agg backend?)
Some notes on versions:
Ubuntu: 12.04, Matplotlib: 1.4.3, Python: 2.7.3, GCC 4.6.3, PyQt: 4.8.1
I've narrowed down to this call:
fig.canvas.tostring_argb() #fig=matplotlib.pyplot.figure()
this function raises an AttributeError when I run the code as a python script.
AttributeError: 'FigureCanvasGTKAgg' object has no attribute 'renderer'
However, this code works properly if run in the ipython --pylab command line.
As far as I can tell from the documentation, the Agg renderer should work OK.
The context is that I'm trying to make a movie from figures, without saving the frames
to disk; as per this question. I'm using the approach that streams the pixel arrays
to ffmpeg (running as a separate process) to do this, I need the argb array of values from the frame.
Is there some configuration setting I can make to get matplotlib to work correctly from within a script?
Edit
Tried use('Agg') as per a comment; still fails; this is a minimal working example.
[dave#dave tools]$ python -c "import matplotlib; matplotlib.use('Agg'); import matplotlib.pyplot; fig=matplotlib.pyplot.figure(); fig.canvas.tostring_argb()"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/matplotlib/backends/backend_agg.py", line 416, in tostring_argb
return self.renderer.tostring_argb()
AttributeError: FigureCanvasAgg instance has no attribute 'renderer'
I suspect that you have missed out the call to:
fig.canvas.draw()
before
fig.canvas.tostring_argb()
as
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot
fig=matplotlib.pyplot.figure()
fig.canvas.tostring_argb()
fails for me, but
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot
fig=matplotlib.pyplot.figure()
fig.canvas.draw()
fig.canvas.tostring_argb()
works.
I ended up installing and using the WXAgg backend; the Agg,and default GTKAgg, didn't work for me.
I ran into a python error that i have been trying to solve for several days now.
My program creates figures, saves and closes them which works fine except for this error. Usually it does not hinder the saving process but sometimes a picture is missing the lower part when saved. The odd thing is that this only happens every second time the loop reaches the savefig method, here is my code:
for num in np.arange(file_number):
plt.figure('abc' + str(num),figsize=(22,12),dpi=100)
#some plots are added to the figure
print 1
plt.savefig(os.path.join(savepath,filename),dpi=100)
print 2
plt.close()
print 3
I use the print commands to see where the error occurs. Here is the console output of spyder:
Reading file1.file
1
2
3
Reading file2.file
1
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_qt4.py", line 151, in <lambda>
lambda: self.close_event())
File "/usr/lib/pymodules/python2.7/matplotlib/backend_bases.py", line 1564, in close_event
self.callbacks.process(s, event)
RuntimeError: underlying C/C++ object has been deleted
2
3
Reading file3.file
1
2
3
Reading file4.file
1
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_qt4.py", line 151, in <lambda>
lambda: self.close_event())
File "/usr/lib/pymodules/python2.7/matplotlib/backend_bases.py", line 1564, in close_event
self.callbacks.process(s, event)
RuntimeError: underlying C/C++ object has been deleted
2
3
To my understanding, the error already occurs while saving the figure (every second time), although it works fine if i omit the close() command. In that case, my RAM is filled after about 70 files and sometimes i need to evaluate a couple of hundreds. That's why i need to include the close() command or something similar.
If you solve this (or improve my programing, i guess the way i did this saving and closing might be considered ugly) please help me.
How about change the backend to other options? For example:
import matplotlib as mpl
mpl.use( "agg" )
from matplotlib import pyplot as plt
import numpy as np
print plt.get_backend()
file_number = 100
for num in np.arange(file_number):
plt.figure('abc' + str(num),figsize=(22,12),dpi=100)
#some plots are added to the figure
print 1
plt.savefig("%d.png" % num,dpi=100)
print 2
plt.close()
print 3
I can't replicate your problem (partially because your example is not self contained), but I think you could look at going about solving the problem slightly different.
Since your figure definition (size, dpi, etc.) stays the same throughout the loop (and even if it didn't) you could look at producing just one figure, and updating it inside the loop:
import matplotlib as mpl
mpl.use( "tkagg" )
from matplotlib import pyplot as plt
import numpy as np
file_number = 1000
fig = plt.figure('abc', figsize=(22,12), dpi=100)
plt.show(block=False)
for num in np.arange(file_number):
fig.set_label('abc%s' % num)
# add an axes to the figure
ax = plt.axes()
#some plots are added to the figure (I just plotted a line)
plt.plot(range(num))
plt.savefig("%d.png" % num, dpi=100)
# draw the latest changes to the gui
plt.draw()
# remove the axes now that we have done what we want with it.
fig.delaxes(ax)
# put in a blocking show to wait for user interaction / closure.
plt.show()
Typically this isn't how you would do things (I would normally update the axes rather than add/remove one each time) but perhaps you have a good reason for doing it this way.
That should improve the performance significantly.