I have the following code which creates a graph animation. The graph should start from 0, but the 1st interval graph isn't coming.
Below is the code:
import matplotlib.pylab as plt
import matplotlib.animation as animation
import numpy as np
fig, ax = plt.subplots()
left = -1
right = 2*np.pi - 1
def animate(i):
global left, right
left = left + 1
right = right + 1
x = np.linspace(left, right, 50)
y = np.cos(x)
ax.cla()
ax.set_xlim(left, right)
ax.plot(x, y, lw=2)
ani = animation.FuncAnimation(fig, animate, interval = 1000)
plt.show()
For the 1st interval [0, 2π] the graph isn't coming.
What's the mistake?
I changed a little bit your code:
first of all I plot the first frame outside the animate function and I generate a line object from it
then I update the line data within animate function
I suggest to use i counter (which starts from 0 and increases by 1 in each frame) to update your data, in place of calling global variables and change them
Complete Code
import matplotlib.pylab as plt
import matplotlib.animation as animation
import numpy as np
fig, ax = plt.subplots()
left = 0
right = 2*np.pi
x = np.linspace(left, right, 50)
y = np.cos(x)
line, = ax.plot(x, y)
ax.set_xlim(left, right)
def animate(i):
x = np.linspace(left + i, right + i, 50)
y = np.cos(x)
line.set_data(x, y)
ax.set_xlim(left + i, right + i)
return line,
ani = animation.FuncAnimation(fig = fig, func = animate, interval = 1000)
plt.show()
Related
basically I am trying to have a sine wave be displayed by matplotlib and then when a certain x value is reached (block_start_pos) for the animation speed to change (slow down in this case). I understand that FuncAnimation repeatedly calls update_plot based on the given parameters but I was wondering if there was a way to change the interval mid animation. My code (mostly taken from a youtube video) is shown below. Thanks!
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import tkinter as tk
x = np.arange(0, 10*np.pi, 0.01)
index_of_refraction = 10
index_of_refraction_lst = [1, 200, 3, 4, 5]
medium = 20*index_of_refraction
w = 1
y = np.cos(w*x)
fig = plt.figure()
ax = plt.subplot(1, 1, 1)
data_skip = 50
block_start_pos = 6*np.pi
def init_func():
ax.clear()
plt.xlabel('pi')
plt.ylabel('sin(pi)')
plt.xlim((x[0], x[-1]))
plt.ylim((-1, 1))
def update_plot(i):
ax.plot(x[i:i+data_skip], y[i:i+data_skip], color='k')
ax.scatter(x[i], y[i], marker='o', color='r')
return medium_test(i)
def medium_test(i):
if x[i] > block_start_pos:
index_of_refraction = index_of_refraction_lst[1]
medium = 20*index_of_refraction
medium = 20*index_of_refraction
anim = FuncAnimation(fig,
update_plot,
frames=np.arange(0, len(x), data_skip),
init_func=init_func,
interval=medium)
plt.show()
# anim.save('sine.mp4', dpi=150, fps = 30, writer='ffmpeg')```
I am very new to animating in python so please bear with me.
So I am trying to make this Lissajous curve animate like the one on this website
I do have code of the lissajous curve stationary if needed. I thought by changing the pi/2 (in the code it's f) to be smaller and bigger would replicate it but the graph doesn't appear. Thank you in advance.
Attempt:
# Import our modules
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
a= 1
A = 1
B = 1
b = 3
c = 1
D = 1
fig = plt.figure()
f=3.14/2
while f > -3.14/2:
f-=1
xdata, ydata = [], []
ax = plt.gca()
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
t = 0.1*i
x = A*np.sin(a*t+f) + c
y = B*np.sin(b*t) + D
xdata.append(x)
ydata.append(y)
line.set_data(xdata, ydata)
# ax.set_facecolor('xkcd:black')
return line,
anim = FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)
anim.save('abclogo.gif', writer='pillow')
You have to include the axes limits
ax = plt.gca()
ax.set_xlim(0,2)
ax.set_ylim(0,2)
line, = ax.plot([], [], lw=2)
Alternately, and slightly more efficient would be to not use append inside the animate function by doing the following:
# Import our modules
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
a= 1
A = 1
B = 1
b = 3
c = 1
D = 1
f=3.14/2
while f > -3.14/2:
f-=1
seq=np.arange(0,200,1)
x = A*np.sin(a*0.1*seq+f) + c
y = B*np.sin(b*0.1*seq) + D
fig, ax = plt.subplots()
line, = ax.plot(x, y, color='k')
def animate(i):
line.set_data(x[:i], y[:i])
return line,
anim = FuncAnimation(fig, animate, frames=len(x),interval=25, blit=True)
anim.save('abclogo.gif', writer='imagemagick')
plt.show()
Edit 2:
FuncAnimation doesn't offer a lot of control. For e.g. you won't be able to access axes elements and modify them. You can achieve better control by making use of for loop as shown here:
import numpy as np
import matplotlib.pyplot as plt
import math
###initializing the parameters##################
M=1
N=2
########setup the plot################
fig, ax = plt.subplots()
t = np.arange(0, 1000, 1)
x = np.sin(M*0.1*t)
y = np.sin(N*0.1*t+math.pi/2.0)
ax.set_xlim(-1.25,1.25)
ax.set_ylim(-1.25,1.25)
##################
for i in t:
phi=np.arange(0,10*math.pi,math.pi/50.)
#phase shifting to give the impression of rotation
y = np.sin(N*0.1*t+phi[i])
line, = ax.plot(x[:i],y[:i],c='black')
plt.pause(0.01)
#remove the track
line.remove()
del line
The animation is shown here
I have a dataframe that I want to animate (line chart) using matplotlib. My x and y values:
here x = df.index and y = df['Likes']
x y
0 200000
1 50000
2 1000000
.so on.. ....
Code I tried:
from matplotlib import pyplot as plt
from matplotlib import animation
import pandas as pd
df = pd.read_csv("C:\\Users\\usr\\Documents\\Sublime\\return_to_windows\\Files\\cod2019.txt", sep='\t')
fig = plt.figure()
ax = plt.axes(xlim=(0, 18), ylim=(6514, 209124))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
line.set_data(df.index[i], df['Likes'][i])
return line,
anim = animation.FuncAnimation(fig, animate, frames=len(df['Likes']), init_func=init, interval=300, blit=True)
plt.show()
I have tried this, but it is showing blank output with no error message. I am using python 3.83, windows machine. Can I do this using numpy? Almost all of the examples used numpy data in FuncAnimation.
I have solved it myself, I have used code of "vkakerbeck" from github as a guide to add more data points:
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
df = pd.read_csv("C:\\Users\\usr\\Documents\\Sublime\\return_to_windows\\Files\\cod2019.txt", sep='\t')
dg = df['Likes']
x_data = []
y_data = []
fig, ax = plt.subplots()
ax.set_xlim(0, len(dg))
ax.set_ylim(0, dg.max() * 1.04) # multiplied with 1.04 to add some gap in y-axis
line, = ax.plot(0, 0)
This part is for formatting
ax.set_xlabel('Part No')
ax.set_ylabel('Number of Likes')
ax.set_title('Likes in Call of Duty 2019')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
fig = plt.gcf()
fig.set_size_inches(12.8, 7.2) # 720p output
I have used this from that guide to add more data points to make the animation less jumpy:
x = np.array(dg.index)
y = np.array(dg)
def augment(xold, yold, numsteps):
xnew = []
ynew = []
for i in range(len(xold) - 1):
difX = xold[i + 1] - xold[i]
stepsX = difX / numsteps
difY = yold[i + 1] - yold[i]
stepsY = difY / numsteps
for s in range(numsteps):
xnew = np.append(xnew, xold[i] + s * stepsX)
ynew = np.append(ynew, yold[i] + s * stepsY)
return xnew, ynew
XN, YN = augment(x, y, 3)
augmented = pd.DataFrame(YN, XN)
ylikes = augmented[0].reset_index() # Index reset to avoid key error
Main Function:
def animation_frame(i):
x_data.append(augmented.index[i])
y_data.append(ylikes[0][i])
line.set_xdata(x_data)
line.set_ydata(y_data)
return line,
plt.cla()
plt.tight_layout()
anima = animation.FuncAnimation(fig, func=animation_frame, frames=len(augmented), interval=80)
plt.show()
Export as mp4
Writer = animation.writers['ffmpeg']
writer = Writer(fps=15, bitrate=1000)
anima.save('lines3.mp4', writer=writer)
I want to create an animation showing a diver jumps into water.
By the given parameters of original height of diver from the water, h and his mass, m, I defined a procedure in Python to calculate the moment he touches the water, Tc .
Knowing that he jumps vertically, X axis is fixed, and
Y axis obeys equation (1/2)gt^2 + h (g is gravitational constant)
How do I plot a graph while time t is in range(Tc), X and Y axis shows the projection the diver? (x is fixed and y depends on time t)
In the graphic window we are supposed to see a dot that 'jumps' from certain height vertically downwards, without seeing the line/trace of projection.
Here is part of my work. I don't know where to introduce Tc in the procedure:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.empty(n) ; x.fill(1) # the vertical position is fixed on x-axis
y = 0.5*g*i^2 + h # the equation of diver's displacement on y axis
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
plt.show()
Edit:
Here is the whole program. I applied and modified the suggestion given by #Mike Muller, but it didn't work. I don’t understand where it goes wrong. Hope you can clarify my doubts.
# -*- coding: utf-8 -*-
from math import *
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
def Plongeon():
h = input("height = ")
h = float(h)
m = input(" mass = ")
m = float(m)
global g
g = 9.8
g = float(g)
global Tc #calculate air time, Tc
Tc = sqrt(2*h/g)
Tc = round(Tc,2)
print Tc
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, h+1)) #ymax : initial height+1
line, = ax.plot([], [], ' o', lw=2)
Tc = int(Tc+1) #make Tc an integer to be used later in def get_y()
xs = [1] # the vertical position is fixed on x-axis
ys = [h, h]
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(y):
ys[-1] = y
line.set_data(xs, ys)
return line,
def get_y():
for step in range(Tc):
t = step / 100.0
y = -0.5*g*t**2 + h # the equation of diver's displacement on y axis
yield y
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, frames=get_y, interval=100)
plt.show()
Plongeon()
Answer based on original question
You need to use a generator to produce your y data. This works:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], ' o', lw=2)
g = 9.81
h = 2
tc = 200
xs = [1] # the vertical position is fixed on x-axis
ys = [h, h]
# animation function. This is called sequentially
def animate(y):
ys[-1] = y
line.set_data(xs, ys)
return line,
def get_y():
for step in range(tc):
t = step / 100.0
y = -0.5*g*t**2 + h # the equation of diver's displacement on y axis
yield y
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, frames=get_y, interval=100)
plt.show()
Integrated answer
This should work:
# -*- coding: utf-8 -*-
from math import *
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
def Plongeon():
h = float(input("height = "))
g = 9.81
#calculate air time, Tc
Tc = sqrt(2 * h / g)
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, h+1)) #ymax : initial height+1
line, = ax.plot([], [], ' o', lw=2)
step = 0.01 # animation step
xs = [1] # the vertical position is fixed on x-axis
ys = [h]
# animation function. This is called sequentially
def animate(y):
ys[-1] = y
line.set_data(xs, ys)
return line,
def get_y():
t = 0
while t <= Tc:
y = -0.5 * g * t**2 + h # the equation of diver's displacement on y axis
yield y
t += step
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, frames=get_y, interval=100)
plt.show()
Plongeon()
I removed unneeded lines. No need for global. Also mass has never been used anywhere in the program.
This is the most important part:
def get_y():
t = 0
while t <= Tc:
y = -0.5 * g * t**2 + h
yield y
t += step
You need to advance your time by an increment.
I have a three-variable function myfunc that is generated inside three for loops. I want to draw a contour plot of y vs x and animate this for different times t. However, I've looked at the various matplotlib examples on the webpage, and am still unsure of how to do this.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import animation
def myfunc(x,y,t):
w = 0.5*x + y + 4*np.sin(1.8*t)
return w
xlist = np.linspace(0,10,10)
ylist = np.linspace(-1,1,10)
tlist = np.linspace(0,50,50)
plt.figure()
for t in tlist:
for x in xlist:
for y in ylist:
w = myfunc(x,y,t)
w_vec = np.array(w)
w_contour = w_vec.reshape((xlist.size, ylist.size))
w_plot = plt.contourf(ylist,xlist,w_contour)
plt.xlabel('x', fontsize=16)
plt.ylabel('y', fontsize=16)
plt.show()
Edit: I quite like the look of dynamic_image2.py in this tutorial. This seems to get things moving, but the axes are wrong:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
def f(x,y,t):
return 0.5*x + np.sin(y) + 4*np.sin(1.8*t)
x = np.linspace(0, 10, 10)
y = np.linspace(-1, 1, 10).reshape(-1, 1)
tlist = np.linspace(0,50,50)
ims = []
for t in tlist:
x += np.pi / 15.0
y += np.pi / 20.0
im = plt.imshow(f(x,y,t))
ims.append([im])
ani = animation.ArtistAnimation(fig, ims, interval=20, blit=True,
repeat_delay=1000)
plt.show()