Skip to content

Commit

Permalink
Merge pull request #1 from benalexkeen/add-pie-chart
Browse files Browse the repository at this point in the history
Add pie chart
  • Loading branch information
benalexkeen committed Oct 26, 2016
2 parents 90d5767 + 6b08e27 commit cf0749e
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 16 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Expand Up @@ -90,4 +90,6 @@ ENV/
.ropeproject

.DS_Store
temp.html
temp.html

.idea/
2 changes: 2 additions & 0 deletions c3pyo/__init__.py
Expand Up @@ -3,5 +3,7 @@
from .line_chart import SplineChart
from .line_chart import StepChart
from .bar_chart import BarChart
from .bar_chart import MultiBarChart
from .scatter_chart import ScatterChart
from .pie_chart import PieChart
from .pie_chart import DonutChart
57 changes: 55 additions & 2 deletions c3pyo/bar_chart.py
Expand Up @@ -20,7 +20,7 @@ def set_data(self, data):
for key in keys:
self.data.append([key, data[key]])
else:
raise TypeError("x_data must be iterable or of type dict")
raise TypeError("data must be iterable or of type dict")

def get_data_for_json(self):
return {
Expand All @@ -47,10 +47,63 @@ def get_chart_json(self):
'legend': self.get_legend_for_json(),
'grid': self.get_grid_for_json(),
'axis': self.get_axis_for_json(),
'zoom': self.get_zoom_for_json(),
'subchart': self.get_subchart_for_json(),
'size': self.get_size_for_json(),
}
chart_json = json.dumps(chart_json)
return chart_json

def plot(self):
chart_json = self.get_chart_json()
self.plot_graph(chart_json)
self.plot_graph(chart_json)


class MultiBarChart(BarChart):
def __init__(self, **kwargs):
super(MultiBarChart, self).__init__(**kwargs)
self.set_stacked(kwargs)
self.y_labels = []
self.x_labels = []

def set_stacked(self, kwargs):
self.stacked = kwargs.get('stacked', False)
msg = 'stacked flag must be a boolean'
assert isinstance(self.stacked, bool), msg

def set_data(self, data):
if isinstance(data, dict):
y_keys = [key for key in data.keys()]
y_keys = sorted(y_keys)
for key in y_keys:
if not is_iterable(data[key]):
msg = "data series must be iterable, received {} of type {}"
raise TypeError(msg.format(data[key], type(data[key])))
data_series = [key]
data_series.extend(data[key])
self.data.append(data_series)
self.y_labels.append(key)
else:
msg = "data type must be dict, received {} of type {}"
raise TypeError(msg.format(data, type(data)))

def set_x_labels(self, x_labels):
msg = "x labels must be iterable, received {} of type {}"
assert is_iterable(x_labels), msg.format(x_labels, type(x_labels))
self.x_labels = ['x']
self.x_labels.extend(x_labels)

def get_data_for_json(self):
data = {
'type': 'bar'
}
if self.stacked:
data['groups'] = [self.y_labels]
if self.x_labels:
self.data.append(self.x_labels)
data['x'] = 'x'
data['columns'] = self.data
return data

def get_axis_for_json(self):
return {'x': {'type': 'category'}}
63 changes: 57 additions & 6 deletions c3pyo/base.py
Expand Up @@ -5,6 +5,7 @@
import os
import json
import datetime
import numbers

from jinja2 import Environment, PackageLoader

Expand Down Expand Up @@ -33,11 +34,36 @@ def __init__(self, **kwargs):
self.name = kwargs.get('name', 'C3 Chart')
self.set_grid_lines(kwargs)
self.set_legend(kwargs)
self.set_zoom(kwargs)
self.set_subchart(kwargs)
self.set_size(kwargs)
self.x_label = kwargs.get('x_label', 'x')
self.y_label = kwargs.get('y_label', 'y')
self.chart_div = '#{}'.format(kwargs.get('chart_div', 'chart_div'))
self.save_output = False

def set_subchart(self, kwargs):
self.subchart = kwargs.get('subchart', False)
if not isinstance(self.subchart, bool):
msg = 'zoom must be a boolean, received {} of type {}'
raise TypeError(msg.format(self.subchart, type(self.subchart)))

def set_zoom(self, kwargs):
self.zoom = kwargs.get('zoom', False)
if not isinstance(self.zoom, bool):
msg = 'zoom must be a boolean, received {} of type {}'
raise TypeError(msg.format(self.zoom, type(self.zoom)))

def set_size(self, kwargs):
self.height = kwargs.get('height', 0)
self.width = kwargs.get('width', 0)
if not isinstance(self.width, numbers.Number):
msg = 'width must be a number, received {} of type {}'
raise TypeError(msg.format(self.width, type(self.width)))
if not isinstance(self.height, numbers.Number):
msg = 'height must be a number, received {} of type {}'
raise TypeError(msg.format(self.height, type(self.height)))

def set_grid_lines(self, kwargs):
self.grid_lines = kwargs.get('grid_lines', False)
if self.grid_lines:
Expand All @@ -51,16 +77,18 @@ def set_grid_lines(self, kwargs):
assert isinstance(self.y_grid_lines, bool), msg.format('y')

def set_legend(self, kwargs):
self.show_legend = kwargs.get('show_legend', False)
self.show_legend = kwargs.get('show_legend', True)
self.legend_position = kwargs.get('legend_position')
if not self.legend_position:
self.legend_position = 'bottom'
if self.legend_position:
self.show_legend = True
msg = 'Currently only bottom, right and inset supported for legend_position'
assert self.legend_position in ('bottom', 'right', 'inset'), msg
msg = 'show_legend must be a boolean'
assert isinstance(self.show_legend, bool), msg
if self.legend_position not in ('bottom', 'right', 'inset'):
msg = 'Currently only bottom, right and inset supported for legend_position'
raise ValueError(msg)
if not isinstance(self.show_legend, bool):
msg = 'show_legend must be a boolean'
raise TypeError('show_legend must be a boolean')

