Lý thuyết
Bài 10/14

Streamlit - Build Data Apps

Xây dựng Data Apps và Dashboards với Streamlit

Streamlit - Build Data Apps

1. Giới thiệu Streamlit

Streamlit biến Python scripts thành web apps chỉ trong vài phút!

FeatureStreamlit
Học dễ⭐⭐⭐⭐⭐ Cực dễ
No frontend✅ Chỉ cần Python
Hot reload✅ Auto refresh
Widgets✅ Buttons, sliders, inputs
Charts✅ Plotly, Matplotlib, Altair
Deploy✅ Streamlit Cloud (free)
Bash
1# Cài đặt
2pip install streamlit
3
4# Chạy app
5streamlit run app.py

2. Hello World App

Python
1# app.py
2import streamlit as st
3
4st.title("Hello Streamlit! 👋")
5st.write("This is my first Streamlit app")
6
7# Text elements
8st.header("This is a header")
9st.subheader("This is a subheader")
10st.text("Fixed width text")
11st.markdown("**Bold** and *italic* text")
12st.caption("Small caption text")
13
14# Code
15st.code("print('Hello World')", language="python")
16
17# LaTeX
18st.latex(r"E = mc^2")

3. Input Widgets

3.1 Text Input

Python
1import streamlit as st
2
3# Text input
4name = st.text_input("Enter your name", "MinAI")
5st.write(f"Hello, {name}!")
6
7# Text area
8description = st.text_area("Description", "Enter text here...")
9
10# Number input
11age = st.number_input("Age", min_value=0, max_value=120, value=25)
12
13# Password
14password = st.text_input("Password", type="password")

3.2 Selection Widgets

Python
1# Selectbox
2option = st.selectbox(
3 "Choose a color",
4 ["Red", "Green", "Blue"]
5)
6
7# Multiselect
8options = st.multiselect(
9 "Select fruits",
10 ["Apple", "Banana", "Cherry", "Date"],
11 ["Apple", "Banana"] # Default
12)
13
14# Radio
15choice = st.radio(
16 "Pick one",
17 ["Option 1", "Option 2", "Option 3"]
18)
19
20# Checkbox
21agree = st.checkbox("I agree to terms")
22if agree:
23 st.write("Thanks for agreeing!")

3.3 Sliders và Date Input

Python
1# Slider
2value = st.slider("Select value", 0, 100, 50)
3
4# Range slider
5values = st.slider("Select range", 0.0, 100.0, (25.0, 75.0))
6
7# Date input
8date = st.date_input("Select date")
9
10# Time input
11time = st.time_input("Select time")
12
13# Color picker
14color = st.color_picker("Pick a color", "#00f900")

3.4 Buttons

Python
1# Button
2if st.button("Click me!"):
3 st.write("Button clicked!")
4
5# Download button
6st.download_button(
7 label="Download CSV",
8 data="col1,col2\n1,2\n3,4",
9 file_name="data.csv",
10 mime="text/csv"
11)
12
13# File uploader
14uploaded_file = st.file_uploader("Choose a file", type=["csv", "xlsx"])
15if uploaded_file:
16 df = pd.read_csv(uploaded_file)
17 st.dataframe(df)

4. Display Data

4.1 DataFrames

Python
1import streamlit as st
2import pandas as pd
3import numpy as np
4
5# Sample data
6df = pd.DataFrame({
7 "Name": ["Alice", "Bob", "Charlie"],
8 "Age": [25, 30, 35],
9 "Salary": [50000, 60000, 70000]
10})
11
12# Display as static table
13st.table(df)
14
15# Display as interactive dataframe
16st.dataframe(df)
17
18# Editable dataframe
19edited_df = st.data_editor(df)
20
21# With styling
22st.dataframe(df.style.highlight_max(axis=0))
23
24# Metrics
25col1, col2, col3 = st.columns(3)
26col1.metric("Revenue", "$10,000", "+5%")
27col2.metric("Users", "1,234", "-2%")
28col3.metric("Rating", "4.5", "+0.2")

4.2 Charts

