FuncAnimation with multiple particles - python

Below is a model that I have been working on for a few weeks now, slowly adding more complexity as I learn how to code (coding newbie). If it is not clear, I am trying to create a model of particles of 2 different densities that settle according to stokes settling velocity (as a function of concentration). I am having trouble getting the animation to work with the second particle (working code with one animated particle at the bottom). I have broken out the variables for the two different particles in an attempt to debug the code, but have not had any luck determining what I am doing wrong.
Any help would be greatly appreciated!
import numpy as np
import matplotlib.pyplot as plt
from pylab import *
from matplotlib.animation import FuncAnimation
import random
import pdb
from scipy import spatial
from scipy.spatial import KDTree
n = 100
n2 = 50
sigma = 0.01
sigma2 = 0.01
pp = 2.56 # pp = particle density (Sphene=3.53) #(Feldspar=2.56)
#(g/cm^3)
pp2 = 3.53
pf = 2.7 # pf = fluid density(g/cm^3)
pf2 = 2.7
g = 9.8 # g = gravity (m/s^2)
g2 = 9.8
r = 0.003 # r = radius of sphere (meter)
r2 = 0.0002
mu = 0.53 # mu = dynamic viscosity of fluid (log10Poise)
mu2 = 0.53
rp = 0.01 #radius around particle to check for nearest neighbor
rp2 = 0.001
dt = 0.008
dt2 = 0.008
fig, ax = plt.subplots()
az = plt.axes(xlim=(-.5, .5), ylim=(-1, 0))
xdata, ydata = [0.0], [0.0]
xdata2, ydata2 = [0.0], [0.0]
ln, = plt.plot([], [], marker= 'o',
markerfacecolor='r',markeredgecolor='k', linestyle='None',
animated=True)
ln2, = plt.plot([], [], marker= 's',
markerfacecolor='b',markeredgecolor='k', linestyle='None',
animated=True)
#pdb.set_trace()
def v_stokes(pp,pf,g,r,mu):
top=2*(pp-pf)*g*(r**2)
bottom=9*mu
ws=top/bottom
return ws
def v_stokes2(pp2,pf2,g2,r2,mu2):
top2=2*(pp2-pf2)*g2*(r2**2)
bottom2=9*mu2
ws2=top2/bottom2
return ws2
def init():
ax.set_xlim( -2, 2)
ax.set_ylim(-10, 0)
return ln, ln2,
def concentration(xdata, ydata, rp):
coords = list(zip(xdata, ydata))
tree = spatial.KDTree(coords)
test = np.column_stack([xdata, ydata])
nnl = tree.query_ball_point(test, rp) #nearest neighbors as a list
#(had tree in here before test but shape was wrong)
#pdb.set.trace()
nnt = np.zeros(len(nnl)) #nearest neighbors total
for i in range(len(nnt)):
nnt[i] = len(nnl[i])
return nnt
def concentration2(xdata2, ydata2, rp2):
coords2 = list(zip(xdata2, ydata2))
tree2 = spatial.KDTree(coords2)
test2 = np.column_stack([xdata2, ydata2])
nnl2 = tree2.query_ball_point(test2, rp2)
nnt2 = np.zeros(len(nnl2)) #nearest neighbors total
for i in range(len(nnt2)):
nnt2[i] = len(nnl2[i])
return nnt2
#y0 = []
#y1 = []
#y2 = []
#y3 = []
#y4 = []
def update(frame):
global xdata
global ydata
global concentration, v_stokes, pp, pf, g, r, mu, rp, dt, n, sigma
xdata = xdata + np.random.normal(0, sigma, n)
wss = v_stokes(pp,pf,g,r,mu)
if frame == 0.0:
ydata = np.zeros(len(xdata)) #makes the ydata length = xdata at
#time 0 print(ydata)
rp = 0.003
if frame > 10:
rp = 0.008
cp = concentration(xdata, ydata, rp)
if np.any(cp == 1):
cp = cp-1
if frame > 0.0:
#y0.append(ydata)
#y1.append(wss)
#y2.append(cp)
#y3.append(dt)
#y4.append(xdata)
ydata = ydata + (wss*(1-cp)**3) - dt # [0]
for v in ydata:
if v < -1.001:
ydata = -1
ln.set_data(xdata, ydata)
return ln,
def update2(frame2):
global xdata2
global ydata2
global concentration2, v_stokes2, pp2, pf2, g2, r2, mu2, rp2, dt2,
n2, sigma2
xdata2 = xdata2 + np.random.normal(0, sigma2, n2)
wss2 = v_stokes2(pp2,pf2,g2,r2,mu2)
if frame2 == 0.0:
ydata2 = np.zeros(len(xdata2)) #makes the ydata length = xdata
#at time 0 print(ydata)
rp2 = 0.003
if frame2 > 10:
rp2 = 0.008
cp2 = concentration2(xdata2, ydata2, rp2)
if np.any(cp2 == 1):
cp2 = cp2-1
if frame2 > 0.0:
#y5.append(ydata2)
#y6.append(wss2)
#y7.append(cp2)
#y8.append(dt2)
#y9.append(xdata2)
ydata2 = ydata2 + (wss2*(1-cp2)**3) - dt2 # [0]
for v2 in ydata2:
if v2 < -1.001:
ydata2 = -1
ln2.set_data(xdata2, ydata2)
return ln2,
def update_all(i):
l1 = update(i)
l2 = update2(i)
return l1, l2,
ani = FuncAnimation(fig, update_all, frames=range(0,200),
init_func=init, blit=True, interval=100, repeat =
False)
# change frames=range(0:1000) to change the number of frames
plt.show()
Below is the original working code with one animated particle:
import numpy as np
import matplotlib.pyplot as plt
from pylab import *
from matplotlib.animation import FuncAnimation
import random
import pdb
from scipy import spatial
from scipy.spatial import KDTree
n=100
sigma= 0.01
#m = np.random.uniform(n)
pp = 2.56 # pp = particle density (Sphene=3.53) #(Feldspar=2.56)
#(g/cm^3)
pf = 2.7 # pf = fluid density(g/cm^3)
g = 9.8 # g = gravity (m/s^2)
r = 0.003 # r = radius of sphere (meter)
mu = 0.53 # mu = dynamic viscosity of fluid (log10Poise)
rp = 0.01 #radius around particle to check for nearest neighbor
dt =0.008
fig, ax = plt.subplots()
az = plt.axes(xlim=(-.5, .5), ylim=(-1, 0))
xdata, ydata = [0.0], [0.0]
ln, = plt.plot([], [], marker= 'o',
markerfacecolor='r',markeredgecolor='k', linestyle='None',
animated=True)
#pdb.set_trace()
def v_stokes(pp,pf,g,r,mu):
top=2*(pp-pf)*g*(r**2)
bottom=9*mu
ws=top/bottom
return ws
def init():
ax.set_xlim( -2, 2)
ax.set_ylim(-10, 0)
return ln,
def concentration(xdata, ydata, rp):
coords = list(zip(xdata, ydata))
tree = spatial.KDTree(coords)
test = np.column_stack([xdata, ydata])
nnl = tree.query_ball_point(test, rp) #nearest neighbors as a list
#(had tree in here before test but shape was wrong)
#pdb.set.trace()
nnt = np.zeros(len(nnl)) #nearest neighbors total
for i in range(len(nnt)):
nnt[i] = len(nnl[i])
return nnt
y0 = []
y1 = []
y2 = []
y3 = []
y4 = []
def update(frame):
global xdata
global ydata
global concentration, v_stokes, pp, pf, g, r, mu, rp, dt, n
xdata = xdata + np.random.normal(0, sigma, n)
wss = v_stokes(pp,pf,g,r,mu)
#print(wss)
if frame == 0.0:
ydata = np.zeros(len(xdata)) #makes the ydata length = xdata at
#time 0 print(ydata)
rp = 0.003
if frame > 10:
rp = 0.008
if frame > 30:
rp = 0.01
if frame > 50: #notice that the particles move up instead of just
#slowing down
rp = 0.013
cp = concentration(xdata, ydata, rp)
#print(cp)
if np.any(cp == 1):
cp = cp-1
#print(xdata)
print(cp)
if frame > 0.0:
y0.append(ydata)
y1.append(wss)
y2.append(cp)
y3.append(dt)
y4.append(xdata)
ydata = ydata + (wss*(1-cp)**3) - dt # [0]
for v in ydata:
if v < -1.001:
ydata = -1
#if np.all(ydata) > 0:
#print(ydata)
#print(frame)
#print(ydata[0:5])
#ydata = ydata + (wss*(1-cp))
ln.set_data(xdata, ydata)
return ln,
#print(test)
ani = FuncAnimation(fig, update, frames=range(0,200),
init_func=init, blit=True, interval=100, repeat =
False)
# change frames=range(0:1000) to change the number of frames
plt.show()

