gpt4 book ai didi

python-2.7 - 类似于Matplotlib-Basemap的3D CartoPy

转载 作者:行者123 更新时间:2023-12-02 22:35:25 24 4
gpt4 key购买 nike

我是Python的新手,但有一个关于Cartopy能否在3D图中使用的问题。以下是使用matplotlibBasemap的示例。

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.basemap import Basemap

m = Basemap(projection='merc',
llcrnrlat=52.0,urcrnrlat=58.0,
llcrnrlon=19.0,urcrnrlon=40.0,
rsphere=6371200.,resolution='h',area_thresh=10)

fig = plt.figure()
ax = Axes3D(fig)
ax.add_collection3d(m.drawcoastlines(linewidth=0.25))
ax.add_collection3d(m.drawcountries(linewidth=0.35))
ax.add_collection3d(m.drawrivers(color='blue'))

ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Height')

fig.show()

这将在3D轴内创建 map ,以便您可以在表面上绘制对象。但是用Cartopy返回 matplotlib.axes.GeoAxesSubplot。不清楚如何使用 matplotlib-basemap将其添加到上述3D图形/轴中。

因此,有人可以提供有关如何使用Cartopy进行类似3D绘图的任何指示吗?

最佳答案

basemap mpl3d是一个相当不错的工具,但尚未设计成以上述方式起作用。结果,除了简单的海岸线之外,您目前无法将相同的技术用于很多其他方面。例如,充满大洲的地区根本无法使用AFAICT。

也就是说,使用Cartopy时也有类似的破解方法。由于我们可以通用地访问shapefile信息,因此该解决方案应适用于任何多段线shapefile(例如海岸线)。

第一步是掌握shapefile以及相应的几何形状:

feature = cartopy.feature.NaturalEarthFeature('physical', 'coastline', '110m')
geoms = feature.geometries()

接下来,我们可以将它们转换为所需的投影:
target_projection = ccrs.PlateCarree()
geoms = [target_projection.project_geometry(geom, feature.crs)
for geom in geoms]

由于这些形状是几何形状,因此我们要使用以下方法将它们转换为matplotlib路径:
from cartopy.mpl.patch import geos_to_path
import itertools

paths = list(itertools.chain.from_iterable(geos_to_path(geom)
for geom in geoms))

有了路径,我们应该能够在matplotlib中创建一个PathCollection并将其添加到轴上,但是遗憾的是,Axes3D似乎无法应付PathCollection实例,因此我们需要通过构造LineCollection来解决此问题(就像 basemap 那样) )。可悲的是LineCollections不采用路径,而是采用段,我们可以使用以下方法进行计算:
segments = []
for path in paths:
vertices = [vertex for vertex, _ in path.iter_segments()]
vertices = np.asarray(vertices)
segments.append(vertices)

综合所有这些,我们最终得到与您的代码生成的 basemap 图类似的结果:
import itertools

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

import cartopy.feature
from cartopy.mpl.patch import geos_to_path
import cartopy.crs as ccrs


fig = plt.figure()
ax = Axes3D(fig, xlim=[-180, 180], ylim=[-90, 90])
ax.set_zlim(bottom=0)


target_projection = ccrs.PlateCarree()

feature = cartopy.feature.NaturalEarthFeature('physical', 'coastline', '110m')
geoms = feature.geometries()

geoms = [target_projection.project_geometry(geom, feature.crs)
for geom in geoms]

paths = list(itertools.chain.from_iterable(geos_to_path(geom) for geom in geoms))

# At this point, we start working around mpl3d's slightly broken interfaces.
# So we produce a LineCollection rather than a PathCollection.
segments = []
for path in paths:
vertices = [vertex for vertex, _ in path.iter_segments()]
vertices = np.asarray(vertices)
segments.append(vertices)

lc = LineCollection(segments, color='black')

ax.add_collection3d(lc)

ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Height')

plt.show()

最重要的是,mpl3d似乎可以很好地处理PolyCollection,这将是我要研究的填充几何图形的路线,例如土地轮廓(而不是海岸线,严格来说是轮廓)。

重要的步骤是将路径转换为多边形,并在PolyCollection对象中使用它们:
concat = lambda iterable: list(itertools.chain.from_iterable(iterable))

polys = concat(path.to_polygons() for path in paths)
lc = PolyCollection(polys, edgecolor='black',
facecolor='green', closed=False)

这种情况的完整代码如下所示:
import itertools

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection, PolyCollection
import numpy as np

import cartopy.feature
from cartopy.mpl.patch import geos_to_path
import cartopy.crs as ccrs


fig = plt.figure()
ax = Axes3D(fig, xlim=[-180, 180], ylim=[-90, 90])
ax.set_zlim(bottom=0)


concat = lambda iterable: list(itertools.chain.from_iterable(iterable))

target_projection = ccrs.PlateCarree()

feature = cartopy.feature.NaturalEarthFeature('physical', 'land', '110m')
geoms = feature.geometries()

geoms = [target_projection.project_geometry(geom, feature.crs)
for geom in geoms]

paths = concat(geos_to_path(geom) for geom in geoms)

polys = concat(path.to_polygons() for path in paths)

lc = PolyCollection(polys, edgecolor='black',
facecolor='green', closed=False)

ax.add_collection3d(lc)

ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Height')

plt.show()

产生:

关于python-2.7 - 类似于Matplotlib-Basemap的3D CartoPy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23785408/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com