Browse Source

Cleanup a bit and prevent crash with log

pull/130/head
Florian Mounier 11 years ago
parent
commit
51c7263e4f
  1. 7
      pygal/graph/base.py
  2. 2
      pygal/graph/dot.py
  3. 6
      pygal/graph/graph.py
  4. 13
      pygal/graph/stackedbar.py
  5. 51
      pygal/graph/verticalpyramid.py
  6. 3
      pygal/test/test_config.py
  7. 23
      pygal/view.py

7
pygal/graph/base.py

@ -55,9 +55,8 @@ class BaseGraph(object):
self.view = None
if self.logarithmic and self.zero == 0:
# Explicit min to avoid interpolation dependency
from pygal.graph.xy import XY
if isinstance(self, XY):
get = lambda x: x[1]
if self._dual:
get = lambda x: x[1] or 1
else:
get = lambda x: x
@ -66,7 +65,7 @@ class BaseGraph(object):
[get(val)
for serie in self.series for val in serie.safe_values]))
self.zero = min(positive_values) if positive_values else 0
self.zero = min(positive_values or 1,) or 1
self._draw()
self.svg.pre_render()

2
pygal/graph/dot.py

@ -76,6 +76,6 @@ class Dot(Graph):
def _plot(self):
r_max = min(
self.view.x(1) - self.view.x(0),
self.view.y(0) - self.view.y(1)) / (2 * (self._max or 1) * 1.05)
(self.view.y(0) or 0) - self.view.y(1)) / (2 * (self._max or 1) * 1.05)
for index, serie in enumerate(self.series):
self.dot(self._serie(index), serie, r_max)

6
pygal/graph/graph.py

@ -128,8 +128,8 @@ class Graph(BaseGraph):
if self.x_label_rotation or len(self._x_labels) <= 1:
truncation = 25
else:
first_label_position = self.view.x(self._x_labels[0][1])
last_label_position = self.view.x(self._x_labels[-1][1])
first_label_position = self.view.x(self._x_labels[0][1]) or 0
last_label_position = self.view.x(self._x_labels[-1][1]) or 0
available_space = (
last_label_position - first_label_position) / (
len(self._x_labels) - 1)
@ -169,7 +169,7 @@ class Graph(BaseGraph):
last_guide = (self._y_2nd_labels and label == lastlabel)
self.svg.node(
guides, 'path',
d='M%f %f v%f' % (x, 0, self.view.height),
d='M%f %f v%f' % (x or 0, 0, self.view.height),
class_='%s%sline' % (
'major ' if major else '',
'guide ' if position != 0 and not last_guide else ''))

13
pygal/graph/stackedbar.py

@ -82,13 +82,13 @@ class StackedBar(Bar):
positive_vals, negative_vals = self._get_separated_values(True)
self.secondary_negative_cumulation = [0] * self._len
self.secondary_positive_cumulation = [0] * self._len
self._pre_compute_secondary(positive_vals, negative_vals)
# 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)) or self.zero
self._secondary_max = (positive_vals and max(
sum_(max(positive_vals)), self.zero)) or self.zero
def _pre_compute_secondary(self, positive_vals, negative_vals):
self._secondary_min = (negative_vals and min(
min(negative_vals), self.zero)) or self.zero
self._secondary_max = (positive_vals and max(
max(positive_vals), self.zero)) or self.zero
def _bar(self, parent, x, y, index, i, zero,
shift=False, secondary=False, rounded=False):
@ -109,6 +109,7 @@ class StackedBar(Bar):
width = (self.view.x(1) - self.view.x(0)) / self._len
x, y = self.view((x, y))
y = y or 0
series_margin = width * self._series_margin
x += series_margin
width -= 2 * series_margin

51
pygal/graph/verticalpyramid.py

