mirror of https://github.com/Kozea/pygal.git
Florian Mounier
13 years ago
4 changed files with 107 additions and 1 deletions
@ -0,0 +1,81 @@ |
|||||||
|
from pygal import Serie, Margin, Label |
||||||
|
from pygal.svg import Svg |
||||||
|
from pygal.base import BaseGraph |
||||||
|
|
||||||
|
|
||||||
|
class Bar(BaseGraph): |
||||||
|
"""Bar graph""" |
||||||
|
|
||||||
|
def __init__(self, width, height, precision=5, |
||||||
|
format='g', style=None): |
||||||
|
self.width = width |
||||||
|
self.height = height |
||||||
|
self.svg = Svg(width, height, style=style) |
||||||
|
self.label_font_size = 12 |
||||||
|
self.format = format |
||||||
|
self.precision = precision |
||||||
|
self.series = [] |
||||||
|
self.x_labels = self.y_labels = self.title = None |
||||||
|
|
||||||
|
def add(self, title, values): |
||||||
|
self.series.append( |
||||||
|
Serie(title, values)) |
||||||
|
|
||||||
|
def _label(self, label): |
||||||
|
return Label(('{:.%d%s}' % ( |
||||||
|
self.precision, self.format)).format(label), label) |
||||||
|
|
||||||
|
def _y_labels(self, ymin, ymax): |
||||||
|
step = (ymax - ymin) / 20. |
||||||
|
if not step: |
||||||
|
return [self._label(ymin)] |
||||||
|
label = ymin |
||||||
|
labels = [] |
||||||
|
while label <= ymax: |
||||||
|
labels.append(self._label(label)) |
||||||
|
label += step |
||||||
|
return labels |
||||||
|
|
||||||
|
def validate(self): |
||||||
|
assert len(self.series) |
||||||
|
if self.x_labels: |
||||||
|
assert len(self.series[0].values) == len(self.x_labels) |
||||||
|
for serie in self.series: |
||||||
|
assert len(self.series[0].values) == len(serie.values) |
||||||
|
|
||||||
|
def draw(self): |
||||||
|
self.validate() |
||||||
|
x_step = len(self.series[0].values) + 1 |
||||||
|
x_pos = [x / float(x_step) for x in range(x_step) |
||||||
|
] if x_step > 1 else [0, 1] # Center if only one value |
||||||
|
x_ranges = zip(x_pos, x_pos[1:]) |
||||||
|
|
||||||
|
vals = [val for serie in self.series for val in serie.values] |
||||||
|
margin = Margin(*(4 * [10])) |
||||||
|
ymin, ymax = min(vals), max(vals) |
||||||
|
if self.x_labels: |
||||||
|
x_labels = [Label(label, sum(x_ranges[i]) / 2) |
||||||
|
for i, label in enumerate(self.x_labels)] |
||||||
|
y_labels = self.y_labels or self._y_labels(ymin, ymax) |
||||||
|
series_labels = [serie.title for serie in self.series] |
||||||
|
margin.left += 10 + max( |
||||||
|
map(len, [l.label for l in y_labels])) * 0.6 * self.label_font_size |
||||||
|
if self.x_labels: |
||||||
|
margin.bottom += 10 + self.label_font_size |
||||||
|
margin.right += 20 + max( |
||||||
|
map(len, series_labels)) * 0.6 * self.label_font_size |
||||||
|
margin.top += 10 + self.label_font_size |
||||||
|
|
||||||
|
# Actual drawing |
||||||
|
self.svg.set_view(margin, ymin, ymax) |
||||||
|
self.svg.graph(margin) |
||||||
|
if self.x_labels: |
||||||
|
self.svg.x_axis(x_labels) |
||||||
|
self.svg.y_axis(y_labels) |
||||||
|
self.svg.legend(margin, series_labels) |
||||||
|
self.svg.title(margin, self.title) |
||||||
|
for serie_index, serie in enumerate(self.series): |
||||||
|
serie_node = self.svg.serie(serie_index) |
||||||
|
self.svg.bar(serie_node, [ |
||||||
|
((x_ranges[i][0], v), (x_ranges[i][1], v)) |
||||||
|
for i, v in enumerate(serie.values)]) |
@ -0,0 +1,11 @@ |
|||||||
|
from pygal.bar import Bar |
||||||
|
from math import cos, sin |
||||||
|
|
||||||
|
|
||||||
|
def test_simple_bar(): |
||||||
|
bar = Bar(800, 600, precision=2, format='f') |
||||||
|
rng = [12, 3, 30, 4, 0] |
||||||
|
bar.add('test1', rng) |
||||||
|
bar.x_labels = map(str, rng) |
||||||
|
bar.title = "Bar test" |
||||||
|
bar._in_browser() |
Loading…
Reference in new issue