def get_legend_for_json(self):
return {
Expand All @@ -69,14 +97,37 @@ def get_legend_for_json(self):
}

def get_grid_for_json(self):
return {
grid = {
'x': {
'show': self.x_grid_lines
},
'y': {
'show': self.y_grid_lines
}
}
if self.chart_type == 'bar':
grid['y']['lines'] = [{'value': 0}]
return grid

def get_zoom_for_json(self):
zoom = {
'enabled': self.zoom
}
return zoom

def get_subchart_for_json(self):
subchart = {
'enabled': self.subchart
}
return subchart

def get_size_for_json(self):
size = {}
if self.height:
size['height'] = self.height
if self.width:
size['width'] = self.width
return size

def reset_data(self):
self.x_data = []
Expand Down
3 changes: 3 additions & 0 deletions c3pyo/line_chart.py
Expand Up @@ -143,6 +143,9 @@ def get_chart_json(self):
'points': self.get_points_for_json(),
'grid': self.get_grid_for_json(),
'axis': self.get_axis_for_json(),
'zoom': self.get_zoom_for_json(),
'subchart': self.get_subchart_for_json(),
'size': self.get_size_for_json()
}

chart_json = json.dumps(chart_json)
Expand Down
27 changes: 26 additions & 1 deletion c3pyo/pie_chart.py
Expand Up @@ -12,7 +12,7 @@ def __init__(self, **kwargs):
self.chart_type = 'pie'

def set_data(self, data):
if isiterable(data):
if is_iterable(data):
for idx, value in enumerate(data):
if isinstance(value, numbers.Number):
self.data.append(['y{}'.format(idx+1), value])
Expand All @@ -29,4 +29,29 @@ def set_data(self, data):
else:
raise TypeError("x_data must be a collection or dict, received {}".format(type(data)))

def get_data_for_json(self):
return {
'columns': self.data,
'type': self.chart_type
}

def get_chart_json(self):
chart_json = {
'bindto': self.chart_div,
'data': self.get_data_for_json(),
'legend': self.get_legend_for_json(),
'zoom': self.get_zoom_for_json(),
'size': self.get_size_for_json(),
}
chart_json = json.dumps(chart_json)
return chart_json

def plot(self):
chart_json = self.get_chart_json()
self.plot_graph(chart_json)


class DonutChart(PieChart):
def __init__(self, **kwargs):
super(DonutChart, self).__init__(**kwargs)
self.chart_type = 'donut'
3 changes: 3 additions & 0 deletions c3pyo/scatter_chart.py
Expand Up @@ -75,6 +75,9 @@ def get_chart_json(self):
'legend': self.get_legend_for_json(),
'grid': self.get_grid_for_json(),
'axis': self.get_axis_for_json(),
'zoom': self.get_zoom_for_json(),
'subchart': self.get_subchart_for_json(),
'size': self.get_size_for_json()
}
chart_json = json.dumps(chart_json)
return chart_json
Expand Down
39 changes: 33 additions & 6 deletions c3pyo/test_base.py
Expand Up @@ -3,14 +3,14 @@
# from c3pyo import C3Chart, LineChart, SplineChart, StepChart, BarChart, ScatterChart
import c3pyo as c3

# chart = LineChart(legend_position='inset', area=True)
chart = c3.LineChart(legend_position='inset', area=True, zoom=True)

# dates = [datetime.date(2015, 3, x) for x in [1,2,3,4,5]]
# datetimes = [datetime.datetime(2015, 3, 5, x) for x in [10,11,12,13,14]]
dates = [datetime.date(2015, 3, x) for x in [1,2,3,4,5]]
datetimes = [datetime.datetime(2015, 3, 5, x) for x in [10,11,12,13,14]]

# chart.set_x_data({"x1": datetimes})
# chart.set_y_data({"y1": [10,20,30,20,10], "y2": [20, 10, 30, 40, 0]})
# chart.plot()
chart.set_x_data({"x1": datetimes})
chart.set_y_data({"y1": [10,20,30,20,10], "y2": [20, 10, 30, 40, 0]})
chart.plot()

### Bar Chart

Expand All @@ -34,3 +34,30 @@
# [[1,2,3,4,5], [6,7,8,9,10], [1.5, 2.5, 3.5, 4.5, 5.5], [5,6,7,8,9]]
# )
# chart.plot()

### Pie Chart

# chart = c3.PieChart()
# chart.set_data([1, 2, 3, 4, 5])
# chart.plot()

# chart = c3.PieChart()
# chart.set_data({"hello": 1, "world": 2, "foo": 4, "bar": 17})
# chart.plot()

### Donut Chart

# chart = c3.DonutChart()
# chart.set_data([1, 2, 3, 4, 5])
# chart.plot()

# chart = c3.PieChart()
# chart.set_data({"hello": 1, "world": 2, "foo": 4, "bar": 17})
# chart.plot()

### Multi-bar chart
# stacked_status = False
# chart = c3.MultiBarChart(stacked=stacked_status)
# chart.set_data({"a": [5, 10, 15], "b": [6, 12, 18], "c": [3, 6, 9]})
# chart.set_x_labels(['cat1', 'cat2', 'cat3'])
# chart.plot()

0 comments on commit cf0749e

Please sign in to comment.