Matplotlib plot pulse propagation in 3d - python

I'd like to plot pulse propagation in such a way at each step, it plots the pulse shape. In other words, I want a serie of x-z plots, for each values of y. Something like this (without color):
How can I do this using matplotlib (or Mayavi)? Here is what I did so far:
def drawPropagation(beta2, C, z):
""" beta2 in ps / km
C is chirp
z is an array of z positions """
T = numpy.linspace(-10, 10, 100)
sx = T.size
sy = z.size
T = numpy.tile(T, (sy, 1))
z = numpy.tile(z, (sx, 1)).T
U = 1 / numpy.sqrt(1 - 1j*beta2*z * (1 + 1j * C)) * numpy.exp(- 0.5 * (1 + 1j * C) * T * T / (1 - 1j*beta2*z*(1 + 1j*C)))
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
surf = ax.plot_wireframe(T, z, abs(U))

Change to:
ax.plot_wireframe(T, z, abs(U), cstride=1000)
and call:
drawPropagation(1.0, 1.0, numpy.linspace(-2, 2, 10))
will create the following graph:
If you need the curve been filled with white color:
import numpy
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot
from matplotlib.collections import PolyCollection
def drawPropagation(beta2, C, z):
""" beta2 in ps / km
C is chirp
z is an array of z positions """
T = numpy.linspace(-10, 10, 100)
sx = T.size
sy = z.size
T = numpy.tile(T, (sy, 1))
z = numpy.tile(z, (sx, 1)).T
U = 1 / numpy.sqrt(1 - 1j*beta2*z * (1 + 1j * C)) * numpy.exp(- 0.5 * (1 + 1j * C) * T * T / (1 - 1j*beta2*z*(1 + 1j*C)))
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
U = numpy.abs(U)
verts = []
for i in xrange(T.shape[0]):
verts.append(zip(T[i, :], U[i, :]))
poly = PolyCollection(verts, facecolors=(1,1,1,1), edgecolors=(0,0,1,1))
ax.add_collection3d(poly, zs=z[:, 0], zdir='y')
ax.set_xlim3d(numpy.min(T), numpy.max(T))
ax.set_ylim3d(numpy.min(z), numpy.max(z))
ax.set_zlim3d(numpy.min(U), numpy.max(U))
drawPropagation(1.0, 1.0, numpy.linspace(-2, 2, 10))
pyplot.show()

Related

Piecewise impclit functions in matplotlib (Python)

I would like to plot the function x^3 - 3xy + y^3 = 0 (Folium of Descartes) but with different colors in quadrant 2 and 4, and at the peak of the leaf I want the colors to change. I was thinking about converting to a piecewise parametric equation to make the plotting in different colors easier, but I don't know how to convert into a parametric form.
I was originally using a contour to plot the function only in one color, but I have no idea how to get the color changes.
Below is what I have for the single color, but I would like to have separate colors for each of the segments listed above.
import matplotlib.pyplot as plt
import numpy as np
xrange = np.arange(-5, 5, .025)
yrange = np.arange(-5, 5, .025)
X, Y = np.meshgrid(xrange, yrange)
plt.contour(X, Y, X**3 - 3*X*Y + Y**3, levels=[0], colors=['#000000'])
plt.show()
This website gives parametric Cartesian and polar equations of the curve.
The parametric equation isn't symmetric in x and y, which is annoying for drawing nice curves.
The polar equation gives a radius rho for a given angle theta. Some experimenting shows that the tails are formed by theta negative, or larger than pi/2. The cusp is at pi/4.
To visualize the polar curve, x=rho*cos(theta) and y=rho*sin(theta) can be used. Coloring can happen depending on theta.
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, ListedColormap
import numpy as np
a = 1
tail = 0.5
theta = np.linspace(-tail, np.pi / 2 + tail, 500)
rho = 3 * a * np.sin(theta) * np.cos(theta) / (np.cos(theta) ** 3 + np.sin(theta) ** 3)
x = rho * np.cos(theta)
y = rho * np.sin(theta)
cmap = LinearSegmentedColormap.from_list('', ['red', 'gold', 'blue'])
# cmap = ListedColormap(['red', 'blue'])
# cmap = 'Spectral'
plt.scatter(x, y, c=theta, cmap=cmap, s=1)
plt.axis('equal')
plt.axis('off')
plt.show()
Copying the leave 4 times, and filling them in decreasing order creates the following plot.
import matplotlib.pyplot as plt
import numpy as np
for a in np.linspace(1, 0.001, 50):
theta = np.linspace(0, np.pi / 2, 500)
rho = 3 * a * np.sin(theta) * np.cos(theta) / (np.cos(theta) ** 3 + np.sin(theta) ** 3)
x = rho * np.cos(theta)
y = rho * np.sin(theta)
for i in [-1, 1]:
for j in [-1, 1]:
plt.fill(i * x, j * y, c=plt.cm.summer(1 - a))
plt.axis('equal')
plt.axis('off')
plt.show()

