matplotlib animation closes just after running - python

I'm trying to make a small animation of particles moving left or right but the figure just closes immediately after running. I tried to read some tips here in the forum but nothing helped.
Can't understand why the animation does not work for me.
I looked at some examples and I do not find the mistake I made.
Could you help me?
import numpy as np
import random
from scipy.spatial.distance import pdist, squareform
import matplotlib.pyplot as plt
import scipy.integrate as integrate
import matplotlib.animation as animation
class ParticleBox:
"""
init_state is a 3D array of x,y coordinates + probability to go left or right
bounds is the size of the box: [xmin, xmax, ymin, ymax]
"""
def __init__(self,
init_state, bounds = [-9, 9, -2, 2],
size = 0.04, step_size=0.05):
self.init_state = np.asarray(init_state, dtype=float)
self.size = size
self.state = self.init_state.copy()
self.time_elapsed = 0
self.bounds = bounds
self.ycorbeg=range(len(self.state))
def step(self, dts):
pr=0.4
pl=0.4
ps=0.2
self.time_elapsed+=dts
for i in range(len(self.state)):
print c
c=random.random()
if c<pr:
print c
self.state[i,2]=ze
elif (pr<=c and c<pr+pl):
self.state[i,2]=-step_size
else:
self.state[i,0]=self.state[i,0]
self.state[:, 0] += dt * self.state[:, 2]
np.random.seed(0)
beginx=np.random.rand(1000)-0.5
lenbegin=len(beginx)
def beginy(lenbegin,maxy=250):
i=0
beginy=np.zeros(lenbegin)
while i<lenbegin:
for j in range(int(-maxy/2),int(maxy/2)):
beginy[i]=j/50.0
i+=1
if len(beginx)==len(beginy):
ze=np.zeros(len(beginy))
print zip(beginx,beginy,ze)[0]
return zip(beginx,beginy,ze)
else:
raise ValueError
init_state=beginy(lenbegin)
box = ParticleBox(init_state)
dts = 1. / 30
#------------------------------------------------------------
# set up figure and animation
fig = plt.figure()
fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False,
xlim=(-3.2, 3.2), ylim=(-2.4, 2.4))
# particles holds the locations of the particles
particles, = ax.plot([], [], 'bo', ms=6)
# rect is the box edge
rect = plt.Rectangle(box.bounds[::2],
box.bounds[1] - box.bounds[0],
box.bounds[3] - box.bounds[2],
ec='none', lw=2, fc='none')
ax.add_patch(rect)
def init():
"""initialize animation"""
global box, rect
particles.set_data([], [])
rect.set_edgecolor('none')
return particles, rect
def animate(i):
"""perform animation step"""
global box, rect, dts, fig
box.step(dts)
ms = int(fig.dpi * 2 * box.size * fig.get_figwidth()
/ np.diff(ax.get_xbound())[0])
# update pieces of the animation
rect.set_edgecolor('k')
particles.set_data(box.state[:, 0], box.state[:, 1])
particles.set_markersize(ms)
return particles, rect
anim = animation.FuncAnimation(fig, animate, frames=600,
interval=10, blit=True, init_func=init)
plt.show()

Related

Python 3.5.4 matplotlib can not draw the animated figure

I want to draw an animated chart using python3.5.4's matplotlib package, the examples of matplotlib official website works well on my local Python environment.
But those codes I wrote can not show me any chart, I can not figure out what's problem in those codes, so I come here to look for some help. Here are my codes.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
class Plot(object):
def __init__(self, update_func, frames):
self.x_data, self.y_data = [], []
self.update_func = update_func
self.frames = frames
self.t = 0
def draw(self):
fig = plt.figure()
self.ax = plt.axes()
self.line, = self.ax.plot([1, 2, 3, 4], [1, 2, 3, 4], lw=2)
# Without invoke the FuncAnimation can display the chart.
self.ani_ref = FuncAnimation(fig, self._update, frames=self.frames, blit=True,
interval=20, init_func=self._animation_init)
plt.show()
def _animation_init(self):
self.line.set_data(self.x_data, self.y_data)
return self.line
def _update(self, i):
# modified the data from outside update function
self.x_data, self.y_data = self.update_func(self.x_data, self.y_data)
x_min, x_max = self.ax.get_xlim()
y_min, y_max = self.ax.get_ylim()
if np.max(self.x_data) >= x_max:
x_max = np.max(self.x_data) + 10
if np.min(self.x_data) <= x_min:
x_min = np.min(self.x_data) - 10
if np.max(self.y_data) >= y_max:
y_max = np.max(self.y_data) + 10
if np.min(self.y_data) <= y_min:
y_min = np.min(self.y_data) - 10
self.ax.set_xlim(x_min, x_max)
self.ax.set_ylim(y_min, y_max)
self.ax.figure.canvas.draw()
self.line.set_data(self.x_data, self.y_data)
return self.line
if __name__ == "__main__":
def update(x_data, y_data):
x, y = x_data[-1], np.sin(2 * np.pi * (x_data[-1] + 0.1))
x_data.append(x)
y_data.append(y)
return x_data, y_data
p = Plot(update_func=update, frames=100)
p.draw()

