Make your Machine Learning Models Come Alive with Streamlit
By: Jeff Hale
Tags: Machine Learning, Data Science, Python, Technology, Artificial Intelligence

Streamlit is a new open source library that uses Python and integrates well with common data science libraries. It handles interactivity and visualizations very well.

To paraphrase co-founder Adrien Treuille, Streamlit apps are Python scripts that treat widgets as variables, can reuse data and computations, and can be developed in a live coding environment. Streamlit is great for rapid development!

Quick Start:

Getting started with Streamlit is as easy as:

In your Python virtual environment pip install -U streamlit pandas . Type the following in your text editor and save the file as my_app.py:

import streamlit as st

import pandas as pd df = pd.DataFrame(dict(a=[1, 2, 4], b=[3, 1, 7]))

st.line_chart(df)

3. Execute streamlit run my_app.py in your terminal.

Code and see output in real time

Boom! 🧨 You’ve created a chart your user can interact with and download!

A line chart

Let’s dive into what Streamlit is and isn’t.

What Streamlit is

Loved by users

Young

Opinionated

Quick to start using

Pure Python

Ideal for visualization

Good for interactivity

Loved by users ❤️

I just have anecdotes here, but read through comments on the Streamlit community forum and issues on GitHub and you’ll see users are really excited about Streamlit. It’s solving a pain point for data scientists. 🎉

Young 🐣

Streamlit was officially launched in fall 2019 and has been iterated on quickly. The library is backed by a Silicon Valley venture-funded startup that raised $6 million USD in seed funding at launch.

Opinionated ☝️

Streamlit will give you a single-page app with an optional side bar. You can add one element after another vertically.

The Streamlit server reruns your script from top to bottom every time. There are no callbacks. Streamlit allows you to cache functions, so that you only re-run code and re-load data when necessary.

Quick to start using 🏃🏾‍♀️

As you saw above, Streamlit comes with batteries included. It plays nicely with the Python data science stack: pandas, NumPy, scikit-learn, TensorFlow, and PyTorch.

Pure Python 🐍

If Javascript frameworks and the Model-view-controller paradigm (MVC) aren’t your things, Streamlit has you covered. You just need Python functions, control flow, and decorators. Sprinkle in some Markdown and HTML/CSS if you want to adjust the formatting.

Ideal for visualization 📊

Streamlit has uses Altair by default by plotting. It makes it easy to change to other visualization options such as Matplotlib, Plotly, Bokeh, Holoviews, Graphviz, and deck.gl.

Good for interactivity ⏯

Built-in Streamlit functions make it easy to add checkboxes, dropdown menus, text boxes, and other interactive features. Streamlit treats these widgets as variables, as you’ll see in a moment.

Now that you’ve seen what Streamlit IS, let’s see what it IS NOT.

What Streamlit is not 🚫 (as of v0.60.0)

A full web framework

Ideal for styling control

Good for managing session state

Not a full web framework 🕸

Streamlit is not a fully featured web framework. There’s no router, so you can’t have multiple pages. There’s no authentication. You can’t add javascript, so popups aren’t happening.

Not ideal for styling control 🎨

Changing the CSS is not straightforward. Right now, some CSS and Javascript customizations are hacky and some are impossible. Side-by-side elements aren’t available yet.

Not good for managing session state 🎮

It’s possible — but not easy — to manage session state. Streamlit is working on a solution. Here’s a prototype. The upside of not having to think about state is that building an app that doesn’t need to preserve state is easy. 🙂 The downside is that it’s a pain to build an app that needs state. ☹️

The Future 🎁

The good news is that improvements in all of these areas are in the works! 🎉Here’s the 2020 roadmap. Note that one-click deployment is a key part of the Streamlit company’s plan to make money. 💰

Alright, now that you have the lay of the land, let’s see how to use Streamlit! ⚡️

Updated Dec. 22, 2020 — Streamlit isn’t too tricky to deploy, so I’ve removed that issue.

