Browse Source

Finally fix horizontal bar

pull/8/head
Florian Mounier 12 years ago
parent
commit
de14bc10d1
  1. 15
      demo/moulinrouge/tests.py
  2. 38
      pygal/graph/bar.py
  3. 7
      pygal/graph/graph.py
  4. 19
      pygal/graph/horizontal.py
  5. 11
      pygal/svg.py
  6. 28
      pygal/view.py

15
demo/moulinrouge/tests.py

@ -99,6 +99,21 @@ def get_test_routes(app):
return dot.render_response() return dot.render_response()
@app.route('/test/<chart>')
def test_for(chart):
graph = CHARTS_BY_NAME[chart]()
graph.add('1', [1, 3, 12, 3, 4, None, 9])
graph.add('2', [7, -4, 10, None, 8, 3, 1])
graph.x_labels = ('a', 'b', 'c', 'd', 'e', 'f', 'g')
return graph.render_response()
@app.route('/test/one/<chart>')
def test_one_for(chart):
graph = CHARTS_BY_NAME[chart]()
graph.add('1', [1, 2])
graph.x_labels = 'a',
return graph.render_response()
@app.route('/test/interpolate/<chart>') @app.route('/test/interpolate/<chart>')
def test_interpolate_for(chart): def test_interpolate_for(chart):
graph = CHARTS_BY_NAME[chart](interpolate='cubic') graph = CHARTS_BY_NAME[chart](interpolate='cubic')

38
pygal/graph/bar.py

@ -29,34 +29,31 @@ from pygal.util import swap, ident, compute_scale, decorate
class Bar(Graph): class Bar(Graph):
"""Bar graph""" """Bar graph"""
_series_margin = .06
_serie_margin = .06
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._x_ranges = None self._x_ranges = None
super(Bar, self).__init__(*args, **kwargs) super(Bar, self).__init__(*args, **kwargs)
def _bar(self, parent, x, y, index): def _bar(self, parent, x, y, index):
width = self.view.x(1 / self._len) width = (self.view.x(1) - self.view.x(0)) / self._len
margin = width * .1 * 0 series_margin = width * self._series_margin
x += margin x += series_margin
width -= 2 * margin width -= 2 * series_margin
width /= self._order width /= self._order
x += index * width x += index * width
padding = width * .005 * 0 serie_margin = width * self._serie_margin
x += padding x += serie_margin
width -= 2 * padding width -= 2 * serie_margin
height = self.view.y(self.zero) - y
y_0 = self.view.y(self.zero) r = self.rounded_bars * 1 if self.rounded_bars else 0
height = abs(y - y_0)
self.svg.transposable_node( self.svg.transposable_node(
parent, parent, 'rect',
'rect', x=x, y=y, rx=r, ry=r, width=width, height=height,
x=x,
y=y,
rx=self.rounded_bars * 1 if self.rounded_bars else 0,
ry=self.rounded_bars * 1 if self.rounded_bars else 0,
width=width,
height=height,
class_='rect reactive tooltip-trigger') class_='rect reactive tooltip-trigger')
return (x + width / 2, y + height / 2) transpose = swap if self.horizontal else ident
return transpose((x + width / 2, y + height / 2))
def bar(self, serie_node, serie, index): def bar(self, serie_node, serie, index):
"""Draw a bar graph for a serie""" """Draw a bar graph for a serie"""
@ -91,9 +88,8 @@ class Bar(Graph):
self._box.ymin, self._box.ymax, self.logarithmic, self.order_min self._box.ymin, self._box.ymax, self.logarithmic, self.order_min
) if not self.y_labels else map(float, self.y_labels) ) if not self.y_labels else map(float, self.y_labels)
# self._x_ranges = zip(x_pos, x_pos[1:])
self._x_labels = self.x_labels and zip(self.x_labels, [ self._x_labels = self.x_labels and zip(self.x_labels, [
sum(x_range) / 2 for x_range in self._x_ranges]) (i + .5) / self._len for i in range(self._len)])
self._y_labels = zip(map(self._format, y_pos), y_pos) self._y_labels = zip(map(self._format, y_pos), y_pos)
def _plot(self): def _plot(self):

7
pygal/graph/graph.py

