Matplotlib 3D绘图 - 从某些角度来看参数曲线“环绕”

时间:2016-04-13 19:47:52

标签: python python-2.7 matplotlib 3d astronomy

我一直在编写一个Python脚本(GitHub LINK),用于可视化小行星/彗星/流星体轨道。该剧本还绘制了行星及其轨道的位置。

它适用于具有小半长轴(即“较小”轨道)的轨道。但是当我的轨道超越海王星(例如哈雷型彗星)时,从某些角度来看,有一种奇怪的“环绕式”(因为没有更好的词)效果。

让我告诉你我的意思:

图片编辑: http://i.imgur.com/onSZG8s.png enter image description here

  1. 此图片从不破坏的角度显示情节。

  2. 当您向右旋转相同的情节时,就好像轨道折成两半并反转它的方向!

  3. 如果你从很远的距离观察情节,你可以看到椭圆是按原样绘制的。

  4. 这是代码的最小版本,可以用来复制问题。只有当摄像机的视角与大轨道紧密平行时,才会出现“环绕”。

    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()
    

    我对此有点傻眼,似乎无法找到合适的解决方案。我非常感谢一些帮助!

2 个答案:

答案 0 :(得分:0)

根据我的经验,

matplotlib对于复杂的3D绘图并不是很好(我对轴外值有类似的奇怪行为)。像mayavi这样的东西值得考虑,因为它是为3D绘图设计的......

blog中给出了一种可能的解决方法,基本上只需将轴值设置为所需轴的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

它删除了环绕声。

答案 1 :(得分:0)

我遇到了类似的问题,并希望让用户更友好。我将这个库中的所有函数移动到javascript并在Three.js中创建了一个webGL接口,它允许你在这里做你想要的,但也通过时间函数绘制小行星/彗星的位置和动画。只需要一个Web浏览器就可以使用它。看看:)

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