Matplotlib 3D绘图-特定视角下的参数曲线“环绕”

4
我一直在编写一份Python脚本(GitHub LINK),用于可视化小行星/彗星/流星体的轨道。该脚本还绘制了行星及其轨道的位置。
它对于半长轴较小(即“更小”的轨道)的轨道运行得非常正常。但是当我有一个远超海王星的轨道时(例如哈雷彗星的轨道),从某些角度看,会出现奇怪的“环绕”效果(缺乏更好的词语)。
让我向您展示我的意思: 图像合成:http://i.imgur.com/onSZG8s.png enter image description here
  1. 这张图片展示了一个不会断裂的视角下的图表。

  2. 当你将同样的图表向右旋转一点时,就好像轨道折叠了一半并且反向了它的方向!

  3. 如果你从远处观察图表,你可以看到椭圆如预期一样被绘制出来。

这里是一个最小化的代码版本,可以重现问题。只有在相机的视角与大轨道近乎平行时才会出现“环绕”。

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

def orbitalElements2Cartesian(a, e, I, peri, node, E):
    """ Convert orbital elements to Cartesian coordinates in the Solar System.

    Args: 
        a (float): semi-major axis (AU)
        e (float): eccentricity
        I (float): inclination (degrees)
        peri (float): longitude of perihelion (degrees)
        node (float): longitude of ascending node (degrees)
        E (float): eccentric anomaly (radians)

    """

    # The source of equations used:
    # http://farside.ph.utexas.edu/teaching/celestial/Celestialhtml/node34.html

    # Check if the orbit is parabolic or hyperbolic
    if e >=1:
        e = 0.99999999

    # Convert degrees to radians
    I, peri, node = map(np.radians, [I, peri, node])

    # True anomaly
    theta = 2*np.arctan(np.sqrt((1.0 + e)/(1.0 - e))*np.tan(E/2.0))

    # Distance from the Sun to the poin on orbit
    r = a*(1.0 - e*np.cos(E))

    # Cartesian coordinates
    x = r*(np.cos(node)*np.cos(peri + theta) - np.sin(node)*np.sin(peri + theta)*np.cos(I))
    y = r*(np.sin(node)*np.cos(peri + theta) + np.cos(node)*np.sin(peri + theta)*np.cos(I))
    z = r*np.sin(peri + theta)*np.sin(I)

    return x, y, z


if __name__ == '__main__':

    # Example orbital elements
    # a, e, incl, peri, node
    orb_elements = np.array([
        [2.363, 0.515, 4.0, 205.0, 346.1],
        [0.989, 0.089, 3.1, 55.6, 21.2],
        [0.898, 0.460, 1.3, 77.1, 331.2],
        [104.585332285, 0.994914, 89.3950, 130.8767, 282.4633]
        ])

    # Setup the plot
    fig = plt.figure()
    ax = fig.gca(projection='3d')


    # Eccentric anomaly (full range)
    E = np.linspace(-np.pi, np.pi, 100)

    # Plot the given orbits
    for i, orbit in enumerate(orb_elements):
        a, e, I, peri, node = orbit

        # Take extra steps in E if the orbit is very large
        if a > 50:
            E = np.linspace(-np.pi, np.pi, (a/20.0)*100)

        # Get the orbit in the cartesian space
        x, y, z = orbitalElements2Cartesian(a, e, I, peri, node, E)

        # Plot orbits
        ax.plot(x, y, z, c='#32CD32')

    # Add limits (in AU)
    ax.set_xlim3d(-5,5)
    ax.set_ylim3d(-5,5)
    ax.set_zlim3d(-5,5)

    plt.tight_layout()
    plt.show()

我对此感到有些困惑,似乎找不到合适的解决方案。非常感谢您的帮助!


请提供一个最小的示例(内联)以重现此问题。 - tacaswell
@tcaswell 谢谢您的建议!我已经编辑了帖子。 - D Vida
渲染之前看起来像是错误的剪裁曲线。那两条贯穿整个屏幕的大线很可能是曲线与投影平面相交的两个线段。一个点可见或非常接近可见区域,而第二个点则不是。由于该线段没有被剪裁掉,因此即使它很可能在摄像机后面(这就是为什么它被镜像的原因),它也会通过屏幕进行渲染和插值。至少这是我的猜测。尝试只渲染完全可见的线段。 - Spektre
@Spektre 看起来我应该向Matplotlib开发人员提交一个关于这个问题的错误报告,这似乎不是一个次要的错误。 - D Vida
@DVida 很可能只是在剔除测试中的某个地方出现了错误的剔除索引+/-1,或者根本没有进行剔除(而这些线条只是来自不同扫描线的越界访问),一个单独的 if 就可以修复它。所以很可能只是一个小错误。我自己使用 GDI 或 OpenGL 渲染这样的东西,没有任何问题,但至少我知道我在做什么。今天大多数人都使用库/框架来处理任何琐碎的事情,失去了背后的知识。 - Spektre
对于任何遇到这个问题的人,OP在GitHub上开了一个问题,链接在这里:https://github.com/matplotlib/matplotlib/issues/6305,同时也有一个开放的PR来修复这个bug。 - undefined
2个回答

0
我曾经遇到过类似的问题,想要做出更加用户友好的东西。于是我将这个库中的所有函数都转移到了JavaScript,并在Three.js中创建了一个WebGL接口,让你可以在这里做你想做的事情,同时通过时间函数以动画方式绘制小行星/彗星的位置。只需要一个网络浏览器就可以使用它。来试试吧 :)

http://rankinstudio.com/asteroids/asteroids.html


0

matplotlib 在我看来不太适合复杂的三维图表(我曾经遇到过类似的轴值异常行为)。像 mayavi 这样的工具可能值得考虑,因为它专门用于三维图表...

这个 博客 中提供了一个可能的解决方法,基本上只需将所需轴的超出范围的值设置为 np.NaN。如果我在你的示例中添加以下内容,

for r in [x,y,z]:
    for i in np.arange(len(r)):
        if r[i] < -5:
            x[i] = np.NaN
            y[i] = np.NaN
            z[i] = np.NaN
        elif r[i] > 5:
            x[i] = np.NaN
            y[i] = np.NaN
            z[i] = np.NaN
        else:
            pass

它移除了包装。


Mayavi看起来很有前途,谢谢!现在裁剪超出某个任意限制的所有内容的问题是,当您从某个特定角度查看轨道时,您会发现它被裁剪了,这对于轨道可视化来说实际上是不可接受的。这可能意味着轨道可能是抛物线或双曲线,而不是椭圆形的。尽管如此,还是谢谢您的答案! - D Vida

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接