Correctly interpolate 3D vector field with python scipy

GOAL
My goal is to interpolate a 3D vector field using python.
CODE
Original Vector field
import numpy as np
import matplotlib.pyplot as plt
# For interpolation
from scipy.interpolate import RegularGridInterpolator
#%% VECTOR FIELD
xx, yy, zz = np.meshgrid(np.arange(-0.8, 1, 0.2),
np.arange(-0.8, 1, 0.2),
np.arange(-0.8, 1, 0.8))
uu = np.sin(np.pi * xx) * np.cos(np.pi * yy) * np.cos(np.pi * zz)
vv = -np.cos(np.pi * xx) * np.sin(np.pi * yy) * np.cos(np.pi * zz)
ww = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * xx) * np.cos(np.pi * yy) *
np.sin(np.pi * zz))
# Ravel -> make 1D lists
x = np.ravel(xx)
y = np.ravel(yy)
z = np.ravel(zz)
u = np.ravel(uu)
v = np.ravel(vv)
w = np.ravel(ww)
Interpolation Function (something is wrong here)
#%% INTERPOLATION FUNCTION
def interpolate_field(x,y,z,u,v,w,new_points):
x = np.unique(x)
y = np.unique(y)
z = np.unique(z)
u = np.reshape(u, (len(x), len(y), len(z)))
v = np.reshape(u, (len(x), len(y), len(z)))
w = np.reshape(u, (len(x), len(y), len(z)))
u_int_f = RegularGridInterpolator((x, y, z), u)
v_int_f = RegularGridInterpolator((x, y, z), v)
w_int_f = RegularGridInterpolator((x, y, z), w)
u_int = u_int_f(new_points)
v_int = v_int_f(new_points)
w_int = w_int_f(new_points)
return u_int, v_int, w_int
Evaluate interpolation at new points
#%% EVALUATE INTERPOLATION FUNCTION
new_grid = np.meshgrid(
np.linspace(np.min(x), np.max(x), 20),
np.linspace(np.min(y), np.max(y), 20),
np.linspace(np.min(z), np.max(z), 3)
, indexing="xy")
# create list of new_points
new_points = np.vstack(list(map(np.ravel, new_grid))).T
# get vector field values at new points
uint, vint, wint = interpolate_field(x,y,z,u,v,w,new_points)
new_points = np.array(new_points)
xn = new_points[:,0]
yn = new_points[:,1]
zn = new_points[:,2]
# PLOT
fig = plt.figure(dpi=300)
ax = fig.gca(projection='3d')
ax.quiver(xn, yn, zn, uint, vint, wint, length=0.1)
plt.show()
THE ISSUE
As you can see something is wrong with the interpolation function since the resulting vector plot does not show the same behavior as the original at all.
Here is a way to do it using RegularGridInterpolator:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import RegularGridInterpolator
def interp_field(field, coords, shape):
interpolator = RegularGridInterpolator(
(gridZ[:, 0, 0], gridY[0, :, 0], gridX[0, 0, :]), field)
return interpolator(coords).reshape(shape)
gridZ, gridY, gridX = np.mgrid[-0.8:1:3j, -0.8:1:10j, -0.8:1:10j]
u = np.sin(np.pi * gridX) * np.cos(np.pi * gridY) * np.cos(np.pi * gridZ)
v = -np.cos(np.pi * gridX) * np.sin(np.pi * gridY) * np.cos(np.pi * gridZ)
w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * gridX) * np.cos(np.pi * gridY) *
np.sin(np.pi * gridZ))
interp_gridZ, interp_gridY, interp_gridX = np.mgrid[
-0.8:1:3j, -0.8:1:20j, -0.8:1:20j]
interp_coords = np.column_stack(
(interp_gridZ.flatten(), interp_gridY.flatten(), interp_gridX.flatten()))
interp_u = interp_field(u, interp_coords, interp_gridX.shape)
interp_v = interp_field(v, interp_coords, interp_gridX.shape)
interp_w = interp_field(w, interp_coords, interp_gridX.shape)
fig, (ax, bx) = plt.subplots(ncols=2, subplot_kw=dict(projection='3d'),
constrained_layout=True)
ax.quiver(gridX, gridY, gridZ, u, v, w, length=0.3)
bx.quiver(interp_gridX, interp_gridY, interp_gridZ,
interp_u, interp_v, interp_w, length=0.3)
plt.show()
The resulting plot looks like that:

