Last Updated on July 14, 2022 by Jay
This tutorial will walk through how to create multiple callback with streamlit, which is a library that makes awesome web-based UI and it’s super easy to use.
What’s A Callback
A callback is basically a function that gets executed when a trigger event happens. In the context of streamlit, usually, an update from the input widget triggers a callback. If you are familiar with R Shiny, this is similar to the reactive feature but much easier to use than reactive.
Python code usually runs from top to bottom, and so does our streamlit app. It means when we finish running a line of code and set some variables/values, they can’t be changed later on unless we re-run the whole app. Session state helps solve this problem.
Streamlit Callback Example – Calculate Area of Square
Let’s make a simple app to calculate the area of squares. There are two input values:
- length of the side of a square
- the area of the square
We can give either input a value and the app should calculate the other value.
First, we’ll import streamlit and create two number input widgets, and assign keys to each so we can access the session_state of each variable.
import streamlit as st
st.write('Area of Sqaure Calculation')
side = st.number_input("length:", key='side')
area = st.number_input("area:", key='area')
st.write(st.session_state)
This app does not calculate anything right now. It simply displays the input values stored inside the session_state.
Callback triggers
All streamlit input widgets have either one of the following arguments: on_change or on_click, which are the callback function trigger events. As their names suggest – when an input gets changed or gets clicked, then streamlit will run the callback function.
Let’s add the callback triggers. Note below for the on_chagne argument, the calc_area and calc_side are function names.
import streamlit as st
st.write('Area of Sqaure Calculation')
side = st.number_input("length:", key='side', on_change = calc_area)
area = st.number_input("area:", key='area', on_change = calc_side)
st.write(st.session_state)
Write The Callback Functions
Now we need to write two functions called calc_area() and calc_side(), so they can be called when the on_change event triggers them. This is where the session_state will be useful. Recall that when initializing the two input widgets, we have assigned session_state keys for both. The callback functions should then update the appropriate session_state variables:
- calc_area() function updates the session_state[‘area’] variable
- calc_side() function updates the session_state[‘side’] variable
def calc_area():
st.session_state['area'] = st.session_state['side'] ** 2
def calc_side():
st.session_state['side'] = st.session_state['area'] ** (1/2)
Now, try entering the value 64 inside the second input box (area). Press enter and the first (length) input value will update to 8.
Multiple Callback
Let’s spice things up a little bit more by adding a third input widget – a slider that should also take the length of the side of a square as its input. Our task is to sync the three input widgets on the interface: length value, area value, and the slider.
Note in the below code we assigned the slider value to a different session_state key “slider_side” to the slider widget.
st.slider('length (slider input):', key='slider_side')
Basically, what we need is that when one of the three input widgets changes, the other two should automatically update.
Let’s modify the existing callback functions to include an update for the slider. When either function is called, update the session_state[‘slider_side’] value to equal to the side length.
def calc_area():
st.session_state['area'] = st.session_state['side'] ** 2
st.session_state['slider_side'] = st.session_state['side']
def calc_side():
st.session_state['side'] = st.session_state['area'] ** (1/2)
st.session_state['slider_side'] = st.session_state['side']
Next, we need to define what happens if we enter an input using the slider. Again, we’ll use the on_change argument, and write a new callback function called slider_input(). Basically, when we update the slider, the two other input boxes should also update.
def slider_input():
st.session_state['side'] = st.session_state['slider_side']
st.session_state['area'] = st.session_state['slider_side'] ** 2
st.slider('length (slider input):', key='slider_side', on_change = slider_input)