Browse Source

Fix the rest as much as I can with secondary

pull/26/merge
Florian Mounier 12 years ago
parent
commit
72ef8ea11b
  1. 12
      demo/moulinrouge/tests.py
  2. 30
      pygal/graph/bar.py
  3. 6
      pygal/graph/graph.py
  4. 2
      pygal/graph/radar.py
  5. 54
      pygal/graph/stackedbar.py
  6. 41
      pygal/graph/verticalpyramid.py
  7. 5
      pygal/test/__init__.py

12
demo/moulinrouge/tests.py

@ -184,12 +184,16 @@ def get_test_routes(app):
@app.route('/test/secondary/<chart>')
def test_secondary_for(chart):
chart = CHARTS_BY_NAME[chart](fill=True)
chart.title = 'LOL ' * 23
chart.x_labels = 'abc'
chart.x_label_rotation = 25
chart.y_label_rotation = 50
chart.add('1', [30, 20, 25])
chart.add(10 * '1b', [4000000, 5, 6], secondary=True)
chart.add(10 * '2b', [3, 0, 12], secondary=True)
chart.add('2', [8, 21, 5])
chart.add('1', [30, 20, -2])
chart.add(10 * '1b', [-4, 50, 6], secondary=True)
chart.add(10 * '2b', [3, 30, -1], secondary=True)
chart.add('2', [8, 21, -0])
chart.add('3', [1, 2, 3])
chart.add('3b', [-1, 2, -3], secondary=True)
return chart.render_response()
@app.route('/test/secondary_xy')

30
pygal/graph/bar.py

@ -36,7 +36,7 @@ class Bar(Graph):
self._x_ranges = None
super(Bar, self).__init__(*args, **kwargs)
def _bar(self, parent, x, y, index, i, zero, shift=True):
def _bar(self, parent, x, y, index, i, zero, shift=True, secondary=False):
width = (self.view.x(1) - self.view.x(0)) / self._len
x, y = self.view((x, y))
series_margin = width * self._series_margin
@ -79,7 +79,7 @@ class Bar(Graph):
val = self._format(serie.values[i])
x_center, y_center = self._bar(
bar, x, y, index, i, self.zero)
bar, x, y, index, i, self.zero, secondary=rescale)
self._tooltip_data(
bar, val, x_center, y_center, classes="centered")
self._static_value(serie_node, val, x_center, y_center)
@ -104,6 +104,32 @@ class Bar(Graph):
(i + .5) / self._len for i in range(self._len)])
self._y_labels = zip(map(self._format, y_pos), y_pos)
def _compute_secondary(self):
if self.secondary_series:
y_pos = zip(*self._y_labels)[1]
ymin = self._secondary_min
ymax = self._secondary_max
min_0_ratio = (self.zero - self._box.ymin) / self._box.height
max_0_ratio = (self._box.ymax - self.zero) / self._box.height
new_ymax = (self.zero - ymin) * (1 / min_0_ratio - 1)
new_ymin = -(ymax - self.zero) * (1 / max_0_ratio - 1)
if ymax > self._box.ymax:
ymin = new_ymin
else:
ymax = new_ymax
left_range = abs(self._box.ymax - self._box.ymin)
right_range = abs(ymax - ymin)
self._scale = left_range / right_range
self._scale_diff = self._box.ymin
self._scale_min_2nd = ymin
self._y_2nd_labels = [
(self._format(self._box.xmin + y * right_range / left_range),
y)
for y in y_pos]
def _plot(self):
for index, serie in enumerate(self.series):
self.bar(self._serie(index), serie, index)

6
pygal/graph/graph.py

@ -411,10 +411,8 @@ class Graph(BaseGraph):
def _compute_secondary(self):
# secondary y axis support
y_pos = zip(*self._y_labels)[1]
# secondary y axis support
if self.secondary_series:
if self.secondary_series and self._y_labels:
y_pos = zip(*self._y_labels)[1]
if self.include_x_axis:
ymin = min(self._secondary_min, 0)
ymax = max(self._secondary_max, 0)

2
pygal/graph/radar.py

@ -117,7 +117,7 @@ class Radar(Line):
def _compute(self):
delta = 2 * pi / self._len if self._len else 0
x_pos = [.5 * pi + i * delta for i in range(self._len + 1)]
for serie in self.series:
for serie in self.all_series:
serie.points = [
(v, x_pos[i])
for i, v in enumerate(serie.values)]

54
pygal/graph/stackedbar.py

