How I Create Dazzling Dashboards Purely in Python.

Sept. 6, 2021

Plotly dashboard created purely in Python.

I don't have to convince you why we need an interactive dashboard. But most people don't know that they don't have to buy expensive licenses of Tableau or PowerBI. You don't have to enroll in a JavaScript course, either.

Dash apps allow you to build interactive dashboards purely in Python. Interestingly, it could reach heights that popular BI platforms can not.

Unlike other tools to create dashboard web applications, you can host Dash apps on your servers and terms. You can use this tool for various use cases, from a key performance indicator dashboard for your employees that changes once a month to a real-time network monitoring dashboard.

I strongly recommend the book, Interactive Dashboards and Data Apps with Plotly and Dash because it gives an in-depth understanding of interactive dashboard design.

Other resources about Dashboards and Data Visualization:
The Big Book of Dashboards
Storytelling with Data


Why Dash? Why not Tableau, Power BI, or some JavaScript library?

BI Platforms such as Tableau and PowerBI do a fantastic job. It allows even non-technical managers to do data exploration themselves. I don't have complaints about them.

They are excellent tools for performing analysis on read-only datasets. But in large data science project, you'll have to perform complex actions. For instance, you must trigger a backend function and start the model retraining.

In such cases, my best solution was to build a web app from scratch. JavaScript data visualization libraries such as HighCharts are excellent tools for this. They have callbacks for almost every possible user action. I use them to send data back to the server and control it better.

Related: How to Make a PDF Text-to-Speech Reader in Python

But this wasn't a walk in the park. My data science team is exceptional in Python and R but not JavaScript. Not on web frameworks such as Django either. And that's not enough; to build modern web apps, you need frontend web frameworks such as React.

As we progressed, we realized the harsh truth. Every new technology in our stack inflates the difficulty exponentially.

And we were fortunate to find Dash—a pure Python open-source web dashboard framework. If you're comparing Plotly dash vs. react, Dash is built using react, so you don't have to do the heavy lifting for yourself.

Now, this is how I create my own web dashboards in Python. If you're looking for a lightweight alternative, check out Streamlit.

Read along if you need flexible, custom dashboards entirely in Python. There's also an amazing extension to this package that lets you create Dash apps inside Jupyter notebooks. See its repository for more Jupiter dashboard examples.

Streamlit vs. Dash vs. Gradio

Both tools are great for building a dashboard web application. But streamlit is more focused on building quick control panels for ML projects. Plotly is great for building cool dashboards at ease.

Another excellent alternative to creating a dashboard web application is Gradio. With gradio, you can even create a dashboard in python Jupiter notebook.

If you create your web dashboard app in either Streamlit or Gradio, it could also work on mobile devices. Your Plotly dashboard app may need a bit more optimization for this.

Building your first dashboard in Python (in less than 1 minute.)

Yes, building dashboards in Dash is that simple. Install Pandas and dash with the following command, then start the timer.

pip install dash pandas

Create a file called app.py in your project directory with the content below.

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import pandas as pd

app = dash.Dash()

df = pd.read_csv(
    "https://raw.githubusercontent.com/ThuwarakeshM/geting-started-with-plottly-dash/main/life_expectancy.csv"
)

fig = px.scatter(
    df,
    x="GDP",
    y="Life expectancy",
    size="Population",
    color="continent",
    hover_name="Country",
    log_x=True,
    size_max=60,
)

app.layout = html.Div([dcc.Graph(id="life-exp-vs-gdp", figure=fig)])


if __name__ == "__main__":
    app.run_server(debug=True)

Showtime! let's run the dashboard app with the following command:

python app.py

You'll see it starting a server at port 8050. If you visit http://127.0.0.1:8050 on your browser, you'd see the dashboard that looks like the following:

Interactive dashboard created in Python using Plotly Dash

You'd appreciate the difference if you've created a similar app using JavaScript libraries. Dash saves a ton of time by eliminating an incredible amount of boilerplate code. Even popular BI tools have lots of prework to get to this point.

Awesome. That's quite a thing for inspiring you to build dashboards. But you might have realized that it's not dazzling yet. In the following sections, we'll discuss how

  • we can improve the layout;
  • add interactions and callbacks to the widgets like google analytics and;
  • style the app further.

With this, you can create the dazzling dashboard you need. Browse the Plottly Dash gallery for more of such dashboards for inspiration.

