can anyone help me, i stuck at the last step
[]
this is my code. then for the last step to rotate it, i didnt know what should i do to rotate the triangle
This is the perfect case for an animation:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
from matplotlib.animation import FuncAnimation
# Enter x and y coordinates of points and colors
a=(0,0.5);b=(0.43,-0.25);c=(-0.43,-0.25)
center=(0,0)
n = 3;r=1.0
theta = np.arange(0,360+(360/(n)),360/(n))
to=np.arange(0,2*np.pi,0.01)
x = r * np.cos(np.radians(theta))
y = r * np.sin(np.radians(theta))
xo = r * np.cos(to); yo = r * np.sin(to)
fig, ax = plt.subplots()
ax.plot(xo,yo)
# create artists: they will be used to update the position
# of the points being rendered
triangle, = ax.plot(x,y)
vertices = ax.scatter(x,y)
lim = r * 1.25
ax.set_xlim([-lim, lim]);ax.set_ylim([-lim, lim])
ax.set_aspect("equal")
w = 2
T = 2 * np.pi / w
# this defines the time steps of the animation
dt = np.linspace(0, 10 * T, num=500)
def animate(i):
x = r * np.cos(np.radians(theta) + w * dt[i])
y = r * np.sin(np.radians(theta) + w * dt[i])
# update the position of the points to be rendered
triangle.set_data(x, y)
vertices.set_offsets(np.stack([x, y]).T)
ax.set_title("Rotation #%s" % int(w * dt[i] / (2 * np.pi) + 1))
ani = FuncAnimation(fig, animate, frames=len(dt), repeat=False)
plt.show()
Check this out..
from IPython import display
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
# Enter x and y coordinates of points and colors
a=(0,0.5);b=(0.43,-0.25);c=(-0.43,-0.25)
center=(0,0)
n = 3;r=1.0
theta = np.arange(0,360+(360/(n)),360/(n))
w = 2
T = 2*np.pi/w
dt = np.linspace(0, 10*T, num=10) #increase num for more finely distributed rotations.
for d in dt:
to=np.arange(0,2*np.pi,0.01)
x = r*np.sin(np.radians(theta + d))
y=r*np.cos(np.radians(theta + d))
xo=r*np.sin(to);yo=r*np.cos(to)
plt.plot(xo,yo)
plt.plot(x,y)
plt.scatter(x,y)
plt.xlim([-1, 1]);plt.ylim([-1,1])
Related
I'm having trouble plotting an animation with python. What I want to do is basically an animation that contains the superposition of many complete plots. In such a way that each frame will be a plot given by
plt.plot(r, Sevol[n])
The code and error displayed on the screen are below. Thanks for any help.
UserWarning: Animation was deleted without rendering anything. This is most likely not intended. To prevent deletion, assign the Animation to a variable, e.g. anim, that exists until you have outputted the Animation using plt.show() or anim.save().
import numpy as np
import math
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
nr = 300
ri = 0
rf = 300
dr = (rf - ri) / (nr - 1)
nt = 1000
dt = 0.1
r = np.linspace(ri, rf, num=nr)
def rk3_step(t, h, y, f, *args):
k1 = h * f(t , y , *args)
k2 = h * f(t + h/2, y + 1/2 * k1 , *args)
k3 = h * f(t + h , y - k1 + 2 * k2, *args)
return y + 1/6*(k1 + 4*k2 + k3)
def rhs_perturb(t, u):
S = u.T[0]
S_dot = u.T[1]
F = u.T[2]
F_dot = u.T[3]
rhs = np.empty((nr, 4))
rhs[0] = np.array([S_dot[0],
(S[2] - 2 * S[1] + S[0]) / (dr ** 2), # + F[0],
F_dot[0],
- S[0] + (F[2] - 2 * F[1] + F[0]) / (dr ** 2)])
rhs[-1] = np.array([S_dot[-1],
(S[-1] - 2 * S[-2] + S[-3]) / (dr ** 2), # + F[-1],
F_dot[-1],
- S[-1] + (F[-1] - 2 * F[-2] + F[-3]) / (dr ** 2)])
for i in range(1, nr - 1):
rhs[i] = np.array([S_dot[i],
(S[i + 1] - 2 * S[i] + S[i - 1]) / (dr ** 2), # + F[i],
F_dot[i],
- S[i] + (F[i + 1] - 2 * F[i] + F[i - 1]) / (dr ** 2)])
return rhs
sigma = 3
r0 = 100
F = np.empty(nr)
F_dot = np.empty(nr)
S = np.empty(nr)
S_dot = np.empty(nr)
for i in range(nr):
F[i] = 0
F_dot[i] = 0
S_dot[i] = 0
S[i] = math.exp(-(r[i] - r0)**2 / sigma**2)
uin = np.block([[S], [S_dot], [F], [F_dot]]).T
u = np.copy(uin)
uaux = np.copy(uin)
nsave = 10
Sevol = np.empty((math.floor(nt/nsave),nr))
Sevol[0] = S
Fevol = np.empty((math.floor(nt/nsave),nr))
Fevol[0] = F
for n in range(nt):
uaux = rk3_step(n * dt, dt, u, rhs_perturb)
if np.any(np.isnan(uaux)):
break
u = uaux
if (n + 1) % nsave == 0:
Sevol[math.floor(n / nsave)] = u.T[0]
Fevol[math.floor(n / nsave)] = u.T[2]
fig = plt.figure()
plt.xlabel('r')
plt.xlabel('S')
plt.grid()
plt.xlim(ri, rf)
def animate(i):
numPlots = i //10 # how many plots (-1) will be shown based on the frame.
for n in range(numPlots):
plt.plot(r[n], Sevol[n], color='gold', markersize=3)
ani = FuncAnimation(fig, animate, frames=100, interval=10, blit = False, repeat = False)
plt.close()
plt.show()
I would suggest initializing your animations with a list of empty placeholders plots. In your case, it looks like you need 100 plots. And then update the data for plot i at each frame with the actual values.
Below is what the animation code looks like:
import numpy as np
import math
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter
N_plots=100
fig,ax = plt.subplots()
color = plt.cm.viridis(np.linspace(0, 1, N_plots))
lns=[ax.plot([],[],color=color[i]) for i in range(N_plots)]
lns=[lns[i][0] for i in range(N_plots)]
plt.xlabel('r')
plt.ylabel('S')
plt.grid()
plt.xlim(ri, rf)
plt.ylim(-0.25, 1)
def animate(i):
lns[i].set_data(r,Sevol[i])
return lns
ani = FuncAnimation(fig, animate, frames=N_plots, interval=100)
And the output gives:
EDIT:
Note that if instead of superimposing the curves you just want to replace them by the next, you can simply use set_data to update your one plot.
See code below:
import numpy as np
import math
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter
N_plots=100
fig,ax = plt.subplots()
color = plt.cm.viridis(np.linspace(0, 1, N_plots))
ln,=ax.plot([],[])
plt.xlabel('r')
plt.ylabel('S')
plt.grid()
plt.xlim(ri, rf)
plt.ylim(-0.25, 1)
def animate(i):
ln.set_data(r,Sevol[i])
ln.set_color(color[i])
return ln
ani = FuncAnimation(fig, animate, frames=N_plots, interval=100)
And the output gives:
I'm trying to plot something like this:
I don't know how to find the center of smaller circles in for loops. First, I've tried to plot it with smaller number of circles(for example 2) but I don't know why the smaller circles are semi-circles??
My try:
import numpy as np
import matplotlib.pyplot as plt
r = 2, h = 1, k = 1
axlim = r + np.max((abs(h),np.max(abs(k))))
x = np.linspace(-axlim, axlim, 100)
X,Y = np.meshgrid(x,x)
F = (X-h)**2 + (Y-k)**2 - r**2
plt.contour(X,Y,F,0)
F1 = (X-(h+r))**2 + (Y-k)**2 - (r/3)**2
plt.contour(X,Y,F1,0)
F2 = (X-h)**2 + (Y-(k+r))**2 - (r/3)**2
plt.contour(X,Y,F2,0)
plt.gca().set_aspect('equal')
plt.axis([-4*r, 4*r, -4*r,4*r])
# plt.axis('off')
plt.show()
The output:
Sine, cosine and an angle evenly divided over the range 0, 2picould be used:
import numpy as np
import matplotlib.pyplot as plt
num_circ = 7
rad_large = 7
rad_small = 6
thetas = np.linspace(0, 2 * np.pi, num_circ, endpoint=False)
fig, ax = plt.subplots()
ax.add_patch(plt.Circle((0, 0), rad_large, fc='none', ec='navy'))
for theta in thetas:
ax.add_patch(plt.Circle((rad_large * np.cos(theta), rad_large * np.sin(theta),), rad_small, fc='none', ec='crimson'))
ax.autoscale_view() # calculate the limits for the x and y axis
ax.set_aspect('equal') # show circles as circles
plt.show()
import matplotlib.pyplot as plt
import numpy as np
import math
import matplotlib.gridspec as gridspec
from matplotlib.animation import FuncAnimation
fig = plt.figure()
plt.xlabel('X')
plt.ylabel('Y')
# limiting the y and x axis
plt.ylim(0, 10)
plt.xlim(0, 10)
def xy_plot1(u, theta):
y_arr1= []
x_arr1 = []
# displacement in the y_direction is zero
x_disp = (u*u)*(math.sin(2*theta))/9.8 # disp_x = (u^2)*sin(2theta)/g {horizontal range}
x = 0 # distance from the origin
while(x <= x_disp):
# below is the equation of path of projectile
y = (x*(math.tan(theta))) - ((9.8*x*x)/(2*pow((u*math.cos(theta)), 2)))
y_arr1.append(y)
x_arr1.append(x)
x = x + 0.1 # basically x = x + dx
plt.plot(x_arr1, y_arr1)
def xy_plot2(u, theta):
y_arr2 = []
x_arr2 = []
# displacement in the y_direction is zero
x_disp = (u*u)*(math.sin(2*theta))/9.8 # disp_x = (u^2)*sin(2theta)/g {horizontal range}
x = 0 # distance from the origin
dx = 0.1
while(x <= x_disp):
# below is the equation of path of projectile
y = (x*(math.tan(theta))) - ((9.8*x*x)/(2*pow((u*math.cos(theta)), 2)))
y_arr2.append(y)
x_arr2.append(x)
x = x + dx
plt.plot(x_arr2, y_arr2)
xy_plot1(10, 60)
xy_plot2(10, 30)
plt.show()
Be careful! Your theta argument for the xyplot() function is in degrees, but inside your function, the math.sin() function takes the argument for the angle in units of radians. The easiest fix is to provide your theta argument in units of radians instead of degrees.
You also don't need both functions if they do the exact same thing, as plt.plot() will draw subsequent projectile curves along with previous ones as long as you don't clear the plot.
import matplotlib.pyplot as plt
import numpy as np
import math
import matplotlib.gridspec as gridspec
from matplotlib.animation import FuncAnimation
fig = plt.figure()
plt.xlabel('X')
plt.ylabel('Y')
# limiting the y and x axis
plt.ylim(0, 10)
plt.xlim(0, 10)
def xy_plot(u, theta):
y_arr2 = []
x_arr2 = []
# displacement in the y_direction is zero
x_disp = (u*u)*(math.sin(2*theta))/9.8 # disp_x = (u^2)*sin(2theta)/g {horizontal range}
x = 0 # distance from the origin
dx=0.1
while(x <= x_disp):
# below is the equation of path of projectile
y = (x*(math.tan(theta))) - ((9.8*x*x)/(2*pow((u*math.cos(theta)), 2)))
y_arr2.append(y)
x_arr2.append(x)
x = x + dx
plt.plot(x_arr2, y_arr2)
# be careful about using degrees versus radians!!
xy_plot(10, math.pi/3)
xy_plot(10, math.pi/6)
plt.show()
[TLDR]:
Essentially my question boils down to how one can extract the 2d data of a plane from a 3D numpy meshgrid
[Detailed Description]:
I am calculating the electric field of two (or more) point charges. I did this in 2D and can plot the results via matplotlib using quiver or streamplot
import numpy as np
from matplotlib import pyplot as plt
eps_0 = 8e-12
fac = (1./(4*np.pi*eps_0))
charges = [1.0,-1.0]
qx = [-2.0,2.0]
qy = [0.0,0.0]
# GRID
gridsize = 4.0
N = 11
X,Y = np.meshgrid( np.linspace(-gridsize,gridsize,N),
np.linspace(-gridsize,gridsize,N))
# CALC E-FIELD
sumEx = np.zeros_like(X)
sumEy = np.zeros_like(Y)
for q, qxi, qyi in zip(charges,qx,qy):
dist_vec_x = X - qxi
dist_vec_y = Y - qyi
dist = np.sqrt(dist_vec_x**2 + dist_vec_y**2)
Ex = fac * q * (dist_vec_x/dist**3)
Ey = fac * q * (dist_vec_y/dist**3)
sumEx += Ex
sumEy += Ey
# PLOT
fig = plt.figure()
ax = fig.add_subplot(111)
ax.streamplot(X,Y,sumEx,sumEy)
plt.show()
This produces the correct results
I can easily extend this to 3D
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
eps_0 = 8e-12
fac = (1./(4*np.pi*eps_0))
charges = [1.0,-1.0]
qx = [-2.0,2.0]
qy = [0.0,0.0]
qz = [0.0,0.0]
# GRID
gridsize = 4.0
N = 11
X,Y,Z = np.meshgrid( np.linspace(-gridsize,gridsize,N),
np.linspace(-gridsize,gridsize,N),
np.linspace(-gridsize,gridsize,N))
# CALC E-FIELD
sumEx = np.zeros_like(X)
sumEy = np.zeros_like(Y)
sumEz = np.zeros_like(Z)
for q, qxi, qyi, qzi in zip(charges,qx,qy,qz):
dist_vec_x = X - qxi
dist_vec_y = Y - qyi
dist_vec_z = Z - qzi
dist = np.sqrt(dist_vec_x**2 + dist_vec_y**2 + dist_vec_z**2)
Ex = fac * q * (dist_vec_x/dist**3)
Ey = fac * q * (dist_vec_y/dist**3)
Ez = fac * q * (dist_vec_z/dist**3)
sumEx += Ex
sumEy += Ey
sumEz += Ez
# PLOT
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.quiver(X,Y,Z,sumEx,sumEy,sumEz, pivot='middle', normalize=True)
plt.show()
This also yields the correct result when plotted in 3D (as far as I can tell)
But for some reason I can not figure out how to extract the data from one x-y plane from the generated 3D numpy mesh. I thought I could just do something like
zplane = round(N/2)
ax.quiver(X,Y,sumEx[:,:,zplane],sumEy[:,:,zplane])
but this does not do the trick. Does anyone know the proper way here?
Remove projection='3d' and index X and Y:
fig = plt.figure()
ax = fig.gca()
zplane = round(N / 2)
ax.quiver(X[:, :, zplane], Y[:, :, zplane], sumEx[:, :, zplane], sumEy[:, :, zplane])
plt.show()
If you select a specific zplane your plot is no longer a 3D-plot.
I have the following code which produces a cylinder-like object using matplotlib:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
nphi,nz=7,20
r=1 # radius of cylinder
phi = np.linspace(0,360, nphi)/180.0*np.pi
z= np.linspace(0,1.0,nz)
print z
cols=[]
verts2 = []
for i in range(len(phi)-1):
cp0= r*np.cos(phi[i])
cp1= r*np.cos(phi[i+1])
sp0= r*np.sin(phi[i])
sp1= r*np.sin(phi[i+1])
for j in range(len(z)-1):
z0=z[j]
z1=z[j+1]
verts=[]
verts.append((cp0, sp0, z0))
verts.append((cp1, sp1, z0))
verts.append((cp1, sp1, z1))
verts.append((cp0, sp0, z1))
verts2.append(verts)
value=np.random.rand()
#print value
col=plt.cm.rainbow(0.9)
#print col
cols.append(col)
poly3= Poly3DCollection(verts2, facecolor=cols,edgecolor = "none" )
poly3.set_alpha(0.8)
ax.add_collection3d(poly3)
ax.set_xlabel('X')
ax.set_xlim3d(-1, 1)
ax.set_ylabel('Y')
ax.set_ylim3d(-1, 1)
ax.set_zlabel('Z')
ax.set_zlim3d(0, 1)
plt.show()
This code produces the following image:
However as you can see the are sharp corners in the figure. Is there anyway to make these edges rounder so that the figure looks like a proper cylinder with a circular cross-section as opposed to a hexagonal cross-section?
The third argument to
np.linspace
controls how many values you want it to generate. Thus, nphi controls the
number of values in phi, and nz controls the number of values in z:
phi = np.linspace(0,360, nphi)/180.0*np.pi
z = np.linspace(0,1.0,nz)
So if you increase nphi, then you'll get more points along the circle:
cp0 = r*np.cos(phi[i])
sp0 = r*np.sin(phi[i])
For example, try changing nphi, nz = 7,20 to nphi, nz = 70, 2.
Note that there is no need for nz to be greater than 2 since the sides of the
cylinder are flat in the z direction.
By the way, the double for-loop can be replaced by:
PHI, Z = np.meshgrid(phi, z)
CP = r * np.cos(PHI)
SP = r * np.sin(PHI)
XYZ = np.dstack([CP, SP, Z])
verts = np.stack(
[XYZ[:-1, :-1], XYZ[:-1, 1:], XYZ[1:, 1:], XYZ[1:, :-1]], axis=-2).reshape(-1, 4, 3)
So, for example,
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
nphi, nz = 70, 2
r = 1 # radius of cylinder
phi = np.linspace(0, 360, nphi) / 180.0 * np.pi
z = np.linspace(0, 1.0, nz)
PHI, Z = np.meshgrid(phi, z)
CP = r * np.cos(PHI)
SP = r * np.sin(PHI)
XYZ = np.dstack([CP, SP, Z])
verts = np.stack(
[XYZ[:-1, :-1], XYZ[:-1, 1:], XYZ[1:, 1:], XYZ[1:, :-1]], axis=-2).reshape(-1, 4, 3)
cmap = plt.cm.rainbow
cols = cmap(np.random.random())
poly3 = Poly3DCollection(verts, facecolor=cols, edgecolor="none")
poly3.set_alpha(0.8)
ax.add_collection3d(poly3)
ax.set_xlabel('X')
ax.set_xlim3d(-1, 1)
ax.set_ylabel('Y')
ax.set_ylim3d(-1, 1)
ax.set_zlabel('Z')
ax.set_zlim3d(0, 1)
plt.show()
yields