Cartopy - drawing limited area maps which cross the dateline

1,534 views
Skip to first unread message

Susan

unread,
Nov 25, 2016, 9:34:27 AM11/25/16
to Iris
I’m having big problems plotting across the dateline (see plots below - I'm sorry about the order I don't seem to be able to move them.).
 
First if I simply set my plotting extent so that it is limited in extent but crosses the dateline the plot defaults to show a longitude range of -180 to 180.

ax = plt.axes(projection=ccrs.PlateCarree())
ax
.set_extent([133, 203, 20, 50])
ax
.coastlines()
gl
= ax.gridlines(draw_labels=True)
plt
.show()

Second if I set the central longitude of my projection to be 180 the plot extent is correct but I just get two tick labels on top of each other at 180.

ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax
.set_extent([133, 203, 20, 50])
ax
.coastlines()
gl
= ax.gridlines(draw_labels=True)
plt
.show()

Third if I set the central longitude of my projection to be 180 and specify the tick locations I get the correct extent but no labels beyond 180. Also the gridlines are truncated at the lowest and highest tick mark.

ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax
.set_extent([133, 203, 20, 50])
ax
.coastlines()
gl
= ax.gridlines(draw_labels=True, xlocs=[140, 160, 180, 200])
plt
.show()
 
Fourth if I subtract 360 from the tick marks which are greater than 180 then the labels will appear on the map but there is now a gap in the gridlines between 180 and the first tick mark after 180.
.ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax
.set_extent([133, 203, 20, 50])
ax
.coastlines()
gl
= ax.gridlines(draw_labels=True, xlocs=[140, 160, 180, -160])
plt
.show()

My current, not quite ideal solution is to plot the map using a central_longitude of 180, plot some gridlines which are not labelled but which extend beyond the plot boundaries and then overplot some gridlines (with a very small linewidth) and tick labels. All tick labels after 180 have had 360 subtracted. This plot is still not perfect but the best I can do. Does anyone have any suggestions about how I could improve this?

ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax
.set_extent([133, 203, 20, 50])
ax
.coastlines()
ax
.gridlines(xlocs=[120, 140, 160, 180, 200, 220] )
gl
= ax.gridlines(draw_labels=True, xlocs=[140, 160, 180, -160], linewidth=0.001 )
plt
.show()


Andrew Dawson

unread,
Nov 25, 2016, 10:05:18 AM11/25/16
to Iris
Hi Susan

Sorry to hear about these annoying issues. The best I could come up with after a quick test was this:

ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax
.set_extent([133, 203, 20, 50], crs=ccrs.PlateCarree())
ax
.coastlines()
gl
= ax.gridlines(draw_labels=True, xlocs=[140, 160, 180, -160, 220])
plt
.show()

and boy is that not pretty!

I think this is worthy of a bug report against cartopy (http://github.com/scitools/cartopy/issues), it should not be this difficult and tedious to arrange gridlines.

Susan

unread,
Nov 28, 2016, 5:00:30 AM11/28/16
to Iris
Thanks Andrew,

I've taken your advice and opened an issue on Cartopy's github pages

Susan

Tom

unread,
Aug 8, 2018, 1:18:28 AM8/8/18
to SciTools (iris, cartopy, cf_units, etc.) - https://github.com/scitools
In case other people stumble across this, one approach that seems to work is below. The Issue (https://github.com/SciTools/cartopy/issues/276 and https://github.com/SciTools/cartopy/issues/821) appear to not be closed yet.

def my_round(x, base=5):
    return int(base * round(float(x)/base))

lola = [133, 203, 20, 50]

ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax.set_extent(lola, crs=ccrs.PlateCarree())

# Draw the gridlines, add labels separately
gl = ax.gridlines(xlocs=np.arange(0,361, 5), ylocs=np.arange(-90,91,5),
                  linewidth=2, linestyle='--', draw_labels=False)

# Calculate the longitude labels, make anything above 180 to be the negative equivalent
xlabels = np.arange(my_round(np.ceil(lola[0]),5),
                    my_round(np.floor(lola[1]), 5)+1, 5)
xlabels[labels>180]-=360
ylabels = np.arange(my_round(np.ceil(lola[2]),5),
                    my_round(np.floor(lola[3]), 5)+1, 5)

# Now plot the labels
glabels = ax.gridlines(xlocs=xlabels,
                       ylocs=ylabels,
                       draw_labels=True, alpha=0)

ax.coastlines()

Reply all
Reply to author
Forward
0 new messages