为什么注释在拼图中出现意外?

时间:2014-08-21 00:38:33

标签: matplotlib cartopy

代码优先:

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)如何纠正?

1 个答案:

答案 0 :(得分:12)

首先 - 感谢代码 - 这使得解决问题变得容易得多。

说实话,我认为注释之前并没有真正使用过Cartopy,所以这可能就是为什么你会遇到这个问题 - 你真的很开心;)

看起来matplotlib的Axes.annotate方法应该归咎于此 - 它会使https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_axes.py#L651周围的变换成为核心。这主要是因为注释具有特殊关键字,用于独立定义坐标和文本位置的变换(请参阅http://matplotlib.org/users/annotations_intro.html#annotating-text中的xycoordstextcoords)。

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

好的,到目前为止,非常好。看起来你可以通过一个坐标系来xycoords,一切都应该是hunky-dory。遗憾的是,annotate不知道如何将matopy坐标系转换为matplotlib变换,就像matplotlib的其余部分所做的那样,所以我们必须预先为annotate函数做到这一点。

要从任何折纸坐标系创建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()

Example of annotate with cartopy

回答你的其他问题:

  

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

cartopy.crs中有一个新的常量,它完全定义了Google Mercator(cartopy.crs.GOOGLE_MERCATOR)。这只是Mercator投影的一个实例,只有一些调整,使其与Google Mercator(https://github.com/SciTools/cartopy/blob/master/lib/cartopy/crs.py#L889)完全相同。

  

我想绘制的坐标数据是121°E,49°N(转换为   当然是在绘制前的十进制度),未投影,WGS84   coords系统,可能来自GPS。我是对的   变换= ccrs.PlateCarree()?或者如果我错了我该怎么用?

我建议你最好使用大地坐标系 - 这个坐标系默认使用WGS84基准面,它可以让你最准确地表示你的WGS84纬度和经度。虽然,在你正在绘制它们的尺度上,我想你会很难注意到它们之间的差异(中纬度地区的最大差异约为22Km)。

HTH,