@@ -213,23 +213,22 @@ def _pad_ticks(ticks, vmin, vmax):
213213 # giant lists of 10,000 gridline locations.
214214 if len (ticks ) == 0 :
215215 return ticks
216- range_ = max (ticks ) - min (ticks )
216+ range_ = np . max (ticks ) - np . min (ticks )
217217 vmin = max (vmin , ticks [0 ] - range_ )
218218 vmax = min (vmax , ticks [- 1 ] + range_ )
219219
220220 # Pad the reported tick range up to specified range
221221 step = ticks [1 ] - ticks [0 ] # MaxNLocator/AutoMinorLocator steps are equal
222- ticks_lo = np .arange (ticks [0 ], vmin , - step )[1 :][::- 1 ]. tolist ()
223- ticks_hi = np .arange (ticks [- 1 ], vmax , step )[1 :]. tolist ()
224- ticks = ticks_lo + ticks + ticks_hi
222+ ticks_lo = np .arange (ticks [0 ], vmin , - step )[1 :][::- 1 ]
223+ ticks_hi = np .arange (ticks [- 1 ], vmax , step )[1 :]
224+ ticks = np . concatenate (( ticks_lo , ticks , ticks_hi ))
225225 return ticks
226226
227227 def get_scale (self ):
228228 return 'linear'
229229
230230 def get_tick_space (self ):
231- # Just use the long-standing default of nbins=9
232- return 9
231+ return 9 # longstanding default of nbins=9
233232
234233 def get_major_formatter (self ):
235234 return self .major .formatter
@@ -241,14 +240,14 @@ def get_minor_locator(self):
241240 return self .minor .locator
242241
243242 def get_majorticklocs (self ):
244- return self ._get_sanitized_ticks (self .major .locator )
243+ return self ._get_ticklocs (self .major .locator )
245244
246245 def get_minorticklocs (self ):
247- return self ._get_sanitized_ticks (self .minor .locator )
246+ return self ._get_ticklocs (self .minor .locator )
248247
249248 def set_major_formatter (self , formatter , default = False ):
250- # NOTE: Cartopy formatters check Formatter.axis.axes.projection and has
251- # special projection-dependent behavior.
249+ # NOTE: Cartopy formatters check Formatter.axis.axes.projection
250+ # in order to implement special projection-dependent behavior.
252251 self .major .formatter = formatter
253252 formatter .set_axis (self )
254253 self .isDefault_majfmt = default
@@ -286,27 +285,41 @@ def __init__(self, axes):
286285 self .set_major_locator (constructor .Locator (locator ), default = True )
287286 self .set_minor_locator (mticker .AutoMinorLocator (), default = True )
288287
289- def _get_sanitized_ticks (self , locator ):
288+ def _get_ticklocs (self , locator ):
290289 # Prevent ticks from looping around
291- eps = 5e-10 # more than 1e-10 because we use 1e-10 in _LongitudeLocator
292- ticks = sorted (locator ())
293- while ticks and ticks [- 1 ] - eps > ticks [0 ] + 360 + eps : # cut off looped ticks
294- ticks = ticks [:- 1 ]
290+ # NOTE: Cartopy 0.17 formats numbers offset by eps with the cardinal indicator
291+ # (e.g. 0 degrees for map centered on 180 degrees). So skip in that case.
292+ # NOTE: Common strange issue is e.g. MultipleLocator(60) starts out at
293+ # -60 degrees for a map from 0 to 360 degrees. If always trimmed circular
294+ # locations from right then would cut off rightmost gridline. Workaround is
295+ # to trim on the side closest to central longitude (in this case the left).
296+ eps = 1e-10
297+ lon0 = self .axes ._get_lon0 ()
298+ ticks = np .sort (locator ())
299+ while ticks .size :
300+ if np .isclose (ticks [0 ] + 360 , ticks [- 1 ]):
301+ if _version_cartopy >= '0.18' or not np .isclose (ticks [0 ] % 360 , 0 ):
302+ ticks [- 1 ] -= eps # ensure label appears on *right* not left
303+ break
304+ elif ticks [0 ] + 360 < ticks [- 1 ]:
305+ idx = (1 , None ) if lon0 - ticks [0 ] > ticks [- 1 ] - lon0 else (None , - 1 )
306+ ticks = ticks [slice (* idx )] # cut off ticks looped over globe
307+ else :
308+ break
295309
296310 # Append extra ticks in case longitude/latitude limits do not encompass
297311 # the entire view range of map, e.g. for Lambert Conformal sectors.
298312 # NOTE: Try to avoid making 10,000 element lists. Just wrap extra ticks
299313 # up to the width of *reported* longitude range.
300314 if isinstance (locator , (mticker .MaxNLocator , mticker .AutoMinorLocator )):
301- lon0 = self .axes ._get_lon0 ()
302315 ticks = self ._pad_ticks (ticks , lon0 - 180 + eps , lon0 + 180 - eps )
303316
304317 return ticks
305318
306319 def get_view_interval (self ):
307320 # NOTE: Proplot tries to set its *own* view intervals to avoid dateline
308- # weirdness, but if geo.extent is 'auto' the interval will be unset, so
309- # we are forced to use _get_extent().
321+ # weirdness, but if rc[' geo.extent'] is 'auto' the interval will be unset.
322+ # In this case we use _get_extent() as a backup .
310323 interval = self ._interval
311324 if interval is None :
312325 extent = self ._get_extent ()
@@ -332,12 +345,12 @@ def __init__(self, axes, latmax=90):
332345 self .set_major_locator (constructor .Locator (locator ), default = True )
333346 self .set_minor_locator (mticker .AutoMinorLocator (), default = True )
334347
335- def _get_sanitized_ticks (self , locator ):
348+ def _get_ticklocs (self , locator ):
336349 # Adjust latitude ticks to fix bug in some projections. Harmless for basemap.
337- # NOTE: Maybe this is fixed by cartopy 0.18?
338- eps = 5e -10
339- ticks = sorted (locator ())
340- if ticks :
350+ # NOTE: Maybe this was fixed by cartopy 0.18?
351+ eps = 1e -10
352+ ticks = np . sort (locator ())
353+ if ticks . size :
341354 if ticks [0 ] == - 90 :
342355 ticks [0 ] += eps
343356 if ticks [- 1 ] == 90 :
@@ -350,7 +363,7 @@ def _get_sanitized_ticks(self, locator):
350363
351364 # Filter ticks to latmax range
352365 latmax = self .get_latmax ()
353- ticks = [ l for l in ticks if - latmax <= l <= latmax ]
366+ ticks = ticks [( ticks >= - latmax ) & ( ticks <= latmax ) ]
354367
355368 return ticks
356369
0 commit comments