Create a Dashboard using Highcharts and Django

Logo of HIghcharts, django, and python

 

In this tutorial, I will create an analytics dashboard using Django, a high-level Python Web framework, together with some sample data (car sales statistics) from Kaggle.  Every step is laid out so that even those new to Python or Django can follow along.

I will be using Bootstrap (CSS framework) for the frontend, with the popular Highcharts Javascript charting library for data visualization.

Let’s get started 🙂

 

Setting up the project

The first thing to do is to install Django using the following command line: pip3 install django

Then I create the project using this command line: django-admin startproject sample_dashboard

The result of the project creation is a folder structure below, btw the structure is created by django-admin:

sample_dashboard/
    manage.py
    sample_dashboard/
        __init__.py
        settings.py
        urls.py
        wsgi.py:

Before going any further let me explain the main important files created:

The sample_dashboard project sub-folder is the entry point for the website:

  • manage.py script allows to create applications, to work with databases, and to start the development web server.
  • init.py is an empty file that instructs Python to process the current directory as a Python package.
  • settings.py contains all the website settings. This is where it is registered any created applications, the static files’ location, database configuration details, etc.
  • urls.py defines the site url-to-view mappings. While this could contain all the url mapping code, it is more common to delegate some of the mapping to particular applications, as you’ll see later.
  • wsgi.py is used to help Django application communicates with the web server. You can think about this file as a boilerplate.

Now, you have an idea about the tasks and benefits of each file, let’s create the application.

Creation of the application

I run this command line to create my application: python3 manage.py startapp sales

The result of the command line above creates a new folder and populates it with files for the different parts of the application. Most of the files contain some minimal boilerplate code for working with the associated objects.

By now, the updated project directory looks like this structure:

sample_dashboard/
    manage.py
    sample_dashboard/
    sales/
        admin.py
        apps.py
        models.py
        tests.py
        views.py
        __init__.py
        migrations/

Another important part of the creation process is to register the application. To do that open the project settings file sample_dashboard/sample_dashboard/settings.py, look for the definition for the INSTALLED_APPS list, then add a new line at the end of the list with the string ‘sales’, this is required, as it will register the application in Django:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sales',
]

