diff --git a/pygal/graph/#box.py# b/pygal/graph/#box.py# deleted file mode 100644 index de928e0..0000000 --- a/pygal/graph/#box.py# +++ /dev/null @@ -1,208 +0,0 @@ -# -*- coding: utf-8 -*- -# This file is part of pygal -# -# A python svg graph plotting library -# Copyright © 2012-2014 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 . -""" -Box plot -""" - -from __future__ import division -from pygal.graph.graph import Graph -from pygal.util import compute_scale, decorate -from pygal._compat import is_list_like - - -class Box(Graph): - """ - Box plot - For each series, shows the median value, the 25th and 75th percentiles, - and the values within - 1.5 times the interquartile range of the 25th and 75th percentiles. - - See http://en.wikipedia.org/wiki/Box_plot - """ - _series_margin = .06 - - def __init__(self, *args, **kwargs): - super(Box, self).__init__(*args, **kwargs) - - @property - def _format(self): - """Return the value formatter for this graph""" - sup = super(Box, self)._format - - def format_maybe_quartile(x): - if is_list_like(x): - if len(x) == 5: - return 'Q1: %s Q2: %s Q3: %s' % tuple(map(sup, x[1:4])) - else: - return sup(x) - return format_maybe_quartile - - def _compute(self): - """ - Compute parameters necessary for later steps - within the rendering process - """ - for serie in self.series: - serie.values = self._box_points(serie.values) - - if self._min: - self._box.ymin = min(self._min, self.zero) - if self._max: - self._box.ymax = max(self._max, 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 list(map(float, self.y_labels)) - - self._x_labels = self.x_labels and list(zip(self.x_labels, [ - (i + .5) / self._order for i in range(self._order)])) - self._y_labels = list(zip(map(self._format, y_pos), y_pos)) - - def _plot(self): - """ - Plot the series data - """ - for index, serie in enumerate(self.series): - self._boxf(self._serie(index), serie, index) - - def _boxf(self, serie_node, serie, index): - """ - For a specific series, draw the box plot. - """ - # Note: q0 and q4 do not literally mean the zero-th quartile - # and the fourth quartile, but rather the distance from 1.5 times - # the inter-quartile range to Q1 and Q3, respectively. - boxes = self.svg.node(serie_node['plot'], class_="boxes") - - metadata = serie.metadata.get(0) - - box = decorate( - self.svg, - self.svg.node(boxes, class_='box'), - metadata) - val = self._format(serie.values) - - x_center, y_center = self._draw_box(box, serie.values, index) - self._tooltip_data(box, val, x_center, y_center, classes="centered") - self._static_value(serie_node, val, x_center, y_center) - - def _draw_box(self, parent_node, quartiles, box_index): - """ - Return the center of a bounding box defined by a box plot. - Draws a box plot on self.svg. - """ - width = (self.view.x(1) - self.view.x(0)) / self._order - series_margin = width * self._series_margin - left_edge = self.view.x(0) + width * box_index + series_margin - width -= 2 * series_margin - - # draw lines for whiskers - bottom, median, and top - for i, whisker in enumerate( - (quartiles[0], quartiles[2], quartiles[4])): - whisker_width = width if i == 1 else width / 2 - shift = (width - whisker_width) / 2 - xs = left_edge + shift - xe = left_edge + width - shift - self.svg.line( - parent_node, - coords=[(xs, self.view.y(whisker)), - (xe, self.view.y(whisker))], - class_='reactive tooltip-trigger', - attrib={'stroke-width': 3}) - - # draw lines connecting whiskers to box (Q1 and Q3) - self.svg.line( - parent_node, - coords=[(left_edge + width / 2, self.view.y(quartiles[0])), - (left_edge + width / 2, self.view.y(quartiles[1]))], - class_='reactive tooltip-trigger', - attrib={'stroke-width': 2}) - self.svg.line( - parent_node, - coords=[(left_edge + width / 2, self.view.y(quartiles[4])), - (left_edge + width / 2, self.view.y(quartiles[3]))], - class_='reactive tooltip-trigger', - attrib={'stroke-width': 2}) - - # box, bounded by Q1 and Q3 - self.svg.node( - parent_node, - tag='rect', - x=left_edge, - y=self.view.y(quartiles[1]), - height=self.view.y(quartiles[3]) - self.view.y(quartiles[1]), - width=width, - class_='subtle-fill reactive tooltip-trigger') - - return (left_edge + width / 2, self.view.y( - sum(quartiles) / len(quartiles))) - - @staticmethod - def _box_points(values): - """ - Return a 5-tuple of Q1 - 1.5 * IQR, Q1, Median, Q3, - and Q3 + 1.5 * IQR for a list of numeric values. - - The iterator values may include None values. - - Uses quartile definition from Mendenhall, W. and - Sincich, T. L. Statistics for Engineering and the - Sciences, 4th ed. Prentice-Hall, 1995. - """ - def median(seq): - n = len(seq) - if n % 2 == 0: # seq has an even length - return (seq[n // 2] + seq[n // 2 - 1]) / 2 - else: # seq has an odd length - return seq[n // 2] - - # sort the copy in case the originals must stay in original order - s = sorted([x for x in values if x is not None]) - n = len(s) - if not n: - return 0, 0, 0, 0, 0 - else: - q2 = median(s) - # See 'Method 3' in http://en.wikipedia.org/wiki/Quartile - if n % 2 == 0: # even - q1 = median(s[:n // 2]) - q3 = median(s[n // 2:]) - else: # odd - if n == 1: # special case - q1 = s[0] - q3 = s[0] - elif n % 4 == 1: # n is of form 4n + 1 where n >= 1 - m = (n - 1) // 4 - q1 = 0.25 * s[m-1] + 0.75 * s[m] - q3 = 0.75 * s[3*m] + 0.25 * s[3*m + 1] - else: # n is of form 4n + 3 where n >= 1 - m = (n - 3) // 4 - q1 = 0.75 * s[m] + 0.25 * s[m+1] - q3 = 0.25 * s[3*m+1] + 0.75 * s[3*m+2] - - iqr = q3 - q1 - q0 = q1 - 1.5 * iqr - q4 = q3 + 1.5 * iqr - return q0, q1, q2, q3, q4 diff --git a/pygal/graph/#pie.py# b/pygal/graph/#pie.py# deleted file mode 100644 index 3e0826e..0000000 --- a/pygal/graph/#pie.py# +++ /dev/null @@ -1,87 +0,0 @@ -# -*- coding: utf-8 -*- -# This file is part of pygal -# -# A python svg graph plotting library -# Copyright © 2012-2014 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 . -""" -Pie chart - -""" - -from __future__ import division -from pygal.util import decorate -from pygal.graph.graph import Graph -from pygal.adapters import positive, none_to_zero -from math import pi - - -class Pie(Graph): - """Pie graph""" - - _adapters = [positive, none_to_zero] - - def slice(self, serie_node, start_angle, serie, total): - """Make a serie slice""" - dual = self._len > 1 and not self._order == 1 - - slices = self.svg.node(serie_node['plot'], class_="slices") - serie_angle = 0 - total_perc = 0 - original_start_angle = start_angle - center = ((self.width - self.margin.x) / 2., - (self.height - self.margin.y) / 2.) - radius = min(center) - for i, val in enumerate(serie.values): - perc = val / total - angle = 2 * pi * perc - serie_angle += angle - val = '{0:.2%}'.format(perc) - metadata = serie.metadata.get(i) - slice_ = decorate( - self.svg, - self.svg.node(slices, class_="slice"), - metadata) - if dual: - small_radius = radius * .9 - big_radius = radius - else: - big_radius = radius * .9 - small_radius = radius * self.config.inner_radius - - self.svg.slice( - serie_node, slice_, big_radius, small_radius, - angle, start_angle, center, val) - start_angle += angle - total_perc += perc - - if dual: - val = '{0:.2%}'.format(total_perc) - self.svg.slice(serie_node, - self.svg.node(slices, class_="big_slice"), - radius * .9, 0, serie_angle, - original_start_angle, center, val) - return serie_angle - - def _plot(self): - total = sum(map(sum, map(lambda x: x.values, self.series))) - - if total == 0: - return - current_angle = 0 - for index, serie in enumerate(self.series): - angle = self.slice( - self._serie(index), current_angle, serie, total) - current_angle += angle