Python
1import streamlit as st
2import pandas as pd
3import numpy as np
4
5# Sample data
6chart_data = pd.DataFrame(
7 np.random.randn(20, 3),
8 columns=["A", "B", "C"]
9)
10
11# Line chart
12st.line_chart(chart_data)
13
14# Area chart
15st.area_chart(chart_data)
16
17# Bar chart
18st.bar_chart(chart_data)
19
20# Scatter chart (Streamlit native)
21st.scatter_chart(chart_data, x="A", y="B")

4.3 Plotly Charts

Python
1import streamlit as st
2import plotly.express as px
3
4# Plotly charts
5df = px.data.gapminder().query("year == 2007")
6fig = px.scatter(df, x="gdpPercap", y="lifeExp",
7 color="continent", size="pop",
8 hover_name="country", log_x=True)
9
10st.plotly_chart(fig, use_container_width=True)

4.4 Matplotlib/Seaborn

Python
1import streamlit as st
2import matplotlib.pyplot as plt
3import seaborn as sns
4
5# Matplotlib
6fig, ax = plt.subplots()
7ax.plot([1, 2, 3, 4], [1, 4, 2, 3])
8ax.set_title("Simple Plot")
9st.pyplot(fig)
10
11# Seaborn
12tips = sns.load_dataset("tips")
13fig, ax = plt.subplots()
14sns.histplot(tips["total_bill"], ax=ax)
15st.pyplot(fig)

5. Layout

5.1 Columns

Python
1import streamlit as st
2
3# Equal columns
4col1, col2, col3 = st.columns(3)
5
6with col1:
7 st.header("Column 1")
8 st.write("Content here")
9
10with col2:
11 st.header("Column 2")
12 st.image("https://picsum.photos/200")
13
14with col3:
15 st.header("Column 3")
16 st.button("Click")
17
18# Custom widths
19col1, col2 = st.columns([2, 1]) # 2:1 ratio

5.2 Tabs

Python
1tab1, tab2, tab3 = st.tabs(["📈 Chart", "🗃 Data", "📝 About"])
2
3with tab1:
4 st.header("Charts")
5 st.line_chart([1, 2, 3, 4])
6
7with tab2:
8 st.header("Data")
9 st.dataframe(df)
10
11with tab3:
12 st.header("About")
13 st.write("This is the about section")

5.3 Expander và Container

Python
1# Expander
2with st.expander("Click to expand"):
3 st.write("Hidden content here")
4 st.image("https://picsum.photos/300")
5
6# Container
7with st.container():
8 st.write("This is inside a container")
9
10# Empty placeholder
11placeholder = st.empty()
12placeholder.text("This will be replaced")
13placeholder.write("New content!")

5.4 Sidebar

Python
1# Sidebar
2st.sidebar.title("Settings")
3option = st.sidebar.selectbox("Select option", ["A", "B", "C"])
4value = st.sidebar.slider("Value", 0, 100, 50)
5
6# With form
7with st.sidebar.form("my_form"):
8 name = st.text_input("Name")
9 submitted = st.form_submit_button("Submit")
10 if submitted:
11 st.write(f"Hello {name}")

6. State Management

Python
1import streamlit as st
2
3# Session state
4if 'count' not in st.session_state:
5 st.session_state.count = 0
6
7# Increment button
8if st.button('Increment'):
9 st.session_state.count += 1
10
11st.write(f"Count: {st.session_state.count}")
12
13# Reset button
14if st.button('Reset'):
15 st.session_state.count = 0

7. Caching

Python
1import streamlit as st
2import pandas as pd
3
4# Cache data (không chạy lại khi có input khác thay đổi)
5@st.cache_data
6def load_data(url):
7 """Load data - chỉ chạy 1 lần"""
8 return pd.read_csv(url)
9
10# Cache resource (database connections, ML models)
11@st.cache_resource
12def load_model():
13 """Load ML model - chỉ chạy 1 lần"""
14 import pickle
15 with open("model.pkl", "rb") as f:
16 return pickle.load(f)
17
18# Sử dụng
19df = load_data("data.csv") # Cached!
20model = load_model() # Cached!

8. Complete Dashboard Example