The matplotlib.animation.FuncAnimation(fig, func, ...) expects as its second argument a callable (e.g. a function) to update the plot.
func : callable
The function to call at each frame. The first argument will be the next value in frames. Any additional positional arguments can be supplied via the fargs parameter.
If you have two functions to update, you would need to merge them into one,
def update_all(i):
l1 = update(i)
l2 = update2(i)
return l1,l2
ani = FuncAnimation(fig, update_all, frames=range(0,200), init_func=init, ...)
Mind that you need to define the plots in the same manner as usual, ln, = plt.plot and that you need to return the line object itself in the two updating functions.
Complete running code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from scipy import spatial
n=100
sigma= 0.01
pp = 2.56 # pp = particle density (Sphene=3.53) #(Feldspar=2.56)
#(g/cm^3)
pp2 = 3.53
pf = 2.7 # pf = fluid density(g/cm^3)
pf2 = 2.7
g = 9.8 # g = gravity (m/s^2)
g2 = 9.8
r = 0.003 # r = radius of sphere (meter)
r2 = 0.0002
mu = 0.53 # mu = dynamic viscosity of fluid (log10Poise)
mu2 = 0.53
rp = 0.01 #radius around particle to check for nearest neighbor
rp2 = 0.001
dt = 0.008
dt2 = 0.008
fig, ax = plt.subplots()
az = plt.axes(xlim=(-.5, .5), ylim=(-1, 0))
xdata, ydata = [0.0], [0.0]
xdata2, ydata2 = [0.0], [0.0]
ln, = plt.plot([], [], marker= 'o',
markerfacecolor='r',markeredgecolor='k', linestyle='None',
animated=True)
ln2, = plt.plot([], [], marker= 's',
markerfacecolor='b',markeredgecolor='k', linestyle='None',
animated=True)
#pdb.set_trace()
def v_stokes(pp,pf,g,r,mu):
top=2*(pp-pf)*g*(r**2)
bottom=9*mu
ws=top/bottom
return ws
def v_stokes2(pp2,pf2,g2,r2,mu2):
top2=2*(pp2-pf2)*g2*(r2**2)
bottom2=9*mu2
ws2=top2/bottom2
return ws2
def init():
ax.set_xlim( -2, 2)
ax.set_ylim(-10, 0)
return ln, ln2
def concentration(xdata, ydata, rp):
coords = list(zip(xdata, ydata))
tree = spatial.KDTree(coords)
test = np.column_stack([xdata, ydata])
nnl = tree.query_ball_point(test, rp)
nnt = np.zeros(len(nnl)) #nearest neighbors total
for i in range(len(nnt)):
nnt[i] = len(nnl[i])
return nnt
def concentration2(xdata2, ydata2, rp2):
coords2 = list(zip(xdata2, ydata2))
tree2 = spatial.KDTree(coords2)
test2 = np.column_stack([xdata2, ydata2])
nnl2 = tree2.query_ball_point(test2, rp2)
nnt2 = np.zeros(len(nnl2)) #nearest neighbors total
for i in range(len(nnt2)):
nnt2[i] = len(nnl2[i])
return nnt2
y0 = [];y1 = [];y2 = [];y3 = [];y4 = []
def update(frame):
global xdata
global ydata
global concentration, v_stokes, pp, pf, g, r, mu, rp, dt, n
xdata = xdata + np.random.normal(0, sigma, n)
wss = v_stokes(pp,pf,g,r,mu)
if frame == 0.0:
ydata = np.zeros(len(xdata)) #makes the ydata length = xdata at
#time 0 print(ydata)
rp = 0.003
if frame > 10:
rp = 0.008
if frame > 30:
rp = 0.01
if frame > 50: #notice that the particles move up instead of just
#slowing down
rp = 0.013
cp = concentration(xdata, ydata, rp)
if np.any(cp == 1):
cp = cp-1
#print(cp)
if frame > 0.0:
y0.append(ydata)
y1.append(wss)
y2.append(cp)
y3.append(dt)
y4.append(xdata)
ydata = ydata + (wss*(1-cp)**3) - dt # [0]
for j,v in enumerate(ydata):
if v < -1.001:
ydata[j] = -1
ln.set_data(xdata, ydata)
return ln
def update2(frame2):
global xdata2
global ydata2
global concentration2, v_stokes, pp2, pf2, g2, r2, mu2, rp2, dt2, n
xdata2 = xdata2 + np.random.normal(0, sigma, n)
wss2 = v_stokes2(pp2,pf2,g2,r2,mu2)
if frame2 == 0.0:
ydata2 = np.zeros(len(xdata2)) #makes the ydata length = xdata
#at time 0 print(ydata)
rp2 = 0.003
if frame2 > 10:
rp2 = 0.008
if frame2 > 30:
rp2 = 0.01
if frame2 > 50: #notice that the particles move up instead of just
#slowing down
rp2 = 0.013
cp2 = concentration2(xdata2, ydata2, rp2)
if np.any(cp2 == 1):
cp2 = cp2-1
if frame2 > 0.0:
y0.append(ydata2)
y1.append(wss2)
y2.append(cp2)
y3.append(dt2)
y4.append(xdata2)
ydata2 = ydata2 + (wss2*(1-cp2)**3) - dt2 # [0]
for j,v in enumerate(ydata2):
if v < -1.001:
ydata2[j] = -1
ln2.set_data(xdata2, ydata2)
return ln2
def update_all(i):
l1 = update(i)
l2 = update2(i)
return l1,l2
ani = FuncAnimation(fig, update_all, frames=range(0,200),
init_func=init, blit=True, interval=100, repeat = False)
plt.show()
Since the code seems mostly redundant for the two particle classes, I would suggest to simplify it by putting it into a class.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from scipy import spatial
n=100
sigma= 0.01
pp = 2.56 # pp = particle density (Sphene=3.53) #(Feldspar=2.56)
#(g/cm^3)
pp2 = 3.53
pf = 2.7 # pf = fluid density(g/cm^3)
pf2 = 2.7
g = 9.8 # g = gravity (m/s^2)
g2 = 9.8
r = 0.003 # r = radius of sphere (meter)
r2 = 0.0002
mu = 0.53 # mu = dynamic viscosity of fluid (log10Poise)
mu2 = 0.53
rp = 0.01 #radius around particle to check for nearest neighbor
rp2 = 0.001
dt = 0.008
dt2 = 0.008
class Particles():
def __init__(self,ax, xdata,
pp, pf, g, r, mu, rp, dt, n,
marker="o",mfc="r"):
self.xdata=xdata
self.ydata = np.zeros(len(self.xdata))
self.pp=pp;self.pf=pf;self.g=g;self.r=r;self.mu=mu
self.rp=rp;self.dt=dt;self.n=n
self.ln, = ax.plot([], [], marker= marker,
markerfacecolor=mfc,markeredgecolor='k', linestyle='None',
animated=True)
def v_stokes(self, pp,pf,g,r,mu):
top=2*(pp-pf)*g*(r**2)
bottom=9*mu
return top/bottom
def concentration(self,xdata, ydata, rp):
coords = list(zip(xdata, ydata))
tree = spatial.KDTree(coords)
test = np.column_stack([xdata, ydata])
nnl = tree.query_ball_point(test, rp)
nnt = np.zeros(len(nnl)) #nearest neighbors total
for i in range(len(nnt)):
nnt[i] = len(nnl[i])
return nnt
def update(self, frame):
self.xdata += np.random.normal(0, sigma, n)
if frame == 0:
self.ydata = np.zeros(len(self.xdata))
wss = self.v_stokes(self.pp,self.pf,self.g,self.r,self.mu)
cp = self.concentration(self.xdata, self.ydata, self.rp)
if np.any(cp == 1):
cp = cp-1
if frame > 0.0:
self.ydata += (wss*(1-cp)**3) - dt
for j,v in enumerate(self.ydata):
if v < -1.001:
self.ydata[j] = -1
self.ln.set_data(self.xdata, self.ydata)
return self.ln
fig, ax = plt.subplots()
xdata, xdata2 = [0.0], [0.0]
p1 = Particles(ax,xdata, pp, pf, g, r, mu, rp, dt, n,
marker="o",mfc="r")
p2 = Particles(ax,xdata2, pp2, pf2, g2, r2, mu2, rp2, dt2, n,
marker="s",mfc="b")
def init():
ax.set_xlim(-2, 2)
ax.set_ylim(-1, 1)
return p1.ln, p2.ln
def update(i):
l1 = p1.update(i)
l2 = p2.update(i)
return l1, l2
ani = FuncAnimation(fig, update, frames=range(0,200),
init_func=init, blit=True, interval=100, repeat = False)
plt.show()

