Browse Source

Add ghost containers

pull/8/head
Florian Mounier 12 years ago
parent
commit
56a876e37e
  1. 43
      pygal/__init__.py
  2. 13
      pygal/config.py
  3. 94
      pygal/ghost.py
  4. 16
      pygal/graph/__init__.py
  5. 48
      pygal/graph/base.py
  6. 12
      pygal/graph/horizontal.py
  7. 28
      pygal/graph/horizontalbar.py
  8. 28
      pygal/graph/horizontalstackedbar.py
  9. 37
      pygal/style.py

43
pygal/__init__.py

@ -21,37 +21,18 @@ Pygal - A python svg graph plotting library
"""
__version__ = '0.10.3'
__version__ = '0.11.0'
import sys
from pygal.config import Config
from pygal.graph.bar import Bar
from pygal.graph.dot import Dot
from pygal.graph.funnel import Funnel
from pygal.graph.gauge import Gauge
from pygal.graph.horizontal import HorizontalBar
from pygal.graph.horizontal import HorizontalStackedBar
from pygal.graph.line import Line
from pygal.graph.pie import Pie
from pygal.graph.pyramid import Pyramid
from pygal.graph.radar import Radar
from pygal.graph.stackedbar import StackedBar
from pygal.graph.stackedline import StackedLine
from pygal.graph.xy import XY
from pygal.ghost import Ghost
from pygal.graph import CHARTS_NAMES
CHARTS = []
for NAME in CHARTS_NAMES:
_CHART = type(NAME, (Ghost,), {})
CHARTS.append(_CHART)
setattr(sys.modules[__name__], NAME, _CHART)
#: List of all chart types
CHARTS = [
Bar,
Dot,
Funnel,
Gauge,
HorizontalBar,
HorizontalStackedBar,
Line,
Pie,
Pyramid,
Radar,
StackedBar,
StackedLine,
XY
]
__all__ = CHARTS_NAMES + [Config.__name__, 'CHARTS']

13
pygal/config.py

@ -119,11 +119,16 @@ class Config(object):
"""Can be instanciated with config kwargs"""
self.css = list(self.css)
self.js = list(self.js)
self.__dict__.update(kwargs)
self._update(kwargs)
def __call__(self, **kwargs):
"""Can be updated with kwargs"""
self.__dict__.update(kwargs)
self._update(kwargs)
def _update(self, kwargs):
self.__dict__.update(
dict([(k, v) for (k, v) in kwargs.items()
if not k.startswith('_') and k in dir(self)]))
def font_sizes(self, with_unit=True):
"""Getter for all font size configs"""
@ -133,8 +138,8 @@ class Config(object):
setattr(
fs,
name.replace('_font_size', ''),
('%dpx' % getattr(self, name)
) if with_unit else getattr(self, name))
('%dpx' % getattr(self, name))
if with_unit else getattr(self, name))
return fs
def to_dict(self):

94
pygal/ghost.py

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
# 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/>.
"""
Ghost container
It is used to delegate rendering to real objects but keeping config in place
"""
import io
from importlib import import_module
from pygal.config import Config
from pygal.serie import Serie, Value
from pygal.graph import CHARTS_NAMES
REAL_CHARTS = {}
for NAME in CHARTS_NAMES:
mod = import_module('pygal.graph.%s' % NAME.lower())
REAL_CHARTS[NAME] = getattr(mod, NAME)
class Ghost(object):
def __init__(self, config=None, **kwargs):
"""Init config"""
self.config = config or Config()
self.config(**kwargs)
self.series = []
def add(self, title, values):
"""Add a serie to this graph"""
self.series.append(
Serie(title, values, len(self.series), Value))
def make_instance(self):
self.config(**self.__dict__)
name = self.__class__.__name__
cls = REAL_CHARTS[name]
self._last__inst = cls(self.config, self.series)
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):
"""Render the graph, convert it to png and write it to filename"""
import cairosvg
from io import BytesIO
fakefile = BytesIO()
fakefile.write(self.render())
fakefile.seek(0)
cairosvg.surface.PNGSurface.convert(
file_obj=fakefile, write_to=filename)

16
pygal/graph/__init__.py

@ -20,3 +20,19 @@
Graph modules
"""
CHARTS_NAMES = [
'Bar',
'Dot',
'Funnel',
'Gauge',
'HorizontalBar',
'HorizontalStackedBar',
'Line',
'Pie',
'Pyramid',
'Radar',
'StackedBar',
'StackedLine',
'XY'
]

48
pygal/graph/base.py

