I have been studying the 1D wave equations and making the animation of the equation. But there are some problems when using the anim.save of animation to save the video file. I have already installed ffmpeg on my computer (a Windows machine) and set the environment variables. But it keeps telling me this:
UserWarning: MovieWriter ffmpeg unavailable
...
RuntimeError: Error creating movie, return code: 4 Try running with --verbose-debug
Here is my code:
from numpy import zeros,linspace,sin,pi
import matplotlib.pyplot as mpl
from matplotlib import animation
mpl.rcParams['animation.ffmpeg_path'] = 'C:\\ffmpeg\\bin\\ffmpeg.exe'
def I(x):
return sin(2*x*pi/L)
def f(x,t):
return sin(0.5*x*t)
def solver0(I,f,c,L,n,dt,t):
# f is a function of x and t, I is a function of x
x = linspace(0,L,n+1)
dx = L/float(n)
if dt <= 0:
dt = dx/float(c)
C2 = (c*dt/dx)**2
dt2 = dt*dt
up = zeros(n+1)
u = up.copy()
um = up.copy()
for i in range(0,n):
u[i] = I(x[i])
for i in range(1,n-1):
um[i] = u[i]+0.5*C2*(u[i-1] - 2*u[i] + u[i+1]) + dt2*f(x[i],t)
um[0] = 0
um[n] = 0
while t <= tstop:
t_old = t
t += dt
#update all inner points:
for i in range(1,n-1):
up[i] = -um[i] + 2*u[i] + C2*(u[i-1] - 2*u[i] + u[i+1]) + dt2*f(x[i],t_old)
#insert boundary conditions:
up[0] = 0
up[n] = 0
#update data structures for next step
um = u.copy()
u = up.copy()
return u
c = 1.0
L = 10
n = 100
dt = 0
tstop = 40
fig = mpl.figure()
ax = mpl.axes(xlim=(0,10),ylim=(-1.0,1.0))
line, = ax.plot([],[],lw=2)
def init():
line.set_data([],[])
return line,
def animate(t):
x = linspace(0,L,n+1)
y = solver0(I, f, c, L, n, dt, t)
line.set_data(x,y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
anim.save('seawave_1d_ani.mp4',writer='ffmpeg',fps=30)
mpl.show()
I believe the problem is in the part of the animation instead of the three functions above. Please help me find what mistake I have made.
I finally worked it out.It seemed that I missed two important lines.
mpl.rcParams['animation.ffmpeg_path'] = 'C:\\ffmpeg\\bin\\ffmpeg.exe' This line is correct.Both '\\' and '/' work in Windows,as far as I've tried.
I add mywriter = animation.FFMpegWriter()at the bottom and modify anim.save('seawave_1d_ani.mp4',writer='ffmpeg',fps=30) by anim.save('seawave_1d_ani.mp4',writer=mywriter,fps=30).It worked at last,thanks to Using FFmpeg and IPython.
Also grateful to those friends who helped me with this problem.
Related
I am coding two different graphs where they are supposed to be alike when a constant dt is a correct value. A part of the assignment is to make a widget slider that controls the constant dt, so when you run the code, the slider appears on the plot and lets you control the constant and changing the graph. However when I run this code:
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, FloatSlider
#constants
T0 = 83 #[celcius]
Ts = 22.8 #[celcius]
r = 0.1 #[min-1]
#The analytical solution. Part i:
def T(t):
return Ts + (T0 - Ts)*np.exp(-r*t)
t50 = np.arange(0, 50.1, 0.1)
Tanalytisk = []
for i in range(len(t50)):
Tanalytisk.append(T(t50[i]))
#Numerical solution. Part ii:
tslutt = 50
h = 1
def f(T):
return -r*(T-Ts)
def euler(f):
Tn = [T0]
tn = [0]
while(tn[-1] < tslutt):
t, y = tn[-1], Tn[-1]
Tn.append(y + h*f(y))
tn.append(t + h)
return (np.array(tn), np.array(Tn))
tn, Tn = euler(f)
plt.plot(t50, Tanalytisk,label="Analytical") #Analytical solution
plt.plot(tn, Tn, label = "Numerical") #Numerical solution
plt.plot(time, temp, label = "Experimental")
plt.xlabel("Time [min]")
plt.ylabel("Temperature [C]")
plt.title("Analytical solution T(t)")
plt.legend()
plt.show()
håndtak = FloatSlider(value = 1, min = 0, max = 15, step = 0.1, description = "dt")
interact(euler(f), h = håndtak)
I end up with this error:
> TypeError Traceback (most recent call last)
~\anaconda3\lib\site-packages\ipywidgets\widgets\interaction.py in update(self, *args)
254 value = widget.get_interact_value()
255 self.kwargs[widget._kwarg] = value
--> 256 self.result = self.f(**self.kwargs)
257 show_inline_matplotlib_plots()
258 if self.auto_display and self.result is not None:
TypeError: 'tuple' object is not callable
<function ipywidgets.widgets.interaction._InteractFactory.__call__.<locals>.<lambda>(*args,
**kwargs)>
How do I understand the problem and how can I make the widget work? It appears on the graph but doesn't change the graph when changing the value.
Is there an easier way to code the slider?
Thanks in advance!
You haven't define time and temp variables so I commented them. Anyway here's how you put the slider in your code :
import numpy as np
import matplotlib.pyplot as plt
import ipywidgets as wg
#wg.interact(h = wg.FloatSlider(min = 0, max = 15, step = 0.1, value=1, description = "dt"))
def run(h):
#constants
T0 = 83 #[celcius]
Ts = 22.8 #[celcius]
r = 0.1 #[min-1]
#The analytical solution. Part i:
def T(t):
return Ts + (T0 - Ts)*np.exp(-r*t)
t50 = np.arange(0, 50.1, 0.1)
Tanalytisk = []
for i in range(len(t50)):
Tanalytisk.append(T(t50[i]))
#Numerical solution. Part ii:
tslutt = 50
# h = 1
def f(T):
return -r*(T-Ts)
def euler(f,h):
Tn = [T0]
tn = [0]
while(tn[-1] < tslutt):
t, y = tn[-1], Tn[-1]
Tn.append(y + h*f(y))
tn.append(t + h)
return (np.array(tn), np.array(Tn))
tn, Tn = euler(f,h)
plt.plot(t50, Tanalytisk,label="Analytical") #Analytical solution
plt.plot(tn, Tn, label = "Numerical") #Numerical solution
# plt.plot(time, temp, label = "Experimental")
plt.xlabel("Time [min]")
plt.ylabel("Temperature [C]")
plt.title("Analytical solution T(t)")
plt.legend();
I have the code below. If you run that program a scatter plot is created. The plot is very messy. I want every point to represent one car. I only want to see the point of the current position of each car in the animation. I am not very good at matplotlib, but how would I do that?
from matplotlib import pyplot as plt
import random
import math
from matplotlib import animation
import numpy as np
roadLength = 100
numFrames = 200
numCars = 60
velocities = []
positions = []
theta = []
r = []
color = []
probability = 0.5
vmax = 1
flowr = []
fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')
ax.axis('off')
for i in range(numCars):
positions.append(i * 2)
theta.append(0)
r.append(1)
color.append(i)
velocities.append(0)
def pos(k):
rand = random.uniform(0,1)
if velocities[k] < vmax:
velocities[k] += 1
if k < numCars-1 and (positions[k+1] - positions[k]) <= velocities[k]:
velocities[k] = positions[k+1] - positions[k] - 1
if k == numCars-1 and (roadLength - (positions[k] - positions[0])) <= velocities[k]:
velocities[k] = roadLength - (positions[k] - positions[0]) - 1
if rand < probability and velocities[k] > 0:
velocities[k] = velocities[k] - 1
positions[k] = positions[k] + velocities[k]
return positions[k]
def animate(frameNr):
for i in range(numCars):
theta[i] = pos(i) * 2 * math.pi / roadLength
flowr.append(velocities[i])
ax.scatter(theta, r, c=color)
return ax.scatter(theta, r, c=color),
def simulate():
anim = animation.FuncAnimation(fig, animate,
frames=numFrames, interval=10, blit=True, repeat=False)
plt.show()
simulate()
Thanks in advance!
Edit:
I fixed so that it became a point plot I am now storing velocity, position and lane in an object for a later problem. My question is:
How do I make the points have different colors?
from matplotlib import pyplot as plt
import random
import math
from matplotlib import animation
import numpy as np
from operator import attrgetter
roadLength = 100
numFrames = 200
nlanes = 1
numCars = 20
posss =[]
theta = []
r = []
color = []
probability = 0.5
vmax = 1
flowr = []
cars=[]
class Car:
def __init__(self, position, velocity, lane):
self.position = position
self.velocity = velocity
self.lane = lane
def pos(car,k):
rand = random.uniform(0,1)
if car[k].velocity < vmax:
car[k].velocity += 1
if k < numCars-1 and (car[k+1].position - car[k].position) <= car[k].velocity:
car[k].velocity = car[k+1].position - car[k].position - 1
if k == numCars-1 and (roadLength - (car[k].position - car[0].position)) <= car[k].velocity:
car[k].velocity = roadLength - (car[k].position - car[0].position) - 1
if rand < probability and car[k].velocity > 0:
car[k].velocity = car[k].velocity - 1
car[k].position = car[k].position + car[k].velocity
return car[k].position
for i in range(numCars):
cars.append(Car(i, 0, 1))
theta.append(0)
r.append(1)
color.append(i)
posss.append(i)
fig = plt.figure()
ax = fig.add_subplot(111)
point, = ax.plot(posss, r, 'o')
ax.set_xlim(-10, 1.2*numFrames)
ax.set_ylim(-2, nlanes + 3)
def animate(frameNr):
sort_cars = sorted(cars, key=attrgetter("position"))
for i in range(numCars):
pos(sort_cars,i)
for k in range(numCars):
theta[k]=cars[k].position
point.set_data(theta, r)
return point,
def simulate():
anim = animation.FuncAnimation(fig, animate,
frames=numFrames, interval=10, blit=True, repeat=False)
plt.show()
simulate()
plot() returns a Line2D object, in which all points have the same color.
If you want your points to have different colors, you should use scatter(). The logic is exactly the same, except you use set_offsets(<2D array>) instead of set_data().
See this question for more details
Trying to plot persuit curves with spiraling in lines and a shrinking, rotating polygon with corners at each of the current points
problem = can't get both line of sight lines and main lines to simultaneously plot
The figure flicks back and forth between the shrinking polygon(described by SightLine) and the main persuit curves (MainLines)
When individually animated one at a time, the polygon and pursuit curves plot fine but I just can't get them to work together on the same figure.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
%matplotlib notebook
plt.style.use('dark_background')
NumOfPoints = 6
deltaT = 0.005
duration = 50
steps = int(duration / deltaT)
speed = 0.2
num = 0
CurrentXPoints = []
CurrentYPoints = []
DeltaX = np.zeros(NumOfPoints)
DeltaY = np.zeros(NumOfPoints)
MagnitudeDelta = np.zeros(NumOfPoints)
VelocityX = np.zeros(NumOfPoints)
VelocityY = np.zeros(NumOfPoints)
#Creates Initial Points by equally spacing the points around a polygon inscribed around circle
for i in range(0,NumOfPoints):
x = np.cos(((i/NumOfPoints)*2)*np.pi)
y = np.sin(((i/NumOfPoints)*2)*np.pi)
CurrentXPoints.append(x)
CurrentYPoints.append(y)
AllXPoints = np.array([CurrentXPoints])
AllYPoints = np.array([CurrentYPoints])
#Fills out both AllXPoints and AllYPoints with all points in duration
for i in range(int(steps)):
for j in range(0,NumOfPoints-1): #Calculates deltaX and deltaY at this timestep
DeltaX[j] = CurrentXPoints[j+1] - CurrentXPoints[j]
DeltaY[j] = CurrentYPoints[j+1] - CurrentYPoints[j]
DeltaX[NumOfPoints-1] = CurrentXPoints[0] - CurrentXPoints[NumOfPoints-1]
DeltaY[NumOfPoints-1] = CurrentYPoints[0] - CurrentYPoints[NumOfPoints-1]
for j in range(0,NumOfPoints): # calculats new X and Y Points
MagnitudeDelta[j] = ((DeltaX[j])**2 + (DeltaY[j])**2)**(1/2)
VelocityX[j] = speed * (DeltaX[j]/MagnitudeDelta[j])
VelocityY[j] = speed * (DeltaY[j]/MagnitudeDelta[j])
CurrentXPoints[j] += deltaT * VelocityX[j]
CurrentYPoints[j] += deltaT * VelocityY[j]
CurrentXPointsArr = np.array(CurrentXPoints)
CurrentYPointsArr = np.array(CurrentYPoints)
AllXPoints = np.vstack((AllXPoints,CurrentXPointsArr))
AllYPoints = np.vstack((AllYPoints,CurrentYPointsArr))
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
MainLines = []
SightLines= []
AllLines = MainLines + SightLines
for i in range(NumOfPoints):
line, = ax.plot([AllXPoints[j][i] for j in range(steps)], [AllYPoints[j][i] for j in range(steps)])
MainLines.append(line)
SightLines.append(line)
def UpdateMain(num, AllXPoints, AllYPoints, MainLines):
for line in MainLines:
position = MainLines.index(line)
line.set_data([AllXPoints[i][position] for i in range(num)], [AllYPoints[i][position] for i in range(num)])
def UpdateSight(num, AllXPoints, AllYPoints, SightLines):
for line in SightLines:
position = SightLines.index(line)
if position < (NumOfPoints-1):
line.set_data([AllXPoints[num][position],AllXPoints[num][position+1]],
[AllYPoints[num][position],AllYPoints[num][position+1]])
else:
line.set_data([AllXPoints[num][position],AllXPoints[num][0]],
[AllYPoints[num][position],AllYPoints[num][0]])
ani1 = animation.FuncAnimation(fig, UpdateMain,steps, fargs=[AllXPoints, AllYPoints, MainLines],
interval=1, blit=True)
ani2 = animation.FuncAnimation(fig, UpdateSight,steps, fargs=[AllXPoints, AllYPoints, SightLines],
interval=1, blit=True)
plt.show()
First, you should use only one FuncAnimation that updates all the artists.
The main problem of your code are the lines
for i in range(NumOfPoints):
line, = ax.plot([AllXPoints[j][i] for j in range(steps)], [AllYPoints[j][i] for j in range(steps)])
MainLines.append(line)
SightLines.append(line)
where you are creating one artist (line) and assign it to two different lists. If you create 2 different lines for each list, then the output is as expected.
Full working code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
%matplotlib notebook
plt.style.use('dark_background')
NumOfPoints = 6
deltaT = 0.005
duration = 50
steps = int(duration / deltaT)
speed = 0.2
num = 0
CurrentXPoints = []
CurrentYPoints = []
DeltaX = np.zeros(NumOfPoints)
DeltaY = np.zeros(NumOfPoints)
MagnitudeDelta = np.zeros(NumOfPoints)
VelocityX = np.zeros(NumOfPoints)
VelocityY = np.zeros(NumOfPoints)
def update(num, AllXPoints, AllYPoints, MainLines, SightLines):
out = []
out.append(UpdateMain(num, AllXPoints, AllYPoints, MainLines))
out.append(UpdateSight(num, AllXPoints, AllYPoints, SightLines))
return out
def UpdateMain(num, AllXPoints, AllYPoints, MainLines):
for line in MainLines:
position = MainLines.index(line)
line.set_data([AllXPoints[i][position] for i in range(num)], [AllYPoints[i][position] for i in range(num)])
return MainLines
def UpdateSight(num, AllXPoints, AllYPoints, SightLines):
for line in SightLines:
position = SightLines.index(line)
if position < (NumOfPoints-1):
line.set_data([AllXPoints[num][position],AllXPoints[num][position+1]],
[AllYPoints[num][position],AllYPoints[num][position+1]])
else:
line.set_data([AllXPoints[num][position],AllXPoints[num][0]],
[AllYPoints[num][position],AllYPoints[num][0]])
return SightLines
#Creates Initial Points by equally spacing the points around a polygon inscribed around circle
for i in range(0,NumOfPoints):
x = np.cos(((i/NumOfPoints)*2)*np.pi)
y = np.sin(((i/NumOfPoints)*2)*np.pi)
CurrentXPoints.append(x)
CurrentYPoints.append(y)
AllXPoints = np.array([CurrentXPoints])
AllYPoints = np.array([CurrentYPoints])
#Fills out both AllXPoints and AllYPoints with all points in duration
for i in range(int(steps)):
for j in range(0,NumOfPoints-1): #Calculates deltaX and deltaY at this timestep
DeltaX[j] = CurrentXPoints[j+1] - CurrentXPoints[j]
DeltaY[j] = CurrentYPoints[j+1] - CurrentYPoints[j]
DeltaX[NumOfPoints-1] = CurrentXPoints[0] - CurrentXPoints[NumOfPoints-1]
DeltaY[NumOfPoints-1] = CurrentYPoints[0] - CurrentYPoints[NumOfPoints-1]
for j in range(0,NumOfPoints): # calculats new X and Y Points
MagnitudeDelta[j] = ((DeltaX[j])**2 + (DeltaY[j])**2)**(1/2)
VelocityX[j] = speed * (DeltaX[j]/MagnitudeDelta[j])
VelocityY[j] = speed * (DeltaY[j]/MagnitudeDelta[j])
CurrentXPoints[j] += deltaT * VelocityX[j]
CurrentYPoints[j] += deltaT * VelocityY[j]
CurrentXPointsArr = np.array(CurrentXPoints)
CurrentYPointsArr = np.array(CurrentYPoints)
AllXPoints = np.vstack((AllXPoints,CurrentXPointsArr))
AllYPoints = np.vstack((AllYPoints,CurrentYPointsArr))
fig = plt.figure(figsize=(5,5))
ax = plt.axes()
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
MainLines = []
SightLines= []
AllLines = MainLines + SightLines
for i in range(NumOfPoints):
line1, = ax.plot([AllXPoints[j][i] for j in range(steps)], [AllYPoints[j][i] for j in range(steps)])
line2, = ax.plot([AllXPoints[j][i] for j in range(steps)], [AllYPoints[j][i] for j in range(steps)])
MainLines.append(line1)
SightLines.append(line2)
ani = animation.FuncAnimation(fig, update, steps, fargs=[AllXPoints, AllYPoints, MainLines, SightLines], interval=1, blit=True)
plt.show()
I want to make a 3d line plot animation with a point at the last point plotted, like a trajectory for a particule. In a case without blitting, I did it with a scatter plot and a line plot3d, updating both plots in the update function. I tried doing it in the same way, with blitting, but it throws the following error
TypeError: 'Path3DCollection' object is not iterable
My code is the following
import matplotlib.pyplot as m
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
def ranstep(start,step,stop):
numberlist = int((stop - start)/step + 1)
lista = [0]*numberlist
i = 0
while i <= numberlist:
if i == 0:
lista[i] = start
i = i + 1
if i != 0 and i < numberlist - 1:
lista[i] = lista[i - 1] + step
i = i + 1
if i != 0 and i == numberlist - 1:
lista[i] = stop
break
return(lista)
k1 = 10.0
k2 = 28.0
k3 = 8.0/3.0
czeroA = 1
czeroB = 0
czeroC = 0
step = 0.001
tfinal = 100
time = list(ranstep(0,step,tfinal))
cA = [0]*len(time)
cB = [0]*len(time)
cC = [0]*len(time)
i = 0
while i <= len(time) - 1:
if i == 0:
cA[i] = czeroA
cB[i] = czeroB
cC[i] = czeroC
i = i + 1
else:
cA[i] = cA[i - 1] + k1*(cB[i - 1] - cA[i - 1])*step
cB[i] = cB[i - 1] + (cA[i - 1]*(k2 - cC[i - 1]) - cB[i-1])*step
cC[i] = cC[i - 1] + (cA[i - 1]*cB[i-1] - k3*cC[i-1])*step
i = i + 1
fig, ax = m.subplots()
ax = fig.add_subplot(111, projection='3d')
line, = ax.plot3D([], [], [], c = 'blue', lw = 1)
line, = ax.scatter([],[],[], c = 'red', s = 30)
def init():
ax.set_xlim([-20,20])
ax.set_ylim([-20,20])
ax.set_zlim([0,50])
ax.set_xlabel('$x(t)$')
ax.set_ylabel('$y(t)$')
ax.set_zlabel('$z(t)$')
return line,
def update(frame):
line.set_data(cA[0:frame*50],cB[0:frame*50])
line.set_3d_properties(cC[0:frame*50])
line.set_data(cA[frame*500,frame*500 + 1],cB[frame*500,frame*500 + 1])
line.set_3d_properties(cC[frame*500,frame*500 + 1])
return line,
ani = animation.FuncAnimation(fig, update,interval=5, frames = len(time),init_func=init, blit=True)
m.show()
I have been using matplotlib from python to show the animation of 1D wave equation.But I got a problem of making the animation.I want the image of the wave to change with time.It means that I may need a loop to form many different pictures of the wave equation.But it seems that the time cannot be put into the wave functions ,so the images do not change at all.Please help me with the mistake that I made.
Here are the codes that I wrote:(Part of the codes comes from the book "Python Scripting for Computational Science")
from numpy import zeros,linspace,sin,pi
import matplotlib.pyplot as mpl
def I(x):
return sin(2*x*pi/L)
def f(x,t):
return sin(x*t)
def solver0(I,f,c,L,n,dt,tstop):
# f is a function of x and t, I is a function of x
x = linspace(0,L,n+1)
dx = L/float(n)
if dt <= 0:
dt = dx/float(c)
C2 = (c*dt/dx)**2
dt2 = dt*dt
up = zeros(n+1)
u = up.copy()
um = up.copy()
t = 0.0
for i in range(0,n):
u[i] = I(x[i])
for i in range(1,n-1):
um[i] = u[i]+0.5*C2*(u[i-1] - 2*u[i] + u[i+1]) + dt2*f(x[i],t)
um[0] = 0
um[n] = 0
while t <= tstop:
t_old = t
t += dt
#update all inner points:
for i in range(1,n-1):
up[i] = -um[i] + 2*u[i] + C2*(u[i-1] - 2*u[i] + u[i+1]) + dt2*f(x[i],t_old)
#insert boundary conditions:
up[0] = 0
up[n] = 0
#update data structures for next step
um = u.copy()
u = up.copy()
return u
c = 3.0 #given by myself
L = 10
n = 100
dt = 0
tstart = 0
tstop = 6
x = linspace(0,L,n+1)
t_values = linspace(tstart,tstop,31)
mpl.ion()
y = solver0(I, f, c, L, n, dt, tstop)
lines = mpl.plot(x,y)
mpl.axis([x[0], x[-1], -1.0, 1.0])
mpl.xlabel('x')
mpl.ylabel('y')
counter = 0
for t in t_values:
y = solver0(I,f,c,L,n,dt,tstop)
lines[0].set_ydata(y)
mpl.draw()
mpl.legend(['t=%4.1f' % t])
mpl.savefig('sea_%04d.png' %counter)
counter += 1
Maybe that's what you need?
y = solver0(I,f,c,L,n,dt,t)