How to avoid plotting a line through a given point in Matplotlib?

I made an animation of an orbit that plots an orbit using an initial altitude and velocity.
Here is the code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import ode
import matplotlib.animation as animation
plt.style.use('dark_background')
mu_earth = 398600
# Planet radius, km
R = 6371
fig = plt.figure()
ax1 = fig.add_subplot(111)
orbit_alt = 500
v_mag = 7.7 # km/s
# time step (delta-time)
dt = 10
satellite_size = 100
r_mag = R + orbit_alt
v_esc = np.sqrt(2*mu_earth*1e9/(R*1000 + orbit_alt*1000))
earth = plt.Circle((0, 0), 6371, color='blue')
ax1.add_artist(earth)
def diff_eq(t, y):
rx, ry, vx, vy = y # state vectors
r = np.array([rx, ry])
radial_vector = np.linalg.norm(r)
ax, ay = -r * mu_earth / radial_vector ** 3
return [vx, vy, ax, ay]
# Initial states
r0 = [r_mag, 0]
v0 = [0, v_mag]
specific_energy = (v_mag * 1000 * v_mag * 1000) / 2 - ((mu_earth * 1e9) / ((R + orbit_alt) * 1000))
semi_major = -mu_earth * 1e9 / (2 * specific_energy)
orbit_period = 2 * np.pi * np.sqrt(semi_major ** 3 / (mu_earth * 1e9))
if v_mag * 1000 < v_esc:
tspan = 5 * orbit_period
else:
tspan = 1500000
eccen = ((v_mag * 1000) ** 2 * (r_mag)*1000)/(mu_earth*1e9) - 1
perigee = (semi_major * (1 - np.abs(eccen)))/1000
apogee = (semi_major * (1 + np.abs(eccen)))/1000
n_steps = int(np.ceil(tspan/dt))
ts = np.zeros((n_steps, 1))
ys = np.zeros((n_steps, 4))
ys0 = r0 + v0
ts[0] = 0
ys[0] = ys0
solver = ode(diff_eq)
solver.set_integrator('lsoda')
solver.set_initial_value(ys0, 0)
rs = ys[:, :2]
def animate(i):
solver.integrate(solver.t + dt)
ts[i] = solver.t
ys[i] = solver.y
point = plt.Circle((ys[i][0], ys[i][1]), satellite_size, facecolor=(1, 1, 1))
ax1.add_artist(point)
satellite, = ax1.plot(rs[:, 0], rs[:, 1], color='r', alpha = 1)
return satellite, point
ax1.set_xlim([-apogee, apogee])
ax1.set_ylim([-apogee, apogee])
ax1.set_xlabel('X (km)')
ax1.set_ylabel('Y (km)')
ax1.set_title("ORBIT SIMULATION")
plt.gca().set_aspect('equal', adjustable='box')
ani = animation.FuncAnimation(fig, animate, interval=0.01, blit=True)
plt.show()
And here is a screen shot of the output:
I want to omit the line that goes to the origin (0, 0). That line is a part of the satellite line object. What I believe is happening is that the origin is considered the first point, and the satellite is the second point, and matplotlib is connecting them. So how could that line leading to the middle be omitted?
The main problem is that your data is a full vector of zeros and your code plots the full dataset. Change from rs[:, 0] to rs[:, 0][:i] to only plot the points that have been simulated so far.
Second consideration is that FuncAnimation is usually used to update data already plotted. See small change below in animate(i).
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import ode
import matplotlib.animation as animation
plt.style.use('dark_background')
mu_earth = 398600
# Planet radius, km
R = 6371
fig = plt.figure()
ax1 = fig.add_subplot(111)
orbit_alt = 500
v_mag = 7.7 # km/s
# time step (delta-time)
dt = 10
satellite_size = 100
r_mag = R + orbit_alt
v_esc = np.sqrt(2*mu_earth*1e9/(R*1000 + orbit_alt*1000))
earth = plt.Circle((0, 0), 6371, color='blue')
ax1.add_artist(earth)
def diff_eq(t, y):
rx, ry, vx, vy = y # state vectors
r = np.array([rx, ry])
radial_vector = np.linalg.norm(r)
ax, ay = -r * mu_earth / radial_vector ** 3
return [vx, vy, ax, ay]
# Initial states
r0 = [r_mag, 0]
v0 = [0, v_mag]
specific_energy = (v_mag * 1000 * v_mag * 1000) / 2 - ((mu_earth * 1e9) / ((R + orbit_alt) * 1000))
semi_major = -mu_earth * 1e9 / (2 * specific_energy)
orbit_period = 2 * np.pi * np.sqrt(semi_major ** 3 / (mu_earth * 1e9))
if v_mag * 1000 < v_esc:
tspan = 5 * orbit_period
else:
tspan = 1500000
eccen = ((v_mag * 1000) ** 2 * (r_mag)*1000)/(mu_earth*1e9) - 1
perigee = (semi_major * (1 - np.abs(eccen)))/1000
apogee = (semi_major * (1 + np.abs(eccen)))/1000
n_steps = int(np.ceil(tspan/dt))
ts = np.zeros((n_steps, 1))
ys = np.zeros((n_steps, 4))
ys0 = r0 + v0
ts[0] = 0
ys[0] = ys0
solver = ode(diff_eq)
solver.set_integrator('lsoda')
solver.set_initial_value(ys0, 0)
rs = ys[:, :2]
orbit, = ax1.plot(rs[:, 0], rs[:, 1], color='r', alpha=1)
point = plt.Circle((ys[0][0], ys[0][1]), satellite_size, facecolor=(1, 1, 1))
ax1.add_artist(point)
def animate(i):
solver.integrate(solver.t + dt)
ts[i] = solver.t
ys[i] = solver.y
orbit.set_data(rs[:, 0][:i], rs[:, 1][:i])
point.set_center((ys[i][0], ys[i][1]))
return orbit, point
ax1.set_xlim([-apogee, apogee])
ax1.set_ylim([-apogee, apogee])
ax1.set_xlabel('X (km)')
ax1.set_ylabel('Y (km)')
ax1.set_title("ORBIT SIMULATION")
plt.gca().set_aspect('equal', adjustable='box')
ani = animation.FuncAnimation(fig, animate, interval=10, blit=True)
plt.show()

