问题描述
我正在尝试绘制全球风暴轨迹,但是当风暴穿过日期变更线(经度从 ~360 到 ~0)时,这条线会一直围绕绘图空间循环。 Here's what the plot looks like. See the weird straight lines near the top. 这是我的代码:
ax = plt.axes(projection=ccrs.Robinson())
ax.set_global()
ax.coastlines()
for i in range(nstorms-1): #loop through each TC
bidx = start_idx[i]
eidx = start_idx[i+1]
plt.plot(clons[bidx:eidx],clats[bidx:eidx],transform=ccrs.PlateCarree())
解决方法
根据 this github issue,这是预期行为,因为 PlateCarree
是投影坐标系。
PlateCarree 坐标系是笛卡尔坐标系,其中两点之间的线是直线(在该坐标系中)。笛卡尔系统不知道日期变更线/反经线,因此当您要求在 -170 和 +170 之间的线时,您会得到一条长度为 340 的线。 PlateCarree 投影永远不会解释这些数字并选择绘制一个非笛卡尔线
一种解决方案是在绘图调用中使用测地变换:
plt.plot(clons[bidx:eidx],clats[bidx:eidx],transform=ccrs.Geodetic())
或者修改您的数据以在使用 PlateCarree
系统时更有意义,例如通过识别值从 360-> 0 循环的位置并将 360 添加到发生后的所有值。您可以将它们移动到不同的范围(例如 -180..180),但是您会遇到与当前 0/360 相同的数据跨越 +/- 180 的问题。
要绘制跨越日期变更线的折线,您需要正确地对经度进行消毒。例如,值 359 到 2 应调整为 359 到 362。在下面的演示代码中,sanitize_lonlist()
用于在使用经度值列表绘制红色锯齿线之前对其进行清理。
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
def sanitize_lonlist(lons):
new_list = []
oldval = 0
treshold = 10 # used to compare adjacent longitudes
for ix,ea in enumerate(lons):
diff = oldval - ea
if (ix>0):
if (diff>treshold):
ea = ea+360
oldval = ea
new_list.append(ea)
return new_list
ax = plt.axes(projection=ccrs.Robinson())
ax.set_global()
ax.coastlines(alpha=0.3)
# sample long/lat data for demo purposes
# xdateline: list of longitudes that cross dateline several times
xdateline = [347,349,352,358,4,7,8,3,359,360,5,1,357,12,6,349]
# ydateline: list of accompanying latitudes
ydateline = range(len(xdateline))
# plot the line crossing dateline using `sanitized` values of longitudes
plt.plot(sanitize_lonlist(xdateline),ydateline,transform=ccrs.PlateCarree(),color='red')
plt.show()
使用 xdateline
的原始值绘制代码行:-
plt.plot(xdateline,color='red')
情节将是:-