2012-12-13 103 views
9

我收到了以下邮件,并希望确保这个问题的答案是提供给大家:建立一个地图横跨在cartopy日界线


嗨,

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

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

Screenshot of google map

可以这样用Cartopy做什么?

+0

只是为了对这个问题,用户问一个简单的“经纬度”地图评论,并提供了一个谷歌地图,这在我看来是*不*简单的“纬度截图经度“地图。从技术上讲,谷歌地图附在球形墨卡托投影;我的答案认为用户是为了说明目的而设计的,实际上,通过简单的“纬度经度”意味着Equirectangular/PlateCarree。 – pelson

回答

23

好问题。这可能会一次又一次地出现,所以我会在实际上之前一步一步地回答你的具体问题。为了将来的参考,下面的例子是用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() 

global plate carree

,你可以在这个地图上绘制的任何一个矩形可以合法一个面积缩小(有一些稍微更先进代码在这里,但图片是值得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() 

global with a second zoomed in map

Unfort unately你想要的情节将需要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() 

target rectangle on global plot

因此,它是不可能得出一个地图,跨越使用标准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() 

Two PlateCarre plots with a central longitude of 180, one global, one zoomed in to the target area

希望它是什么你必须做为了实现你的目标地图,上面的代码可能有点复杂,以实现你的目标,所以简化一下,我会写的代码产生你想要的情节会是这样的:

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

final target map

这是一个长的答案,希望我不仅回答了这个问题,但进行了一些的地图制作更复杂的细节和cartopy更加清晰,以帮助消除您的任何未来的问题。

干杯,