First step

In this tutorial we will use Brython, an implementation of Python written in javascript and Python, to access the Highcharts javascript library and to manage the data to be used in the maps. To integrate Brython in the IPython notebook we are using an extension for the notebook called brythonmagic that provides a new magic cell, **%%brython**, that allow us to write and execute Brython code in the notebook.

Installation of the brythonmagic IPython extension

As stated before, we will use Brython, and brythonmagic so first of all we need to load the extension and the Brython library.

So, let's load the extension:


In [ ]:
%load_ext brythonmagic

And the brython js lib:


In [ ]:
from brythonmagic import load_brython_dev
load_brython_dev()

[It is highly recommended that, at least, you read the brythonmagic docs to understand what it does. It is also recommended to have a quick look at the Brython docs].

Warning

In order to load javascript libraries in a safety way you should try to use https instead of http when possible (read more here). If you don't trust the source and/or the source cannot be loaded using https then you could download the javascript library and load it from a local location.

Conventions used in the following tutorial.

In the following tutorial I will try to follow several conventions to try to make it more readable.

Code in cells that are not code cells:

  • a block of code will appear as follows:
# This is a block of code
print("Hello world!")
  • Python/Brython code commented in a line of text will appear as follows, **this is a piece of Python/Brython code inline with the text**
  • Javascript code commented in a line of text will appear as follows, **this is a piece of javascript code inline with the text**
  • Most of new code used in a code cell will be commented in a paragraph starting with **[NEW CODE]**
  • When the Python and the javascript code is not exactly the same I will try to comment how the code would be in javascript.

What is Highcharts?

Highcharts is an open source, client side JavaScript library for making interactive charts, viewable in nearly any modern web browser. Since it is a client side library, it requires no special server side software or settings — you can use it without even downloading anything!

This tutorial just try to explain a little bit what can be found in the official documentation and try to introduce this library to Python users.

The website for Highcharts is located at http://www.highcharts.com/. To begin, we need to download a copy of Highcharts (or, we can directly link to the library — this is what we will do in the present tutorial). You can download the compressed library as a .zip file.

So, before continuing let's load the Highcharts library.


In [ ]:
from brythonmagic import load_js_lib
load_js_lib("https://cdnjs.cloudflare.com/ajax/libs/highcharts/5.0.7/highcharts.js")

First example: A simple line chart

First we create some simple HTML code. This HTML code will contain our chart. We will not use complicated HTML code during the tutorial to keep it simple and to be focused in 'How to create interactive charts in the browser with Python'. There is a lot of amazing resources to learn about HTML and CSS.


In [ ]:
html = """<div id="hc_ex1" style="width: 700px; height: 300px;"></div>"""

Now the interesting part. To make Highcharts available to Brython we need to 'load' the Highchart object/namespace to Brython using **Highcharts = window.Highcharts**. We will use the **new** method injected by Brython to the Javascript object that would behave similarly as if we were using Javascript constructors, (ie functions used with the Javascript keyword **new**).

The code is as follows:


In [ ]:
%%brython -h html -p
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

