@@ -2184,6 +2184,23 @@ def text_wrapper(
21842184 return obj
21852185
21862186
2187+ def _iter_legend_objects (objs ):
2188+ """
2189+ Retrieve the (object, label) pairs for objects with actual labels
2190+ from nested lists and tuples of objects.
2191+ """
2192+ # Account for (1) multiple columns of data, (2) functions that return
2193+ # multiple values (e.g. hist() returns (bins, values, patches)), and
2194+ # (3) matplotlib.Collection list subclasses.
2195+ if isinstance (objs , (list , tuple )):
2196+ for obj in objs :
2197+ yield from _iter_legend_objects (obj )
2198+ elif hasattr (objs , 'get_label' ):
2199+ label = objs .get_label ()
2200+ if label and label [:1 ] != '_' :
2201+ yield (objs , label )
2202+
2203+
21872204def cycle_changer (
21882205 self , func , * args ,
21892206 cycle = None , cycle_kw = None ,
@@ -2253,18 +2270,29 @@ def cycle_changer(
22532270 proplot.constructor.Cycle
22542271 proplot.constructor.Colors
22552272 """
2256- # Parse input args
2273+ # Parse positional args
22572274 # NOTE: Requires standardize_1d wrapper before reaching this. Also note
22582275 # that the 'x' coordinates are sometimes ignored below.
22592276 name = func .__name__
2260- autoformat = rc ['autoformat' ] # possibly manipulated by standardize_[12]d
22612277 if not args :
22622278 return func (self , * args , ** kwargs )
22632279 x , y , * args = args
22642280 ys = (y ,)
22652281 if len (args ) >= 1 and name in ('fill_between' , 'fill_betweenx' ):
22662282 ys , args = (y , args [0 ]), args [1 :]
2283+ # Parse keyword args
2284+ autoformat = rc ['autoformat' ] # possibly manipulated by standardize_[12]d
22672285 barh = stacked = False
2286+ cycle_kw = cycle_kw or {}
2287+ legend_kw = legend_kw or {}
2288+ colorbar_kw = colorbar_kw or {}
2289+ labels = _not_none (
2290+ values = values ,
2291+ labels = labels ,
2292+ label = label ,
2293+ legend_kw_labels = legend_kw .pop ('labels' , None ),
2294+ )
2295+ colorbar_legend_label = None # for colorbar or legend
22682296 if name in ('pie' ,): # add x coordinates as default pie chart labels
22692297 kwargs ['labels' ] = _not_none (labels , x ) # TODO: move to pie wrapper?
22702298 if name in ('bar' , 'fill_between' , 'fill_betweenx' ):
@@ -2274,9 +2302,6 @@ def cycle_changer(
22742302 width = kwargs .pop ('width' , 0.8 ) # 'width' for bar *and* barh (see bar_wrapper)
22752303 bottom = 'x' if barh else 'bottom'
22762304 kwargs .setdefault (bottom , 0 ) # 'x' required even though 'y' isn't for bar plots
2277- cycle_kw = cycle_kw or {}
2278- legend_kw = legend_kw or {}
2279- colorbar_kw = colorbar_kw or {}
22802305
22812306 # Determine and temporarily set cycler
22822307 # NOTE: Axes cycle has no getter, only set_prop_cycle, which sets a
@@ -2348,13 +2373,10 @@ def cycle_changer(
23482373 # assumed! This is fixed in parse_1d by converting to values.
23492374 y1 = ys [0 ]
23502375 ncols = 1
2351- labels = _not_none (values = values , labels = labels , label = label )
2352- colorbar_legend_label = None # for colorbar or legend
23532376 if name in ('pie' , 'boxplot' , 'violinplot' ):
2354- # Pass labels directly to functions
2377+ # Functions handle multiple labels on their own
23552378 if labels is not None :
23562379 kwargs ['labels' ] = labels # error raised down the line
2357-
23582380 else :
23592381 # Get column count and sanitize labels
23602382 ncols = 1 if y .ndim == 1 else y .shape [1 ]
@@ -2497,14 +2519,10 @@ def cycle_changer(
24972519 if errobjs_join :
24982520 legobjs = [(* legobjs , * errobjs_join )[::- 1 ]]
24992521 legobjs .extend (errobjs_separate )
2500- for _ in range (3 ):
2501- # Account for (1) multiple columns of data, (2) functions that return
2502- # multiple values (e.g. hist() returns (bins, values, patches)), and
2503- # (3) matplotlib.Collection list subclasses.
2504- legobjs = [
2505- obj [- 1 ] if isinstance (obj , (list , tuple )) else obj
2506- for obj in legobjs
2507- ]
2522+ try :
2523+ legobjs , labels = list (zip (* _iter_legend_objects (legobjs )))
2524+ except ValueError :
2525+ legobjs = labels = ()
25082526
25092527 # Add handles and labels
25102528 # NOTE: Important to add labels as *keyword* so users can override
0 commit comments