11

先上代码:

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

ax = plt.axes(projection=ccrs.Mercator())
ax.set_extent([72, 135, 18, 53])
ax.annotate('hello', xy=(100, 49), xycoords='data',
            transform=ccrs.PlateCarree(), zorder=12)
plt.show()

结果不是预期的,我对我的方法还有其他疑问。所以我的问题是:

  1. 如果我想绘制一个看起来像网络地图的地图(例如谷歌地图)。地图区域可能和中国一样大,大多不是全球性的。在谷歌搜索之后,这些网站主要使用“网络墨卡托”投影。所以我想我应该plt.axes(projection=ccrs.Mercator()在这里使用,对吗?或者如果我错了我应该使用什么?

  2. 我想要绘制的坐标数据就像 121°E,49°N(当然在绘制之前将度数转换为十进制),未投影的 WGS84 坐标系统,可能来自 GPS。那我可以使用transform=ccrs.PlateCarree()吗?或者如果我错了我应该使用什么?

  3. annotate上面没有显示任何内容。注释该ax.set_extent行后,“hello”文本将绘制在零(0, 0)点处。我想要的是在点(100°E,49°N)如何纠正这个?

4

1 回答 1

27

首先-感谢您的代码-它使解决问题变得更加容易。

老实说,我认为之前没有认真使用过 Cartopy 的注释,所以这可能就是你遇到这个问题的原因 - 你是开拓者;)

看起来 matplotlib 的Axes.annotate方法应该归咎于此 - 它破坏了通过https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_axes.py#L651周围传递的变换。这主要是因为 annotate 具有用于独立定义坐标和文本位置变换的特殊关键字(xycoords参见textcoordshttp://matplotlib.org/users/annotations_intro.html#annotating-text

当我们深入到 Annotate 类时,我们会发现 Annotate 的_get_xy_transformhttps://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/text.py#L1446)可以处理各种(一些未记录的)形式为的值textcoords,包括转换实例。

好的,到目前为止,一切都很好。看起来你可以通过一个坐标系来xycoords,一切都应该是笨拙的。遗憾的是,annotate 不知道如何将 Cartopy 坐标系转换为 matplotlib 转换,就像 matplotlib 的大多数其余部分所做的那样,所以我们必须预先为 annotate 函数做这件事。

要从任何 cartopy 坐标系创建 matplotlib 变换,对于任何轴,我们可以简单地执行以下操作:

ax = plt.axes(projection=ccrs.Mercator())
crs = ccrs.PlateCarree()
transform = crs._as_mpl_transform(ax)

我们现在可以将这个转换传递给 annotate 方法,我们应该在预期的位置得到文本和箭头。我采取了一些自由来突出注释的一些功能,而我正在使用它:

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


ax = plt.axes(projection=ccrs.Mercator())

ax.set_extent([65, 125, 5, 40])

ax.add_feature(cartopy.feature.OCEAN)
ax.add_feature(cartopy.feature.LAND)
ax.add_feature(cartopy.feature.BORDERS, linestyle=':', edgecolor='gray')
ax.coastlines()

ax.plot(116.4, 39.95, 'ob', transform=ccrs.PlateCarree())

transform = ccrs.PlateCarree()._as_mpl_transform(ax)
ax.annotate('Beijing', xy=(116.4, 39.9), xycoords=transform,
            ha='right', va='top')

ax.annotate('Delhi', xy=(113, 40.5), xytext=(77.23, 28.61),
            arrowprops=dict(facecolor='gray',
                            arrowstyle="simple",
                            connectionstyle="arc3,rad=-0.2",
                            alpha=0.5),
            xycoords=transform,
            ha='right', va='top')

plt.show()

使用 cartopy 进行注释的示例

在回答您的其他问题时:

如果我想绘制一个看起来像网络地图的地图(例如谷歌地图)

cartopy.crs 中有一个新常量,它准确地定义了谷歌墨卡托 ( cartopy.crs.GOOGLE_MERCATOR)。这只是墨卡托投影的一个实例,经过一些调整,使其与谷歌墨卡托完全一样(https://github.com/SciTools/cartopy/blob/master/lib/cartopy/crs.py#L889)。

我想要绘制的坐标数据就像 121°E,49°N(当然在绘制之前将度数转换为十进制),未投影的 WGS84 坐标系统,可能来自 GPS。那么我使用 transform=ccrs.PlateCarree() 是否正确?或者如果我错了我应该使用什么?

我建议您最好使用 Geodetic 坐标系 - 此坐标系默认使用 WGS84 基准面,这将为您提供 WGS84 纬度和经度的最准确表示。虽然,按照您当前绘制的比例,我想您可能很难注意到差异(中纬度地区的最大差异约为 22 公里)。

高温下,

于 2014-08-21T08:46:03.417 回答