Browse Source

Add horizontal graphs

pull/8/head
Florian Mounier 13 years ago
parent
commit
8f0da6222d
  1. 3
      demo/moulinrouge/__init__.py
  2. 26
      out.py
  3. 2
      pygal/__init__.py
  4. 2
      pygal/css/graph.css
  5. 5
      pygal/graph/base.py
  6. 25
      pygal/graph/horizontal.py
  7. 52
      pygal/svg.py
  8. 3
      pygal/util.py
  9. 4
      pygal/view.py

3
demo/moulinrouge/__init__.py

@ -70,7 +70,8 @@ def create_app():
width, height = 600, 400
svgs = [url_for('all_svg', type=type, style=style)
for style in styles
for type in ('Bar', 'Line', 'XY', 'Pie', 'StackedBar')]
for type in ('Bar', 'Line', 'XY', 'Pie', 'StackedBar',
'HorizontalBar', 'HorizontalStackedBar')]
return render_template('svgs.jinja2',
svgs=svgs,
width=width,

26
out.py

@ -1,5 +1,7 @@
#!/usr/bin/env python
from pygal import Line, Bar, XY, Pie, StackedBar, Config
from pygal import (
Line, Bar, XY, Pie, StackedBar, Config,
HorizontalBar, HorizontalStackedBar)
from pygal.style import NeonStyle
from math import cos, sin
@ -12,6 +14,17 @@ bar.title = "Bar test"
with open('out-bar.svg', 'w') as f:
f.write(bar.render())
hbar = HorizontalBar()
rng = [18, 9, 7, 3, 1, 0, -5]
hbar.add('test1', rng)
rng2 = [16, 14, 10, 9, 7, 3, -1]
hbar.add('test2', rng2)
hbar.x_labels = map(
lambda x: '%s / %s' % x, zip(map(str, rng), map(str, rng2)))
hbar.title = "Horizontal Bar test"
with open('out-horizontalbar.svg', 'w') as f:
f.write(hbar.render())
rng = [3, -32, 39, 12]
rng2 = [24, -8, 18, 12]
@ -22,8 +35,9 @@ config.x_labels = map(lambda x: '%s / %s / %s' % x,
zip(map(str, rng),
map(str, rng2),
map(str, rng3)))
config.title = "Config test"
config.title = "Stacked Bar test"
config.style = NeonStyle
config.horizontal = True
stackedbar = StackedBar(config)
stackedbar.add('@@@@@@@', rng)
@ -32,6 +46,14 @@ stackedbar.add('--->', rng3)
with open('out-stackedbar.svg', 'w') as f:
f.write(stackedbar.render())
config.title = "Horizontal Stacked Bar test"
hstackedbar = HorizontalStackedBar(config)
hstackedbar.add('@@@@@@@', rng)
hstackedbar.add('++++++', rng2)
hstackedbar.add('--->', rng3)
with open('out-horizontalstackedbar.svg', 'w') as f:
f.write(hstackedbar.render())
line = Line(Config(y_scale=.0005))
rng = range(-30, 31, 5)
line.add('test1', [cos(x / 10.) for x in rng])

2
pygal/__init__.py

@ -1,7 +1,9 @@
from collections import namedtuple
from pygal.graph.bar import Bar
from pygal.graph.horizontal import HorizontalBar
from pygal.graph.stackedbar import StackedBar
from pygal.graph.horizontal import HorizontalStackedBar
from pygal.graph.line import Line
from pygal.graph.xy import XY
from pygal.graph.pie import Pie

2
pygal/css/graph.css

@ -71,7 +71,7 @@ svg * {
stroke-dasharray: 5,5;
}
.axis.x .guide.line {
.axis.{{ hidden }} .guide.line {
opacity: 0;
}

5
pygal/graph/base.py

@ -3,13 +3,14 @@ from pygal.view import Margin, Box
from pygal.util import round_to_scale, cut, rad
from pygal.svg import Svg
from pygal.config import Config
from math import log10, sin, cos, pi
from math import log10, sin, cos
class BaseGraph(object):
"""Graphs commons"""
def __init__(self, config=None):
def __init__(self, config=None, horizontal=False):
self.horizontal = horizontal
self.config = config or Config()
self.svg = Svg(self)
self.series = []

25
pygal/graph/horizontal.py

@ -0,0 +1,25 @@
from pygal.graph.bar import Bar
from pygal.graph.stackedbar import StackedBar
class HorizontalGraph(object):
"""Horizontal graph"""
def __init__(self, *args, **kwargs):
kwargs['horizontal'] = True
super(HorizontalGraph, self).__init__(*args, **kwargs)
def _compute(self):
super(HorizontalGraph, self)._compute()
self._x_labels, self._y_labels = self._y_labels, self._x_labels
self._box.swap()
# Y axis is inverted
for serie in self.series:
serie.values = reversed(serie.values)
class HorizontalBar(HorizontalGraph, Bar):
"""Horizontal Bar graph"""
class HorizontalStackedBar(HorizontalGraph, StackedBar):
"""Horizontal Stacked Bar graph"""

52
pygal/svg.py

@ -1,7 +1,7 @@
import os
from lxml import etree
from pygal.view import View
from pygal.util import template
from pygal.util import template, swap, ident
from math import cos, sin, pi
@ -31,7 +31,8 @@ class Svg(object):
style.text = template(
f.read(),
style=self.graph.style,
font_sizes=self.graph.font_sizes)
font_sizes=self.graph.font_sizes,
hidden='y' if self.graph.horizontal else 'x')
def node(self, parent=None, tag='g', attrib=None, **extras):
if parent is None:
@ -180,16 +181,23 @@ class Svg(object):
def view(rng):
"""Project range"""
return (self.view(rng[0]), self.view(rng[1]))
t, T = rng
fun = swap if self.graph.horizontal else ident
return (self.view(fun(t)), self.view(fun(T)))
bars = self.node(serie_node, class_="bars")
view_values = map(view, values)
for i, ((x, y), (X, Y)) in enumerate(view_values):
# x and y are left range coords and X, Y right ones
if self.graph.horizontal:
x, y, X, Y = Y, X, y, x
width = X - x
padding = .1 * width
inner_width = width - 2 * padding
height = self.view.y(0) - y
if self.graph.horizontal:
height = self.view.x(0) - y
else:
height = self.view.y(0) - y
if stack_vals == None:
bar_width = inner_width / len(self.graph.series)
bar_padding = .1 * bar_width
@ -209,17 +217,31 @@ class Svg(object):
y_txt = y + height / 2 + .3 * self.graph.values_font_size
bar = self.node(bars, class_='bar')
self.node(bar, 'rect',
x=x,
y=y - shift,
rx=self.graph.rounded_bars * 1,
ry=self.graph.rounded_bars * 1,
width=bar_inner_width,
height=height,
class_='rect')
self.node(bar, 'text',
x=x + bar_inner_width / 2,
y=y_txt - shift,
if self.graph.horizontal:
self.node(bar, 'rect',
x=y - shift,
y=x,
rx=self.graph.rounded_bars * 1,
ry=self.graph.rounded_bars * 1,
width=height,
height=bar_inner_width,
class_='rect')
self.node(bar, 'text',
x=y_txt - shift,
y=x + bar_inner_width / 2,
).text = str(values[i][1][1])
else:
self.node(bar, 'rect',
x=x,
y=y - shift,
rx=self.graph.rounded_bars * 1,
ry=self.graph.rounded_bars * 1,
width=bar_inner_width,
height=height,
class_='rect')
self.node(bar, 'text',
x=x + bar_inner_width / 2,
y=y_txt - shift,
).text = str(values[i][1][1])
return stack_vals

3
pygal/util.py

@ -48,3 +48,6 @@ def _swap_curly(string):
def template(string, **kwargs):
"""Format a string using double braces"""
return _swap_curly(string).format(**kwargs)
swap = lambda tuple_: tuple(reversed(tuple_))
ident = lambda x: x

4
pygal/view.py

@ -27,6 +27,10 @@ class Box(object):
def height(self):
return self.ymax - self.ymin
def swap(self):
self.xmin, self.ymin = self.ymin, self.xmin
self.xmax, self.ymax = self.ymax, self.xmax
def fix(self):
if not self.width:
self.xmax = self.xmin + 1

Loading…
Cancel
Save