diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..a6b8dc8 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,6 @@ +include MANIFEST.in +include LICENSE + +graft tests + +global-exclude *.py[co] diff --git a/README.md b/README.md index 3a4aa28..c57b75b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# python-highcharts +# python-highcharts [![CircleCI](https://circleci.com/gh/kyper-data/python-highcharts.svg?style=svg)](https://circleci.com/gh/kyper-data/python-highcharts) ## License @@ -10,13 +10,16 @@ However, please be aware that the Highcharts project itself, as well as Highmaps python-highcharts is a simple translation layer between Python and Javascript for Highcharts projects (highcharts, highmaps, and highstocks). -In addition, python-highcharts integrates with [Jupyter/IPython notebook](https://github.com/jupyter/notebook), which enables you to render Highcharts, Highmaps, and Highstock visualizations directly in notebooks. See examples [here](https://github.com/kyper-data/python-highcharts/tree/developer/examples/ipynb). +In addition, python-highcharts integrates with [Jupyter notebook](https://github.com/jupyter/notebook), which enables you to render Highcharts, Highmaps, and Highstock visualizations directly in notebooks. See examples [here](https://github.com/kyper-data/python-highcharts/tree/developer/examples/ipynb). The original framework was inspired by [python-nvd3](https://github.com/areski/python-nvd3) and [PyHighcharts](https://github.com/fidyeates/PyHighcharts). ## Installation --need to work on this- +python-highcharts supports Python 2.7/3.4+ and is available on PyPI. To install: +``` +pip install python-highcharts +``` --------------------------------------------------------------------------------------------------------------- # Highcharts/Highstock @@ -193,6 +196,12 @@ chart.add_data_set(data, 'spline', 'Temperature', marker={'enabled': False}) chart ``` +### Example notebooks: + +* [Highcharts](http://nbviewer.ipython.org/github/kyper-data/python-highcharts/blob/master/examples/ipynb/highcharts/Example1.ipynb) +* [Highmaps](http://nbviewer.ipython.org/github/kyper-data/python-highcharts/blob/master/examples/ipynb/highmaps/Example1.ipynb) +* [Highstock](http://nbviewer.ipython.org/github/kyper-data/python-highcharts/blob/master/examples/ipynb/highstock/Example1-basic-line.ipynb) + ## Todo: * More charts support @@ -581,4 +590,4 @@ chart.save_file() * More examples * Clean code and put more explanation -Reference: [Highcharts API](http://api.highcharts.com/highcharts) \ No newline at end of file +Reference: [Highcharts API](http://api.highcharts.com/highcharts) diff --git a/examples/highcharts/heatmap.py b/examples/highcharts/heatmap.py new file mode 100644 index 0000000..338134b --- /dev/null +++ b/examples/highcharts/heatmap.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +""" +Highcharts Demos +Heatmap: http://www.highcharts.com/demo/heatmap +""" +from highcharts import Highchart +H = Highchart() + +data = [ + [0, 0, 10], + [0, 1, 19], + [0, 2, 8], + [0, 3, 24], + [0, 4, 67], + [1, 0, 92], + [1, 1, 58], + [1, 2, 78], + [1, 3, 117], + [1, 4, 48], + [2, 0, 35], + [2, 1, 15], + [2, 2, 123], + [2, 3, 64], + [2, 4, 52], + [3, 0, 72], + [3, 1, 132], + [3, 2, 114], + [3, 3, 19], + [3, 4, 16], + [4, 0, 38], + [4, 1, 5], + [4, 2, 8], + [4, 3, 117], + [4, 4, 115], + [5, 0, 88], + [5, 1, 32], + [5, 2, 12], + [5, 3, 6], + [5, 4, 120], + [6, 0, 13], + [6, 1, 44], + [6, 2, 88], + [6, 3, 98], + [6, 4, 96], + [7, 0, 31], + [7, 1, 1], + [7, 2, 82], + [7, 3, 32], + [7, 4, 30], + [8, 0, 85], + [8, 1, 97], + [8, 2, 123], + [8, 3, 64], + [8, 4, 84], + [9, 0, 47], + [9, 1, 114], + [9, 2, 31], + [9, 3, 48], + [9, 4, 91] +] + +H.add_data_set(data, ) + +H.set_options('chart', { + 'type': 'heatmap', + 'marginTop': 40, + 'marginBottom': 80, + 'plotBorderWidth': 1 +}) + +H.set_options('xAxis', { + 'categories': + ['Alexander', 'Marie', 'Maximilian', 'Sophia', 'Lukas', 'Maria', 'Leon', 'Anna', 'Tim', 'Laura'] +}) + +H.set_options('yAxis', { + 'categories': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + 'title': None +}) + +H.set_options('title', { + 'text': "Sales per employee per weekday" +}) + +H.set_options('colorAxis', { + 'min': 0, + 'minColor': '#FFFFFF', + 'maxColor': '#7CB5EC' +}) + +H.set_options('legend', { + 'align': 'right', + 'layout': 'vertical', + 'margin': 0, + 'verticalAlign': 'top', + 'y': 25, + 'symbolHeight': 280 +}) + +H.set_options('tooltip', { + 'formatter': "function () {" + + "return '' + this.series.xAxis.categories[this.point.x] + ' sold
' +" + + "this.point.value + ' items on
' + this.series.yAxis.categories[this.point.y] + '';" + + "}" +}) + +H.htmlcontent \ No newline at end of file diff --git a/examples/highcharts/spline-irregular-time.py b/examples/highcharts/spline-irregular-time.py new file mode 100644 index 0000000..7ad233f --- /dev/null +++ b/examples/highcharts/spline-irregular-time.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- +""" +Highcharts Demos +Time data with irregular intervals: http://www.highcharts.com/demo/spline-irregular-time +""" +from datetime import datetime +from highcharts import Highchart +H = Highchart() + +winter_12_13_data = [ + [datetime(1970, 10, 21), 0], + [datetime(1970, 11, 4), 0.28], + [datetime(1970, 11, 9), 0.25], + [datetime(1970, 11, 27), 0.2], + [datetime(1970, 12, 2), 0.28], + [datetime(1970, 12, 26), 0.28], + [datetime(1970, 12, 29), 0.47], + [datetime(1971, 1, 11), 0.79], + [datetime(1971, 1, 26), 0.72], + [datetime(1971, 2, 3), 1.02], + [datetime(1971, 2, 11), 1.12], + [datetime(1971, 2, 25), 1.2], + [datetime(1971, 3, 11), 1.18], + [datetime(1971, 4, 11), 1.19], + [datetime(1971, 5, 1), 1.85], + [datetime(1971, 5, 5), 2.22], + [datetime(1971, 5, 19), 1.15], + [datetime(1971, 6, 3), 0] +] + +winter_13_14_data = [ + [datetime(1970, 10, 29), 0], + [datetime(1970, 11, 9), 0.4], + [datetime(1970, 12, 1), 0.25], + [datetime(1971, 1, 1), 1.66], + [datetime(1971, 1, 10), 1.8], + [datetime(1971, 2, 19), 1.76], + [datetime(1971, 3, 25), 2.62], + [datetime(1971, 4, 19), 2.41], + [datetime(1971, 4, 30), 2.05], + [datetime(1971, 5, 14), 1.7], + [datetime(1971, 5, 24), 1.1], + [datetime(1971, 6, 10), 0] +] + +winter_14_15_data = [ + [datetime(1970, 11, 25), 0], + [datetime(1970, 12, 6), 0.25], + [datetime(1970, 12, 20), 1.41], + [datetime(1970, 12, 25), 1.64], + [datetime(1971, 1, 4), 1.6], + [datetime(1971, 1, 17), 2.55], + [datetime(1971, 1, 24), 2.62], + [datetime(1971, 2, 4), 2.5], + [datetime(1971, 2, 14), 2.42], + [datetime(1971, 3, 6), 2.74], + [datetime(1971, 3, 14), 2.62], + [datetime(1971, 3, 24), 2.6], + [datetime(1971, 4, 2), 2.81], + [datetime(1971, 4, 12), 2.63], + [datetime(1971, 4, 28), 2.77], + [datetime(1971, 5, 5), 2.68], + [datetime(1971, 5, 10), 2.56], + [datetime(1971, 5, 15), 2.39], + [datetime(1971, 5, 20), 2.3], + [datetime(1971, 6, 5), 2], + [datetime(1971, 6, 10), 1.85], + [datetime(1971, 6, 15), 1.49], + [datetime(1971, 6, 23), 1.08] +] + +H.add_data_set(winter_12_13_data, series_type="spline", name="Winter 2012-2013") +H.add_data_set(winter_13_14_data, series_type="spline", name="Winter 2013-2014") +H.add_data_set(winter_14_15_data, series_type="spline", name="Winter 2014-2015") + +H.set_options('chart', { + 'type': 'spline' +}) + +H.set_options('xAxis', { + 'type': 'datetime', + 'dateTimeLabelFormats': { # don't display the dummy year + 'month': '%e. %b', + 'year': '%b' + }, + 'title': { + 'text': 'Date' + } +}) + +H.set_options('yAxis', { + 'title': { + 'text': 'Snow depth (m)' + }, + 'min': 0 +}) + +H.set_options('title', { + 'text': "Snow depth at Vikjafjellet, Norway" +}) + +H.set_options('subtitle', { + 'text': "Irregular time data in Highcharts JS" +}) + +H.set_options('tooltip', { + 'headerFormat': '{series.name}
', + 'pointFormat': '{point.x:%e. %b}: {point.y:.2f} m' +}) + +H.set_options('plotOptions', { + 'spline': { + 'marker': { + 'enabled': True + } + } +}) + +H.htmlcontent \ No newline at end of file diff --git a/examples/ipynb/highcharts/3d-scatter-draggable.ipynb b/examples/ipynb/highcharts/3d-scatter-draggable.ipynb index 4f2c9de..cfd6205 100644 --- a/examples/ipynb/highcharts/3d-scatter-draggable.ipynb +++ b/examples/ipynb/highcharts/3d-scatter-draggable.ipynb @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 1, "metadata": { "collapsed": false, "scrolled": false @@ -21,7 +21,7 @@ { "data": { "text/html": [ - "" + "</html> \"height= 400 width =550>" ], "text/plain": [ - "" + "" ] }, - "execution_count": 8, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } diff --git a/examples/ipynb/highcharts/heatmap.ipynb b/examples/ipynb/highcharts/heatmap.ipynb new file mode 100644 index 0000000..9fd0880 --- /dev/null +++ b/examples/ipynb/highcharts/heatmap.ipynb @@ -0,0 +1,159 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# -*- coding: utf-8 -*-\n", + "\"\"\"\n", + "Highcharts Demos\n", + "Heatmap: http://www.highcharts.com/demo/heatmap\n", + "\"\"\"\n", + "from highcharts import Highchart\n", + "H = Highchart()\n", + "\n", + "data = [\n", + " [0, 0, 10],\n", + " [0, 1, 19],\n", + " [0, 2, 8],\n", + " [0, 3, 24],\n", + " [0, 4, 67],\n", + " [1, 0, 92],\n", + " [1, 1, 58],\n", + " [1, 2, 78],\n", + " [1, 3, 117],\n", + " [1, 4, 48],\n", + " [2, 0, 35],\n", + " [2, 1, 15],\n", + " [2, 2, 123],\n", + " [2, 3, 64],\n", + " [2, 4, 52],\n", + " [3, 0, 72],\n", + " [3, 1, 132],\n", + " [3, 2, 114],\n", + " [3, 3, 19],\n", + " [3, 4, 16],\n", + " [4, 0, 38],\n", + " [4, 1, 5],\n", + " [4, 2, 8],\n", + " [4, 3, 117],\n", + " [4, 4, 115],\n", + " [5, 0, 88],\n", + " [5, 1, 32],\n", + " [5, 2, 12],\n", + " [5, 3, 6],\n", + " [5, 4, 120],\n", + " [6, 0, 13],\n", + " [6, 1, 44],\n", + " [6, 2, 88],\n", + " [6, 3, 98],\n", + " [6, 4, 96],\n", + " [7, 0, 31],\n", + " [7, 1, 1],\n", + " [7, 2, 82],\n", + " [7, 3, 32],\n", + " [7, 4, 30],\n", + " [8, 0, 85],\n", + " [8, 1, 97],\n", + " [8, 2, 123],\n", + " [8, 3, 64],\n", + " [8, 4, 84],\n", + " [9, 0, 47],\n", + " [9, 1, 114],\n", + " [9, 2, 31],\n", + " [9, 3, 48],\n", + " [9, 4, 91]\n", + "]\n", + "\n", + "H.add_data_set(data, series_type='heatmap', borderWidth=1, dataLabels={\n", + " 'enabled': True,\n", + " 'color': '#000000'\n", + "})\n", + "\n", + "H.set_options('chart', {\n", + " 'type': 'heatmap',\n", + " 'marginTop': 40,\n", + " 'marginBottom': 80,\n", + " 'plotBorderWidth': 1\n", + "})\n", + "\n", + "H.set_options('xAxis', {\n", + " 'categories': \n", + " ['Alexander', 'Marie', 'Maximilian', 'Sophia', 'Lukas', 'Maria', 'Leon', 'Anna', 'Tim', 'Laura']\n", + "})\n", + "\n", + "H.set_options('yAxis', {\n", + " 'categories': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],\n", + " 'title': None\n", + "})\n", + "\n", + "H.set_options('title', {\n", + " 'text': \"Sales per employee per weekday\"\n", + "})\n", + "\n", + "H.set_options('colorAxis', {\n", + " 'min': 0,\n", + " 'minColor': '#FFFFFF',\n", + " 'maxColor': '#7CB5EC'\n", + "})\n", + "\n", + "H.set_options('legend', {\n", + " 'align': 'right',\n", + " 'layout': 'vertical',\n", + " 'margin': 0,\n", + " 'verticalAlign': 'top',\n", + " 'y': 25,\n", + " 'symbolHeight': 280\n", + "})\n", + "\n", + "H.set_options('tooltip', {\n", + " 'formatter': \"function () {\" + \n", + " \"return '' + this.series.xAxis.categories[this.point.x] + ' sold
' +\" +\n", + " \"this.point.value + ' items on
' + this.series.yAxis.categories[this.point.y] + '';\" +\n", + " \"}\"\n", + "})\n", + "\n", + "H" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/examples/ipynb/highcharts/spline-irregular-time.ipynb b/examples/ipynb/highcharts/spline-irregular-time.ipynb new file mode 100644 index 0000000..0b1139a --- /dev/null +++ b/examples/ipynb/highcharts/spline-irregular-time.ipynb @@ -0,0 +1,168 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# -*- coding: utf-8 -*-\n", + "\"\"\"\n", + "Highcharts Demos\n", + "Time data with irregular intervals: http://www.highcharts.com/demo/spline-irregular-time\n", + "\"\"\"\n", + "from datetime import datetime\n", + "from highcharts import Highchart\n", + "H = Highchart()\n", + "\n", + "winter_12_13_data = [\n", + " [datetime(1970, 10, 21), 0],\n", + " [datetime(1970, 11, 4), 0.28],\n", + " [datetime(1970, 11, 9), 0.25],\n", + " [datetime(1970, 11, 27), 0.2],\n", + " [datetime(1970, 12, 2), 0.28],\n", + " [datetime(1970, 12, 26), 0.28],\n", + " [datetime(1970, 12, 29), 0.47],\n", + " [datetime(1971, 1, 11), 0.79],\n", + " [datetime(1971, 1, 26), 0.72],\n", + " [datetime(1971, 2, 3), 1.02],\n", + " [datetime(1971, 2, 11), 1.12],\n", + " [datetime(1971, 2, 25), 1.2],\n", + " [datetime(1971, 3, 11), 1.18],\n", + " [datetime(1971, 4, 11), 1.19],\n", + " [datetime(1971, 5, 1), 1.85],\n", + " [datetime(1971, 5, 5), 2.22],\n", + " [datetime(1971, 5, 19), 1.15],\n", + " [datetime(1971, 6, 3), 0]\n", + "]\n", + "\n", + "winter_13_14_data = [\n", + " [datetime(1970, 10, 29), 0],\n", + " [datetime(1970, 11, 9), 0.4],\n", + " [datetime(1970, 12, 1), 0.25],\n", + " [datetime(1971, 1, 1), 1.66],\n", + " [datetime(1971, 1, 10), 1.8],\n", + " [datetime(1971, 2, 19), 1.76],\n", + " [datetime(1971, 3, 25), 2.62],\n", + " [datetime(1971, 4, 19), 2.41],\n", + " [datetime(1971, 4, 30), 2.05],\n", + " [datetime(1971, 5, 14), 1.7],\n", + " [datetime(1971, 5, 24), 1.1],\n", + " [datetime(1971, 6, 10), 0]\n", + "]\n", + "\n", + "winter_14_15_data = [\n", + " [datetime(1970, 11, 25), 0],\n", + " [datetime(1970, 12, 6), 0.25],\n", + " [datetime(1970, 12, 20), 1.41],\n", + " [datetime(1970, 12, 25), 1.64],\n", + " [datetime(1971, 1, 4), 1.6],\n", + " [datetime(1971, 1, 17), 2.55],\n", + " [datetime(1971, 1, 24), 2.62],\n", + " [datetime(1971, 2, 4), 2.5],\n", + " [datetime(1971, 2, 14), 2.42],\n", + " [datetime(1971, 3, 6), 2.74],\n", + " [datetime(1971, 3, 14), 2.62],\n", + " [datetime(1971, 3, 24), 2.6],\n", + " [datetime(1971, 4, 2), 2.81],\n", + " [datetime(1971, 4, 12), 2.63],\n", + " [datetime(1971, 4, 28), 2.77],\n", + " [datetime(1971, 5, 5), 2.68],\n", + " [datetime(1971, 5, 10), 2.56],\n", + " [datetime(1971, 5, 15), 2.39],\n", + " [datetime(1971, 5, 20), 2.3],\n", + " [datetime(1971, 6, 5), 2],\n", + " [datetime(1971, 6, 10), 1.85],\n", + " [datetime(1971, 6, 15), 1.49],\n", + " [datetime(1971, 6, 23), 1.08]\n", + "]\n", + "\n", + "H.add_data_set(winter_12_13_data, series_type=\"spline\", name=\"Winter 2012-2013\")\n", + "H.add_data_set(winter_13_14_data, series_type=\"spline\", name=\"Winter 2013-2014\")\n", + "H.add_data_set(winter_14_15_data, series_type=\"spline\", name=\"Winter 2014-2015\")\n", + "\n", + "H.set_options('chart', {\n", + " 'type': 'spline'\n", + "})\n", + "\n", + "H.set_options('xAxis', {\n", + " 'type': 'datetime',\n", + " 'dateTimeLabelFormats': { # don't display the dummy year\n", + " 'month': '%e. %b',\n", + " 'year': '%b'\n", + " },\n", + " 'title': {\n", + " 'text': 'Date'\n", + " }\n", + "})\n", + "\n", + "H.set_options('yAxis', {\n", + " 'title': {\n", + " 'text': 'Snow depth (m)'\n", + " },\n", + " 'min': 0\n", + "})\n", + "\n", + "H.set_options('title', {\n", + " 'text': \"Snow depth at Vikjafjellet, Norway\"\n", + "})\n", + "\n", + "H.set_options('subtitle', {\n", + " 'text': \"Irregular time data in Highcharts JS\"\n", + "})\n", + "\n", + "H.set_options('tooltip', {\n", + " 'headerFormat': '{series.name}
',\n", + " 'pointFormat': '{point.x:%e. %b}: {point.y:.2f} m'\n", + "})\n", + "\n", + "H.set_options('plotOptions', {\n", + " 'spline': {\n", + " 'marker': {\n", + " 'enabled': True\n", + " }\n", + " }\n", + "})\n", + "\n", + "H" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/highcharts/highcharts/common.py b/highcharts/highcharts/common.py index fe780ba..ab929fe 100644 --- a/highcharts/highcharts/common.py +++ b/highcharts/highcharts/common.py @@ -371,7 +371,7 @@ class Events(CommonObject): class Point(CommonObject): ALLOWED_OPTIONS = { - "events": Events + "events": (Events, dict) } class Position(CommonObject): @@ -568,6 +568,7 @@ class Hover(CommonObject): "marker": (Marker, dict), "radius": int, "radiusPlus": int, + "color": (ColorObject, basestring, dict), } class States(CommonObject): @@ -661,7 +662,7 @@ class PlotBands(ArrayObject): class PlotLines(ArrayObject): ALLOWED_OPTIONS = { "color": (ColorObject, basestring, dict), - "dashStyle": int, + "dashStyle": basestring, "events": (Events, dict), "id": basestring, "label": (Labels, dict), @@ -695,6 +696,14 @@ class Breaks(ArrayObject): "to": [int, float], } +class DataClasses(ArrayObject): + ALLOWED_OPTIONS = { + "color": (ColorObject, basestring, dict), + "from": [int, float], + "name": basestring, + "to": [int, float], + } + class Zones(ArrayObject): ALLOWED_OPTIONS = { "color": (ColorObject, basestring, dict), diff --git a/highcharts/highcharts/highchart_types.py b/highcharts/highcharts/highchart_types.py index 09817af..c8c241d 100644 --- a/highcharts/highcharts/highchart_types.py +++ b/highcharts/highcharts/highchart_types.py @@ -429,6 +429,7 @@ "cropThreshold": int, "dashStyle": basestring, "lineWidth": int, + "linkedTo": basestring, "marker": (Marker, dict), "pointInterval": int, "pointPlacement": [basestring, int, float], @@ -479,6 +480,7 @@ "selected": bool, "sliced": bool, "showInLegend": bool, + "stack": basestring, "type": basestring, "visible": bool, "x": [int, float], @@ -617,26 +619,27 @@ def __getattr__(self,item): class Series(object): """Series class for input data """ - def __init__(self,data,series_type="line",supress_errors=False,**kwargs): + def __init__(self, data, series_type="line", supress_errors=False, **kwargs): # List of dictionaries. Each dict contains data and properties, # which need to handle before construct the object for series - for item in data: - if isinstance(item, dict): - for k, v in item.items(): - if k in DATA_SERIES_ALLOWED_OPTIONS: - if SeriesOptions.__validate_options__(k,v,DATA_SERIES_ALLOWED_OPTIONS[k]): - if isinstance(DATA_SERIES_ALLOWED_OPTIONS[k], tuple): - if isinstance(v, dict): - item.update({k:DATA_SERIES_ALLOWED_OPTIONS[k][0](**v)}) - elif isinstance(v, CommonObject) or isinstance(v, ArrayObject) or \ - isinstance(v, CSSObject) or isinstance(v, SVGObject) or isinstance(v, ColorObject) or \ - isinstance(v, JSfunction) or isinstance(v, Formatter) or isinstance(v, datetime.datetime): - item.update({k:v}) + if isinstance(data, list): + for item in data: + if isinstance(item, dict): + for k, v in item.items(): + if k in DATA_SERIES_ALLOWED_OPTIONS: + if SeriesOptions.__validate_options__(k,v,DATA_SERIES_ALLOWED_OPTIONS[k]): + if isinstance(DATA_SERIES_ALLOWED_OPTIONS[k], tuple): + if isinstance(v, dict): + item.update({k:DATA_SERIES_ALLOWED_OPTIONS[k][0](**v)}) + elif isinstance(v, CommonObject) or isinstance(v, ArrayObject) or \ + isinstance(v, CSSObject) or isinstance(v, SVGObject) or isinstance(v, ColorObject) or \ + isinstance(v, JSfunction) or isinstance(v, Formatter) or isinstance(v, datetime.datetime): + item.update({k:v}) + else: + item.update({k:DATA_SERIES_ALLOWED_OPTIONS[k][0](v)}) else: - item.update({k:DATA_SERIES_ALLOWED_OPTIONS[k][0](v)}) - else: - item.update({k:v}) + item.update({k:v}) self.__dict__.update({ "data": data, diff --git a/highcharts/highcharts/highcharts.py b/highcharts/highcharts/highcharts.py index 86f38b1..59e093e 100644 --- a/highcharts/highcharts/highcharts.py +++ b/highcharts/highcharts/highcharts.py @@ -6,14 +6,14 @@ from past.builtins import basestring from jinja2 import Environment, PackageLoader -# import sys -# reload(sys) -# sys.setdefaultencoding("utf-8") import json, uuid -import datetime, random, os, inspect +import re +import datetime +import urllib.request, urllib.error, urllib.parse +import html from collections import Iterable -from .options import BaseOptions, ChartOptions, \ +from .options import BaseOptions, ChartOptions, ColorAxisOptions, \ ColorsOptions, CreditsOptions, DrilldownOptions, ExportingOptions, \ GlobalOptions, LabelsOptions, LangOptions, \ LegendOptions, LoadingOptions, NavigationOptions, PaneOptions, \ @@ -52,6 +52,9 @@ def __init__(self, **kwargs): This is the base class for all the charts. The following keywords are accepted: :keyword: **display_container** - default: ``True`` + **offline - default: ``False`` + If True, download all .js and .css file and put them + into the generated .html so it can be viewed offline. """ # set the model self.model = self.__class__.__name__ #: The chart model, @@ -60,13 +63,15 @@ def __init__(self, **kwargs): # an Instance of Jinja2 template self.template_page_highcharts = template_page self.template_content_highcharts = template_content + # set Javascript src, Highcharts lib needs to make sure it's up to date self.JSsource = [ - 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', - 'https://code.highcharts.com/highcharts.js', - 'https://code.highcharts.com/highcharts-more.js', - 'https://code.highcharts.com/modules/exporting.js' + 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', + 'https://code.highcharts.com/6/highcharts.js', + 'https://code.highcharts.com/6/highcharts-more.js', + 'https://code.highcharts.com/6/modules/heatmap.js', + 'https://code.highcharts.com/6/modules/exporting.js' ] # set CSS src @@ -74,16 +79,20 @@ def __init__(self, **kwargs): 'https://www.highcharts.com/highslide/highslide.css', ] + + self.offline = kwargs.get("offline", False) + # set data self.data = [] self.data_temp = [] # Data from jsonp self.jsonp_data_flag = False + self.jsonp_data_url_list = [] # DEM 2017/07/27: List of JSON data sources # set drilldown data self.drilldown_data = [] self.drilldown_data_temp = [] - + # javascript self.jscript_head_flag = False self.jscript_head = kwargs.get('jscript_head', None) @@ -110,6 +119,7 @@ def __init__(self, **kwargs): # Bind Base Classes to self self.options = { "chart": ChartOptions(), + #"colorAxis" : ColorAxisOptions(), "colors": ColorsOptions(), "credits": CreditsOptions(), #"data": #NotImplemented @@ -211,10 +221,10 @@ def add_drilldown_data_set(self, data, series_type, id, **kwargs): self.drilldown_data_set_count += 1 if self.drilldown_flag == False: self.drilldown_flag = True - + kwargs.update({'id':id}) series_data = Series(data, series_type=series_type, **kwargs) - + series_data.__options__().update(SeriesOptions(series_type=series_type, **kwargs).__options__()) self.drilldown_data_temp.append(series_data) @@ -224,12 +234,17 @@ def add_data_from_jsonp(self, data_src, data_name='json_data', series_type="line the data_src is the https link for data and it must be in jsonp format """ - self.jsonp_data_flag = True - self.jsonp_data_url = json.dumps(data_src) - if data_name == 'data': - data_name = 'json_'+ data_name - self.jsonp_data = data_name + if not self.jsonp_data_flag: + self.jsonp_data_flag = True + + if data_name == 'data': + data_name = 'json_'+ data_name + + self.jsonp_data = data_name self.add_data_set(RawJavaScriptText(data_name), series_type, name=name, **kwargs) + # DEM 2017/07/27: Append new JSON data source to a list instead of + # replacing whatever already exists + self.jsonp_data_url_list.append(json.dumps(data_src)) def add_JSscript(self, js_script, js_loc): @@ -264,10 +279,14 @@ def set_options(self, option_type, option_dict, force_options=False): self.options[option_type].update(**each_dict) elif option_type == 'colors': self.options["colors"].set_colors(option_dict) # option_dict should be a list - elif option_type == 'zAxis': self.options.update({'zAxis': zAxisOptions()}) self.options[option_type].update_dict(**option_dict) + elif option_type in ["global" , "lang"]: #Highcharts.setOptions: + self.setOptions[option_type].update_dict(**option_dict) + elif option_type == 'colorAxis': + self.options.update({'colorAxis': ColorAxisOptions()}) + self.options[option_type].update_dict(**option_dict) else: self.options[option_type].update_dict(**option_dict) @@ -292,9 +311,14 @@ def buildcontent(self): self.buildcontainer() self.option = json.dumps(self.options, cls = HighchartsEncoder) - self.setoption = json.dumps(self.setOptions, cls = HighchartsEncoder) + self.setoption = json.dumps(self.setOptions, cls = HighchartsEncoder) self.data = json.dumps(self.data_temp, cls = HighchartsEncoder) - + + # DEM 2017/04/25: Make 'data' available as an array + # ... this permits jinja2 array access to each data definition + # ... which is useful for looping over multiple data sources + self.data_list = [json.dumps(x, cls = HighchartsEncoder) for x in self.data_temp] + if self.drilldown_flag: self.drilldown_data = json.dumps(self.drilldown_data_temp, cls = HighchartsEncoder) self._htmlcontent = self.template_content_highcharts.render(chart=self).encode('utf-8') @@ -318,13 +342,27 @@ def buildhtmlheader(self): if self.drilldown_flag: self.add_JSsource('http://code.highcharts.com/modules/drilldown.js') - self.header_css = [ - '' % h for h in self.CSSsource - ] - self.header_js = [ - '' % h for h in self.JSsource - ] + + if self.offline: + opener = urllib.request.build_opener() + opener.addheaders = [('User-Agent', 'Mozilla/5.0')] + + self.header_css = [ + '' % opener.open(h).read() for h in self.CSSsource + ] + + self.header_js = [ + '' % opener.open(h).read() for h in self.JSsource + ] + else: + self.header_css = [ + '' % h for h in self.CSSsource + ] + + self.header_js = [ + '' % h for h in self.JSsource + ] self.htmlheader = '' for css in self.header_css: @@ -357,6 +395,24 @@ def buildcontainer(self): def htmlcontent(self): return self.buildhtml() + @property + def iframe(self): + htmlsrcdoc = html.escape(self.htmlcontent) + htmlsrcdoc = re.sub('\\n', ' ', htmlsrcdoc) + htmlsrcdoc = re.sub(' +', ' ', htmlsrcdoc) + width = int(self.options['chart'].__dict__['width']) if self.options['chart'].__dict__.get('width') else 820 + height = int(self.options['chart'].__dict__['height']) if self.options['chart'].__dict__.get('height') else 520 + + if self.options['chart'].__dict__.get('options3d'): + if len(htmlsrcdoc) < 99965000 : + return '' + else: + return '' + else: + return '' + + def __str__(self): """return htmlcontent""" #self.buildhtml() diff --git a/highcharts/highcharts/options.py b/highcharts/highcharts/options.py index 85e7689..d91b827 100644 --- a/highcharts/highcharts/options.py +++ b/highcharts/highcharts/options.py @@ -4,7 +4,7 @@ from .highchart_types import OptionTypeError, Series, SeriesOptions from .common import Formatter, Events, Position, ContextButton, Options3d, ResetZoomButton, \ DrillUpButton, Labels, PlotBands, PlotLines, Title, Items, Navigation, Background, Breaks, \ - DateTimeLabelFormats, Zones, Levels, \ + DataClasses, DateTimeLabelFormats, Zones, Levels, Marker, \ JSfunction, ColorObject, CSSObject, SVGObject, CommonObject, ArrayObject import json, datetime @@ -153,6 +153,52 @@ class ChartOptions(BaseOptions): } +class ColorAxisOptions(BaseOptions): + ALLOWED_OPTIONS = { + "dataClassColor": basestring, + "dataClasses": (DataClasses, dict), + "endOnTick": bool, + "events": (Events, dict), + "gridLineColor": (ColorObject, basestring, dict), + "gridLineDashStyle": basestring, + "gridLineWidth": [float, int], + "id": basestring, + "labels": (Labels, dict), + "lineColor": (ColorObject, basestring, dict), + "lineWidth": [float, int], + "marker": (Marker, dict), + "max": [float, int], + "maxColor": (ColorObject, basestring, dict), + "maxPadding": [float, int], + "min": [float, int], + "minColor": (ColorObject, basestring, dict), + "minPadding": [float, int], + "minorGridLineColor": (ColorObject, basestring, dict), + "minorGridLineDashStyle": basestring, + "minorGridLineWidth": int, + "minorTickColor": (ColorObject, basestring, dict), + "minorTickInterval": int, + "minorTickLength": int, + "minorTickPosition": basestring, + "minorTickWidth": int, + "reversed": bool, + "showFirstLabel": bool, + "showLastLabel": bool, + "startOfWeek": int, + "startOnTick": bool, + "stops": list, + "tickColor": (ColorObject, basestring, dict), + "tickInterval": int, + "tickLength": int, + "tickPixelInterval": int, + "tickPosition": basestring, + "tickPositioner": JSfunction, + "tickPositions": list, + "tickWidth": int, + "type": basestring, +} + + class ColorsOptions(BaseOptions): """ Special Case, this is simply just an array of colours """ def __init__(self): @@ -389,6 +435,7 @@ class TooltipOptions(BaseOptions): "formatter": (Formatter, JSfunction), "headerFormat": basestring, "pointFormat": basestring, + "pointFormatter": (Formatter, JSfunction), "positioner": (JSfunction, basestring), "shadow": bool, "shared": bool, diff --git a/highcharts/highcharts/templates/content.html b/highcharts/highcharts/templates/content.html index 64e3e86..b92181e 100644 --- a/highcharts/highcharts/templates/content.html +++ b/highcharts/highcharts/templates/content.html @@ -5,19 +5,14 @@ {% block body_head %} - {% if chart.jsonp_data_flag %} - $.getJSON({{chart.jsonp_data_url}}, function ({{chart.jsonp_data}}) - { - {% endif %} + {% if chart.jscript_head_flag %} + {{chart.jscript_head}} + {% endif %} {% endblock body_head %} {% block body_content %} - {% if chart.jscript_head_flag %} - {{chart.jscript_head}} - {% endif %} - Highcharts.setOptions({{chart.setoption}}); var option = {{chart.option}}; @@ -25,9 +20,6 @@ var geojson = {{chart.mapdata}} {% endif %} - var data = {{chart.data}}; - option.series = data; - {% if chart.drilldown_flag %} var drilldowndata = {{chart.drilldown_data}}; option.drilldown.series = drilldowndata; @@ -35,6 +27,26 @@ var chart = new Highcharts.Chart(option); + {# DEM 2017/07/27: Use a list of JSONP data sources + {# DEM 2017/07/27: This implementation is limited and could easily be improved! #} + {% if chart.jsonp_data_flag %} + {% for data_url in chart.jsonp_data_url_list %} + + $.getJSON({{data_url}}, function ({{chart.jsonp_data}}) + { + chart.addSeries({{chart.data_list[loop.index0]}}); + }); + + {% endfor %} + {% else %} + var data = {{chart.data}}; + var dataLen = data.length; + for (var ix = 0; ix < dataLen; ix++) { + chart.addSeries(data[ix]); + } + {% endif %} + + {% if chart.jscript_end_flag %} {{chart.jscript_end}} {% endif %} @@ -73,8 +85,4 @@ {% block body_end %} - {% if chart.jsonp_data_flag %} - }); - {% endif %} - -{% endblock body_end %} \ No newline at end of file +{% endblock body_end %} diff --git a/highcharts/highmaps/highmaps.py b/highcharts/highmaps/highmaps.py index 0fc67f3..0d73afc 100644 --- a/highcharts/highmaps/highmaps.py +++ b/highcharts/highmaps/highmaps.py @@ -6,12 +6,13 @@ from past.builtins import basestring -from optparse import OptionParser from urllib.request import urlopen from jinja2 import Environment, PackageLoader import json, uuid -import datetime, random, os, inspect +import re +import datetime +import html from collections import Iterable from .options import BaseOptions, ChartOptions, \ ColorsOptions, ColorAxisOptions, CreditsOptions, DrilldownOptions, ExportingOptions, \ @@ -64,12 +65,12 @@ def __init__(self, **kwargs): # Set Javascript src self.JSsource = [ - 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', - 'https://code.highcharts.com/maps/highmaps.js', - 'https://code.highcharts.com/highcharts.js', - 'https://code.highcharts.com/maps/modules/map.js', - 'https://code.highcharts.com/maps/modules/data.js', - 'https://code.highcharts.com/maps/modules/exporting.js' + 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', + 'https://code.highcharts.com/maps/6/highmaps.js', + 'https://code.highcharts.com/6/highcharts.js', + 'https://code.highcharts.com/maps/6/modules/map.js', + 'https://code.highcharts.com/maps/6/modules/data.js', + 'https://code.highcharts.com/maps/6/modules/exporting.js' ] # set CSS src @@ -327,6 +328,8 @@ def set_options(self, option_type, option_dict, force_options=False): elif option_type == 'colorAxis': self.options.update({'colorAxis': self.options.get('colorAxis', ColorAxisOptions())}) self.options[option_type].update_dict(**option_dict) + elif option_type in ["global" , "lang"]: + self.setOptions[option_type].update_dict(**option_dict) else: self.options[option_type].update_dict(**option_dict) @@ -369,7 +372,7 @@ def buildhtml(self): self.buildcontent() self.buildhtmlheader() self.content = self._htmlcontent.decode('utf-8') # need to ensure unicode - self._htmlcontent = self.template_page_highcharts.render(chart=self).encode('utf-8') + self._htmlcontent = self.template_page_highcharts.render(chart=self) return self._htmlcontent def buildhtmlheader(self): @@ -418,6 +421,23 @@ def buildcontainer(self): def htmlcontent(self): return self.buildhtml() + @property + def iframe(self): + htmlsrcdoc = html.escape(self.htmlcontent) + htmlsrcdoc = re.sub('\\n', ' ', htmlsrcdoc) + htmlsrcdoc = re.sub(' +', ' ', htmlsrcdoc) + width = int(self.options['chart'].__dict__['width']) if self.options['chart'].__dict__.get('width') else 820 + height = int(self.options['chart'].__dict__['height']) if self.options['chart'].__dict__.get('height') else 520 + + if self.options['chart'].__dict__.get('options3d'): + if len(htmlsrcdoc) < 99965000 : + return '' + else: + return '' + else: + return '' + def __str__(self): """return htmlcontent""" #self.buildhtml() diff --git a/highcharts/highstock/highstock.py b/highcharts/highstock/highstock.py index 624c9fb..ef8610d 100644 --- a/highcharts/highstock/highstock.py +++ b/highcharts/highstock/highstock.py @@ -4,11 +4,12 @@ from future.standard_library import install_aliases install_aliases() -from optparse import OptionParser from jinja2 import Environment, PackageLoader import json, uuid -import datetime, random, os, inspect +import re +import datetime +import html from collections import Iterable from .options import BaseOptions, ChartOptions, \ ColorsOptions, CreditsOptions, ExportingOptions, \ @@ -60,10 +61,10 @@ def __init__(self, **kwargs): # set Javascript src, Highcharts lib needs to make sure it's up to date self.JSsource = [ - 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', - 'https://code.highcharts.com/stock/highstock.js', - 'https://code.highcharts.com/stock/modules/exporting.js', - 'https://code.highcharts.com/highcharts-more.js', + 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', + 'https://code.highcharts.com/stock/6/highstock.js', + 'https://code.highcharts.com/stock/6/modules/exporting.js', + 'https://code.highcharts.com/6/highcharts-more.js', ] # set CSS src @@ -82,6 +83,7 @@ def __init__(self, **kwargs): # Data from jsonp self.jsonp_data_flag = False + self.jsonp_data_url_list = [] # DEM 2017/04/25: List of JSON data sources # javascript self.jscript_head_flag = False @@ -205,13 +207,15 @@ def add_data_from_jsonp(self, data_src, data_name='json_data', series_type="line """ if not self.jsonp_data_flag: self.jsonp_data_flag = True - self.jsonp_data_url = json.dumps(data_src) if data_name == 'data': data_name = 'json_'+ data_name self.jsonp_data = data_name self.add_data_set(RawJavaScriptText(self.jsonp_data), series_type, name=name, **kwargs) + # DEM 2017/04/25: Append new JSON data source to a list instead of + # replacing whatever already exists + self.jsonp_data_url_list.append(json.dumps(data_src)) def add_navi_series(self, data, series_type="line", **kwargs): @@ -269,6 +273,8 @@ def set_options(self, option_type, option_dict, force_options=False): self.options[option_type].update(**each_dict) elif option_type == 'colors': self.options["colors"].set_colors(option_dict) # option_dict should be a list + elif option_type in ["global" , "lang"]: #Highcharts.setOptions: + self.setOptions[option_type].update_dict(**option_dict) else: self.options[option_type].update_dict(**option_dict) @@ -291,6 +297,11 @@ def buildcontent(self): self.option = json.dumps(self.options, cls = HighchartsEncoder) self.setoption = json.dumps(self.setOptions, cls = HighchartsEncoder) self.data = json.dumps(self.data_temp, cls = HighchartsEncoder) + + # DEM 2017/04/25: Make 'data' available as an array + # ... this permits jinja2 array access to each data definition + # ... which is useful for looping over multiple data sources + self.data_list = [json.dumps(x, cls = HighchartsEncoder) for x in self.data_temp] if self.navi_seri_flag: self.navi_seri = json.dumps(self.navi_seri_temp, cls = HighchartsEncoder) @@ -306,7 +317,7 @@ def buildhtml(self): self.buildcontent() self.buildhtmlheader() self.content = self._htmlcontent.decode('utf-8') # need to ensure unicode - self._htmlcontent = self.template_page_highcharts.render(chart=self).encode('utf-8') + self._htmlcontent = self.template_page_highcharts.render(chart=self) return self._htmlcontent @@ -352,6 +363,23 @@ def buildcontainer(self): def htmlcontent(self): return self.buildhtml() + @property + def iframe(self): + htmlsrcdoc = html.escape(self.htmlcontent) + htmlsrcdoc = re.sub('\\n', ' ', htmlsrcdoc) + htmlsrcdoc = re.sub(' +', ' ', htmlsrcdoc) + width = int(self.options['chart'].__dict__['width']) if self.options['chart'].__dict__.get('width') else 820 + height = int(self.options['chart'].__dict__['height']) if self.options['chart'].__dict__.get('height') else 520 + + if self.options['chart'].__dict__.get('options3d'): + if len(htmlsrcdoc) < 99965000 : + return '' + else: + return '' + else: + return '' + def __str__(self): """return htmlcontent""" #self.buildhtml() diff --git a/highcharts/highstock/options.py b/highcharts/highstock/options.py index 18fa235..4a21318 100644 --- a/highcharts/highstock/options.py +++ b/highcharts/highstock/options.py @@ -301,6 +301,7 @@ class PlotOptions(BaseOptions): "arearange": (SeriesOptions, dict), "areaspline": (SeriesOptions, dict), "areasplinerange": (SeriesOptions, dict), + "candlestick": (SeriesOptions, dict), "column": (SeriesOptions, dict), "columnrange": (SeriesOptions, dict), "flags": (SeriesOptions, dict), @@ -541,6 +542,11 @@ class yAxisOptions(BaseOptions): "tickmarkPlacement": basestring, "title": (Title, dict), "top": [int, float, basestring], + # DEM 2017/11/16: Note that the 'type' keyword for highstock is + # undocumented yet appears to be supported, likely because of underlying + # shared code. This permits logarithmic Y-Axis scale which is + # frequently useful in stock charts. + "type": basestring, "units": list } diff --git a/highcharts/highstock/templates/content.html b/highcharts/highstock/templates/content.html index 4eade17..54615ba 100644 --- a/highcharts/highstock/templates/content.html +++ b/highcharts/highstock/templates/content.html @@ -5,25 +5,17 @@ {% block body_head %} - {% if chart.jsonp_data_flag %} - $.getJSON({{chart.jsonp_data_url}}, function ({{chart.jsonp_data}}) - { - {% endif %} + {% if chart.jscript_head_flag %} + {{chart.jscript_head}} + {% endif %} {% endblock body_head %} {% block body_content %} - {% if chart.jscript_head_flag %} - {{chart.jscript_head}} - {% endif %} - Highcharts.setOptions({{chart.setoption}}); var option = {{chart.option}}; - var data = {{chart.data}}; - option.series = data; - {% if chart.navi_seri_flag %} var navi_data = {{chart.navi_seri}} option.navigator.series = navi_data; @@ -31,16 +23,34 @@ var chart = new Highcharts.StockChart(option); - {% if chart.jscript_end_flag %} - {{chart.jscript_end}} - {% endif %} + + {# DEM 2017/04/25: Use a list of JSONP data sources + {# DEM 2017/07/27: This implementation is limited and could easily be improved! #} + {% if chart.jsonp_data_flag %} + {% for data_url in chart.jsonp_data_url_list %} + + $.getJSON({{data_url}}, function ({{chart.jsonp_data}}) + { + chart.addSeries({{chart.data_list[loop.index0]}}); + }); + + {% endfor %} + {% else %} + + var data = {{chart.data}}; + var dataLen = data.length; + for (var ix = 0; ix < dataLen; ix++) { + chart.addSeries(data[ix]); + } + + {% endif %} {% endblock body_content %} {% block body_end %} - {% if chart.jsonp_data_flag %} - }); - {% endif %} + {% if chart.jscript_end_flag %} + {{chart.jscript_end}} + {% endif %} -{% endblock body_end %} \ No newline at end of file +{% endblock body_end %} diff --git a/highcharts/highstock/templates/page.html b/highcharts/highstock/templates/page.html index 3559aaa..dd722fe 100644 --- a/highcharts/highstock/templates/page.html +++ b/highcharts/highstock/templates/page.html @@ -8,5 +8,6 @@ {{ chart.content }} + {{ chart.other }} diff --git a/highcharts/ipynb.py b/highcharts/ipynb.py index 69a6cb4..20b4e3a 100644 --- a/highcharts/ipynb.py +++ b/highcharts/ipynb.py @@ -10,27 +10,14 @@ _ip = get_ipython() except: _ip = None -if _ip and _ip.__module__.startswith('IPython'): +if _ip and (_ip.__module__.startswith('IPython') or _ip.__module__.startswith('ipykernel')): def _print_html(chart): '''Function to return the HTML code for the div container plus the javascript to generate the chart. This function is bound to the ipython formatter so that charts are displayed inline.''' - import html - htmlsrcdoc = html.escape(chart.htmlcontent) - width = int(chart.options['chart'].__dict__['width']) if chart.options['chart'].__dict__.get('width') else 820 - height = int(chart.options['chart'].__dict__['height']) if chart.options['chart'].__dict__.get('height') else 520 - - if chart.options['chart'].__dict__.get('options3d'): - if len(htmlsrcdoc) < 99965000 : - return '' - else: - return '' - else: - return '' - + return chart.iframe def _setup_ipython_formatter(ip): ''' Set up the ipython formatter to display HTML formatted output inline''' @@ -45,4 +32,4 @@ def _setup_ipython_formatter(ip): for chart_type in [Highchart, Highmap, Highstock]: html_formatter.for_type(chart_type, _print_html) - _setup_ipython_formatter(_ip) \ No newline at end of file + _setup_ipython_formatter(_ip) diff --git a/highcharts/version.py b/highcharts/version.py index c1ced06..c8472d3 100644 --- a/highcharts/version.py +++ b/highcharts/version.py @@ -1,7 +1,7 @@ version_info = ( "0", - "1", - "0" + "4", + "2" ) __version__ = '.'.join(map(str, version_info)) diff --git a/tests/test_highcharts.py b/tests/test_highcharts.py index 6d6628c..bef8136 100644 --- a/tests/test_highcharts.py +++ b/tests/test_highcharts.py @@ -56,6 +56,9 @@ def test_Example1(self): execfile(os.path.join(self.PATH_ROOT, 'Example1.py')) os.remove("highcharts.html") + def test_error_bar(self): + execfile(os.path.join(self.PATH_ROOT, 'heatmap.py')) + def test_line_time_series(self): execfile(os.path.join(self.PATH_ROOT, 'line-time-series.py')) @@ -77,9 +80,12 @@ def test_scatter(self): def test_spline_inverted(self): execfile(os.path.join(self.PATH_ROOT, 'spline-inverted.py')) + def test_spline_irregular_time(self): + execfile(os.path.join(self.PATH_ROOT, 'spline-irregular-time.py')) + def test_spline_symbols(self): execfile(os.path.join(self.PATH_ROOT, 'spline-symbols.py')) def test_treemap_levels(self): execfile(os.path.join(self.PATH_ROOT, 'treemap-levels.py')) - \ No newline at end of file +