Browse Source

Fix side effect on graph re-render + add cairosvg rendering to png

pull/8/head
Florian Mounier 13 years ago
parent
commit
d5db1a4dc7
  1. 6
      demo/simple_test.py
  2. 14
      pygal/graph/base.py
  3. 11
      pygal/graph/horizontal.py
  4. 4
      pygal/svg.py
  5. 27
      pygal/test/test_graph.py
  6. 2
      setup.py

6
demo/simple_test.py

@ -46,7 +46,7 @@ hbar.x_labels = map(
hbar.title = "Horizontal Bar test" hbar.title = "Horizontal Bar test"
# hbar.render_to_file('out-horizontalbar.svg') # hbar.render_to_file('out-horizontalbar.svg')
rng = [3, -32, 39, 12] rng = [30, -32, 39, 12]
rng2 = [24, -8, 18, 12] rng2 = [24, -8, 18, 12]
rng3 = [6, 1, -10, 0] rng3 = [6, 1, -10, 0]
config = Config() config = Config()
@ -70,7 +70,9 @@ hstackedbar = HorizontalStackedBar(config)
hstackedbar.add('@@@@@@@', rng) hstackedbar.add('@@@@@@@', rng)
hstackedbar.add('++++++', rng2) hstackedbar.add('++++++', rng2)
hstackedbar.add('--->', rng3) 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, line = Line(Config(style=NeonStyle,
zero=.0001, fill=True, zero=.0001, fill=True,

14
pygal/graph/base.py

@ -15,8 +15,10 @@ class BaseGraph(object):
self.config(**kwargs) self.config(**kwargs)
self.svg = Svg(self) self.svg = Svg(self)
self.series = [] self.series = []
self.margin = Margin(*([20] * 4))
self._x_labels = self._y_labels = None self._x_labels = self._y_labels = None
def _init(self):
self.margin = Margin(*([20] * 4))
self._box = Box() self._box = Box()
def __getattr__(self, attr): def __getattr__(self, attr):
@ -149,6 +151,7 @@ class BaseGraph(object):
return True return True
def _render(self): def _render(self):
self._init()
self.svg._init() self.svg._init()
if self._has_data(): if self._has_data():
self._draw() self._draw()
@ -179,3 +182,12 @@ class BaseGraph(object):
def render_to_file(self, filename): def render_to_file(self, filename):
with open(filename, 'w') as f: with open(filename, 'w') as f:
f.write(self.render()) 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)

11
pygal/graph/horizontal.py

@ -24,18 +24,21 @@ from pygal.graph.stackedbar import StackedBar
class HorizontalGraph(Graph): class HorizontalGraph(Graph):
"""Horizontal graph""" """Horizontal graph"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.first_pass = True
kwargs['_horizontal'] = True kwargs['_horizontal'] = True
super(HorizontalGraph, self).__init__(*args, **kwargs) super(HorizontalGraph, self).__init__(*args, **kwargs)
def _compute(self): def _compute(self):
if self.x_labels: self.first_pass = False
self.x_labels = reversed(self.x_labels) if self.first_pass and self.x_labels:
self.x_labels = list(reversed(self.x_labels))
super(HorizontalGraph, self)._compute() super(HorizontalGraph, self)._compute()
self._x_labels, self._y_labels = self._y_labels, self._x_labels self._x_labels, self._y_labels = self._y_labels, self._x_labels
self._box.swap() self._box.swap()
# Y axis is inverted # Y axis is inverted
for serie in self.series: if self.first_pass:
serie.values = reversed(serie.values) for serie in self.series:
serie.values = list(reversed(serie.values))
class HorizontalBar(HorizontalGraph, Bar): class HorizontalBar(HorizontalGraph, Bar):

4
pygal/svg.py

@ -51,7 +51,7 @@ class Svg(object):
style.text = templ.decode('utf-8') style.text = templ.decode('utf-8')
def add_script(self, js): 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: with open(js) as f:
templ = template( templ = template(
f.read(), f.read(),
@ -87,6 +87,8 @@ class Svg(object):
return '%f %f' % xy return '%f %f' % xy
def line(self, node, coords, close=False, **kwargs): 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' root = 'M%s L%s Z' if close else 'M%s L%s'
origin_index = 0 origin_index = 0
while None in coords[origin_index]: while None in coords[origin_index]:

27
pygal/test/test_graph.py

@ -18,6 +18,20 @@
# along with pygal. If not, see <http://www.gnu.org/licenses/>. # along with pygal. If not, see <http://www.gnu.org/licenses/>.
import os import os
from pygal import Line 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(): def test_render_to_file():
@ -31,3 +45,16 @@ def test_render_to_file():
with open(file_name) as f: with open(file_name) as f:
assert 'pygal' in f.read() assert 'pygal' in f.read()
os.remove(file_name) 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)

2
setup.py

@ -31,7 +31,7 @@ setup(
packages=find_packages(), packages=find_packages(),
provides=['pygal'], provides=['pygal'],
scripts=["pygal_gen.py"], scripts=["pygal_gen.py"],
keywords=["svg", "graph", "diagram", "plot", "histogram", "kiviat"], keywords=["svg", "chart", "graph", "diagram", "plot", "histogram", "kiviat"],
tests_require=["pytest", "pyquery", "flask"], tests_require=["pytest", "pyquery", "flask"],
package_data={'pygal': ['css/*', 'js/*']}, package_data={'pygal': ['css/*', 'js/*']},
install_requires=['lxml'], install_requires=['lxml'],

Loading…
Cancel
Save