Python: 在球面上绘制点和圆

10
为了我在大学的一个项目部分,我正在尝试使用Python重新创建地球,并使用它来绘制特定位置的点,并绘制各种方向的圆,以便与我拥有的卫星数据对齐,以便从数据集中给出飞机在给定时间的位置表示。
我开始时只是绘制了一个线框,并在线框上绘制了我需要的点(都按照地球的比例和地理位置)。
我遇到的问题是,当我在一个类似球体的对象上绘制点,并在其上叠加地球的图像时,当旋转球体超过一定点时,这些点会消失。所以,首先的问题是:我如何防止它们消失?
其次,我似乎找不到任何方法来绘制以球体为中心的圆圈 - 例如,绕赤道的圆圈,然后利用相同的思路在球体表面绘制圆圈,以得到下面这样的图像:

Circles on the Earth

我知道这是来自谷歌地图,但我很好奇是否可以用Python来实现(我认为是可以的)。
我的当前代码是:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from itertools import product, combinations
import PIL

#Plot the Earth
f = plt.figure(1, figsize=(13,13))
ax = f.add_subplot(111, projection='3d')
u, v = np.mgrid[0:2*np.pi:30j, 0:np.pi:20j]
x=6371*np.cos(u)*np.sin(v)
y=6371*np.sin(u)*np.sin(v)
z=6371*np.cos(v)
ax.plot_wireframe(x, y, z, color="b")

#GES ground station @ Perth & AES @ KLIA

ax.scatter([-2368.8],[4881.1],[-3342.0],color="r",s=100)
ax.scatter([-1293.0],[6238.3],[303.5],color="k",s=100)

#Load earthmap with PIL
bm = PIL.Image.open('earthmap.jpg')
#It's big, so I'll rescale it, convert to array, and divide by 256 to get RGB values that matplotlib accept 
bm = np.array(bm.resize([d/3 for d in bm.size]))/256.

#d/1 is normal size, anything else is smaller - faster loading time on Uni HPC

#Coordinates of the image - don't know if this is entirely accurate, but probably close
lons = np.linspace(-180, 180, bm.shape[1]) * np.pi/180 
lats = np.linspace(-90, 90, bm.shape[0])[::-1] * np.pi/180 

#Repeat code specifying face colours 

x = np.outer(6371*np.cos(lons), np.cos(lats)).T
y = np.outer(6371*np.sin(lons), np.cos(lats)).T
z = np.outer(6371*np.ones(np.size(lons)), np.sin(lats)).T
ax.plot_surface(x, y, z, rstride=4, cstride=4, facecolors = bm)

plt.show()

如果有办法让点不再消失,并且在赤道上绘制一个圆圈,那就太好了!谢谢!

我猜你应该知道basemap,但是为了确认一下,你之前没有接触过吗?不确定它的旋转能力。然而,通过图像搜索,我发现了这个(相当差劲的)例子,它似乎展示了一个basemap投影在一个交互式的matplotlib窗口中。 - roganjosh
@roganjosh 不,我之前没有听说过这个,我会去了解一下。虽然,获取地球的图片并不是问题,更多的是当球体旋转到观察这些圆和点时它们消失了。 - Nyancoil
然而,basemap的问题在于它被设计用于在地球表面上绘制等高线等。因为它(潜在地)将所有要求打包在一个软件包中,所以与解决2个或更多不同软件包之间的冲突(例如PIL)相比,可能更容易使它们协调工作。如果您发现它具有您需要的功能,我会很感兴趣知道 :) - roganjosh
3
更好的例子,展示了在表面上绘制自定义点进行旋转:https://waterprogramming.wordpress.com/2013/11/02/python-makes-the-world-go-round/ - roganjosh
2
似乎basemap已经整合了隐藏在球体后面的点的功能。如果你想要使用纯matplotlib方法,你可以查看这里的问题 - ImportanceOfBeingErnest
不确定它是否有帮助,但是你可以看一下OpenGL库,可能会发现有用的见解。祝好。 - Lorenzo Bassetti
1个回答

0

我相信你问题的第一部分已经得到了解决。关于你问题的第二部分,你可以尝试以下方法:

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


# Creating an arbitrary sphere
f = plt.figure(1, figsize=(10, 10))
ax = f.add_subplot(111, projection='3d')
u, v = np.mgrid[0:2*np.pi:100j, 0:np.pi:100j]
x=np.cos(u)*np.sin(v)
y=np.sin(u)*np.sin(v)
z=np.cos(v)
ax.plot_surface(x, y, z, color="b", alpha=0.3) #low alpha value allows for better visualization of scatter points



def draw_circle_on_sphere(p:float, a:float, v:float):
    '''
        Parametric equation determined by the radius and angular positions (both polar and azimuthal relative to the z-axis) of the circle on the spherical surface
        Parameters:
            p (float): polar angle
            a (float): azimuthal angle
            v (float): radius is controlled by sin(v)
            
        Returns:
            Circular scatter points on a spherical surface
    '''
    
    u = np.mgrid[0:2*np.pi:30j]
    
    x = np.sin(v)*np.cos(p)*np.cos(a)*np.cos(u) + np.cos(v)*np.sin(p)*np.cos(a) - np.sin(v)*np.sin(a)*np.sin(u)
    y = np.sin(v)*np.cos(p)*np.sin(a)*np.cos(u) + np.cos(v)*np.sin(p)*np.sin(a) + np.sin(v)*np.cos(a)*np.sin(u)
    z = -np.sin(v)*np.sin(p)*np.cos(u) + np.cos(v)*np.cos(p)

    return ax.scatter(x, y, z, color="r")


_ = draw_circle_on_sphere(3*np.pi/2, np.pi/4, np.pi/4) # example

结果

查看结果


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