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.config import Config
from pygal.graph.bar import Bar from pygal.ghost import Ghost
from pygal.graph.dot import Dot from pygal.graph import CHARTS_NAMES
from pygal.graph.funnel import Funnel
from pygal.graph.gauge import Gauge CHARTS = []
from pygal.graph.horizontal import HorizontalBar
from pygal.graph.horizontal import HorizontalStackedBar for NAME in CHARTS_NAMES:
from pygal.graph.line import Line _CHART = type(NAME, (Ghost,), {})
from pygal.graph.pie import Pie CHARTS.append(_CHART)
from pygal.graph.pyramid import Pyramid setattr(sys.modules[__name__], NAME, _CHART)
from pygal.graph.radar import Radar
from pygal.graph.stackedbar import StackedBar
from pygal.graph.stackedline import StackedLine
from pygal.graph.xy import XY
#: List of all chart types __all__ = CHARTS_NAMES + [Config.__name__, 'CHARTS']
CHARTS = [
Bar,
Dot,
Funnel,
Gauge,
HorizontalBar,
HorizontalStackedBar,
Line,
Pie,
Pyramid,
Radar,
StackedBar,
StackedLine,
XY
]

13
pygal/config.py

@ -119,11 +119,16 @@ class Config(object):
"""Can be instanciated with config kwargs""" """Can be instanciated with config kwargs"""
self.css = list(self.css) self.css = list(self.css)
self.js = list(self.js) self.js = list(self.js)
self.__dict__.update(kwargs) self._update(kwargs)
def __call__(self, **kwargs): def __call__(self, **kwargs):
"""Can be updated with 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): def font_sizes(self, with_unit=True):
"""Getter for all font size configs""" """Getter for all font size configs"""
@ -133,8 +138,8 @@ class Config(object):
setattr( setattr(
fs, fs,
name.replace('_font_size', ''), name.replace('_font_size', ''),
('%dpx' % getattr(self, name) ('%dpx' % getattr(self, name))
) if with_unit else getattr(self, name)) if with_unit else getattr(self, name))
return fs return fs
def to_dict(self): 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 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 from __future__ import division
import io
from pygal.serie import Serie, Value
from pygal.view import Margin, Box from pygal.view import Margin, Box
from pygal.serie import Value
from pygal.util import ( from pygal.util import (
get_text_box, get_texts_box, cut, rad, humanize, truncate) get_text_box, get_texts_box, cut, rad, humanize, truncate)
from pygal.svg import Svg from pygal.svg import Svg
from pygal.config import Config
from pygal.util import cached_property from pygal.util import cached_property
from math import sin, cos, sqrt from math import sin, cos, sqrt
@ -38,13 +36,12 @@ class BaseGraph(object):
__value__ = Value __value__ = Value
def __init__(self, config=None, **kwargs): def __init__(self, config, series):
"""Init the graph""" """Init the graph"""
self.config = config or Config() self.config = config
self.config(**kwargs) self.series = series
self.horizontal = getattr(self, 'horizontal', False) self.horizontal = getattr(self, 'horizontal', False)
self.svg = Svg(self) self.svg = Svg(self)
self.series = []
self._x_labels = None self._x_labels = None
self._y_labels = None self._y_labels = None
self._box = None self._box = None
@ -52,11 +49,6 @@ class BaseGraph(object):
self.margin = None self.margin = None
self.view = 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): def reinit(self):
"""(Re-)Init the graph""" """(Re-)Init the graph"""
self.margin = Margin(*([20] * 4)) self.margin = Margin(*([20] * 4))
@ -191,7 +183,7 @@ class BaseGraph(object):
else: else:
self.svg.pre_render(True) self.svg.pre_render(True)
def render(self, is_unicode=False): def render(self, is_unicode):
"""Render the graph, and return the svg string""" """Render the graph, and return the svg string"""
self._render() self._render()
return self.svg.render( return self.svg.render(
@ -201,33 +193,3 @@ class BaseGraph(object):
"""Render the graph, and return lxml tree""" """Render the graph, and return lxml tree"""
self._render() self._render()
return self.svg.root 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 # You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>. # 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.graph import Graph
from pygal.graph.bar import Bar
from pygal.graph.stackedbar import StackedBar
class HorizontalGraph(Graph): class HorizontalGraph(Graph):
@ -46,11 +44,3 @@ class HorizontalGraph(Graph):
if self.first_pass: if self.first_pass:
for serie in self.series: for serie in self.series:
serie.values = list(reversed(serie.values)) 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): class Style(object):
"""Styling class containing colors for the css generation""" """Styling class containing colors for the css generation"""
def __init__(self, def __init__(
background='black', self,
plot_background='#111', background='black',
foreground='#999', plot_background='#111',
foreground_light='#eee', foreground='#999',
foreground_dark='#555', foreground_light='#eee',
opacity='.8', foreground_dark='#555',
opacity_hover='.9', opacity='.8',
transition='250ms', opacity_hover='.9',
colors=( transition='250ms',
'#ff5995', '#b6e354', '#feed6c', '#8cedff', '#9e6ffe', colors=(
'#899ca1', '#f8f8f2', '#bf4646', '#516083', '#f92672', '#ff5995', '#b6e354', '#feed6c', '#8cedff', '#9e6ffe',
'#82b414', '#fd971f', '#56c2d6', '#808384', '#8c54fe', '#899ca1', '#f8f8f2', '#bf4646', '#516083', '#f92672',
'#465457')): '#82b414', '#fd971f', '#56c2d6', '#808384', '#8c54fe',
'#465457')):
self.background = background self.background = background
self.plot_background = plot_background self.plot_background = plot_background
self.foreground = foreground self.foreground = foreground
@ -55,10 +56,10 @@ class Style(object):
def color(tupl): def color(tupl):
"""Make a color css""" """Make a color css"""
return ( return (
'.color-{0} {{\n' '.color-{0} {{\n'
' stroke: {1};\n' ' stroke: {1};\n'
' fill: {1};\n' ' fill: {1};\n'
'}}\n'.format(*tupl)) '}}\n'.format(*tupl))
return '\n'.join(map(color, enumerate(cycle_fill(self._colors, 16)))) return '\n'.join(map(color, enumerate(cycle_fill(self._colors, 16))))
def to_dict(self): def to_dict(self):

Loading…
Cancel
Save