config = {
    'chart':{
        'renderTo': 'hc_ex1'
    },
    'title': {
        'text': 'Monthly Average Temperature',
        'x': -20 #center
    },
    'subtitle': {
        'text': 'Source: WorldClimate.com',
        'x': -20
    },
    'xAxis': {
        'categories': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
            'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
    },
    'yAxis': {
        'title': {
            'text': 'Temperature (°C)'
        },
        'plotLines': [{
            'value': 0,
            'width': 1,
            'color': '#808080'
        }]
    },
    'tooltip': {
        'valueSuffix': '°C'
    },
    'legend': {
        'layout': 'vertical',
        'align': 'right',
        'verticalAlign': 'middle',
        'borderWidth': 0
    },
    'series': [{
        'name': 'Tokyo',
        'data': [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
    }]
}

hc(config)

Pretty simple!!

Ok, let's dissect the code in the Brython cell above.

**%%brython -h html -p** :

  • Indicates that the code cell is written using Brython and we use some options for the Brython code cell, -h to use the HTML code defined in the html variable located in the cell above and -p to print the final HTML code generated below the generated chart. In this example, the generated code should be something like the following:
<script id="66406" type="text/python">
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

config = {
    'chart':{
        'renderTo': 'hc_ex1'
    },
    'title': {
        'text': 'Monthly Average Temperature',
        'x': -20 #center
    },
    'subtitle': {
        'text': 'Source: WorldClimate.com',
        'x': -20
    },
    'xAxis': {
        'categories': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
            'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
    },
    'yAxis': {
        'title': {
            'text': 'Temperature (°C)'
        },
        'plotLines': [{
            'value': 0,
            'width': 1,
            'color': '#808080'
        }]
    },
    'tooltip': {
        'valueSuffix': '°C'
    },
    'legend': {
        'layout': 'vertical',
        'align': 'right',
        'verticalAlign': 'middle',
        'borderWidth': 0
    },
    'series': [{
        'name': 'Tokyo',
        'data': [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
    }]
}

hc(config)
  </script>
  <div id="brython_container_66406"><div id="hc_ex1" style="width: 700px; height: 300px;"></div></div>
  <script type="text/javascript">brython({debug:1, static_stdlib_import: false, ipy_id: ["66406"]});</script>

the -p option only provides information and it isn't required to run the Brython code cell.

**hc = Highcharts.Chart.new**

  • Here we are instantiating the chart, i.e., accessing the function to the Brython namespace.

**config = { ... }**

  • Here we are defining the options and data to be used in the chart. More on this later.

**hc(config))**

  • We call the hc function with the data and configuration options defined in the config dict.

Configuring Highcharts

We can configure how the chart will be shown, layout, dimensions, axis, titles, legends,... All this information can be managed on each plot or using a configuration object (in javascript or dictionary in Python).

In the previous example we have seen the config dict. Let's dedicate some time to understand it. The config dict contains a series of dicts and each of these dicts manage several pieces of the chart:

  • chart dict (complete api): It contains information related with how the chart is presented (background colors, area plot colors, type of chart to be used, where the chart should be rendered (html element), margins and spacings,...). A more complete example would be something like the following:
'chart': {
    'renderTo': 'The_id_of_the_html_element',
    'backgroundColor': 'a_valid_html_object',
    'type': 'spline',
    'plotBorderWidth': 1,
    'plotBorderColor': '#3F4044',
    ...
}
  • colors key: The value is a list of strings containing valid html colors. The default colors in the latest highcharts version are:
'colors': ['#7cb5ec', '#434348', '#90ed7d', '#f7a35c', '#8085e9', 
           '#f15c80', '#e4d354', '#8085e8', '#8d4653', '#91e8e1']
  • credits dict (complete api): This dict allows you to control the credits label in the chart. By default will be shown the credits in the bottom left area of the chart. To control the credits you can use the following:
'credits': {
    'enabled': Boolean,
    'href': String,
    'text': String,
    ...
}
  • legend dict (complete api): This dict allows you to control how the legend is shown:
'legend': {
    'enabled': Boolean,
    'align': String,
    'backgroundColor': String,
    ...
}
  • plotOptions dict (complete api): The plotOptions dict is a wrapper object for config objects for each series type. The config objects for each series can also be overridden for each series item as given in the series array. Configuration options for the series are given in three levels. Options for all series in a chart are given in the plotOptions['series'] dict. Then options for all series of a specific type are given in the plotOptions of that type, for example plotOptions[line]. Next, options for one single series are given in the specific series array:
'plotOptions': {
    'enabled': Boolean,
    'align': String,
    'backgroundColor': String,
    ...
}
  • title and subtitle dicts (complete api for title and for subtitle): this options controls the appeareance of the title and subtitle of the chart. The keys are almost similar for both options:
'title': {
    'align': String,
    'text': String,
    ...
}
  • tooltip dict (complete api): Options for the tooltip that appears when the user hovers over a series or point:
'tooltip': {
    'enabled': Boolean,
    'backgroundColor': 'a_valid_html_color',
    'borderColor': 'a_valid_html_color',
    ...
}
  • xAxis and yAxis dicts (complete api for xAxis and for yAxis): The x axis or category axis and the y axis or the value axis. Normally, xAxis is the horizontal axis and yAxis the vertical axis except if the chart is inverted. The keys are pretty similar for both options:
'xAxis': {
    'min': float or int,
    'max': float or int,
    'title': {a dict with options},
    'lineColor': 'A_valid_html_color',
    ...
}
  • series dict (complete api): The actual series to append to the chart. In addition to the possible options, any member of the plotOptions for that specific type of plot can be added to a series individually. For example, even though a general lineWidth is specified in plotOptions['series'], an individual lineWidth can be specified for each series:

    • data list: It is a list that can be one of the following options (we will come back to this later):

      1. An array of numerical values. In this case, the numerical values will be interpreted as y values, and x values will be automatically calculated, either starting at 0 and incrementing by 1, or from pointStart and pointInterval given in the plotOptions dict. If the axis has categories, these will be used. This option is not available for range series.

      2. An array of arrays with two values. In this case, the first value is the x value and the second is the y value. If the first value is a string, it is applied as the name of the point, and the x value is incremented following the above rules. For range series, the arrays will be interpreted as [x, low, high]. In this cases, the x value can be skipped altogether to make use of pointStart and pointRange.

      3. An array of objects with named values. In this case the objects are point configuration objects. Range series values are given by low and high.

'series': {
    'data': [* see above],
    'name': String,
    'type': String,
    ...
}

Let's see a more complete (and ugly) example using several configuration options:


In [ ]:
html = """<div id="hc_ex2" style="width: 700px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

config = {
    'chart': {
        'renderTo': 'hc_ex2',
        'backgroundColor': {
            'linearGradient': [0, 0, 500, 500],
            'stops': [[0, 'rgb(255, 255, 255)'],
                      [1, 'rgb(200, 200, 255)']]
        },
        'borderRadius': 10
    },
    'title': {
        'align': 'left',
        'text': 'My dummy title',
        'style': { "color": "green", "fontSize": "20px" }
    },
    'subtitle': {
        'align': 'right',
        'text': 'Ugly subtitle',
        'style': { "color": "orange", "fontSize": "12px" }
    },
    'legend': {
        'backgroundColor': 'green',
        'borderColor': 'yellow',
        'borderRadius': 10,
        'borderWidth': 3,
    },
    'series': [{
        'data': [1,2,3,4],
        'type': 'line',
        'name': 'Name of the series',
        'color': 'orange',
    }],
    'tooltip': {
        'backgroundColor': 'gray',
        'borderColor': 'yellow',
        'borderRadius': 10,
        'borderWidth': 3,
    },
    'xAxis': {
        'categories': ['data'] * 4,
        'lineWidth': 5,
        'lineColor': 'violet',
        'gridLineColor': 'violet',
        'gridLineWidth': 3,
        'title': {'text': 'X axis title'}
    },
    'yAxis': {
        'lineWidth': 5,
        'lineColor': 'blue',
        'gridLineColor': 'blue',
        'gridLineWidth': 3,
        'title': {'text': 'Y axis title'}
    },
    'credits': {
        'text': "Pybonacci rules!",
        'href': 'https://twitter.com/pybonacci'
    }
}

hc(config)

I got it!!! It's the ugliest chart in the world!!!

Defining options for all the charts

If we want we can define some of the options to be used during a complete session so we don't have to define each of the options when defining a new chart.

We will use **Highcharts.setOptions** to create a set of options that could be overwritten on each individual chart if necessary. You can learn more about how to create themes for highcharts here.

In general, I don't like some default values for Highcharts and as Randall Olson has said, sometimes less is more. Also, as I have some degree of color blindness I will use the 'color blind 10' palette of colors from Tableau.


In [ ]:
%%brython -s globaloptions
from browser import window

Highcharts = window.Highcharts

global_options = {
    'colors': ['rgb(0, 107, 164)', 'rgb(255, 128, 114)',
               'rgb(171, 171, 171)', 'rgb(89, 89, 89)',
               'rgb(95, 158, 209)', 'rgb(200, 82, 0)',
               'rgb(137, 137, 137)', 'rgb(162, 200, 236)',
               'rgb(256, 188, 121)', 'rgb(207, 207, 207)'],
    'chart':{
        'plotBackgroundColor': 'rgb(229, 229, 229)'
    },
    'credits':{
        'enabled': False
    },
    'legend':{
        'align': 'right',
        'verticalAlign': 'middle',
        'layout': 'vertical',
        'borderWidth': 0,
        'enabled': True
    },
    'plotOptions':{
        'area': {
            'fillOpacity': 0.5,
            'marker': {'enabled': False},
        },
        'arearange': {
            'fillOpacity': 0.5,
            'marker': {'enabled': False},
        },
        'areaspline': {
            'fillOpacity': 0.5,
            'marker': {'enabled': False},
        },
        'areasplinerange': {
            'fillOpacity': 0.5,
            'marker': {'enabled': False},
        },
        'bar': {
            'borderWidth': 0
        },
        'boxplot': {
            'fillColor': '#FAFAFA',
            'lineWidth': 2,
            'medianWidth': 4,
            'stemDashStyle': 'line',
            'stemWidth': 1,
            'whiskerLength': '30%',
            'whiskerWidth': 2
        },
        'column': {
            'borderWidth': 0
        },
        'columnrange': {
            'borderWidth': 0
        },
        'errorbar': {
            'color': '#fefefe',
            'lineWidth': 2
        },
        'line': {
            'marker': {'enabled': False},
            'lineWidth': 2
        },
        'scatter': {
            'marker': {
                'enabled': True,
                'lineWidth': 0,
                'symbol': 'circle',
                'radius': 5
            },
        },
        'spline': {
            'marker': {'enabled': False},
            'lineWidth': 2
        },
        'waterfall': {
            'borderWidth': 0
        }
    },
    'subtitle': {
        'align': 'center',
        'style': {
            'color': '#555555',
            'fontWeight': 'bold'
        }
    },
    'title': {
        'align': 'center',
        'text': None,
        'style': {
            'color': '#000000',
            'fontWeight': 'bold'
        }
    },
    'tooltip': {
        'backgroundColor': 'rgba(255,255,224,0.5)',
        'borderRadius': 5,
        'crosshairs': [{
                'width': 3,
                'color': '#ffffff',
                'dashStyle': 'shortdot'
            }, {
                'width': 3,
                'color': '#ffffff',
                'dashStyle': 'shortdot'
            }], 
        'hideDelay': 200,
        'enabled': True,
        'shadow': False,
        
    },
    'xAxis': {
        'gridLineColor': '#FFFFFF',
        'gridLineWidth': 1,
        'lineColor': 'rgb(229, 229, 229)',
        'tickColor': 'rgb(229, 229, 229)',
        'shadow': False,
        
    },
    'yAxis': {
        'gridLineColor': '#FFFFFF',
        'gridLineWidth': 1,
        'lineColor': 'rgb(229, 229, 229)',
        'tickColor': 'rgb(229, 229, 229)',
        'shadow': False,
        
    }
}

Highcharts.setOptions.new(global_options)

And now, let's repeat our first example again after the global configuration:


In [ ]:
html = """<div id="hc_ex3" style="width: 700px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

config = {
    'chart':{'renderTo': 'hc_ex3'},
    'title': {'text': 'Monthly Average Temperature'},
    'subtitle': {'text': 'Source: WorldClimate.com'},
    'xAxis': {'categories': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                             'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']},
    'yAxis': {'title': {'text': 'Temperature (°C)'}},
    'tooltip': {'valueSuffix': '°C'},
    'series': [{'name': 'Tokyo',
                'data': [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]}]
}

