Python not responding after executing plt.show() - python

I am using the following code and python stops responding after executing plt.show(). I noticed removing the next input command removes the error, however, I need to retain both commands.
Next, I tried to sandwich plt.pause(2) between the two commands but here, python stops after I press any key once plot is displayed. Please help:
PS: I am using Atom editor with python 3.7.4
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import fsolve
def f(x):
y=2.0*np.sin(x**2)+3.0*x-10.0
return y
x=np.linspace(-5,3,100000)
plt.ion()
plt.plot(x,f(x))
plt.show()
plt.pause(2)
yy=input("pppp")
print(fsolve(f,2))

You have the following line in your code plt.ion(). If I remove the parentheses from the end of the line the program seems to work fine in Atom.

Related

When I plot something in python the programs execution stops until I close the plot figure

This is my code and after calculating some stuff I want it to draw them at each step
import time
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
FilePatch='E:\\# Civil Engineering Undergraduate\\Projects\\Python\\Frame'
NodesFile=FilePatch+'\\nodes.xlsx'
MemsFile=FilePatch+'\\members.xlsx'
MatsFile=FilePatch+'\\sections.xlsx'
nodes=pd.read_excel(NodesFile)
mems=pd.read_excel(MemsFile)
mats=pd.read_excel(MatsFile)
nodes=np.array(nodes)
mems=np.array(mems)
mats=np.array(mats)
np.nan_to_num(nodes)
np.nan_to_num(mems)
np.nan_to_num(mats)
Segments=100
Scale=1
n=np.size(nodes[:,0])
m=np.size(mems[:,0])
UsedEIA=np.zeros((m,3))
.
.
.
But the problem is that when it calls the plt.plot(...) for the first time it stops execution and won't go on unless I close the figure!
Is there any solution for this issue??
.
.
.
for i in range(1,1+n):
dx=Scale*D[3*i-3,0]
dy=Scale*D[3*i-2,0]
xn=nodes[nodes[:,0]==i,1]+dx
yn=nodes[nodes[:,0]==i,2]+dy
plt.text(xn,yn,str(i))
s=np.sum(nodes[nodes[:,0]==i,3:5])
if nodes[nodes[:,0]==i,5]==1:
plt.scatter(xn,yn,c='r',marker='s')
elif nodes[nodes[:,0]==i,3]==1 or nodes[nodes[:,0]==i,4]==1:
plt.scatter(xn,yn,c='g',marker='^')
plt.axis('equal')
plt.show()
time.sleep(0.1)
Also I wanna add some text in to my plot but it gives me an error which I can't understand it!
Here it is:
p=mems[i,4]
px=mems[i,3]
dl=mems[i,5]*L
w=mems[i,6]
xtxt=(FrameShape[0,0]+FrameShape[0:])/2
ytxt=(FrameShape[1,0]+FrameShape[1:])/2
xtxtp=FrameShape[0,0]
xtxtpx=FrameShape[0,0]+abs(px)/(1+abs(p))
xtxtw=FrameShape[0,0]+abs(p)/(1+abs(p))+abs(px)/(1+abs(px))
if p!=0 or px!=0:
btxt=' Py='+str(p)+' , Px=',str(px)+' #'+str(dl)
plt.text(xtxtp,ytxt-0.5,btxt)
XY=np.array([X,Shape])
FrameShape=np.transpose(T[0:2,0:2])#XY
FrameShape[0,:]=FrameShape[0,:]+xi
FrameShape[1,:]=FrameShape[1,:]+yi
if w!=0:
atxt='UL='+str(w)
plt.text(xtxtw,ytxt+0.5,atxt)
This is the error it gives me in the console:
TypeError: only size-1 arrays can be converted to Python scalars
plt.show() blocks the execution of your code. To avoid that, you could replace that line by plt.show(block=False). Your application will then run, but, as described in this post, your plots will likely not show up during execution.
So instead, try replacing plt.show() by
plt.show(block=False)
plt.pause(0.001)
in order to see the plots during runtime.
Finally, add a plt.show() at the very end of your program to keep the plots open, elsewise every figure will be closed upon program termination.

