【问题标题】:Why the annotate worked unexpected here in cartopy?为什么注释在 cartopy 中出乎意料地起作用?
【发布时间】:2014-10-14 12:17:48
【问题描述】:

代码优先:

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

【问题讨论】:

  • 只是基于我的答案长度的建议 - 将来可能值得将您的问题分开。例如,“如何在 Cartopy 中创建 Google Mercator”没有理由不能成为它自己的问题。否则,这些都是很好的问题。 :+1:
  • 感谢您如此详细地回答问题。并请原谅我表达不好。我来自中国,我必须把一本英语词典放在一边才能问这些问题。现在我更专注于选择正确的单词并准确输入,而不是适当的表达。但是对于cartopy和英语,我都在练习。我会听取您的建议,分别提出问题。
  • 我认为你的英语很好——我理解了最重要的问题。祝您在英语和 cartopy 的旅途中好运。听到使用 cartopy 所做的事情总是很有趣,所以如果您将来有一些有趣的结果要分享,请随时与我们联系(也许发布一个 github gist 并通知我@pelson) - 这会很棒收到您的来信。

标签: matplotlib cartopy


【解决方案1】:

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

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

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

当我们深入 Annotate 类时,我们会发现 Annotate 的 _get_xy_transform (https://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()

回答您的其他问题:

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

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

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

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

HTH,

【讨论】:

  • 很好的答案!对于注释,是否可以有多个箭头从同一点发出,例如德里 - 北京,德里 - 开罗,德里 - 东京?
  • @pelson,当你说 “我建议你最好使用大地坐标系” - 我应该使用什么来代替 @ 987654335@transform = ccrs.PlateCarree()._as_mpl_transform(ax) 在这里听取您的建议?
猜你喜欢
  • 1970-01-01
  • 2020-09-26
  • 2011-11-24
  • 2011-01-29
  • 1970-01-01
  • 2014-04-02
  • 2022-08-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多