使用 Cartopy 绘制跨越国际日期变更线的线

Plotting line across international dateline with Cartopy

我正在尝试绘制全球风暴轨迹,但是当风暴越过日期变更线(经度从 ~360 变为 ~0)时,这条线一直围绕着绘图 space。 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())

如果我尝试将转换更改为 Geodetic,它看起来像这样:

根据 this github issue,这是预期的行为,因为 PlateCarree 是投影坐标系。

The PlateCarree coordinate system is Cartesian where a line between two points is straight (in that coordinate system). The Cartesian system has no knowledge of datelines/antimeridians and so when you ask for a line between -170 and +170 you get a line of length 340. It can never be the case that the PlateCarree projection interprets these numbers and chooses to draw a non-cartesian line

一种解决方案是在绘图调用中使用大地测量变换:

plt.plot(clons[bidx:eidx], clats[bidx:eidx], transform=ccrs.Geodetic())

或者修改您的数据以在使用 PlateCarree 系统时更有意义,例如通过确定值从 360-> 0 循环的位置,并在此之后将 360 添加到所有值。您可以将它们移动到不同的范围(例如 -180..180),但是数据跨越 +/- 180 会遇到与当前 0/360 相同的问题。

要绘制跨越日期变更线的折线,您需要正确清理经度。例如,值 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,358,360,3,5,359,1,357,0,8,12,6,357,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, ydateline, transform=ccrs.PlateCarree(), color='red')

情节将是:-