diff --git a/pygal/graph/datey.py b/pygal/graph/datey.py
index bda6d6e..51909d2 100644
--- a/pygal/graph/datey.py
+++ b/pygal/graph/datey.py
@@ -30,8 +30,12 @@ def jour(n) :
x=(1,20,35,54,345,898)
x=tuple(map(jour,x))
+x_label=(0,100,200,300,400,500,600,700,800,900,1000)
+x_label=map(jour,x_label)
y=(1,3,4,2,3,1)
graph=pygal.DateY(x_label_rotation=20)
+graph.x_label_format = "%Y-%m-%d"
+graph.x_labels = x_label
graph.add("graph1",list(zip(x,y))+[None,None])
graph.render_in_browser()
"""
@@ -75,27 +79,19 @@ class DateY(XY):
for serie in self.all_series:
serie.values = [(self._tonumber(v[0]), v[1]) for v in serie.values]
- xvals = [val[0]
- for serie in self.series
- for val in serie.values
- if val[0] is not None]
- yvals = [val[1]
- for serie in self.series
- for val in serie.values
- if val[1] is not None]
- if xvals:
- xmin = min(xvals)
- xmax = max(xvals)
+ if self.xvals:
+ xmin = min(self.xvals)
+ xmax = max(self.xvals)
rng = (xmax - xmin)
else:
rng = None
- if yvals:
- ymin = min(yvals)
- ymax = max(yvals)
+ if self.yvals:
+ ymin = self._min
+ ymax = self._max
if self.include_x_axis:
- ymin = min(ymin or 0, 0)
- ymax = max(ymax or 0, 0)
+ ymin = min(self._min or 0, 0)
+ ymax = max(self._max or 0, 0)
for serie in self.all_series:
serie.points = serie.values
@@ -106,25 +102,46 @@ class DateY(XY):
serie.interpolated = self._interpolate(vals[0], vals[1])
if self.interpolate and rng:
- xvals = [val[0]
- for serie in self.all_series
- for val in serie.interpolated]
- yvals = [val[1]
- for serie in self.all_series
- for val in serie.interpolated]
- if xvals:
- xmin = min(xvals)
- xmax = max(xvals)
+ self.xvals = [val[0]
+ for serie in self.all_series
+ for val in serie.interpolated]
+ self.yvals = [val[1]
+ for serie in self.all_series
+ for val in serie.interpolated]
+ if self.xvals:
+ xmin = min(self.xvals)
+ xmax = max(self.xvals)
rng = (xmax - xmin)
else:
rng = None
- if rng:
+ # Calculate/prcoess the x_labels
+ if self.x_labels and all(
+ map(lambda x: isinstance(
+ x, (datetime.datetime, datetime.date)), self.x_labels)):
+ # Process the given x_labels
+ x_labels_num = []
+ for label in self.x_labels:
+ x_labels_num.append(self._tonumber(label))
+ x_pos = x_labels_num
+
+ # Update the xmin/xmax to fit all of the x_labels and the data
+ xmin = min(xmin, min(x_pos))
+ xmax = max(xmax, max(x_pos))
+
self._box.xmin, self._box.xmax = xmin, xmax
self._box.ymin, self._box.ymax = ymin, ymax
+ else:
+ # Automatically generate the x_labels
+ if rng:
+ self._box.xmin, self._box.xmax = xmin, xmax
+ self._box.ymin, self._box.ymax = ymin, ymax
+
+ x_pos = compute_scale(
+ self._box.xmin, self._box.xmax, self.logarithmic,
+ self.order_min)
- x_pos = compute_scale(
- self._box.xmin, self._box.xmax, self.logarithmic, self.order_min)
+ # Always auto-generate the y labels
y_pos = compute_scale(
self._box.ymin, self._box.ymax, self.logarithmic, self.order_min)
diff --git a/pygal/graph/xy.py b/pygal/graph/xy.py
index 24272ac..292c3a5 100644
--- a/pygal/graph/xy.py
+++ b/pygal/graph/xy.py
@@ -44,12 +44,22 @@ class XY(Line):
for val in serie.values
if val[1] is not None]
+ @cached_property
+ def _min(self):
+ return (self.range[0] if (self.range and self.range[0] is not None)
+ else (min(self.yvals) if self.yvals else None))
+
+ @cached_property
+ def _max(self):
+ return (self.range[1] if (self.range and self.range[1] is not None)
+ else (max(self.yvals) if self.yvals else None))
+
def _has_data(self):
"""Check if there is any data"""
return sum(
map(len, map(lambda s: s.safe_values, self.series))) != 0 and any((
- sum(map(abs, self.xvals)) != 0,
- sum(map(abs, self.yvals)) != 0))
+ sum(map(abs, self.xvals)) != 0,
+ sum(map(abs, self.yvals)) != 0))
def _compute(self):
if self.xvals:
@@ -60,8 +70,8 @@ class XY(Line):
xrng = None
if self.yvals:
- ymin = min(self.yvals)
- ymax = max(self.yvals)
+ ymin = self._min
+ ymax = self._max
if self.include_x_axis:
ymin = min(ymin or 0, 0)
diff --git a/pygal/svg.py b/pygal/svg.py
index 76956fe..f09bbff 100644
--- a/pygal/svg.py
+++ b/pygal/svg.py
@@ -26,7 +26,7 @@ from pygal._compat import to_str, u
import io
import os
import json
-from datetime import date
+from datetime import date, datetime
from numbers import Number
from lxml import etree
from math import cos, sin, pi
@@ -97,7 +97,12 @@ class Svg(object):
"""Add the js to the svg"""
common_script = self.node(self.defs, 'script', type='text/javascript')
common_script.text = " = ".join(
- ("window.config", json.dumps(self.graph.config.to_dict())))
+ ("window.config", json.dumps(
+ self.graph.config.to_dict(),
+ default=lambda o: (
+ o.isoformat() if isinstance(o, (datetime, date))
+ else json.JSONEncoder().default(o))
+ )))
for js in self.graph.js:
if '://' in js:
diff --git a/pygal/test/test_date.py b/pygal/test/test_date.py
new file mode 100644
index 0000000..391a658
--- /dev/null
+++ b/pygal/test/test_date.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+# This file is part of pygal
+#
+# A python svg graph plotting library
+# Copyright © 2012-2014 Kozea
+#
+# This library is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This library is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with pygal. If not, see .
+from pygal import DateY
+from pygal.test.utils import texts
+from datetime import datetime
+
+
+def test_date():
+ datey = DateY(truncate_label=1000)
+ datey.add('dates', [
+ (datetime(2013, 1, 2), 300),
+ (datetime(2013, 1, 12), 412),
+ (datetime(2013, 2, 2), 823),
+ (datetime(2013, 2, 22), 672)
+ ])
+
+ q = datey.render_pyquery()
+
+ assert list(
+ map(lambda t: t.split(' ')[0],
+ q(".axis.x text").map(texts))) == [
+ '2013-01-02',
+ '2013-01-13',
+ '2013-01-25',
+ '2013-02-05',
+ '2013-02-17'
+ ]
+
+ datey.x_labels = [
+ datetime(2013, 1, 1),
+ datetime(2013, 2, 1),
+ datetime(2013, 3, 1)
+ ]
+
+ q = datey.render_pyquery()
+ assert list(
+ map(lambda t: t.split(' ')[0],
+ q(".axis.x text").map(texts))) == [
+ '2013-01-01',
+ '2013-02-01',
+ '2013-03-01'
+ ]
diff --git a/pygal/test/test_graph.py b/pygal/test/test_graph.py
index dbefd1f..30c0a4a 100644
--- a/pygal/test/test_graph.py
+++ b/pygal/test/test_graph.py
@@ -16,6 +16,7 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see .
+
import os
import pygal
import uuid