Interpolate 3D Vector Field with Python - python

The task
I would like to interpolate a 3D vector field using python.
intial grid -> asociated u,v,w
=> new grid --> compute associated u,v,w
What I have done so far:
Code to create a sample vector field:
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import RegularGridInterpolator
# REDUCED EXAMPLE
Nx = 8
Ny = 8
Nz = 3
grid = np.meshgrid(np.linspace(-1, 1, Nx),
np.linspace(-1, 1, Ny),
np.linspace(-1, 1, Nz))
x,y,z = grid
# CONSTRUCT u,v,w
u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z)
v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z)
w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) *
np.sin(np.pi * z))
fig = plt.figure(dpi=300)
ax = fig.gca(projection='3d')
ax.quiver(x, y, z, u, v, w, length=0.2)
plt.title("Reduced")
plt.show()
... I tried to create an interpolation function:
def interpolate_field(old_points,u,v,w,new_points):
# old points zip(x,y,z) where x,y,z linspace -> regular grid
# u,v,w each of shape (NX, NY, NZ)
# mew points np.array(list(zip(xx,yy,zz))) where xx,yy,zz np.meshgrid
x, y, z = old_points
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
..but when I try to apply it:+
# New grid
NNx = 20
NNy = 20
NNz = 3
grid = np.meshgrid(np.linspace(-1, 1, NNx),
np.linspace(-1, 1, NNy),
np.linspace(-1, 1, NNz))
# Reshape for interpolation function
u_reshape = np.reshape(u, (Nx, Ny, Nz))
v_reshape = np.reshape(v, (Nx, Ny, Nz))
w_reshape = np.reshape(w, (Nx, Ny, Nz))
old_points = (x,y,z)
new_points = np.vstack(list(map(np.ravel, grid))).T
u_int, v_int, w_int = interpolate_field(old_points,
u_reshape,
v_reshape,
w_reshape,
new_points)
I get the error:
ValueError: The points in dimension 0 must be strictly ascending

RegularGridInterpolator requires a tuple of points before the meshgrid was applied
Parameters points
tuple of ndarray of float, with shapes (m1, ), …,
(mn, ) The points defining the regular grid in n dimensions
So you can either pass in the grid beforehand:
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import RegularGridInterpolator
def interpolate_field(old_points,u,v,w,new_points):
# old points zip(x,y,z) where x,y,z linspace -> regular grid
# u,v,w each of shape (NX, NY, NZ)
# mew points np.array(list(zip(xx,yy,zz))) where xx,yy,zz np.meshgrid
x, y, z = old_points
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
# New grid
Nx = 20
Ny = 20
Nz = 3
x = np.linspace(-1, 1, Nx)
y = np.linspace(-1, 1, Ny)
z = np.linspace(-1, 1, Nz)
grid = np.meshgrid(x, y, z)
XX, YY, ZZ = grid
# CONSTRUCT u,v,w
u = np.sin(np.pi * XX) * np.cos(np.pi * YY) * np.cos(np.pi * ZZ)
v = -np.cos(np.pi * XX) * np.sin(np.pi * YY) * np.cos(np.pi * ZZ)
w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * XX) * np.cos(np.pi * YY) *
np.sin(np.pi * ZZ))
# Reshape for interpolation function
u_reshape = np.reshape(u, (Nx, Ny, Nz))
v_reshape = np.reshape(v, (Nx, Ny, Nz))
w_reshape = np.reshape(w, (Nx, Ny, Nz))
old_points = (x,y,z)
new_points = np.vstack(list(map(np.ravel, grid))).T
u_int, v_int, w_int = interpolate_field(old_points,
u_reshape,
v_reshape,
w_reshape,
new_points)
Or you can try and inverse the meshgrid from within the interpolate_field function
EDIT:
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import RegularGridInterpolator
def interpolate_field(old_points,u,v,w,new_points):
# old points zip(x,y,z) where x,y,z linspace -> regular grid
# u,v,w each of shape (NX, NY, NZ)
# mew points np.array(list(zip(xx,yy,zz))) where xx,yy,zz np.meshgrid
x, y, z = old_points
x = x[0, :, 0]
y = y[:, 0, 0]
z = z[0, 0, :]
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
# New grid
NNx = 20
NNy = 20
NNz = 3
x = np.linspace(-1, 1, NNx)
y = np.linspace(-1, 1, NNy)
z = np.linspace(-1, 1, NNz)
grid = np.meshgrid(np.linspace(-1, 1, NNx),
np.linspace(-1, 1, NNy),
np.linspace(-1, 1, NNz))
x,y,z = grid
# CONSTRUCT u,v,w
u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z)
v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z)
w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) *
np.sin(np.pi * z))
# Reshape for interpolation function
u_reshape = np.reshape(u, (NNx, NNy, NNz))
v_reshape = np.reshape(v, (NNx, NNy, NNz))
w_reshape = np.reshape(w, (NNx, NNy, NNz))
old_points = (x,y,z)
new_points = np.vstack(list(map(np.ravel, grid))).T
u_int, v_int, w_int = interpolate_field(old_points,
u_reshape,
v_reshape,
w_reshape,
new_points)
u_int = np.reshape(u_int, (NNx,NNy,NNz))
v_int = np.reshape(v_int, (NNx,NNy,NNz))
w_int = np.reshape(w_int, (NNx,NNy,NNz))
fig = plt.figure(dpi=300)
ax = fig.gca(projection='3d')
ax.quiver(x, y, z, u_int, v_int, w_int, length=0.2)
plt.title("Reduced")
plt.show()