Shading over plot with funcanimation

I'm trying to shade over a map to show "explored regions" of the dot as it moves around using FuncAnimation. This is the code I have so far:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.animation as animation
import numpy as np
import random
import scipy.stats as stats
map_x = 100
map_y = 100
fig = plt.figure(0)
plt.figure(0)
ax1 = plt.subplot2grid((2,3), (0,0), colspan=2, rowspan=2)
ax2 = plt.subplot2grid((2,3), (0,2), colspan=1)
ax1.set_xlim([0, map_x])
ax1.set_ylim([0, map_y])
ax2.set_xlim([0, map_x])
ax2.set_ylim([0, map_y])
agent = plt.Circle((50, 1), 2, fc='r')
agent2 = plt.Circle((50, 1), 2, fc='r')
agents = [agent, agent2]
ax1.add_patch(agent)
ax2.add_patch(agent2)
def animate(i):
x, y = agent.center
x = x+.1
y = y+.1
agent.center = (x, y)
agent2.center = (x, y)
return agent,
def fillMap(x, y):
circle=plt.Circle((x,y), 4, fc='b')
ax2.add_patch(circle)
def animate2(i):
x, y = agent2.center
x = x+.1
y = y+.1
agent2.center = (x, y)
fillMap(x, y)
return agent2,
anim = animation.FuncAnimation(fig, animate, frames=200, interval=20, blit=True)
anim2 = animation.FuncAnimation(fig, animate2, frames=200, interval=20, blit=True)
plt.show()
However, it only goes into fillMap once, and only draws the blue filled in circle once, instead of everywhere where the red dot goes in the smaller subplot.
If you want the circle you added to persist on the screen you probably shouldn't use blitting. Not using blitting makes the animation slower, but it may be enough to draw a new blue circle every 20th step or so.
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.animation as animation
import numpy as np
import scipy.stats as stats
map_x = 100
map_y = 100
fig = plt.figure(0)
plt.figure(0)
ax1 = plt.subplot2grid((2,3), (0,0), colspan=2, rowspan=2)
ax2 = plt.subplot2grid((2,3), (0,2), colspan=1)
ax1.set_xlim([0, map_x])
ax1.set_ylim([0, map_y])
ax2.set_xlim([0, map_x])
ax2.set_ylim([0, map_y])
agent = plt.Circle((50, 1), 2, fc='r')
agent2 = plt.Circle((50, 1), 2, fc='r')
agents = [agent, agent2]
ax1.add_patch(agent)
ax2.add_patch(agent2)
def fillMap(x, y):
circle=plt.Circle((x,y), 4, fc='b')
ax2.add_patch(circle)
def animate2(i):
x, y = agent.center
x = x+.1
y = y+.1
agent.center = (x, y)
x, y = agent2.center
x = x+.1
y = y+.1
agent2.center = (x, y)
if i%20==0:
circle = fillMap(x, y)
anim2 = animation.FuncAnimation(fig, animate2, frames=200, interval=20, blit=False)
plt.show()
In case you want to use blitting, consider using a line to mark the region where the circle has been.
line, =ax2.plot([],[], lw=3, color="b")
xl = []; yl=[]
def fillMap(x, y):
xl.append(x); yl.append(y)
line.set_data(xl,yl)
return line
def animate2(i):
x, y = agent.center
x = x+.1
y = y+.1
agent.center = (x, y)
x, y = agent2.center
x = x+.1
y = y+.1
agent2.center = (x, y)
if i%20==0:
fillMap(x, y)
return agent, agent2, line
anim2 = animation.FuncAnimation(fig, animate2, frames=200, interval=20, blit=True)