Numpy and Matplotlib Error with very Minimal Example

I have been using numpy and matplotlib together for some time now, successfully. Suddenly, I am getting unusual errors when using them together. The following is a minimal example:
import numpy as np
import matplotlib.pyplot as plt
fig,ax = plt.subplots(1,1)
x = np.eye(10)
u = np.linalg.svd(x)
plt.show()
If I run the code once, it works. If I run the code again, I get an exception:
LinAlgError: SVD did not converge. Bizarrely, this behavior disappears when the call to pyplot is removed:
import numpy as np
import matplotlib.pyplot as plt
#fig,ax = plt.subplots(1,1)
x = np.eye(10)
u = np.linalg.svd(x)
#plt.show()
I tried this with two different python environments with numpy versions 18.1 and 18.5. I am wondering if anyone has any information about what could possibly cause this behavior.
edit: I was running these two blocks of code in a jupyter notebook with only those lines of code and nothing else. In order to reproduce the behavior in the interactive interpreter, you need to add the line plt.show() in between runs. I edited the post to include this line.
edit: matplotlib 3.3.2, numpy 18.1 or 18.5, and I can use python 3.8.1 or 3.6.8

Different behaviour of matplotlib in interpretor and in script

Running following code inside python interpretor displays a figure with random values
>>>fig = plt.figure();ax1 = fig.add_subplot(111);plt.ion();ax1 = ax1.imshow(np.random.rand(256,256))
while running the following script as a file does not display any output/figure.
import numpy as np
import matplotlib.pyplot as plt
import time
fig = plt.figure()
ax1 = fig.add_subplot(111)
plt.ion()
ax1 =ax1.imshow(np.random.rand(256,256))
what is the reason for difference in behaviour?
I suspect what is going on is that
matplotlib.rcParams['interactive'] == True
and this is set in your .matplotlibrc file.
which means that plt.show is non-blocking (so that you get a figure that you can interact with and an command prompt you can type more code at). However, in the case of a script the (implicit) plt.show does not block so the script exits, taking the figure with it.
I suggest the setting the interactive rcparam to False and then either explitily setting it to true in the repl or (the preferred method) use IPython and the %matplotlib magic.

How to manipulate figures while a script is running in Python?

