Slide 1

Slide 1 text

INTERACTIVE PLOTS WITH DJANGO AND HIGHCHARTS JS (WITHOUT JS) ERNESTO ARBITRIO Florence - Saturday 16 April 2016

Slide 2

Slide 2 text

whoami “Tech researcher at FBK” “Python enthusiast, stuff mixer, Earl J. Hickey double” email: [email protected] twitter: @earbitrio github.com/ernestoarbitrio

Slide 3

Slide 3 text

THE GOAL “PUBLISH PREDICTIVE AND STATISTICAL ANALYSIS ON A WEB DASHBOARD” Analytics engine DB

Slide 4

Slide 4 text

PLOT LIBRARIES ● Google charts ● D3JS ● Flot ● Chart.js ● Bokeh What I considered

Slide 5

Slide 5 text

RESIGNED TO USE JS …. BUT WHY HIGHCHARTS? ● Great interactivity ● Several plot types (box plot, bubble, meteogram, speedometers, etc…) ● Good DOCS ● Cheap licensing costs (FREE FOR NON-COMMERCIAL) ● Easy customization ● Internationalization

Slide 6

Slide 6 text

SO … WHAT COULD I USE AS ALTERNATIVE TO JAVASCRIPT?

Slide 7

Slide 7 text

DJANGO-HIGHCHARTS “Generate charts in your Django application using Highcharts helpers” https://github.com/ernestoarbitrio/django-highcharts ● Area charts ● Bar charts ● Heatmap charts ● Polar Spider web charts ● HighStock basic charts ● Pie with drilldown ● 3D Pie Options ● Speedometer charts ● Multiple Axes charts (Combined plots)

Slide 8

Slide 8 text

SORRY FOR INDENTATION, PEP8 VIOLATIONS AND … I NEED VERTICAL SPACE IN THE SLIDES

Slide 9

Slide 9 text

class HighChartsBasicView(JSONResponseMixin, AjaxResponseMixin): title = None title_style = None subtitle = None chart_type = None ... def get_data(self): data = dict() ... return data def get(self, request, *args, **kwargs): return self.get_ajax(request, *args, **kwargs) def get_ajax(self, request, *args, **kwargs): return self.render_json_response(self.get_data()) FROM django-braces JSONResponseMixin """ A mixin that allows you to easily serialize simple data such as a dict or Django models. """ AjaxResponseMixin """ Mixin allows you to define alternative methods for ajax requests. Similar to the normal get, post, and put methods, you can use get_ajax, post_ajax, and put_ajax. """ INTERNALS

Slide 10

Slide 10 text

INTERNALS class HighChartsDualAxisView(HighChartsBasicView): y_axis = {} y_axis_title = None def get_data(self): data = super(HighChartsDualAxisView, self).get_data() data['xAxis'] = {} data['yAxis'] = self.y_axis data['yAxis']['title'] = {"text": self.y_axis_title} return data DualAxisView Class for a standard XY plot

Slide 11

Slide 11 text

AREA CHART CLASS from django.views.generic import View from highcharts.views.common import HighChartsDualAxisView class HighChartsAreaView(HighChartsDualAxisView, View): chart_type = 'area' _series = [] def get_data(self): data = super(HighChartsAreaView, self).get_data() data['series'] = self.series return data @property def series(self): return self._series @series.setter def series(self, value): self._series = value According to Highcharts API DOCs Setter decorator encapsulates the private attribute self._series. In this way I can redefine the series attr within the get_data method

Slide 12

Slide 12 text

EXAMPLE OF USAGE (AREA) class DemoAreaView(HighChartsAreaView): title = 'area test' subtitle = 'test' chart = {'zoomType': 'xy'} @property def series(self): series = [ { 'name': 'Incoming', 'data': random.sample(range(10,60), 14), 'tooltip': "{ valueSuffix: ' euro' }" } ] return series

Slide 13

Slide 13 text

