How can I animate a set of moving point in matplotlib? - python

I'm trying to build a simulator for some BOID objects, but I'm having some trouble with matplotlib's animation module (not helped by the very obtuse documentation).
Here's the code:
from mpl_toolkits.mplot3d import Axes3D #Import axes
import matplotlib.pyplot as plt #Import plotting library
from matplotlib import animation
import numpy as np #Import numpy library
dim = 2 #Defines the dimensionality of the system
n = 6 #Number of BOIDS
tmax = 5 #Length of sim
o = np.zeros(dim) #Origin as vector
r = np.random.rand(n,dim) #Places BOIDs randomly with co-ordinates (x,y,z) from 0 to 1. Has dimensions n and dim
v = 2*np.random.rand(n,dim)-1#Sets initial velocity of each BOID from -1 to 1 in each cardinal direction
rt = np.zeros((tmax,n,dim)) #This array contains the whole system's positions at each point in time
x = np.empty(n)
y = np.empty(n)
"""rt[a]is r at t=a
rt[a][b] is r array for t=a and n=b
rt[0][a][b] is the x co-ordinate of boid n=b at t=a"""
fig = plt.figure() #Setting up a plotting figure for animation
ax = fig.add_subplot(111) #Establishes a subplot with axes
ax.grid(True,linestyle='-',color='0.75') #Sets up a grid on subplot
ax.set_xlim(-50,50)
ax.set_ylim(-50,50) #Set limits for x and y axes
for t in range (0,tmax):
for i in range (0,n):
r[i] = r[i] + v[i]
rt[t][i] = r[i]
def init():
for i in range (0,n):
x[i] = rt[0][0][i]
y[i] = rt[1][0][i]
print(i)
return x,y,
def update(j):
for i in range (0,n):
x[i] = rt[0][j][i]
y[i] = rt[1][j][i]
return x,y
anim = animation.FuncAnimation(fig, update, frames=tmax, init_func=init, interval=20, blit=True)
My problem is two-fold; Currently the code gives me this error:
x[i] = rt[0][0][i]
IndexError: index 2 is out of bounds for axis 0 with size 2
suggesting that I've mismatched the dimensions of the two array elements, but they should both just be a single number and not an array so I don't understand what's wrong.
Also, I don't really understand the need for the functions init and update. Can I not simply animate slices of rt instead?
Thanks in advance.

Related

How to update a plot by calling data from within the program?

I am writing a programme which takes a circular membrane and models its evolution under certain forces. The programme is as follows (with the details of the evolution omitted)
import numpy as np
import math
from matplotlib import pyplot as plt
xCoords = {"%s" % i: np.array([math.cos(2*math.pi*i/360),0,0,0,0,0,0,0,0,0], dtype=float)
for i in range(0, 360)} #coordinates stored in arrays whose entries correspond to time evolution
yCoords = {"%s" % i: np.array([math.sin(2*math.pi*i/360),0,0,0,0,0,0,0,0,0], dtype=float)
for i in range(0, 360)}
#fill out arrays using diff eq.
x = np.zeros((360,10), dtype = float)
y = np.zeros((360,10), dtype = float)
for i in range(0,360):
for j in range(0,10):
x[i][j] = xCoords["%s" % i][j]
y[i][j] = yCoords["%s" % i][j]
If I want to now plot the evolution of the coordinates over time, how would I do that?
I tried to plot with the following.
plt.plot(x,y)
plt.show
but it just outputs
In particular, how do I get a plot of just (x[i][j],y[i][j]) at time j?
I then tried
for j in range(0,62):
for i in range(0,360):
plt.plot(x[i][j],y[i][j])
plt.show()
but that didn't work either as it didn't give a new 'circle' everytime.
I think you are looking for something like this:
fig = plt.figure()
ax = fig.gca()
h, = ax.plot([],[])
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
for time_ind in range(0,10):
h.set_data(x[:, time_ind], y[:, time_ind])
plt.draw()
plt.pause(0.5)

How to turn this plot into an animation? I have a plot but would like to turn this into an animation somehow

