Redirect Chapter 12: Interactive Apps with Streamlit | AI Fundamentals
← Back to Tutorials Chapter 12

Interactive Apps with Streamlit

Flask gives you total control but requires you to write HTML. Streamlit inverts that: you write plain Python, and Streamlit turns your script into a live web app with buttons, sliders, and charts automatically. It is the fastest way to let people interact with your models and data.

Building Web Apps with Streamlit

Install Streamlit, then run any script with streamlit run. Every time a widget changes, Streamlit re-runs the whole script from top to bottom — so your app is just a normal Python script.

pip install streamlit

st.write and Basic Widgets

st.write is the catch-all that displays text, data, or charts. Widgets like buttons, sliders, text inputs, and select boxes store the user's choice in a variable.

import streamlit as st

st.title("My First App")
name = st.text_input("What is your name?")
age = st.slider("Select your age", 0, 100, 25)
likes = st.radio("Favorite color", ["Red", "Blue", "Green"])

if st.button("Say hello"):
    st.write(f"Hello {name}, age {age}, you chose {likes}.")

Layout and Sidebar

Columns arrange content side by side, and st.sidebar moves widgets into a panel that stays visible as users scroll.

import streamlit as st
import pandas as pd

df = pd.DataFrame({"value": [3, 7, 2, 9, 4]})

with st.sidebar:
    bins = st.slider("Number of bins", 1, 20, 5)
    color = st.color_picker("Bar color", "#7c3aed")

col1, col2 = st.columns(2)
with col1:
    st.metric("Mean", round(df["value"].mean(), 2))
with col2:
    st.metric("Max", df["value"].max())

st.bar_chart(df, color=color)
st.write(f"Chart drawn with {bins} bins of color {color}.")
Streamlit re-runs the script on every interaction. Keep expensive work (loading models, reading files) behind @st.cache_data so it only happens once. The decorator remembers the result for the given inputs, which keeps the app fast as users tweak sliders.

Caching Expensive Work

import streamlit as st
import time

@st.cache_data
def load_big_file(path):
    time.sleep(2)          # simulate a slow read
    return [line.strip() for line in open(path)]

lines = load_big_file("words.txt")
st.write(f"Loaded {len(lines)} lines. First: {lines[0]}")

An Example ML App with Streamlit

The classic pattern: load a trained model, collect inputs with widgets, make a prediction, and display the result. This example uses a simple linear regression from scikit-learn that we train on the fly so the app runs anywhere.

import streamlit as st
import numpy as np
from sklearn.linear_model import LinearRegression

@st.cache_resource
def train_model():
    rng = np.random.default_rng(7)
    x = rng.uniform(0, 10, 200).reshape(-1, 1)
    y = 3 * x.ravel() + rng.normal(0, 1, 200)
    model = LinearRegression()
    model.fit(x, y)
    return model

st.title("House Price Estimator (demo)")
st.write("Enter the key features and get a prediction.")

size = st.number_input("Size (square meters)", min_value=20.0, max_value=400.0, value=80.0)
rooms = st.slider("Number of rooms", 1, 6, 3)
year = st.slider("Year built", 1950, 2025, 2005)

features = np.array([size + rooms, rooms, 2025 - year]).reshape(1, -1)

if st.button("Predict price"):
    model = train_model()
    # demo model actually uses only one feature; we show the pattern
    prediction = 1200 * size + 900 * rooms - 500 * (2025 - year)
    st.success(f"Estimated price: ${prediction:,.0f}")

with st.expander("How it works"):
    st.markdown("In a real project, `model.predict(features)` replaces the "
                "formula above. The model was trained on 200 synthetic "
                "samples and is cached with `@st.cache_resource`.")
Train once, serve many: Loading a model on every rerun is wasteful. @st.cache_resource keeps heavyweight objects (models, database connections) alive across reruns, while @st.cache_data caches plain data like DataFrames. Reserve a st.expander or st.markdown for explanations rather than crowding the UI.

Deploying a Streamlit App

  1. Put your app in a file like app.py and add a requirements.txt listing every import you use.
  2. Push the project to a GitHub repository.
  3. Sign in to Streamlit Community Cloud (share.streamlit.io) with GitHub, click "New app", pick the repo, branch, and file, and press Deploy.
  4. Streamlit builds the environment from requirements.txt and gives you a public URL like https://yourname-project-name.streamlit.app.
# requirements.txt
streamlit
numpy
pandas
scikit-learn
Before deploying: Do not hard-code secrets (API keys, database passwords) in your script. Use st.secrets to read them from the platform's secrets manager, and set PYTHONUNBUFFERED=1 in the cloud settings so logs stream properly.

Practice Exercise

Build an interactive data-explorer app:

  1. Let the user upload a CSV with st.file_uploader.
  2. Show a preview with st.dataframe and basic stats with df.describe().
  3. Let the user pick two numeric columns; plot them with st.scatter_chart.
  4. Show the correlation between the chosen columns with st.metric.
import streamlit as st
import pandas as pd

st.title("CSV Explorer")

uploaded = st.file_uploader("Choose a CSV file", type="csv")
if uploaded is not None:
    df = pd.read_csv(uploaded)
    st.dataframe(df.head(100))
    st.write(df.describe())

    numeric = df.select_dtypes(include="number").columns.tolist()
    if numeric:
        x = st.selectbox("X axis", numeric)
        y = st.selectbox("Y axis", numeric, index=min(1, len(numeric) - 1))
        st.scatter_chart(df[[x, y]])
        st.metric(f"Correlation ({x} vs {y})",
                  round(df[x].corr(df[y]), 3))
    else:
        st.info("No numeric columns found in this file.")
Stretch goal: Add a sidebar filter that lets the user restrict the chart to rows where one column exceeds a threshold (use a slider over that column's min and max). Then deploy the finished app to Streamlit Community Cloud and share the public URL with a classmate — you will have shipped a real interactive data tool in one sitting.