Create A Professional Dashboard With Dash And CSS Bootstrap

Gabriele Albini Gabriele Albini
November 12, 2020 AI & Machine Learning

A step-by-step explained example available on Git and Heroku

Introduction

In this article, I am going through the steps I followed to create an interactive dashboard, using PlotlyDash, a library for Python and R, and enhancing the layout with CSS Bootstrap.

Dash library is written on top of Flask, Plotly.js, and React.js, that allows to build data visualization apps in pure Python, rendered via the web browser.

The final result I produced can be displayed here: https://corporate-dash.herokuapp.com/

Create A Professional Dashboard With Dash And CSS Bootstrap
Image by author

This is a multi-page dashboard, simulating a business scenario, where there normally are some layout guidelines to be respected (corporate colours scheme, a pre-defined font, a corporate website that can inspire us, …) and some sales-related KPIs to be monitored.

The first page is filled with different types of charts (scatter plots, bar charts, bubble charts, heat-maps) and a recap table, with random data; the other pages are blank, but useful to show how to build a multi-page structure.

In this article, I’ll cover:

1. Dashboard Objectives

2. Getting started with Dash

3. Configuring the folder structure for a multi-page dashboard

4. Conceptualizing the layout with the CSS Bootstrap Grid system

4.1 Building the layout framework with CSS Bootstrap

4.2 Styling Dash components accessing to their CSS classes

5. Callbacks & Components

5.1 Multi dropdown filter : how to have a “Select All” option

5.2 Unveiling seasonality patterns with Heatmaps

5.3 Providing additional information when hovering on data points

6. How to deploy and share the dashboard

7. Conclusions

1. Dashboard Objectives

Dashboards are intended to provide a clear and accurate view on some business-relevant KPIs, enabling the end user to understand what’s presented, find the information needed, apply some filters, and hopefully derive some conclusions.

This dashboard is designed like a website, composed by different pages with a top navigator bar.

Each page content is divided into three parts:

  • Some top filters that can be applied to all the charts displayed in the page
  • A recap table, also displayed at the top, which enables the user to quickly have a glance on the main KPIs. Ideally, the intention is for the user to avoid going through each and every chart on the page, but immediately spot where to focus on just by looking at the recap table. This recap table has some conditional colour formatting, as a sort of traffic light, highlighting the positive / negative values.
  • Finally, a grid of charts, showing different views on the main KPIs

I have deliberately avoided to offer any way for the user to export the underlying data: due to the raising concerns around data privacy and data loss, the dashboard is intended to use aggregated data only. Raw data points are unreachable to the end user.

2. Getting started with Dash

There are plenty of user guidelines and introductions to plotly Dash.

I’ve personally found very useful to go through these sources, which explains plenty of examples:

  • The official Dash website https://dash.plotly.com/ is very useful, easy to read and navigate, showing all available components and their main properties
  • This article explains a very complete and detailed example inside-out: https://towardsdatascience.com/how-to-build-a-complex-reporting-dashboard-using-dash-and-plotl-4f4257c18a7f
  • I’ve also looked for a large amount of Youtube videos that shows how to create and customise basic Dash layouts and callbacks

Despite going through all these useful sources, I’ve had to face many challenges, especially in order to understand how to customise Dash components the way I wanted.

For this reason, I will also focus on this aspect in the steps below: the enhanced features and the layout, the visual identify of the end result is a very important aspect that can make the difference.

3. Configuring the folder structure for a multi-page dashboard