matplotlib animation keep the old patch when blit = True

I want to animate a random rectangle in matplotlib. I found out that when I set blit=True, the animation always keeps the first rectangle calculated. If I set blit=False, the animation will keep update the rectangle and the old rectangle disappears. How to remove the old rectangle if I want to set blit=True?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
import random
class box_sim_env(object):
def __init__(self):
self.env_fig = plt.figure()
self.ax = self.env_fig.add_subplot(111, aspect='equal')
self.box_pose = np.array([0.48, 0.5, 0])
self.create_box(self.box_pose)
self.ax.add_patch(self.box_patch)
def update_box(self, pose):
self.box_verts = self.get_rect_verts(np.array([pose[0], pose[1]]), 0.6, 0.3,
angle=pose[2])
self.box_patch.set_xy(self.box_verts)
def create_box(self, pose):
self.box_verts = self.get_rect_verts(np.array([pose[0], pose[1]]), 0.6, 0.3,
angle=pose[2])
self.box_patch = plt.Polygon(self.box_verts, facecolor='cyan', edgecolor='blue')
def get_rect_verts(self, center, length, width, angle):
rotation_mtx = np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]])
half_length = length / 2.0
half_width = width / 2.0
verts = np.array([[-half_length, half_width],
[half_length, half_width],
[half_length, -half_width],
[-half_length, -half_width]])
verts_rot = np.dot(rotation_mtx, verts.T)
verts_trans = verts_rot.T + center.reshape((1,2))
return verts_trans.reshape((4,2))
def animate(self, i):
pose = np.zeros(3)
pose[0] = random.uniform(-3,3)
pose[1] = random.uniform(-3,3)
pose[2] = random.uniform(-np.pi, np.pi)
self.update_box(pose)
return [self.box_patch,]
def plt_show(self):
self.anim = animation.FuncAnimation(self.env_fig, self.animate,
init_func=None,
frames=1000,
interval=1,
# repeat= False,
blit=True)
plt.xlim([-4,4])
plt.ylim([-4,4])
plt.show()
if __name__ == '__main__':
print '============'
box_sim = box_sim_env()
box_sim.plt_show()

Get data from Python plot with matplotlib then save to array

The first block of code in this answer allows the user to generate a matplotlib figure and by clicking on the graph, it is possible to display the x- and y- coordinates of the graph after each click. How can I save these coordinates to 5 decimal places, say, into a numpy array (X for the x-coordinates and Y for the y-coordinates)? I'm not really sure how to start this (and it's probably trivial), but here is the code:
import numpy as np
import matplotlib.pyplot as plt
X = []
Y = []
class DataCursor(object):
text_template = 'x: %0.2f\ny: %0.2f'
x, y = 0.0, 0.0
xoffset, yoffset = -20, 20
text_template = 'x: %0.2f\ny: %0.2f'
def __init__(self, ax):
self.ax = ax
self.annotation = ax.annotate(self.text_template,
xy=(self.x, self.y), xytext=(self.xoffset, self.yoffset),
textcoords='offset points', ha='right', va='bottom',
bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0')
)
self.annotation.set_visible(False)
def __call__(self, event):
self.event = event
self.x, self.y = event.mouseevent.xdata, event.mouseevent.ydata
if self.x is not None:
self.annotation.xy = self.x, self.y
self.annotation.set_text(self.text_template % (self.x, self.y))
self.annotation.set_visible(True)
event.canvas.draw()
fig = plt.figure()
line, = plt.plot(range(10), 'ro-')
fig.canvas.mpl_connect('pick_event', DataCursor(plt.gca()))
line.set_picker(5) # Tolerance in points
plt.show()
It sounds like you want plt.ginput().
As a quick example:
fig, ax = plt.subplots()
ax.plot(range(10), 'ro-')
points = plt.ginput(n=4)
print points
np.savetxt('yourfilename', points)
plt.show()
I think you can do this by using list members in DataCursor:
def __init__(self, ax):
...
self.mouseX = []
self.mouseY = []
In your call, you would then store the X and Y for each event into these members:
def __call__(self, event):
...
self.mouseX.append(self.x)
self.mouseY.append(self.y)
You would then pass this to mpl_connect like this:
DC = DataCursor(plt.gca())
fig.canvas.mpl_connect('pick_event', DC)
...
print DC.mouseX, DC.mouseY
I have illustrated the principle here, but I don't see why this couldn't be applied to numpy arrays as well.