hc(config)

Much better than the ugly chart.

And other simple charts will look like the following:


In [ ]:
html = """
<div style="float: left;">
  <div id="hc_ex4a" style="width: 400px; height: 300px;"></div>
  <div id="hc_ex4b" style="width: 400px; height: 300px;"></div>
</div>
<div style="float: left;">
  <div id="hc_ex4c" style="width: 400px; height: 300px;"></div>
  <div id="hc_ex4d" style="width: 400px; height: 300px;"></div>
</div>"""

In [ ]:
%%brython -h html
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# Bar
config = {
    'chart': {'renderTo': 'hc_ex4a', 'type': 'bar'},
    'xAxis': {'categories': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                             'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']},
    'yAxis':  {'title': {'text': 'Temperature (°C)'}},
    'tooltip': {'valueSuffix': '°C'},
    'series': [{'name': 'Tokyo',
                'data': [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]}]
}
hc(config)

# Area
config = {
    'chart': {'renderTo': 'hc_ex4b', 'type': 'area'},
    'xAxis': {'categories': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                             'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']},
    'yAxis': {'title': {'text': 'Temperature (°C)'}},
    'tooltip': {'valueSuffix': '°C'},
    'series': [{'name': 'Tokyo',
                'data': [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]}]
}
hc(config)

# Bubble
config = {
    'chart': {'renderTo': 'hc_ex4c', 'type': 'scatter', 'zoomType': 'xy'},
    'title': {'text': 'You can pan and zoom'},
    'series': [{'name': 'Tokyo',
                'data': [[7.0, 6.9], [9.5, 14.5], [18.2, 21.5], [25.2, 26.5], [23.3, 18.3], [13.9, 9.6]]}]
}
hc(config)

# Pie
config = {
    'chart': {'renderTo': 'hc_ex4d', 'type': 'pie', 'plotBackgroundColor': 'white'},
    'series': [{'name': 'Python scientific libs',
                'data': [['scipy', 6.9], ['IPython', 14.5], 
                         ['Matplotlib', 21.5], ['Numpy', 26.5], ['Pandas', 18.3]]}]
}
hc(config)

**[NEW CODE]** In the previous figures we have included some new options in the chart dict:

  • **'type': 'type_of_chart'**. It indicates which chart will be used to render the data.

  • **'zoomType': 'xy'**. It allows us to zoom after the selection of an area with the mouse.

Also, in the Pie chart, we have used the option **'plotBackgroundColor': 'white'** so the global option defined before is not used.

Using data

Before, we have seen three different ways to insert data into a chart. Let's see it again to understand better how it is used:

  • An array of numerical values. In this case, the numerical values will be interpreted as y values, and x values will be automatically calculated, either starting at 0 and incrementing by 1, or from pointStart and pointInterval given in the plotOptions dict. If the axis has categories, these will be used. This option is not available for range series.

We have seen examples before but let's create a more complete example using this way:


