import streamlit as st
st.title("Saying Hello.")
name = st.text_input("And you are?")
if name:
st.write(f"Hello, {name}!")2. Creating simple web apps with Streamlit
In this tutorial we will learn basic usage of https://docs.streamlit.io/get-started/fundamentals/main-concepts.
To do this tutorial you will need streamlit installed in your conda environment. To do that:
Open a terminal (from in VS Code, click “Terminal” -> “New Terminal”).
Activate your
ist356conda environment by running:conda activate ist356Install
streamlitby either running:pip install streamlitor:
conda install -c conda-forge -y streamlit
What is Streamlit?
Streamlit markets itself as a User Interface library for building simple web applications from Python scripts.
Build:
- Interactive dashboard with tables, charts and graphs
- Accepting user input for a data pipeline
- Chat applications
- and more!
The best part of streamlit is the application runs in a browser and you don’t need to learn front-end technologies like HTML, CSS and Javascript
How does it work?
To illustrate how streamlit works, here is a simple Python script that uses the Streamlit library:
To test this:
Create a file called
hello-ui.pyusing VS Code (Click “File -> New File”) and paste the above code into it.Save the file (File -> Save, or CTRL/CMD + S).
Open a terminal (in VS Code, Terminal -> New Terminal). If your
ist356environment is not active, activate it by runningconda activate ist356.Now run:
python -m streamlit run hello-ui.pyWhen you run the script, Streamlit launches a webserver on your computer to run your app; your default web browser will automatically open with the simple website Streamlit created.
If you edit the
hello-ui.pyfile, streamlit will automatically detect the changes when the changes are saved. If you re-do the interaction (in this case, adding a name and hitting Enter), the new code will be executed. Try it! Add a waving emoji by adding:wave:before theHelloin thest.write.The app will continue to run in the browser. You can stop it by first hitting CTRL+C in the terminal, then closing the browser tab.
Interactions
Streamlit supports both linear and event-driven interactions.
Linear style
With linear interactions the code runs from top-down each time the input changes.
The linear pattern is the simpler pattern.
The most effective way to use of this pattern is:
- setup widgets, saving their state in variables
- then check interations through the variables with if
An example:
import streamlit as st
st.title("Streamlit Interaction: linear")
# setup
name = st.text_input("Who are you?")
hi_clicked = st.button('Say Hi!')
clear_clicked = st.button('Clear')
# interactions
if hi_clicked:
if name:
st.success(f"Hello, {name}", icon="👍")
else:
st.error(f"I can't say hello, if you don't tell me your name!", icon="💣")
if clear_clicked:
name = None Event-driven style
With event-driven interactions, you write a function to handle the event. This is similar to how most other UI libraries work.
The event-driven pattern is more complex, and might have unexpected behaviors due to streamlit’s processing order!
The most effective use of this pattern is to:
- create handler functions with def
- setup interactions, using the function on the event
Example:
import streamlit as st
def hi_click():
if name:
st.success(f"Hello, {name}", icon="👍")
else:
st.error(f"I can't say hello, if you don't tell me your name!", icon="💣")
def clear_click():
name = None
# setup
st.title("Streamlit Interaction: event-driven")
name = st.text_input("Who are you?")
st.button('Say Hi!', on_click=hi_click)
st.button('Clear', on_click=clear_click)Session State: Helping Streamlit Remember values
st.session_state is a global key/value store for data that need to persist between streamlit runs.
Any data dependent on a previous interaction would be a use case for this.
The pattern using session state is:
- initialize the session state
- create the widgets
- check the interactions that change the state
- display the widgets that update the state
The session state is necessary to store persistent data. For example, the following will not work:
Wrong way:
import streamlit as st
# Streamlit is always running, so only do this will not do what you think
count = 0
# widget setup
st.title('Counter Example: Wrong')
st.write("variables that change based on previous runs will not work as expected ")
st.write("this is because streamlit runs all this code with each interaction")
incr_clicked = st.button('increment counter', type='primary')
reset_clicked = st.button('reset counter', type='secondary')
# interactions
if reset_clicked:
count = 0
elif incr_clicked:
count = count + 1
# display session state, after interations
st.write(f'Button clicked {count} times')Why not? (Try it!)
However, this will work:
Right way:
import streamlit as st
# Streamlit is always running, so only do this when count is not in session_state
# initialize
if 'count' not in st.session_state:
st.session_state.count = 0
# widget setup
st.title('Counter Example: Session State')
st.write("variables that change based on previous runs need session state")
st.write("`st.session_state` preserves the values of the variable between runs")
incr_clicked = st.button('increment counter', type='primary')
reset_clicked = st.button('reset counter', type='secondary')
# interactions
if reset_clicked:
st.session_state.count = 0
elif incr_clicked:
st.session_state.count = st.session_state.count + 1
# display session state, after interations
st.write(f'Button clicked {st.session_state.count} times')Exploring Streamlit input widgets
Streamlit offers a number of different widgets for user input, beyond the text input highlighted above. The following code highlights them:
import streamlit as st
from datetime import datetime
st.title('Streamlit Input Widgets!')
st.markdown("## Text Inputs")
txt = st.text_input('Enter your name:', value='John Doe')
st.text(f"OUTPUT: {txt}, type: {type(txt)}")
pw = st.text_input('Enter your password:', type="password")
st.text(f"OUTPUT: {pw}, type: {type(pw)}")
txta = st.text_area('Leave a comment:', value='Type here...')
st.text(f"OUTPUT: {txta}, type: {type(txta)}")
st.divider()
st.markdown("## Binary Widgets")
chk = st.checkbox('I agree to the terms and conditions', value=False)
st.text(f"OUTPUT: {chk}, type: {type(chk)}")
tog = st.toggle('Enable notifications', value=False)
st.text(f"OUTPUT: {tog}, type: {type(tog)}")
st.divider()
st.markdown("## Date / Time Widgets")
dt =st.date_input('Select a date:')
st.text(f"OUTPUT: {dt}, type: {type(dt)}")
tm = st.time_input('Select a time:')
st.text(f"OUTPUT: {tm}, type: {type(tm)}")
st.divider()
st.markdown("## Number Widgtets")
numi = st.number_input('Enter Hourly Wage:', value=7.25, max_value=20.0, min_value=5.25, step=0.25)
st.text(f"OUTPUT: {numi}, type: {type(numi)}")
nums = st.slider('Pick a number between 1 and 20:', min_value=1, max_value=20, value=10, step=1)
st.text(f"OUTPUT: {nums}, type: {type(nums)}")
st.divider()
st.markdown("## Selection Widgets")
selbox = st.selectbox('Choose one shipping method:', ['Jiffy Express', ' You Pee Es', 'FedUp Express'])
st.text(f"OUTPUT: {selbox}, type: {type(selbox)}")
mulselbox = st.multiselect('Select all your favorite colors:', ['Red', 'Green', 'Blue', 'Yellow', 'White'])
st.text(f"OUTPUT: {mulselbox}, type: {type(mulselbox)}")
selslider = st.select_slider('Rate us:', options=['1=Poor','2=ok','3=good','4=great','5=excellent'], value = '3=good')
st.text(f"OUTPUT: {selslider}, type: {type(selslider)}")
radio = st.radio('Rate us:', ['1=Poor','2=ok','3=good','4=great','5=excellent'], index=2, horizontal=True)
st.text(f"OUTPUT: {radio}, type: {type(radio)}")
st.divider()
st.markdown("## 'Other' Widgets")
feed = st.feedback('faces')
st.text(f"OUTPUT: {feed}, type: {type(feed)}")
color = st.color_picker('Pick a color:', value='#00f900')
st.text(f"OUTPUT: {color}, type: {type(color)}")
file = st.file_uploader('Upload a file:')
st.text(f"OUTPUT: {file}, type: {type(file)}")
pic = st.camera_input('Take a selfie:')
st.text(f"OUTPUT: {pic}, type: {type(pic)}")
st.divider()Exploring Steamlit output widgets
Likewise, Streamlit offers a number of different widgets for displaying different types of output. Here’s a sampling:
import streamlit as st
st.title('Streamlit Output Widgets!')
st.markdown("## Text Output")
st.text("Plain text.\nObeys newlines.")
st.markdown("## Markdown Output")
st.markdown('''
### Heading 3
- this
- is a
- list
Learn markdown here: [https://www.markdownguide.org/getting-started/](https://www.markdownguide.org/getting-started/)
''')
st.markdown("## Code Output")
st.code('''
name = input("Enter your name:")
print(f"Hello, {name}")
''', language="python", line_numbers=True)
st.markdown("## Image Output")
st.image("https://ist256.com/images/logo.png",caption="IST256 logo")
st.markdown("## Metric / Card Ouput")
st.metric(label="Temperature", value="70 °F", delta="1.2 °F")
st.metric(label="Mike Fudge", value="B+", delta="-5 pts")
st.markdown("## Video Output")
st.video("https://youtu.be/soVItkifdms?si=eNNbRXnAg4efcJGi")
st.markdown("## Audio Output")
st.audio("https://file-examples.com/storage/fe6993554766e3161a375a5/2017/11/file_example_MP3_700KB.mp3")
st.markdown("## Toast Output")
if st.button("Click to show toast"):
st.toast("Congrats! You clicked it!", icon=":material/thumb_up:")
st.markdown("## Column Layouts")
col1, col2, col3 = st.columns(3)
col1.markdown("Hello")
col2.text("There")
col2.text("Mike")
col3.warning("Warning!")
col3.error("Error!")
col3.success("Success!")
st.markdown("## Tab Layouts")
col1, col2, col3 = st.tabs(["Tab A","Tab B","Tab C"])
col1.markdown("Hello")
col2.text("There")
col2.text("Mike")
col3.warning("Warning!")
col3.error("Error!")
col3.success("Success!")
st.markdown("## Expander Output")
with st.expander("See a map"):
st.write('Here is a map for you!')
st.map(latitude=76,longitude=-43, zoom=13)File Uploads
We can use st.file_uploader() to allow users to upload files. The uploaded files return a Python “file-like” that can be used in a variety of applications with little additional processing.
An example:
import streamlit as st
from io import StringIO # required to convert binary to text
st.title("File Upload Example")
st.markdown('''
This example demonstrates how to process and uploaded file.
- The first example can process and file-like (image, video, data for a dataframe, etc)
- The second example shows how to process text explicitly.
''')
bin_file_data = st.file_uploader("Upload an image/photo file", type=["png", "jpeg", "jpg", "gif"])
text_file_data = st.file_uploader("Upload a text file", type=["txt", "csv", "md"])
if bin_file_data:
st.markdown(f"### {bin_file_data.name}")
st.image(bin_file_data)
if text_file_data:
st.markdown(f"### {text_file_data.name}")
binary_contents = text_file_data.getvalue()
# Convert binary to text
text_contents = StringIO(binary_contents.decode("utf-8")).read()
st.text(text_contents)
print(text_file_data)Image Processing with the camera
We can use st.camera_input() to get images from our webcams.
From there its easy to load into popular image processing libraries.
An example:
import streamlit as st
from PIL import Image
st.title("Camera Example")
st.markdown('''
Let's take a picture with the camera and conver the image to greyscale with PIL
Learn More about PIL: https://pillow.readthedocs.io/en/stable/index.html
''')
pic_data = st.camera_input("Take a pic!")
if pic_data:
img = Image.open(pic_data)
grey_img = img.convert("L")
st.image(grey_img)