Related

chart_pie index to generate

I need help to generate this graph, especially with domains limits
and the arrow indicating the domain
all I can do is generate the domains name but not the limits and arrow
The following code will produce something like what you require:
from matplotlib import pyplot as plt
from matplotlib.patches import Wedge
import numpy as np
labels = ["Obésité\nmassive", "Obésité", "Surpoids", "Normal", "Maigreur"]
innerlabels = [">40", "30 à 40", "25 à 30", "18,5 à 25", "< 18,5"]
colours = ["red", "darkorange", "orange", "green", "blue"]
fig, ax = plt.subplots(figsize=(6, 6), dpi=200)
theta = 0
dtheta = 180 / len(labels)
width = 0.35
def pol2cart(rho, phi):
x = rho * np.cos(phi)
y = rho * np.sin(phi)
return(x, y)
patches = []
for i in range(len(labels)):
# outer wedge
wedge = Wedge(0, r=1, width=width, theta1=theta, theta2=(theta + dtheta), fc=colours[i], alpha=0.6, edgecolor="whitesmoke")
ax.add_patch(wedge)
# inner wedge
wedge = Wedge(0, r=1 - width, width=width, theta1=theta, theta2=(theta + dtheta), fc=colours[i], edgecolor="whitesmoke")
ax.add_patch(wedge)
theta += dtheta
# add text label
tr = 1 - (width / 2)
ta = theta - dtheta / 2
x, y = pol2cart(tr, np.deg2rad(ta))
textangle = -np.fmod(90 - ta, 180)
ax.text(x, y, labels[i], rotation=textangle, va="center", ha="center", color="white", fontweight="bold")
# inner labels
tr = (1 - width) - (width / 2)
x, y = pol2cart(tr, np.deg2rad(ta))
textangle = -np.fmod(90 - ta, 180)
ax.text(x, y, innerlabels[i], rotation=textangle, va="center", ha="center", color="white")
ax.set_xlim([-1, 1])
ax.set_ylim([0, 1])
ax.set_axis_off()
ax.set_aspect("equal")
def bmiposition(bmi):
"""
Get angular position of BMI arrow.
"""
from scipy.interpolate import interp1d
bmiranges = [(0, 18.5), (18.5, 25), (25, 30), (30, 40), (40, 80)]
angrange = [(180 - dtheta * i, 180 - dtheta * (i + 1)) for i in range(len(bmiranges))]
interpfuncs = []
for i in range(len(bmiranges)):
interpfuncs.append(interp1d(bmiranges[i], angrange[i], kind="linear"))
bmiang = np.piecewise(
bmi,
[bmiranges[i][0] < bmi <= bmiranges[i][1] for i in range(len(bmiranges))],
interpfuncs,
)
return bmiang
bmi = 22.5 # set BMI
# add arrow
pos = bmiposition(bmi) # get BMI angle
x, y = pol2cart(0.25, np.deg2rad(pos))
ax.arrow(0, 0, x, y, head_length=0.125, width=0.025, fc="k")
ax.plot(0, 0, 'ko', ms=10) # circle at origin
giving:

