设置一个与纸板中的日期行相交的地图

pel*_*son 11 matplotlib cartopy

我收到了以下电子邮件,并希望确保每个人都能获得这个问题的答案:


嗨,

我想设置一个简单的纬度经度地图,使用纸板,横跨日期线,并在左侧显示东亚,右侧显示北美西部.以下谷歌地图大致是我所追求的:

https://maps.google.co.uk/?ll=56.559482,-175.253906&spn=47.333523,133.066406&t=m&z=4

谷歌地图的截图

这可以用Cartopy完成吗?

pel*_*son 29

好问题.这可能是东西,将再次拿出时间和时间,所以我将通过这一步一步的前居然回答您的具体问题.为了将来参考,以下示例使用cartopy v0.5编写.

首先,重要的是要注意默认的"纬度经度"(或更专业的PlateCarree)投影在-180到180的前向范围内工作.这意味着您无法在此之外绘制标准的PlateCarree投影.有几个很好的理由,其中大部分可以归结为一个事实,即cartopy将不得不做很多突出的载体和栅格(例如简单的海岸线)时,更多的工作.不幸的是,您尝试生成的图表恰好需要此功能.要将此限制放入图片中,默认的PlateCarree投影如下所示:

import cartopy.crs as ccrs
import matplotlib.pyplot as plt

proj = ccrs.PlateCarree(central_longitude=0)

ax1 = plt.axes(projection=proj)
ax1.stock_img()
plt.title('Global')

plt.show()
Run Code Online (Sandbox Code Playgroud)

全球板块

您可以在此地图上绘制的任何单个矩形在法律上都可以是放大区域(这里有一些稍高级的代码,但图片值1000字):

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import shapely.geometry as sgeom

box = sgeom.box(minx=-90, maxx=45, miny=15, maxy=70)
x0, y0, x1, y1 = box.bounds

proj = ccrs.PlateCarree(central_longitude=0)

ax1 = plt.subplot(211, projection=proj)
ax1.stock_img()
ax1.add_geometries([box], proj, facecolor='coral', 
                   edgecolor='black', alpha=0.5)
plt.title('Global')

ax2 = plt.subplot(212, projection=proj)
ax2.stock_img()
ax2.set_extent([x0, x1, y0, y1], proj)
plt.title('Zoomed in area')

plt.show()
Run Code Online (Sandbox Code Playgroud)

全局,第二个放大地图

不幸的是,你想要的情节需要2个带有这个投影的矩形:

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import shapely.geometry as sgeom

box = sgeom.box(minx=120, maxx=260, miny=15, maxy=80)

proj = ccrs.PlateCarree(central_longitude=0)

ax1 = plt.axes(projection=proj)
ax1.stock_img()
ax1.add_geometries([box], proj, facecolor='coral', 
                   edgecolor='black', alpha=0.5)
plt.title('Target area')

plt.show()
Run Code Online (Sandbox Code Playgroud)

全局图上的目标矩形

因此,无法使用标准PlateCarree定义绘制穿过日期线的地图.相反,我们可以更改PlateCarree定义的中心经度,以允许绘制我们所针对的区域的单个框:

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import shapely.geometry as sgeom

box = sgeom.box(minx=120, maxx=260, miny=15, maxy=80)
x0, y0, x1, y1 = box.bounds

proj = ccrs.PlateCarree(central_longitude=180)
box_proj = ccrs.PlateCarree(central_longitude=0)

ax1 = plt.subplot(211, projection=proj)
ax1.stock_img()
ax1.add_geometries([box], box_proj, facecolor='coral', 
                   edgecolor='black', alpha=0.5)
plt.title('Global')

ax2 = plt.subplot(212, projection=proj)
ax2.stock_img()
ax2.set_extent([x0, x1, y0, y1], box_proj)
plt.title('Zoomed in area')

plt.show()
Run Code Online (Sandbox Code Playgroud)

两个PlateCarre图,中心经度为180,一个全局,一个放大到目标区域

希望将告诉您什么是你必须做,以实现你的目标的地图,上面的代码可能有点复杂,以实现自己的目标,所以要稍微简化的代码,我会写来生成所需会是这样的情节:

import cartopy.feature
import cartopy.crs as ccrs
import matplotlib.pyplot as plt    

ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax.set_extent([120, 260, 15, 80], crs=ccrs.PlateCarree())

# add some features to make the map a little more polished
ax.add_feature(cartopy.feature.LAND)
ax.add_feature(cartopy.feature.OCEAN)
ax.coastlines('50m')

plt.show()
Run Code Online (Sandbox Code Playgroud)

最终目标地图

这是一个很长的答案,希望我不仅回答了这个问题,而且使一些更为复杂的地图制作和图谱细节更加清晰,以帮助解决您可能遇到的任何未来问题.

干杯,

  • 请注意,如果向图中添加数据,则可能需要调整中心经度:`ax.scatter(X + offset, Y)` (2认同)