diff --git a/cycler.py b/cycler.py index 0ac2376..45d1557 100644 --- a/cycler.py +++ b/cycler.py @@ -216,7 +216,7 @@ def _from_iter(cls, label, itr): def __getitem__(self, key): # TODO : maybe add numpy style fancy slicing if isinstance(key, slice): - trans = self._transpose() + trans = self.by_key() return reduce(add, (_cycler(k, v[key]) for k, v in six.iteritems(trans))) else: @@ -255,7 +255,7 @@ def __mul__(self, other): if isinstance(other, Cycler): return Cycler(self, other, product) elif isinstance(other, int): - trans = self._transpose() + trans = self.by_key() return reduce(add, (_cycler(k, v*other) for k, v in six.iteritems(trans))) else: @@ -346,17 +346,21 @@ def _repr_html_(self): output += "" return output - def _transpose(self): - """ - Internal helper function which iterates through the - styles and returns a dict of lists instead of a list of - dicts. This is needed for multiplying by integers and - for __getitem__ + def by_key(self): + """Values by key + + This returns the transposed values of the cycler. Iterating + over a `Cycler` yields dicts with a single value for each key, + this method returns a `dict` of `list` which are the values + for the given key. + + The returned value can be used to create an equivalent `Cycler` + using only `+`. Returns ------- - trans : dict - dict of lists for the styles + transpose : dict + dict of lists of the values for each key. """ # TODO : sort out if this is a bottle neck, if there is a better way @@ -371,6 +375,9 @@ def _transpose(self): out[k].append(d[k]) return out + # for back compatibility + _transpose = by_key + def simplify(self): """Simplify the Cycler @@ -386,7 +393,7 @@ def simplify(self): # ((a + b) + (c + d)) # I would believe that there is some performance implications - trans = self._transpose() + trans = self.by_key() return reduce(add, (_cycler(k, v) for k, v in six.iteritems(trans))) def concat(self, other): @@ -453,8 +460,8 @@ def concat(left, right): raise ValueError(msg) - _l = left._transpose() - _r = right._transpose() + _l = left.by_key() + _r = right.by_key() return reduce(add, (_cycler(k, _l[k] + _r[k]) for k in left.keys)) diff --git a/doc/source/index.rst b/doc/source/index.rst index ddf21a7..b62a5ba 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -210,6 +210,26 @@ Cycles can be sliced with :obj:`slice` objects to return a sub-set of the cycle as a new `Cycler`. +Inspecting the `Cycler` +----------------------- + +To inspect the values of the transposed `Cycler` use +the `Cycler.by_key` method: + +.. ipython:: python + + c_m.by_key() + +This `dict` can be mutated and used to create a new `Cycler` with +the updated values + +.. ipython:: python + + bk = c_m.by_key() + bk['color'] = ['green'] * len(c_m) + cycler(**bk) + + Examples -------- diff --git a/test_cycler.py b/test_cycler.py index d1dc11e..f65a4cd 100644 --- a/test_cycler.py +++ b/test_cycler.py @@ -7,6 +7,7 @@ assert_raises, assert_true) from itertools import product, cycle, chain from operator import add, iadd, mul, imul +from collections import defaultdict def _cycler_helper(c, length, keys, values): @@ -95,6 +96,8 @@ def test_failures(): assert_raises(ValueError, iadd, c1, c2) assert_raises(ValueError, mul, c1, c2) assert_raises(ValueError, imul, c1, c2) + assert_raises(TypeError, iadd, c2, 'aardvark') + assert_raises(TypeError, imul, c2, 'aardvark') c3 = cycler(ec=c1) @@ -265,6 +268,8 @@ def test_eq(): yield _eq_test_helper, a, c, False d = cycler(c='ymk') yield _eq_test_helper, b, d, False + e = cycler(c='orange') + yield _eq_test_helper, b, e, False def test_cycler_exceptions(): @@ -296,3 +301,30 @@ def test_concat_fail(): b = cycler('b', range(3)) assert_raises(ValueError, concat, a, b) assert_raises(ValueError, a.concat, b) + + +def _by_key_helper(cy): + res = cy.by_key() + target = defaultdict(list) + for sty in cy: + for k, v in sty.items(): + target[k].append(v) + + assert_equal(res, target) + + +def test_by_key_add(): + input_dict = dict(c=list('rgb'), lw=[1, 2, 3]) + cy = cycler(c=input_dict['c']) + cycler(lw=input_dict['lw']) + res = cy.by_key() + assert_equal(res, input_dict) + yield _by_key_helper, cy + + +def test_by_key_mul(): + input_dict = dict(c=list('rg'), lw=[1, 2, 3]) + cy = cycler(c=input_dict['c']) * cycler(lw=input_dict['lw']) + res = cy.by_key() + assert_equal(input_dict['lw'] * len(input_dict['c']), + res['lw']) + yield _by_key_helper, cy