\n",
285 | " "
286 | ],
287 | "text/plain": [
288 | "
"
289 | ]
290 | },
291 | "metadata": {},
292 | "output_type": "display_data"
293 | }
294 | ],
295 | "source": [
296 | "df4 = pd.DataFrame(df3.sum(), columns=['sum'])\n",
297 | "#df4.to_dict('series').items()[0][1].tolist()\n",
298 | "display_charts(df4, polar=True, kind='bar', ylim=(0, 2.3), title='Angel Deals By Sector')"
299 | ]
300 | }
301 | ],
302 | "metadata": {
303 | "kernelspec": {
304 | "display_name": "Python 2",
305 | "language": "python",
306 | "name": "python2"
307 | },
308 | "language_info": {
309 | "codemirror_mode": {
310 | "name": "ipython",
311 | "version": 2
312 | },
313 | "file_extension": ".py",
314 | "mimetype": "text/x-python",
315 | "name": "python",
316 | "nbconvert_exporter": "python",
317 | "pygments_lexer": "ipython2",
318 | "version": "2.7.10"
319 | }
320 | },
321 | "nbformat": 4,
322 | "nbformat_minor": 0
323 | }
324 |
--------------------------------------------------------------------------------
/pandas_highcharts/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = '0.5.1'
--------------------------------------------------------------------------------
/pandas_highcharts/core.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pandas
4 | import copy
5 |
6 |
7 | _pd2hc_kind = {
8 | "bar": "column",
9 | "barh": "bar",
10 | "area": "area",
11 | "line": "line",
12 | "pie": "pie"
13 | }
14 |
15 |
16 | def pd2hc_kind(kind):
17 | if kind not in _pd2hc_kind:
18 | raise ValueError("%(kind)s plots are not yet supported" % locals())
19 | return _pd2hc_kind[kind]
20 |
21 | _pd2hc_linestyle = {
22 | "-": "Solid",
23 | "--": "Dash",
24 | "-.": "DashDot",
25 | ":": "Dot"
26 | }
27 |
28 |
29 | def pd2hc_linestyle(linestyle):
30 | if linestyle not in _pd2hc_linestyle:
31 | raise ValueError("%(linestyle)s linestyles are not yet supported" % locals())
32 | return _pd2hc_linestyle[linestyle]
33 |
34 |
35 | def json_encode(obj):
36 | return pandas.io.json.dumps(obj)
37 |
38 |
39 | def serialize(df, output_type="javascript", chart_type="default", *args, **kwargs):
40 | def serialize_chart(df, output, *args, **kwargs):
41 | output["chart"] = {}
42 | if 'render_to' in kwargs:
43 | output['chart']['renderTo'] = kwargs['render_to']
44 | if "figsize" in kwargs:
45 | output["chart"]["width"] = kwargs["figsize"][0]
46 | output["chart"]["height"] = kwargs["figsize"][1]
47 | if "kind" in kwargs:
48 | output["chart"]["type"] = pd2hc_kind(kwargs["kind"])
49 | if kwargs.get('polar'):
50 | output['chart']['polar'] = True
51 |
52 | def serialize_colors(df, output, *args, **kwargs):
53 | pass
54 |
55 | def serialize_credits(df, output, *args, **kwargs):
56 | pass
57 |
58 | def serialize_data(df, output, *args, **kwargs):
59 | pass
60 |
61 | def serialize_drilldown(df, output, *args, **kwargs):
62 | pass
63 |
64 | def serialize_exporting(df, output, *args, **kwargs):
65 | pass
66 |
67 | def serialize_labels(df, output, *args, **kwargs):
68 | pass
69 |
70 | def serialize_legend(df, output, *args, **kwargs):
71 | output["legend"] = {
72 | "enabled": kwargs.get("legend", True)
73 | }
74 |
75 | def serialize_loading(df, output, *args, **kwargs):
76 | pass
77 |
78 | def serialize_navigation(df, output, *args, **kwargs):
79 | pass
80 |
81 | def serialize_noData(df, output, *args, **kwargs):
82 | pass
83 |
84 | def serialize_pane(df, output, *args, **kwargs):
85 | pass
86 |
87 | def serialize_plotOptions(df, output, *args, **kwargs):
88 | pass
89 |
90 | def serialize_series(df, output, *args, **kwargs):
91 | def is_secondary(c, **kwargs):
92 | return c in kwargs.get("secondary_y", [])
93 | if kwargs.get('sort_columns'):
94 | df = df.sort_index()
95 | series = df.to_dict('series')
96 | output["series"] = []
97 | for name, data in series.items():
98 | if df[name].dtype.kind in "biufc":
99 | sec = is_secondary(name, **kwargs)
100 | d = {
101 | "name": name if not sec or not kwargs.get("mark_right", True) else name + " (right)",
102 | "yAxis": int(sec),
103 | "data": list(zip(df.index, data.values.tolist()))
104 | }
105 | if kwargs.get('polar'):
106 | d['data'] = [v for k, v in d['data']]
107 | if kwargs.get("kind") == "area" and kwargs.get("stacked", True):
108 | d["stacking"] = 'normal'
109 | if kwargs.get("style"):
110 | d["dashStyle"] = pd2hc_linestyle(kwargs["style"].get(name, "-"))
111 | output["series"].append(d)
112 | output['series'].sort(key=lambda s: s['name'])
113 |
114 | def serialize_subtitle(df, output, *args, **kwargs):
115 | pass
116 |
117 | def serialize_title(df, output, *args, **kwargs):
118 | if "title" in kwargs:
119 | output["title"] = {"text": kwargs["title"]}
120 |
121 | def serialize_tooltip(df, output, *args, **kwargs):
122 | if 'tooltip' in kwargs:
123 | output['tooltip'] = kwargs['tooltip']
124 |
125 | def serialize_xAxis(df, output, *args, **kwargs):
126 | output["xAxis"] = {}
127 | if df.index.name:
128 | output["xAxis"]["title"] = {"text": df.index.name}
129 | if df.index.dtype.kind in "M":
130 | output["xAxis"]["type"] = "datetime"
131 | if df.index.dtype.kind == 'O':
132 | output['xAxis']['categories'] = sorted(list(df.index)) if kwargs.get('sort_columns') else list(df.index)
133 | if kwargs.get("grid"):
134 | output["xAxis"]["gridLineWidth"] = 1
135 | output["xAxis"]["gridLineDashStyle"] = "Dot"
136 | if kwargs.get("loglog") or kwargs.get("logx"):
137 | output["xAxis"]["type"] = 'logarithmic'
138 | if "xlim" in kwargs:
139 | output["xAxis"]["min"] = kwargs["xlim"][0]
140 | output["xAxis"]["max"] = kwargs["xlim"][1]
141 | if "rot" in kwargs:
142 | output["xAxis"]["labels"] = {"rotation": kwargs["rot"]}
143 | if "fontsize" in kwargs:
144 | output["xAxis"].setdefault("labels", {})["style"] = {"fontSize": kwargs["fontsize"]}
145 | if "xticks" in kwargs:
146 | output["xAxis"]["tickPositions"] = kwargs["xticks"]
147 |
148 | def serialize_yAxis(df, output, *args, **kwargs):
149 | yAxis = {}
150 | if kwargs.get("grid"):
151 | yAxis["gridLineWidth"] = 1
152 | yAxis["gridLineDashStyle"] = "Dot"
153 | if kwargs.get("loglog") or kwargs.get("logy"):
154 | yAxis["type"] = 'logarithmic'
155 | if "ylim" in kwargs:
156 | yAxis["min"] = kwargs["ylim"][0]
157 | yAxis["max"] = kwargs["ylim"][1]
158 | if "rot" in kwargs:
159 | yAxis["labels"] = {"rotation": kwargs["rot"]}
160 | if "fontsize" in kwargs:
161 | yAxis.setdefault("labels", {})["style"] = {"fontSize": kwargs["fontsize"]}
162 | if "yticks" in kwargs:
163 | yAxis["tickPositions"] = kwargs["yticks"]
164 | output["yAxis"] = [yAxis]
165 | if kwargs.get("secondary_y"):
166 | yAxis2 = copy.deepcopy(yAxis)
167 | yAxis2["opposite"] = True
168 | output["yAxis"].append(yAxis2)
169 |
170 | def serialize_zoom(df, output, *args, **kwargs):
171 | if "zoom" in kwargs:
172 | if kwargs["zoom"] not in ("x", "y", "xy"):
173 | raise ValueError("zoom must be in ('x', 'y', 'xy')")
174 | output["chart"]["zoomType"] = kwargs["zoom"]
175 |
176 | output = {}
177 | df_copy = copy.deepcopy(df)
178 | if "x" in kwargs:
179 | df_copy.index = df_copy.pop(kwargs["x"])
180 | if kwargs.get("use_index", True) is False:
181 | df_copy = df_copy.reset_index()
182 | if "y" in kwargs:
183 | df_copy = pandas.DataFrame(df_copy, columns=kwargs["y"])
184 | serialize_chart(df_copy, output, *args, **kwargs)
185 | serialize_colors(df_copy, output, *args, **kwargs)
186 | serialize_credits(df_copy, output, *args, **kwargs)
187 | serialize_data(df_copy, output, *args, **kwargs)
188 | serialize_drilldown(df_copy, output, *args, **kwargs)
189 | serialize_exporting(df_copy, output, *args, **kwargs)
190 | serialize_labels(df_copy, output, *args, **kwargs)
191 | serialize_legend(df_copy, output, *args, **kwargs)
192 | serialize_loading(df_copy, output, *args, **kwargs)
193 | serialize_navigation(df_copy, output, *args, **kwargs)
194 | serialize_noData(df_copy, output, *args, **kwargs)
195 | serialize_pane(df_copy, output, *args, **kwargs)
196 | serialize_plotOptions(df_copy, output, *args, **kwargs)
197 | serialize_series(df_copy, output, *args, **kwargs)
198 | serialize_subtitle(df_copy, output, *args, **kwargs)
199 | serialize_title(df_copy, output, *args, **kwargs)
200 | serialize_tooltip(df_copy, output, *args, **kwargs)
201 | serialize_xAxis(df_copy, output, *args, **kwargs)
202 | serialize_yAxis(df_copy, output, *args, **kwargs)
203 | serialize_zoom(df_copy, output, *args, **kwargs)
204 | if output_type == "dict":
205 | return output
206 | if output_type == "json":
207 | return json_encode(output)
208 | if chart_type == "stock":
209 | return "new Highcharts.StockChart(%s);" % json_encode(output)
210 | return "new Highcharts.Chart(%s);" % json_encode(output)
211 |
--------------------------------------------------------------------------------
/pandas_highcharts/data/ANGEL_SECTORS.csv:
--------------------------------------------------------------------------------
1 | Year,Software,Healthcare,Hardware,Biotech,Telecom,Manufacturing,Financial Products and Services,IT Services,Industrial/Energy,Retail,Media
2 | 2013-12-31,23.0,14.0,,11.0,,,7.0,,,7.0,16.0
3 | 2012-12-31,23.0,14.0,,11.0,,,,,7.0,12.0,7.0
4 | 2011-12-31,23.0,19.0,,13.0,,,,7.0,13.0,,5.0
5 | 2010-12-31,16.0,30.0,,15.0,,,,5.0,8.0,5.0,
6 | 2009-12-31,19.0,17.0,,8.0,,,5.0,,17.0,9.0,
7 | 2008-12-31,13.0,16.0,,11.0,,,,,8.0,12.0,7.0
8 | 2007-12-31,27.0,19.0,,12.0,,,,,8.0,6.0,5.0
9 | 2006-12-31,18.0,21.0,,18.0,,,6.0,,6.0,8.0,
10 | 2005-12-31,18.0,20.0,8.0,12.0,,,,6.0,6.0,,6.0
11 | 2004-12-31,22.0,16.0,10.0,10.0,6.0,,8.0,8.0,,7.0,
12 | 2003-12-31,26.0,13.0,12.0,11.0,5.0,12.0,,,,,
13 | 2002-12-31,40.0,14.0,5.0,5.0,5.0,,,,,,
14 |
--------------------------------------------------------------------------------
/pandas_highcharts/data/DEU_PCPIPCH.csv:
--------------------------------------------------------------------------------
1 | Date,Value
2 | 2019-12-31,1.7
3 | 2018-12-31,1.7
4 | 2017-12-31,1.7
5 | 2016-12-31,1.5
6 | 2015-12-31,1.247
7 | 2014-12-31,0.896
8 | 2013-12-31,1.601
9 | 2012-12-31,2.13
10 | 2011-12-31,2.498
11 | 2010-12-31,1.158
12 | 2009-12-31,0.226
13 | 2008-12-31,2.738
14 | 2007-12-31,2.285
15 | 2006-12-31,1.784
16 | 2005-12-31,1.92
17 | 2004-12-31,1.799
18 | 2003-12-31,1.022
19 | 2002-12-31,1.346
20 | 2001-12-31,1.904
21 | 2000-12-31,1.418
22 | 1999-12-31,0.626
23 | 1998-12-31,0.593
24 | 1997-12-31,1.542
25 | 1996-12-31,1.19
26 | 1995-12-31,1.733
27 | 1994-12-31,2.717
28 | 1993-12-31,4.476
29 | 1992-12-31,5.046
30 | 1991-12-31,3.474
31 | 1990-12-31,2.687
32 | 1989-12-31,2.778
33 | 1988-12-31,1.274
34 | 1987-12-31,0.242
35 | 1986-12-31,-0.125
36 | 1985-12-31,2.084
37 | 1984-12-31,2.396
38 | 1983-12-31,3.284
39 | 1982-12-31,5.256
40 | 1981-12-31,6.324
41 | 1980-12-31,5.447
42 |
--------------------------------------------------------------------------------
/pandas_highcharts/display.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from __future__ import absolute_import
4 |
5 | """Functions to quickly display charts in a Notebook.
6 | """
7 |
8 | import string
9 | import random
10 | import json
11 | import copy
12 |
13 | from IPython.core import getipython
14 | from IPython.core.display import display, HTML
15 |
16 | from .core import serialize
17 |
18 |
19 | # Note that Highstock includes all Highcharts features.
20 | HIGHCHARTS_SCRIPTS = """
21 |
22 |
23 |
24 | """
25 |
26 |
27 | def load_highcharts():
28 | return display(HTML(HIGHCHARTS_SCRIPTS))
29 |
30 | # Automatically insert the script tag into your Notebook.
31 | # Call when you import this module.
32 | if 'IPKernelApp' in getipython.get_ipython().config:
33 | load_highcharts()
34 |
35 |
36 | def _generate_div_id_chart(prefix="chart_id", digits=8):
37 | """Generate a random id for div chart.
38 | """
39 | choices = (random.randrange(0, 52) for _ in range(digits))
40 | return prefix + "".join((string.ascii_letters[x] for x in choices))
41 |
42 |
43 | def display_charts(df, chart_type="default", render_to=None, **kwargs):
44 | """Display you DataFrame with Highcharts.
45 |
46 | df: DataFrame
47 | chart_type: str
48 | 'default' or 'stock'
49 | render_to: str
50 | div id for plotting your data
51 | """
52 | if chart_type not in ("default", "stock"):
53 | raise ValueError("Wrong chart_type: accept 'default' or 'stock'.")
54 | chart_id = render_to if render_to is not None else _generate_div_id_chart()
55 | json_data = serialize(df, render_to=chart_id, chart_type=chart_type,
56 | **kwargs)
57 | content = """
58 | """
59 | return display(HTML(content.format(chart_id=chart_id,
60 | data=json_data)))
61 |
62 |
63 | def _series_data_filter(data):
64 | """Replace each 'data' key in the list stored under 'series' by "[...]".
65 |
66 | Use to not store and display the series data when you just want display and
67 | modify the Highcharts parameters.
68 |
69 | data: dict
70 | Serialized DataFrame in a dict for Highcharts
71 |
72 | Returns: a dict with filtered values
73 |
74 | See also `core.serialize`
75 | """
76 | data = copy.deepcopy(data)
77 | if "series" in data:
78 | for series in data["series"]:
79 | series["data"] = "[...]"
80 | return data
81 |
82 |
83 | def pretty_params(data, indent=2):
84 | """Pretty print your Highcharts params (into a JSON).
85 |
86 | data: dict
87 | Serialized DataFrame in a dict for Highcharts
88 | """
89 | data_to_print = _series_data_filter(data)
90 | print(json.dumps(data_to_print, indent=indent))
91 |
--------------------------------------------------------------------------------
/pandas_highcharts/tests.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from __future__ import absolute_import
4 |
5 | import datetime
6 | import json
7 | import pandas
8 | from unittest import TestCase
9 |
10 | from .core import serialize, json_encode
11 |
12 | df = pandas.DataFrame([
13 | {'a': 1, 'b': 2, 'c': 3, 't': datetime.datetime(2015, 1, 1), 's': 's1'},
14 | {'a': 2, 'b': 4, 'c': 6, 't': datetime.datetime(2015, 1, 2), 's': 's2'}
15 | ])
16 |
17 |
18 | class CoreTest(TestCase):
19 | def test_type(self):
20 | self.assertEqual(type(serialize(df, render_to="chart")), str)
21 | obj = serialize(df, render_to="chart", output_type="dict")
22 | self.assertEqual(type(obj), dict)
23 | self.assertTrue('series' in obj)
24 | series = obj['series'][0]
25 | self.assertEqual(series['name'], 'a')
26 | self.assertTrue('data' in series)
27 | self.assertEqual(series['data'], [(0, 1), (1, 2)])
28 |
29 | obj = serialize(df, render_to="chart", output_type="dict", zoom="xy")
30 | self.assertTrue("chart" in obj)
31 | self.assertEqual(type(obj["chart"]), dict)
32 | self.assertTrue("zoomType" in obj["chart"])
33 | self.assertRaises(ValueError, serialize, df, **{"render_to": "chart", "zoom": "z"})
34 | obj = serialize(df, render_to="chart", output_type="dict", kind="bar")
35 | self.assertTrue("chart" in obj)
36 | self.assertEqual(type(obj["chart"]), dict)
37 | self.assertEqual(obj["chart"].get("type"), "column")
38 | self.assertRaises(ValueError, serialize, df, **{"render_to": "chart", "kind": "z"})
39 | obj = serialize(df, render_to="chart", output_type="dict", secondary_y="a")
40 | self.assertTrue(obj.get("yAxis", [])[1].get('opposite'))
41 | obj = serialize(df, render_to="chart", output_type="dict", rot=45, loglog=True)
42 | self.assertEqual(obj.get('xAxis', {}).get('labels'), {'rotation': 45})
43 | self.assertEqual(obj.get('yAxis', [])[0].get('labels'), {'rotation': 45})
44 | self.assertEqual(obj.get('xAxis', {}).get('type'), 'logarithmic')
45 | obj = serialize(df, render_to="chart", output_type="dict", x="t")
46 | self.assertEqual(obj.get('xAxis', {}).get('type'), 'datetime')
47 | obj = serialize(df, render_to="chart", output_type="dict", x="t", style={"a": ":"})
48 | for series in obj.get("series"):
49 | if series["name"] == "a":
50 | self.assertEqual(series.get("dashStyle"), "Dot")
51 | self.assertRaises(ValueError, serialize, df, **{"render_to": "chart", "style": {"a": "u"}})
52 | obj = serialize(df, render_to="chart", output_type="dict", kind="area", stacked=True)
53 | self.assertEqual(obj.get("series")[0].get("stacking"), "normal")
54 |
55 | obj = serialize(df, render_to="chart", output_type="dict", grid=True)
56 | self.assertEqual(obj.get('xAxis', {}).get('gridLineDashStyle'), 'Dot')
57 | self.assertEqual(obj.get('xAxis', {}).get('gridLineWidth'), 1)
58 | self.assertEqual(obj.get('yAxis', [])[0].get('gridLineDashStyle'), 'Dot')
59 | self.assertEqual(obj.get('yAxis', [])[0].get('gridLineWidth'), 1)
60 |
61 | obj = serialize(df, render_to="chart", output_type="dict", xlim=(0, 1), ylim=(0, 1))
62 | self.assertEqual(obj.get('xAxis', {}).get('min'), 0)
63 | self.assertEqual(obj.get('xAxis', {}).get('max'), 1)
64 | self.assertEqual(obj.get('yAxis', [])[0].get('min'), 0)
65 | self.assertEqual(obj.get('yAxis', [])[0].get('max'), 1)
66 |
67 | obj = serialize(df, render_to="chart", output_type="dict", fontsize=12, figsize=(4, 5))
68 | self.assertEqual(obj.get('xAxis', {}).get('labels', {}).get('style', {}).get('fontSize'), 12)
69 | self.assertEqual(obj.get('yAxis', [])[0].get('labels', {}).get('style', {}).get('fontSize'), 12)
70 |
71 | obj = serialize(df, render_to="chart", output_type="dict", title='Chart', xticks=[1], yticks=[2])
72 | self.assertTrue(obj.get('title', {}).get('text'))
73 | self.assertTrue(obj.get('xAxis', {}).get('tickPositions'))
74 | for yaxis in obj.get('yAxis', []):
75 | self.assertTrue(yaxis.get('tickPositions'))
76 |
77 | obj = serialize(df, render_to="chart", output_type="dict", fontsize=12, kind='pie', x='s', y=['a'], tooltip={'pointFormat': '{series.name}: {point.percentage:.1f}%'})
78 | self.assertTrue(obj.get('tooltip'))
79 |
80 | obj = serialize(df, render_to="chart", output_type="dict", polar=True, x='s', y=['a'])
81 | self.assertTrue(obj.get('chart', {}).get('polar'))
82 |
83 | df2 = pandas.DataFrame({'s': [2, 1]}, index=['b', 'a'])
84 | obj = serialize(df2, render_to='chart', output_type='dict', sort_columns=True)
85 | self.assertEqual(obj['series'], [{'data': [('a', 1), ('b', 2)], 'name': 's', 'yAxis': 0}])
86 | obj = serialize(df2, render_to='chart', output_type='dict')
87 | self.assertEqual(obj['series'], [{'data': [('b', 2), ('a', 1)], 'name': 's', 'yAxis': 0}])
88 |
89 | def test_json_output(self):
90 | json_output = serialize(df, output_type="json")
91 | self.assertEqual(type(json_output), str)
92 | decoded = json.loads(json_output)
93 | self.assertEqual(type(decoded), dict)
94 |
95 | def test_jsonencoder(self):
96 | self.assertEqual(json_encode(datetime.date(1970, 1, 1)), "0")
97 | self.assertEqual(json_encode(datetime.date(2015, 1, 1)), "1420070400000")
98 | self.assertEqual(json_encode(datetime.datetime(2015, 1, 1)), "1420070400000")
99 | self.assertEqual(json_encode(pandas.tslib.Timestamp(1420070400000000000)), "1420070400000")
100 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pandas
2 | ipython
3 | coverage
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from distutils.core import setup
4 | from setuptools import find_packages
5 |
6 | setup(
7 | name='pandas-highcharts',
8 | version='0.5.2',
9 | author='Guillaume Thomas',
10 | author_email='guillaume.thomas642@gmail.com',
11 | license='MIT',
12 | description='pandas-highcharts is a Python package which allows you to easily build Highcharts plots with pandas.DataFrame objects.',
13 | url='https://github.com/gtnx/pandas-highcharts',
14 | install_requires=[line.strip("\n") for line in open("requirements.txt", "r").readlines()],
15 | include_package_data=True,
16 | packages=find_packages(),
17 | )
18 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = py27,py34
3 |
4 | [testenv]
5 | deps = nose
6 | commands = nosetests --with-cover --cover-package pandas_highcharts pandas_highcharts
7 |
8 | [flake8]
9 | ignore = E501
10 |
--------------------------------------------------------------------------------