Using Streamlit

To run the code below, install Streamlit into a virtual environment with Python, pandas, NumPy, and Plotly. As of this writing, Streamlit is only on PyPI so you need to pip install it.

I suggest you set up your web browser and your code editor side-by-side for the best development experience. 😀

You can rerun your code manually on each update by clicking Rerun in the web app after you change your code. I suggest you set your app to rerun automatically by clicking Always rerun.

Header buttons after a change

You might need to refresh your webpage or restart your Streamlit server occasionally if the wires really get twisted, but generally, things should just work. 👍

If you get stuck, the Streamlit docs are unusually clear. And here’s the community forum.

Let’s take the 10 key Streamlit functions for a spin.

10 Key functions

Headings Text Markdown Dataframes Visualizations Interactive widgets CSS modifications Media Caching Miscellaneous features

Let’s look at headings first.

Headings

With Streamilt installed and a Streamlit server serving your file ( streamlit run my_app.py ), enter the following code in your text editor and watch the magic happen in your web browser. 🐇

import streamlit as st st.title("The Title for my App")

st.header("A Header")

st.subheader("A Subheader")

If you don’t see anything, copy the Network URL from the terminal to a web browser window. Or click the Rerun button at the top of your browser window if your Streamlit server is already running. 😉

title, header, subheader = h1, h2, h3

Using your browser inspection tool, you can verify that these functions create h1, h2, and h3 HTML tags, respectively. If you need an HTML primer, I suggest heading to W3 Schools. 👍

Text

Output text with st.write() .

st.write("Some text to output")

Or skip st.write() if you don’t need special functionality and just type the string alone.

"Some text to output"

Like Jupyter notebooks, a value or a variable name by itself will output to the screen. Unlike a Jupyter notebook, the result of a method call will not output anything. You have to save the return value as a variable to display it. ☝️

For example, the following won’t display anything:

("Some text to output").upper()

But this will:

my_uppercased_string = ("Some text to output").upper()

my_uppercased_string

Output text

It bears repeating that Streamlit reruns your code from top to bottom every time you make a change. As you explore Streamlit you will find you don’t want to display everything all the time. Comment out blocks of code to save time and screen real estate. 👍

Markdown

You can use markdown to format your text and add emoji like this:

st.markdown("_This_ __is__ *__markdown__*. 😀")

Which displays this:

Markdown stying

You can also add links using Markdown like this:

st.markdown('Learn Python [here](https://memorablepython.com)')

Viola! A link appears.

We’ll explore other Markdown use cases in a moment.

DataFrames

Streamlit was built with data scientists in mind. You can output the contents of a pandas DataFrame directly like this:

df = pd.DataFrame(dict(a=[1, 2, 4], b=[3, 1, 7]))

df

The columns are automatically sortable by the user. 🎉

If you want styling enhancements, use st.dataframe() explicitly. For example, you can highlight the minimum value in each column like this:

st.dataframe(df.style.highlight_min(axis=0))

DataFrame with highlighting

Alternatively, you can use st.write() to achieve the same outcome like this:

st.write(df.style.highlight_min(axis=0))

st.write() detects the type of object passed to it and adjusts accordingly.

Now let’s see what Streamlit can do with plots.

Visualizations

Streamlit makes visualizations a breeze. 💨

It provides default functions for interactive line, area, and bar, charts. You saw st.line_chart() above. st.bar_chart() and st.area_chart() are similar. They all use the Altair plotting library under the hood.

There are a number of other top-level functions that wrap plotting libraries, such as st.pyplot() for Matplotlib and st.map() for Mapbox GL. Here’s the code to create a map adopted from the docs:

map_data = pd.DataFrame(

np.random.randn(1000, 2) / [50, 50] + [38.9, -77],

columns=['lat', 'lon']

) st.map(map_data)

And here’s the output:

Output of st.map()

Alternatively, you can use your favorite Python plotting library. For example, here’s a geo-visualization adopted from the Plotly docs.

