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.
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.
pip install plotly
streamlit package, Plotly may already be available. Run python -c "import plotly; print(plotly.__version__)" to check.The pattern is always the same: create a figure with Plotly, then render it with st.plotly_chart(). Here's the simplest possible example:
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.
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)
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)
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)
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.
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)
Plotly's default theme is functional but plain. Two quick improvements make charts look professional:
# 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)
)
Use st.columns() to put charts next to each other. This is how you build a real dashboard layout:
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
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.
date, region, revenue, units_sold.st.selectbox for region selection at the top.st.metric() calls above the charts: total revenue, average revenue, and max single-day revenue.px.line, px.bar, px.scatter for most cases.use_container_width=True to st.plotly_chart().st.columns() puts charts side by side. Pass a list like [2,1] to control relative widths.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.