Day 2 of 5
⏱ ~50 minutes
Build a Data Dashboard — Day 2

Plotly Charts: Interactive Visualizations That Actually Respond

Static charts are fine for reports. Interactive charts are what make dashboards worth using. Today you'll add Plotly to your Streamlit app and build line charts, bar charts, and scatter plots that respond to real data and user input.

Why Plotly Over Matplotlib

Matplotlib produces static images. You render them, they sit there. Plotly produces interactive HTML — hover to see values, click to filter, zoom in, drag axes. In a browser-based app like Streamlit, interactive charts are the obvious choice.

Plotly Express is the high-level API. It produces most charts in one line of code. For this course, you'll use Plotly Express almost exclusively.

bash
pip install plotly
ℹ️
If you installed the full streamlit package, Plotly may already be available. Run python -c "import plotly; print(plotly.__version__)" to check.

Your First Plotly Chart in Streamlit

The pattern is always the same: create a figure with Plotly, then render it with st.plotly_chart(). Here's the simplest possible example:

python
import streamlit as st
import plotly.express as px
import pandas as pd

# Sample data
df = pd.DataFrame({
    "month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
    "revenue": [42000, 51000, 47000, 63000, 58000, 71000]
})

st.title("Monthly Revenue")

fig = px.line(df, x="month", y="revenue", title="Revenue by Month")
st.plotly_chart(fig, use_container_width=True)

use_container_width=True makes the chart fill the available column width instead of using Plotly's default fixed size. Always include it — it's almost always what you want.

The Three Charts You'll Use Most

Line Chart — Trends Over Time

python
fig = px.line(
    df,
    x="date",
    y="revenue",
    color="region",        # separate line per region
    title="Revenue Trend",
    labels={"revenue": "Revenue ($)", "date": "Date"}
)
fig.update_layout(hovermode="x unified")  # show all lines on hover
st.plotly_chart(fig, use_container_width=True)

Bar Chart — Comparisons

python
fig = px.bar(
    df,
    x="product",
    y="sales",
    color="category",
    barmode="group",       # "stack" for stacked bars
    title="Sales by Product"
)
st.plotly_chart(fig, use_container_width=True)

Scatter Plot — Relationships

python
fig = px.scatter(
    df,
    x="ad_spend",
    y="revenue",
    size="deals_closed",   # bubble size
    color="region",
    hover_name="salesperson",
    title="Ad Spend vs Revenue"
)
st.plotly_chart(fig, use_container_width=True)

Connecting Charts to Streamlit Widgets

This is where dashboards get useful. A chart that responds to a dropdown or date range is worth ten static ones. The pattern: get the user's selection from a widget, filter the dataframe, rebuild the chart.

python
import streamlit as st
import plotly.express as px
import pandas as pd

# Generate sample sales data
import numpy as np
np.random.seed(42)
dates = pd.date_range("2024-01-01", periods=90)
df = pd.DataFrame({
    "date": dates.tolist() * 3,
    "region": ["North"] * 90 + ["South"] * 90 + ["West"] * 90,
    "revenue": np.random.randint(3000, 12000, 270)
})

st.title("Sales Dashboard")

# Widget: region selector
regions = df["region"].unique().tolist()
selected = st.multiselect(
    "Select regions",
    options=regions,
    default=regions
)

# Filter data
filtered = df[df["region"].isin(selected)]

# Chart updates automatically when selection changes
if filtered.empty:
    st.warning("No regions selected.")
else:
    fig = px.line(
        filtered,
        x="date",
        y="revenue",
        color="region",
        title=f"Revenue — {', '.join(selected)}"
    )
    st.plotly_chart(fig, use_container_width=True)
💡
How Streamlit reruns work: Every time a user interacts with a widget, Streamlit reruns the entire script from top to bottom. That's why filtering before building the chart just works — you don't need event handlers or callbacks.

Customizing Chart Appearance

Plotly's default theme is functional but plain. Two quick improvements make charts look professional:

python
# Use a clean theme
fig = px.bar(df, x="month", y="revenue", template="plotly_white")

# Or set globally for the whole app
import plotly.io as pio
pio.templates.default = "plotly_white"

# Custom colors
fig = px.line(
    df, x="date", y="revenue",
    color_discrete_sequence=["#1e3a5f", "#c4873e", "#2a9d8f"]
)

# Remove gridlines, adjust margins
fig.update_layout(
    plot_bgcolor="white",
    yaxis=dict(showgrid=True, gridcolor="#f0f0f0"),
    margin=dict(l=20, r=20, t=40, b=20)
)

Side-by-Side Charts with Columns

Use st.columns() to put charts next to each other. This is how you build a real dashboard layout:

python
col1, col2 = st.columns(2)

with col1:
    fig1 = px.bar(df, x="month", y="revenue", title="Monthly Revenue")
    st.plotly_chart(fig1, use_container_width=True)

with col2:
    fig2 = px.pie(df, names="region", values="revenue", title="Revenue by Region")
    st.plotly_chart(fig2, use_container_width=True)

# Three-column layout
col1, col2, col3 = st.columns([2, 1, 1])  # col1 is twice as wide
📝 Day 2 Exercise
Build a 3-Chart Sales Dashboard

Use the sample data below (or your own CSV) to build a dashboard with three linked charts. All three should respond to the same region filter.

  1. Generate or load a dataframe with columns: date, region, revenue, units_sold.
  2. Add a st.selectbox for region selection at the top.
  3. Filter the dataframe based on the selection.
  4. Show a line chart (revenue over time) in the first column.
  5. Show a bar chart (units by month) in the second column.
  6. Add three st.metric() calls above the charts: total revenue, average revenue, and max single-day revenue.

Day 2 Summary

  • Plotly Express produces interactive charts in one line. Use px.line, px.bar, px.scatter for most cases.
  • Always pass use_container_width=True to st.plotly_chart().
  • Streamlit reruns on every widget interaction — filter your dataframe before building the chart and it updates automatically.
  • st.columns() puts charts side by side. Pass a list like [2,1] to control relative widths.
Challenge

Add a date range picker to your dashboard using st.date_input(). Filter the dataframe to only show data between the selected start and end dates. Combine it with the region filter so both apply at once.

Finished this lesson?