1: Gathering & Cleaning · 2: Cleaning & the Model · 3: Transformation · 4: Cube Operations · 5: Dashboard
Python and Streamlit. You need the database from Practice 3.
Last week you wrote four kinds of query: slice, dice, roll-up and drill-down. A dashboard is those same queries with controls on top, and several views of one slice on one page. Nothing new to learn about the warehouse — only how to put a front end on it.
Streamlit turns a Python script into a web page. You write ordinary Python; it draws the widgets.
pip install streamlit # already done on the lab machines streamlit run dashboard.py # opens in your browser
Everything on the page comes from one query. Load it once and keep it in memory, so moving a control does not hit the database again:
import sqlite3
import pandas as pd
import streamlit as st
DB = "warehouse/world_economy_multi.sqlite"
@st.cache_data
def load(indicator_cd):
sql = """
SELECT e.name AS country,
e.region AS region,
y.year AS year,
y.is_projection AS projected,
f.value AS value
FROM fact_observation f
JOIN dim_entity e ON e.entity_key = f.entity_key
JOIN dim_indicator i ON i.indicator_key = f.indicator_key
JOIN dim_year y ON y.year_key = f.year_key
WHERE i.indicator_cd = ?
AND e.entity_type = 'country'
AND e.region IS NOT NULL
"""
with sqlite3.connect(DB) as db:
return pd.read_sql_query(sql, db, params=[indicator_cd])@st.cache_data Streamlit re-runs the whole script every time you touch a control, so the query runs again and again. With it, the query runs once per indicator.INDICATORS = {
"Unemployment (%)": "UNEMPLOYMENT",
"Inflation (%)": "INFLATION_CPI",
"GDP per capita (PPP)": "GDP_PCAP_PPP",
}
st.title("World Economy Dashboard")
c1, c2, c3 = st.columns(3)
label = c1.selectbox("Indicator", list(INDICATORS))
df = load(INDICATORS[label])
# 2026 onwards are IMF projections and cover half as many
# countries, so keep them out of the picker.
actual = sorted(df[df.projected == 0].year.unique())
year = c2.selectbox("Year", actual, index=len(actual) - 1)
regions = ["All regions"] + sorted(df.region.unique())
region = c3.selectbox("Region", regions)
view = df[df.year == year] # slice
if region != "All regions":
view = view[view.region == region] # diceThose two lines are the slice and the dice from last week. The dropdowns just supply the values.
A dashboard is not one chart. It is several views that answer different questions about the same selection, and they all change together.
k1, k2, k3, k4 = st.columns(4)
by_region = view.groupby("region").value.mean().sort_values(ascending=False)
k1.metric("Average", f"{view.value.mean():.1f}")
k2.metric("Highest region", f"{by_region.iloc[0]:.1f}", by_region.index[0])
k3.metric("Lowest region", f"{by_region.iloc[-1]:.1f}", by_region.index[-1])
k4.metric("Countries", len(view))left, right = st.columns(2)
with left:
st.subheader("By region")
st.bar_chart(by_region, horizontal=True) # roll-up
with right:
st.subheader("Over time")
scope = df[df.projected == 0]
if region != "All regions":
scope = scope[scope.region == region]
st.line_chart(scope.groupby("year").value.mean())st.subheader("Countries")
if region == "All regions":
detail = view.nlargest(10, "value")[["country", "region", "value"]]
else:
detail = view.sort_values("value", ascending=False)[["country", "value"]]
st.dataframe(detail, hide_index=True, use_container_width=True)Add government debt to the INDICATORS dictionary. How much code did you have to change?
Add a fifth view: the three countries that changed most since 2015. You will need a second query, or a groupby on the data you already have.
Comment out @st.cache_data and change the year a few times. Does it feel slower? With 5,000 rows it probably does not — which is the point of the next section.
Your fact table has about 57,000 rows, so every query is instant and the dashboard feels fine. A real warehouse has millions. At that size the roll-up you run on every click becomes the slow part, and the answer is to compute it once and store it — a summary table.
That is a real technique, but it solves a problem you do not have yet. Build the dashboard first; add the summary table when it is slow.
Summary tables and performance. Making a slow warehouse fast, and measuring whether it worked.