Update mayavi plot in loop - python

What I want to do is to update a mayavi plot in a loop. I want the updating of the plot to be done at a time specified by me (unlike, e.g., the animation decorator).
So an example piece of code I would like to get running is:
import time
import numpy as np
from mayavi import mlab
V = np.random.randn(20, 20, 20)
s = mlab.contour3d(V, contours=[0])
for i in range(5):
time.sleep(1) # Here I'll be computing a new V
V = np.random.randn(20, 20, 20)
# Update the plot with the new information
s.mlab_source.set(scalars=V)
However, this doesn't display a figure. If I include mlab.show() in the loop, then this steals the focus and doesn't allow the code to continue.
I feel what I should be using is a traits figure (e.g. this). I can follow the example traits application to run a figure which live-updates as I update the sliders. However, I can't get it to update when my code asks it to update; the focus now is 'stolen' by visualization.configure_traits().
Any pointers, or a link to appropriate documentation, would be appreciated.
EDIT
David Winchester's answer gets a step closer to the solution.
However, as I point out in the comments, I am not able to manipulate the figure with the mouse during the time.sleep() step. It is during this step that, in the full program, the computer will be busy computing the new value of V. During this time I would like to be able to manipulate the figure, rotating it with the mouse etc.

I thin Mayavi uses generators to animate data. This is working for me:
import time
import numpy as np
from mayavi import mlab
f = mlab.figure()
V = np.random.randn(20, 20, 20)
s = mlab.contour3d(V, contours=[0])
#mlab.animate(delay=10)
def anim():
i = 0
while i < 5:
time.sleep(1)
s.mlab_source.set(scalars=np.random.randn(20, 20, 20))
i += 1
yield
anim()
I used this post as reference ( Animating a mayavi points3d plot )

If you use the wx backend, you can call wx.Yield() periodically if you want to interact with your data during some long-running function. In the following example, wx.Yield() is called for every iteration of some "long running" function, animate_sleep. In this case, you could start the program with $ ipython --gui=wx <program_name.py>
import time
import numpy as np
from mayavi import mlab
import wx
V = np.random.randn(20, 20, 20)
f = mlab.figure()
s = mlab.contour3d(V, contours=[0])
def animate_sleep(x):
n_steps = int(x / 0.01)
for i in range(n_steps):
time.sleep(0.01)
wx.Yield()
for i in range(5):
animate_sleep(1)
V = np.random.randn(20, 20, 20)
# Update the plot with the new information
s.mlab_source.set(scalars=V)

Related

Why is matplotlib.animation slower with large windows that with small windows?