Related: 7 Ways to Make Your Python Project Structure More Elegant

Let's add more widgets to the layout.

Dash follows an HTML-like element hierarchy. You can attach any of Dash's HTML or Core components to the layout property of the app. The layout property is the root of a Dash app's element hierarchy.

Core components are a pre-configured set of widgets such as dropdowns and sliders.

Dash's HTML components cover almost every HTML element available. To create a heading, you can use html.H1 and html.P to create a paragraph. The children attribute allows you to nest one HTML component within another.

app.layout = html.Div(
    [   
        # Dropdown to filter developing/developed country.
        html.Div(
            [
                dcc.Dropdown(
                    id="status-dropdown",
                    options=[{"label": s, "value": s} for s in df.Status.unique()], # Create available options from the dataset
                ),
            ]
        ),
        # Dropdown to filter countries with average schooling years.
        html.Div(
            [
                dcc.Dropdown(
                    id="schooling-dropdown",
                    options=[
                        {"label": y, "value": y}
                        for y in range(
                            int(df.Schooling.min()), int(df.Schooling.max()) + 1
                        )
                    ], # add options from the dataset.
                ),
            ]
        ),
        # Placeholder to render teh chart.
        html.Div(dcc.Graph(id="life-exp-vs-gdp"), className="chart"),

        # Slider to select year.
        dcc.Slider(
            "year-slider",
            min=df.Year.min(), # dynamically select minimum and maximum years from the dataset.
            max=df.Year.max(),
            step=None,
            marks={year: str(year) for year in range(df.Year.min(), df.Year.max() + 1)}, # set markers at one year interval.
            value=df.Year.min(),
        ),
    ],
)

In the above code, we've included three core components—two dropdowns and a slider. These controller elements allow us to filter the chart data and create interactivity in the next section.

Adding interactivity with component callbacks.

Dash's core components have callbacks to control the response for a user action. This feature is remarkable of why Dash apps outshine popular BI platforms.

You can use this call back to control a chart re-rendering or trigger a heavy analysis. Check out my article on performing massive computations to use with Dash apps and Celery.

Here in this post, we use callbacks to filter the chart data.

@app.callback(
    Output("life-exp-vs-gdp", "figure"),
    Input("year-slider", "value"),
    Input("status-dropdown", "value"),
    Input("schooling-dropdown", "value"),
)
def update_figure(selected_year, country_status, schooling):
    filtered_dataset = df[(df.Year == selected_year)]

    if schooling:
        filtered_dataset = filtered_dataset[filtered_dataset.Schooling <= schooling]

    if country_status:
        filtered_dataset = filtered_dataset[filtered_dataset.Status == country_status]

    fig = px.scatter(
        filtered_dataset,
        x="GDP",
        y="Life expectancy",
        size="Population",
        color="continent",
        hover_name="Country",
        log_x=True,
        size_max=60,
    )

    return fig

The callback function is annotated with the @app.callback decorator. The first argument of this decorator is the Output component in the element tree. We need to specify the id of that element and the property we need to change. This property will change to the return value of the callback function.

Then the decorated will accept any number of input arguments. Each will be tied to a core component as we attached the output component. We can specify the element's id and the property that emits the change value. Usually, this would be 'value.'

Each input in the decorator should have a respective argument in the callback function's definition.

Finally, we moved the figure component inside the callback function. Every time we run the callback function, it creates a new figure instance and updates the UI.

Let's Style your dashboard (in Python; no CSS.)

You can use the inline styling options available in Dash app. But with little CSS, you could have spectacular results.

In-dash, you can style elements in three different ways.

Inline styling

Every Dash py component accepts a style argument. You can pass a dictionary and style any element. This is the most convenient way to style a Dash app.

html.H1("My Dazzling Dashboard", style={"color": "#011833"}),

Local stylesheets (okay, some CSS if you need.)

Alternatively, you can pass a class name attribute to any Dash component and use a separate CSS file to style it. You should place this CSS file inside an asset folder in your project directory. Dash will automatically pick it and apply its styles to the components.

# - app.py
# - assets/
#     |-- style.css

# style.css
# -----------------------------------------
# .title { color: #011833 }

# app.py
html.H1("My Dazzling Dashboard", className='title')

External stylesheets.

You can also use stylesheets from the internet. For instance, dash has this preconfigured stylesheet with convenient utility classes. You can specify the style sheet and use its class names in elements to make them beautiful.

