From 46580d475ac668723d3fb584d605a8c70ad49d39 Mon Sep 17 00:00:00 2001 From: Gabriel Queiroz Date: Sun, 22 Jun 2014 12:53:56 -0300 Subject: [PATCH 1/2] Added new mode to box plot chart: "extremes". Which will use the minimum and the maximum values as q0 and q4, respectively. --- pygal/graph/box.py | 17 +++++++++++++---- pygal/test/test_box.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/pygal/graph/box.py b/pygal/graph/box.py index cc35dfa..9cb7248 100644 --- a/pygal/graph/box.py +++ b/pygal/graph/box.py @@ -159,10 +159,15 @@ class Box(Graph): sum(quartiles) / len(quartiles))) @staticmethod - def _box_points(values): + def _box_points(values, mode='1.5IQR'): """ - Return a 5-tuple of Q1 - 1.5 * IQR, Q1, Median, Q3, + Default mode: (mode='1.5IQR' or unset) + Return a 5-tuple of Q1 - 1.5 * IQR, Q1, Median, Q3, and Q3 + 1.5 * IQR for a list of numeric values. + Extremes mode: (mode='extremes') + Return a 5-tuple of minimum, Q1, Median, Q3, + and maximum for a list of numeric values. + The iterator values may include None values. @@ -202,6 +207,10 @@ class Box(Graph): 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 + if mode == 'extremes': + q0 = min(s) + q4 = max(s) + else: + q0 = q1 - 1.5 * iqr + q4 = q3 + 1.5 * iqr return q0, q1, q2, q3, q4 diff --git a/pygal/test/test_box.py b/pygal/test/test_box.py index 6cec21b..492c3a3 100644 --- a/pygal/test/test_box.py +++ b/pygal/test/test_box.py @@ -49,6 +49,35 @@ def test_quartiles(): assert q3 == 4 assert q4 == 4 +def test_quartiles_min_extremes(): + a = [-2.0, 3.0, 4.0, 5.0, 8.0] # odd test data + q0, q1, q2, q3, q4 = Box._box_points(a, mode='extremes') + + assert q1 == 7.0 / 4.0 + assert q2 == 4.0 + assert q3 == 23 / 4.0 + assert q0 == -2.0 # min + assert q4 == 8.0 # max + + b = [1.0, 4.0, 6.0, 8.0] # even test data + q0, q1, q2, q3, q4 = Box._box_points(b, mode='extremes') + + 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, mode='extremes') + + assert q2 == 4.0 + + d = [4] + q0, q1, q2, q3, q4 = Box._box_points(d, mode='extremes') + + assert q0 == 4 + assert q1 == 4 + assert q2 == 4 + assert q3 == 4 + assert q4 == 4 + def test_simple_box(): box = ghostedBox() From 0e2272e0a495b7029afdf835b944c0a13f7fc1ac Mon Sep 17 00:00:00 2001 From: Gabriel Queiroz Date: Sun, 22 Jun 2014 14:00:42 -0300 Subject: [PATCH 2/2] Bug fix on box plot modes. --- pygal/config.py | 4 ++++ pygal/graph/box.py | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pygal/config.py b/pygal/config.py index 5cea237..2e70f0e 100644 --- a/pygal/config.py +++ b/pygal/config.py @@ -320,6 +320,10 @@ class Config(CommonConfig): "ie: For hermite interpolation, you can set the cardinal tension with" "{'type': 'cardinal', 'c': .5}", int) + mode = Key( + None, str, "Value", "Sets the mode to be used. (Currently only supported on box plot)", + "May be %s" % ' or '.join(["1.5IQR", "extremes"])) + order_min = Key( None, int, "Value", "Minimum order of scale, defaults to None") diff --git a/pygal/graph/box.py b/pygal/graph/box.py index 9cb7248..e74313a 100644 --- a/pygal/graph/box.py +++ b/pygal/graph/box.py @@ -47,7 +47,10 @@ class Box(Graph): def format_maybe_quartile(x): if is_list_like(x): - return 'Q1: %s Q2: %s Q3: %s' % tuple(map(sup, x[1:4])) + if self.mode == "extremes": + return 'Min: %s Q1: %s Q2: %s Q3: %s Max: %s' % tuple(map(sup, x)) + else: + return 'Q1: %s Q2: %s Q3: %s' % tuple(map(sup, x[1:4])) else: return sup(x) return format_maybe_quartile @@ -58,7 +61,7 @@ class Box(Graph): within the rendering process """ for serie in self.series: - serie.values = self._box_points(serie.values) + serie.values = self._box_points(serie.values, self.mode) if self._min: self._box.ymin = min(self._min, self.zero)