@ -23,7 +23,7 @@ Stacked Bar chart
from __future__ import division
from pygal.graph.bar import Bar
from pygal.util import compute_scale
from pygal.util import compute_scale, swap, ident
from pygal.adapters import none_to_zero
@ -32,8 +32,9 @@ class StackedBar(Bar):
_adapters = [none_to_zero]
def _get_separated_values(self):
transposed = zip(*[serie.values for serie in self.series])
def _get_separated_values(self, secondary=False):
series = self.secondary_series if secondary else self.series
transposed = zip(*[serie.values for serie in series])
positive_vals = [sum([
val for val in vals
if val is not None and val >= self.zero])
@ -77,13 +78,50 @@ class StackedBar(Bar):
self.negative_cumulation = [0] * self._len
self.positive_cumulation = [0] * self._len
def _bar(self, parent, x, y, index, i, zero, shift=True):
cumulation = (self.negative_cumulation if y < self.zero else
self.positive_cumulation)
if self.secondary_series:
positive_vals, negative_vals = self._get_separated_values(True)
self.secondary_negative_cumulation = [0] * self._len
self.secondary_positive_cumulation = [0] * self._len
# In case of pyramids
sum_ = lambda x: sum(x) if isinstance(x, tuple) else x
self._secondary_min = negative_vals and min(
sum_(min(negative_vals)), self.zero)
self._secondary_max = positive_vals and max(
sum_(max(positive_vals)), self.zero)
def _bar(self, parent, x, y, index, i, zero, shift=False, secondary=False):
if secondary:
cumulation = (self.secondary_negative_cumulation
if y < self.zero else
self.secondary_positive_cumulation)
else:
cumulation = (self.negative_cumulation
if y < self.zero else
self.positive_cumulation)
zero = cumulation[i]
cumulation[i] = zero + y
if zero == 0:
zero = self.zero
y -= self.zero
return super(StackedBar, self)._bar(
parent, x, zero + y, index, i, zero, False)
y += zero
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
if self.secondary_series:
width /= 2
x += int(secondary) * width
serie_margin = width * self._serie_margin
x += serie_margin
width -= 2 * serie_margin
height = self.view.y(zero) - y
r = self.rounded_bars * 1 if self.rounded_bars else 0
self.svg.transposable_node(
parent, 'rect',
x=x, y=y, rx=r, ry=r, width=width, height=height,
class_='rect reactive tooltip-trigger')
transpose = swap if self.horizontal else ident
return transpose((x + width / 2, y + height / 2))

41
pygal/graph/verticalpyramid.py

@ -35,12 +35,13 @@ class VerticalPyramid(StackedBar):
def _format(self, value):
return super(VerticalPyramid, self)._format(abs(value))
def _get_separated_values(self):
def _get_separated_values(self, secondary=False):
series = self.secondary_series if secondary else self.series
positive_vals = zip(*[serie.safe_values
for index, serie in enumerate(self.series)
for index, serie in enumerate(series)
if index % 2])
negative_vals = zip(*[serie.safe_values
for index, serie in enumerate(self.series)
for index, serie in enumerate(series)
if not index % 2])
return positive_vals, negative_vals
@ -50,8 +51,38 @@ class VerticalPyramid(StackedBar):
self._box.ymax = max(max(positive_sum), max(negative_sum))
self._box.ymin = - self._box.ymax
def _bar(self, parent, x, y, index, i, zero, shift=True):
def _compute_secondary(self):
# Need refactoring
if self.secondary_series:
y_pos = zip(*self._y_labels)[1]
positive_vals, negative_vals = self._get_separated_values(True)
positive_sum = map(sum, positive_vals) or [self.zero]
negative_sum = map(sum, negative_vals) or [self.zero]
ymax = max(max(positive_sum), max(negative_sum))
ymin = -ymax
min_0_ratio = (self.zero - self._box.ymin) / self._box.height
max_0_ratio = (self._box.ymax - self.zero) / self._box.height
new_ymax = (self.zero - ymin) * (1 / min_0_ratio - 1)
new_ymin = -(ymax - self.zero) * (1 / max_0_ratio - 1)
if ymax > self._box.ymax:
ymin = new_ymin
else:
ymax = new_ymax
left_range = abs(self._box.ymax - self._box.ymin)
right_range = abs(ymax - ymin)
self._scale = left_range / right_range
self._scale_diff = self._box.ymin
self._scale_min_2nd = ymin
self._y_2nd_labels = [
(self._format(self._box.xmin + y * right_range / left_range),
y)
for y in y_pos]
def _bar(self, parent, x, y, index, i, zero, shift=True, secondary=False):
if index % 2:
y = -y
return super(VerticalPyramid, self)._bar(
parent, x, y, index, i, zero, False)
parent, x, y, index, i, zero, False, secondary)

5
pygal/test/__init__.py

@ -42,8 +42,9 @@ def pytest_generate_tests(metafunc):
])
def make_data(chart, datas):
def make_data(chart, datas, secondary=False):
for data in datas:
chart.add(data[0],
data[1] if chart.__class__ == pygal.XY else cut(data[1]))
data[1] if chart.__class__ == pygal.XY else cut(data[1]),
secondary=secondary)
return chart

Loading…
Cancel
Save