The app source-code files should be structured as recommended by the Dash guidelines (https://dash.plotly.com/urls) to enable a multi-page navigation. Based on this guide, I’ve used the following approach to minimise any code change or adaptation.

My root folder contains:

  • app.py : this file is very basic and will only define the app variable needed by Flask. I’ve simply followed the Plotly Dash guidelines to create this file.
  • index.py : this is a sort of navigator file, helping the app managing the URLs of the different pages. Also this file is very standard: I recommend to follow the Plotly Dash guidelines for it, as we just need to customise the pathnames to have this working.
  • layouts.py : all pages html layouts will be stored in this file. Given that some components (like the header or the navbar) have to be replicated on each page, I’ve created some functions to return them, avoiding many repetitions within the code
  • callbacks.py : all callbacks (the functions behind the Dash components, that define the user interactions with the graphs) will be stored in this file

Within the root folder, Dash will look for:

  • a “data” subfolder: containing the underlying data of the dashboard
  • an “assets” subfolder: containing additional files, like: images; favorite icon, used by the browser; .css files

If this structure is followed for the assets subfolder, the app will automatically detect and use the favico.ico file or the .css files, with no code needed! Just name an image like “favicon.ico” and place it within root/assets and Dash will automatically use it.

There are some additional files within the root folder (such as the .gitgnore, README.md, Procfile, requirements.txt) : these files are needed to deploy the app on Heroku or store the code on Git Hub.

4. Conceptualizing the layout with the CSS Bootstrap Grid system

With the app folder structure in place, the next thing to configure is the overall layout of our pages. We can’t talk about a web application layout without mentioning .css files, which centralise almost all layout properties and that can be read by the browser.

In very few words, .css files define the properties (fonts properties, sizes, colors, backgounds, …) of html components, also used by Dash.

The App will start applying the layout properties to the corresponding html components, reading them from the .css files stored in the “assets” folder of the app.

It is important to note that: if the properties for the same html component (eg. a H2 html title font family) is defined in multiple .css files, the last one read by the app will be applied (let’s ignore the !important css suffix for now).

CSS properties can also be defined by creating some custom “class”, then assigned to the html components (like a div) we want to style.

In my example, I’ve used 3 .css files, which I’ve named with some leading numbers to ensure that they are read by the app in a specific order:

  • A customised font, defining a new font family used by the app (you can download font families from google, copying their .css content. Note that, within the font file, there are some URLs, that the app will download. If your app will run in an offline environment, you should download the content of these URLs and place them in a subfolder: root/assets/fonts, adapting the url to this pathname, within the font .css file)
  • The bootstrap .css standard file, which I’ll describe just below (I basically downloaded the official CSS file from the Bootstrap website)
  • A “corporate-style.css” containing all customisation I introduced on the layout

I’ve seen that many Plotly Dash examples use a basic .css template (https://codepen.io/chriddyp/pen/bWLwgP.css): this is not a requirement for the app and I chose not to use it for my dashboard (I’ve used the official .css Bootstrap file, instead).

4.1 Building the layout framework with CSS Bootstrap

CSS Boostrap provides a lot of predefined .css properties, classes and layout features we can reuse. CSS Bootstrap is famous for the known “grid systems” which helps to scale websites pages depending on the device sizes used.

In short, we can think of our webpage as a table of rows and up to 12-columns: our html components can be placed inside this grid, which will have a dynamic size, according to the screen of the device it is displayed on.

I think this helped me a lot to obtain the layout I had in mind, which looked like the following:

Create A Professional Dashboard With Dash
Image by author

I’ve started thinking about the layout from the different sections (the “rows” of my page), and then picturing in my mind the different columns of the dashboard.

I’ve assumed that, like in a business scenario, some colours are already part of the corporate visual identity (in this case a sort of green palette with some pink elements) and I’ve picked a nice font-family called Dosis.

After that, I’ve been creating the scheme in the picture, with the different placeholders and the columns Bootstrap .css classes I’ve used.

Within the CSS Bootstrap grid system, different .div elements are nested, each with its class, starting from a row and then one or more columns. CSS Bootstrap has different columns classes, from col-1 to col-12, meaning that we can have the dynamic column width we wish, starting from a column which will be a 1/12 of the max width, till a column which will use the full width available (12/12). Within each column, it is possible to nest another row-columns sequence of .Div.

All these classes can be assigned to the html.Div([]) elements, within their className property.

This system helps to keep each section of the dashboard in order, with a designated area for each Dash component that is also dynamic to the screen used.

For instance, the following structure has been used to style the header, the navbar and the filters.

The header, consists of:

  • An external html.Div component, which has a .css “row” class, styled with a background color
  • Three html.Div components, inside the row; each represents a “col” .css class (remember that the total of these columns width must be equal to 12): a className=”2-col” div (a column of width 2/12), which will be kept empty, just to ensure that the title is centred; a 8-col div, hosting the main page title, and finally another 2-col div, hosting the corporate logo image

Image by author

The navbar, consists of:

  • Two empty col-3 div at the sides of the row
  • Three central col-2 div, each will contain a dcc.Link Dash component, that can be used to switch from one page to the other. The dcc.Link page for the current page is styled differently, to highlight the page the user is on

Image by author

The filters section consists of the following components:

Externally, we have a row and column div:

  • An external html.Div that has a “row sticky-top” class. This is a Bootstrap class that is the same as a row but that sticks at the top of the page, even when the user scroll down.
  • Inside the row, there’s a 12-col Div with some styling properties

Within the 12-col Div column, we have another “row” div containing the following set of columns:

  • Two empty col-2 div at the sides of the internal row
  • Two col-4 div, internally, each containing filter components: a dcc.DatePickerRange and two dcc.Dropdown componentes

Image by author

4.2 Styling Dash components accessing to their CSS classes

Once the layout is defined, the next challenge, from a user-interface perspective, is to properly style each Dash component, such as date ranges (dcc.DatePickerRange), dropdown filters(dcc.Dropdown), etc.

All of these components have a “style” property, where we can define the css properties we want to style, such as font-size, colour, white-space, and many more. Most of the layout enhancements we want to achieve, can be achieved defining the right css property, within the “style” of the Dash component. However, I faced different challenges in styling some features of these components, which seems inaccessible from their “style” properties. I’ve read similar challenges online from many different users, wondering how to style certain feature or detail of these components.

I think the main challenge here is to identify what’s the right CSS property that is used by Dash. There’s in fact a method to point and click, or “inspect” each element on the page, and unveil the CSS property it is defined by.

We can in-fact run the app in the browser, right-click on the page and choose “Inspect”: this will pop-up a window, on the right-side of the page, where we can navigate through the html and css code of the page. At the top of the page, we can click on this tool

Image for post

Image by author

We can finally hover on the element we want to style and get all its CSS classes and properties to understand what to change / redefine.

4.2.1 Examples: style a DatePickerRange element

A DatePickerRange by default look like this:

Create A Professional Dashboard With Dash And CSS Bootstrap
Image by author

We can change the component layout from the “style” property and define the font-size, add a border with some colour, etc. But how to modify that arrow that separates the start date from the end date ? How to change the green colours highlighting the selected days or around the helper icon?

These elements seem unreachable from the “style” property and we have to use a different method to change their layout properties. Within the browser, if we inspect and select the arrow, we’ll see something like that:

Create A Professional Dashboard With Dash And CSS Bootstrap
Image by author

This component is using some CSS classes, that we can modify by adding some code into our custom CSS file, forcing the arrow to a new size:


Image by author

Similarly, we can unveil how the change the calendar style by inspecting the calendar selection:

Create A Professional Dashboard With Dash And CSS Bootstrap
Image by author

By analysing this element, it seems that “.CalendarDay__selected” is the CSS class for the date extremes that are selected, while “.CalendarDay__selected_span” is the CSS class used for all the days in between the two extremes. It is possible to use these classes to change the background colours of the calendar (and to define some layout modifications when hovering the mouse on the different days). I’ve added the code below to the custom CSS file:


Image by author

(“!important” overrides any other layout definition for the same CSS element or class).

4.2.2 Example: style a dash_table.DataTable element

Another element which I found difficult to style was the DataTable that I used in the recap section at the top of the dashboard.

DataTables have, by default, a feature that enables to select a cell, making it appear in a pink/red background colour. Additionally, by using the default CSS Bootstrap file, a default setting will change the background colour to white for all the table rows we hover on.

Create A Professional Dashboard With Dash And CSS Bootstrap
Image by author

I wanted to really change these two default properties which were clashing with my overall layout.

First of all, the selectable cell is not actually a CSS property but a component property which can be disabled: adding “cell_selectable = False” within the creation of the DataTable removes this functionality.

In order to change the row hovering colour, with the method explained before we can see that DataTable rows are actually <tr> </tr> html elements, with no particular CSS class associated.

Create A Professional Dashboard With Dash And CSS Bootstrap
Image by author

In order to customize the background colour when hovering on rows, I’ve added the following on the custom CSS file:


Image by author

5. Callbacks & Components

Once the dashboard layout has been defined and the chart and filter components have been placed on the page, let’s move to the callbacks.

I’ll go through some examples of Callbacks, focusing on the most troublesome that I’ve used.

5.1 Multi dropdown filter : how to have a “Select All” option

Dashboards very often include one or more dropdown filters, allowing the user to select one or multiple values at the same time.

In very simple cases, there shouldn’t be any Callback “behind” the dropdown component: the user selects one or more dropdown options; the selected values are normally “inputs” for other callbacks that adjust what’s presented on charts.

However, in more complex cases, we may want to have a multi-dropdown selection, where the options of a second dropdown depend on the selections of the first dropdown. In the example that I’ve created, I have a country dropdown and a city dropdown: the city dropdown options, definitely depend on the country that has already been chosen.

To add some more complexity, I’ve noticed there is not an out-of-the-box feature, in Dash, to “Select All”. Especially in those cases where the dropdown options are long lists, it is highly recommended to add a way to “Select All”, otherwise we would need to enter one by one all the options every time we want to analyse all values. Additionally, I also wanted to configure the dashboard in a way that “no selection” (ie. leave the dropdown blank) means that all options are considered.

In order to achieve all the features described here, I’ve followed the steps listed right below.

5.1.1 Create options lists

First of all, I’ve created a list of options for each of the Dropdown components. The data that I randomly created has the “Country” information on one column, and the “City” information on another. I’ve simply created two unique lists, one for all possible cities and one for all possible countries and I’ve added a “(Select All)” entry, which I wanted to have at the top of the option list.

Next, I’ve included the Dropdown component on the page layout, simply specifying the “multi” property:


Image by author

5.1.2 Manage option lists dynamically

I’ve then defined a callback that takes as input the list of values (selections) from the first Dropdown and returns, as output, the list of options of the second Dropdown.

Given that the list of options depends on the values, I’ve generated a dictionary where each key is a possible value of the first dropdown, and each value is a list of all possible options of the second dropdown. The result looks like the following:

{Brasil : [Fortaleza, Rio De Janiero, Sao Paulo],

Italy : [Milan, Venice], … }

To finalize the Callback, some key considerations are:

  • the “values” from the first Dropdown will be a python list
  • this list may or may not contain the “All” option
  • leaving the list of values empty, will mean that we’ll have [‘’] as input of our Callback

As a first step, I’ve created a variable (isselect_all), useful to determine if the user has left the first dropdown blank, or if the user chose “Select All”, or neither of these two possibilities.

In the first two cases, the callbacks simply returns a sorted list of all possible cities. Otherwise, the user is picking one or more countries individually, therefore I’m using the previously created dictionary (that I named repo_groups_l1_l2) to calculate a sorted list of all possible cities.


Image by author

5.2 Unveiling seasonality patterns with Heatmaps

Among all possible charts, Heatmaps are ideal whenever we’d like to plot 3 dimensions and show seasonality or patterns in data. For instance, I’ve included a heatmap to show sales trend across the year (week number in my case) and day of the week, to see if there is any seasonality on these two dimensions.

The weekdays will be on the x-axis, the calendar week numbers will be on the y-axis; each cell will be colored depending on the sale volumes. The heatmap will also need to respond to filters (based on dates and on the city and country dropdowns).

5.2.1 Heatmap: the layout

First of all, let’s include a placeholder for the heatmap within the dash layout. In the below code, the headtmap will be in the last column with the id “sales-weekly-heatmap”:


Image by author

5.2.2 Heatmap: callback overview

Then, let’s move to the callback, which will have:

  • inputs: the different filters — In my case these are the start and end date from the date picker and the “country” and “city” dropdown selections
  • output: the above dcc.Graph “figure” element
  • 1st section: data preparation. The callback will use the datasource (which consists of a single dataframe) and will filter and aggregate data by week nr. and weekday
  • 2nd section: graph preparation (using Plotly: go.Heatmap). The chart will use a predefined colorscale which I custom created via a function

5.2.3 Heatmap: data preparation

In the data preparation part, I had to include some statements to handle the “Select All” for both the dropdown selections. In case the user has chosen this option from the dropdown, the dataframe doesn’t need to be filtered by country/city; otherwise, only the values selected by user will be considered from the initial complete dataframe:


mage by author

I’ve then filtered the dataframe by stard and end date and finally aggregated it by week number and weekday:


Image by author

5.2.4 Heatmap: graph configuration

In order to draw some nice and consistent charts, across the dashboard, I’ve created a go.Layout() variable (named corporate_layout) at the top of the callback file. This layout variable includes a lot of properties that are almost all the same across all dashboard charts (chart transparent background, font family, title font size, gridlines, zerolines, overall height, legend syle, margins, …).

Inside each chart callbacks, a new fig = go.Figure(data=data, layout=corporate_layout) is defined. This allows then to update the fig layout (via this command: fig.update_layout()) to adapt the corporate_layout and include the chart title and the axis titles.

With this approach, the main layout of the chart is defined only once: this helps keeping the code clean, but also flexible; i.e. in order to change all charts height, we simply need to adjust one variable in the whole code.

Regarding the “data” component of the go.Figure, I’ve used a go.Heatmap(), including a colorscale, which I’ll describe right below.


Image by author

5.2.5 Heatmap: add a custom colorscale

Plotly heatmap includes some standard colorscales we can choose from, or we can assign a custom created one.

Plotly provides some instructions (available here) to create a custom colorscale. The colorscale that I’ve used look like this : a list of 11 colors that are used by the heatmap according to the percentile of each datapoint.


Image by author

In order to generate colors in some gradient sequence, I’ve created a function that takes as input the amount of colors we need to generate and the RGB values of two colors: one will be the “starting point” and the other will be the “target point”. The function, for each color, increments the RGB values of the same amount, reaching the target one. It is a very simplistic approach, but this function serves the purpose:


Image by author

We can finally add the colorscale to the Heatmap to unveil some seasonality : as we can see, sales seem to decrease between week 10 and 20; then they started to increase reaching again the same levels by week 25+. We don’t have a significant seasonality within the days of the week.

Create A Professional Dashboard
Image by author

5.3 Providing additional information when hovering on data points

Within Dash, hovertemplates can be defined to specify what data is shown in what format, when the user hovers the mouse on the datapoints.

It may be useful to include additional information in the hovertemplate, besides the data which is already used by the chart (x and y value, for instance). Plotly official documentation provides useful alternatives: I am going to present the one that I found most effective.

In the chart below, I’ve created a stacked bar-chart, where every country is represented by each vertical bar, showing the sales as the sum of each city individual sales. When hovering, I also wanted to show the information about the total target as opposed to the sales:

Create A Professional Dashboard
Image by author

The “target” by city is an information present in the datasource, but it is something which is not shown in the chart: where is the hover-template taking this info?

The approach I followed is to basically create, within the dataframe used by the chart, a new column containing all info I wanted to present in the hovertemplate:


Image by author

Plotly hovertemplate requires some html formatting: “<i> </i>” for instance means that the content will be italic; “<extra> </extra>” is used to remove the trace name of the datapoint. Values are formatted with the d3-format’s syntax (as explained by Plotly here): “{:,d}” is used to include thousand’s separators (in case you’re wondering how that would work for other value types: percentages with 2 decimals can be formatted like this: “{:.2%}”; dates can be formatted like: “{x|%a, %d-%b-%Y}”.

Once we have the hovertext within the data, we can use it in the chart, just by assigning the dataframe column to the chart hovertemplate.

6. How to deploy and share the dashboard

Dashboards created via Dash can be deployed as Flask application. Heroku is definitely one of the most effective ways to make the application available online (and for free).

The guide I used to get this app deployed is very well explained through this video, including a list of approx. 15 steps to get this app online.

7. Conclusions

Plotly Dash is definitely a fun and very powerful Python library: I have been looking for a quick way to get repeatable analysis automated and very well presented and this definitely served the purpose!

With Python knowledge, some html & css experience, I was able to realize this dashboard during spare time in few weeks: I must say that embodying CSS Bootstrap to the layout made the difference and definitely allowed to build an underlying “grid” that allows to control very easily every section of the dashboard in the way I wanted to be.

  • Experfy Insights

    Top articles, research, podcasts, webinars and more delivered to you monthly.

  • Gabriele Albini

    Tags
    CSS BootstrapDashboardPlotlyDashPythonR
    © 2021, Experfy Inc. All rights reserved.
    Leave a Comment
    Next Post
    3. Automation: Digital Transformation Debts post-Covid-19

    3. Automation: Digital Transformation Debts post-Covid-19

    Leave a Reply Cancel reply

    Your email address will not be published. Required fields are marked *

    More in AI & Machine Learning
    AI & Machine Learning,Future of Work
    AI’s Role in the Future of Work

    Artificial intelligence is shaping the future of work around the world in virtually every field. The role AI will play in employment in the years ahead is dynamic and collaborative. Rather than eliminating jobs altogether, AI will augment the capabilities and resources of employees and businesses, allowing them to do more with less. In more

    5 MINUTES READ Continue Reading »
    AI & Machine Learning
    How Can AI Help Improve Legal Services Delivery?

    Everybody is discussing Artificial Intelligence (AI) and machine learning, and some legal professionals are already leveraging these technological capabilities.  AI is not the future expectation; it is the present reality.  Aside from law, AI is widely used in various fields such as transportation and manufacturing, education, employment, defense, health care, business intelligence, robotics, and so

    5 MINUTES READ Continue Reading »
    AI & Machine Learning
    5 AI Applications Changing the Energy Industry

    The energy industry faces some significant challenges, but AI applications could help. Increasing demand, population expansion, and climate change necessitate creative solutions that could fundamentally alter how businesses generate and utilize electricity. Industry researchers looking for ways to solve these problems have turned to data and new data-processing technology. Artificial intelligence, in particular — and

    3 MINUTES READ Continue Reading »

    About Us

    Incubated in Harvard Innovation Lab, Experfy specializes in pipelining and deploying the world's best AI and engineering talent at breakneck speed, with exceptional focus on quality and compliance. Enterprises and governments also leverage our award-winning SaaS platform to build their own customized future of work solutions such as talent clouds.

    Join Us At

    Contact Us

    1700 West Park Drive, Suite 190
    Westborough, MA 01581

    Email: [email protected]

    Toll Free: (844) EXPERFY or
    (844) 397-3739

    © 2025, Experfy Inc. All rights reserved.