I've been struggling for the last few nights how to turn my waves in the graph here into some sort of animation after each time step or after each x step. How can I modify and write the code so that my program animations each time step of the wave somehow. I'm very new to python and programming and never used the animation part of matplotlib before.
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
T = 20.0 # t
X = 10.0 # x
n = 300
m = 300
#positions of time and space, xp= x position accross grid, tp = t position accross grid
tp = T / (n - 1)
xp = X / (m - 1)
C = 0.5
U = np.zeros((n, m))
# Set the initial values for each x position
for i in range(0, n):
U[i, 0] = np.exp(- (i * xp - 2.5) ** 2)
for i in range(1, n): # across x
for j in range(1, m): # across t
U[i, j] = (xp * U[i, j - 1] + C * tp * U[i - 1, j]) / (xp + C * tp) # equation for new distribution value
fig = plt.figure(1)
#gives time position instead of time step
tn = np.zeros((m, 1))
for j in range(0, m):
tn[j] = j * tp
#gives x position instead of x step
xn = np.zeros((n, 1))
for j in range(0, n):
xn[j] = j * xp
for i in [0, 50, 100, 150, 200, 250, 299 ]: # selects which position of time
label = 't = ' + str(tn[i][0]) # lables legend
subfig = fig.add_subplot(1, 1, 1)
subfig.plot(xn, U[:, i], label=label)
subfig.legend()
subfig.grid(True)
print(tn)
# Save Image
plt.xlabel('x: position')
plt.ylabel('u: u(x, t)')
plt.title(r'$\frac{\partial u}{\partial t} + C \frac{\partial u}{\partial x} = 0$')
plt.savefig('transport-equation')`
plt is a tricky package to get used to. In general, graphics is not an easy thing to manage and plt tries to be as simple as possible, while also providing max flexibility. In general, when you use plt, there are a lot of global variables that are automatically generated, updated, cleaned, and handled for you. When you use things "plt.xlabel", you are really applying this to a particular axis in a particular figure, which are automatically determined for you. If you want more control in plt and/or you want to do something complicated like an animation, then you need to make your globals explicit.
#Create xn and U.
import matplotlib.pyplot as plt
figure = plt.figure() #This is the window that pops open.
axis = figure.add_subplot(1,1,1) #This is a graph/grid.
axis.grid(True) #Add a grid to the axis.
label = 't = ' + str(tn[i][0])
plots = axis.plot(xn,U[:,0],label=label) #These are the plots of data with X and Y.
An X and Y arrays can generate more than one plot at a time, hence, plots is a list with one item in it. To get a sense of how this works, you can literally manipulate the data in real time and watch it change in the plt window.
figure.show()
plots[0].set_ydata(U[:,10])
plots[0].set_ydata(U[:,-1])
# Close the window when done.
To make an animation we need to tell plt to apply an animation to a given figure. plt will then attempt to update the figure and everything that has been attached to it. If you already have the window open, the animation will still get applied and work, but you will also keep whatever was originally plotting in the figure (so we should close the window and re-code the animation). plt does NOT follow convention that executing one line at a time is the same as executing all the lines at once. plt behaves differently before and after a window is opened.
#Create xn and U.
import matplotlib.pyplot as plt
figure = plt.figure()
axis = figure.add_subplot(1,1,1)
axis.grid(True)
label = 't = ' + str(tn[i][0])
plots = axis.plot(xn,U[:,0],label=label)
def animate_function(frame):
frame %= 300 #frame is an integer that counts from 0.
plots[0].set_ydata(U[:,frame]) #Change which globals you want.
return plots #Return the changed items so plt knows.
#Tell plt to apply this animation function to your figure.
#Tell plt to wait approximately 10ms per frame.
#Tell plt to only update pixels that actually change (called blit).
#Save to a global variable so plt doesn't get upset at you.
ani = animation.FuncAnimation(figure,animate_function,interval=10,blit=True)
#Now open the window and show the figure.
figure.show()

Python FuncAnimation is not updating the frame when I am trying to update 4 plots in a subplot

I am a newbie and trying to get the basics of Python right. I am trying to create an animation with 4 plots using matplotlib.pyplot.subplots. Each plot has same mean but different standard deviation. Here's my code:
import numpy as np
import matplotlib as mlp
import matplotlib.animation as animation
Test data
n = 100
mn = 0
stdv = [1,2,3,4]
x = [np.random.normal(loc= mn, scale = stdv[0], size = n ),
np.random.normal(loc= mn, scale = stdv[1], size = n ),
np.random.normal(loc= mn, scale = stdv[2], size = n ),
np.random.normal(loc= mn, scale = stdv[3], size = n )]
Animation update function
def anim_norm(i):
if (i == n):
b.event_source.stop()
plt.cla()
ax = [ax1,ax2,ax3,ax4]
for k in range((len(ax)+1)):
ax[k].set_title('S.D. = {}, n = {}'.format(stdv[k],i))
ax[k].set_xlabel('Value')
ax[k].set_ylabel('Frequency')
ax[k].hist(x[k][:i])
Running the animation
fig,((ax1,ax2),(ax3,ax4)) = plt.subplots(2,2, sharex = True)
b = animation.FuncAnimation(fig,anim_norm, interval = 300)
All I see is the plots with xlabel, ylabel, and title and the first frame. I would appreciate any guidance. Also, do I need to increment (i - the frame count) or FuncAnimation does it automatically?
Thank you!

How do I plot a function with multiple different values for constants?

I am trying to plot this function: y(x) = (e^-ax)cos(x)
For x value spanning the interval (0,4pi) and 'a' ranging from 0 to 1 in steps of 0.25. I have managed to successfully plot this for a=0.
However, I am wondering if I can write some code that will allow me to plot it for the range of 'a' values, instead of having to rewrite the code for each different 'a' value.
Here is the code I have: (Note y = cos(x) as this is for a = 0)
from numpy import *
import pylab as p
# function to plot ( a = 0 )
x = linspace(0, 4*pi, 100)
y = cos(x)
#plot the function
p.plot(x,y,'o')
# axis annotation
p.xlabel('x-variable')
p.ylabel('y=(e**-ax)cosx')
# graph title
p.title('Plot of function')
#set axis range
p.axis([-0.5, 4*pi, -1.3, 1.3])
# turn grid on
p.grid(True)
p.show()
Thank you!
assuming that you want everything on the same plot...
from numpy import linspace, pi, cos, exp
import pylab as p
for a in p.frange(xini=0, xfin=1, delta=0.25):
x = linspace(0, 4*pi, 100)
y = exp(-a*x)*cos(x)
p.plot(x,y,'o')
# axis annotation
p.xlabel('x-variable')
p.ylabel('y=(e**-ax)cosx')
# graph title
p.title('Plot of function')
#set axis range
p.axis([-0.5, 4*pi, -1.3, 1.3])
# turn grid on
p.grid(True)
p.show()

Can i put a color changer in a loop?

So basically what i'm wondering, is at the bottom of my code when i plot the graph of my trials, is there a way to run a color generator through there? Or more explicitly put, could i make a list of warm colors, and put that into my plot function, where it runs through each color in a list as the loop runs through, and therefore my plot would only consist of warm colors?
from numpy import *
from pylab import show,plot
from scipy.special import erfinv
n = 366 #number of days
ntrials = 5000
u = random.rand(ntrials)
v = sqrt(2.)*erfinv(2.*u-1.)
mu = 0
sigma = .05
investment = 1000.
data = empty((ntrials,n))
data[:,0] = investment
for t in range(n-1):
u = random.rand(ntrials)
v = sqrt(2.)*erfinv(2.*u-1.)
epsilon = v
data[:,t+1] = (1. + mu +sigma*epsilon)*data[:,t]
data2 = data.sum(axis=0)
woo = data2[-1]/ntrials
data3 = data2[-1]
x = linspace(0,n,n)
for t in range(n):
plot(x,data[t,:])
show()
It sounds like you just want something like this?
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
# Generate data...
nx, nsteps = 100, 20
x = np.linspace(0, 1, nx)
data = np.random.random((nx, nsteps)) - 0.5
data = data.cumsum(axis=0)
data = data.cumsum(axis=1)
# Plot
cmap = mpl.cm.autumn
for i, y in enumerate(data.T):
plt.plot(x, y, color=cmap(i / float(nsteps)))
plt.show()
The key is that calling a matplotlib colormap instance with a value between 0 and 1 will return a color (where 0 is the lowest color in the colormap and 1 is the highest).
For a list of available colormaps, see here. You can access the reversed version of any of these with name_r (e.g. the reversed version of mpl.cm.autumn is mpl.cm.autumn_r).

Categories