Matplotlib polar does not plot as expected

I'm trying to insert a polar plot "version" of a cartesian plot. Here's what it should look like (according to a similar program done in Matlab):
And here's enough of the code to show the weirdness I'm getting:
from scipy import pi, sin, cos, log
from numpy import radians as rad
from numpy import log10, linspace
from matplotlib import pyplot as plt
############## Inputs ##############
#Beamwidth, in degrees
BW = 5
############## Constants for calculations ##############
# 0 = uniform/sin, 1 = cos, 2 = cos^2, etc
#Peak Pattern break points, from Table 3
p0, p1, p2, p3, p4 = -5.75, -14.4, -22.3, -31.5, -39.4
#Average pattern break points, from Table 3
a0, a1 ,a2, a3, a4 = -12.16, -20.6, -29, -37.6, -42.5
#Constant added to peak pattern to convert it to average, from Table 3
c0, c1, c2, c3, c4 = -3.72, -4.32, -4.6, -4.2, -2.61
#Mask floor levels, from Table 3
floor0, floor1, floor2, floor3, floor4 = -30, -50, -60, -70, -80
############## Calculations ##############
#Lists for plotting purposes
u_x = list(linspace(0,90,500))
u0_norm_y = list()
u0_peak_y = list()
u0_avg_y = list()
##Calculations start
for ang in u_x:
########## Uniform
u0 = pi * 50.8 * sin(rad(ang)) / BW
def u0_norm(ang):
if ang == 0:
return 0
else:
return 20 * log10(abs(sin(u0) / u0))
def u0_peak(ang, u0_norm):
if ang == 0:
return 0
elif u0_norm(ang) > p0:
return u0_norm(ang)
elif -8.584 * log(2.876 * ang / BW) > floor0:
return -8.584 * log(2.876 * ang / BW)
else:
return floor0
def u0_avg(ang, u0_norm):
if ang == 0:
return 0
elif u0_norm(ang) > a0:
return u0_norm(ang)
elif -8.584 * log(2.876 * ang / BW) + c0 > floor0:
return -8.584 * log(2.876 * ang / BW) + c0
else:
return floor0
u0_peak_y.append(u0_peak(ang, u0_norm))
u0_norm_y.append(u0_norm(ang))
u0_avg_y.append(u0_avg(ang, u0_norm))
############## Plots ##############
#Uniform
fig1 = plt.figure()
ax1 = plt.subplot(121)
ax2 = plt.subplot(122, polar = True)
ax1.plot(u_x, u0_norm_y, label= "Normalized Pattern")
ax1.plot(u_x, u0_peak_y, label= "Peak")
ax1.plot(u_x, u0_avg_y, label= "Average")
ax1.set_title("Uniform Pattern")
ax1.set_xlabel("Angle (degrees)")
ax1.set_ylabel("Normalized Antenna Pattern (dB)")
ax2.set_theta_zero_location("N")
ax2.set_theta_direction(-1)
ax2.plot(u_x, u0_norm_y, label= "Normalized Pattern")
ax2.plot(u_x, u0_peak_y, label= "Peak")
ax2.plot(u_x, u0_avg_y, label= "Average")
ax2.set_thetamin(0)
ax2.set_thetamax(90)
ax1.grid(True)
plt.tight_layout()
plt.subplots_adjust(wspace = 0.4)
plt.show()
Obviously, something has gone terribly wrong. My plot is an actual mess. I'm assuming something about the way polar plots are created vs cartesian plots, code-wise, is very different, but I haven't been able to find any real detail about this.
You are mixing up radians and degrees (the intuition of ImportanceOfBeingErnest was correct).
Remove the conversion to radians you do when defining u0 and convert to radians directly the input u_x.
from scipy import pi, sin, cos, log
from numpy import radians as rad
from numpy import log10, linspace
from matplotlib import pyplot as plt
############## Inputs ##############
#Beamwidth, in degrees
BW = 5
############## Constants for calculations ##############
# 0 = uniform/sin, 1 = cos, 2 = cos^2, etc
#Peak Pattern break points, from Table 3
p0, p1, p2, p3, p4 = -5.75, -14.4, -22.3, -31.5, -39.4
#Average pattern break points, from Table 3
a0, a1 ,a2, a3, a4 = -12.16, -20.6, -29, -37.6, -42.5
#Constant added to peak pattern to convert it to average, from Table 3
c0, c1, c2, c3, c4 = -3.72, -4.32, -4.6, -4.2, -2.61
#Mask floor levels, from Table 3
floor0, floor1, floor2, floor3, floor4 = -30, -50, -60, -70, -80
############## Calculations ##############
#Lists for plotting purposes
u_x = list(linspace(0,rad(90),500))
u0_norm_y = list()
u0_peak_y = list()
u0_avg_y = list()
##Calculations start
for ang in u_x:
########## Uniform
u0 = pi * 50.8 * sin((ang)) / BW
def u0_norm(ang):
if ang == 0:
return 0
else:
return 20 * log10(abs(sin(u0) / u0))
def u0_peak(ang, u0_norm):
if ang == 0:
return 0
elif u0_norm(ang) > p0:
return u0_norm(ang)
elif -8.584 * log(2.876 * ang / BW) > floor0:
return -8.584 * log(2.876 * ang / BW)
else:
return floor0
def u0_avg(ang, u0_norm):
if ang == 0:
return 0
elif u0_norm(ang) > a0:
return u0_norm(ang)
elif -8.584 * log(2.876 * ang / BW) + c0 > floor0:
return -8.584 * log(2.876 * ang / BW) + c0
else:
return floor0
u0_peak_y.append(u0_peak(ang, u0_norm))
u0_norm_y.append(u0_norm(ang))
u0_avg_y.append(u0_avg(ang, u0_norm))
############## Plots ##############
#Uniform
fig1 = plt.figure()
ax1 = plt.subplot(121)
ax2 = plt.subplot(122, polar = True)
ax1.plot(u_x, u0_norm_y, label= "Normalized Pattern")
ax1.plot(u_x, u0_peak_y, label= "Peak")
ax1.plot(u_x, u0_avg_y, label= "Average")
ax1.set_title("Uniform Pattern")
ax1.set_xlabel("Angle (degrees)")
ax1.set_ylabel("Normalized Antenna Pattern (dB)")
ax2.set_theta_zero_location("N")
ax2.set_theta_direction(-1)
ax2.plot(u_x, u0_norm_y, label= "Normalized Pattern")
ax2.plot(u_x, u0_peak_y, label= "Peak")
ax2.plot(u_x, u0_avg_y, label= "Average")
ax2.set_thetamin(0)
ax2.set_thetamax(90)
ax1.grid(True)
plt.tight_layout()
plt.subplots_adjust(wspace = 0.4)
plt.show()
Here is what I think is a better version of the same code, with little edits.
from scipy import pi, sin, cos, log
from numpy import radians as rad
from numpy import log10, linspace
from matplotlib import pyplot as plt
############## Inputs ##############
#Beamwidth, in degrees
BW = 5
############## Constants for calculations ##############
# 0 = uniform/sin, 1 = cos, 2 = cos^2, etc
#Peak Pattern break points, from Table 3
p0, p1, p2, p3, p4 = -5.75, -14.4, -22.3, -31.5, -39.4
#Average pattern break points, from Table 3
a0, a1 ,a2, a3, a4 = -12.16, -20.6, -29, -37.6, -42.5
#Constant added to peak pattern to convert it to average, from Table 3
c0, c1, c2, c3, c4 = -3.72, -4.32, -4.6, -4.2, -2.61
#Mask floor levels, from Table 3
floor0, floor1, floor2, floor3, floor4 = -30, -50, -60, -70, -80
############## Calculations ##############
#Lists for plotting purposes
u_x = list(linspace(0,rad(90),500))
u0_norm_y = list()
u0_peak_y = list()
u0_avg_y = list()
##Function definition
def u0_norm(ang, u0):
if ang == 0:
return 0
else:
return 20 * log10(abs(sin(u0) / u0))
def u0_peak(ang, u0):
if ang == 0:
return 0
elif u0_norm(ang, u0) > p0:
return u0_norm(ang, u0)
elif -8.584 * log(2.876 * ang / BW) > floor0:
return -8.584 * log(2.876 * ang / BW)
else:
return floor0
def u0_avg(ang, u0):
if ang == 0:
return 0
elif u0_norm(ang, u0) > a0:
return u0_norm(ang, u0)
elif -8.584 * log(2.876 * ang / BW) + c0 > floor0:
return -8.584 * log(2.876 * ang / BW) + c0
else:
return floor0
for ang in u_x:
########## Uniform
u0 = pi * 50.8 * sin(ang) / BW
u0_peak_y.append(u0_peak(ang, u0))
u0_norm_y.append(u0_norm(ang, u0))
u0_avg_y.append(u0_avg(ang, u0))
############## Plots ##############
#Uniform
fig1 = plt.figure()
ax1 = plt.subplot(121)
ax2 = plt.subplot(122, polar = True)
ax1.plot(u_x, u0_norm_y, label= "Normalized Pattern")
ax1.plot(u_x, u0_peak_y, label= "Peak")
ax1.plot(u_x, u0_avg_y, label= "Average")
ax1.set_title("Uniform Pattern")
ax1.set_xlabel("Angle (radians)")
ax1.set_ylabel("Normalized Antenna Pattern (dB)")
ax2.set_theta_zero_location("N")
ax2.set_theta_direction(-1)
ax2.plot(u_x, u0_norm_y, label= "Normalized Pattern")
ax2.plot(u_x, u0_peak_y, label= "Peak")
ax2.plot(u_x, u0_avg_y, label= "Average")
ax2.set_thetamin(0)
ax2.set_thetamax(90)
ax1.grid(True)
plt.tight_layout()
plt.subplots_adjust(wspace = 0.4)
plt.show()