In [ ]:
html = """<div id="hc_ex5" style="width: 700px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

config = {
    'chart': {'renderTo': 'hc_ex5'},
    'yAxis':  {'title': {'text': 'Temperature (°C)'}},
    'tooltip': {'valueSuffix': '°C'},
    'series': [{'name': 'Tokyo',
                'data': [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]},
               {'name': 'Madrid',
                'data': [3.0, 5.4, 6.5, 12.7, 16.8, 21.4, 26.5, 26.2, 24.3, 17.3, 11.8, 6.7]}]
}
hc(config)
  • An array of arrays with two values. In this case, the first value is the x value and the second is the y value. If the first value is a string, it is applied as the name of the point, and the x value is incremented following the above rules and the string will be used in the tooltip of the point. For range series, the arrays will be interpreted as [x, low, high]. In this cases, the x value can be skipped altogether to make use of pointStart and pointRange.

This way has been used in the scatter chart previously. In the example above we have seen that the x values start at 0. If we want a different behaviour we could define the x values as follows:


In [ ]:
html = """<div id="hc_ex6" style="width: 700px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

config = {
    'chart': {'renderTo': 'hc_ex6', 'type': 'line'},
    'yAxis':  {'title': {'text': 'Temperature (°C)'}},
    'tooltip': {'valueSuffix': '°C'},
    'series': [{'name': 'Neverland',
                'data': [[1, 6.9], [3, 14.5], [7, 21.5], [8, 26.5], [9, 18.3], [10, 9.6]]}]
}
hc(config)

If the x values are not a valid number it will be used as a label in the tooltip and the x values will start by 0 and incrementing by 1. For example:


In [ ]:
html = """<div id="hc_ex7" style="width: 700px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

config = {
    'chart': {'renderTo': 'hc_ex7', 'type': 'line'},
    'yAxis':  {'title': {'text': 'Temperature (°C)'}},
    'tooltip': {'valueSuffix': '°C'},
    'series': [{'name': 'Neverland',
                'data': [['Jan', 6.9], ['Mar', 14.5], ['Jul', 21.5], ['Aug', 26.5], ['Sep', 18.3], ['Oct', 9.6]]}]
}
hc(config)
  • An array of objects with named values. In this case the objects are point configuration objects. Range series values are given by low and high.

This is the most complete case as you can define more precisely how the data is displayed.

[HINT] In the next chart we will use the 'bubble' chart type. We must load a new javascript file as the highcharts.js doesn't provide the complete functionality of Highcharts and some type of charts (like 'arearange', 'bubble',...) are included as extras. The new javascript file is highcharts-more.js.


In [ ]:
from brythonmagic import load_js_lib
load_js_lib("https://cdnjs.cloudflare.com/ajax/libs/highcharts/5.0.7/highcharts-more.js")

In [ ]:
html = """<div id="hc_ex8" style="width: 700px; height: 300px;"></div>"""

In [ ]:
%%brython -h html

import random
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data = [{'name': 'Data {}'.format(i+1), 
         'color': 'rgb(100,50,{0})'.format(random.randrange(0,255)), 
         'y': random.randrange(0,25), 
         'x': i+1} for i in range(10)]

config = {
    'chart': {'renderTo': 'hc_ex8'},
    'yAxis':  {'title': {'text': 'Temperature (°C)'}},
    'series': [{'data': data, 'type': 'line', 'color': 'black'},
               {'data': data, 'type': 'bubble'}]
}
hc(config)

On each data value we have used a name (shown in the tooltip), a color (used in scatter, bar, column, bubble,..., charts but not in line or area charts, for example) and the x and y values.

Types of charts

Line charts

We already have seen several line charts. Let's see something more advanced. In the following example we will include the data value for each record and we will be able to choose an area of the chart to zoom on the chosen subset.


In [ ]:
html = """<div id="hc_ex9" style="width: 900px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
import random
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data = [[i+1, random.randrange(0,35)] for i in range(100)] 

config = {
    'chart': {'renderTo': 'hc_ex9', 'type': 'line', 'zoomType': 'x'},
    'yAxis':  {'title': {'text': 'Wind speed (m/s)'}},
    'series': [{'data': data}],
    'plotOptions': {
        'line': {'dataLabels': {'enabled': True}, 'enableMouseTracking': False}
    },
    'title': {'text': 'Click and drag to zoom'}
}
hc(config)

**[NEW CODE]** In the previous figure we have included some new options in the chart dict:

  • **'zoomType': 'x'**. It allows us to zoom after the selection of an area with the mouse. In this case, the zoom is over the x axis

Also, in the **plotOptions** dict, we have included some new options.

  • **'line': {'dataLabels': {'enabled': True}, 'enableMouseTracking': False}**. The **'dataLabels'** option allow us to show the value of each record while the **'enableMouseTracking'** option allows us to disable the default mouse interaction with the plot (tooltip,...).

In the following plot we are defining some areas in the background to help highlight some aspects of the dataset:


In [ ]:
html = """<div id="hc_ex10" style="width: 900px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
import random
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data = [[i+1, random.randrange(10,105)] for i in range(100)] 

config = {
    'chart': {'renderTo': 'hc_ex10'},
    'xAxis':  {'min': -20},
    'yAxis':  {
        'title': {'text': 'Mean Daily NO2 (ug/m3)'},
        'max': 110,
        'minorGridLineWidth': 0,
        'gridLineWidth': 0,
        'alternateGridColor': None,
        'plotBands': [{ 
            'from': 0,
            'to': 15,
            'color': 'rgba(100,100,255,0.5)',
            'label': {
                'text': 'Clean air',
                'style': {
                    'color': 'black'
                }
            }
        }, { 
            'from': 15,
            'to': 40,
            'color': 'rgba(0,255,0,0.5)',
            'label': {
                'text': 'Below EU limit',
                'style': {
                    'color': 'black'
                }
            }
        }, { 
            'from': 40,
            'to': 120,
            'color': 'rgba(255,0,0,0.5)',
            'label': {
                'text': 'Above EU limit',
                'style': {
                    'color': 'black'
                }
            }
        }]
    },
    'series': [{'data': data, 'lineWidth': 2, 'color': 'black'}]
}
hc(config)

**[NEW CODE]** In the previous figure we have included some new options in the options dict:

  • **'xAxis': {'min': -20}**. This indicates the minimum value for the x axis.

  • With the following code we have suppresed the grid lines for the y axis and added some band colors. I think the code is self-explanatory.

'yAxis': { 'title': {'text': 'Mean Daily NO2 (ug/m3)'}, 'max': 110, 'minorGridLineWidth': 0, 'gridLineWidth': 0, 'alternateGridColor': None, 'plotBands': [{ 'from': 0, 'to': 15, 'color': 'rgba(100,100,255,0.5)', 'label': { 'text': 'Clean air', 'style': { 'color': 'black' } } }, { 'from': 15, 'to': 40, 'color': 'rgba(0,255,0,0.5)', 'label': { 'text': 'Below EU limit', 'style': { 'color': 'black' } } }, { 'from': 40, 'to': 120, 'color': 'rgba(255,0,0,0.5)', 'label': { 'text': 'Above EU limit', 'style': { 'color': 'black' } } }] }

In the next plot we are going to play a little bit with the axis, where is the y axis located?, and the legend?:


In [ ]:
html = """<div id="hc_ex11" style="width: 900px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data = [[3**i, i] for i in range(1, 10)] 

