Python to generate nice looking SVG graph http://pygal.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
4.7 KiB

# -*- coding: utf-8 -*-
13 years ago
# This file is part of pygal
#
# A python svg graph plotting library
# Copyright © 2012 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 <http://www.gnu.org/licenses/>.
import os
from lxml import etree
from pygal.util import template
13 years ago
from pygal import __version__
class Svg(object):
"""Svg object"""
ns = 'http://www.w3.org/2000/svg'
13 years ago
def __init__(self, graph):
self.graph = graph
def _init(self):
self.root = etree.Element(
"{%s}svg" % self.ns,
nsmap={
None: self.ns,
'xlink': 'http://www.w3.org/1999/xlink',
13 years ago
},
onload="svg_load();")
13 years ago
self.root.append(etree.Comment(
u'Generated with pygal %s ©Kozea 2012' % __version__))
self.root.append(etree.Comment(u'http://github.com/Kozea/pygal'))
self.defs = self.node(tag='defs')
def add_style(self, css):
style = self.node(self.defs, 'style', type='text/css')
with open(css) as f:
13 years ago
templ = template(
13 years ago
f.read(),
style=self.graph.style,
font_sizes=self.graph.font_sizes(),
13 years ago
hidden='y' if self.graph._horizontal else 'x')
13 years ago
style.text = templ.decode('utf-8')
13 years ago
def add_script(self, js):
script = self.node(self.defs, 'script', type='text/javascript')
13 years ago
with open(js) as f:
templ = template(
f.read(),
font_sizes=self.graph.font_sizes(False),
animation_steps=self.graph.animation_steps
)
script.text = templ.decode('utf-8')
13 years ago
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 value is None:
del attrib[key]
elif not isinstance(value, basestring):
attrib[key] = str(value)
elif key.endswith('_'):
attrib[key.rstrip('_')] = attrib[key]
del attrib[key]
return etree.SubElement(parent, tag, attrib)
def transposable_node(self, parent=None, tag='g', attrib=None, **extras):
13 years ago
if self.graph._horizontal:
for key1, key2 in (('x', 'y'), ('width', 'height')):
attr1 = extras.get(key1, None)
attr2 = extras.get(key2, None)
extras[key1], extras[key2] = attr2, attr1
return self.node(parent, tag, attrib, **extras)
def format(self, xy):
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]:
origin_index += 1
origin = self.format(coords[origin_index])
line = ' '.join([self.format(c)
for c in coords[origin_index + 1:]
if None not in c])
self.node(node, 'path',
d=root % (origin, line), **kwargs)
def _pre_render(self, no_data=False):
self.add_style(self.graph.base_css or os.path.join(
os.path.dirname(__file__), 'css', 'graph.css'))
self.add_script(self.graph.base_js or os.path.join(
os.path.dirname(__file__), 'js', 'graph.js'))
self.root.set(
'viewBox', '0 0 %d %d' % (self.graph.width, self.graph.height))
if self.graph.explicit_size:
self.root.set('width', str(self.graph.width))
self.root.set('height', str(self.graph.height))
if no_data:
no_data = self.node(self.root, 'text',
x=self.graph.width / 2,
y=self.graph.height / 2,
class_='no_data')
no_data.text = self.graph.no_data_text
def render(self):
svg = etree.tostring(
self.root, pretty_print=True,
xml_declaration=not self.graph.disable_xml_declaration,
encoding='utf-8')
if self.graph.disable_xml_declaration:
svg = svg.decode('utf-8')
return svg