How to plot Ekman spiral curve in 2-D figure (u-v plot)
I have the following equation:
z = rang from (-228,0)
u = V0*cos(alpha*z + 3*pi/4)*e^(alpha*z)
v = V0*sin(alpha*z + 3*pi/4)*e^(alpha*z)
V0 = 0.1314; alpha = 0.013738, Az = 0.1, f = 3.775e-05
How could I use these equation to plot this figure?
from numpy import cos, sin, e, pi, linspace
import matplotlib.pyplot as plt
z = linspace(-228,0,1000)
V0 = 0.1314
alpha = 0.013738
u = V0*cos(alpha*z + 3*pi/4)*e**(alpha*z)
v = V0*sin(alpha*z + 3*pi/4)*e**(alpha*z)
plt.plot(u,v)
plt.show()
Related
Here is a Hopf torus created in Python with PyVista:
import numpy as np
import pyvista as pv
A = 0.44
n = 3
def Gamma(t):
alpha = np.pi/2 - (np.pi/2-A)*np.cos(n*t)
beta = t + A*np.sin(2*n*t)
return np.array([
np.sin(alpha) * np.cos(beta),
np.sin(alpha) * np.sin(beta),
np.cos(alpha)
])
def HopfInverse(p, phi):
return np.array([
(1+p[2])*np.cos(phi),
p[0]*np.sin(phi) - p[1]*np.cos(phi),
p[0]*np.cos(phi) + p[1]*np.sin(phi),
(1+p[2])*np.sin(phi)
]) / np.sqrt(2*(1+p[2]))
def Stereo(q):
return 2*q[0:3] / (1-q[3])
def F(t, phi):
return Stereo(HopfInverse(Gamma(t), phi))
angle = np.linspace(0, 2*np.pi, 300)
angle2 = np.linspace(0, np.pi, 150)
theta, phi = np.meshgrid(angle, angle2)
x, y, z = F(theta, phi)
# Display the mesh
grid = pv.StructuredGrid(x, y, z)
grid.plot(smooth_shading=True)
I would like to add a palette of colors to this surface. The torus is centered at the origin (0,0,0). I would like to have a color in function of the distance to the origin.
With Matplotlib, I do:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.colors as mcolors
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
A = 0.44
n = 3
......
colorfunction = (X**2+Y**2+Z**2)
norm = mcolors.Normalize(colorfunction.min(),colorfunction.max())
# Display the mesh
fig = plt.figure()
ax = fig.gca(projection = '3d')
ax.plot_surface(z, x, y, rstride = 1, cstride = 1, facecolors=cm.jet(norm(colorfunction)))
plt.show()
EDIT
I have a solution, but I don't control the colors:
grid = pv.StructuredGrid(x, y, z)
grid['Data'] = grid.points
grid.plot(smooth_shading=True, scalars="Data")
As a side note, at least to me it's clearer to compute the magnitude of the points yourself and set those as scalars (rather than relying on the magnitude of vector data as scalars for colour mapping, even though this is supported and valid).
What you're missing is just a choice of colourmap. The default, just like with matplotlib, is viridis. Instead it seems you want jet (although I'd recommend against this; perceptually uniform colourmaps are preferable in most cases for data visualization):
import numpy as np
import pyvista as pv
A = 0.44
n = 3
def Gamma(t):
alpha = np.pi/2 - (np.pi/2-A)*np.cos(n*t)
beta = t + A*np.sin(2*n*t)
return np.array([
np.sin(alpha) * np.cos(beta),
np.sin(alpha) * np.sin(beta),
np.cos(alpha)
])
def HopfInverse(p, phi):
return np.array([
(1+p[2])*np.cos(phi),
p[0]*np.sin(phi) - p[1]*np.cos(phi),
p[0]*np.cos(phi) + p[1]*np.sin(phi),
(1+p[2])*np.sin(phi)
]) / np.sqrt(2*(1+p[2]))
def Stereo(q):
return 2*q[0:3] / (1-q[3])
def F(t, phi):
return Stereo(HopfInverse(Gamma(t), phi))
angle = np.linspace(0, 2 * np.pi, 300)
theta, phi = np.meshgrid(angle, angle)
x, y, z = F(theta, phi)
grid = pv.StructuredGrid(x, y, z)
# convert to PolyData and clean to remove the seam
cleaned_poly = grid.extract_geometry().clean(tolerance=1e-6)
# add distance from origin as scalars
cleaned_poly.point_data['distance'] = np.linalg.norm(cleaned_poly.points, axis=1)
# this also makes these the default scalars
cleaned_poly.plot(smooth_shading=True, cmap='jet') # but don't use jet if possible
Am trying to create a 3D plot in Python where I have an FFT on the XY plane and a parameter on the Z axis
import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft, ifft
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
from scipy.signal import blackman
Nmax=64 # length of logistic series and no of FFT bins
w = blackman(Nmax) # blackman window for FFT
def fourier_of_logmap(k, r): # returns kth element in spectrum for given r
x_0 = 0.5
x_n = x_0
n_0 = 0
n = n_0
x_values = []
while n < Nmax:
y = r*x_n*(1-x_n)
x_values.append(x_n)
n = n + 1
x_n = y
fourier = np.log(abs(fft(w*x_values)))
return fourier[k]
test = fourier_of_logmap(20,3.7) #test if function is working
k_values = np.linspace(0, Nmax-1, Nmax)
r_values = np.linspace(0,4,100)
K, R = np.meshgrid(k_values, r_values)
A = fourier_of_logmap(K, R)
'Plot 3d surface'
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(K, R, A, cmap=cm.coolwarm, linewidth=0, antialiased=False)
plt.show()
Testing the function with 'test' returns a float as desired. However when applied to (K, R) I get "ValueError: setting an array element with a sequence". Yet when I replace fourier_of_logmap with a simple function like K + R it runs fine. Why is this happening?
[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.
so my question is how to make a polar plot r = f(theta) for a function f by calculating r for a range of values of theta and then converting r and theta to Cartesian coordinates using equations x = r cos(theta) , y = r sin(theta).
BUT I need to plot the spiral r = (theta)^2 for 0 <= theta <= 10*pi
this is what I have so far....not getting a spiral here.
#! /usr/bin/env python
import matplotlib.pyplot as plt
from math import cos, sin, pi
from numpy import linspace
for theta in linspace(0,10*pi):
r = ((theta)**2)
x = r*cos(theta)
y = r*sin(theta)
plt.plot(x,y)
plt.savefig("spiral.png")
plt.show()
You need to create a list of values, not just a single point. In your case, you keep calculating x and y, but never save them anywhere. So all you are plotting is the pair (x,y) after the last iteration.
x = []
y = []
for theta in linspace(0,10*pi):
r = ((theta)**2)
x.append(r*cos(theta))
y.append(r*sin(theta))
plt.plot(x,y)
plt.show()
Output
import numpy as np
import matplotlib.pyplot as plt
theta = np.radians(np.linspace(0,360*5,1000))
r = theta**2
x_2 = r*np.cos(theta)
y_2 = r*np.sin(theta)
plt.figure(figsize=[10,10])
plt.plot(x_2,y_2)
plt.show()
I'm trying to plot a contour plot in matplotlib and I keep getting a missing "wedge". The following example illustrates what I'm trying to do.
import numpy as np
import matplotlib.pyplot as plt
ph_cut = 0.05
nphi = 13
phi = np.linspace(ph_cut,2*np.pi-ph_cut, nphi)
nr = 50
rmax=1
rr = np.linspace(0, rmax, nr)
PH, RR = np.meshgrid(phi,rr)
X = RR * np.cos(PH)
Y = RR * np.sin(PH)
Z = np.sin(PH)
nlev = 13
levels=np.linspace(-1, 1, nlev)
cs=plt.contourf(X,Y,Z, levels)
plt.colorbar(cs)
plt.show()
The wedge between -ph_cut and ph_cut is never filled. Is there no way for matplotlib to interpolate across? Strictly speaking, this region is no different and has no less information than the corresponding pi-ph_cut to pi+ph_cut... I tried searching around but could not find any solution.
Just don't leave out the cut:
import numpy as np
import matplotlib.pyplot as plt
ph_cut = 0.05
nphi = 13
phi = np.linspace(0,2*np.pi, nphi)
nr = 50
rmax=1
rr = np.linspace(0, rmax, nr)
PH, RR = np.meshgrid(phi,rr)
X = RR * np.cos(PH)
Y = RR * np.sin(PH)
Z = np.sin(PH)
nlev = 13
levels=np.linspace(-1, 1, nlev)
cs=plt.contourf(X,Y,Z, levels)
plt.colorbar(cs)
plt.show()