config = {
    'chart': {'renderTo': 'hc_ex11', 'type': 'spline'},
    'yAxis':  {'type': 'logarithmic', 'opposite': True, 'offset': 30},
    'legend': {'align': 'left'},
    'series': [{'data': data, 'lineWidth': 4, 'color': 'black'}]
}
hc(config)

**[NEW CODE]** In the previous figure we have included some new options to modify the y axis:

  • **'yAxis': {'type': 'logarithmic', 'opposite': True, 'offset': 30}**. The axis scale is logarithmic, it is located on the opposite site and is located with an offset of 30px from the plot area.

We can include some interactivity to the plot using some basic controls. With the buttons you can update the plot (every second a new point is created), stop the updates or reset to the original state:


In [ ]:
html = """<div id="hc_ex12container" style="height: 350px;">
  <div id="hc_ex12" style="width: 900px; height: 300px;"></div>
</div>"""

In [ ]:
%%brython -h html
from browser.timer import set_interval, clear_interval
from browser import window, document, html
from random import randrange

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data = [[i, randrange(0,10)] for i in range(0, 20)]
data_tmp = data[:]

config = {
    'chart': {
        'renderTo': 'hc_ex12', 
        'type': 'spline'
    },
    'series': [{'data': data, 'lineWidth': 2, 'color': 'black', 'animation': False,
                'marker': {'enabled': True}}]
}

hc(config)

### NEW CODE ###

idtimer = None

# A button to animate the plot with new data
document['hc_ex12container'] <= html.BUTTON('Animate', Id = 'anim')

def add_point():
    global data_tmp
    x = data_tmp[-1][0] + 1
    y = randrange(0,10)
    data_tmp.append([x, y])
    config['series'][0]['data'] = data_tmp[-20:]
    hc(config)

def animate(ev):
    global idtimer, config, data_tmp
    idtimer = set_interval(add_point, 1000)

document['anim'].bind('click', animate)

# A button to stop the plot with new data
document['hc_ex12container'] <= html.BUTTON('Stop', Id = 'stop')

def stop(ev):
    global idtimer
    clear_interval(idtimer)

document['stop'].bind('click', stop)

# A button to reset the plot with the original values
document['hc_ex12container'] <= html.BUTTON('Reset', Id = 'reset')

def reset(ev):
    global idtimer, config, data, data_tmp
    if idtimer:
        clear_interval(idtimer)
        data_tmp = data[:]
    config['series'][0]['data'] = data
    hc(config)
    
document['reset'].bind('click', reset)

**[NEW CODE]** In the previous figure we have included some Brython specific code to animate the figure:

  • **document['hc_ex12container'].append(html.BUTTON('xxx', Id = 'xxx'))**. With this code we are appending some buttons to the html div with id 'hc_ex12container', i.e., the html div element that contains the chart and the buttons. See the Brython docs for more info.

  • **document['xxx'].bind('click', xxx)**. With this code we are attaching some functionality (events) to some DOM elements. See the Brython docs for more info.

  • Finally, we have defined some functions to manage the events using the browser.timer module. See the Brython docs for more info.

Area charts

As some area charts are quite similar to line plots I will write some examples and I will only explain the code that is relevant:

A simple area chart:


In [ ]:
html = """<div id="hc_ex13" style="width: 900px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from random import randrange
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data1 = [[i, randrange(0,10)] for i in range(0, 20)]
data2 = [[i, randrange(0,10)] for i in range(0, 20)]

config = {
    'chart': {
        'renderTo': 'hc_ex13', 
        'type': 'area'
    },
    'series': [{'data': data1, 'dashStyle': 'ShortDot', 'lineWidth': 3},
               {'data': data2}]
}

hc(config)

**[NEW CODE]**

  • **'dashStyle': 'ShortDot'**. This option in the first data series modifies the line defining the area. In this case we have used 'ShortDot' but there are ather options.

A simple stacked area chart:


In [ ]:
html = """<div id="hc_ex14" style="width: 900px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from random import randrange
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data1 = [[i, randrange(0,10)] for i in range(0, 20)]
data2 = [[i, randrange(0,10)] for i in range(0, 20)]

config = {
    'chart': {
        'renderTo': 'hc_ex14', 
        'type': 'area'
    },
    'series': [{'data': data1, 'lineWidth': 3},
               {'data': data2}],
    'plotOptions': {'area': {'stacking': 'normal'}},
    'tooltip': {'shared': True},
}

hc(config)

**[NEW CODE]**

  • **'plotOptions': {'area': {'stacking': 'normal'}}**. This indicates that the areas will be stacked. We can choose a 'normal' or a 'percent' stacking. Other chart types like line, bar, columns,.., can be stacked.

  • **'tooltip': {'shared': True}**. This option indicates that the tooltip is shared between the datasets so the tooltip will show the information from all the available datasets.

A simple arearange chart combined with a line plot:


In [ ]:
html = """<div id="hc_ex15" style="width: 900px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from random import randrange
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data1 = [[i, randrange(5,10), randrange(10,15)] for i in range(0, 20)]
data2 = [[i, (lst[1] + lst[2]) / 2.] for i, lst in enumerate(data1)]

config = {
    'chart': {
        'renderTo': 'hc_ex15'
    },
    'series': [{'data': data2, 'type': 'line', 'name': 'mean', 'lineWidth': 3, 'color': 'black'},
               {'data': data1, 'lineWidth': 1, 'type': 'arearange', 'name': 'extremes'}],
    'tooltip': {'shared': True}
}

hc(config)

Column and bar charts

A bar plot with positive and negative values:


In [ ]:
html = """<div id="hc_ex16" style="width: 900px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from random import randrange
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data1 = [[i, -randrange(1,15)] for i in range(0, 20)]
data2 = [[i,  randrange(1,15)] for i in range(0, 20)]