@ -37,49 +37,24 @@ class VerticalPyramid(StackedBar):
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(series)
if index % 2])
negative_vals = zip(*[serie.safe_values
for index, serie in enumerate(series)
if not index % 2])
positive_vals = map(sum, zip(
*[serie.safe_values
for index, serie in enumerate(series)
if index % 2]))
negative_vals = map(sum, zip(
*[serie.safe_values
for index, serie in enumerate(series)
if not index % 2]))
return list(positive_vals), list(negative_vals)
def _compute_box(self, positive_vals, negative_vals):
positive_sum = list(map(sum, positive_vals)) or [self.zero]
negative_sum = list(map(sum, negative_vals)) or [self.zero]
self._box.ymax = max(max(positive_sum), max(negative_sum))
self._box.ymax = max(max(positive_vals or [self.zero]),
max(negative_vals or [self.zero]))
self._box.ymin = - self._box.ymax
def _compute_secondary(self):
# Need refactoring
if self.secondary_series:
y_pos = list(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 _pre_compute_secondary(self, positive_vals, negative_vals):
self._secondary_max = max(max(positive_vals), max(negative_vals))
self._secondary_min = - self._secondary_max
def _bar(self, parent, x, y, index, i, zero,
shift=True, secondary=False, rounded=False):

3
pygal/test/test_config.py

@ -23,9 +23,8 @@ from pygal import (
FrenchMap_Regions, FrenchMap_Departments)
from pygal._compat import u
from pygal.test.utils import texts
from pygal.test import pytest_generate_tests, make_data
from pygal.test import pytest_generate_tests
from tempfile import NamedTemporaryFile
from uuid import uuid4
def test_config_behaviours():

23
pygal/view.py

@ -288,7 +288,6 @@ class PolarThetaLogView(View):
class LogView(View):
"""Logarithmic projection """
# Do not want to call the parent here
# pylint: disable-msg=W0231
def __init__(self, width, height, box):
self.width = width
self.height = height
@ -297,11 +296,10 @@ class LogView(View):
self.log10_ymin = log10(self.box.ymin) if self.box.ymin > 0 else 0
self.box.fix(False)
# pylint: enable-msg=W0231
def y(self, y):
"""Project y"""
if y is None or y <= 0 or self.log10_ymax - self.log10_ymin == 0:
return None
return 0
return (self.height - self.height *
(log10(y) - self.log10_ymin)
/ (self.log10_ymax - self.log10_ymin))
@ -310,16 +308,14 @@ class LogView(View):
class XLogView(View):
"""Logarithmic projection """
# Do not want to call the parent here
# pylint: disable-msg=W0231
def __init__(self, width, height, box):
self.width = width
self.height = height
self.box = box
self.log10_xmax = log10(self.box.xmax)
self.log10_xmin = log10(self.box.xmin)
self.log10_xmax = log10(self.box.xmax) if self.box.xmax > 0 else 0
self.log10_xmin = log10(self.box.xmin) if self.box.xmin > 0 else 0
self.box.fix(False)
# pylint: enable-msg=W0231
def x(self, x):
"""Project x"""
if x is None or x <= 0 or self.log10_xmax - self.log10_xmin == 0:
@ -334,24 +330,23 @@ class XYLogView(XLogView, LogView):
self.width = width
self.height = height
self.box = box
self.log10_ymax = log10(self.box.ymax)
self.log10_ymin = log10(self.box.ymin)
self.log10_xmax = log10(self.box.xmax)
self.log10_xmin = log10(self.box.xmin)
self.log10_ymax = log10(self.box.ymax) if self.box.ymax > 0 else 0
self.log10_ymin = log10(self.box.ymin) if self.box.ymin > 0 else 0
self.log10_xmax = log10(self.box.xmax) if self.box.xmax > 0 else 0
self.log10_xmin = log10(self.box.xmin) if self.box.xmin > 0 else 0
self.box.fix(False)
class HorizontalLogView(XLogView):
"""Logarithmic projection """
# Do not want to call the parent here
# pylint: disable-msg=W0231
def __init__(self, width, height, box):
self._force_vertical = None
self.width = width
self.height = height
self.box = box
self.log10_xmax = log10(self.box.ymax)
self.log10_xmin = log10(self.box.ymin)
self.log10_xmax = log10(self.box.ymax) if self.box.ymax > 0 else 0
self.log10_xmin = log10(self.box.ymin) if self.box.ymin > 0 else 0
self.box.fix(False)
self.box.swap()

Loading…
Cancel
Save