Browse Source

Fix stacked

pull/8/head
Florian Mounier 12 years ago
parent
commit
77fc66de59
  1. 2
      demo/moulinrouge/tests.py
  2. 25
      pygal/graph/bar.py
  3. 6
      pygal/graph/base.py
  4. 40
      pygal/graph/stackedbar.py

2
demo/moulinrouge/tests.py

@ -104,6 +104,8 @@ def get_test_routes(app):
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.add('3', [7, -14, -10, None, 8, 3, 1])
graph.add('4', [7, 4, -10, None, 8, 3, 1])
graph.x_labels = ('a', 'b', 'c', 'd', 'e', 'f', 'g')
return graph.render_response()

25
pygal/graph/bar.py

@ -36,17 +36,20 @@ class Bar(Graph):
self._x_ranges = None
super(Bar, self).__init__(*args, **kwargs)
def _bar(self, parent, x, y, index):
def _bar(self, parent, x, y, index, i, zero, shift=True):
width = (self.view.x(1) - self.view.x(0)) / self._len
x, y = self.view((x, y))
series_margin = width * self._series_margin
x += series_margin
width -= 2 * series_margin
width /= self._order
x += index * width
serie_margin = width * self._serie_margin
x += serie_margin
width -= 2 * serie_margin
height = self.view.y(self.zero) - y
if shift:
width /= self._order
x += index * width
serie_margin = width * self._serie_margin
x += serie_margin
width -= 2 * serie_margin
height = self.view.y(zero) - y
print height
r = self.rounded_bars * 1 if self.rounded_bars else 0
self.svg.transposable_node(
parent, 'rect',
@ -58,8 +61,7 @@ class Bar(Graph):
def bar(self, serie_node, serie, index):
"""Draw a bar graph for a serie"""
bars = self.svg.node(serie_node['plot'], class_="bars")
view_values = map(self.view, serie.points)
for i, (x, y) in enumerate(view_values):
for i, (x, y) in enumerate(serie.points):
if None in (x, y):
continue
metadata = serie.metadata.get(i)
@ -68,9 +70,10 @@ class Bar(Graph):
self.svg,
self.svg.node(bars, class_='bar'),
metadata)
val = self._get_value(serie.points, i)
val = self._format(serie.values[i])
x_center, y_center = self._bar(bar, x, y, index)
x_center, y_center = self._bar(
bar, x, y, index, i, self.zero)
self._tooltip_data(
bar, val, x_center, y_center, classes="centered")
self._static_value(serie_node, val, x_center, y_center)

6
pygal/graph/base.py

@ -49,9 +49,9 @@ class BaseGraph(object):
self.view = None
if self.logarithmic and self.zero == 0:
# Explicit min to avoid interpolation dependency
self.zero = min(
val for serie in self.series for val in serie.values)
self.zero = min(filter(
lambda x: x > 0,
[val for serie in self.series for val in serie.safe_values]))
if self.series and self._has_data():
self._draw()
else:

40
pygal/graph/stackedbar.py

@ -24,23 +24,29 @@ Stacked Bar chart
from __future__ import division
from pygal.graph.bar import Bar
from pygal.util import compute_scale
from pygal.adapters import none_to_zero
class StackedBar(Bar):
"""Stacked Bar graph"""
_adapters = [none_to_zero]
def _compute(self):
transposed = zip(*[serie.values for serie in self.series])
positive_vals = [sum([
val if val is not None and val > self.zero else self.zero
for val in vals]) - self.zero
val for val in vals
if val is not None and val >= self.zero])
for vals in transposed]
negative_vals = [sum([
val - self.zero
if val is not None and val < self.zero else self.zero
for val in vals]) + self.zero
val
for val in vals
if val is not None and val < self.zero])
for vals in transposed]
positive_vals = positive_vals or [self.zero]
negative_vals = negative_vals or [self.zero]
self._box.ymin, self._box.ymax = (
min(min(negative_vals), self.zero),
max(max(positive_vals), self.zero))
@ -48,6 +54,8 @@ class StackedBar(Bar):
x_pos = [
x / self._len for x in range(self._len + 1)
] if self._len > 1 else [0, 1] # Center if only one value
self._points(x_pos)
y_pos = compute_scale(
self._box.ymin, self._box.ymax, self.logarithmic, self.order_min
) if not self.y_labels else map(float, self.y_labels)
@ -57,12 +65,16 @@ class StackedBar(Bar):
sum(x_range) / 2 for x_range in self._x_ranges])
self._y_labels = zip(map(self._format, y_pos), y_pos)
def _points(self, x_pos):
accumulation = [0] * self._len
for serie in self.series:
accumulation = map(sum, zip(accumulation, serie.values))
serie.points = [
(x_pos[i], v)
for i, v in enumerate(accumulation)]
if self.interpolate:
serie.interpolated = self._interpolate(accumulation, x_pos)
self.negative_cumulation = [0] * self._len
self.positive_cumulation = [0] * self._len
def _bar(self, parent, x, val, index, i, zero):
cumulation = (self.negative_cumulation if val < self.zero else
self.positive_cumulation)
zero = cumulation[i]
cumulation[i] = zero + val
if zero == 0:
zero = self.zero
val -= self.zero
return super(StackedBar, self)._bar(
parent, x, zero + val, index, i, zero, False)

Loading…
Cancel
Save