This is highly related to an earlier question by another person a couple of years ago: Matplotlib - Force plot display and then return to main code
I am using Canopy 1.5.5 on MacOSX 10.8.5, with matplotlib 1.4.3.
I will need to load data, look at it, press enter to approve and move to the next dataset (and do that a few thousand times, so it's kind of critical to get this functionality). Here is my MWE:
import numpy as np
from matplotlib import pyplot as plt
plt.ion()
plt.figure()
ind=np.arange(5)
for i in ind:
plt.clf()
plt.scatter(ind,ind+i)
plt.title('this is plot number %i' % i)
plt.show()
u=raw_input("Press any button")
The code seems to do everything EXCEPT actually showing me the plot. If I finish the script (or interrupt it), then I see the current figure.
I have tried everything from the previous answer: with and without interactive mode, with and without plt.show(block=False), every permutation of plt.draw and plt.show, and every backend on my available list.
This seems like a very basic functionality! Please tell me that this can be done. I find it weird that matplolib says here http://matplotlib.org/users/shell.html that "by default the drawing is deferred until the end of the script", but does not have suggestions on how to override the default. Please help!
Your example works for me (my backend is osx), although the figure window appears behind other windows at first. I needed to use alt-tab to raise it to the front.
Try starting your script with the --matplotlib option of IPython. You can select a backend or let it be auto-detected like so: ipython --matplotlib auto yourscript.py
Not sure if you now, but the raw_input function waits for you to press the return key, not just any key.
Edit:
About your last remark: this section explains how to force drawing before the end of the script. This can be done with the draw function. In interactive mode every pyplot command calls draw as well. Drawing in this context means rendering the figure by the backend.
Related
With a single script, I have to produce dozens of figures with matplotlib using spyder. I would like spyder to create figures while I can work with other browsers or windows without interruption. Here were the methods I tried. Let us say that there are 40 plots to be created. Each plot contains multiple subplots
(1) From How do I get interactive plots again in Spyder/IPython/matplotlib?. I used %matplotlib inline. The plots will be created inline at the end of the program. However, the usage of computation memory keeps accumulating. At some point, python will show an error message due to lack of memory and then crash. The message is like: "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."
(2) Then, I use plt.close() to close each figure after saving it. The memory issue is resolved. However, even if the figure is not shown, every time python close a figure and open another one, all other browsers and windows will be affected. If I am typing on a window, after the interruption, I have to click the window again in order to continue typing.
Previously, when I used MATLAB, I could simply specify h=figure and then set(h,'visible','off') to avoid this issue. I wonder if I can do similar things with python.
Thank you for the help!
The following python script does not display a figure anymore, as it used to on my machine:
import matplotlib.pyplot as plt
plt.scatter(1, 1)
plt.show() # Blocks and opens a graphical window as usual.
plt.ion()
plt.scatter(1, 1) # Does *not* open a graphical window anymore as I expect.
plt.scatter(2, 2) # Does *not* update the graphical window anymore as I expect (there is still no window at all)
plt.ioff()
plt.show() # The window opens at last, but it's blocking.
I also note that graphical windows style has changed (bottom bar):
My guess is that it is because my Arch system has recently upgraded to matplotlib 3.0.3-1. But I see nothing about a major change in ion() on their What's New page.
What could be causing this?
How do I get a non-blocking plot progressively updating like I used to get between two ion() and ioff() invokations?
[UPDATE] I can confirm that downgrading to matplotlib 2.2.3-2 does revert to expected behaviour. The problem thus seems to lie within recent upgrades of matplotlib or its environment.
[UDPATE] Filed on matplotlib issue tracker.
I'm following a book by Wes McKinney and in the section introducing pandas, he's given a simple example of plotting a pandas Data Frame. Here're the lines I wrote:
tz_counts = frame['tz'].value_counts() # frame is a Data Frame
tz_counts[:10] # works fine till here. I can see the key-value I wanted
tz_counts[:10].plot(kind='barh', rot=0)
It just prints a line on screen that says
<matplotlib.axes.AxesSubplot object at 0x3d14ed0>
rather than displaying a plot window as I'd expect with matplotlib's plot function. What's wrong here? How can I make it work?
Matplotlib doesn't show the plot until you tell it to, unless you're in "interactive" mode.
Short Answer: Call plt.show() when you're ready to display the plot.
This starts the gui mainloop of whatever backend you're using, so it is blocking. (i.e. execution will stop until you close the window)
If you want it to show up automatically without stopping execution, you can turn on interactive mode either with plt.ion() or by using ipython --pylab.
However, using --pylab mode in ipython will import all of numpy, matplotlib.pyplot, and a few other things into the global namespace. This is convenient for interactive use, but teaches very bad habits and overwrites functions in the standard library (e.g. min, max, etc).
You can still use matplotlib's interactive mode in ipython without using "pylab" mode to avoid the global import. Just call plt.ion()
Matplotlib's default TkAgg backend will work in interactive mode with any python shell (not just ipython). However, other backends can't avoid blocking further execution without the gui mainloop being run in a separate thread. If you're using a different backend, then you'll need to tell ipython this with the --gui=<backend> option.
Try using:
%matplotlib
tz_counts = frame['tz'].value_counts()
tz_counts[:10].plot(kind='barh', rot=0)
Using % matplotlib prevents importing * from pylab and numpy which in turn prevents variable clobbering.
I've been trying for hours to get this simple script working, but nothing I do seems to help. It's a slight modification of the most basic animated plot sample code from the Matplotlib website, that should just show a few frames of noise (I have the same issue with the unmodified code from their website BTW).
On my computer with the TkAgg backend I get about 20 frames (out of 60) before the plot window freezes. With Qt4Agg I just get a frozen, black window and no frames at all are plotted. I've tried multiple combinations of different NumPy, PyQt, Python and Matplotlib versions, but always get the same result.
Please let me know if this works for you or if anything looks wrong. I'm pretty sure this did work in the past, so I'm thinking it may be a Windows issue or something related to ion().
FYI I'm using Windows 7 (32 bit) and I've tested with Python 2.6/2.7, MPL 1.0.0/0.9.9.8, PyQt 4.6/4.7, Numpy 1.4/1.5b.
import matplotlib
matplotlib.use('TkAgg') # Qt4Agg gives an empty, black window
from pylab import *
import time
ion()
hold(False)
# create initial plot
z = zeros(10)
line, = plot(z)
ylim(-3, 3)
for i in range(60):
print 'frame:', i
d = randn(10)
line.set_ydata(d)
draw()
time.sleep(10e-3)
This simpler version also freezes after the first couple frames:
from pylab import *
ion()
hold(False)
for i in range(40):
plot(randn(10))
draw()
show()
Thanks!
EDIT: These people seem to be having the same or a similar problem as me:
mail-archive.com/matplotlib-users#lists.sourceforge.net/msg10844.html
stackoverflow.com/questions/2604119/matplotlib-pyplot-pylab-not-updating-figure-while-isinteractive-using-ipython
mail-archive.com/matplotlib-users#lists.sourceforge.net/msg01283.html
Doesn't look like any of them were able to fix it either :(
Typically, GUI frameworks need to 'own' the main loop of the program. Sitting in a tight loop with sleeps to delay iterations will usually 'break' GUI applications (your problem description is consistent with typical breakage along these lines). It's possible that the matplotlib devs have implemented some behind the scenes logic to pevent these lockups from happening for certain toolkits but restructuring your program slightly should eliminate any chance of mainloop ownership being the problem (which is very likely I think). The matplotlib animation wiki also suggests using native event loops for anything nontrivial (probably for this reason)
Rather than sitting in a loop with sleeps, I suggest that, instead, you use the GUI toolkit to schedule a function call after a certain delay.
def update_function():
# do frame calculation here
refresh_timer = QtCore.QTimer()
QtCore.QObject.connect( refresh_timer, QtCore.SIGNAL('timeout()'), update_function )
refresh_timer.start( 1.0 / 30 ) # have update_function called at 30Hz
Looking at the matplotlib documentation suggests that it may be possible to use their API natively but I couldn't find any good examples using just a quick search.
When you say freezes after the first couple of frames do you mean 2 or 3, or say, 40 or 60, as those are the upper limits of your loop?
If you want the animation to continue indefinitely you need something like
while True:
d = randn(10)
line.set_ydata(d)
draw()
time.sleep(10e-3)
But you'll have to force quit your program.
Generally you can't use show() and draw() like this. As the Posts are suggesting, you need a small GUI loop, just look at the Animations examples on the Matplotlib page.
After many hours fighting with this same issue I think I've found the answer: To do these simple animations with matplotlib you can only use the GTKAgg backend. This is stated as a passing remark in the scipy cookbook, but I think it should be stressed more clearly. When I use it, I can run your animations until the end without freezes or any other problem.
Beware that to use this backend you need to install PyGTK. I don't know what else you need on Windows (because I'm on Linux) but that seems the minimum. Besides, if you want to use it by default you have to add this line to your matplotlibrc (on Linux placed on ~/.matplotlib/matplotlibrc):
backend : GTKAgg
To use the other backends you need to follow the official matplotlib examples, but that means you have to build a mini-gui application just to run a simple animation, and I find that quite awful!
I was struggling with this same problem for quite a while. I would recommend taking a look at this example: http://matplotlib.sourceforge.net/examples/animation/strip_chart_demo.html
I thought I was following this example exactly, but it wasn't working. It would only run the "update" function one time. Turns out the only difference in my code was that the animation.FuncAnimation() was not assigned to a variable. As soon as I assigned the return value of animation.FuncAnimation() to a value, everything worked.
I was having (I think) the same trouble, where the window would freeze if I took the focus off it or tried to drag it around, using Python 2.7 on Windows 7 with Matplotlib 1.3, and TKAgg backend. I had a call to time.sleep(1) in my main while loop, and when I replaced that with plt.pause(1), that fixed the problem. So, try and use matplotlib's pause function rather than time module sleep function, it worked for me.
calling time.sleep() or plt.pause() causes flicker on the graph window when using blitting, but I got good results by simply calling the event loop explicitely :
fig.canvas.blit() # or draw()
fig.canvas.start_event_loop(0.001) #1 ms seems enough
greetings from the future.
Here's how you'd do it in python 3:
import matplotlib
matplotlib.use('TkAgg') # Qt4Agg gives an empty, black window
import matplotlib.pylab as plt
import time
# create initial plot
z = zeros(10)
line, = plot(z)
ylim(-3, 3)
for i in range(60):
print('frame:', i)
d = randn(10)
line.set_ydata(d)
draw()
#replace time.sleep() with plt.pause()
plt.pause(0.5)
I got rid of the call to ion() and hold(False). I also replaced time.sleep with plt.pause
I am working in linux and I don't know why using python and matplotlib commands draws me only once the chart I want.
The first time I call show() the plot is drawn, wihtout any problem, but not the second time and the following.
I close the window showing the chart between the two calls. Do you know why and hot to fix it?
Thanks AFG
from numpy import *
from pylab import *
data = array( [ 1,2,3,4,5] )
plot(data)
[<matplotlib.lines.Line2D object at 0x90c98ac>]
show() # this call shows me a plot
#..now I close the window...
data = array( [ 1,2,3,4,5,6] )
plot(data)
[<matplotlib.lines.Line2D object at 0x92dafec>]
show() # this one doesn't shows me anything
in windows this works perfect:
from pylab import *
plot([1,2,3,4])
[<matplotlib.lines.Line2D object at 0x03442C10>]
#close window here
plot([1,2,3,4])
[<matplotlib.lines.Line2D object at 0x035BC570>]
did you try with:
from matplotlib import interactive
interactive(True)
sometimes matplotlib produces some headaches because we have to remember that some options are set in matplotlibrc (such as the backend or the interactive parameters). If you use matplotlib from different editors (IDLE-tk, pycrust-wxpython) or alternating interactive with scripting, then you have to take into account that the configuration that works in one mode could give you problems in the other mode and must be modified programmatically or using a dedicated configuration file.
The example I give, works directly (and without show()) because in matplotlibrc I have interactive set to True as default
You likely have conflicts between your editor/IDE windowing system, and your plot windows.
A very good way around this is to use IPython. IPython is a great interactive environment, and has worked out these issues plus has many other advantages. At the beginning, start IPython with the command (from a terminal window) ipython -pylab to put it in the interactive pylab mode.
I'm guessing that you are doing this in IDLE on Windows because that's where I've noticed this same problem.
From what I've deduced, there is a problem with using the TkAgg backend,which comes with the basic Python dist and appears to be the default for matplotlib, when using matplotlib with IDLE. It has something to do with the way IDLE uses subprocesses because if I start IDLE with the -n option, which disables subprocesses, I don't have this problem. An easy way to start it IDLE with the -n option on Windows is to right click and file and select 'Open with IDLE'. If you do this you should get an IDLE shell which says
=== No Subprocess ===
just above the prompt. For instance, borrowing code from joaquin's solution, you could try this simple code:
from matplotlib import interactive
interactive(True)
from pylab import *
plot([1,2,3,4])
then close the window and type the last line into the console again. It works for me in IDLE with the -n option.
So what can you do? You can always run IDLE in the mode without subprocesses, but there are dangers to that. You can use a different IDE. Many people suggest IPython though I'm not sold on it yet myself. You could also try a different backend for matplotlib. I'm going to try that in a little while cause I've been wondering whether it will work.
show() is only meant to be used once in a program, at the very end: it is a never ending loop that checks for events in the graphic windows.
The normal way of doing what you want is:
# … plot …
draw() # Draws for real
raw_input() # Or anything that waits for user input
# … 2nd plot …
draw()
raw_input()
# Last plot
show() # or, again, draw(); raw_input()
You could try to see whether this works for you.
Alternatively, you can try to change the backend, as some backends work better than others:
import matplotlib
matplotlib.use('TkAgg') # For other backends, do matplotlib.use('') in a shell