I want to show the change of distance between two points a and b with respect to time. That's why I would like to display the segment generated by these two points. Here is a simple example of a horizontal line increasing its length with time. I can't obtain the wished plot! Any help will be more than welcome! Thank you!
from matplotlib import pyplot as plt
from matplotlib import animation
a = [None] * 2
b = [None] * 2
fig = plt.figure()
ax = plt.axes(xlim=(0, 1), ylim=(0, 1))
line, = ax.plot([], [], lw=1)
def init():
line.set_data([], [])
return line,
ax.set_xlim(0,1)
ax.set_ylim(0,1)
def animate(i):
a[0] = .5 - 0.01*i
a[1] = .5 + 0.01*i
b[0] = .5
b[1] = .5
line.set_data(a, b)
return line
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=45, interval=1, blit=True)
plt.show()
Thank you so much for your help!
Related
I'm just trying to make a live graph using matplotlib.However I couldn't find a way to draw-remove-redraw axhline(). My aim is to show a horizontal line of newest value of Y axis values and of course remove the recent horizontal line.
`
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
import time
from random import randrange
style.use("fivethirtyeight")
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
#ax1 = plt.subplot()
second = 1
xs = list()
ys = list()
ann_list = []
a = 0
ten = 10
def animate(i):
global second
global a, ten
random = randrange(ten)
ys.append(random)
xs.append(second)
second += 1
ax1.plot(xs, ys, linestyle='--', marker='o', color='b')
plt.axhline(y = ys[-1], linewidth=2, color='r', linestyle='-')
if len(xs) > 2:
plt.axhline(y = ys[-2], linewidth=2, color='r', linestyle='-').remove()
if len(ys) > 20 and len(xs) > 20:
ax1.lines.pop(0)
ys.pop(0)
xs.pop(0)
a += 1
ax1.set_xlim(a, (21 + a))
# ax1.set_ylim(0, 200)
ani = animation.FuncAnimation(fig, animate, interval=100)
plt.show()
`
expecting that to only show the newest y axis values with a horizontal line. However horizontal lines doesn't vanish away.
In your code, this:
plt.axhline(y = ys[-2], linewidth=2, color='r', linestyle='-').remove()
doesn't remove the previous axhline; it adds a new axhline at y=ys[-2] and then immediately removes it. So, it effectively does nothing.
You have to remove the same line you inserted with plt.axhline. Save the object returned by this function somewhere, and remove it when the next frame is animated.
Here's a solution with a bit of default mutable argument abuse.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
import time
from random import randrange
style.use("fivethirtyeight")
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
second = 1
xs = list()
ys = list()
ann_list = []
a = 0
ten = 10
def animate(i, prev_axhline=[]):
global second
global a, ten
random = randrange(ten)
ys.append(random)
xs.append(second)
second += 1
ax1.plot(xs, ys, linestyle='--', marker='o', color='b')
if prev_axhline:
prev_axhline.pop().remove()
prev_axhline.append(plt.axhline(y = ys[-1], linewidth=2, color='r', linestyle='-'))
if len(ys) > 20 and len(xs) > 20:
ax1.lines.pop(0)
ys.pop(0)
xs.pop(0)
a += 1
ax1.set_xlim(a, (21 + a))
# ax1.set_ylim(0, 200)
ani = animation.FuncAnimation(fig, animate, interval=100)
plt.show()
Context: I am trying to create a teaching demo tool to show how the iteration guesses through a set of points to ultimately arrive at the root of an equation
Problem: I want to animate using matplotlib to show the iterations viusally. Specifically, given a curve (see along side) and an initial guess (say 1.5 in this particular case), I want to compose an animation of 3 scenes:
draw a vertical line at x = guess (=1.5), to meet the curve at y= 9 (aka value).
Draw a line through (guess, value) with a slope 'm' (generated by my code). Delete the vertical line at this stage and keep the second line
Delete the second line after a pause
For illustration, here is the image
Additionally here is my code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
xdata, ydata = [], []
xdata2, ydata2 = [], []
ln, = plt.plot([], [])
def init():
ax.set_xlim(-3, 3)
ax.set_ylim(-10, 10)
return [ln]
def update(frame):
xdata.append(frame)
ydata.append(frame ** 3 + 4 * frame ** 2 + frame - 6)
ln.set_data(xdata, ydata)
return [ln]
def update2(frame):
xdata2.append(1.5)
ydata2.append(frame)
ln.set_data(xdata2,ydata2)
return[ln]
ani = FuncAnimation(fig, update, frames=np.linspace(-3, 3, 100),
init_func=init, blit=True)
ani2 = FuncAnimation(fig, update2, frames=np.linspace(0, 3, 100),blit=True)
plt.show()
This is a simplified version of the problem that I am trying to solve and is not part of the code that involves the calculation of the iterations etc. For now I am just trying to draw the curve in Update and post that, draw a vertical line at x=1.5.
Results: At my end, the entire animation is a set of flickering where it is apparent that matplotlib switches "thread context" very rapidly between the two FuncAnimation calls
The desired animation in your next question can be achieved in the form of drawing a curve as a base graph, adding line graphs frame by frame, and deleting that graph object when necessary.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import time
fig, ax = plt.subplots()
x = np.linspace(-3, 3, 100)
y = x ** 3 + 4 * x **2 + x -6
xx = x[74]
yy = y[74]
#print(xx,yy)
xx2 = x[65]
yy2 = y[65]
#print(xx2,yy2)
ln, = ax.plot(x, y)
ln2, = ax.plot([], [])
ln3, = ax.plot([],[])
ax.set_xlim(-3, 3)
ax.set_ylim(-10, 10)
# Move axes center and spines off
ax.spines[['top', 'right']].set_visible(False)
ax.spines[['left', 'bottom']].set_position('center')
# Show ticks axes only
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
def update(i):
ln2.set_data((xx, xx), (0, yy))
ln2.set_color('k')
if i == 2:
ln3.set_data((xx2, xx), (yy2, yy))
ln3.set_color('red')
ln3.set_width=3
if i >=3:
ln2.set_data([],[])
ln3.set_data([],[])
return ln2,ln3
ani = FuncAnimation(fig, update, frames=[0,1,2,3], interval=500, blit=True, repeat=True)
plt.show()
I am trying to plot an animation of a physics system. I've worked out the equations and it plots, but there's a second plot I don't want that keeps showing up and I can't get it to stop.
import numpy as np
from scipy import integrate
import matplotlib.pyplot as plt
from matplotlib import animation, rc
from IPython.display import HTML
# Input constants
m = 10 # mass (kg)
L = 4 # length (m)
g = 9.81 # gravity (m/s^2)
dt = 0.1 # time step size (seconds)
t_max = 40 # max sim time (seconds)
num_steps = 1 + int(t_max/dt)
theta_0 = np.pi/2 # initial angle (radians)
theta_dot_0 = 0 # initial angular velocity (rad/s)
state0 = [theta_0,theta_dot_0]
# Get timesteps
time_index = np.arange(0, t_max + dt, dt)
def derivatives(state, time_index, L=L, m=m, g=g):
theta_dot = state[1]
theta_ddot = -g*np.sin(state[0])/L
return theta_dot,theta_ddot
output = integrate.odeint(derivatives, state0, time_index)
theta = output[:,0]
theta_dot = output[:,1]
fig = plt.figure()
ax = fig.add_subplot(111, autoscale_on=True, xlim=(-2*L, 2*L), ylim=(-2*L, 2*L))
ax.set_aspect('equal')
ax.grid()
line, = ax.plot([], [], 'o-', lw=2)
time_template = 'time = %.1fs'
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
x = L*np.sin(theta)
y = -L*np.cos(theta)
def init():
# create empty object to put the points in
line.set_data([], [])
time_text.set_text('')
return line, time_text
def animate(t):
x_t = [0, x[t]]
y_t = [0, y[t]]
# add the point to the line
line.set_data(x_t, y_t)
# add the time text to plot
# time_template will be the text next to thetime
time_text.set_text(time_template % (t*dt))
return line, time_text
# we don't want the range of the steps to start at 0
# start it at one
ani = animation.FuncAnimation(fig, animate, range(1, num_steps),
interval=dt*1000, blit=True, init_func=init)
rc('animation', html='jshtml')
#ani.save('pendulum.mp4', fps=15)
ani
Here's the output:
The plot I want to get rid of is the one I circled with red. This is the entirety of my code, so it should be completely reproducible.
I tried several variations of trimming the plotting code but I wasn't able to debug why it's happening.
How can I get rid of this second plot?
A simple plt.close() before your call to ani will do the job.
Last few lines:
ani = animation.FuncAnimation(fig, animate, range(1, num_steps),
interval=dt*1000, blit=True, init_func=init)
rc('animation', html='jshtml')
#ani.save('pendulum.mp4', fps=15)
plt.close()
ani
Demo:
More info at this link.
Note this is a follow-up question of How to make an animation of a Lissajous curve;
My first idea was to edit my original question and ask for the animation, but I understand and respect SO way of operating. So the best is making another question.
I want to make an animation of the curve (where you incrementally draw it) with parametrization: x(t) = sin(3t) and y(y) = sin(4t) where t[0, 2pi].
For doing so I would add the code:
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
ln, = plt.plot([], [], 'b')
def init():
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
x.append(np.sin(4*frame))
y.append(np.sin(3*frame))
ln.set_data(x, y)
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
The problem is that with this code it doesn't draw the whole curve from scratch. What does is overdrawing it, getting overlapping.
How can I draw it from scratch (i.e. starting with white background)? I've been thinking about an if else but got nothing.
Thanks
EDIT
Let me show you the whole code:
%matplotlib notebook
import matplotlib.pyplot as plt
import math
import numpy as np
from matplotlib.animation import FuncAnimation
# set the minimum potential
rm = math.pow(2, 1 / 6)
t = np.linspace(-10, 10, 1000, endpoint = False)
x = []
y = []
for i in t: #TypeError 'int' object is not iterable
x_i = np.sin( 3 * i )
y_i = np.sin( 4 * i )
x.append(x_i)
y.append(y_i)
# set the title
plt.title('Plot sin(4t) Vs sin(3t)')
# set the labels of the graph
plt.xlabel('sin(3t)')
plt.ylabel('sin(4t)')
fig, ax = plt.subplots()
ln, = plt.plot([], [], 'b')
def init():
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
x.append(np.sin(4*frame))
y.append(np.sin(3*frame))
ln.set_data(x, y)
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
# display the graph
plt.show()
This is the image I get at the beginning (screenshot taken after approximately 1s after started running; that's why you see that funny line): https://imgur.com/a/bNoViDA. As you can see it doesn't start from scratch (i.e not from white background)
This is the plot I get at the end: https://imgur.com/a/WQHHUk9
I am seeking getting that ending point but drawing everything from scratch, without starting with the shown plot.
I would like to fill an array gradually in a loop and display the result by every iteration, so that I don’t like to declare it as ones or zeros. Is there any technique to achieve that?
Here is an example in which I want to fill xp and yp gradually. Defining xp and yp as empty falsifies the plots! Any help please?
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
a=.1
dt=.05
nx=33
ny=33
px=1
py=1
qx=1.0*px/(nx-1)
qy=1.0*py/(ny-1)
x = np.linspace(0,px,nx)
y = np.linspace(0,py,ny)
fig = plt.figure()
ax = plt.axes(xlim=(0, px), ylim=(0, py))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
ax.set_xlim(0,px)
ax.set_ylim(0,py)
X,Y = np.meshgrid(x,y)
U=-a*Y
V=a*X
x1=.5
y1=.5
xp=np.empty(nx)
yp=np.empty(ny)
xp[0]=x1
yp[0]=y1
def animate(i):
xp[i+1]=xp[i]+dt*U[yp[i]/qy,xp[i]/qx]
yp[i+1]=yp[i]+dt*V[yp[i]/qy,xp[i]/qx]
line.set_data(xp,yp)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=int(10), interval=5, blit=True)
plt.show()
Thank you!
In order to declare an array without filling it with ones or zeros/empty you may use for your 2 vectors the following:
xp = [None] * 80
yp = [None] * 80
And all now is going well!