Lesson 12 · Python for Data Analysts
Building a Streamlit Data App
Everything you need to build a real, interactive Streamlit dashboard: widgets, layout, charts, caching, and running the finished app. No prior Streamlit…
- CoursePython for Data Analysts
- Lesson12 of 12
- Video20 min
- FormatJupyter notebook · 13 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbBuilding a Streamlit Data App#
- Everything you need to build a real, interactive Streamlit dashboard: widgets, layout, charts, caching, and running the finished app.
- No prior Streamlit experience needed. Let's get straight into it.
Before You Start#
- Open a new Jupyter Notebook in VS Code and select your Python interpreter as the kernel.
- If streamlit isn't installed yet, open a terminal in VS Code and run: pip install streamlit
Part 1: Why We Build a File, Not Notebook Cells#
Streamlit Apps Are Scripts, Not Cells#
- A Streamlit app is a single Python script that Streamlit re-runs top to bottom every time you interact with a widget.
- Calling Streamlit functions directly inside a notebook cell doesn't raise an error, but it also doesn't render anything useful; there's no running app around it.
- Instead, we'll write genuine Streamlit code into app.py using regular file writes, then launch it properly from a terminal.
with open('app.py', 'w') as f:
f.write('# Sales Dashboard App\n')
f.write('# Generated step by step throughout this lesson\n\n')
print('app.py created')
Part 2: Page Setup and Text#
page_setup = '''import streamlit as st
import pandas as pd
import numpy as np
st.set_page_config(page_title='Sales Dashboard', layout='wide')
st.title('Sales Dashboard')
st.write('An interactive view of synthetic regional sales data.')
'''
with open('app.py', 'a') as f:
f.write(page_setup)
print('Page setup written')
Part 3: Widgets#
widgets_code = '''
st.sidebar.header('Filters')
user_name = st.sidebar.text_input('Your name', value='Analyst')
min_amount = st.sidebar.slider('Minimum order amount ($)', 0, 300, 50)
region_choice = st.sidebar.selectbox('Region', ['All', 'North', 'South', 'East', 'West'])
show_raw = st.sidebar.checkbox('Show raw data table')
st.sidebar.write(f'Hello, {user_name}!')
'''
with open('app.py', 'a') as f:
f.write(widgets_code)
print('Widgets written')
Part 4: Displaying Data#
data_code = '''
@st.cache_data
def load_sales_data():
rng = np.random.default_rng(seed=11)
regions = ['North', 'South', 'East', 'West']
rows = []
for _ in range(200):
rows.append({
'region': rng.choice(regions),
'product': rng.choice(['Mouse', 'Keyboard', 'Monitor', 'Webcam']),
'amount': round(float(rng.uniform(10, 300)), 2),
})
return pd.DataFrame(rows)
sales = load_sales_data()
'''
with open('app.py', 'a') as f:
f.write(data_code)
print('Data loading written')
filter_and_display_code = '''
filtered = sales[sales['amount'] >= min_amount]
if region_choice != 'All':
filtered = filtered[filtered['region'] == region_choice]
st.metric('Orders shown', len(filtered))
st.metric('Total revenue', f"${filtered['amount'].sum():,.2f}")
if show_raw:
st.dataframe(filtered)
'''
with open('app.py', 'a') as f:
f.write(filter_and_display_code)
print('Filtering and display written')
Part 5: Charts#
charts_code = '''
st.subheader('Revenue by Region')
region_totals = filtered.groupby('region')['amount'].sum()
st.bar_chart(region_totals)
st.subheader('Order Amount Distribution')
amount_counts = filtered['amount'].round(-1).value_counts().sort_index()
st.line_chart(amount_counts)
'''
with open('app.py', 'a') as f:
f.write(charts_code)
print('Charts written')
Part 6: Layout#
columns_code = '''
st.subheader('Regional Comparison')
col1, col2, col3, col4 = st.columns(4)
for col, region in zip([col1, col2, col3, col4], ['North', 'South', 'East', 'West']):
region_total = filtered[filtered['region'] == region]['amount'].sum()
col.metric(region, f'${region_total:,.0f}')
'''
with open('app.py', 'a') as f:
f.write(columns_code)
print('Columns layout written')
tabs_code = '''
tab1, tab2 = st.tabs(['Summary', 'About'])
with tab1:
st.write(f'Showing {len(filtered)} orders totaling ${filtered["amount"].sum():,.2f}.')
with tab2:
st.write('This dashboard was built entirely in Python using Streamlit, pandas, and numpy.')
'''
with open('app.py', 'a') as f:
f.write(tabs_code)
print('Tabs written')
Part 7: Caching#
cache_note_code = '''
st.sidebar.divider()
if st.sidebar.button('Clear cached data'):
load_sales_data.clear()
st.sidebar.write('Cache cleared, data will reload on next run.')
'''
with open('app.py', 'a') as f:
f.write(cache_note_code)
print('Cache control written')
Part 8: Running the App#
import py_compile
py_compile.compile('app.py', doraise=True)
print('app.py is valid, runnable Python')
with open('app.py') as f:
contents = f.read()
print(contents)
Launching It For Real#
- Open a terminal in VS Code, in the same folder as app.py.
- Run: streamlit run app.py
- Streamlit opens a browser tab automatically; the sidebar filters, metrics, charts, columns, and tabs all become fully interactive.
- Press Ctrl+C in the terminal to stop the app when you're done.
Capstone Project: Final Polish#
download_code = '''
st.sidebar.divider()
csv_data = filtered.to_csv(index=False).encode('utf-8')
st.sidebar.download_button(
label='Download filtered data as CSV',
data=csv_data,
file_name='filtered_sales.csv',
mime='text/csv',
)
st.divider()
st.caption('Built with Streamlit, pandas, and numpy.')
'''
with open('app.py', 'a') as f:
f.write(download_code)
print('Download button and footer written')
py_compile.compile('app.py', doraise=True)
with open('app.py') as f:
final_line_count = len(f.readlines())
print(f'app.py is valid and complete: {final_line_count} lines')
Wrap-Up: What You Learned#
- Why Streamlit apps are scripts, not notebook cells, and building app.py progressively as a real file.
- Page setup, titles, and text with set_page_config, title, and write.
- Interactive widgets: text_input, slider, selectbox, checkbox, and button.
- Displaying data with metric and dataframe.
- Charts with bar_chart and line_chart.
- Layout with columns and tabs.
- Caching with @st.cache_data, and clearing it on demand.
- Running the finished app for real with streamlit run.
- A capstone polish adding a live download button and a footer.
- You went from an empty file to a complete, interactive dashboard in one sitting. If you want the next build to land in your feed automatically, subscribing is the move see you in the next one.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