Related

Contour plot of a multivariate function

I have a multivariate function
X is (2, 1), A(100, 2), and b is (100, 1).
How can I plot the contour plot of it in python? for a simple case like Z = X^2 + Y^2 I have this code, but I don't think it can work for my problem.
x, y = np.linspace(-3, 3, 400), np.linspace(-3, 3, 400)
XX, YY = np.meshgrid(x, y)
Z = (XX ** 2 + YY ** 2)
fig, ax = plt.subplots()
ax.contour(XX, YY, Z)
How can I plot contour of my function?
I assumed that in the pictured formula x is the same as X, which represents the coordinates of a point in a 2D plane.
Then, with np.meshgrid you create the usual grid of coordinates over which evaluating the function, xx and yy. At this points, you need to combine them into a matrix X of 2 rows (representing x and y coordinates) and as many columns as necessary.
Finally, you evaluate the function over each column of X.
import numpy as np
import matplotlib.pyplot as plt
# create example data
x = y = np.linspace(0, 2 * np.pi, 100)
A = np.stack([np.cos(x), np.sin(x * y)]).T
b = np.cbrt(x * y)
print("A.shape = ", A.shape)
print("b.shape = ", b.shape)
# define the function
f = lambda X: np.linalg.norm(b - A # X, 2)**2
# creates the coordinates over which the function
# will be evaluated
x = y = np.linspace(-np.pi, np.pi, 200)
xx, yy = np.meshgrid(x, y)
# assemble the coordinates into a "vector of coordinates"
X = np.stack([xx, yy]).reshape(2, -1)
print("X.shape = ", X.shape)
# apply the function f on each pair of coordinates
Z = np.apply_along_axis(f, 0, X).reshape(xx.shape)
print("Z.shape = ", Z.shape)
fig, ax = plt.subplots()
c = ax.contourf(xx, yy, Z)
fig.colorbar(c)
plt.show()

Is there a way to graph 3d points on a cylinder graph in python?

I'm in the process of graphing different color values based on their hue, lightness, and saturation as the xyz axis. It works pretty well with matplotlib, here's a pic.
But recently I saw an image of a graph on the internet that's cylinder based
I couldn't find any info on the internet about it, and it seems that matplotlib doesn't support making this kind of graph. Does anyone know of a way to plot scatter points on a cylinder graph in python?
In order to place points on the surface of a cylinder, you would have to parameterize the surface. This is one way:
import numpy as np
import matplotlib.pyplot as plt
def cylinder(R, z_min, z_max, theta_max, N):
z = np.random.uniform(z_min, z_max, N)
theta = np.random.uniform(0, theta_max, N)
x = R * np.cos(theta)
y = R * np.sin(theta)
return x, y, z
def dics(z, R_max, theta_max, N):
r = np.random.uniform(0, R_max, N)
theta = np.random.uniform(0, theta_max, N)
x = r * np.cos(theta)
y = r * np.sin(theta)
return x, y, z * np.ones_like(x)
def plane(theta, R_max, z_min, z_max, N):
r = np.random.uniform(0, R_max, N)
x = r * np.cos(theta)
y = r * np.sin(theta)
z = np.random.uniform(z_min, z_max, N)
return x, y, z
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection="3d")
N = 1000
z_min = -1
z_max = 1
R = 3
theta_max = 1.5 * np.pi
# points on the cylindrical surface
x_cyl, y_cyl, z_cyl = cylinder(R, z_min, z_max, theta_max, N)
ax.scatter(x_cyl, y_cyl, z_cyl)
# points on the top cap
x_top, y_top, z_top = dics(z_max, R, theta_max, N)
ax.scatter(x_top, y_top, z_top)
# points on the bottom cap
x_bottom, y_bottom, z_bottom = dics(z_min, R, theta_max, N)
ax.scatter(x_bottom, y_bottom, z_bottom)
# points on the first slice-wall
x1, y1, z1 = plane(0, R, z_min, z_max, N)
ax.scatter(x1, y1, z1)
# points on the second slice-wall
x2, y2, z2 = plane(theta_max, R, z_min, z_max, N)
ax.scatter(x2, y2, z2)
plt.show()
Then, you would have to modify the above functions to return the angle theta and the radius r, so that you can apply colors based on H, S, V, but that's left for you as an exercise :)
Edit: if you just want to plot scatter points into the volume of a sliced cylinder, you could modify the cylinder function in this way:
def cylinder(R, z_min, z_max, theta_max, N):
z = np.random.uniform(z_min, z_max, N)
theta = np.random.uniform(0, theta_max, N)
r = np.random.uniform(0, R, N)
x = r * np.cos(theta)
y = r * np.sin(theta)
return x, y, z

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:

