mirror of https://github.com/Kozea/pygal.git
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.
160 lines
5.1 KiB
160 lines
5.1 KiB
# -*- coding: utf-8 -*- |
|
# This file is part of pygal |
|
# |
|
# A python svg graph plotting library |
|
# Copyright © 2012-2013 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/>. |
|
""" |
|
Ghost container |
|
|
|
It is used to delegate rendering to real objects but keeping config in place |
|
|
|
""" |
|
|
|
from __future__ import division |
|
import io |
|
import sys |
|
from pygal.config import Config |
|
from pygal._compat import u, is_list_like |
|
from pygal.graph import CHARTS_NAMES |
|
from pygal.util import prepare_values |
|
from uuid import uuid4 |
|
|
|
|
|
REAL_CHARTS = {} |
|
for NAME in CHARTS_NAMES: |
|
mod_name = 'pygal.graph.%s' % NAME.lower() |
|
__import__(mod_name) |
|
mod = sys.modules[mod_name] |
|
REAL_CHARTS[NAME] = getattr(mod, NAME) |
|
|
|
|
|
class Ghost(object): |
|
|
|
def __init__(self, config=None, **kwargs): |
|
"""Init config""" |
|
name = self.__class__.__name__ |
|
self.cls = REAL_CHARTS[name] |
|
self.uuid = str(uuid4()) |
|
if config and isinstance(config, type): |
|
config = config() |
|
|
|
if config: |
|
config = config.copy() |
|
else: |
|
config = Config() |
|
|
|
config(**kwargs) |
|
self.config = config |
|
self.raw_series = [] |
|
self.raw_series2 = [] |
|
self.xml_filters = [] |
|
|
|
def add(self, title, values, secondary=False): |
|
"""Add a serie to this graph""" |
|
if not is_list_like(values) and not isinstance(values, dict): |
|
values = [values] |
|
if secondary: |
|
self.raw_series2.append((title, values)) |
|
else: |
|
self.raw_series.append((title, values)) |
|
|
|
def add_xml_filter(self, callback): |
|
self.xml_filters.append(callback) |
|
|
|
def make_series(self, series): |
|
return prepare_values(series, self.config, self.cls) |
|
|
|
def make_instance(self, overrides={}): |
|
self.config(**self.__dict__) |
|
self.config.__dict__.update(overrides) |
|
series = self.make_series(self.raw_series) |
|
secondary_series = self.make_series(self.raw_series2) |
|
self._last__inst = self.cls( |
|
self.config, series, secondary_series, self.uuid, |
|
self.xml_filters) |
|
return self._last__inst |
|
|
|
# Rendering |
|
def render(self, is_unicode=False): |
|
return self.make_instance().render(is_unicode=is_unicode) |
|
|
|
def render_tree(self): |
|
return self.make_instance().render_tree() |
|
|
|
def render_pyquery(self): |
|
"""Render the graph, and return a pyquery wrapped tree""" |
|
from pyquery import PyQuery as pq |
|
return pq(self.render_tree()) |
|
|
|
def render_in_browser(self): |
|
"""Render the graph, open it in your browser with black magic""" |
|
from lxml.html import open_in_browser |
|
open_in_browser(self.render_tree(), encoding='utf-8') |
|
|
|
def render_response(self): |
|
"""Render the graph, and return a Flask response""" |
|
from flask import Response |
|
return Response(self.render(), mimetype='image/svg+xml') |
|
|
|
def render_to_file(self, filename): |
|
"""Render the graph, and write it to filename""" |
|
with io.open(filename, 'w', encoding='utf-8') as f: |
|
f.write(self.render(is_unicode=True)) |
|
|
|
def render_to_png(self, filename=None, dpi=72): |
|
"""Render the graph, convert it to png and write it to filename""" |
|
import cairosvg |
|
return cairosvg.svg2png( |
|
bytestring=self.render(), write_to=filename, dpi=dpi) |
|
|
|
def render_sparktext(self, relative_to=None): |
|
"""Make a mini text sparkline from chart""" |
|
bars = u('▁▂▃▄▅▆▇█') |
|
if len(self.raw_series) == 0: |
|
return u('') |
|
values = list(self.raw_series[0][1]) |
|
if len(values) == 0: |
|
return u('') |
|
|
|
chart = u('') |
|
values = list(map(lambda x: max(x, 0), values)) |
|
|
|
vmax = max(values) |
|
if relative_to is None: |
|
relative_to = min(values) |
|
divisions = len(bars) - 1 |
|
for value in values: |
|
chart += bars[int(divisions * |
|
(value - relative_to) / (vmax - relative_to))] |
|
return chart |
|
|
|
def render_sparkline(self, **kwargs): |
|
spark_options = dict( |
|
width=200, |
|
height=50, |
|
show_dots=False, |
|
show_legend=False, |
|
show_y_labels=False, |
|
spacing=0, |
|
margin=5, |
|
explicit_size=True |
|
) |
|
spark_options.update(kwargs) |
|
return self.make_instance(spark_options).render() |
|
|
|
def _repr_png_(self): |
|
"""Display png in IPython notebook""" |
|
return self.render_to_png()
|
|
|