From d5db1a4dc70401af69b79aa90f4864cc19a793a7 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Wed, 28 Mar 2012 10:52:08 +0200 Subject: [PATCH] Fix side effect on graph re-render + add cairosvg rendering to png --- demo/simple_test.py | 6 ++++-- pygal/graph/base.py | 14 +++++++++++++- pygal/graph/horizontal.py | 11 +++++++---- pygal/svg.py | 4 +++- pygal/test/test_graph.py | 27 +++++++++++++++++++++++++++ setup.py | 2 +- 6 files changed, 55 insertions(+), 9 deletions(-) diff --git a/demo/simple_test.py b/demo/simple_test.py index 6a9fa3f..4905084 100755 --- a/demo/simple_test.py +++ b/demo/simple_test.py @@ -46,7 +46,7 @@ hbar.x_labels = map( hbar.title = "Horizontal Bar test" # hbar.render_to_file('out-horizontalbar.svg') -rng = [3, -32, 39, 12] +rng = [30, -32, 39, 12] rng2 = [24, -8, 18, 12] rng3 = [6, 1, -10, 0] config = Config() @@ -70,7 +70,9 @@ hstackedbar = HorizontalStackedBar(config) hstackedbar.add('@@@@@@@', rng) hstackedbar.add('++++++', rng2) hstackedbar.add('--->', rng3) -# hstackedbar.render_to_file('out-horizontalstackedbar.svg') + +hstackedbar.render_to_file('out-horizontalstackedbar1.svg') +hstackedbar.render_to_file('out-horizontalstackedbar2.svg') line = Line(Config(style=NeonStyle, zero=.0001, fill=True, diff --git a/pygal/graph/base.py b/pygal/graph/base.py index 334100d..01fa5a5 100644 --- a/pygal/graph/base.py +++ b/pygal/graph/base.py @@ -15,8 +15,10 @@ class BaseGraph(object): self.config(**kwargs) self.svg = Svg(self) self.series = [] - self.margin = Margin(*([20] * 4)) self._x_labels = self._y_labels = None + + def _init(self): + self.margin = Margin(*([20] * 4)) self._box = Box() def __getattr__(self, attr): @@ -149,6 +151,7 @@ class BaseGraph(object): return True def _render(self): + self._init() self.svg._init() if self._has_data(): self._draw() @@ -179,3 +182,12 @@ class BaseGraph(object): def render_to_file(self, filename): with open(filename, 'w') as f: f.write(self.render()) + + def render_to_png(self, filename): + import cairosvg + import StringIO + fakefile = StringIO.StringIO() + fakefile.write(self.render()) + fakefile.seek(0) + cairosvg.surface.PNGSurface.convert( + file_obj=fakefile, write_to=filename) diff --git a/pygal/graph/horizontal.py b/pygal/graph/horizontal.py index 6bf23db..900487c 100644 --- a/pygal/graph/horizontal.py +++ b/pygal/graph/horizontal.py @@ -24,18 +24,21 @@ from pygal.graph.stackedbar import StackedBar class HorizontalGraph(Graph): """Horizontal graph""" def __init__(self, *args, **kwargs): + self.first_pass = True kwargs['_horizontal'] = True super(HorizontalGraph, self).__init__(*args, **kwargs) def _compute(self): - if self.x_labels: - self.x_labels = reversed(self.x_labels) + self.first_pass = False + if self.first_pass and self.x_labels: + self.x_labels = list(reversed(self.x_labels)) super(HorizontalGraph, self)._compute() self._x_labels, self._y_labels = self._y_labels, self._x_labels self._box.swap() # Y axis is inverted - for serie in self.series: - serie.values = reversed(serie.values) + if self.first_pass: + for serie in self.series: + serie.values = list(reversed(serie.values)) class HorizontalBar(HorizontalGraph, Bar): diff --git a/pygal/svg.py b/pygal/svg.py index 00c74d5..18f05d3 100644 --- a/pygal/svg.py +++ b/pygal/svg.py @@ -51,7 +51,7 @@ class Svg(object): style.text = templ.decode('utf-8') def add_script(self, js): - script = self.node(self.root, 'script', type='text/javascript') + script = self.node(self.defs, 'script', type='text/javascript') with open(js) as f: templ = template( f.read(), @@ -87,6 +87,8 @@ class Svg(object): return '%f %f' % xy def line(self, node, coords, close=False, **kwargs): + if len(coords) < 2: + return root = 'M%s L%s Z' if close else 'M%s L%s' origin_index = 0 while None in coords[origin_index]: diff --git a/pygal/test/test_graph.py b/pygal/test/test_graph.py index 258741b..c2be88e 100644 --- a/pygal/test/test_graph.py +++ b/pygal/test/test_graph.py @@ -18,6 +18,20 @@ # along with pygal. If not, see . import os from pygal import Line +import pygal + + +def test_multi_render(): + for Chart in pygal.CHARTS: + chart = Chart() + rng = range(20) + if Chart == pygal.XY: + rng = zip(rng, rng) + chart.add('Serie', rng) + chart.add('Serie 2', list(reversed(rng))) + svg = chart.render() + for i in range(2): + assert svg == chart.render() def test_render_to_file(): @@ -31,3 +45,16 @@ def test_render_to_file(): with open(file_name) as f: assert 'pygal' in f.read() os.remove(file_name) + + +def test_render_to_png(): + file_name = '/tmp/test_graph.png' + if os.path.exists(file_name): + os.remove(file_name) + + line = Line() + line.add('Serie 1', [1]) + line.render_to_png(file_name) + with open(file_name) as f: + assert f.read() + os.remove(file_name) diff --git a/setup.py b/setup.py index 9fb9059..44f058b 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ setup( packages=find_packages(), provides=['pygal'], scripts=["pygal_gen.py"], - keywords=["svg", "graph", "diagram", "plot", "histogram", "kiviat"], + keywords=["svg", "chart", "graph", "diagram", "plot", "histogram", "kiviat"], tests_require=["pytest", "pyquery", "flask"], package_data={'pygal': ['css/*', 'js/*']}, install_requires=['lxml'],