77You can add cyclers::
88
99 from cycler import cycler
10- cc = (cycler(' color', list('rgb')) +
11- cycler(' linestyle', ['-', '--', '-.']))
10+ cc = (cycler(color= list('rgb')) +
11+ cycler(linestyle= ['-', '--', '-.']))
1212 for d in cc:
1313 print(d)
1414
2222You can multiply cyclers::
2323
2424 from cycler import cycler
25- cc = (cycler(' color', list('rgb')) *
26- cycler(' linestyle', ['-', '--', '-.']))
25+ cc = (cycler(color= list('rgb')) *
26+ cycler(linestyle= ['-', '--', '-.']))
2727 for d in cc:
2828 print(d)
2929
@@ -113,8 +113,8 @@ def __init__(self, left, right=None, op=None):
113113 Do not use this directly, use `cycler` function instead.
114114 """
115115 self ._keys = _process_keys (left , right )
116- self ._left = copy .copy (left )
117- self ._right = copy .copy (right )
116+ self ._left = copy .deepcopy (left )
117+ self ._right = copy .deepcopy (right )
118118 self ._op = op
119119
120120 @property
@@ -164,7 +164,7 @@ def __getitem__(self, key):
164164 # TODO : maybe add numpy style fancy slicing
165165 if isinstance (key , slice ):
166166 trans = self ._transpose ()
167- return reduce (add , (cycler (k , v [key ])
167+ return reduce (add , (_cycler (k , v [key ])
168168 for k , v in six .iteritems (trans )))
169169 else :
170170 raise ValueError ("Can only use slices with Cycler.__getitem__" )
@@ -203,7 +203,7 @@ def __mul__(self, other):
203203 return Cycler (self , other , product )
204204 elif isinstance (other , int ):
205205 trans = self ._transpose ()
206- return reduce (add , (cycler (k , v * other )
206+ return reduce (add , (_cycler (k , v * other )
207207 for k , v in six .iteritems (trans )))
208208 else :
209209 return NotImplemented
@@ -228,11 +228,11 @@ def __iadd__(self, other):
228228 other : Cycler
229229 The second Cycler
230230 """
231- old_self = copy .copy (self )
231+ old_self = copy .deepcopy (self )
232232 self ._keys = _process_keys (old_self , other )
233233 self ._left = old_self
234234 self ._op = zip
235- self ._right = copy .copy (other )
235+ self ._right = copy .deepcopy (other )
236236 return self
237237
238238 def __imul__ (self , other ):
@@ -245,11 +245,11 @@ def __imul__(self, other):
245245 The second Cycler
246246 """
247247
248- old_self = copy .copy (self )
248+ old_self = copy .deepcopy (self )
249249 self ._keys = _process_keys (old_self , other )
250250 self ._left = old_self
251251 self ._op = product
252- self ._right = copy .copy (other )
252+ self ._right = copy .deepcopy (other )
253253 return self
254254
255255 def __eq__ (self , other ):
@@ -329,17 +329,76 @@ def simplify(self):
329329 # I would believe that there is some performance implications
330330
331331 trans = self ._transpose ()
332- return reduce (add , (cycler (k , v ) for k , v in six .iteritems (trans )))
332+ return reduce (add , (_cycler (k , v ) for k , v in six .iteritems (trans )))
333333
334334
335- def cycler (label , itr ):
335+ def cycler (* args , ** kwargs ):
336+ """
337+ Create a new `Cycler` object from a single positional argument,
338+ a pair of positional arguments, or the combination of keyword arguments.
339+
340+ cycler(arg)
341+ cycler(label1=itr1[, label2=iter2[, ...]])
342+ cycler(label, itr)
343+
344+ Form 1 simply copies a given `Cycler` object.
345+
346+ Form 2 composes a `Cycler` as an inner product of the
347+ pairs of keyword arguments. In other words, all of the
348+ iterables are cycled simultaneously, as if through zip().
349+
350+ Form 3 creates a `Cycler` from a label and an iterable.
351+ This is useful for when the label cannot be a keyword argument
352+ (e.g., an integer or a name that has a space in it).
353+
354+ Parameters
355+ ----------
356+ arg : Cycler
357+ Copy constructor for Cycler.
358+
359+ label : name
360+ The property key. In the 2-arg form of the function,
361+ the label can be any hashable object. In the keyword argument
362+ form of the function, it must be a valid python identifier.
363+
364+ itr : iterable
365+ Finite length iterable of the property values.
366+
367+ Returns
368+ -------
369+ cycler : Cycler
370+ New `Cycler` for the given property
371+
372+ """
373+ if args and kwargs :
374+ raise TypeError ("cyl() can only accept positional OR keyword "
375+ "arguments -- not both." )
376+
377+ if len (args ) == 1 :
378+ if not isinstance (args [0 ], Cycler ):
379+ raise TypeError ("If only one positional argument given, it must "
380+ " be a Cycler instance." )
381+ return copy .deepcopy (args [0 ])
382+ elif len (args ) == 2 :
383+ return _cycler (* args )
384+ elif len (args ) > 2 :
385+ raise TypeError ("Only a single Cycler can be accepted as the lone "
386+ "positional argument. Use keyword arguments instead." )
387+
388+ if kwargs :
389+ return reduce (add , (_cycler (k , v ) for k , v in six .iteritems (kwargs )))
390+
391+ raise TypeError ("Must have at least a positional OR keyword arguments" )
392+
393+
394+ def _cycler (label , itr ):
336395 """
337396 Create a new `Cycler` object from a property name and
338397 iterable of values.
339398
340399 Parameters
341400 ----------
342- label : str
401+ label : hashable
343402 The property key.
344403
345404 itr : iterable
@@ -357,7 +416,7 @@ def cycler(label, itr):
357416 raise ValueError (msg )
358417
359418 if label in keys :
360- return copy .copy (itr )
419+ return copy .deepcopy (itr )
361420 else :
362421 lab = keys .pop ()
363422 itr = list (v [lab ] for v in itr )
0 commit comments