Skip to content

Commit

Permalink
Fix stacked
Browse files Browse the repository at this point in the history
  • Loading branch information
paradoxxxzero committed Oct 3, 2012
1 parent aa056bf commit 77fc66d
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 28 deletions.
2 changes: 2 additions & 0 deletions demo/moulinrouge/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ 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.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()

Expand Down
25 changes: 14 additions & 11 deletions pygal/graph/bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,20 @@ def __init__(self, *args, **kwargs):
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',
Expand All @@ -58,8 +61,7 @@ def _bar(self, parent, x, y, index):
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)
Expand All @@ -68,9 +70,10 @@ def bar(self, serie_node, serie, index):
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)
Expand Down
6 changes: 3 additions & 3 deletions pygal/graph/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ def __init__(self, config, series):
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:
Expand Down
40 changes: 26 additions & 14 deletions pygal/graph/stackedbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,38 @@
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))

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)
Expand All @@ -57,12 +65,16 @@ def _compute(self):
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)

0 comments on commit 77fc66d

Please sign in to comment.