使用 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')
情节将是:-
我正在尝试绘制全球风暴轨迹,但是当风暴越过日期变更线(经度从 ~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')
情节将是:-