config = {
    'chart': {
        'renderTo': 'hc_ex16',
        'type': 'bar'
    },
    'series': [{'data': data1, 'name': 'negative'},
               {'data': data2, 'name': 'positive'}],
    'plotOptions': {'bar': {'stacking': 'normal'}},
    'tooltip': {'shared': True},
    'xAxis': [{'opposite': False}, {'opposite': True, 'linkedTo': 0}]
}

hc(config)

**[NEW CODE]**

  • **'xAxis': [{'opposite': False}, {'opposite': True, 'linkedTo': 0}]**. We are defining two x axis, the second one in the opposite side of the plot area and the values are linked to the first axis, i.e., both axis are the same but each one on one side of the chart.

A bar plot with interactive values:


In [ ]:
html = """<div id="hc_ex17container">
  <div id="hc_ex17" style="position: relative; float: left; width: 700px; height: 300px; margin: 20px;"></div>
  <div id="tablediv"></div>
</div>"""

In [ ]:
%%brython -h html
from browser import window, document, html
from random import randrange

Highcharts = window.Highcharts

# first we create a table with two series of data, X and Y:
tab = html.TABLE()
tab.style = {'textAlign': 'center', 'width': '50px'}
tab <= html.TR(html.TD('X') + html.TD('Y'))
for i in range(5):
    tab <= html.TR(
            html.TD(
                html.INPUT(
                    Id = 'x' + str(i), value = randrange(1,5), style = {'width': '50px'}
                )
            ) + 
            html.TD(
                html.INPUT(
                    Id = 'y' + str(i), value = randrange(1,5), style = {'width': '50px'}
                )
            )
        )
    
document['tablediv'] <= tab

# Function to retrieve the data from the table
def get_data():
    data1 = []
    data2 = []
    for i in range(5):
        print('x' + str(i))
        data1.append(float(document['x' + str(i)].value))
        data2.append(float(document['y' + str(i)].value))
    return [data1, data2]

# Function to update the chart
def update(ev):
    global config, hc
    datasets = get_data()
    config['series'][0]['data'] = datasets[0]
    config['series'][1]['data'] = datasets[1]
    hc(config)
    print(datasets)

# Button and event
document['hc_ex17container'] <= html.BUTTON('Update', Id = 'btn')
document['btn'].bind('click', update)

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
datasets = get_data()
data1 = datasets[0]
data2 = datasets[1]

config = {
    'chart': {
        'renderTo': 'hc_ex17',
        'type': 'column'
    },
    'series': [{'data': data1, 'name': 'X'},
               {'data': data2, 'name': 'Y'}],
    'title': {'text': 'Modify the values in the table and update'}
}

hc(config)

**[NEW CODE]**

  • In this case, there is no relevant Highcharts code and the Brython specific code is out of the scope of this tutorial but it is pretty similar to that seen previously in a previous example.

Pie charts

In the examples above we have seen a simple pie plot. A donut plot would be quite similar:


In [ ]:
html = """<div id="hc_ex18" style="width: 600px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# Pie
config = {
    'chart': {'renderTo': 'hc_ex18', 'type': 'pie'},
    'series': [{'name': 'Python scientific libs', 'innerSize': '60%',
                'data': [['scipy', 6.9], ['IPython', 14.5], 
                         ['Matplotlib', 21.5], ['Numpy', 26.5], ['Pandas', 18.3]]}]
}
hc(config)

**[NEW CODE]**

  • **'innerSize': '50%'**. This is the only difference wth the previous pie plot example. It indicates radius where the pie plot should start from the centre.

Scatter and bubble charts

In the examples above we have seen a simple scatter plot. A scatter plot with two datasets is similar:


In [ ]:
html = """<div id="hc_ex19" style="width: 600px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from random import randrange
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data1 = [[i + randrange(-2, 2), randrange(i-3,i+3)] for i in range(0, 20)]
data2 = [[i + randrange(-2, 2) + 2, randrange(i-3,i+3)] for i in range(0, 20)]

# Scatter
config = {
    'chart': {'renderTo': 'hc_ex19', 'type': 'scatter'},
    'series': [{'name': 'Station 1 vs model', 'data': data1},
               {'name': 'Station 2 vs model', 'data': data2}],
    'xAxis': {'title': {'text': 'Station'}},
    'yAxis': {'title': {'text': 'Model'}}
}
hc(config)

A bubble plot with different colors depending on the size for each record would be as follows:


In [ ]:
html = """<div id="hc_ex20" style="width: 600px; height: 300px;"></div>"""

In [ ]:
%%brython -h html
from random import randrange
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data = []
for i in range(20):
    x = randrange(-10, 10)
    y = randrange(-10, 10)
    z = randrange(1, 20)
    data.append({'x': x, 'y': y, 'z': z, 
                 'color': 'rgb(40,40,{0})'.format(int(z * 255 / 20)),
                 'marker': {'lineWidth': 1, 'lineColor': 'black'}})

# Scatter
config = {
    'chart': {'renderTo': 'hc_ex20', 'type': 'bubble'},
    'series': [{'name': 'bubbles', 'data': data}]
}
hc(config)

3d Charts

For this examples we should first load the 3d highcharts library:


In [ ]:
from brythonmagic import load_js_lib
load_js_lib("https://cdnjs.cloudflare.com/ajax/libs/highcharts/5.0.7/highcharts-3d.js")

With the 3d 'module' loaded we can see a new example where some interactivity is added:


In [ ]:
html = """
<div id="hc_ex21" style="width: 900px; height: 400px;"></div>
<div id="sliders">
  <table>
    <tr>
      <td>Alpha Angle</td>
      <td>
        <input id="R0" type="range" min="0" max="45" value="15"/> <span id="R0-value" class="value"></span>
      </td>
    </tr>
    <tr>
      <td>Beta Angle</td>
      <td>
        <input id="R1" type="range" min="0" max="45" value="15"/> <span id="R1-value" class="value"></span>
      </td>
    </tr>
  </table>
</div>"""