EXAMPLE OF USAGE (AREA) class DemoAreaView(HighChartsAreaView): title = 'area test' subtitle = 'test' chart = {'zoomType': 'xy'} def get_data(self): try: obj = MyModel.objects.value_list('a').filter(field=self.kwargs['a1']) self.series = [{'name': 'Incoming', 'data': obj, 'tooltip': "{ valueSuffix: ' euro' }"}] except MyModel.DoesNotExist: self.series = None data = super(DemoAreaView, self).get_data() return data

Slide 14

Slide 14 text

EXAMPLE OF USAGE (PIE CHART WITH DRILLDOWN) class PieDrilldown(HighChartsPieView): title = 'Demo Pie' subtitle = 'langs' @property def series(self): series = [{'name': 'Programming Languages', 'colorByPoint': 'true', 'data': [{'name': 'Python', 'y': 20, 'drilldown': 1}, {'name': '.NET', 'y': 12, 'drilldown': 2}, {'name': 'GO', 'y': 9, 'drilldown': 3}]}] return series @property def drilldown(self): drilldown = {'series': [ {'id': 1,'data': [['py2.7', 10],['py3.3', 5],['py3.5', 5]]}, {'id': 2,'data': [['1.1', 2],['2.0', 9],['3.0', 1],]}, {'id': '3','data': [['1.3', 3],['1.4', 1],['1.5', 1],['1.6',4]]}]} return drilldown

Slide 15

Slide 15 text

ADDING OPTIONS TO THE CHART EXAMPLE title = 'My demo chart' subtitle = 'Data from 1970-1990' chart = {'zoomType': 'xy'} tooltip = {'shared': 'true'} legend = {'layout': 'horizontal', 'align': 'left', 'x': 60, 'verticalAlign': 'top', 'y': 5, 'floating': 'true', 'borderWidth': 1} title = None title_style = None subtitle = None tooltip = None tooltip_point_format = None plot_options = {} chart = {} legend = True credits = {} coloraxis = {} exporting = {} class attributes = general chart attributes Refer to Highcharts API documentation

Slide 16

Slide 16 text

ADDING OPTIONS TO THE CHART e.g. if you want to change the chart subtitle according to the request data... class DemoChartView(HighChartsMultiAxesView): title = 'Trend with demo data' subtitle = 'Period ????-????' def get_data(self): p1 = self.request.GET['p1'] p2 = self.request.GET['p2'] self.subtitle = 'Period {0}-{1}'.format(p1, p2) ... data = super(DemoChartView, self).get_data() return data

Slide 17

Slide 17 text

DJANGO PROJECT INTEGRATION 1/3 polls/ __init__.py admin.py apps.py graphs.py migrations/ __init__.py models.py tests.py urls.py views.py Separate graphs classes view from standard views from django.conf.urls import patterns, include, url from .views import MainView from .graphs import DemoChart1, DemoChart2 urlpatterns = [ url(r'^$', view=MainView.as_view(), name='main') # plot urls url(r'^plot1/$', view=DemoChart1.as_view(), name='plot1') url(r'^plot2/$', view=DemoChart2.as_view(), name='plot2') ]

Slide 18

Slide 18 text

DJANGO PROJECT INTEGRATION 2/3 {% load staticfiles %} {% load highcharts_tags %} ... … {% highcharts_js 1 0 0 0 %} {% set_highcharts_theme "dark-unica" %} Load the custom template tags for django-highcharts helper Inclusion tag for mandatory and optionals (e.g. exporting, extras, 3d, highstock) Highcharts JS components Inclusion tag for chart theme selection

Slide 19

Slide 19 text

DJANGO PROJECT INTEGRATION 3/3
$(function () { $.getJSON("{% url 'plot1' %}", function(data) { $('#container').highcharts(data); }); }); Render the chart in the specified container

Slide 20

Slide 20 text

USER ACCESS CONTROL sdfdf class AdvancedTrendGroupChart(LoginRequiredMixin, HighChartsMultiAxesView): Each plot class can be protected by standard or custom Django AccessMixin classes

Slide 21

Slide 21 text

DEMONSTRATION TIME

Slide 22

Slide 22 text

not sure if to say thank you for your attention or thank you for staying awake BTW: ENJOY THE CONFERENCE Questions? Suggestions? Pull requests? we’re hiring