mirror of https://github.com/Kozea/pygal.git
Florian Mounier
13 years ago
7 changed files with 147 additions and 9 deletions
@ -0,0 +1,122 @@ |
|||||||
|
# -*- coding: utf-8 -*- |
||||||
|
# This file is part of pygal |
||||||
|
# |
||||||
|
# A python svg graph plotting library |
||||||
|
# Copyright © 2012 Kozea |
||||||
|
# |
||||||
|
# This library is free software: you can redistribute it and/or modify it under |
||||||
|
# the terms of the GNU Lesser General Public License as published by the Free |
||||||
|
# Software Foundation, either version 3 of the License, or (at your option) any |
||||||
|
# later version. |
||||||
|
# |
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT |
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
||||||
|
# details. |
||||||
|
# |
||||||
|
# You should have received a copy of the GNU Lesser General Public License |
||||||
|
# along with pygal. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
""" |
||||||
|
Gauge chart |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
from __future__ import division |
||||||
|
from pygal.util import decorate, compute_scale |
||||||
|
from pygal.view import PolarView |
||||||
|
from pygal.graph.graph import Graph |
||||||
|
from math import pi |
||||||
|
|
||||||
|
|
||||||
|
class Gauge(Graph): |
||||||
|
"""Gauge graph""" |
||||||
|
|
||||||
|
def _set_view(self): |
||||||
|
self.view = PolarView( |
||||||
|
self.width - self.margin.x, |
||||||
|
self.height - self.margin.y, |
||||||
|
self._box) |
||||||
|
|
||||||
|
def arc_pos(self, value): |
||||||
|
aperture = pi / 3 |
||||||
|
if value > self._max: |
||||||
|
return (3 * pi - aperture / 2) / 2 |
||||||
|
if value < self._min: |
||||||
|
return (3 * pi + aperture / 2) / 2 |
||||||
|
start = 3 * pi / 2 + aperture / 2 |
||||||
|
return start + (2 * pi - aperture) * ( |
||||||
|
value - self.min_) / (self.max_ - self.min_) |
||||||
|
|
||||||
|
def needle(self, serie_node, serie,): |
||||||
|
thickness = .05 |
||||||
|
for i, value in enumerate(serie.values): |
||||||
|
theta = self.arc_pos(value) |
||||||
|
fmt = lambda x: '%f %f' % x |
||||||
|
value = self._format(serie.values[i]) |
||||||
|
metadata = serie.metadata[i] |
||||||
|
gauges = decorate( |
||||||
|
self.svg, |
||||||
|
self.svg.node(serie_node['plot'], class_="dots"), |
||||||
|
metadata) |
||||||
|
|
||||||
|
self.svg.node(gauges, 'polygon', points=' '.join([ |
||||||
|
fmt(self.view((0, 0))), |
||||||
|
fmt(self.view((.75, theta + thickness))), |
||||||
|
fmt(self.view((.8, theta))), |
||||||
|
fmt(self.view((.75, theta - thickness)))]), |
||||||
|
class_='line reactive tooltip-trigger') |
||||||
|
|
||||||
|
x, y = self.view((.75, theta)) |
||||||
|
self._tooltip_data(gauges, value, x, y) |
||||||
|
self._static_value(serie_node, value, x, y) |
||||||
|
|
||||||
|
def _x_axis(self, draw_axes=True): |
||||||
|
if not self._x_labels: |
||||||
|
return |
||||||
|
|
||||||
|
axis = self.svg.node(self.nodes['plot'], class_="axis x gauge") |
||||||
|
|
||||||
|
for i, (label, pos) in enumerate(self._x_labels): |
||||||
|
guides = self.svg.node(axis, class_='guides') |
||||||
|
theta = self.arc_pos(pos) |
||||||
|
self.svg.line( |
||||||
|
guides, [self.view((.95, theta)), self.view((1, theta))], |
||||||
|
close=True, |
||||||
|
class_='line') |
||||||
|
|
||||||
|
self.svg.line( |
||||||
|
guides, [self.view((0, theta)), self.view((.95, theta))], |
||||||
|
close=True, |
||||||
|
class_='guide line %s' % ('major' |
||||||
|
if i in (0, len(self._x_labels) - 1) else '')) |
||||||
|
|
||||||
|
x, y = self.view((.9, theta)) |
||||||
|
self.svg.node(guides, 'text', |
||||||
|
x=x, |
||||||
|
y=y |
||||||
|
).text = label |
||||||
|
|
||||||
|
def _y_axis(self, draw_axes=True): |
||||||
|
axis = self.svg.node(self.nodes['plot'], class_="axis y gauge") |
||||||
|
x, y = self.view((0, 0)) |
||||||
|
self.svg.node(axis, 'circle', cx=x, cy=y, r=4) |
||||||
|
|
||||||
|
def _compute(self): |
||||||
|
self._box.xmin = -1 |
||||||
|
self._box.ymin = -1 |
||||||
|
|
||||||
|
self.min_ = self._min |
||||||
|
self.max_ = self._max |
||||||
|
if self.max_ - self.min_ == 0: |
||||||
|
self.min_ -= 1 |
||||||
|
self.max_ += 1 |
||||||
|
|
||||||
|
x_pos = compute_scale( |
||||||
|
self.min_, self.max_, self.logarithmic |
||||||
|
) |
||||||
|
self._x_labels = zip(map(self._format, x_pos), x_pos) |
||||||
|
|
||||||
|
def _plot(self): |
||||||
|
for serie in self.series: |
||||||
|
self.needle( |
||||||
|
self._serie(serie.index), serie) |
Loading…
Reference in new issue