Browse Source

Make tests pass for DateY + Pep8

pull/32/head
Florian Mounier 12 years ago
parent
commit
64501f61c0
  1. 15
      demo/moulinrouge/tests.py
  2. 13
      pygal/adapters.py
  3. 10
      pygal/graph/base.py
  4. 49
      pygal/graph/datey.py
  5. 11
      pygal/test/__init__.py
  6. 10
      pygal/util.py

15
demo/moulinrouge/tests.py

@ -2,7 +2,7 @@
# This file is part of pygal # This file is part of pygal
from pygal import ( from pygal import (
Bar, Gauge, Pyramid, Funnel, Dot, StackedBar, XY, Bar, Gauge, Pyramid, Funnel, Dot, StackedBar, XY,
CHARTS_BY_NAME, Config, Line) CHARTS_BY_NAME, Config, Line, DateY)
from pygal.style import styles from pygal.style import styles
@ -248,4 +248,17 @@ def get_test_routes(app):
stacked.add('2', [4, 5, 6]) stacked.add('2', [4, 5, 6])
return stacked.render_response() return stacked.render_response()
@app.route('/test/datey')
def test_datey():
from datetime import datetime
datey = DateY(show_dots=False)
datey.add('1', [
(datetime(2011, 12, 21), 10),
(datetime(2013, 4, 8), 12),
(datetime(2010, 2, 28), 2)
])
datey.add('2', [(12, 4), (219, 8), (928, 6)])
datey.x_label_rotation = 25
return datey.render_response()
return filter(lambda x: x.startswith('test'), locals()) return filter(lambda x: x.startswith('test'), locals())

13
pygal/adapters.py

@ -20,6 +20,8 @@
Value adapters to use when a chart doesn't accept all value types Value adapters to use when a chart doesn't accept all value types
""" """
import datetime
from numbers import Number
def positive(x): def positive(x):
@ -38,3 +40,14 @@ def not_zero(x):
def none_to_zero(x): def none_to_zero(x):
return x or 0 return x or 0
def date(x):
# Make int work for date graphs by counting days number from now
if isinstance(x, Number):
try:
d = datetime.date.today() + datetime.timedelta(days=x)
return datetime.datetime.combine(d, datetime.time(0, 0, 0))
except OverflowError:
return None
return x

10
pygal/graph/base.py

@ -52,9 +52,17 @@ class BaseGraph(object):
self.view = None self.view = None
if self.logarithmic and self.zero == 0: if self.logarithmic and self.zero == 0:
# Explicit min to avoid interpolation dependency # Explicit min to avoid interpolation dependency
from pygal.graph.xy import XY
if isinstance(self, XY):
get = lambda x: x[1]
else:
get = lambda x: x
positive_values = filter( positive_values = filter(
lambda x: x > 0, lambda x: x > 0,
[val for serie in self.series for val in serie.safe_values]) [get(val)
for serie in self.series for val in serie.safe_values])
self.zero = min(positive_values) if positive_values else 0 self.zero = min(positive_values) if positive_values else 0
self._draw() self._draw()
self.svg.pre_render() self.svg.pre_render()

49
pygal/graph/datey.py

