📊 Section 3 · Data Viz 🟡 Intermediate MODULE 17

Dashboard Project — Plotly Dash Basics

⏱️ 26 min read
📖 Theory + Code
🧩 5 Quiz Questions
🏗️ 1 Challenge
Your progress in Section 380%
🎯 What you'll learn: Every chart so far has lived in a notebook or a single HTML file — useful, but static once shared. Dash is a Python framework, built on top of Plotly and Flask, for turning those charts into a real running web dashboard — with dropdowns, sliders, and other controls that update the charts live — without writing any JavaScript. You'll build a minimal Dash app skeleton, add a Plotly chart with dcc.Graph, wire up a dropdown with @app.callback, and run it locally.

What Is Dash?

Dash is an open-source Python framework, maintained by Plotly, for building interactive web applications — most commonly dashboards — entirely in Python. Under the hood, it runs on Flask (a Python web server) for the backend and React for the frontend, but you never touch either directly: you describe the page's layout and behavior in Python, and Dash generates the HTML/CSS/JS for you.

🐍
Pure Python
No JavaScript required to build a fully interactive web page
📊
Plotly-native
Drop any Plotly Express figure straight into the layout
🌐
Runs as a web app
Built on Flask — served locally, or deployed like any web app
📝
Installing Dash
Dash is a separate package from Plotly — pip install dash installs it (and pulls in Plotly as a dependency automatically). It's a good idea to also have pandas installed, since dashboards are almost always built on top of a DataFrame.

A Minimal Dash App Skeleton

