Skip to content

Commit

Permalink
Merge pull request Kozea#133 from gjvnq/master
Browse files Browse the repository at this point in the history
Added new mode to box plot chart: "extremes"
  • Loading branch information
paradoxxxzero committed Jun 23, 2014
2 parents 383777c + 0e2272e commit 750d76d
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 6 deletions.
4 changes: 4 additions & 0 deletions pygal/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
24 changes: 18 additions & 6 deletions pygal/graph/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ def _format(self):

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
Expand All @@ -58,7 +61,7 @@ def _compute(self):
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)
Expand Down Expand Up @@ -160,10 +163,15 @@ def _draw_box(self, parent_node, quartiles, box_index):
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.
Expand Down Expand Up @@ -203,6 +211,10 @@ def median(seq):
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
29 changes: 29 additions & 0 deletions pygal/test/test_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 750d76d

Please sign in to comment.