I am currently trying to visualize the focal shape of a lens using matplotlib, specifically the mplot3d toolbox. I obtained the data from fitting ellipses to a set of microscope images at different focal lengths as major major
and minor minor
radius, as well as the rotation angle ang
of said ellipses. From this, I'm generating x
, y
and z
arrays containing the coordinates of the ellipses like this.
i = 100
omega = np.linspace(0, 2 * np.pi, i, endpoint=True)
x = [major * np.cos(omega) * np.cos(np.deg2rad(ang + 90)) - minor * np.sin(omega) * np.sin(np.deg2rad(ang + 90)) for major, minor, ang in zip(maj_avg, min_avg, ang_avg)]
y = [major * np.cos(omega) * np.sin(np.deg2rad(ang + 90)) + minor * np.sin(omega) * np.cos(np.deg2rad(ang + 90)) for major, minor, ang in zip(maj_avg, min_avg, ang_avg)]
z = [np.full(i, zi) for zi in zs]
If I now plot the individual ellipses in 3D space, everything works as intended.
fig = plt.figure(figsize=(16, 12))
ax = fig.add_subplot(111, projection='3d')
for x_arr, y_arr, z_arr in zip(x, y, z):
ax.plot(x_arr, y_arr, z_arr)
plt.show()
What I am trying to do is generate a surface plot from this dataset which shows the focal shape of the lens. Up to now, I tried plot_surface
together with meshgrid
/ griddata
like this:
xi = np.arange(-300, 300, 0.1)
yi = np.arange(-300, 300, 0.1)
xgrid, ygrid = np.meshgrid(xi, yi)
zgrid = griddata(np.ravel(x), np.ravel(y), np.ravel(z), xi, yi, interp='linear')
fig = plt.figure(figsize=(16, 12))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(xgrid, ygrid, zgrid)
plt.show()
And also plot_trisurf
is giving similarly unsatisfactory results:
triang = mtri.Triangulation(np.ravel(x), np.ravel(y))
fig = plt.figure(figsize=(16, 12))
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(triang, np.ravel(z), cmap=plt.cm.CMRmap)
plt.show()
Could someone suggest a way to properly show the high-z region of my dataset in the surface plots?
The problem is that you are trying to interpolate a parametric curve on a grid. Since the shape to draw is a non-bijective, non-sujective one, you get a complete mess.
Instead of trying to interpolate the points you may directly plot them.
X = np.array(x)
Y = np.array(y)
Z = np.array(z)
ax.plot_surface(X,Y,Z, cmap="RdYlBu")
plt.show()
Complete example for reproduction:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
maj_avg = 50*(np.linspace(0,1,20)-0.6)**2+50
min_avg = 60*(np.linspace(0,1,20)-0.7)**2+60
ang_avg = np.linspace(0,90,20)
zs = np.arange(0,40,2)
i = 100
omega = np.linspace(0, 2 * np.pi, i, endpoint=True)
x = [major * np.cos(omega) * np.cos(np.deg2rad(ang + 90)) \
- minor * np.sin(omega) * np.sin(np.deg2rad(ang + 90)) \
for major, minor, ang in zip(maj_avg, min_avg, ang_avg)]
y = [major * np.cos(omega) * np.sin(np.deg2rad(ang + 90)) \
+ minor * np.sin(omega) * np.cos(np.deg2rad(ang + 90)) \
for major, minor, ang in zip(maj_avg, min_avg, ang_avg)]
z = [np.full(i, zi) for zi in zs]
fig = plt.figure(figsize=(16, 12))
ax = fig.add_subplot(111, projection='3d')
#for x_arr, y_arr, z_arr in zip(x, y, z):
# ax.plot(x_arr, y_arr, z_arr)
X = np.array(x)
Y = np.array(y)
Z = np.array(z)
ax.plot_surface(X,Y,Z, cmap="RdYlBu")
plt.show()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.