Introduction
As I am coming from matlab, I am used to an interactive interface where a script can update figures while it is running. During the processing each figure can be re-sized or even closed. This probably means that each figure is running in its own thread which is obviously not the case with matplotlib.
IPython can imitate the Matlab behavior using the magic command %pylab or %matplotlib which does something that I don't understand yet and which is the very point of my question.
My goal is then to allow standalone Python scripts to work as Matlab does (or as IPython with %matplotlib does). In other words, I would like this script to be executed from the command line. I am expecting a new figure that pop-up every 3 seconds. During the execution I would be able to zoom, resize or even close the figure.
#!/usr/bin/python
import matplotlib.pyplot as plt
import time
def do_some_work():
time.sleep(3)
for i in range(10):
plt.plot([1,2,3,4])
plt.show() # this is way too boilerplate, I'd like to avoid it too.
do_some_work()
What alternative to %matplotlib I can use to manipulate figures while a script is running in Python (not IPython)?
What solutions I've already investigated?
I currently found 3 way to get a plot show.
1. %pylab / %matplotlib
As tom said, the use of %pylab should be avoided to prevent the namespace to be polluted.
>>> %pylab
>>> plot([1,2,3,4])
This solution is sweet, the plot is non-blocking, there is no need for an additionnal show(), I can still add a grid with grid() afterwards and I can close, resize or zoom on my figure with no additional issues.
Unfortunately the %matplotlib command is only available on IPython.
2. from pylab import * or from matplotlib.pyplot import plt
>>> from pylab import *
>>> plot([1,2,3,4])
Things are quite different here. I need to add the command show() to display my figure which is blocking. I cannot do anything but closing the figure to execute the next command such as grid() which will have no effect since the figure is now closed...
** 3. from pylab import * or from matplotlib.pyplot import plt + ion()**
Some suggestions recommend to use the ion() command as follow:
>>> from pylab import *
>>> ion()
>>> plot([1,2,3,4])
>>> draw()
>>> pause(0.0001)
Unfortunately, even if the plot shows, I cannot close the figure manually. I will need to execute close() on the terminal which is not very convenient. Moreover the need for two additional commands such as draw(); pause(0.0001) is not what I am expecting.
Summary
With %pylab, everything is wonderful, but I cannot use it outside of IPython
With from pylab import * followed by a plot, I get a blocking behavior and all the power of IPython is wasted.
from pylab import * followed by ion offers a nice alternative to the previous one, but I have to use the weird pause(0.0001) command that leads to a window that I cannot close manually (I know that the pause is not needed with some backends. I am using WxAgg which is the only one that works well on Cygwin x64.
This question advices to use matplotlib.interactive(True). Unfortunately it does not work and gives the same behavior as ion() does.
Change your do_some_work function to the following and it should work.
def do_some_work():
plt.pause(3)
For interactive backends plt.pause(3) starts the event loop for 3 seconds so that it can process your resize events. Note that the documentation says that it is an experimental function and that for complex animations you should use the animation module.
The, %pylab and %matplotlib magic commands also start an event loop, which is why user interaction with the plots is possible. Alternatively, you can start the event loop with %gui wx, and turn it off with %gui. You can use the IPython.lib.guisupport.is_event_loop_running_wx() function to test if it is running.
The reason for using ion() or ioff() is very well explained in the 'What is interactive mode' page. In principle, user interaction is possible without IPython. However, I could not get the interactive-example from that page to work with the Qt4Agg backend, only with the MacOSX backend (on my Mac). I didn't try with the WX backend.
Edit
I did manage to get the interactive-example to work with the Qt4Agg backend by using PyQt4 instead of PySide (so by setting backend.qt4 : PyQt4 in my ~/.config/matplotlibrc file). I think the example doesn't work with all backends. I submitted an issue here.
Edit 2
I'm afraid I can't think of a way of manipulating the figure while a long calculation is running, without using threads. As you mentioned: Matplotlib doesn't start a thread, and neither does IPython. The %pylab and %matplotlib commands alternate between processing commands from the read-eval-print loop and letting the GUI processing events for a short time. They do this sequentially.
In fact, I'm unable to reproduce your behavior, even with the %matplotlib or %pylab magic. (Just to be clear: in ipython I first call %matplotlib and then %run yourscript.py). The %matplotlib magic puts Matplotlib in interactive-mode, which makes the plt.show() call non-blocking so that the do_some_work function is executed immediately. However, during the time.sleep(3) call, the figure is unresponsive (this becomes even more apparent if I increase the sleeping period). I don't understand how this can work at your end.
Unless I'm wrong you'll have to break up your calculation in smaller parts and use plt.pause (or even better, the animation module) to update the figures.
My advice would be to keep using IPython, since it manages the GUI event loop for you (that's what pylab/pylot does).
I tried interactive plotting in a normal interpreter and it worked the way it is expected, even without calling ion() (Debian unstable, Python 3.4.3+, Matplotlib 1.4.2-3.1). If I recall it right, it's a fairly new feature in Matplotlib.
Alternatively, you can also use Matplotlib's animation capabilities to update a plot periodically:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
plt.ion()
tt = np.linspace(0, 1, 200)
freq = 1 # parameter for sine
t0 = time.time() # for measuring ellapsed time
fig, ax = plt.subplots()
def draw_func(i):
""" This function gets called repeated times """
global freq # needed because freq is changed in this function
xx = np.sin(2*np.pi*freq*tt)/freq
ax.set_title("Passed Time: %.1f s, " % (time.time()-t0) +
"Parameter i=%d" % i)
ax.plot(tt, xx, label="$f=%d$ Hz" % freq)
ax.legend()
freq += 1
# call draw_func every 3 seconds 1 + 4 times (first time is initialization):
ani = animation.FuncAnimation(fig, draw_func, np.arange(4), interval=3000,
repeat=False)
# plt.show()
Checkout matplotlib.animation.FuncAnimation for details. You'll find further examples in the examples section.

How to update matplotlib plot in while loop? [duplicate]

what I am trying to do is having a script compute something, prepare a plot and show the already obtained results as a pylab.figure - in python 2 (specifically python 2.7) with a stable matplotlib (which is 1.1.1).
In python 3 (python 3.2.3 with a matplotlib git build ... version 1.2.x), this works fine. As a simple example (simulating a lengthy computation by time.sleep()) consider
import pylab
import time
import random
dat=[0,1]
pylab.plot(dat)
pylab.ion()
pylab.draw()
for i in range (18):
dat.append(random.uniform(0,1))
pylab.plot(dat)
pylab.draw()
time.sleep(1)
In python 2 (version 2.7.3 vith matplotlib 1.1.1), the code runs cleanly without errors but does not show the figure. A little trial and error with the python2 interpreter seemed to suggest to replace pylab.draw() with pylab.show(); doing this once is apparently sufficient (not, as with draw calling it after every change/addition to the plot). Hence:
import pylab
import time
import random
dat=[0,1]
pylab.plot(dat)
pylab.ion()
pylab.show()
for i in range (18):
dat.append(random.uniform(0,1))
pylab.plot(dat)
#pylab.draw()
time.sleep(1)
However, this doesn't work either. Again, it runs cleanly but does not show the figure. It seems to do so only when waiting for user input. It is not clear to me why this is, but the plot is finally shown when a raw_input() is added to the loop
import pylab
import time
import random
dat=[0,1]
pylab.plot(dat)
pylab.ion()
pylab.show()
for i in range (18):
dat.append(random.uniform(0,1))
pylab.plot(dat)
#pylab.draw()
time.sleep(1)
raw_input()
With this, the script will of course wait for user input while showing the plot and will not continue computing the data before the user hits enter. This was, of course, not the intention.
This may be caused by different versions of matplotlib (1.1.1 and 1.2.x) or by different python versions (2.7.3 and 3.2.3).
Is there any way to accomplish with python 2 with a stable (1.1.1) matplotlib what the above script (the first one) does in python 3, matplotlib 1.2.x:
- computing data (which takes a while, in the above example simulated by time.sleep()) in a loop or iterated function and
- (while still computing) showing what has already been computed in previous iterations
- and not bothering the user to continually hit enter for the computation to continue
Thanks; I'd appreciate any help...
You want the pause function to give the gui framework a chance to re-draw the screen:
import pylab
import time
import random
import matplotlib.pyplot as plt
dat=[0,1]
fig = plt.figure()
ax = fig.add_subplot(111)
Ln, = ax.plot(dat)
ax.set_xlim([0,20])
plt.ion()
plt.show()
for i in range (18):
dat.append(random.uniform(0,1))
Ln.set_ydata(dat)
Ln.set_xdata(range(len(dat)))
plt.pause(1)
print 'done with loop'
You don't need to create a new Line2D object every pass through, you can just update the data in the existing one.
Documentation:
pause(interval)
Pause for *interval* seconds.
If there is an active figure it will be updated and displayed,
and the gui event loop will run during the pause.
If there is no active figure, or if a non-interactive backend
is in use, this executes time.sleep(interval).
This can be used for crude animation. For more complex
animation, see :mod:`matplotlib.animation`.
This function is experimental; its behavior may be changed
or extended in a future release.
A really over-kill method to is to use the matplotlib.animate module. On the flip side, it gives you a nice way to save the data if you want (ripped from my answer to Python- 1 second plots continous presentation).
example, api, tutorial
Some backends (in my experience "Qt4Agg") require the pause function, as #tcaswell suggested.
Other backends (in my experience "TkAgg") seem to just update on draw() without requiring a pause. So another solution is to switch your backend, for example with matplotlib.use('TkAgg').

Categories