Python
1# dashboard.py
2import streamlit as st
3import pandas as pd
4import plotly.express as px
5
6# Page config
7st.set_page_config(
8 page_title="Sales Dashboard",
9 page_icon="📊",
10 layout="wide"
11)
12
13# Title
14st.title("📊 Sales Dashboard")
15st.markdown("---")
16
17# Load data
18@st.cache_data
19def load_data():
20 # Sample data
21 return pd.DataFrame({
22 'Date': pd.date_range('2024-01-01', periods=100),
23 'Sales': np.random.randint(100, 1000, 100),
24 'Region': np.random.choice(['North', 'South', 'East', 'West'], 100),
25 'Product': np.random.choice(['A', 'B', 'C'], 100)
26 })
27
28df = load_data()
29
30# Sidebar filters
31st.sidebar.header("Filters")
32regions = st.sidebar.multiselect(
33 "Select Region",
34 options=df['Region'].unique(),
35 default=df['Region'].unique()
36)
37products = st.sidebar.multiselect(
38 "Select Product",
39 options=df['Product'].unique(),
40 default=df['Product'].unique()
41)
42
43# Filter data
44df_filtered = df[
45 (df['Region'].isin(regions)) &
46 (df['Product'].isin(products))
47]
48
49# KPIs
50col1, col2, col3, col4 = st.columns(4)
51col1.metric("Total Sales", f"${df_filtered['Sales'].sum():,.0f}")
52col2.metric("Avg Sales", f"${df_filtered['Sales'].mean():,.0f}")
53col3.metric("Max Sales", f"${df_filtered['Sales'].max():,.0f}")
54col4.metric("Transactions", f"{len(df_filtered):,}")
55
56st.markdown("---")
57
58# Charts
59col1, col2 = st.columns(2)
60
61with col1:
62 st.subheader("Sales by Region")
63 fig = px.pie(df_filtered, values='Sales', names='Region', hole=0.4)
64 st.plotly_chart(fig, use_container_width=True)
65
66with col2:
67 st.subheader("Sales Trend")
68 daily_sales = df_filtered.groupby('Date')['Sales'].sum().reset_index()
69 fig = px.line(daily_sales, x='Date', y='Sales')
70 st.plotly_chart(fig, use_container_width=True)
71
72# Data table
73st.subheader("Raw Data")
74st.dataframe(df_filtered, use_container_width=True)
75
76# Download
77csv = df_filtered.to_csv(index=False)
78st.download_button("Download CSV", csv, "sales_data.csv", "text/csv")

9. Deploy to Streamlit Cloud

9.1 Chuẩn bị files

Text
1my_app/
2├── app.py # Main app
3├── requirements.txt # Dependencies
4└── .streamlit/
5 └── config.toml # Config (optional)

9.2 requirements.txt

Text
1streamlit
2pandas
3plotly
4numpy

9.3 Deploy

  1. Push code lên GitHub
  2. Vào share.streamlit.io
  3. Connect GitHub repo
  4. Select app.py
  5. Click "Deploy"

10. Best Practices

Python
1# 1. Use page config
2st.set_page_config(page_title="My App", layout="wide")
3
4# 2. Cache expensive operations
5@st.cache_data
6def load_data():
7 return pd.read_csv("large_file.csv")
8
9# 3. Use session state for persistence
10if 'initialized' not in st.session_state:
11 st.session_state.initialized = True
12
13# 4. Organize with containers
14with st.container():
15 st.header("Section 1")
16
17# 5. Use forms for multiple inputs
18with st.form("my_form"):
19 name = st.text_input("Name")
20 age = st.number_input("Age")
21 submitted = st.form_submit_button("Submit")
22
23# 6. Progress bars for long operations
24with st.spinner("Loading..."):
25 time.sleep(2)
26
27progress = st.progress(0)
28for i in range(100):
29 progress.progress(i + 1)

Tổng Kết

Trong bài này, bạn đã học:

  • ✅ Streamlit basics và cài đặt
  • ✅ Input widgets: text, select, slider, button
  • ✅ Display data: tables, charts
  • ✅ Layout: columns, tabs, sidebar
  • ✅ State management và caching
  • ✅ Build complete dashboard
  • ✅ Deploy to Streamlit Cloud

Bài tiếp theo: Exploratory Data Analysis (EDA)!