with st.spinner("Component is loading"):

fig = px.scatter_geo(

df_geo, # just making it take some time load

title='Gapminder Data',

locations="iso_alpha",

color="continent",

hover_name="country",

size="pop",

animation_frame="year",

projection="robinson",

) fig

Plotly with Streamlit

Note that we added a st.spinner() context block to display a message while our content was loading. 👍

Streamlit’s plotting is very cool!

Now let’s look at the interactive features that are at the heart of Streamlit.

Interactive widgets

Streamlit uses pre-defined functions to create interactive widgets.

Here’s an example select widget.

select widget output

The code to create the widget and variable is just one line!

transport = st.selectbox(label=”Select Transportation”, options=[“car”, “bike”, “walk”])

Here are seven Streamlit functions you can use to have a user to select something. I include the required arguments and a description for each widget.

button(label='Click to do something') — click a button

— click a button radio(label='Choose', options=['rock', 'classical', 'jazz']) — radio button

— radio button checkbox(label='Check the box') — toggle a checkbox

— toggle a checkbox selectbox(label='Choose one', options=['walk', 'bike']) — select an option from a dropdown menu

— select an option from a dropdown menu multiselect(label='Choose as many as you like', options=['walk', 'bike']) — select multiple options from a dropdown menu

— select multiple options from a dropdown menu slider(label='Slide the bar') — select a value from a slider bar

— select a value from a slider bar beta_color_picker(label='Pick a color') — pick a color

Here are six functions for a user to input or upload something.

number_input(label='Input a number') — input a number

— input a number text_input(label='Enter text') — input text

— input text text_area(label='Write an essay') — input multi-line text

— input multi-line text date_input(label='Input a date') — input a date

— input a date time_input(label='Input a time') — input a time

— input a time file_uploader(label='Upload a .jpg file') — upload a file

Just pass the interactive function a label that the user will see. Save the return value as a variable and do something with it. It’s that easy! 😀

Let’s see more about how to use these widgets.

Using widgets

The widgets are customizable and come with sensible defaults. For example, here’s the st.date_input() widget code:

date = st.date_input(label='Input a date')

date

And the result:

You can pass date_input a default value, a minimum value, or a maximum value. Right now, the respective defaults for date_input are today, January 1, 2001, and today plus 10 years.

Note that no duplicate widgets are allowed. Each widget must be differentiated by the arguments you pass it or else you will get an error. If needed, you can pass a key argument to ensure uniqueness. 👆

I won’t demo all the widget types here, but let’s look at a few common patterns.

You’ll often use a checkbox with an if statement. Here’s how to display or hide a DataFrame depending upon whether a user has checked a box.

display_df = st.checkbox(label='Want to see the data?') if display_df:

df

Here’s what the output looks like:

Checkbox with control flow to display a dataframe

Add any of the widgets to the sidebar with st.sidebar like this:

st.sidebar.radio(

label="Choose wisely",

options=["Laser Tag", "Ax Throwing", "Trampoline Park"]

)

Now an expandable sidebar will hold the widget. 👍

The side bar expanded with the radio buttons.

While most of the widgets have been around for a while, the color picker widget is in beta, and subject to change. Here’s the code:

user_color = st.beta_color_picker("Pick a color")

user_color

Color picker widget

Streamlit widgets are a big part of what makes the library so powerful. I encourage you to play with them to see just how cool they are! 😀

CSS Modifications

Modifying CSS in Streamlit is possible, but not elegant. You can modify the CSS through use of st.markdown("<style> some css goes here </style>") .

Here’s a basic example to change the color of the text on a section of a page.

st.markdown(

'''

<span style="color:blue">

Print it in blue. <br />

Please. 😀

</span>

''',

unsafe_allow_html=True

)

Note the use of triple quotes for multiline CSS. ☝️

Changing the color of text.

You must use st.markdown() with the keyword argument unsafe_allow_html=True to access the underlying CSS.

Interactive CSS

