@@ -206,7 +206,8 @@ def default_crs(self, func, *args, crs=None, **kwargs):
206206 except TypeError as err : # duplicate keyword args, i.e. crs is positional
207207 if not args :
208208 raise err
209- result = func (self , * args [:- 1 ], crs = args [- 1 ], ** kwargs )
209+ args , crs = args [:- 1 ], args [- 1 ]
210+ result = func (self , * args , crs = crs , ** kwargs )
210211 # Fix extent, so axes tight bounding box gets correct box!
211212 # From this issue:
212213 # https://github.com/SciTools/cartopy/issues/1207#issuecomment-439975083
@@ -217,15 +218,18 @@ def default_crs(self, func, *args, crs=None, **kwargs):
217218 return result
218219
219220
220- def _standard_label (data , axis = None , units = True ):
221+ def _axis_labels_title (data , axis = None , units = True ):
221222 """
222- Get data and label for pandas or xarray objects or their coordinates.
223+ Get data and label for pandas or xarray objects or their coordinates
224+ along axis `axis`. If `units` is ``True`` also look for units on xarray
225+ data arrays.
223226 """
224227 label = ''
225228 _load_objects ()
226229 if isinstance (data , ndarray ):
227230 if axis is not None and data .ndim > axis :
228231 data = np .arange (data .shape [axis ])
232+
229233 # Xarray with common NetCDF attribute names
230234 elif isinstance (data , DataArray ):
231235 if axis is not None and data .ndim > axis :
@@ -239,6 +243,7 @@ def _standard_label(data, axis=None, units=True):
239243 label = f'{ label } ({ units } )'
240244 elif units :
241245 label = units
246+
242247 # Pandas object with name attribute
243248 # if not label and isinstance(data, DataFrame) and data.columns.size == 1:
244249 elif isinstance (data , (DataFrame , Series , Index )):
@@ -251,6 +256,7 @@ def _standard_label(data, axis=None, units=True):
251256 # DataFrame has no native name attribute but user can add one:
252257 # https://github.com/pandas-dev/pandas/issues/447
253258 label = getattr (data , 'name' , '' ) or ''
259+
254260 return data , str (label ).strip ()
255261
256262
@@ -307,7 +313,7 @@ def standardize_1d(self, func, *args, **kwargs):
307313 if x is None :
308314 axis = 1 if (name in ('hist' , 'boxplot' , 'violinplot' ) or any (
309315 kwargs .get (s , None ) for s in ('means' , 'medians' ))) else 0
310- x , _ = _standard_label (y , axis = axis )
316+ x , _ = _axis_labels_title (y , axis = axis )
311317 x = _to_array (x )
312318 if x .ndim != 1 :
313319 raise ValueError (
@@ -332,20 +338,21 @@ def standardize_1d(self, func, *args, **kwargs):
332338 kwargs ['positions' ] = xi
333339 if name in ('boxplot' , 'violinplot' ):
334340 kwargs ['positions' ] = xi
341+
335342 # Next handle labels if 'autoformat' is on
336343 if self .figure ._auto_format :
337344 # Ylabel
338- y , label = _standard_label (y )
339- if label :
340- # for histogram, this indicates x coordinate
345+ y , label = _axis_labels_title (y )
346+ if label : # for histogram, this label is used for *x* coordinates
341347 iaxis = xax if name in ('hist' ,) else yax
342348 kw [iaxis + 'label' ] = label
343349 # Xlabel
344- x , label = _standard_label (x )
350+ x , label = _axis_labels_title (x )
345351 if label and name not in ('hist' ,):
346352 kw [xax + 'label' ] = label
347353 if name != 'scatter' and len (x ) > 1 and xi is None and x [1 ] < x [0 ]:
348354 kw [xax + 'reverse' ] = True
355+
349356 # Appply
350357 if kw :
351358 self .format (** kw )
@@ -550,7 +557,7 @@ def standardize_2d(self, func, *args, order='C', globe=False, **kwargs):
550557 # Handle labels if 'autoformat' is on
551558 if self .figure ._auto_format :
552559 for key , xy in zip (('xlabel' , 'ylabel' ), (x , y )):
553- _ , label = _standard_label (xy )
560+ _ , label = _axis_labels_title (xy )
554561 if label :
555562 kw [key ] = label
556563 if len (xy ) > 1 and all (isinstance (xy , Number )
@@ -562,8 +569,8 @@ def standardize_2d(self, func, *args, order='C', globe=False, **kwargs):
562569 y = yi
563570 # Handle figure titles
564571 if self .figure ._auto_format :
565- _ , colorbar_label = _standard_label (Zs [0 ], units = True )
566- _ , title = _standard_label (Zs [0 ], units = False )
572+ _ , colorbar_label = _axis_labels_title (Zs [0 ], units = True )
573+ _ , title = _axis_labels_title (Zs [0 ], units = False )
567574 if title :
568575 kw ['title' ] = title
569576 if kw :
@@ -1789,7 +1796,7 @@ def cycle_changer(
17891796
17901797 # Plot susccessive columns
17911798 objs = []
1792- label_leg = None # for colorbar or legend
1799+ label_leg_cbar = None # for colorbar or legend
17931800 for i in range (ncols ):
17941801 # Prop cycle properties
17951802 kw = kwargs .copy ()
@@ -1806,59 +1813,70 @@ def cycle_changer(
18061813 kw [key ] = value
18071814
18081815 # Get x coordinates
1809- ix , iy = x , ys [0 ] # samples
1816+ x_col , y_first = x , ys [0 ] # samples
18101817 if name in ('pie' ,):
1811- kw ['labels' ] = _not_none (labels , ix ) # TODO: move to pie wrapper?
1818+ kw ['labels' ] = _not_none (labels , x_col ) # TODO: move to pie wrapper?
18121819 if name in ('bar' ,): # adjust
18131820 if not stacked :
1814- ix = x + (i - ncols / 2 + 0.5 ) * width / ncols
1815- elif stacked and iy .ndim > 1 :
1821+ x_col = x + (i - ncols / 2 + 0.5 ) * width / ncols
1822+ elif stacked and y_first .ndim > 1 :
18161823 key = 'x' if barh else 'bottom'
1817- kw [key ] = _to_indexer (iy )[:, :i ].sum (axis = 1 )
1824+ kw [key ] = _to_indexer (y_first )[:, :i ].sum (axis = 1 )
18181825
18191826 # Get y coordinates and labels
18201827 if name in ('pie' , 'boxplot' , 'violinplot' ):
1821- iys = (iy ,) # only ever have one y value, cannot have legend labs
1828+ # Only ever have one y value, cannot have legend labs
1829+ ys_col = (y_first ,)
1830+
18221831 else :
18231832 # The coordinates
18241833 # WARNING: If stacked=True then we always *ignore* second
18251834 # argument passed to fill_between. Warning should be issued
18261835 # by fill_between_wrapper in this case.
18271836 if stacked and 'fill_between' in name :
1828- iys = tuple (
1829- iy if iy .ndim == 1 else _to_indexer (iy )[:, :ii ].sum (axis = 1 )
1837+ ys_col = tuple (
1838+ y_first if y_first .ndim == 1
1839+ else _to_indexer (y_first )[:, :ii ].sum (axis = 1 )
18301840 for ii in (i , i + 1 )
18311841 )
18321842 else :
1833- iys = tuple (
1834- iy if iy .ndim == 1 else _to_indexer (iy )[:, i ]
1835- for iy in ys
1843+ ys_col = tuple (
1844+ y_i if y_i .ndim == 1 else _to_indexer (y_i )[:, i ]
1845+ for y_i in ys
18361846 )
1847+
18371848 # Possible legend labels
1849+ # Several scenarios:
1850+ # 1. Always prefer input labels
1851+ # 2. Always add labels if this is a *named* dimension.
1852+ # 3. Even if not *named* dimension add labels if labels are string
18381853 if len (labels ) != ncols :
18391854 raise ValueError (
18401855 f'Got { ncols } columns in data array, '
18411856 f'but { len (labels )} labels.'
18421857 )
1843- label = labels [i ]
1844- values , label_leg = _standard_label (iy , axis = 1 )
1845- if label_leg and label is None :
1846- label = _to_ndarray (values )[i ]
1858+ label = labels [i ] # input labels
1859+ labels_cols , label_leg_cbar = _axis_labels_title (y_first , axis = 1 )
1860+ labels_cols = _to_ndarray (labels_cols )
1861+ if label is None and (
1862+ label_leg_cbar or labels_cols .size and isinstance (labels_cols [i ], str )
1863+ ):
1864+ label = labels_cols [i ]
18471865 if label is not None :
18481866 kw ['label' ] = label
18491867
18501868 # Build coordinate arguments
1851- xy = ()
1869+ x_ys_col = ()
18521870 if barh : # special, use kwargs only!
1853- kw .update ({'bottom' : ix , 'width' : iys [0 ]})
1871+ kw .update ({'bottom' : x_col , 'width' : ys_col [0 ]})
18541872 kw .setdefault ('x' , kwargs .get ('bottom' , 0 )) # required
18551873 elif name in ('pie' , 'hist' , 'boxplot' , 'violinplot' ):
1856- xy = ( * iys ,)
1874+ x_ys_col = ys_col
18571875 else : # has x-coordinates, and maybe more than one y
1858- xy = (ix , * iys )
1876+ x_ys_col = (x_col , * ys_col )
18591877
18601878 # Call plotting function
1861- obj = func (self , * xy , * args , ** kw )
1879+ obj = func (self , * x_ys_col , * args , ** kw )
18621880 if isinstance (obj , (list , tuple )) and len (obj ) == 1 :
18631881 obj = obj [0 ]
18641882 objs .append (obj )
@@ -1873,8 +1891,8 @@ def cycle_changer(
18731891 # Add keywords
18741892 if loc != 'fill' :
18751893 colorbar_kw .setdefault ('loc' , loc )
1876- if label_leg :
1877- colorbar_kw .setdefault ('label' , label_leg )
1894+ if label_leg_cbar :
1895+ colorbar_kw .setdefault ('label' , label_leg_cbar )
18781896 self ._auto_colorbar [loc ][1 ].update (colorbar_kw )
18791897
18801898 # Add legend
@@ -1887,8 +1905,8 @@ def cycle_changer(
18871905 # Add keywords
18881906 if loc != 'fill' :
18891907 legend_kw .setdefault ('loc' , loc )
1890- if label_leg :
1891- legend_kw .setdefault ('label' , label_leg )
1908+ if label_leg_cbar :
1909+ legend_kw .setdefault ('label' , label_leg_cbar )
18921910 self ._auto_legend [loc ][1 ].update (legend_kw )
18931911
18941912 # Return
@@ -2270,6 +2288,7 @@ def cmap_changer(
22702288 colorbar_kw = colorbar_kw or {}
22712289
22722290 # Flexible user input
2291+ Z_sample = args [- 1 ]
22732292 vmin = _not_none (vmin = vmin , norm_kw_vmin = norm_kw .pop ('vmin' , None ))
22742293 vmax = _not_none (vmax = vmax , norm_kw_vmax = norm_kw .pop ('vmax' , None ))
22752294 values = _not_none (values = values , centers = centers )
@@ -2349,7 +2368,7 @@ def cmap_changer(
23492368 ticks = None
23502369 if cmap is not None and name not in ('hexbin' ,):
23512370 norm , cmap , levels , ticks = _build_discrete_norm (
2352- args [ - 1 ] , # sample data for getting suitable levels
2371+ Z_sample , # sample data for getting suitable levels
23532372 levels = levels , values = values ,
23542373 norm = norm , norm_kw = norm_kw ,
23552374 locator = locator , locator_kw = locator_kw ,
@@ -2471,7 +2490,7 @@ def cmap_changer(
24712490 if colorbar :
24722491 loc = self ._loc_translate (colorbar , 'colorbar' , allow_manual = False )
24732492 if 'label' not in colorbar_kw and self .figure ._auto_format :
2474- _ , label = _standard_label ( args [ - 1 ] ) # last one is data, we assume
2493+ _ , label = _axis_labels_title ( Z_sample ) # last one is data, we assume
24752494 if label :
24762495 colorbar_kw .setdefault ('label' , label )
24772496 if name in ('parametric' ,) and values is not None :
0 commit comments