使用 matplotlib 从三个正交向量和大小绘制椭圆体,python

Plot an ellipsoid from three orthonormal vectors and the magnitudes using matplotlib, python

我有三个正交向量

(-0.460021, -0.241295, -0.854493), 
(-0.641846, 0.755344, 0.132244),
(-0.613526, -0.609288, 0.502348) 

以及沿每个方向 1.44, 3.452.02.

的星等值

如何绘制一个椭圆体(3D 表面)来表示沿正交向量的轴方向以及由它们的大小给出的轴长度?

如果我对你的问题的理解正确,你想创建一个椭圆体并旋转它,使其长轴与正交向量对齐。

注意:由于 Matplotlib 的 3D 功能相当有限,我将使用 Plotly:它可以让我们的生活更轻松,因为它提供了“相等”的纵横比对于 3D 图。您可以轻松地将绘图库更改为 Matplotlib。

椭圆体的参数方程can be found here

import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objects as go

# compute ellipsoid coordinates on standard basis
# e1=(1, 0, 0), e2=(0, 1, 0), e3=(0, 0, 1)
a, b, c = 1.44, 3.45, 2.02
u, v = np.mgrid[0:2*np.pi:40j, 0:np.pi:20j]
x1 = a * np.cos(u) * np.sin(v)
y1 = b * np.sin(u) * np.sin(v)
z1 = c * np.cos(v)
# points on the ellipsoid
points = np.stack([t.flatten() for t in [x1, y1, z1]])

v1 = np.array([-0.460021, -0.241295, -0.854493])
v2 = np.array([-0.641846, 0.755344, 0.132244])
v3 = np.array([-0.613526, -0.609288, 0.502348])
# 3x3 transformation matrix
T = np.array([v1, v2, v3]).T

# transform coordinates to the new orthonormal basis
new_points = T @ points
x2 = new_points[0, :]
y2 = new_points[1, :]
z2 = new_points[2, :]
x2, y2, z2 = [t.reshape(x1.shape) for t in [x2, y2, z2]]

# scale vector for better visualization
scale = 5
v1, v2, v3 = [scale * t for t in [v1, v2, v3]]

fig = go.Figure([
    # axis on the standard base
    go.Scatter3d(x=[0, 5], y=[0, 0], z=[0, 0], mode="lines", name="x1", line=dict(width=5, color="red")),
    go.Scatter3d(x=[0, 0], y=[0, 5], z=[0, 0], mode="lines", name="y1", line=dict(width=5, color="green")),
    go.Scatter3d(x=[0, 0], y=[0, 0], z=[0, 5], mode="lines", name="z1", line=dict(width=5, color="blue")),
    # axis on the new orthonormal base
    go.Scatter3d(x=[0, v1[0]], y=[0, v1[1]], z=[0, v1[2]], mode="lines", name="x2", line=dict(width=2, color="red")),
    go.Scatter3d(x=[0, v2[0]], y=[0, v2[1]], z=[0, v2[2]], mode="lines", name="y2", line=dict(width=2, color="green")),
    go.Scatter3d(x=[0, v3[0]], y=[0, v3[1]], z=[0, v3[2]], mode="lines", name="z2", line=dict(width=2, color="blue")),
    # original ellipsoid aligned to the standard base
    go.Surface(x=x1, y=y1, z=z1, opacity=0.35, colorscale="plotly3", surfacecolor=y1, cmin=y1.min(), cmax=y1.max(), colorbar=dict(len=0.6, yanchor="bottom", y=0)),
    # final ellipsoid aligned to the new orthonormal base
    go.Surface(x=x2, y=y2, z=z2, opacity=1, colorscale="aggrnyl", surfacecolor=y1, cmin=y1.min(), cmax=y1.max(), colorbar=dict(len=0.6, yanchor="bottom", y=0, x=0.95))
])
fig.update_layout({"scene": {"aspectmode": "auto"}})
fig