mirror of https://github.com/Kozea/pygal.git
Python to generate nice looking SVG graph
http://pygal.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.2 KiB
112 lines
3.2 KiB
#!python |
|
|
|
from itertools import chain, repeat, izip |
|
import datetime |
|
|
|
# from itertools recipes (python documentation) |
|
def grouper(n, iterable, padvalue=None): |
|
""" |
|
>>> tuple(grouper(3, 'abcdefg', 'x')) |
|
(('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'x', 'x')) |
|
""" |
|
return izip(*[chain(iterable, repeat(padvalue, n-1))]*n) |
|
|
|
def reverse_mapping(mapping): |
|
""" |
|
For every key, value pair, return the mapping for the |
|
equivalent value, key pair |
|
>>> reverse_mapping({'a': 'b'}) == {'b': 'a'} |
|
True |
|
""" |
|
keys, values = zip(*mapping.items()) |
|
return dict(zip(values, keys)) |
|
|
|
def flatten_mapping(mapping): |
|
""" |
|
For every key that has an __iter__ method, assign the values |
|
to a key for each. |
|
>>> flatten_mapping({'ab': 3, ('c','d'): 4}) == {'ab': 3, 'c': 4, 'd': 4} |
|
True |
|
""" |
|
return dict(flatten_items(mapping.items())) |
|
|
|
def flatten_items(items): |
|
for keys, value in items: |
|
if hasattr(keys, '__iter__'): |
|
for key in keys: |
|
yield (key, value) |
|
else: |
|
yield (keys, value) |
|
|
|
def float_range(start=0, stop=None, step=1): |
|
""" |
|
Much like the built-in function range, but accepts floats |
|
>>> tuple(float_range(0, 9, 1.5)) |
|
(0.0, 1.5, 3.0, 4.5, 6.0, 7.5) |
|
""" |
|
start = float(start) |
|
while start < stop: |
|
yield start |
|
start += step |
|
|
|
def date_range(start=None, stop=None, step=None): |
|
""" |
|
Much like the built-in function range, but works with dates |
|
>>> my_range = tuple(date_range(datetime.datetime(2005,12,21), datetime.datetime(2005,12,25))) |
|
>>> datetime.datetime(2005,12,21) in my_range |
|
True |
|
>>> datetime.datetime(2005,12,22) in my_range |
|
True |
|
>>> datetime.datetime(2005,12,25) in my_range |
|
False |
|
""" |
|
if step is None: step = datetime.timedelta(days=1) |
|
if start is None: start = datetime.datetime.now() |
|
while start < stop: |
|
yield start |
|
start += step |
|
|
|
# copied from jaraco.datetools |
|
def divide_timedelta_float(td, divisor): |
|
""" |
|
Meant to work around the limitation that Python datetime doesn't support |
|
floats as divisors or multiplicands to datetime objects |
|
>>> one_day = datetime.timedelta(days=1) |
|
>>> half_day = datetime.timedelta(days=.5) |
|
>>> divide_timedelta_float(one_day, 2.0) == half_day |
|
True |
|
>>> divide_timedelta_float(one_day, 2) == half_day |
|
False |
|
""" |
|
# td is comprised of days, seconds, microseconds |
|
dsm = [getattr(td, attr) for attr in ('days', 'seconds', 'microseconds')] |
|
dsm = map(lambda elem: elem/divisor, dsm) |
|
return datetime.timedelta(*dsm) |
|
|
|
def get_timedelta_total_microseconds(td): |
|
seconds = td.days*86400 + td.seconds |
|
microseconds = td.microseconds + seconds*(10**6) |
|
return microseconds |
|
|
|
def divide_timedelta(td1, td2): |
|
""" |
|
Get the ratio of two timedeltas |
|
>>> one_day = datetime.timedelta(days=1) |
|
>>> one_hour = datetime.timedelta(hours=1) |
|
>>> divide_timedelta(one_hour, one_day) == 1/24.0 |
|
True |
|
""" |
|
|
|
td1_total = float(get_timedelta_total_microseconds(td1)) |
|
td2_total = float(get_timedelta_total_microseconds(td2)) |
|
return td1_total/td2_total |
|
|
|
class TimeScale(object): |
|
"Describes a scale factor based on time instead of a scalar" |
|
def __init__(self, width, range): |
|
self.width = width |
|
self.range = range |
|
|
|
def __mul__(self, delta): |
|
scale = divide_timedelta(delta, self.range) |
|
return scale*self.width |