Streamlit#
Maybe the most used freeware dashboard in Python.
Enormous choice of elements, widgets and extensions.
Can use several interactive graphics packages.
Can be run as a local app in a browser or in various other environments.
Create a .py file and run using the terminal command below in your favourite Python environment.
First time local usage prompts for an email address (press Enter if you do not want to supply it).
Code can be updated while the app is running.
Any action performed in the app triggers a rerun of the code.
streamlit run /path_to_your_streamlit_folder/appname.py
# Teacher's path to be used below in examples:
path_prefix = "/Users/kristian/Documents/GitHub/IND320/streamlit/"
Examples and documentation#
Basic concepts#
Streamlit apps rerun all Python code from top to bottom each time
a user interacts with any widget (like buttons, sliders, or text inputs), or
when the source code changes.
The session state is stored in st.session_state
Persistent across interactions.
Updated before the code is rerun.
Caching of data is important to achieve a responsive app.
Progress indicators are useful for large operations.
Static vs dynamic content#
Static content in Streamlit means fixed outputs—like Markdown, text, or images that do not change unless the code/script changes.
Dynamic content is interactive or data-driven—updates based on user input (widgets, forms), external files, or live data sources.
# static_dynamic.py
import streamlit as st
# Static Example
st.markdown("# Static Dashboard\nThis content won't change until the file is reloaded.")
# Dynamic Example
user_input = st.text_input("Type something:")
if user_input:
st.write(f"You entered: {user_input}")
file_name = "static_dynamic.py"
# !streamlit run {path_prefix}{file_name}
Magic vs explicit content#
Magic: Streamlit automatically displays objects, markdown, and charts on their own line, no function needed (“magic”).
Explicit: Using Streamlit functions like st.write, st.markdown, st.dataframe to control display.
# magic_explicit.py
# Magic
"**This shows with magic!**"
import pandas as pd
df = pd.DataFrame({'A': [1,2,3]})
df
# Explicit
st.write("**This shows with explicit command!**")
st.dataframe(df)
file_name = "magic_explicit.py"
# !streamlit run {path_prefix}{file_name}
Session state and on_click / on_event#
st.session_state persists variables across reruns, ideal for storing app state and counters.
st.session_state is automatically created, and we can extend and manipulate it.
on_click/on_change: Assign callback functions to widgets for event-driven updates.
# session_state.py
import streamlit as st
if 'counter' not in st.session_state:
st.session_state.counter = 0
def increment():
st.session_state.counter += 1
st.button("Increment", on_click=increment)
st.write(f"Button clicked {st.session_state.counter} times")
file_name = "session_state.py"
# !streamlit run {path_prefix}{file_name}
Reruns and caching#
Every interaction reruns the script top-to-bottom; avoid costly computations on every rerun.
Use @st.cache_data to store results of expensive operations.
# caching.py
import streamlit as st
@st.cache_data
def get_data():
import time; time.sleep(2) # Simulate expensive task
return [1, 2, 3]
st.write("Data:", get_data())
# Interactive part that costs very little compute time
if 'counter' not in st.session_state:
st.session_state.counter = 0
def increment():
st.session_state.counter += 1
st.button("Increment", on_click=increment)
st.write(f"Button clicked {st.session_state.counter} times")
file_name = "caching.py"
# !streamlit run {path_prefix}{file_name}
Exercise#
Create a streamlit app with a single button and a single output.
On first time startup:
The button should show the label “Start”.
The output should say “Ready”
When the button is pressed the first time:
A random integer between 1 and 100 is sampled and cached.
The button label is changed to “Next”.
The output should show the integer.
On subsequent button presses:
If the integer is even, divide it by 2 and update the output and cache.
If the integer is odd, multiply by 3 and add 1, then update the output and cache.
The Collatz conjecture says that after clicking the button a sufficient amount of times, the integer will reach 1, no matter what the starting point was.
Extra: Let the button say “Half it” and “Triple and add one” based on the current integer shown.
Widgets and interaction#
We will look at some basic widgets.
The full catalogue is too big for inclusion here.
Below:
slider (select_slider for a range),
selectbox (dropdown menu),
pills (toggle elements),
radiobuttons (select one alternative),
checkbox,
toggle (yes/no switch)
Also useful: text_input, text_area, date_input, time_input, …
# widgets.py
import streamlit as st
value = st.slider("Pick a value", 0, 100, value=24, step=1)
title = st.selectbox("Select title",
("Ms.", "Mrs.", "Mr.", "Dr.", "Prof.", "Lady", "Lord", "Dutchess", "Duke", "Queen", "King", "Master", "Mistress"))
area = st.pills("Select area", ["Ås", "Ski", "Drøbak", "Kroer", "Vestby"])
subject = st.radio("Choose a subject", ["Deployment", "Data Sources", "Data Quality", "Machine Learning"])
check = st.checkbox("Please, check")
active = st.toggle("Agree, or not?", value=True)
# Use st.session_state to make printout conditional
st.write("Chosen")
st.write(value, title, area, subject, check, active)
file_name = "widgets.py"
# !streamlit run {path_prefix}{file_name}
Layout#
Streamlit apps can be partitioned and layered in various ways.
Below:
columns (vertical containers),
expander (hidden information),
tabs (layers of elements on the same page)
import streamlit as st
left, right = st.columns(2, border=True)
with left:
st.write("This is the left column")
expander = st.expander("Soo secret")
expander.write('''
This is an explanation that is hidden until you click the expander.
''')
with right:
tabA, tabB = st.tabs(["Tab A", "Tab B"])
tabA.subheader("This is tab A")
tabA.write("You can put any elements in a tab")
tabB.subheader("This is tab B")
tabB.write("You can put any elements in a tab, also here")
file_name = "layout.py"
# !streamlit run {path_prefix}{file_name}
Storing keys and passwords#
A streamlit app may be dependent on login credentials or similar to interact with the world.
Locally one can store secrets in .streamlit/secrets.toml
Exclude these from the GitHub sync using .gitignore!!
For apps at streamlit.app, the secrets must be copied into the right place.
import streamlit as st
# Assume secrets.toml has a section called
# [api]
# where the secret is stored after
# key =
st.write("API Key:", st.secrets["api"]["key"])
file_name = "secrets.py"
# !streamlit run {path_prefix}{file_name}
Configuration#
An optional file named config.toml can also be put in the .streamlit directory.
Some options that can be controlled:
the appeareance of the app (theme, colours, element visibility, …),
warnings, exceptions and deprecations that will be shown to the users,
event logging,
automatic reruns on code change,
server-side options, etc.
Exercise#
Continue on the previous exercise.
If the user has pressed the button 20 times without reaching 1, pop up a dialog asking if they really want to continue.
Look at the documentation for st.dialog() to figure out out to do this (notice, especially the example at the bottom).
See also