Why these two ODE solving program don't match?

I don't understand why this code (reference):
from numpy import zeros, linspace
import matplotlib.pyplot as plt
# Time unit: 1 h
beta = 10./(40*8*24)
gamma = 3./(15*24)
dt = 0.1 # 6 min
D = 30 # Simulate for D days
N_t = int(D*24/dt) # Corresponding no of hours
t = linspace(0, N_t*dt, N_t+1)
S = zeros(N_t+1)
I = zeros(N_t+1)
R = zeros(N_t+1)
# Initial condition
S[0] = 50
I[0] = 1
R[0] = 0
# Step equations forward in time
for n in range(N_t):
S[n+1] = S[n] - dt*beta*S[n]*I[n]
I[n+1] = I[n] + dt*beta*S[n]*I[n] - dt*gamma*I[n]
R[n+1] = R[n] + dt*gamma*I[n]
fig = plt.figure()
l1, l2, l3 = plt.plot(t, S, t, I, t, R)
fig.legend((l1, l2, l3), ('S', 'I', 'R'), 'upper left')
plt.xlabel('hours')
plt.show()
doesn't produce the same results as this code I made:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
beta = 10. / (40 * 8 * 24)
gamma = 3. / (15 * 24)
def flu(y, t):
S = y[0]
P = y[1]
R = y[2]
S = - beta * S * P
P = beta * S * P - gamma * P
R = gamma * P
return [S, P, R]
C_I = [50, 1, 0]
t = np.linspace(0, 1000, 1000)
y = odeint(flu, C_I, t)
S = y[:, 0]
P = y[:, 1]
R = y[:, 2]
fig, ax = plt.subplots()
ax.plot(t, S, 'b--', label='S')
ax.plot(t, P, 'r--', label='I')
ax.plot(t, R, 'g--', label='R')
legend = ax.legend(loc='upper right', shadow=True, fontsize='x-large')
legend.get_frame().set_facecolor('#FFFCCC')
plt.show()
I used P instead of I to avoid confusion.
The equations solved with odeint should be the same as the ones provided in the reference link above. And if the equations I use are correct, which I am convinced they are, I don't understand where the mistake(s) lie(s).
Thank you for your help
You set S=y[0] then you set S=- beta * S * P. This overwrites y[0]!!! Similar problems for P and R
Try this:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
beta = 10. / (40 * 8 * 24)
gamma = 3. / (15 * 24)
def flu(y, t):
S = y[0]
P = y[1]
R = y[2]
dS = - beta * S * P
dP = beta * S * P - gamma * P
dR = gamma * P
return [dS, dP, dR]
C_I = [50, 1, 0]
t = np.linspace(0, 1000, 1000)
y = odeint(flu, C_I, t)
S = y[:, 0]
P = y[:, 1]
R = y[:, 2]
fig, ax = plt.subplots()
ax.plot(t, S, 'b--', label='S')
ax.plot(t, P, 'r--', label='I')
ax.plot(t, R, 'g--', label='R')
legend = ax.legend(loc='upper right', shadow=True, fontsize='x-large')
legend.get_frame().set_facecolor('#FFFCCC')
plt.show()

