Browse Source

Added tests for box, fixed regressions

pull/91/head
Jeffrey Starr 11 years ago
parent
commit
080c2e5b22
  1. 40
      pygal/graph/box.py
  2. 62
      pygal/test/test_box.py
  3. 4
      pygal/test/test_config.py
  4. 4
      pygal/test/test_graph.py

40
pygal/graph/box.py

@ -23,6 +23,7 @@ Box plot
from __future__ import division
from pygal.graph.graph import Graph
from pygal.util import compute_scale, decorate
from math import floor
class Box(Graph):
@ -123,23 +124,44 @@ class Box(Graph):
@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
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.
"""
n = len(values)
def median(seq):
n = len(seq)
if n % 2 == 0: # seq has an even length
return (seq[n // 2] + s[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:
s = sorted(values) # sort the copy in case the originals must stay in original order
if n % 2 == 0: # n is even
q2 = (values[n // 2] + values[n // 2 + 1]) / 2
else:
q2 = values[(n + 1) // 2]
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]
q1 = values[int(round((n + 1) / 4))]
q3 = values[int(round((3 * n + 3) / 4))]
iqr = q3 - q1
q0 = q1 - 1.5 * iqr
q4 = q3 + 1.5 * iqr

62
pygal/test/test_box.py

@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
# This file is part of pygal
#
# A python svg graph plotting library
# Copyright © 2012-2013 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/>.
from pygal.graph.box import Box
from pygal import Box as ghostedBox
def test_quartiles():
a = [-2.0, 3.0, 4.0, 5.0, 8.0] # odd test data
q0, q1, q2, q3, q4 = Box._box_points(a)
assert q1 == 7.0 / 4.0
assert q2 == 4.0
assert q3 == 23 / 4.0
assert q0 == 7.0 / 4.0 - 6.0 # q1 - 1.5 * iqr
assert q4 == 23 / 4.0 + 6.0 # q3 + 1.5 * iqr
b = [1.0, 4.0, 6.0, 8.0] # even test data
q0, q1, q2, q3, q4 = Box._box_points(b)
assert q2 == 5.0
c = [2.0, None, 4.0, 6.0, None] # odd with None elements
q0, q1, q2, q3, q4 = Box._box_points(c)
assert q2 == 4.0
d = [4]
q0, q1, q2, q3, q4 = Box._box_points(d)
assert q0 == 4
assert q1 == 4
assert q2 == 4
assert q3 == 4
assert q4 == 4
def test_simple_box():
box = ghostedBox()
box.add('test1', [-1, 2, 3, 3.1, 3.2, 4, 5])
box.add('test2', [2, 3, 5, 6, 6, 4])
box.title = 'Box test'
q = box.render_pyquery()
assert len(q(".axis.y")) == 1
assert len(q(".legend")) == 2
assert len(q(".plot .series rect")) == 2

4
pygal/test/test_config.py

@ -18,7 +18,7 @@
# along with pygal. If not, see <http://www.gnu.org/licenses/>.
from pygal import (
Line, Dot, Pie, Radar, Config, Bar, Funnel, Worldmap,
SupranationalWorldmap, Histogram, Gauge)
SupranationalWorldmap, Histogram, Gauge, Box)
from pygal._compat import u
from pygal.test.utils import texts
from pygal.test import pytest_generate_tests, make_data
@ -270,7 +270,7 @@ def test_no_data():
def test_include_x_axis(Chart):
chart = Chart()
if Chart in (Pie, Radar, Funnel, Dot, Gauge, Worldmap,
SupranationalWorldmap, Histogram):
SupranationalWorldmap, Histogram, Box):
return
if not chart.cls._dual:
data = 100, 200, 150

4
pygal/test/test_graph.py

@ -68,7 +68,9 @@ def test_render_to_png(Chart, datas):
def test_metadata(Chart):
chart = Chart()
v = range(7)
if Chart == pygal.XY:
if Chart in (pygal.Box,):
return # summary charts cannot display per-value metadata
elif Chart == pygal.XY:
v = list(map(lambda x: (x, x + 1), v))
elif Chart == pygal.Worldmap or Chart == pygal.SupranationalWorldmap:
v = list(map(lambda x: x, i18n.COUNTRIES))

Loading…
Cancel
Save