Skip to content

Commit

Permalink
Merge pull request #26 from tacaswell/enh_by_key
Browse files Browse the repository at this point in the history
ENH: add by_key
  • Loading branch information
efiring committed Dec 13, 2015
2 parents 78f477d + 714b346 commit 233c66d
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 13 deletions.
33 changes: 20 additions & 13 deletions cycler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -346,17 +346,21 @@ def _repr_html_(self):
output += "</table>"
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
Expand All @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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))


Expand Down
20 changes: 20 additions & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
--------

Expand Down
32 changes: 32 additions & 0 deletions test_cycler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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():
Expand Down Expand Up @@ -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

0 comments on commit 233c66d

Please sign in to comment.