我想在笛卡尔坐标x,y,z中绘制由3D矢量给出的数据表面。数据不能用平滑函数表示。
首先,我们使用函数eq_points(N_count, r)
生成一些伪数据,它返回一个数组points
,其中包含对象表面上每个点的x,y,z坐标。数量omega
是立体角,现在不感兴趣。
#credit to Markus Deserno from MPI
#https://www.cmu.edu/biolphys/deserno/pdf/sphere_equi.pdf
def eq_points(N_count, r):
points = []
a = 4*np.pi*r**2/N_count
d = np.sqrt(a)
M_theta = int(np.pi/d)
d_theta = np.pi/M_theta
d_phi = a/d_theta
for m in range(M_theta):
theta = np.pi*(m+0.5)/M_theta
M_phi = int(2*np.pi*np.sin(theta)/d_phi)
for n in range(M_phi):
phi = 2*np.pi*n/M_phi
points.append(np.array([r*np.sin(theta)*np.cos(phi),
r*np.sin(theta)*np.sin(phi),
r*np.cos(theta)]))
omega = 4*np.pi/N_count
return np.array(points), omega
#starting plotting sequence
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
points, omega = eq_points(400, 1.)
ax.scatter(points[:,0], points[:,1], points[:,2])
ax.scatter(0., 0., 0., c="r")
ax.set_xlabel(r'$x$ axis')
ax.set_ylabel(r'$y$ axis')
ax.set_zlabel(r'$Z$ axis')
plt.savefig("./sphere.png", format="png", dpi=300)
plt.clf()
结果是下图所示的球体。 蓝点标记来自points
数组的数据,而红点是原点。
我想得到像这样的东西
取自here。但是,mplot3d教程中的数据始终是平滑功能的结果。除了我用于球体图的ax.scatter()
函数。
所以最后我的目标是绘制一些只显示其表面的数据。通过改变到每个蓝点原点的径向距离来产生该数据。此外,有必要确保每个点与表面接触。如何绘制here的表面,例如在plot_surface()
详细构建?一些实际的实时数据如下所示:
答案 0 :(得分:3)
我建议找到船体,然后绘制单体(即形成船体的三角形)。确保适当更新x,y,z限制。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from scipy.spatial import ConvexHull
N = 1000
pts = np.random.randn(N, 3)
# exclude outliers
# obviously, this is data dependent
cutoff = 3.
is_outlier = np.any(np.abs(pts) > cutoff, axis=1)
pts = pts[~is_outlier]
# plot points
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(pts[:,0], pts[:,1], pts[:,2])
ax.set_xlim(-(cutoff +1), cutoff+1)
ax.set_ylim(-(cutoff +1), cutoff+1)
ax.set_zlim(-(cutoff +1), cutoff+1)
# get and plot hull
hull = ConvexHull(pts)
fig = plt.figure()
ax = Axes3D(fig)
vertices = [pts[s] for s in hull.simplices]
triangles = Poly3DCollection(vertices, edgecolor='k')
ax.add_collection3d(triangles)
ax.set_xlim(-(cutoff +1), cutoff+1)
ax.set_ylim(-(cutoff +1), cutoff+1)
ax.set_zlim(-(cutoff +1), cutoff+1)
plt.show()
答案 1 :(得分:1)
使用新规范解决问题,即所有点都触及表面。假设角度由用户设置,如示例所示,通过计算由单位球面上的点以相同角度形成的船体的单纯形状,很容易预先计算形成表面的单线的点的指数。如在感兴趣的数据集中。然后我们可以使用这些指数来获得感兴趣的表面。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from scipy.spatial import ConvexHull
def eq_points(N_count, r):
points = []
a = 4*np.pi*r**2/N_count
d = np.sqrt(a)
M_theta = int(np.pi/d)
d_theta = np.pi/M_theta
d_phi = a/d_theta
for m in range(M_theta):
theta = np.pi*(m+0.5)/M_theta
M_phi = int(2*np.pi*np.sin(theta)/d_phi)
for n in range(M_phi):
phi = 2*np.pi*n/M_phi
points.append(np.array([r*np.sin(theta)*np.cos(phi),
r*np.sin(theta)*np.sin(phi),
r*np.cos(theta)]))
omega = 4*np.pi/N_count
return np.array(points), omega
def eq_points_with_random_radius(N_count, r):
points = []
a = 4*np.pi*r**2/N_count
d = np.sqrt(a)
M_theta = int(np.pi/d)
d_theta = np.pi/M_theta
d_phi = a/d_theta
for m in range(M_theta):
theta = np.pi*(m+0.5)/M_theta
M_phi = int(2*np.pi*np.sin(theta)/d_phi)
for n in range(M_phi):
phi = 2*np.pi*n/M_phi
rr = r * np.random.rand()
points.append(np.array([rr*np.sin(theta)*np.cos(phi),
rr*np.sin(theta)*np.sin(phi),
rr*np.cos(theta)]))
omega = 4*np.pi/N_count
return np.array(points), omega
N = 400
pts, _ = eq_points(N, 1.)
pts_rescaled, _ = eq_points_with_random_radius(N, 1.)
extremum = 2.
# plot points
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(pts_rescaled[:,0], pts_rescaled[:,1], pts_rescaled[:,2])
ax.set_xlim(-extremum, extremum)
ax.set_ylim(-extremum, extremum)
ax.set_zlim(-extremum, extremum)
# get indices of simplices making up the surface using points on unit sphere;
# index into rescaled points
hull = ConvexHull(pts)
vertices = [pts_rescaled[s] for s in hull.simplices]
fig = plt.figure()
ax = Axes3D(fig)
triangles = Poly3DCollection(vertices, edgecolor='k')
ax.add_collection3d(triangles)
ax.set_xlim(-extremum, extremum)
ax.set_ylim(-extremum, extremum)
ax.set_zlim(-extremum, extremum)
plt.show()