I also have to add the URL mapper by opening sample_dashboard/sample_dashboard/urls.py and adding URL mapper and the static folder.Url mapping it required to map the browser URL with the application. Here, I add included sales.url file defined in folder sales and I redirect blank URL (http://localhost:8000) to sales.

from django.contrib import admin
from django.urls import include
from django.urls import path
from django.views.generic import RedirectView
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('sales/', include("sales.urls")),
    path('', RedirectView.as_view(url='/sales/', permanent=True)),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

In this step, I define the view in the urls.py file. So in the previous step, I redirect the url (http://localhost:8000/sales) and in here I map <url>/sales/ to the view.

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

Read Data

After I the setting up and the creation processes, it is time to add the data to the application. To do that, I create this structure where I save the data in this format:

Manufacturer,Model,Sales in thousands,4-year resale value,Vehicle type,Price in thousands,Engine size,Horsepower,Wheelbase,Width,Length,Curb weight,Fuel capacity,Fuel efficiency,Latest Launch
Acura        ,Integra          ,16.919,16.36,Passenger,21.5,1.8,140,101.2,67.3,172.4,2.639,13.2,28,2-Feb-14
Acura        ,TL               ,39.384,19.875,Passenger,28.4,3.2,225,108.1,70.3,192.9,3.517,17.2,25,6-Mar-15
Acura        ,CL               ,14.114,18.225,Passenger,.,3.2,225,106.9,70.6,192,3.47,17.2,26,1-Apr-14
Acura        ,RL               ,8.588,29.725,Passenger,42,3.5,210,114.6,71.4,196.6,3.85,18,22,3-Oct-15
Audi         ,A4               ,20.397,22.255,Passenger,23.99,1.8,150,102.6,68.2,178,2.998,16.4,27,10-Aug-15
Audi         ,A6               ,18.78,23.555,Passenger,33.95,2.8,200,108.7,76.1,192,3.561,18.5,22,8-Sep-15

Before reading the data I have to define the view, and here how I do it:

from django.shortcuts import render
import pandas as pd

def index(request):
    """ view function for sales app """

    # read data                                                                                                  
	
    df = pd.read_csv("data/car_sales.csv")
    rs = df.groupby("Engine size")["Sales in thousands"].agg("sum")
    categories = list(rs.index)
    values = list(rs.values)
	
	table_content = df.to_html(index=None)
    table_content = table_content.replace("","")
    table_content = table_content.replace('class="dataframe"',"class='table table-striped'")
    table_content = table_content.replace('border="1"',"")
	
    context = {"categories": categories, 'values': values, 'table_data':table_content}
    return render(request, 'index.html', context=context)

Well, now everything is ready to display the data, so let’s set up the dashboard.

Creation of the Dashboard

 

 

In this step, I set up the dashboard using Bootstrap and Highcharts. I use Bootstrap to design the page skeleton including the chart container, and I use Highcharts to create the chart using javascript.

After defining the view, we will now be defining the code that presents the information to users. This is how the data flows:

* URL mappers forward the supported URLs (and any information encoded in the URLs) to the appropriate view functions.

* View functions get the requested data from the models, create HTML pages that display the data, and return the pages to the user to view in the browser

* Templates are used when rendering data in the views.

Django will automatically look for templates in a directory named ‘templates’ in your application. Hence, let’s create a new folder named `templates` in sales and create a new file `index.html` in it. The complete index.html is posted below, but before that here are the snippets:

The first thing to do is to add the libraries to the index.html.

Here I add Bootstrap:

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa\
9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">

And here, I add Highchart libraries:

<script src="https://code.highcharts.com/highcharts.js"> 
<script src="https://code.highcharts.com/modules/exporting.js"> 
<script src="https://code.highcharts.com/modules/export-data.js">

The next step is to define the chart’s container. This is where charts will be displayed.

<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto" class="border"></div>

The final step is to create the charts in javascript. The idea is simple, I pass the charts’ values from Django objects {{categories|safe}} and {{values|safe}}. I also have to define the chart’s title, yaxis title, tooltips, and series label.

_categories = {{categories|safe}};
_values = {{values|safe}};
Highcharts.chart('container', {
	chart: {
		type: 'column'
	},
	title: {
		text: 'Sales in Thousand per Engine Capacity'
	},
	subtitle: {
		text: ''
	},
	xAxis: {
		categories:_categories,
		crosshair: true
	},
	yAxis: {
		min: 0,
		title: {
			text: 'Sales in thousands'
		}
	},
	tooltip: {
		headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
		pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
			'<td style="padding:0"><b>{point.y:.1f} mm</b></td></tr>',
			footerFormat: '</table>',
		shared: true,
		useHTML: true
	},
	plotOptions: {
		column: {
			pointPadding: 0.2,
			borderWidth: 0
		}
	},
	series: [{
		name: 'Engine Capacity',
		data: _values
		
	}]
});

This is how the final HTML will look:

<!doctype html>
<html lang="en">
  <head>
    <title>Big Analytics</title>

    <!-- Bootstrap core CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">

  </head>
  <body>
    <!-- Top Bar -->
    <nav class="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow">
      <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">Big Analytics</a>
      <input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
      <ul class="navbar-nav px-3">
	<li class="nav-item text-nowrap">
	  <a class="nav-link" href="#">Sign out</a>
	</li>
      </ul>
    </nav>

    <div class="container-fluid">
      <div class="row">

	<!-- Left Pane -->
	<nav class="col-md-2 d-none d-md-block bg-light sidebar">
	  <div class="sidebar-sticky">
            <ul class="nav flex-column">
              <li class="nav-item">
		<a class="nav-link active" href="#">
		  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
		  Dashboard <span class="sr-only">(current)</span>
		</a>
              </li>
              <li class="nav-item">
		<a class="nav-link" href="#">
		  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-users"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
		  Customers
		</a>
              </li>
              <li class="nav-item">
		<a class="nav-link" href="#">
		  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bar-chart-2"><line x1="18" y1="20" x2="18" y2="10"></line><line x1="12" y1="20" x2="12" y2="4"></line><line x1="6" y1="20" x2="6" y2="14"></line></svg>
		  Reports
		</a>
              </li>
            </ul>
	    
            <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
              <span>Saved reports</span>
              <a class="d-flex align-items-center text-muted" href="#">
		<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>
		  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
		  Dashboard <span class="sr-only">(current)</span>
		</a>
              </li>
              <li class="nav-item">
		<a class="nav-link" href="#">
		  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-users"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
		  Customers
		</a>
              </li>
              <li class="nav-item">
		<a class="nav-link" href="#">
		  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bar-chart-2"><line x1="18" y1="20" x2="18" y2="10"></line><line x1="12" y1="20" x2="12" y2="4"></line><line x1="6" y1="20" x2="6" y2="14"></line></svg>
		  Reports
		</a>
              </li>
            </ul>
	    
            <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
              <span>Saved reports</span>
              <a class="d-flex align-items-center text-muted" href="#">
		<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>
              </a>
            </h6>
            <ul class="nav flex-column mb-2">
              <li class="nav-item">
		<a class="nav-link" href="#">
		  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>
		  Current month
		</a>
              </li>
              <li class="nav-item">
		<a class="nav-link" href="#">
		  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>
		  Last quarter
		</a>
              </li>
              <li class="nav-item">
		<a class="nav-link" href="#">
		  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>
		  Year-end sale
<h1 class="h2">Dashboard</h1>
            <div class="btn-toolbar mb-2 mb-md-0">
			              <div class="btn-group mr-2">
<button type="button" class="btn btn-sm btn-outline-secondary">Share</button>
<button type="button" class="btn btn-sm btn-outline-secondary">Export</button>
              </div>
			                <button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-calendar"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>
		This week
              </button>
            </div>
	  </div>

	  <!-- Highcharts display -->
	  <div class="border" id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>

	  <!-- Table data -->
	  <h2 class="pt-4">Section Details</h2>
	  <p class="text-danger">This table will be upated by Django objects, hence leaving it as it is.</p>
	  <div class="table-responsive">
	    {{table_data|safe}}
	  </div>
	</main>
      </div>
    </div>
	
    <!-- Chartjs libraries -->
    <script src="https://code.highcharts.com/highcharts.js"></script>
    <script src="https://code.highcharts.com/modules/exporting.js"></script>
    <script src="https://code.highcharts.com/modules/export-data.js"></script>
    
    <script>
      _categories = {{categories|safe}};
      _values = {{values|safe}};
      
      Highcharts.chart('container', {
	  chart: {
              type: 'column'
	  },
	  title: {
              text: 'Sales in Thousand per Engine Capacity'
	  },
	  subtitle: {
              text: ')'
	  },
	  xAxis: {
              categories:_categories,
              crosshair: true
	  },
	  yAxis: {
              min: 0,
              title: {
		  text: 'Sales in thousands'
              }
	  },
	  tooltip: {
              headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
              pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
		  '<td style="padding:0"><b>{point.y:.1f} mm</b></td></tr>',
              footerFormat: '</table>',
              shared: true,
              useHTML: true
	  },
	  plotOptions: {
              column: {
		  pointPadding: 0.2,
		  borderWidth: 0
        }
	  },
	  series: [{
              name: 'Engine Capacity',
              data: _values
	      
	  }]
      });
      </script>
    
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
    
  </body>
</html>

Running the Application

Now, all I have to do is to run the application using this command line:python3 manage.py runserver

Then I open the application on the browser using the local host link http://localhost:8000/sales

 

I hope this step by step tutorial will help you to understand how to use Highcharts with Django to set up online interactive charts.