Python 3.5.4 matplotlib can not draw the animated figure

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()

My circles are not matching up with my planets orbits

My planets orbits are not matching up with my circular paths im plotting of the orbits, I have matched in my for loop the distance for every planet with the distance they are from the center.(image is attached)
from pylab import *
from matplotlib.animation import *
Here is where I am defining the circes I will plot to show the paths of the orbits at the "def circle..."
def circle(x0,y0,R,N) :
''' create circle, given center x0,y0, input radius R,
and number of points N, then
output arrays of x and y coordinates '''
theta = linspace(0.0,2.0*pi,N)
x = R * cos(theta) + x0
y = R * sin(theta) + y0
return x,y
a= array([.39,.72,1,1.52,5.20,9.54,19.2,30.1]) #astronomical units of #the planets in order of the planets(i.e mercury, venus, earth,mars...)
period = a**(3.0/2.0)
I am taking the distane of the planets and inputting them in array, to be able to use a for loop to graph the circles.
#distance of the planets
d= array([390,790,980, 1520,5200,9540,19200,30100])#same order of the #planets as well
#attributes of the sun
x0 =0
y0 = 0
r_s=70*1.2#actual earth radius is 695e6
#radius of the planets
r_Ear = 63.781#e in m {for all the planets}
r_Merc= 24
r_Ven = 60
r_Mars= 33.9
r_Jup = 700
r_Sat = 582
r_Ura = 253
r_Nep = 246
the actual distance of the planets
#Distance of the planets
d_Ear = 1000#152
d_Merc= 390#70
d_Ven = 790#109
d_Mars= 1520#249
d_Jup = 5200#816
d_Sat = 9540#1514
d_Ura = 19200#3003
d_Nep = 30100#4545
fig = plt.figure()
ax = plt.axes(xlim=(-1e4-5000, 1e4+5000), ylim=(-1e4-5000, 1e4+5000), aspect=True)
This is where I am looping over, to plot 8 circles. Theres a link here to see the plot I have generated.
for i in range(8) :
x, y = circle(0.0,0.0,d[i],10000) # orbit
plot(x,y,':k')
[enter image description here][1]
The rest are the patches of the planets and the FuncAnimation.
Sun = plt.Circle((x0, y0), radius=r_s, ec='yellow', fc='yellow', lw=3)
Mercury = plt.Circle((0, 0), radius=r_Merc, ec='brown', fc='brown', lw=3)
Venus = plt.Circle((0, 0), radius=r_Ven, ec='brown', fc='brown', lw=3)
Earth = plt.Circle((0, 0), radius=r_Ear, ec='black', fc='black', lw=3)
Mars = plt.Circle((0, 0), radius=r_Mars, ec='brown', fc='brown', lw=3)
Jupiter = plt.Circle((0, 0), radius=r_Jup, ec='green', fc='green', lw=3)
Saturn = plt.Circle((0, 0), radius=r_Sat, ec='green', fc='green', lw=3)
Uranus = plt.Circle((0, 0), radius=r_Ura, ec='green', fc='green', lw=3)
Neptune = plt.Circle((0, 0), radius=r_Nep, ec='green', fc='green', lw=3)
ax.add_patch(Sun)
def init():
ax.add_patch(Earth)
ax.add_patch(Mercury)
ax.add_patch(Venus)
ax.add_patch(Mars)
ax.add_patch(Jupiter)
ax.add_patch(Saturn)
ax.add_patch(Uranus)
ax.add_patch(Neptune)
return Mercury, Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune,
def animate(i):
theta = radians(i)
mx = d_Merc*np.cos(theta/period[0]) - d_Merc*np.sin(theta/period[0])
my = d_Merc*np.sin(theta/period[0]) + d_Merc*np.cos(theta/period[0])
vx = d_Ven *np.cos(theta/period[1]) - d_Ven*np.sin(theta/period[1])
vy = d_Ven *np.cos(theta/period[1]) + d_Ven*np.sin(theta/period[1])
ex = d_Ear*np.cos(theta/period[2]) - d_Ear*np.sin(theta/period[2])
ey = d_Ear*np.sin(theta/period[2]) + d_Ear*np.cos(theta/period[2])
Mx = d_Mars*np.cos(theta/period[3]) - d_Mars*np.sin(theta/period[3])
My = d_Mars*np.sin(theta/period[3]) + d_Mars*np.cos(theta/period[3])
Jx = d_Jup*np.cos(theta/period[4]) - d_Jup*np.sin(theta/period[4])
Jy = d_Jup*np.sin(theta/period[4]) + d_Jup*np.cos(theta/period[4])
Sx = d_Sat*np.cos(theta/period[5]) - d_Sat*np.sin(theta/period[5])
Sy = d_Sat*np.sin(theta/period[5]) + d_Sat*np.cos(theta/period[5])
Ux = d_Ura*np.cos(theta/period[6]) - d_Ura*np.sin(theta/period[6])
Uy = d_Ura*np.sin(theta/period[6]) + d_Ura*np.cos(theta/period[6])
Nx = d_Nep*np.cos(theta/period[7]) - d_Nep*np.sin(theta/period[7])
Ny = d_Nep*np.sin(theta/period[7]) + d_Nep*np.cos(theta/period[7])
Mercury.center = (mx, my)
Mercury._angle = i
Venus.center = (vx, vy)
Venus._angle = i
Earth.center = (ex, ey)
Earth._angle = i
Mars.center = (Mx, My)
Mars.angle =i
Jupiter.center = (Jx, Jy)
Jupiter._angle = i
Saturn.center = (Sx, Sy)
Saturn._angle = i
Uranus.center = (Ux, Uy)
Uranus.angle = i
Neptune.center = (Nx, Ny)
Neptune._angle = i
return Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune,
anim = FuncAnimation(fig, animate, init_func=init, frames=1080,
interval=25, blit=True)
plt.show()
I'm not following your math on this:
mx = d_Merc*np.cos(theta/period[0]) - d_Merc*np.sin(theta/period[0])
my = d_Merc*np.sin(theta/period[0]) + d_Merc*np.cos(theta/period[0])
You'll be more correct if you change that to this:
mx = d_Merc*np.cos(theta/period[0])
my = d_Merc*np.sin(theta/period[0])
And even more correct if you take the size of the planet into account
mx = (d_Merc+(r_Merc/2))*np.cos(theta/period[0])
my = (d_Merc+(r_Merc/2))*np.sin(theta/period[0])
That will fix your basic issue I think.
Beyond that:
d_Ear differs from Earth's value in the d array. 980 vs. 1000.
vy = d_Ven *np.cos(theta/period[1]) is not correct. That needs
to be vy = d_Ven *np.sin(theta/period[1])
As far as the code goes, you may consider using a few dictionaries to
avoid repetition like with your d array.

