Dash Crush, part 0: basic concepts

Post Contents

Welcome to Dash Crush, your walk-through tutorial to advanced interactive Data Viz dashboards using Dash Plotly.

TL;DR

In this chapter:

  1. Introduction to dash
  2. Installation
  3. Your first app: layout and callback
  4. Running your first app

What is Dash?

Dash is an open-source framework by Plotly to build data-centric apps. It was originally released as a Python library, so I will focus on Python code. (Currently, there are Dash implementations for R, Julia, and F#). Using Dash you can build a dashboard without excessive knowledge of all the web stuff like HTML, CSS or JS (Though we will reach a point where you will benefit from knowing them).
The backbone of Dash consists of Flask, React, and Plotly.js. Hopefully, they are hidden from the user, so you do not have to worry.

Strengths of Dash

After a few years of intensive usage of Dash, I identified a few key strengths contributing to its success:

  1. Immanent power: you can do a lot with core Dash libraries and new features are added in every release.
  2. Community: over 5 million developers using Dash equals many community SW components available and many colleagues to ask for advice.
  3. Extensibility: if the previous points do not provide an answer to your question, you can create a Dash component from React ones.
  4. Paid options: you can use Dash Enterprise or sponsor implementing the feature you need by Plotly.

Web resources

My intention is not to copy content you can easily find on the web, so I'll only list some very useful links for further reading:

  1. Dash has detailed (and usually working) documentation, including basic tutorials and API references. You can find them here:
    https://dash.plotly.com/
  2. Plotly community forum where you can ask questions that bother you. And you will be heard:
    https://community.plotly.com/c/python/25
  3. Especially worth mentioning is the list of community components for Dash:
    https://community.plotly.com/t/community-components-index/60098

Basic concepts of Dash

There are two basic concepts behind the Dash framework:

  1. Layout - defines how your application looks. It's a hierarchy of nested components like Row, Col, and Div used analogously, as in good old HTML.
  2. Callbacks - are functions that define interactivity between components. They are executed when given properties of components (marked as Input in callback definition) change, and define the way to modify properties marked as Outputs.

Let's start coding

To be able to work with Dash, you will need to have the following prerequisites installed:

  1. Python,
  2. Pip,
  3. (optional, but recommended) virtual environment.

Let's create your first Dash app.

Creating the virtual env

Create your virtual env:
python -m venv dashenv

and activate it with:

  • on Linux/macOS:
    source dashenv/bin/activate
  • on Windows:
    dashenv/Scripts/activate

Installing Dash Plotly

To use Dash, we need to install it first. We will also need pandas for data manipulation.
Open the terminal and run the following command:
pip install dash pandas

First Dash app

We will create a simple dashboard that plots the precalculated Band Structure of Gallium Arsenide or Indium Arsenide, depending on material selection in the dropdown. (I will use examples from Quantum Physics in this tutorial, as those are most of the techniques I used to build http://qc.slashdev.team:8866/dash/)

Main file

The entry point of the app is dashboard.py. To create an empty dashboard, we only need to create an instance of Dash and call its run_server method

# dashboard.py

import dash

APP = dash.Dash(__name__)

# Run the Dash app
if __name__ == "__main__":
    APP.run_server(debug=True)

To fill the content of the app, we need to set APP.layout. There are two ways we could do that:

  1. Provide a tree of the components,
  2. Provide a function that returns the tree of components.

I will use the 2nd option and define the function create_layout in the file src/layout

Layout

Our simple layout looks like this:

# src/layout.py

from dash import dcc, html

MATERIALS = ["GaAs", "InAs"]

def create_layout():
    """Build layout"""
    return html.Div(
        [
            html.H5("Material:"),
            dcc.Dropdown(
                id="material_dropdown",
                options=[{"label": name, "value": name} for name in MATERIALS],
                value="GaAs",
            ),
            dcc.Graph(
                id="band_structure_graph",
            ),
        ],
    )

Let's go through it step by step:

  • Dash provides two modules that contain components:
    • html has a component for every HTML element (we use h5 header and div)
    • dash_core_components (dcc) contains higher level components that are not pure HTML. Instead, they are interactive and are generated with JavaScript, HMTL, CSS using React.js library
  • Function create_layout defines simple layout that consists of header, dropdown enabling material selection and graph

Now, we can set the layout of our app. We need to modify dashboard.py to import the layout module

from src import layout

and pass the create_layout function to APP:

APP.layout = layout.create_layout

The resulting code is:

import dash
from src import layout

APP = dash.Dash(__name__)
APP.layout = layout.create_layout

# Run the Dash app
if __name__ == "__main__":
    APP.run_server(debug=True)

At this moment, we have an empty layout. To make it interactive, we need one more element.

Callback

We will define callbacks in the src/callbacks.py file.

from dash import Input, Output
from dash.exceptions import PreventUpdate
import pandas as pd
import plotly.graph_objs as go

MATERIAL_DATA = {"GaAs": pd.read_csv("GaAs.dat"), "InAs": pd.read_csv("InAs.dat")}

TRACES = ["E_so", "E_lh", "E_hh", "E_c"]

def create_figure(to_draw):
    """Style graph"""
    layout = go.Layout(
        autosize=True,
        title="Band structure",
        xaxis={"title": "k (wave vector) [1/nm]"},
        yaxis={"title": "E (Energy) [eV]"},
    )
    return go.Figure(data=to_draw, layout=layout)

def create_callbacks(app):
    """Create callbacks"""

    @app.callback(
        Output("band_structure_graph", "figure"),
        Input("material_dropdown", "value"),
        prevent_initial_call=True,
    )
    def plot(material):
        if not material:
            raise PreventUpdate

        data = MATERIAL_DATA[material]

        to_draw = []
        for trace in TRACES:
            to_draw.append(go.Scatter(x=data["k"], y=data[trace], mode="lines", name=trace))

        return create_figure(to_draw)

Let's go through it step-by-step:

  • imports

    • Input, Output are definitions of Callback Input and Output objects
    • PreventUpdate is a special exception that is used if we do not want to modify the existing state of the app
    • import plotly.graph_objs as go is a module providing various types of plots. We will use the scatter plot
  • we read data files, containing energy profile data for each material and define traces to be plotted:

    MATERIAL_DATA = {"GaAs": pd.read_csv("GaAs.dat"), "InAs": pd.read_csv("InAs.dat")}
    TRACES = ["E_so", "E_lh", "E_hh", "E_c"]
  • create_figure is a helper method that defines the layout of the graph itself, sets the graph and axes' titles.

  • Actual callback: we need to define a callback function to plot a new graph on trigger. It's done by adding app.callback decorator to the function definition

    @app.callback(
        Output("band_structure_graph", "figure"),
        Input("material_dropdown", "value"),
        prevent_initial_call=True,
    )
    def plot(material):
    • The decorator means that the plot function is executed whenever the value property of the material_dropdown dcc.Dropdown component changes.
    • app is a Dash object passed from the caller.
    • prevent_initial_call is used to prevent firing a callback when a webpage is loaded in a browser
  • Inside the plot function, we fill in graph content. We add a new Scatter trace for each series in input data.

  • We turn data into a graph with create_figure

As with the layout, we need to import create_callbacks in dashboard.py:
from src.callbacks import create_callbacks
and call it there:
create_callbacks(APP)

Starting the app:

Start the app with python dashboard.py. You should see an indication of a running app in your console. The dashboard is available under http://localhost:8050. Navigate to that URL in your browser and enjoy your first dashboard!

Summary:

Quick recap:

  1. To run Dash you need Python and a virtual env
  2. Install dash with pip install dash
  3. Create your app with APP = dash.Dash(__name__)
  4. Setup APP.layout = and create callbacks
  5. Run your app with python dashboard.py
  6. Enjoy the result under http://localhost:8050

The complete code from this tutorial can be found on GitHub:
https://github.com/ptrhbt/dash-crush/tree/0-intro

There is also a file requirements.txt which lists all used packages. Just install it to your virtual env with pip install -r requirements.txt.

More detailed info can be found in the official Dash documentation:
https://dash.plotly.com/
including Minimal Dash App, Dash in 20 Minutes Tutorial, and Layout/Callbacks fundamentals.

We will explore more of Dash magic in the upcoming parts of Dash Crush.

Share this Post:

Related posts