@ -27,46 +27,52 @@ from datetime import datetime,timedelta
def jour(n) : def jour(n) :
return datetime(year=2013,month=1,day=1)+timedelta(days=n) return datetime(year=2013,month=1,day=1)+timedelta(days=n)
x=(1,20,35,54,345,898) x=(1,20,35,54,345,898)
x=tuple(map(jour,x)) x=tuple(map(jour,x))
y=(1,3,4,2,3,1) y=(1,3,4,2,3,1)
graph=pygal.DateY(x_label_rotation=20) graph=pygal.DateY(x_label_rotation=20)
graph.add("graph1",list(zip(x,y))+[None,None]) graph.add("graph1",list(zip(x,y))+[None,None])
graph.render_in_browser() graph.render_in_browser()
""" """
from pygal.adapters import date
from pygal.util import compute_scale from pygal.util import compute_scale
from pygal.graph.line import Line from pygal.graph.xy import XY
from pygal.graph.xy import XY
import datetime import datetime
class DateY(XY): class DateY(XY):
""" DateY Graph """ """ DateY Graph """
_offset=datetime.datetime(year=2000,month=1,day=1) _offset = datetime.datetime(year=2000, month=1, day=1)
def _todate(self, d) : _adapters = [date]
""" Converts a number to a date """
return str(self._offset+datetime.timedelta(seconds=d)) def _todate(self, d):
def _tonumber(self,d) : """ Converts a number to a date """
return str(self._offset + datetime.timedelta(seconds=d))
def _tonumber(self, d):
""" Converts a date to a number """ """ Converts a date to a number """
if d==None: return None if d is None:
return (d-self._offset).total_seconds() return None
return (d - self._offset).total_seconds()
def _get_value(self, values, i): def _get_value(self, values, i):
return 'x=%s, y=%s' % (self._todate(values[i][0]),self._format(values[i][1])) return 'x=%s, y=%s' % (
self._todate(values[i][0]), self._format(values[i][1]))
def _compute(self): def _compute(self):
# Approximatively the same code as in XY. # Approximatively the same code as in XY.
# The only difference is the transformation of dates to numbers # The only difference is the transformation of dates to numbers
# (beginning) and the reversed transforamtion to dates (end) # (beginning) and the reversed transformation to dates (end)
self._offset = min([val[0] self._offset = min([val[0]
for serie in self.series for serie in self.series
for val in serie.values for val in serie.values
if val[0] is not None]) if val[0] is not None]
for serie in self.series : or [datetime.datetime.fromtimestamp(0)])
serie.values=[(self._tonumber(v[0]),v[1]) for v in serie.values] for serie in self.series:
serie.values = [(self._tonumber(v[0]), v[1]) for v in serie.values]
xvals = [val[0] xvals = [val[0]
for serie in self.series for serie in self.series
for val in serie.values for val in serie.values
@ -86,7 +92,8 @@ class DateY(XY):
serie.points = serie.values serie.points = serie.values
if self.interpolate and rng: if self.interpolate and rng:
vals = list(zip(*sorted( vals = list(zip(*sorted(
[t for t in serie.points if None not in t], key=lambda x: x[0]))) [t for t in serie.points if None not in t],
key=lambda x: x[0])))
serie.interpolated = self._interpolate( serie.interpolated = self._interpolate(
vals[1], vals[0], xy=True, xy_xmin=xmin, xy_rng=rng) vals[1], vals[0], xy=True, xy_xmin=xmin, xy_rng=rng)

11
pygal/test/__init__.py

@ -19,6 +19,7 @@
import pygal import pygal
from pygal.util import cut from pygal.util import cut
from datetime import datetime
def get_data(i): def get_data(i):
@ -43,8 +44,16 @@ def pytest_generate_tests(metafunc):
def make_data(chart, datas, secondary=False): def make_data(chart, datas, secondary=False):
def get(data):
if isinstance(chart, pygal.XY):
if isinstance(chart, pygal.DateY):
# Convert to a credible datetime
return datetime.fromtimestamp(1360000000 + data * 987654)
return data
return cut(data)
for data in datas: for data in datas:
chart.add(data[0], chart.add(data[0],
data[1] if chart.__class__ == pygal.XY else cut(data[1]), get(data[1]),
secondary=secondary) secondary=secondary)
return chart return chart

10
pygal/util.py

@ -297,6 +297,9 @@ from pygal.serie import Serie
def prepare_values(raw, config, cls): def prepare_values(raw, config, cls):
"""Prepare the values to start with sane values""" """Prepare the values to start with sane values"""
from pygal.graph.xy import XY
from pygal.graph.datey import DateY
if not raw: if not raw:
return return
@ -333,12 +336,15 @@ def prepare_values(raw, config, cls):
else: else:
value = raw_value value = raw_value
if cls.__name__ == 'XY' or cls.__name__ == 'DateY': if issubclass(cls, XY):
if value is None: if value is None:
value = (None, None) value = (None, None)
elif not hasattr(value, '__iter__'): elif not hasattr(value, '__iter__'):
value = (value, config.zero) value = (value, config.zero)
value = map(adapter, value) if issubclass(cls, DateY):
value = (adapter(value[0]), value[1])
else:
value = map(adapter, value)
else: else:
value = adapter(value) value = adapter(value)

Loading…
Cancel
Save