Plotting 3D Vector Field

I am trying to plot a 3D vector field. I used the following example as guidance:
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2),
np.arange(-0.8, 1, 0.2),
np.arange(-0.8, 1, 0.8))
u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z)
v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z)
w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) *
np.sin(np.pi * z))
ax.quiver(x, y, z, u, v, w, length=0.1)
plt.show()
This example comes from the matplotlib examples library. However, I wanted to try a different function to replace u, v and w like this:
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
x,y,z = np.meshgrid(np.arange(-0.1,0.005,0.1),np.arange(-0.1,0.005,0.1),np.arange(-0.1,0.005,0.1))
VolMag = 3.218E-6 #Volume of magnet in experiment in m^3
BR = np.sqrt(x**2 + y**2 + z**2)
MagMoment = np.array([0,0,(BInput*VolMag)/u0])
Bx = (u0/(4*np.pi))*(3*x*MagMoment*z)/BR**5
By = (u0/(4*np.pi))*(3*y*MagMoment*z)/BR**5
Bz = (u0/(4*np.pi))*((3*z*MagMoment*(z**2)/BR**5 - MagMoment/BR**3)
ax.quiver(x,y,z,Bx,By,Bz,length=0.1)
plt.show()
This is giving me an "invalid syntax" error for line 16. Why is this? I only changed the function and some of the names of the definitions.
It looks like your missing a closing parenthesis on this line.
Bz = (u0/(4*np.pi))*((3*z*MagMoment*(z**2)/BR**5 - MagMoment/BR**3)
should be
Bz = (u0/(4*np.pi))*((3*z*MagMoment*(z**2)/BR**5 - MagMoment/BR**3))

Matplotlib plot pulse propagation in 3d

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

Categories