@@ -202,6 +202,42 @@ def _process_plot_format(fmt, *, ambiguous_fmt_datakey=False):
202202 return linestyle , marker , color
203203
204204
205+ class _PropCycle :
206+ """
207+ A class that holds the property cycle information.
208+
209+ It expands the iterator-based Cycler into an explicit indexed list to support
210+ conditional advancing.
211+ """
212+ def __init__ (self , cycler ):
213+ self ._idx = 0
214+ self ._cycler_items = [* cycler ]
215+
216+ def get_next_color (self ):
217+ """Return the next color in the cycle."""
218+ entry = self ._cycler_items [self ._idx ]
219+ if "color" in entry :
220+ self ._idx = (self ._idx + 1 ) % len (self ._cycler_items ) # Advance cycler.
221+ return entry ["color" ]
222+ else :
223+ return "k"
224+
225+ def getdefaults (self , kw , ignore = frozenset ()):
226+ """
227+ If some keys in the property cycle (excluding those in the set
228+ *ignore*) are absent or set to None in the dict *kw*, return a copy
229+ of the next entry in the property cycle, excluding keys in *ignore*.
230+ Otherwise, don't advance the property cycle, and return an empty dict.
231+ """
232+ defaults = self ._cycler_items [self ._idx ]
233+ if any (kw .get (k , None ) is None for k in {* defaults } - ignore ):
234+ self ._idx = (self ._idx + 1 ) % len (self ._cycler_items ) # Advance cycler.
235+ # Return a new dict to avoid exposing _cycler_items entries to mutation.
236+ return {k : v for k , v in defaults .items () if k not in ignore }
237+ else :
238+ return {}
239+
240+
205241class _process_plot_var_args :
206242 """
207243 Process variable length arguments to `~.Axes.plot`, to support ::
@@ -220,8 +256,7 @@ def __init__(self, output='Line2D'):
220256 self .set_prop_cycle (None )
221257
222258 def set_prop_cycle (self , cycler ):
223- self ._idx = 0
224- self ._cycler_items = [* mpl ._val_or_rc (cycler , 'axes.prop_cycle' )]
259+ self ._prop_cycle = _PropCycle (mpl ._val_or_rc (cycler , 'axes.prop_cycle' ))
225260
226261 def __call__ (self , axes , * args , data = None , return_kwargs = False , ** kwargs ):
227262 axes ._process_unit_info (kwargs = kwargs )
@@ -300,29 +335,10 @@ def __call__(self, axes, *args, data=None, return_kwargs=False, **kwargs):
300335
301336 def get_next_color (self ):
302337 """Return the next color in the cycle."""
303- entry = self ._cycler_items [self ._idx ]
304- if "color" in entry :
305- self ._idx = (self ._idx + 1 ) % len (self ._cycler_items ) # Advance cycler.
306- return entry ["color" ]
307- else :
308- return "k"
309-
310- def _getdefaults (self , kw , ignore = frozenset ()):
311- """
312- If some keys in the property cycle (excluding those in the set
313- *ignore*) are absent or set to None in the dict *kw*, return a copy
314- of the next entry in the property cycle, excluding keys in *ignore*.
315- Otherwise, don't advance the property cycle, and return an empty dict.
316- """
317- defaults = self ._cycler_items [self ._idx ]
318- if any (kw .get (k , None ) is None for k in {* defaults } - ignore ):
319- self ._idx = (self ._idx + 1 ) % len (self ._cycler_items ) # Advance cycler.
320- # Return a new dict to avoid exposing _cycler_items entries to mutation.
321- return {k : v for k , v in defaults .items () if k not in ignore }
322- else :
323- return {}
338+ return self ._prop_cycle .get_next_color ()
324339
325- def _setdefaults (self , defaults , kw ):
340+ @staticmethod
341+ def _setdefaults (defaults , kw ):
326342 """
327343 Add to the dict *kw* the entries in the dict *default* that are absent
328344 or set to None in *kw*.
@@ -333,13 +349,13 @@ def _setdefaults(self, defaults, kw):
333349
334350 def _make_line (self , axes , x , y , kw , kwargs ):
335351 kw = {** kw , ** kwargs } # Don't modify the original kw.
336- self ._setdefaults (self ._getdefaults (kw ), kw )
352+ self ._setdefaults (self ._prop_cycle . getdefaults (kw ), kw )
337353 seg = mlines .Line2D (x , y , ** kw )
338354 return seg , kw
339355
340356 def _make_coordinates (self , axes , x , y , kw , kwargs ):
341357 kw = {** kw , ** kwargs } # Don't modify the original kw.
342- self ._setdefaults (self ._getdefaults (kw ), kw )
358+ self ._setdefaults (self ._prop_cycle . getdefaults (kw ), kw )
343359 return (x , y ), kw
344360
345361 def _make_polygon (self , axes , x , y , kw , kwargs ):
@@ -367,7 +383,7 @@ def _make_polygon(self, axes, x, y, kw, kwargs):
367383 # for getting defaults for back-compat reasons.
368384 # Doing it with both seems to mess things up in
369385 # various places (probably due to logic bugs elsewhere).
370- default_dict = self ._getdefaults (kw , ignores )
386+ default_dict = self ._prop_cycle . getdefaults (kw , ignores )
371387 self ._setdefaults (default_dict , kw )
372388
373389 # Looks like we don't want "color" to be interpreted to
0 commit comments