mirror of https://github.com/Kozea/pygal.git
Florian Mounier
13 years ago
8 changed files with 124 additions and 0 deletions
@ -0,0 +1,3 @@ |
|||||||
|
from collections import namedtuple |
||||||
|
|
||||||
|
Serie = namedtuple('Serie', ('title', 'values')) |
@ -0,0 +1,13 @@ |
|||||||
|
|
||||||
|
|
||||||
|
class BaseGraph(object): |
||||||
|
"""Graphs commons""" |
||||||
|
|
||||||
|
def render(self): |
||||||
|
self.draw() |
||||||
|
return self.svg.render() |
||||||
|
|
||||||
|
def _in_browser(self): |
||||||
|
from lxml.html import open_in_browser |
||||||
|
self.draw() |
||||||
|
open_in_browser(self.svg.root, encoding='utf-8') |
@ -0,0 +1,26 @@ |
|||||||
|
from pygal import Serie |
||||||
|
from pygal.svg import Svg |
||||||
|
from pygal.base import BaseGraph |
||||||
|
|
||||||
|
|
||||||
|
class Line(BaseGraph): |
||||||
|
"""Line graph""" |
||||||
|
|
||||||
|
def __init__(self, width, height): |
||||||
|
self.width = width |
||||||
|
self.height = height |
||||||
|
self.svg = Svg(width, height) |
||||||
|
self.series = [] |
||||||
|
|
||||||
|
def add(self, title, values): |
||||||
|
self.series.append( |
||||||
|
Serie(title, values)) |
||||||
|
|
||||||
|
def draw(self): |
||||||
|
self.svg.graph() |
||||||
|
for serie in self.series: |
||||||
|
n_values = len(serie.values) |
||||||
|
x_spacing = self.width / n_values |
||||||
|
self.svg.line([ |
||||||
|
(i * x_spacing, v) |
||||||
|
for i, v in enumerate(serie.values)]) |
@ -0,0 +1,52 @@ |
|||||||
|
from lxml import etree |
||||||
|
|
||||||
|
|
||||||
|
class Svg(object): |
||||||
|
"""Svg object""" |
||||||
|
ns = 'http://www.w3.org/2000/svg' |
||||||
|
|
||||||
|
def __init__(self, width, height): |
||||||
|
self.width = width |
||||||
|
self.height = height |
||||||
|
self.root = etree.Element( |
||||||
|
"{%s}svg" % self.ns, |
||||||
|
attrib={ |
||||||
|
'viewBox': '0 0 %d %d' % (width, height) |
||||||
|
}, |
||||||
|
nsmap={ |
||||||
|
None: self.ns, |
||||||
|
'xlink': 'http://www.w3.org/1999/xlink', |
||||||
|
}) |
||||||
|
|
||||||
|
def node(self, parent=None, tag='g', attrib=None, **extras): |
||||||
|
if parent is None: |
||||||
|
parent = self.root |
||||||
|
attrib = attrib or {} |
||||||
|
attrib.update(extras) |
||||||
|
for key, value in attrib.items(): |
||||||
|
if not isinstance(value, basestring): |
||||||
|
attrib[key] = str(value) |
||||||
|
if key == 'class_': |
||||||
|
attrib['class'] = attrib['class_'] |
||||||
|
del attrib['class_'] |
||||||
|
|
||||||
|
return etree.SubElement(parent, tag, attrib) |
||||||
|
|
||||||
|
def format_coords(self, xy): |
||||||
|
return '%f %f' % xy |
||||||
|
|
||||||
|
def graph(self): |
||||||
|
self.graph = self.node(id='graph') |
||||||
|
self.node(self.graph, 'rect', id='graph_background', |
||||||
|
x=0, y=0, width=self.width, height=self.height) |
||||||
|
|
||||||
|
def line(self, values, origin=None): |
||||||
|
origin = self.format_coords(origin or values[0]) |
||||||
|
values = ' '.join(map(self.format_coords, values)) |
||||||
|
self.node(self.graph, 'path', |
||||||
|
d='M%s L%s' % (origin, values)) |
||||||
|
|
||||||
|
def render(self): |
||||||
|
return etree.tostring( |
||||||
|
self.root, pretty_print=True, |
||||||
|
xml_declaration=True, encoding='utf-8') |
@ -0,0 +1,7 @@ |
|||||||
|
from pygal.line import Line |
||||||
|
|
||||||
|
|
||||||
|
def test_simple_line(): |
||||||
|
line = Line(800, 600) |
||||||
|
line.add('test', [10, 20, 5, 17]) |
||||||
|
line._in_browser() |
@ -0,0 +1,11 @@ |
|||||||
|
from pygal.svg import Svg |
||||||
|
|
||||||
|
|
||||||
|
def test_root(): |
||||||
|
svg = Svg(800, 600) |
||||||
|
assert svg.render() == ('\n'.join(( |
||||||
|
'<?xml version=\'1.0\' encoding=\'utf-8\'?>', |
||||||
|
'<svg xmlns:xlink="http://www.w3.org/1999/xlink" ' |
||||||
|
'xmlns="http://www.w3.org/2000/svg" ' |
||||||
|
'viewBox="0 0 800 600"/>', |
||||||
|
''))) |
Loading…
Reference in new issue