Let’s see how the color picker widget could allow a user to change the background on the page. Here’s the code.

user_color = st.beta_color_picker("Pick a color")

user_color if user_color != "#000000":

st.markdown(

f"<style> body{{ background-color: {user_color};}}</style>",

unsafe_allow_html=True

)

Note double curly braces {{ }} are needed to escape because of string interpolation. Here’s the color picker in action:

Using the color picker to change the CSS on the page

Bootstrap

Streamlit uses Bootstrap for styling, so you have access to Bootstrap classes such as buttons and warnings. For example, here’s how to display a success badge:

st.markdown(

'<span class="badge badge-pill badge-success"> Badge </span>',

unsafe_allow_html=True

)

Badge output that uses Bootstrap

You can try to make a grid layout with Bootstrap, but Streamlit widgets won’t respect the layout, so it’s not a good option. ☹ ️A grid layout solution is in the works. 🙂

Remove Branding

Here’s the code to remove the remove the hamburger menu and the footer with Made with Streamlit text:

hide_st_style = """

<style>

#MainMenu {visibility: hidden;}

footer {visibility: hidden;}

</style>

""" st.markdown(hide_st_style, unsafe_allow_html=True)

-source: Streamlit forums.

Media

Let’s see how to display images, videos, and audio files in your Streamlit app.

Image

You need to import the PIL library to display an image with st.image() . Here’s code you can use to get an image from a user and display it:

from PIL import Image img = []

img = st.file_uploader(label='input', type=['png', 'jpg']) if img:

image = Image.open(img)

st.image(image, caption='Your Image')

You can specify a width and BGR channel, if necessary.

Video

Play a video with st.video() . You can play your own video or one on YouTube. Here’s how you play a YouTube video starting at 45 seconds:

st.video(

'https://www.youtube.com/watch?v=AqAJLh9wuZ0',

start_time=45

)

The default video format is mp4, but you can specify another format.

Audio

Play an audio file with st.audio() . You can specify something other than the default wav file type and and pass a start time.

Caching

Caching can save your app users time the second time they load your app. Caching allows your app to avoid reloading the same files and redoing the same calculations.

Add caching with the @st.cache decorator. Here’s a basic explanation of how Streamlit caching works:

Streamlit checks these four things:

The input parameters that you called the function with

The value of any external variable used in the function

The body of the function

The body of any function used inside the cached function

If this is the first time Streamlit has seen these four components with these exact values and in this exact combination and order, it runs the function and stores the result in a local cache. Then, next time the cached function is called, if none of these components changed, Streamlit will just skip executing the function altogether and, instead, return the output previously stored in the cache.

-source: the docs.

Caching can be helpful to speed up the feel of your app, but it can also be tricky and sometimes behaves unexpectedly. ⚠️

Miscellaneous Features

Streamlit makes it easy for users to create a screen recording from the hamburger menu. The Record a screencast option gives users a range of screen options to record. This can be helpful for collaboration. 👍

You can easily display the code behind your Streamlit app. Just put the code you want to display within a st.echo() context block like this:

with st.echo():

def my_function():

return None

The output is nicely formatted code that looks like this on the user’s screen:

Code from the app

Alternatively, if you want to display formatted code but not run it, use st.code() like this:

st.code(

"""

my_var = f"testing my code {1 + 2} times"

"""

)

Code not run by the app

Wrap

Streamlit lets you quickly turn a machine learning model into a basic app. It’s packed with useful features and has a roadmap to overcome many of its current limitations. I think it will become a popular self-service tool the data scientist’s toolbox.

In a future article I plan to discuss deploying Streamlit to the cloud. Follow me to make sure you don’t miss it!

I hope you found this introduction to Streamlit to be helpful. If you did, please share it on your favorite social media so other folks can find it, too. 😀

I write about Python, SQL, and other tech topics. If any of that’s of interest to you, sign up for my mailing list of awesome data science resources and read more to help you grow your skills here. 👍