In [ ]:
%%brython -h html
from browser import window, document

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

config = {
    'chart': {
        'renderTo': 'hc_ex21',
        'plotBackgroundColor': 'white',
        'type': 'column',
        'margin': 100,
        'options3d': {
            'enabled': True,
            'alpha': 15,
            'beta': 15,
            'depth': 50,
            'viewDistance': 50
        }
    },
    'plotOptions': {'column': {'depth': 25}},
    'series': [{'data': [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 
                         135.6, 148.5, 216.4, 194.1, 95.6, 54.4]}],
    'xAxis': {'gridLineColor': '#C0C0C0'},
    'yAxis': {'gridLineColor': '#C0C0C0'}
}

columns = hc(config)

def show_values():
    document['R0-value'].html = columns.options.chart.options3d.alpha
    document['R1-value'].html = columns.options.chart.options3d.beta

show_values()

# activate the sliders
def change_alpha(ev):
    columns.options.chart.options3d.alpha = ev.target.value
    show_values()
    columns.redraw(False)

def change_beta(ev):
    columns.options.chart.options3d.beta = ev.target.value
    show_values()
    columns.redraw(False)

document['R0'].bind('change', change_alpha)
document['R1'].bind('change', change_beta)

**[NEW CODE]**

  • **'options3d': {'enabled': True,'alpha': 15,'beta': 15,'depth': 50,'viewDistance': 50}'**. In this case, we are switching on the 3d options and the initial view of the plot.

You can create 3D pie, donut, scatter,..., plots.

Heat map

In this case, as we did it before, we have to add a new module called heatmap:


In [ ]:
from brythonmagic import load_js_lib
load_js_lib("https://cdnjs.cloudflare.com/ajax/libs/highcharts/5.0.7/modules/heatmap.js")

A simple heatmap would be as follows:


In [ ]:
html = """<div id="hc_ex22" style="width: 900px; height: 400px;"></div>"""

In [ ]:
%%brython -h html
from random import randrange
from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

# First we create the data to be passed to the plot
data = []
for y in range(7):
    for x in range(7):
        data.append([y, x, randrange(0,150)])
    
config = {
    'chart': {
        'renderTo': 'hc_ex22',
        'type': 'heatmap',
        'marginTop': 40,
        'marginBottom': 40
    },
    'title': {'text': 'Commits made last week :-P'},
    'xAxis': {'categories': ['Numpy', 'Scipy', 'Matplotlib', 'IPython', 
                             'Pandas', 'Brython', 'Brythonmagic']},
    'yAxis': {'categories': ['Monday', 'Tuesday', 'Wednesday', 
                             'Thursday', 'Friday', 'Saturday', 'Sunday'],
              'title': {'text': None}},
    'colorAxis': {'min': 0,
                  'minColor': '#FFFFFF',
                  'maxColor': JSConstructor(Highcharts.getOptions)().colors[0]},
    'legend': {
        'align': 'right',
        'layout': 'vertical',
        'margin': 0,
        'verticalAlign': 'top',
        'y': 25,
        'symbolHeight': 300
    },
    'series': [{
        'borderWidth': 1,
        'data': data,
        'dataLabels': {
            'enabled': True,
            'color': 'black',
            'style': {
                    'textShadow': 'none',
                    'HcTextStroke': None
            }
        }
    }]
}

hc(config)

**[NEW CODE]**

  • **'colorAxis': {'min': 0, 'minColor': '#FFFFFF', 'maxColor': JSConstructor(Highcharts.getOptions)().colors[0]},**. The colorAxis adds a colorbar to the plot.

Other chart types

We already have seen line, bubble, column, bar, donut, scatter, ..., charts. You can create Pyramid, Funnel, Waterfall or others.

Let's use Highcharts in a more pythonic way

All we have seen until now is better that writting plain javascript but the use of Highcharts is not very Pythonic.

Creating a simple wrapper for Highcharts:

Let's start with something very simple


In [ ]:
%%brython -s wrapper01

from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

class HC:
    def __init__(self, container):
        self.options = {}
        self.options['chart'] = {}
        self.options['chart']['renderTo'] = container
        self.options['title'] = {}
        self.options['title']['text'] = ""
        self.options['legend'] = {}
        self.options['legend']['enabled'] = False
        self.options['subtitle'] = {}
        self.options['subtitle']['text'] = ""
        self.options['series'] = []
  
    def show(self):
        hc(self.options)

In [ ]:
html = """<div id="hc_ex23" style="width: 900px; height: 400px;"></div>"""

In [ ]:
%%brython -h html -S wrapper01

plt = HC('hc_ex23')
plt.show()
print(plt.options)

Ok, not very exciting. We initialise with an empty dictionary of options and with the show method we pass the options dictionary to Highcharts and we can plot an empty chart. As stated before, not very fascinating. Let's add options to include a title and a subtitle.

[HINT] The -s option in brythonmagic is used to name a brython cell ('wrapper01' is the name for the portion of code defined in the first cell of this section). With the name of that cell the code of the cell can be used in a new Brython cell using the -S option. The use of the -S option would be like an import of the code of the cell with the defined name ('wrapper01' in this case).


In [ ]:
%%brython -s wrapper02

from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

class HC:
    def __init__(self, container):
        self.options = {}
        self.options['chart'] = {}
        self.options['chart']['renderTo'] = container
        self.options['title'] = {}
        self.options['title']['text'] = ""
        self.options['legend'] = {}
        self.options['legend']['enabled'] = False
        self.options['subtitle'] = {}
        self.options['subtitle']['text'] = ""
        self.options['series'] = []
        
    def show(self):
        hc(self.options)
    
    def title(self, text):
        self.options['title']['text'] = text
        #self.show()
    
    def subtitle(self, text):
        self.options['subtitle']['text'] = text
        #self.show()

In [ ]:
html = """<div id="hc_ex24" style="width: 900px; height: 400px;"></div>"""

In [ ]:
%%brython -h html -S wrapper02

plt = HC('hc_ex24')
plt.title('Dummy title')
plt.subtitle('Dummy title')
plt.show()

Still not very funny. If you see the two new methods added, title and subtitle, there is one line commented. We can uncomment these lines if we don't want to call the show method but everytime we use a method the chart will be plotted. I didn't see any overhead doing this but let's avoid it for the moment.

Ok, let's do something more interesting plotting some data in a line chart.