@ -22,13 +22,11 @@ Base for pygal charts
"""
from __future__ import division
import io
from pygal.serie import Serie, Value
from pygal.view import Margin, Box
from pygal.serie import Value
from pygal.util import (
get_text_box, get_texts_box, cut, rad, humanize, truncate)
from pygal.svg import Svg
from pygal.config import Config
from pygal.util import cached_property
from math import sin, cos, sqrt
@ -38,13 +36,12 @@ class BaseGraph(object):
__value__ = Value
def __init__(self, config=None, **kwargs):
def __init__(self, config, series):
"""Init the graph"""
self.config = config or Config()
self.config(**kwargs)
self.config = config
self.series = series
self.horizontal = getattr(self, 'horizontal', False)
self.svg = Svg(self)
self.series = []
self._x_labels = None
self._y_labels = None
self._box = None
@ -52,11 +49,6 @@ class BaseGraph(object):
self.margin = None
self.view = None
def add(self, title, values):
"""Add a serie to this graph"""
self.series.append(
Serie(title, values, len(self.series), self.__value__))
def reinit(self):
"""(Re-)Init the graph"""
self.margin = Margin(*([20] * 4))
@ -191,7 +183,7 @@ class BaseGraph(object):
else:
self.svg.pre_render(True)
def render(self, is_unicode=False):
def render(self, is_unicode):
"""Render the graph, and return the svg string"""
self._render()
return self.svg.render(
@ -201,33 +193,3 @@ class BaseGraph(object):
"""Render the graph, and return lxml tree"""
self._render()
return self.svg.root
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):
"""Render the graph, convert it to png and write it to filename"""
import cairosvg
from io import BytesIO
fakefile = BytesIO()
fakefile.write(self.render())
fakefile.seek(0)
cairosvg.surface.PNGSurface.convert(
file_obj=fakefile, write_to=filename)

12
pygal/graph/horizontal.py

@ -17,12 +17,10 @@
# You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>.
"""
Horizontal graph
Horizontal graph base
"""
from pygal.graph.graph import Graph
from pygal.graph.bar import Bar
from pygal.graph.stackedbar import StackedBar
class HorizontalGraph(Graph):
@ -46,11 +44,3 @@ class HorizontalGraph(Graph):
if self.first_pass:
for serie in self.series:
serie.values = list(reversed(serie.values))
class HorizontalBar(HorizontalGraph, Bar):
"""Horizontal Bar graph"""
class HorizontalStackedBar(HorizontalGraph, StackedBar):
"""Horizontal Stacked Bar graph"""

28
pygal/graph/horizontalbar.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# 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/>.
"""
Horizontal bar graph
"""
from pygal.graph.horizontal import HorizontalGraph
from pygal.graph.bar import Bar
class HorizontalBar(HorizontalGraph, Bar):
"""Horizontal Bar graph"""

28
pygal/graph/horizontalstackedbar.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# 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/>.
"""
Horizontal stacked graph
"""
from pygal.graph.horizontal import HorizontalGraph
from pygal.graph.stackedbar import StackedBar
class HorizontalStackedBar(HorizontalGraph, StackedBar):
"""Horizontal Stacked Bar graph"""

37
pygal/style.py

@ -24,20 +24,21 @@ from pygal.util import cycle_fill
class Style(object):
"""Styling class containing colors for the css generation"""
def __init__(self,
background='black',
plot_background='#111',
foreground='#999',
foreground_light='#eee',
foreground_dark='#555',
opacity='.8',
opacity_hover='.9',
transition='250ms',
colors=(
'#ff5995', '#b6e354', '#feed6c', '#8cedff', '#9e6ffe',
'#899ca1', '#f8f8f2', '#bf4646', '#516083', '#f92672',
'#82b414', '#fd971f', '#56c2d6', '#808384', '#8c54fe',
'#465457')):
def __init__(
self,
background='black',
plot_background='#111',
foreground='#999',
foreground_light='#eee',
foreground_dark='#555',
opacity='.8',
opacity_hover='.9',
transition='250ms',
colors=(
'#ff5995', '#b6e354', '#feed6c', '#8cedff', '#9e6ffe',
'#899ca1', '#f8f8f2', '#bf4646', '#516083', '#f92672',
'#82b414', '#fd971f', '#56c2d6', '#808384', '#8c54fe',
'#465457')):
self.background = background
self.plot_background = plot_background
self.foreground = foreground
@ -55,10 +56,10 @@ class Style(object):
def color(tupl):
"""Make a color css"""
return (
'.color-{0} {{\n'
' stroke: {1};\n'
' fill: {1};\n'
'}}\n'.format(*tupl))
'.color-{0} {{\n'
' stroke: {1};\n'
' fill: {1};\n'
'}}\n'.format(*tupl))
return '\n'.join(map(color, enumerate(cycle_fill(self._colors, 16))))
def to_dict(self):

Loading…
Cancel
Save