I would like to do an animation in python representing each point, dot by dot. I am doing it as I always have done it, but it does not work. Any help?
I tried 2 different ways.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
%matplotlib nbagg
def mcd(a, b):
resto = 0
while(b > 0):
resto = b
b = a % b
a = resto
return a
N = 1200
n = list (range (N))
an = [1,1]
for i in range (2,N):
k = i-1
if mcd (n[i], an[k]) == 1:
an.append (n[i] + 1 + an[k])
else:
an.append (an[k]/mcd (n[i], an[k]))
fig = plt.figure ()
ax = fig.add_subplot (111)
ax.grid (True)
ax.set_xlim(0, N*1.1)
pt, = ax.plot ([],[],'ko', markersize=2)
ax.plot (n,an, 'ko', markersize=2)
def init ():
pt.set_data([],[])
return (pt)
def animate (i,pt):
pt.set_data (n[:i],an[:i])
return (pt)
ani = FuncAnimation (fig, animate, fargs = (pt), frames=N, init_func=init, interval=50, blit = True)
plt.show ()
And the second way:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
%matplotlib nbagg
def mcd(a, b):
resto = 0
while(b > 0):
resto = b
b = a % b
a = resto
return a
N = 1200
n = list (range (N))
an = [1,1]
for i in range (2,N):
k = i-1
if mcd (n[i], an[k]) == 1:
an.append (n[i] + 1 + an[k])
else:
an.append (an[k]/mcd (n[i], an[k]))
xdata, ydata = [],[]
fig = plt.figure ()
ax = fig.add_subplot(111)
ax.grid (True)
pt, = ax.plot ([],[],'ko', markersize=2)
ax.plot (n,an, 'ko', markersize=2)
def init ():
ax.set_xlim(0, N*1.1)
pt.set_data([],[])
return (pt)
def animate (pt):
xdata.append (n[i])
ydata.append (an[i])
pt.set_data (xdata,ydata)
return (pt)
ani = FuncAnimation (fig, animate, fargs = (pt), frames=N, init_func=init, interval=50, blit = True)
plt.show ()
Using those codes, I get the entire figure with all the points. I would like to fill the graph point by point in an animated way.
The following will work
%matplotlib nbagg
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def mcd(a, b):
resto = 0
while(b > 0):
resto = b
b = a % b
a = resto
return a
N = 1200
n = list (range (N))
an = [1,1]
for i in range (2,N):
k = i-1
if mcd (n[i], an[k]) == 1:
an.append (n[i] + 1 + an[k])
else:
an.append (an[k]/mcd (n[i], an[k]))
fig = plt.figure ()
ax = fig.add_subplot (111)
ax.grid (True)
ax.set_xlim(0, N*1.1)
ax.set_ylim(min(an), max(an))
pt, = ax.plot([],[],'ko', markersize=2)
def init ():
pt.set_data([], [])
return pt,
def animate(i):
pt.set_data (n[:i], an[:i])
return pt,
ani = FuncAnimation (fig, animate, frames=N, init_func=init, interval=50, blit = True)
plt.show ()
EDIT: I tested it in normal Python Shell and it draws black dots on red dots but Jupyter draws black dots hidden behind red dots so it needs these lines in different order - first red dots, next empty plot for black dots.
ax.plot(n, an, 'ro', markersize=2) # red dots
pt, = ax.plot([], [], 'ko', markersize=2)
First: I get error message
TypeError: 'Line2D' object is not iterable.
All because () doesn't create tuple - you have to use comma , to create tuple in
return pt, and fargs=(pt,)
Problem is because you draw all point at start using
ax.plot(n, an, 'ko', markersize=2)
and later it draws dots in the same places so you don't see animation.
If you use different color - ie. red
ax.plot(n, an, 'ro', markersize=2)
then you will see animation of black points on red points.
Or remove this line and it will draw dots in empty window.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
#%matplotlib nbagg
def mcd(a, b):
resto = 0
while(b > 0):
resto = b
b = a % b
a = resto
return a
N = 1200
n = list(range(N))
an = [1, 1]
for i in range(2, N):
k = i-1
if mcd(n[i], an[k]) == 1:
an.append(n[i] + 1 + an[k])
else:
an.append(an[k]/mcd(n[i], an[k]))
fig = plt.figure()
ax = fig.add_subplot(111)
ax.grid(True)
ax.set_xlim(0, N*1.1)
pt, = ax.plot([], [], 'ko', markersize=2)
ax.plot(n, an, 'ro', markersize=2) # red dots
def init():
pt.set_data([], [])
return (pt,)
def animate(i, pt):
pt.set_data(n[:i], an[:i])
return (pt,)
ani = FuncAnimation(fig, animate, fargs=(pt,), frames=N, init_func=init, interval=50, blit=True)
plt.show ()
In second code you have the same problems and you also forgot i in def animate(i, pt):
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
#%matplotlib nbagg
def mcd(a, b):
resto = 0
while(b > 0):
resto = b
b = a % b
a = resto
return a
N = 1200
n = list(range (N))
an = [1, 1]
for i in range(2, N):
k = i-1
if mcd(n[i], an[k]) == 1:
an.append(n[i] + 1 + an[k])
else:
an.append(an[k]/mcd (n[i], an[k]))
xdata, ydata = [], []
fig = plt.figure()
ax = fig.add_subplot(111)
ax.grid(True)
pt, = ax.plot([], [], 'ko', markersize=2)
ax.plot(n, an, 'ro', markersize=2)
def init():
ax.set_xlim(0, N*1.1)
pt.set_data([], [])
return (pt,)
def animate(i, pt):
xdata.append(n[i])
ydata.append(an[i])
pt.set_data(xdata, ydata)
return (pt,)
ani = FuncAnimation(fig, animate, fargs=(pt,), frames=N, init_func=init, interval=50, blit=True)
plt.show ()
Related
I was trying to animate arrow and used the script from the following answer. Plus my animation has scatter-points and text too.
This is the script that I am using:-
from my_func import Pitch
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
## Pitch for plotting the football-pitch in the background
pitch = Pitch(line_color='grey', pitch_color='#121212', orientation='horizontal')
fig, ax = pitch.create_pitch()
x_start, y_start = (50, 35)
x_end, y_end = (90, 45)
x_1, y_1, x_2, y_2 = 50.55, 35.1375, 89.45, 44.8625
x = np.linspace(x_1, x_2, 20)
y = np.linspace(y_1, y_2, 20)
sc_1 = ax.scatter([], [], color="crimson", zorder=4, s=150, alpha=0.7, edgecolor="w")
sc_2 = ax.scatter([], [], color="crimson", zorder=4, s=150, alpha=0.7, edgecolor="w")
title = ax.text(50, 65, "", bbox={'facecolor':'w', 'alpha':0.5, 'pad':5}, ha="center")
def animate(i):
if i == 1:
sc_1.set_offsets([x_start, y_start])
title.set_text("Start of Action 01")
if i == 2:
plt.pause(0.5)
title.set_text("Action 02")
## plot arrow
## haven't included ax.cla() as it was removing the pitch in the background
if i <= len(x):
patch = plt.Arrow(x_start, y_start, x[i] - x_start, y[i] - y_start)
ax.add_patch(patch)
## plot scatter point
if i > len(x):
plt.pause(0.2)
title.set_text("Action 03")
sc_2.set_offsets([x_end, y_end])
return sc_1, patch, sc_2, title,
ani = animation.FuncAnimation(
fig=fig, func=animate, interval=50, blit=True)
plt.show()
The result is showing a little bit of animation and then giving me the following error:
File "test.py", line 33, in animate
patch = plt.Arrow(x_start, y_start, x[i] - x_start, y[i] - y_start)
IndexError: index 20 is out of bounds for axis 0 with size 20
[1] 14116 abort (core dumped) python test.py
I am a begineer in matplotlib animations and don't know how to solve this error what should I change in my code to remove the error and generate the animated output.
The modifications are as follows: 1) plt.axes() is added to ax. 2) The return value of the animation function is set to ax. 3) The number of objects to be animated is 20, so frames=20 is used.
# from my_func import Pitch
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
## Pitch for plotting the football-pitch in the background
# pitch = Pitch(line_color='grey', pitch_color='#121212', orientation='horizontal')
# fig, ax = pitch.create_pitch()
fig,ax = plt.subplots()
x_start, y_start = 50, 35
x_end, y_end = 90, 45
x_1, y_1, x_2, y_2 = 50.55, 35.1375, 89.45, 44.8625
x = np.linspace(x_1, x_2, 20)
y = np.linspace(y_1, y_2, 20)
ax = plt.axes(xlim=(50, 90), ylim=(35, 45))
sc_1 = ax.scatter([], [], color="crimson", zorder=1, s=150, alpha=0.7, edgecolor="w")
sc_2 = ax.scatter([], [], color="crimson", zorder=1, s=150, alpha=0.7, edgecolor="w")
title = ax.text(50, 65, "", bbox={'facecolor':'w', 'alpha':0.5, 'pad':5}, ha="center")
def animate(i):
if i == 1:
sc_1.set_offsets([x_start, y_start])
title.set_text("Start of Action 01")
if i == 2:
plt.pause(0.5)
title.set_text("Action 02")
## plot arrow
## haven't included ax.cla() as it was removing the pitch in the background
if i <= len(x):
ax.clear()
#patch = plt.Arrow(x_start, y_start, x[i] - x_start, y[i] - y_start)
#ax.add_patch(patch)
ax.arrow(x_start, y_start, x[i]-x_start, y[i]-y_start, head_width=1, head_length=1, fc='black', ec='black')
ax.set(xlim=(50,90), ylim=(35,45))
## plot scatter point
if i == len(x)-1:
plt.pause(0.2)
title.set_text("Action 03")
sc_2.set_offsets([x_end, y_end])
return sc_1, sc_2, title, ax
ani = animation.FuncAnimation(fig=fig, func=animate, frames=20, interval=200, repeat=False, blit=True)
plt.show()
I'm trying to figure out why an extra blank figure is shown using this code, there should be only two figures but three are shown where one is empty. Here is an image showing what happens:
Here is the code I am using:
f1 = plt.figure(1)
img=mpimg.imread(image_path)
imgplot = plt.imshow(img)
original_image = Image.open(image_path)
bw_image = original_image.convert('1', dither=Image.NONE)
bw_image_array = np.array(bw_image, dtype=np.int)
black_indices = np.argwhere(bw_image_array == 0)
chosen_black_indices = black_indices[np.random.choice(black_indices.shape[0], replace=False, size=3000)]
distances = pdist(chosen_black_indices)
distance_matrix = squareform(distances)
optimized_path = solve_tsp(distance_matrix)
optimized_path_points = [chosen_black_indices[x] for x in optimized_path]
f2 = plt.figure(2)
plt.xlim(0, 600)
plt.ylim(0, 800)
plt.gca().invert_yaxis()
plt.xticks([])
plt.yticks([])
xstartdata = optimized_path_points[0][0]
ystartdata = optimized_path_points[0][1]
fig, ax = plt.subplots()
ln, = plt.plot([], [], color='black', marker='o', linestyle='dashed', markersize=1, animated=True)
plt.plot([xstartdata], [ystartdata], color='black', marker='o', linestyle='dashed', markersize=1, lw=0.1)
plt.gca().invert_yaxis()
x = []
y = []
def init():
ln.set_data([],[])
return ln,
def animate(i):
x.append(optimized_path_points[i][1])
y.append(optimized_path_points[i][0])
ln.set_data(x, y)
plt.plot(x , y , lw=0.1,animated=True)
return ln,
anim = animation.FuncAnimation(fig, animate, init_func=init,frames=range(len(optimized_path_points)), interval=5, blit=True)
plt.show()
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()
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()
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)