@ -24,7 +24,7 @@ Commmon graphing functions
from __future__ import division from __future__ import division
from pygal.interpolate import interpolation from pygal.interpolate import interpolation
from pygal.graph.base import BaseGraph from pygal.graph.base import BaseGraph
from pygal.view import View, XLogView, YLogView, XYLogView from pygal.view import View, XLogView, YLogView, XYLogView, HorizontalView
from pygal.util import is_major, truncate, reverse_text_len from pygal.util import is_major, truncate, reverse_text_len
from math import isnan, pi, sqrt, ceil from math import isnan, pi, sqrt, ceil
@ -50,8 +50,6 @@ class Graph(BaseGraph):
if self.logarithmic: if self.logarithmic:
if self.__class__.__name__ == 'XY': if self.__class__.__name__ == 'XY':
view_class = XYLogView view_class = XYLogView
elif self.horizontal:
view_class = XLogView
else: else:
view_class = YLogView view_class = YLogView
else: else:
@ -104,7 +102,7 @@ class Graph(BaseGraph):
self.svg.node(a, 'rect', self.svg.node(a, 'rect',
id="tooltip-box", id="tooltip-box",
rx=5, ry=5, width=0, height=0 rx=5, ry=5, width=0, height=0
) )
text = self.svg.node(a, 'text', class_='text') text = self.svg.node(a, 'text', class_='text')
self.svg.node(text, 'tspan', class_='label') self.svg.node(text, 'tspan', class_='label')
self.svg.node(text, 'tspan', class_='value') self.svg.node(text, 'tspan', class_='value')
@ -113,7 +111,6 @@ class Graph(BaseGraph):
"""Make the x axis: labels and guides""" """Make the x axis: labels and guides"""
if not self._x_labels: if not self._x_labels:
return return
axis = self.svg.node(self.nodes['plot'], class_="axis x") axis = self.svg.node(self.nodes['plot'], class_="axis x")
truncation = self.truncate_label truncation = self.truncate_label
if not truncation: if not truncation:

19
pygal/graph/horizontal.py

@ -21,6 +21,7 @@ Horizontal graph base
""" """
from pygal.graph.graph import Graph from pygal.graph.graph import Graph
from pygal.view import HorizontalView, XLogView
class HorizontalGraph(Graph): class HorizontalGraph(Graph):
@ -32,4 +33,20 @@ class HorizontalGraph(Graph):
def _compute(self): def _compute(self):
super(HorizontalGraph, self)._compute() super(HorizontalGraph, self)._compute()
self._x_labels, self._y_labels = self._y_labels, self._x_labels self._x_labels, self._y_labels = self._y_labels, self._x_labels
self._box.swap()
def _axes(self):
self.view._force_vertical = True
super(HorizontalGraph, self)._axes()
self.view._force_vertical = False
def _set_view(self):
"""Assign a view to current graph"""
if self.logarithmic:
view_class = XLogView
else:
view_class = HorizontalView
self.view = view_class(
self.width - self.margin.x,
self.height - self.margin.y,
self._box)

11
pygal/svg.py

@ -26,6 +26,7 @@ import io
import os import os
import json import json
from datetime import date from datetime import date
from numbers import Number
from lxml import etree from lxml import etree
from math import cos, sin, pi from math import cos, sin, pi
from urlparse import urlparse from urlparse import urlparse
@ -96,6 +97,16 @@ class Svg(object):
parent = self.root parent = self.root
attrib = attrib or {} attrib = attrib or {}
attrib.update(extras) attrib.update(extras)
def in_attrib_and_number(key):
return key in attrib and isinstance(attrib[key], Number)
for pos, dim in (('x', 'width'), ('y', 'height')):
if in_attrib_and_number(dim) and attrib[dim] < 0:
attrib[dim] = - attrib[dim]
if in_attrib_and_number(pos):
attrib[pos] = attrib[pos] - attrib[dim]
for key, value in attrib.items(): for key, value in attrib.items():
if value is None: if value is None:
del attrib[key] del attrib[key]

28
pygal/view.py

@ -64,7 +64,7 @@ class Box(object):
return self.ymax - self.ymin return self.ymax - self.ymin
def swap(self): def swap(self):
"""Return the box (for horizontal qraphs)""" """Return the box (for horizontal graphs)"""
self.xmin, self.ymin = self.ymin, self.xmin self.xmin, self.ymin = self.ymin, self.xmin
self.xmax, self.ymax = self.ymax, self.xmax self.xmax, self.ymax = self.ymax, self.xmax
@ -111,6 +111,32 @@ class View(object):
return (self.x(x), self.y(y)) return (self.x(x), self.y(y))
class HorizontalView(View):
def __init__(self, width, height, box):
self._force_vertical = None
self.width = width
self.height = height
self.box = box
self.box.fix()
self.box.swap()
def x(self, x):
"""Project x"""
if x is None:
return None
if self._force_vertical:
return super(HorizontalView, self).x(x)
return super(HorizontalView, self).y(x)
def y(self, y):
if y is None:
return None
if self._force_vertical:
return super(HorizontalView, self).y(y)
return super(HorizontalView, self).x(y)
class PolarView(View): class PolarView(View):
"""Polar projection for pie like graphs""" """Polar projection for pie like graphs"""

Loading…
Cancel
Save