In [ ]:
%%brython -s wrapper03

from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

class HC:
    def __init__(self, container):
        self.options = {}
        self.options['chart'] = {}
        self.options['chart']['renderTo'] = container
        self.options['title'] = {}
        self.options['title']['text'] = ""
        self.options['legend'] = {}
        self.options['legend']['enabled'] = False
        self.options['subtitle'] = {}
        self.options['subtitle']['text'] = ""
        self.options['series'] = []
        
    def show(self):
        hc(self.options)
    
    def title(self, text):
        self.options['title']['text'] = text
        #self.draw()
    
    def subtitle(self, text):
        self.options['subtitle']['text'] = text
        #self.draw()
        
    def plot(self, x, y = None, label = None, color = None, linewidth = None):
        if y:
            data = [[i, j] for i, j in zip(x, y)]
        else:
            data = x
        serie = {'data': data, 'type': 'line'}
        if linewidth:
            serie['lineWidth'] = linewidth
        if label:
            serie['name'] = label
        if color:
            serie['color'] = color
        self.options['series'].append(serie)
        #self.draw()

In [ ]:
html = """<div id="hc_ex25" style="width: 900px; height: 400px;"></div>"""

In [ ]:
%%brython -h html -S wrapper03

plt = HC('hc_ex25')
plt.plot([1,2,4,5], [3,6,4,7], label = 'lineplot1', linewidth = 5, color = 'red')
plt.plot([1,2,4,5], [8,5,9,2], label = 'lineplot2', linewidth = 2, color = 'blue')
plt.title('Some line plots')
plt.show()

Wow!!, with less than 40 lines of Brython code we have a wrapper to do very simple interactive charts using Highcharts in a pythonic way. We added the label keyword in the plot method. In Matplotlib, the label is used by the legend in the case we want to add a legend. Let's add a legend method to provide the label keyword some utility.


In [ ]:
%%brython -s wrapper04

from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

class HC:
    def __init__(self, container):
        self.options = {}
        self.options['chart'] = {}
        self.options['chart']['renderTo'] = container
        self.options['title'] = {}
        self.options['title']['text'] = ""
        self.options['legend'] = {}
        self.options['legend']['enabled'] = False
        self.options['subtitle'] = {}
        self.options['subtitle']['text'] = ""
        self.options['series'] = []
        
    def show(self):
        hc(self.options)
    
    def title(self, text):
        self.options['title']['text'] = text
        #self.draw()
    
    def subtitle(self, text):
        self.options['subtitle']['text'] = text
        #self.draw()
        
    def plot(self, x, y = None, label = None, color = None, linewidth = None):
        if y:
            data = [[i, j] for i, j in zip(x, y)]
        else:
            data = x
        serie = {'data': data, 'type': 'line'}
        if linewidth:
            serie['lineWidth'] = linewidth
        if label:
            serie['name'] = label
        if color:
            serie['color'] = color
        self.options['series'].append(serie)
        #self.draw()
    
    def legend(self, loc = 'right'):
        self.options['legend']['enabled'] = True
        if loc:
            self.options['legend']['align'] = loc
        #self.draw()

In [ ]:
html = """<div id="hc_ex26" style="width: 900px; height: 400px;"></div>"""

In [ ]:
%%brython -h html -S wrapper04

plt = HC('hc_ex26')
plt.title('Line plots')
plt.plot([1,2,4,5], [3,6,4,7], label = 'lineplot1', linewidth = 5, color = 'red')
plt.plot([1,2,4,5], [8,5,9,2], label = 'lineplot2', linewidth = 2, color = 'blue')
plt.legend(loc = 'left')
plt.show()

The behaviour is not similar to that in the pyplot module of the matplotlib library but we can get some basic functionality. We can add a scatter method to combine line plots with scatter plots.


In [ ]:
%%brython -s wrapper05

from browser import window

Highcharts = window.Highcharts

hc = Highcharts.Chart.new

class HC:
    def __init__(self, container):
        self.options = {}
        self.options['chart'] = {}
        self.options['chart']['renderTo'] = container
        self.options['title'] = {}
        self.options['title']['text'] = ""
        self.options['legend'] = {}
        self.options['legend']['enabled'] = False
        self.options['subtitle'] = {}
        self.options['subtitle']['text'] = ""
        self.options['series'] = []
        
    def show(self):
        hc(self.options)
    
    def title(self, text):
        self.options['title']['text'] = text
        #self.draw()
    
    def subtitle(self, text):
        self.options['subtitle']['text'] = text
        #self.draw()
        
    def plot(self, x, y = None, label = None, color = None, linewidth = None):
        if y:
            data = [[i, j] for i, j in zip(x, y)]
        else:
            data = x
        serie = {'data': data, 'type': 'line'}
        if linewidth:
            serie['lineWidth'] = linewidth
        if label:
            serie['name'] = label
        if color:
            serie['color'] = color
        self.options['series'].append(serie)
        #self.draw()
    
    def legend(self, loc = 'right'):
        self.options['legend']['enabled'] = True
        if loc:
            self.options['legend']['align'] = loc
        #self.draw()
    
    def scatter(self, x, y, label = None, color = None):
        data = [[i, j] for i, j in zip(x, y)]
        serie = {'data': data, 'type': 'scatter'}
        if label:
            serie['name'] = label
        if color:
            serie['color'] = color
        self.options['series'].append(serie)
        #self.draw()

In [ ]:
html = """<div id="hc_ex27" style="width: 900px; height: 400px;"></div>"""

In [ ]:
%%brython -h html -S wrapper05

plt = HC('hc_ex27')
plt.title('Line plots')
plt.plot([1,2,4,5], [3,6,4,7], label = 'lineplot1', linewidth = 5, color = 'red')
plt.plot([1,2,4,5], [8,5,9,2], label = 'lineplot2', linewidth = 2, color = 'blue')
plt.scatter([1,2,4,5], [2,4,6,8], label = 'scatter1', color = 'green')
plt.legend(loc = 'left')
plt.show()

Let's stop here the wrapper.

More than Highcharts!!!

You can use Highstock to create beautiful and interactive time series visualisation. You can create very simple maps using Highmaps or check out the notebook about OpenLayers 2.x we made some time ago.

If you do something with this information and/or need some help just let me know about it opening an issue in the repo where this notebook is stored.