Exercises: Streamlit Dashboards

Install: pip install streamlit pandas plotly. Run apps with streamlit run app.py from the terminal, not from Jupyter.


Part A: Conceptual (6 problems)

A.1 ★☆☆ | Recall

Describe Streamlit's execution model in one sentence.

GuidanceA Streamlit app is a Python script that re-runs from top to bottom on every user interaction.

A.2 ★☆☆ | Recall

What is the difference between @st.cache_data and @st.cache_resource?

Guidance`cache_data` is for serializable data (DataFrames, lists, dicts). It deep-copies the result, making it safe for later mutation. `cache_resource` is for non-serializable objects (database connections, ML models). It returns the same object reference, which is necessary for connection pools and stateful objects.

A.3 ★★☆ | Understand

Why does Streamlit need caching, and what happens without it?

GuidanceWithout caching, every widget interaction re-runs the entire script including expensive operations (data loading, model training, API calls). The app becomes unresponsive. Caching stores the output of expensive functions and returns the cached value on subsequent calls with the same arguments, so only the cheap code runs on each interaction.

A.4 ★★☆ | Understand

When should you use st.session_state instead of a local variable?

GuidanceLocal variables reset on every re-run. `session_state` persists across re-runs for the user's session. Use session_state for: counters, multi-step workflows, persistent selections, form values, and anything that needs to survive across widget interactions.

A.5 ★★★ | Analyze

The chapter's threshold concept is "apps are scripts." How is this different from a traditional web framework like Flask?

GuidanceFlask has event handlers, routes, and component lifecycles. You write `@app.route("/path")` for a URL handler, `@app.before_request` for setup, etc. Streamlit has none of these. It is a plain Python script that re-runs top-to-bottom. The benefit is massively lower cognitive overhead; the cost is that complex interactivity (cross-filtering, real-time updates) is harder than in callback-based frameworks like Dash.

A.6 ★★★ | Evaluate

When should you choose Dash over Streamlit for a project?

GuidanceChoose Dash when: (1) you need cross-filtering between multiple charts, (2) you have many interactive controls with complex dependencies, (3) you need custom CSS styling beyond Streamlit's theme system, (4) the app has high concurrency requirements and you need enterprise scaling. Streamlit is faster to build and easier to learn, so default to Streamlit unless these specific needs arise.

Part B: Applied (10 problems)

B.1 ★☆☆ | Apply

Create a minimal Streamlit app that displays a title and a DataFrame.

Guidance
# app.py
import streamlit as st
import pandas as pd

st.title("My App")
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
st.dataframe(df)
Run with `streamlit run app.py`.

B.2 ★☆☆ | Apply

Add a sidebar with a slider controlling the number of rows shown.

Guidance
n = st.sidebar.slider("Rows", 1, 100, 10)
st.dataframe(df.head(n))

B.3 ★★☆ | Apply

Add caching to a data-loading function with @st.cache_data.

Guidance
@st.cache_data
def load_data():
    return pd.read_csv("data.csv")

df = load_data()

B.4 ★★☆ | Apply

Create a three-column layout with KPI metrics.

Guidance
col1, col2, col3 = st.columns(3)
col1.metric("Revenue", "$1.2M", "+15%")
col2.metric("Users", "45,678", "+7%")
col3.metric("Conversion", "3.4%", "-0.2%")

B.5 ★★☆ | Apply

Embed a Plotly chart that updates based on a selectbox.

Guidance
import plotly.express as px

col = st.selectbox("Column", df.columns)
fig = px.histogram(df, x=col)
st.plotly_chart(fig, use_container_width=True)

B.6 ★★☆ | Apply

Create a multi-tab layout with three tabs: Overview, Details, Raw Data.

Guidance
tab1, tab2, tab3 = st.tabs(["Overview", "Details", "Raw Data"])
with tab1:
    st.write("Summary")
with tab2:
    st.write("Details")
with tab3:
    st.dataframe(df)

B.7 ★★★ | Apply

Use st.session_state to build a counter that increments on button click.

Guidance
if "count" not in st.session_state:
    st.session_state.count = 0
if st.button("Increment"):
    st.session_state.count += 1
st.write(f"Count: {st.session_state.count}")

B.8 ★★☆ | Apply

Add a st.download_button to export a filtered DataFrame as CSV.

Guidance
st.download_button(
    "Download CSV",
    filtered.to_csv(index=False),
    file_name="data.csv",
    mime="text/csv",
)

B.9 ★★☆ | Apply

Use st.form to batch several widgets with a submit button.

Guidance
with st.form("my_form"):
    name = st.text_input("Name")
    age = st.number_input("Age", 0, 120)
    submitted = st.form_submit_button("Submit")
if submitted:
    st.write(f"Hello, {name} ({age})")

B.10 ★★★ | Create

Build a complete climate dashboard with sidebar filters (date range, variable selection), a Plotly line chart, KPI metrics, and a download button.

Guidance Use the progressive-project skeleton from Section 29.12 of the chapter. About 80 lines of Python, producing a full dashboard with data loading, filtering, charting, metrics, and export.

Part C: Synthesis (4 problems)

C.1 ★★★ | Analyze

You have a dashboard that re-runs 30 seconds on every interaction. Profile it and determine which part is slow, then apply caching.

Guidance Use `%time` or `time.time()` around each major step. Typically the culprit is data loading or an expensive transformation. Wrap the slow function with `@st.cache_data` (or `@st.cache_resource` if it produces an unserializable object). Verify that subsequent interactions are fast.

C.2 ★★★ | Evaluate

A colleague has built a Streamlit app with all its data loading at the top of the script without caching. The app takes 45 seconds per interaction. What is your fix?

Guidance Wrap the data loading in a `@st.cache_data`-decorated function. This alone usually solves the problem. If the data is truly too large to cache, consider pre-aggregating before loading or using a smaller subset for the dashboard.

C.3 ★★★ | Create

Deploy a Streamlit app to Streamlit Community Cloud. Document the steps in a README.md.

Guidance Steps: (1) create a GitHub repo with `app.py` and `requirements.txt`; (2) go to share.streamlit.io; (3) click "New app" and connect the repo; (4) specify the main file; (5) wait for build; (6) share the URL. Document each step with screenshots for the README.

C.4 ★★★ | Evaluate

Streamlit's re-run model is both a strength and a limitation. Discuss when it helps and when it hurts.

Guidance **Helps**: gentle learning curve (no callbacks to understand), linear code (top-to-bottom mental model), good for exploration (change something, see the result). **Hurts**: every interaction re-runs everything (slow without caching), stateful apps are awkward (session_state everywhere), complex dependencies are implicit (hard to see which widget affects which chart). For simple dashboards, the help outweighs the hurt. For complex dashboards, Dash's explicit callbacks become the better choice.

Chapter 30 introduces Dash, the main alternative to Streamlit with a different execution model.