Animating 3d scatterplot in matplotlib

I'm trying to get a 3d animation of a scatterplot in matplotlib, based off the 2d scatterplot animation posted here and the 3d line plot posted here.
The problems arise from set_data and set_offsets not working in 3D, so you're supposed to use set_3d_properties to tack on the z information. Playing around with that it usually chokes, but with the code posted below it runs. However, the transparency increases enough that the points just fade away after a few frames. What am I doing wrong here? I want the points to jump around within the bounds of the box for a while. Even adjusting the step size to something very small doesn't slow down the transparency.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
FLOOR = -10
CEILING = 10
class AnimatedScatter(object):
def __init__(self, numpoints=5):
self.numpoints = numpoints
self.stream = self.data_stream()
self.angle = 0
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111,projection = '3d')
self.ani = animation.FuncAnimation(self.fig, self.update, interval=100,
init_func=self.setup_plot, blit=True)
def change_angle(self):
self.angle = (self.angle + 1)%360
def setup_plot(self):
x, y, z = next(self.stream)
c = ['b', 'r', 'g', 'y', 'm']
self.scat = self.ax.scatter(x, y, z,c=c, s=200, animated=True)
self.ax.set_xlim3d(FLOOR, CEILING)
self.ax.set_ylim3d(FLOOR, CEILING)
self.ax.set_zlim3d(FLOOR, CEILING)
return self.scat,
def data_stream(self):
data = np.zeros((3, self.numpoints))
xyz = data[:3, :]
while True:
xyz += 2 * (np.random.random((3, self.numpoints)) - 0.5)
yield data
def update(self, i):
data = next(self.stream)
data = np.transpose(data)
self.scat.set_offsets(data[:,:2])
#self.scat.set_3d_properties(data)
self.scat.set_3d_properties(data[:,2:],'z')
self.change_angle()
self.ax.view_init(30,self.angle)
plt.draw()
return self.scat,
def show(self):
plt.show()
if __name__ == '__main__':
a = AnimatedScatter()
a.show()
Found the solution finally, here is how to update points w/o touching colors:
from mpl_toolkits.mplot3d.art3d import juggle_axes
scat._offsets3d = juggle_axes(xs, ys, zs, 'z')
this is internally done by set_3d_properties along with re-initializing colors
I've found this, and more generic, solution:
You shold add np.ma.ravel( x_data ) ... before inserting your data in the collection.
But the scatter plot don't seems to be intended for animations; it's too slow.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
FLOOR = -10
CEILING = 10
class AnimatedScatter(object):
def __init__(self, numpoints=5):
self.numpoints = numpoints
self.stream = self.data_stream()
self.angle = 0
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111,projection = '3d')
self.ani = animation.FuncAnimation(self.fig, self.update, interval=100,
init_func=self.setup_plot, blit=True)
def change_angle(self):
self.angle = (self.angle + 1)%360
def setup_plot(self):
X = next(self.stream)
c = ['b', 'r', 'g', 'y', 'm']
self.scat = self.ax.scatter(X[:,0], X[:,1], X[:,2] , c=c, s=200, animated=True)
self.ax.set_xlim3d(FLOOR, CEILING)
self.ax.set_ylim3d(FLOOR, CEILING)
self.ax.set_zlim3d(FLOOR, CEILING)
return self.scat,
def data_stream(self):
data = np.zeros(( self.numpoints , 3 ))
xyz = data[:,:3]
while True:
xyz += 2 * (np.random.random(( self.numpoints,3)) - 0.5)
yield data
def update(self, i):
data = next(self.stream)
data = np.transpose(data)
self.scat._offsets3d = ( np.ma.ravel(data[:,0]) , np.ma.ravel(data[:,0]) , np.ma.ravel(data[:,0]) )
self.change_angle()
self.ax.view_init(30,self.angle)
plt.draw()
return self.scat,
def show(self):
plt.show()
if __name__ == '__main__':
a = AnimatedScatter()
a.show()

Categories

Resources