Why Streamlit for Analysts
Power BI and Tableau are excellent BI tools, but they have a hard ceiling: if your stakeholder wants something that Power BI can't do — custom ML predictions, dynamic SQL queries, API integrations — you're stuck. Streamlit removes that ceiling. If you can write it in Python, you can put it in a Streamlit app.
The key insight is that Streamlit re-runs your entire script top to bottom whenever a user interacts with a widget. This sounds inefficient but is actually elegant — your app logic stays in pure Python, with no callback hell, no state management boilerplate, and no JavaScript.
Streamlit is not a replacement for Power BI or Tableau — it's what you reach for when your analysis needs to become a product: a live tool that non-analysts can interact with, not just a static report they read once.
Setup and First App in 5 Minutes
pip install streamlit pandas plotly
# Create app.py:
import streamlit as st
import pandas as pd
import plotly.express as px
st.title("My First Data App")
st.write("Upload a CSV to explore your data.")
uploaded = st.file_uploader("Choose a CSV file", type="csv")
if uploaded:
df = pd.read_csv(uploaded)
st.dataframe(df.head(20))
st.write(f"Shape: {df.shape[0]} rows × {df.shape[1]} columns")
# Run with:
# streamlit run app.py
That's a fully functional file explorer in 12 lines of Python. Streamlit handles the HTTP server, file upload UI, and data rendering automatically.
KPI Dashboard: Metrics, Charts, Filters
Here's a realistic KPI dashboard structure for an e-commerce analyst:
import streamlit as st
import pandas as pd
import plotly.express as px
st.set_page_config(page_title="Sales Dashboard", layout="wide")
@st.cache_data # Cache data loading for performance
def load_data():
return pd.read_csv("sales.csv", parse_dates=["date"])
df = load_data()
# ── Sidebar filters ──
st.sidebar.header("Filters")
date_range = st.sidebar.date_input(
"Date range",
value=(df["date"].min(), df["date"].max())
)
categories = st.sidebar.multiselect(
"Category",
options=df["category"].unique(),
default=df["category"].unique()
)
# Apply filters
mask = (
(df["date"] >= pd.Timestamp(date_range[0])) &
(df["date"] <= pd.Timestamp(date_range[1])) &
(df["category"].isin(categories))
)
filtered = df[mask]
# ── KPI metrics row ──
col1, col2, col3, col4 = st.columns(4)
col1.metric("Total Revenue", f"${filtered['revenue'].sum():,.0f}", "+12%")
col2.metric("Orders", f"{filtered['orders'].sum():,}", "+8%")
col3.metric("Avg Order Value", f"${filtered['revenue'].mean():,.2f}", "+3%")
col4.metric("Customers", f"{filtered['customer_id'].nunique():,}", "+5%")
# ── Charts ──
st.subheader("Revenue Trend")
daily = filtered.groupby("date")["revenue"].sum().reset_index()
fig = px.line(daily, x="date", y="revenue", title="Daily Revenue")
st.plotly_chart(fig, use_container_width=True)
st.subheader("Top Categories")
cat_rev = filtered.groupby("category")["revenue"].sum().sort_values(ascending=True)
fig2 = px.bar(cat_rev, orientation="h")
st.plotly_chart(fig2, use_container_width=True)
@st.cache_data for data loading functions. Without it, Streamlit reloads the CSV on every user interaction, which kills performance for large datasets.Working with Real Data: SQL + Pandas
Streamlit integrates natively with SQLAlchemy, which means you can connect directly to PostgreSQL, BigQuery, or any other database your team uses:
import streamlit as st
import pandas as pd
from sqlalchemy import create_engine, text
# Store credentials in .streamlit/secrets.toml (never in code)
engine = create_engine(st.secrets["database"]["url"])
@st.cache_data(ttl=3600) # Refresh cache every hour
def run_query(sql: str) -> pd.DataFrame:
with engine.connect() as conn:
return pd.read_sql(text(sql), conn)
# Dynamic SQL based on user input
metric = st.selectbox("Metric", ["revenue", "orders", "customers"])
period = st.radio("Group by", ["day", "week", "month"])
query = f"""
SELECT
DATE_TRUNC('{period}', order_date) AS period,
SUM({metric}) AS value
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY 1
ORDER BY 1
"""
df = run_query(query)
st.line_chart(df.set_index("period")["value"])
Adding AI: Chat with Your Data
Streamlit 1.30+ includes st.chat_message and st.chat_input components that make it trivial to add LLM-powered chat to any data app:
import streamlit as st
import openai
client = openai.OpenAI(api_key=st.secrets["openai"]["api_key"])
if "messages" not in st.session_state:
st.session_state.messages = []
# Display chat history
for msg in st.session_state.messages:
with st.chat_message(msg["role"]):
st.write(msg["content"])
# User input
if prompt := st.chat_input("Ask about your data..."):
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.write(prompt)
# System context includes data summary
system = f"""You are a data analyst assistant.
The dataset has {len(df)} rows and columns: {', '.join(df.columns)}.
Summary statistics: {df.describe().to_string()}"""
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "system", "content": system}] +
st.session_state.messages
)
answer = response.choices[0].message.content
st.session_state.messages.append({"role": "assistant", "content": answer})
with st.chat_message("assistant"):
st.write(answer)
Deploying to Streamlit Cloud
Streamlit Cloud offers free hosting for public GitHub repositories. Deployment takes 3 steps:
- Push your
app.pyandrequirements.txtto GitHub - Go to share.streamlit.io → New app → select your repo
- Add secrets (database URLs, API keys) in the Secrets panel
Your app is live at yourusername-appname.streamlit.app in under 2 minutes. For private data, use Streamlit Community Cloud with private repos, or self-host on a VPS with Docker.
Streamlit vs Power BI vs Tableau
| Criteria | Streamlit | Power BI | Tableau |
|---|---|---|---|
| Learning curve | Low (Python) | Medium (DAX) | Medium (VizQL) |
| Custom logic | Unlimited (Python) | Limited (DAX) | Limited (calculated fields) |
| ML integration | Native | Via Python/R visual | Via TabPy |
| Collaboration | Git-based | Power BI Service | Tableau Server/Cloud |
| Cost | Free (Cloud free tier) | $10–20/user/month | $35–70/user/month |
| Best for | Custom data apps | Corporate BI | Data storytelling |
