Skip to content

Commit

Permalink
Initial grouped bars, issue with scale. wireservice#26
Browse files Browse the repository at this point in the history
  • Loading branch information
nbedi committed May 26, 2016
1 parent 828db2c commit d5d6737
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 1 deletion.
14 changes: 14 additions & 0 deletions leather/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,20 @@ def add_lines(self, data, x=None, y=None, name=None, color=None, width=None):

self.add_series(Series(data, Lines(color, width), x=x, y=y, name=name))

def add_grouped_bars(self, data, x=None, y=None, name=None, color=None):
"""
Create and add multiple :class:`.Series` rendered with :class:`.Bars`.
Data should be a sequence of :class:`.Series` data, one for each bar in
a group.
Color should be a sequence of colors, one for each bar in a group.
"""
if not color:
color = self._series_colors.pop(0)

self.add_series(Series(data, Bars(color, grouped=True), x=x, y=y, name=name))

def _validate_dimension(self, dimension):
"""
Validates that the given scale and axis are valid for the data that
Expand Down
21 changes: 20 additions & 1 deletion leather/shapes/bars.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import six

from leather.shapes.base import Shape
from leather.utils import Y


class Bars(Shape):
Expand All @@ -14,9 +15,13 @@ class Bars(Shape):
:param color:
The color to fill the bars. You may also specify a
:func:`.style_function`.
:param grouped:
If True, any values in data with equal x values will be rendered as
grouped bars. Defaults to False.
"""
def __init__(self, fill_color):
def __init__(self, fill_color, grouped=False):
self._fill_color = fill_color
self._grouped = grouped

def to_svg(self, width, height, x_scale, y_scale, series):
"""
Expand All @@ -27,11 +32,25 @@ def to_svg(self, width, height, x_scale, y_scale, series):

zero_x = x_scale.project(0, 0, width)

if self._grouped:
y_values = series.values(Y)
y_counts = {y: y_values.count(y) for y in set(y_values)}

seen_y_counts = {y: 0 for y in set(y_values)}

for i, (x, y, row) in enumerate(series):
if x is None or y is None:
continue

y1, y2 = y_scale.project_interval(y, height, 0)

if self._grouped:
group_height = (y1 - y2) / y_counts[y]

y1 = y2 + (group_height * (seen_y_counts[y] + 1))
y2 = y2 + (group_height * seen_y_counts[y])
seen_y_counts[y] += 1

proj_x = x_scale.project(x, 0, width)

if x < 0:
Expand Down

0 comments on commit d5d6737

Please sign in to comment.