【问题标题】:Plotting Ellipsoid with Matplotlib用 Matplotlib 绘制椭球体
【发布时间】:2021-04-23 19:03:43
【问题描述】:

有人有绘制椭球的示例代码吗?在matplotlib 站点上有一个用于球体,但没有用于椭球体。我正在尝试绘制

x**2 + 2*y**2 + 2*z**2 = c

其中c 是一个定义椭圆体的常数(如10)。我尝试了meshgrid(x,y) 路线,重新设计了方程式,所以z 在一侧,但sqrt 是一个问题。 matplotlib 球体示例适用于角度 u,v,但我不确定如何将其用于椭球体。

【问题讨论】:

  • @tillsten:您提供的参考资料描述了如何绘制椭圆,而问题是关于椭圆体,这是三个-椭圆的尺寸等价物。
  • EOL:你说得对,我会删除我的评论。

标签: python matplotlib


【解决方案1】:

这是通过球坐标实现的方法:

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=plt.figaspect(1))  # Square figure
ax = fig.add_subplot(111, projection='3d')

coefs = (1, 2, 2)  # Coefficients in a0/c x**2 + a1/c y**2 + a2/c z**2 = 1 
# Radii corresponding to the coefficients:
rx, ry, rz = 1/np.sqrt(coefs)

# Set of all spherical angles:
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)

# Cartesian coordinates that correspond to the spherical angles:
# (this is the equation of an ellipsoid):
x = rx * np.outer(np.cos(u), np.sin(v))
y = ry * np.outer(np.sin(u), np.sin(v))
z = rz * np.outer(np.ones_like(u), np.cos(v))

# Plot:
ax.plot_surface(x, y, z,  rstride=4, cstride=4, color='b')

# Adjustment of the axes, so that they all have the same span:
max_radius = max(rx, ry, rz)
for axis in 'xyz':
    getattr(ax, 'set_{}lim'.format(axis))((-max_radius, max_radius))

plt.show()

结果图类似于

上面的程序实际上产生了一个更好看的“方形”图形。

此解决方案的灵感来自 Matplotlib's gallery 中的 example

【讨论】:

  • 感谢您的回答。然而,轴调整线给了我一个错误,“AttributeError:'Axes3DSubplot'对象没有属性'set_zlim'”。是不是因为我使用的是旧版本的 matplotlib(我使用的是 1.0.1)
  • 是的,这就是问题所在。我升级到 1.1.0,现在一切正常。
  • rx, ry, rz = 1/np.sqrt(coef) 应该是 rx, ry, rz = 1/np.sqrt(coefs)
  • 如果我有半长轴作为a和c,半短轴作为b,系数会是(1/a2,1/b2,1/ c**2) ?
  • 是的。当然在那种情况下你可以直接做rx, ry, rz = a, b, c(不需要系数coefs)。
【解决方案2】:

以 EOL 的回答为基础。有时你有一个矩阵格式的椭球:

A 和 c 其中 A 是椭球矩阵,c 是表示椭球中心的向量。

import numpy as np
import numpy.linalg as linalg
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# your ellispsoid and center in matrix form
A = np.array([[1,0,0],[0,2,0],[0,0,2]])
center = [0,0,0]

# find the rotation matrix and radii of the axes
U, s, rotation = linalg.svd(A)
radii = 1.0/np.sqrt(s)

# now carry on with EOL's answer
u = np.linspace(0.0, 2.0 * np.pi, 100)
v = np.linspace(0.0, np.pi, 100)
x = radii[0] * np.outer(np.cos(u), np.sin(v))
y = radii[1] * np.outer(np.sin(u), np.sin(v))
z = radii[2] * np.outer(np.ones_like(u), np.cos(v))
for i in range(len(x)):
    for j in range(len(x)):
        [x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], rotation) + center

# plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(x, y, z,  rstride=4, cstride=4, color='b', alpha=0.2)
plt.show()
plt.close(fig)
del fig

所以,这里没有太多新内容,但如果您有一个旋转的矩阵形式的椭球,并且可能不以 0,0,0 为中心并且想要绘制它,那么它会很有帮助。

【讨论】:

  • 嗨,为什么你需要计算奇异值的平方根,而不是平方根,才能得到半径?我的意思是为什么半径 = 1.0/np.sqrt(s) 而不是半径 = np.sqrt(s)。我认为后者给出了正确的半径。
  • 您根本不需要任何这种复杂的数学运算,至少不需要 SVD。协方差矩阵的全部意义在于,如果将球体乘以它,就会得到椭圆。
  • 我已经发布了一个答案来说明我的意思。
【解决方案3】:

如果您有一个由任意协方差矩阵cov 和偏移量bias 指定的椭球体,您确实不需要需要找出椭球体的直观参数来获得形状。具体来说,您不需要单独的轴或旋转。矩阵的全部意义在于它将单位球体(由单位矩阵表示)转换为椭圆。

开始

u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)

制作一个单位球体

x = np.outer(np.cos(u), np.sin(v))
y = np.outer(np.sin(u), np.sin(v))
z = np.outer(np.ones_like(u), np.cos(v))

现在变换球体:

ellipsoid = (cov @ np.stack((x, y, z), 0).reshape(3, -1) + bias).reshape(3, *x.shape)

您可以像以前一样绘制结果:

ax.plot_surface(*ellipsoid, rstride=4, cstride=4, color='b', alpha=0.75)

【讨论】:

  • 当我这样做时,我得到一个样本协方差椭球,它比采样点大很多。有没有办法将其缩放到置信区间?
  • @Translunar。任何标量乘数在矩阵上都有效
  • 这个答案有点小技巧 取零均值随机向量 X,协方差矩阵为 C = 。 C可以分解为RLR',其中R是特征向量的旋转矩阵,L是特征值的对角矩阵。对于 S = \sqrt{L},我们有 C = RSS'R'$。假设 N 是一个正常的随机向量,使得 = I。我们可以通过 X = RSN 将 N 转换为 X。这得到了证实,因为 = = RS S'R' = RSIS' R' = C。所以要完成的“正确”转换是 X = RSN .
  • 但是,在这种情况下,您可以侥幸成功,因为我们的“数据集”是球体上的点。当你对它执行 R' 时,你会得到相同的点集,所以你的转换 C = RSS'R' 实际上是转换 RSS'。这几乎是应该的 RS,您只需将数据缩放两次 S 而不是一次。这就是为什么 Translunar 抱怨协方差椭球没有适当地缩放到数据。所以这个方法确实给你一个几乎正确形状的椭圆体,但就像我说的那样,它有点小技巧。
猜你喜欢
  • 2016-02-06
  • 1970-01-01
  • 2016-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-14
相关资源
最近更新 更多