So, I wrote up a Langton's Ant program.
#!/bin/env python
import matplotlib.animation as ani
import matplotlib.pyplot as plt
import numpy as np
w,h = 100,100
d = np.array([0,1])
p = np.array([w//2,h//2])
grid = np.ones((w,h),dtype=int)
#MAIN
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(1,1,1)
img = ax.imshow(grid,vmin=-1,vmax=1)
tle = ax.text(0.5,0.95,"",bbox={'facecolor':'w','alpha':0.5,'pad':5},transform=ax.transAxes,ha="center")
ax.tick_params(axis='x',which='both',bottom=False,top=False,labelbottom=False,labeltop=False)
ax.tick_params(axis='y',which='both',right=False,left=False,labelright=False,labelleft=False)
def langtons_ant_animator(frame):
global w,h,d,p,grid
v = grid[p[0],p[1]]
grid[p[0],p[1]] = -v
d = [[0,v],[-v,0]] # d
p = (p+d) % (w,h)
img.set_data(grid)
tle.set_text(f'{frame: 9} Steps; Point ({p[0]: 3},{p[1]: 3}), Direction ({d[0]: 2},{d[1]: 2})')
return [tle,img]
animation = ani.FuncAnimation(
fig = fig,
func = langtons_ant_animator,
interval = 1,
blit = True,
)
plt.show(block=True)
While this program is running I can dynamically change the window size. If I make the size really small (1in by 1in) the Ant moves at rapid speeds, nearing 1000 steps a second. But if I leave the window at (10in by 10in) it updates at around 100 or so steps a second. You would think that the number of pixels being updated is what effects the speed, but this isn't the case; change the window to a 1000,1000 and the animation runs just as fast at 10in by 10in.
It seems that window size is the most important factor in animation speed. Why?
Why doesn't img take into consideration the underlying numpy array size and know exactly the pixels that need to be updated together?
Could this be done smarter to get faster speeds?
Why are pixels so slow to update in matplotlib in the first place?

Slow tkinter GUI

I've written a simple GUI in python using pylabs and tkinter based on an example found here:
http://hardsoftlucid.wordpress.com/various-stuff/realtime-plotting/
used for sine wave generation.
Except I tweaked it to pull data through suds from a server on the internet. It's not working as I exactly anticipated as the GUI is somewhat slow. I think its due to the timer. I just started learning how to use matplotlib functions yesterday so I'm not aware of how every function works.
How can I speed it up? Right now the data comes in at 2-3 seconds which is fine, but I just want to increase the GUI responsiveness.
Here is my code:
import numpy as np
from matplotlib import pyplot as plt
plt.ion() # set plot to animated
url = "http://10.217.247.36/WSDL/v4.0/iLON100.WSDL"
client = Client(url, username='ilon', password='ilon', location = 'http://10.217.247.36/WSDL/iLON100.WSDL')
read = client.factory.create('ns0:E_xSelect')
read['xSelect'] = """//Item[starts-with(UCPTname, "Net/MB485/MAIN POWER/Fb/PowerSum")]"""
ydata = [0] * 50
ax1=plt.axes()
# make plot
line, = plt.plot(ydata)
plt.ylim([10,40])
# start data collection
while True:
x = client.service.Read(read).Item[0].UCPTvalue[0].value #data stream
x = float(x)
ymin = float(min(ydata))-10
ymax = float(max(ydata))+10
plt.ylim([ymin,ymax])
ydata.append(x)
del ydata[0]
line.set_xdata(np.arange(len(ydata)))
line.set_ydata(ydata) # update the data
plt.draw() # update the plot

Python- 1 second plots continous presentation

I have a dictionary with data. For every entry I would like to display plots for 1 second and move to the next one. The plots to display are already coded in external scripts. I would like to do this automatically. So I loop through the dict, display first set of plots[0], close the plots[0], display plots[1] close plots[1] ... I would like to set up display time for let say 1 second and have the plot as full screen. The problem that during the presentation I don't want to touch the computer.
import pylab as pl
import numpy as np
x = np.arange(-np.pi, np.pi, 0.1) # only for the example purpose
myDict = {"sin":np.sin(x), "cos":np.cos(x), "exp":np.exp(x)}
for key in myDict:
print myDict[key]
pl.plt.plot(myDict[key]) # in origin coming from external function
pl.plt.plot(x) # in origin coming from external function
pl.plt.show()
Does anyone know what function should be used and how to modify above?
A simple method is to use plt.pause(1). A more sophisticated method is to usethe matplotlib.animate module. See pylab.ion() in python 2, matplotlib 1.1.1 and updating of the plot while the program runs
example, api, tutorial
import time
import pylab as pl
import numpy as np
pl.ion()
x = np.arange(-np.pi, np.pi, 0.1) # only for the example purpose
myDict = {"sin":np.sin, "cos":np.cos, "exp":np.exp}
for key in myDict:
print myDict[key]
pl.clf()
y = myDict[key](x)
pl.plt.plot(x, y, label=key)
pl.plt.draw()
time.sleep(1)

How does one close a figure or replace a figure without having to manually close each figure in Python/pylab?

I have searched numerous sites, used plots, subplots, some basic animation, and other roundabout ways, but the figure will not close despite using close(), clf(), etc.
I have something like this:
import numpy
from pylab import *
import time
fig = Figure()
counter1 = 0
counter2 = 0
while counter1<5:
counter1 = counter1+1
while counter2<10:
scatter(x_list[counter2], y_list[counter2], hold = 'on') ### x_list and y_list are just lists of random numbers
counter2 = counter2 + 1
show()
sleep(0.5)
close()
I am looking for any solution, as seen above. Plots, subplots, animation...
Two side issues to start: first, are you sure that this is the code you're actually running? sleep isn't a function in my version of pylab, so your import time doesn't seem to match your call, it should be time.sleep(0.5).. Second, I don't understand your loops at all. It looks like you're plotting the same thing 5 times, because counter1 has no effect and you add each point to the scatterplot before you pause. Are you trying to plot x_list/y_list point by point?
If you use draw() instead of show() I think it should work; the show() is what's holding the close(). Is the following something like what you want?
import time
from pylab import *
ion()
# test data
x = arange(0, 10, 0.5)
y = 10*x+exp(x)*abs(cos(x))
for j in range(len(x)):
if j > 0: scatter(x[:j], y[:j])
# assuming we don't want the limits to change
xlim(0, 10)
ylim(0, 1000)
draw()
time.sleep(2)
#close()
Note that I've commented out the close() because this way it produces a nice animation. If you leave it in, it'll keep closing and reopening the window, which could be what you want, but doesn't look very useful to my eyes. YMMV, of course.

Quitting matplotlib.pyplot animation gracefully

I have a script that plots data of some photometry apertures, and I want to plot them in an xy plot. I am using matplotlib.pyplot with python 2.5.
The input data is stored in around 500 files and read. I am aware that this is not the most efficient way of inputting the data but that's another issue...
Example code:
import matplotlib.pyplot as plt
xcoords = []
ycoords = []
# lists are populated with data from first file
pltline, = plt.plot(xcoords, ycoords, 'rx')
# then loop populating the data from each file
for file in filelist:
xcoords = [...]
ycoords = [...]
pltline.set_xdata(xcoords)
pltline.set_ydata(ycoords)
plt.draw()
As there are over 500 files, I will occasionally want to close the animation window in the middle of the plotting. My code to plot works but it doesn't exit very gracefully. The plot window does not respond to clicking the close button and I have to Ctrl+C out of it.
Can anyone help me find a way to close the animation window while the script is running whilst looking graceful (well more graceful than a series of python traceback errors)?
If you update the data and do the draw in a loop, you should be able to interrupt it. Here's an example (that draws a stationary circle and then moves a line around the perimeter):
from pylab import *
import time
data = [] # make the data
for i in range(1000):
a = .01*pi*i+.0007
m = -1./tan(a)
x = arange(-3, 3, .1)
y = m*x
data.append((clip(x+cos(a), -3, 3),clip(y+sin(a), -3, 3)))
for x, y in data: # make a dynamic plot from the data
try:
plotdata.set_data(x, y)
except NameError:
ion()
fig = figure()
plot(cos(arange(0, 2.21*pi, .2)), sin(arange(0, 2.21*pi, .2)))
plotdata = plot(x, y)[0]
xlim(-2, 2)
ylim(-2, 2)
draw()
time.sleep(.01)
I put in the time.sleep(.01) command to be extra sure that I could break the run, but in my tests (running Linux) it wasn't necessary.

Categories