Browse Source

Fix median computation (s -> seq) and fix tooltips on box plot.

pull/98/head
Florian Mounier 11 years ago
parent
commit
293576a52c
  1. 6
      pygal/css/graph.css
  2. 2
      pygal/graph/bar.py
  3. 31
      pygal/graph/box.py

6
pygal/css/graph.css

@ -85,7 +85,7 @@
{{ id }}.axis.x .guides:hover .guide.line { {{ id }}.axis.x .guides:hover .guide.line {
opacity: 1; opacity: 1;
} }
I
{{ id }}.axis .guides:hover text { {{ id }}.axis .guides:hover text {
opacity: 1; opacity: 1;
} }
@ -94,6 +94,10 @@ I
fill: none; fill: none;
} }
{{ id }}.subtle-fill {
fill-opacity: .2;
}
{{ id }}.dot { {{ id }}.dot {
stroke-width: 1px; stroke-width: 1px;
fill-opacity: 1; fill-opacity: 1;

2
pygal/graph/bar.py

@ -98,7 +98,7 @@ class Bar(Graph):
y_pos = compute_scale( y_pos = compute_scale(
self._box.ymin, self._box.ymax, self.logarithmic, self.order_min self._box.ymin, self._box.ymax, self.logarithmic, self.order_min
) if not self.y_labels else map(float, self.y_labels) ) if not self.y_labels else list(map(float, self.y_labels))
self._x_labels = self.x_labels and list(zip(self.x_labels, [ self._x_labels = self.x_labels and list(zip(self.x_labels, [
(i + .5) / self._len for i in range(self._len)])) (i + .5) / self._len for i in range(self._len)]))

31
pygal/graph/box.py

@ -23,9 +23,9 @@ Box plot
from __future__ import division from __future__ import division
from pygal.graph.graph import Graph from pygal.graph.graph import Graph
from pygal.util import compute_scale, decorate from pygal.util import compute_scale, decorate
from pygal._compat import is_list_like
# TODO: Implement tooltip
class Box(Graph): class Box(Graph):
""" """
Box plot Box plot
@ -40,6 +40,19 @@ class Box(Graph):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Box, self).__init__(*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): def _compute(self):
""" """
Compute parameters necessary for later steps Compute parameters necessary for later steps
@ -81,7 +94,6 @@ class Box(Graph):
# Note: q0 and q4 do not literally mean the zero-th quartile # Note: q0 and q4 do not literally mean the zero-th quartile
# and the fourth quartile, but rather the distance from 1.5 times # and the fourth quartile, but rather the distance from 1.5 times
# the inter-quartile range to Q1 and Q3, respectively. # the inter-quartile range to Q1 and Q3, respectively.
q0, q1, q2, q3, q4 = serie.values
boxes = self.svg.node(serie_node['plot'], class_="boxes") boxes = self.svg.node(serie_node['plot'], class_="boxes")
metadata = serie.metadata.get(0) metadata = serie.metadata.get(0)
@ -90,10 +102,11 @@ class Box(Graph):
self.svg, self.svg,
self.svg.node(boxes, class_='box'), self.svg.node(boxes, class_='box'),
metadata) metadata)
val = self._format(q2) val = self._format(serie.values)
x_center, y_center = self._draw_box(box, (q0, q1, q2, q3, q4), index) x_center, y_center = self._draw_box(box, serie.values, index)
self._tooltip_data(box, val, x_center, y_center, classes="centered") 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): def _draw_box(self, parent_node, quartiles, box_index):
""" """
@ -116,6 +129,7 @@ class Box(Graph):
parent_node, parent_node,
coords=[(xs, self.view.y(whisker)), coords=[(xs, self.view.y(whisker)),
(xe, self.view.y(whisker))], (xe, self.view.y(whisker))],
class_='reactive tooltip-trigger',
attrib={'stroke-width': 3}) attrib={'stroke-width': 3})
# draw lines connecting whiskers to box (Q1 and Q3) # draw lines connecting whiskers to box (Q1 and Q3)
@ -123,11 +137,13 @@ class Box(Graph):
parent_node, parent_node,
coords=[(left_edge + width / 2, self.view.y(quartiles[0])), coords=[(left_edge + width / 2, self.view.y(quartiles[0])),
(left_edge + width / 2, self.view.y(quartiles[1]))], (left_edge + width / 2, self.view.y(quartiles[1]))],
class_='reactive tooltip-trigger',
attrib={'stroke-width': 2}) attrib={'stroke-width': 2})
self.svg.line( self.svg.line(
parent_node, parent_node,
coords=[(left_edge + width / 2, self.view.y(quartiles[4])), coords=[(left_edge + width / 2, self.view.y(quartiles[4])),
(left_edge + width / 2, self.view.y(quartiles[3]))], (left_edge + width / 2, self.view.y(quartiles[3]))],
class_='reactive tooltip-trigger',
attrib={'stroke-width': 2}) attrib={'stroke-width': 2})
# box, bounded by Q1 and Q3 # box, bounded by Q1 and Q3
@ -138,9 +154,10 @@ class Box(Graph):
y=self.view.y(quartiles[1]), y=self.view.y(quartiles[1]),
height=self.view.y(quartiles[3]) - self.view.y(quartiles[1]), height=self.view.y(quartiles[3]) - self.view.y(quartiles[1]),
width=width, width=width,
attrib={'fill-opacity': 0.25}) class_='subtle-fill reactive tooltip-trigger')
return (left_edge + width / 2, self.view.height / 2) return (left_edge + width / 2, self.view.y(
sum(quartiles) / len(quartiles)))
@staticmethod @staticmethod
def _box_points(values): def _box_points(values):
@ -157,7 +174,7 @@ class Box(Graph):
def median(seq): def median(seq):
n = len(seq) n = len(seq)
if n % 2 == 0: # seq has an even length if n % 2 == 0: # seq has an even length
return (seq[n // 2] + s[n // 2 - 1]) / 2 return (seq[n // 2] + seq[n // 2 - 1]) / 2
else: # seq has an odd length else: # seq has an odd length
return seq[n // 2] return seq[n // 2]

Loading…
Cancel
Save