Can't get my program to animate multiple patches in python matplotlib

I am attempting to animate two different particles in matplotlib (python). I just figured out a way to animate one particle in matplotlib, but I am havign difficulties trying to get the program to work with multiple particles. Does anyone know what is wrong and how to fix it?
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(5, 4.5)
ax = plt.axes(xlim=(0, 100), ylim=(0, 100))
enemy = plt.Circle((10, -10), 0.75, fc='r')
agent = plt.Circle((10, -10), 0.75, fc='b')
def init():
#enemy.center = (5, 5)
#agent.center = (5, 5)
ax.add_patch(agent)
ax.add_patch(enemy)
return []
def animationManage(i,agent,enemy):
patches = []
enemy.center = (5, 5)
agent.center = (5, 5)
enemy_patches = animateCos(i,agent)
agent_patches = animateLine(i,enemy)
patches[enemy_patches, agent_patches]
#patches.append(ax.add_patch(enemy_patches))
#patches.append(ax.add_patch(agent_patches))
return enemy_patches
def animateCirc(i, patch):
# It seems that i represents time step
x, y = patch.center
# 1st constant = position and 2nd constant = trajectory
x = 50 + 30 * np.sin(np.radians(i))
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateLine(i, patch):
x, y = patch.center
x = x + 1
y = x+ 1
patch.center = (x, y)
return patch,
def animateCos(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateSin(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.sin(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animationManage,
init_func=init,
frames=360,
fargs=(agent,enemy,),
interval=20,
blit=True)
plt.show()
Working code for animating one particle
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(5, 4.5)
ax = plt.axes(xlim=(0, 100), ylim=(0, 100))
enemy = plt.Circle((10, -10), 0.75, fc='r')
agent = plt.Circle((10, -10), 0.75, fc='b')
def init():
enemy.center = (5, 5)
agent.center = (5, 5)
ax.add_patch(enemy)
ax.add_patch(agent)
return enemy,
def animateCirc(i, patch):
# It seems that i represents time step
x, y = patch.center
# 1st constant = position and 2nd constant = trajectory
x = 50 + 30 * np.sin(np.radians(i))
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateLine(i, patch):
x, y = patch.center
x = x + 1
y = x+ 1
patch.center = (x, y)
return patch,
def animateCos(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
def animateSin(i, patch):
x, y = patch.center
x = x + 0.2
y = 50 + 30 * np.sin(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animateCos,
init_func=init,
frames=360,
fargs=(enemy,),
interval=20,
blit=True)
plt.show()
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(5, 4.5)
ax = plt.axes(xlim=(0, 100), ylim=(0, 100))
enemy = plt.Circle((10, -10), 0.75, fc='r')
agent = plt.Circle((10, -10), 0.75, fc='b')
def init():
enemy.center = (5, 5)
agent.center = (5, 5)
ax.add_patch(agent)
ax.add_patch(enemy)
return []
def animationManage(i,agent,enemy):
animateCos(i,enemy)
animateLine(i,agent)
return []
def animateLine(i, patch):
x, y = patch.center
x += 0.25
y += 0.25
patch.center = (x, y)
return patch,
def animateCos(i, patch):
x, y = patch.center
x += 0.2
y = 50 + 30 * np.cos(np.radians(i))
patch.center = (x, y)
return patch,
anim = animation.FuncAnimation(fig, animationManage,
init_func=init,
frames=360,
fargs=(agent,enemy,),
interval=20,
blit=True,
repeat=True)
plt.show()

Categories

Resources