app = dash.Dash(
    __name__, external_stylesheets="https://codepen.io/chriddyp/pen/bWLwgP.css"
)

# Alternative way
app.css.append_css({
    "external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
})

final project - creating visualizations and dashboards

Here is the complete styled source code of the application. We've used a local stylesheet and organized the HTML to support styling. The full code and the local stylesheet are in this GitHub repository.

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash_html_components.Label import Label
from pandas.io.formats import style
import plotly.express as px
import pandas as pd
from dash.dependencies import Input, Output

app = dash.Dash(
    __name__,
)

df = pd.read_csv(
    "https://raw.githubusercontent.com/ThuwarakeshM/geting-started-with-plottly-dash/main/life_expectancy.csv"
)

colors = {"background": "#011833", "text": "#7FDBFF"}

app.layout = html.Div(
    [
        html.H1(
            "My Dazzling Dashboard",
        ),
        html.Div(
            [
                html.Div(
                    [
                        html.Label("Developing Status of the Country"),
                        dcc.Dropdown(
                            id="status-dropdown",
                            options=[
                                {"label": s, "value": s} for s in df.Status.unique()
                            ],
                            className="dropdown",
                        ),
                    ]
                ),
                html.Div(
                    [
                        html.Label("Average schooling years grater than"),
                        dcc.Dropdown(
                            id="schooling-dropdown",
                            options=[
                                {"label": y, "value": y}
                                for y in range(
                                    int(df.Schooling.min()), int(df.Schooling.max()) + 1
                                )
                            ],
                            className="dropdown",
                        ),
                    ]
                ),
            ],
            className="row",
        ),
        html.Div(dcc.Graph(id="life-exp-vs-gdp"), className="chart"),
        dcc.Slider(
            "year-slider",
            min=df.Year.min(),
            max=df.Year.max(),
            step=None,
            marks={year: str(year) for year in range(df.Year.min(), df.Year.max() + 1)},
            value=df.Year.min(),
        ),
    ],
    className="container",
)


@app.callback(
    Output("life-exp-vs-gdp", "figure"),
    Input("year-slider", "value"),
    Input("status-dropdown", "value"),
    Input("schooling-dropdown", "value"),
)
def update_figure(selected_year, country_status, schooling):
    filtered_dataset = df[(df.Year == selected_year)]

    if schooling:
        filtered_dataset = filtered_dataset[filtered_dataset.Schooling <= schooling]

    if country_status:
        filtered_dataset = filtered_dataset[filtered_dataset.Status == country_status]

    fig = px.scatter(
        filtered_dataset,
        x="GDP",
        y="Life expectancy",
        size="Population",
        color="continent",
        hover_name="Country",
        log_x=True,
        size_max=60,
    )

    fig.update_layout(
        plot_bgcolor=colors["background"],
        paper_bgcolor=colors["background"],
        font_color=colors["text"],
    )

    return fig


if __name__ == "__main__":
    app.run_server(debug=True)

Your web app refreshes as you update your code with the above. And it may look like the below—your first version of a dazzling dashboard.

Screencast of a basic styled Plotly Dash app.

What next in your Dash app journey?

Dash is no doubt the best web dashboard framework for Python developers. Check out the Dash Enterprise App Gallery for more Python dash examples.

A vital benefit of these gallery apps is that they are a rich repository of dash layout examples.

If you'd like to take your Dash skills to the next level, check out this popular course on Udemy. More than 42k people benefited from this course, and about 7.8k rated this course 4.7 stars.

It's a beneficial resource if you've questions about adding authorization to the app or cloud deployment.

Final Thoughts

Plotly, Dash apps are an incredible tool for Python developers. Since most data science teams do not specialize in JavaScript, building dashboards with Dash saves much of their time.

We can use Tableau, PowerBI, and similar BI platforms for data exploration and visualization. But Dash apps outshine them as they tightly integrate with the backend code.

In this article, we explored the surface of Dash apps. I trust this would've given you the kickstart to build outstanding dashboards without worrying about scary technology stacks.

As a next step, I strongly recommend exploring Dash's documentation page and its example gallery.

How we work

Readers support The Analytics Club. We earn through display ads. Also, when you buy something we recommend, we may get an affiliate commission. But it never affects your price or what we pick.

Connect with us