Python plotting in 3d

How can I plot in 3D in python?
I am trying to plot orbital trajectories. Plotting Orbital Trajectories
From the link above, I was able to get help with setting up the function. However I don't know how to plot in 3D.
When this is run, it doesn't generate the correct trajectory.
Switching np.linspace to np.arnage cause a memory error and I am running this on a 64bit system running Xubuntu with 16 GB of Ram.
So I tried converting Distance Units and Time Units but something isn't correct. Maybe my math or something else.
I let 149.6 * 10 ** 6 = 1 DU. A TU is defined as mu = DU ** 3 / TU ** 2 so 1TU = 2241.15 and DU/TU = 66751.4 Using these conversion, I have: I also tried using x2,y2,z2 to see if that would work.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from numpy import linspace
from mpl_toolkits.mplot3d import Axes3D
mu = 1
# r0 = [-149.6 * 10 ** 6, 0.0, 0.0] # Initial position
# v0 = [29.9652, -5.04769, 0.0] # Initial velocity
u0 = [-1, 0.0, 0.0, 0.000448907, -0.0000756192, 0.0]
def deriv(u, dt):
n = -mu / np.sqrt(u[0] ** 2 + u[1] ** 2 + u[2] ** 2)
return [u[3], # dotu[0] = u[3]'
u[4], # dotu[1] = u[4]'
u[5], # dotu[2] = u[5]'
u[0] * n, # dotu[3] = u[0] * n
u[1] * n, # dotu[4] = u[1] * n
u[2] * n] # dotu[5] = u[2] * n
dt = np.arange(0.0, 20, .0001) # Time to run code in seconds'
u = odeint(deriv, u0, dt)
x, y, z, x2, y2, z2 = u.T
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(x2, y2, z2)
plt.show()
but this plot isn't correct either. It should be an ellipse that stays on the same trajectory.
#!/usr/bin/env python
# This program solves the 3 Body Problem numerically and plots the
# trajectories
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from numpy import linspace
from mpl_toolkits.mplot3d import Axes3D
mu = 132712000000.0
# r0 = [-149.6 * 10 ** 6, 0.0, 0.0] # Initial position
# v0 = [29.9652, -5.04769, 0.0] # Initial velocity
u0 = [-149.6 * 10 ** 6, 0.0, 0.0, 29.9652, -5.04769, 0.0]
def deriv(u, dt):
n = -mu / np.sqrt(u[0] ** 2 + u[1] ** 2 + u[2] ** 2)
return [u[3], # dotu[0] = u[3]'
u[4], # dotu[1] = u[4]'
u[5], # dotu[2] = u[5]'
u[0] * n, # dotu[3] = u[0] * n
u[1] * n, # dotu[4] = u[1] * n
u[2] * n] # dotu[5] = u[2] * n
dt = np.linspace(0.0, 86400 * 700, 5000) # Time to run code in seconds'
u = odeint(deriv, u0, dt)
x, y, z, x2, y2, z2 = u.T
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(x, y, z)
plt.show()
You can literally take the first several lines from that page that #sashkello, and plug in the x,y, and z that you got from the ode solver.
Copied from http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html :
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
#<<solve for x, y, z here>>#
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(x, y, z)
plt.show()

Categories