Every Dash app follows the same three-part shape: create an app object, describe app.layout (what's on the page), and run it. Here's the smallest possible working app — no chart yet, just text.

app.py — minimal skeleton
PYTHON
from dash import Dash, dcc, html

app = Dash(__name__)

app.layout = html.Div([
    html.H1("Sales Dashboard"),
    html.P("A minimal Dash app skeleton."),
])

if __name__ == "__main__":
    app.run_server(debug=True)
📝
html.Div, html.H1, html.P — Python objects that render as HTML
The dash.html module provides a Python class for every HTML tag — html.Div, html.H1, html.P, and so on. app.layout is built by nesting these objects, which Dash then renders into actual HTML in the browser. No .html file to write by hand.
⚠️
run_server() vs. run()
This lesson uses app.run_server(debug=True), the method used across most existing Dash tutorials and still fully supported. Recent Dash versions (2.11+) also offer app.run(debug=True) as the newer, preferred name for the same thing — both start the same local development server, so either works.

Adding a Chart with dcc.Graph

dash.dcc ("Dash Core Components") provides the interactive building blocks — graphs, dropdowns, sliders, date pickers. dcc.Graph(figure=fig) drops any Plotly figure — built with plotly.express, exactly like in the last lesson — straight into the page.

app.py — with a chart
PYTHON
from dash import Dash, dcc, html
import plotly.express as px
import pandas as pd

df = pd.DataFrame({
    "city": ["Lahore", "Karachi", "Islamabad", "Faisalabad"],
    "sales": [820000, 950000, 610000, 430000],
})

app = Dash(__name__)

fig = px.bar(df, x="city", y="sales", title="Sales by City")

app.layout = html.Div([
    html.H1("Sales Dashboard"),
    dcc.Graph(figure=fig),
])

if __name__ == "__main__":
    app.run_server(debug=True)
Still fully interactive
Because fig is a regular Plotly figure, it keeps every bit of interactivity from the last lesson — hover tooltips, zoom, pan — now embedded inside a real web page instead of a standalone HTML file.

Making It Interactive with @app.callback

A static chart on a dashboard is only marginally more useful than a static chart anywhere else. Dash's real power is the callback — a Python function that automatically re-runs and updates part of the page whenever an input control changes, wired up with the @app.callback decorator.

app.py — interactive with a dropdown
PYTHON
from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import pandas as pd

df = pd.DataFrame({
    "city": ["Lahore", "Lahore", "Karachi", "Karachi", "Islamabad", "Islamabad"],
    "month": ["Jan", "Feb", "Jan", "Feb", "Jan", "Feb"],
    "sales": [420000, 460000, 500000, 530000, 300000, 320000],
})

app = Dash(__name__)

app.layout = html.Div([
    html.H1("City Sales Explorer"),
    dcc.Dropdown(
        id="city-dropdown",
        options=[{"label": c, "value": c} for c in df["city"].unique()],
        value="Lahore",
    ),
    dcc.Graph(id="sales-chart"),
])

@app.callback(
    Output("sales-chart", "figure"),
    Input("city-dropdown", "value"),
)
def update_chart(selected_city):
    filtered = df[df["city"] == selected_city]
    fig = px.bar(filtered, x="month", y="sales", title=f"Sales in {selected_city}")
    return fig

if __name__ == "__main__":
    app.run_server(debug=True)
📝
Reading the callback
Output("sales-chart", "figure") says "this function's return value becomes the figure property of the component with id="sales-chart"" — that's the dcc.Graph above. Input("city-dropdown", "value") says "run this function every time the value property of the component with id="city-dropdown" changes" — that's the dropdown. The decorated function's parameter (selected_city) receives that new value automatically, in the same order as the Inputs are listed.
⚠️
Component ids must match exactly
The strings "city-dropdown" and "sales-chart" inside Output()/Input() must exactly match the id= given to the actual component in app.layout. A typo here is one of the most common Dash beginner errors — the app runs, but the callback silently never fires because it's pointed at an id that doesn't exist.

Running the App Locally

Save any of the scripts above as app.py and run it like any other Python file:

terminal
SHELL
python app.py

Dash starts a local development server and prints a URL — by default http://127.0.0.1:8050/. Open that address in a browser to see the dashboard, and it stays running (and reloading on save, thanks to debug=True) until you stop the script.

1
Run python app.py
Starts the local Flask development server that Dash runs on top of.
2
Open http://127.0.0.1:8050/
The default local address — visit it in any browser to see the live dashboard.
3
Interact with it
Change the dropdown and watch the chart's callback fire and redraw, without a page reload.
4
Edit and save
With debug=True, the server auto-reloads your changes — no need to restart it manually.
debug=True is for development, not production
The debug mode gives helpful error pages and auto-reloading, which is great while building a dashboard. If a Dash app is ever deployed for real users, it's run with debug turned off and served by a production-grade WSGI server — a topic beyond this lesson, but worth knowing the distinction exists.

Lesson Summary

Let's recap everything you learned in this lesson:

Dash is a Python framework, built on Plotly + Flask, for building web dashboards with no JavaScript.
app.layout describes the page using nested html.* and dcc.* components.
dcc.Graph(figure=fig) embeds any Plotly Express figure into the layout.
@app.callback with Output()/Input() wires a control to a chart, re-running a function whenever the input changes.
app.run_server(debug=True) starts the local dev server at http://127.0.0.1:8050/.
🧩 Knowledge Check — Lesson 17
Answer all 5 questions to test your understanding. Instant feedback on every answer.
1. What is Dash built on top of?
2. Which component embeds a Plotly figure into a Dash app's layout?
3. What decorator wires a Python function to run automatically when an input control changes?
4. In Output("sales-chart", "figure"), what do the two arguments refer to?
5. What is the default local URL Dash's development server runs the app at?
💪
Coding Challenge — Lesson 17
Apply what you learned · Intermediate Level

Extend the interactive app from Section 4 with a second control.

Challenge: Two-Way City Sales Explorer 🏙️

Starting from the interactive app in Section 4, add a second dcc.Dropdown (id "chart-type-dropdown") that lets the user switch the chart between "bar" and "line". Update the @app.callback to take two Inputs — the city and the chart type — and build either px.bar() or px.line() inside update_chart() depending on which is selected.

Rules: The callback function needs one parameter per Input, in the same order they're listed inside @app.callback(...).
💡 Show hints if you're stuck
  • Second dropdown: dcc.Dropdown(id="chart-type-dropdown", options=["bar", "line"], value="bar")
  • Callback signature: @app.callback(Output("sales-chart", "figure"), Input("city-dropdown", "value"), Input("chart-type-dropdown", "value"))
  • Function: def update_chart(selected_city, chart_type): then branch with if chart_type == "bar": ... else: ...
Finished this lesson?
Mark it complete to track your progress.
🎉

Lesson 17 Complete!

You can build a Dash app skeleton, embed a Plotly chart, and wire up a dropdown with a callback so the chart updates live. Next up: the Section 3 capstone — a full sales dashboard for a Pakistani business.

Module 17 of 18 Section 3 — Data Visualization: Matplotlib & Seaborn