Hello Everyone,
I’m trying to write an app that plots continually changing data (potentially many plots in parallel) using threads and session state to avoid rerunning some code on widget change. The following code does this WITHOUT threading, but restricts me to having only one plots:
from time import sleep as snooze
import streamlit as st
from streamlit import session_state as state
import numpy as np
def change_func():
state.periodic_function = state.periodic_function_dict[state.func_choice]
st.title("Animator")
plot_here = st.empty()
if 'periodic_function_dict' not in state:
state.periodic_function_dict = {"cos(x)": np.cos, "sin(x)":np.sin}
if 'n' not in state:
state.n = 1001
if 'x' not in state:
state.x = np.linspace(0, 2*np.pi, state.n)
if 'index' not in state:
state.index = 0
st.radio("Choose a function to plot.", state.periodic_function_dict.keys(), index=0, horizontal=True, key='func_choice', on_change=change_func)
if 'periodic_function' not in state:
change_func()
while True:
with plot_here.container():
st.line_chart(state.periodic_function(state.x + state.x[state.index % state.n]), use_container_width=True)
st.write(state.index)
st.write(state.periodic_function)
state.index += 1
snooze(.001)
To allow me to make multiple plots and also create app elements that appear after the plot, I packaged the loop into a function that I run using python threads:
from time import sleep as snooze
import streamlit as st
from streamlit import session_state as state
from streamlit.runtime.scriptrunner import add_script_run_ctx as ctx
import numpy as np
import threading
def change_func():
state.periodic_function = state.periodic_function_dict[state.func_choice]
def plot_loop():
while True:
with plot_here.container():
st.line_chart(state.periodic_function(state.x + state.x[state.index % state.n]), use_container_width=True)
st.write(state.index)
st.write(state.periodic_function)
state.index += 1
snooze(.001)
st.title("Animator")
plot_here = st.empty()
if 'periodic_function_dict' not in state:
state.periodic_function_dict = {"cos(x)": np.cos, "sin(x)":np.sin}
if 'n' not in state:
state.n = 1001
if 'x' not in state:
state.x = np.linspace(0, 2*np.pi, state.n)
if 'index' not in state:
state.index = 0
st.radio("Choose a function to plot.", state.periodic_function_dict.keys(), index=0, horizontal=True, key='func_choice', on_change=change_func)
if 'periodic_function' not in state:
change_func()
if "loop_thread" not in state:
state.loop_thread = threading.Thread(target=plot_loop)
ctx(state.loop_thread)
state.loop_thread.start()
state.loop_thread.join()
However, any changes to the session state made outside of the thread are not reflected in the code that the thread is running. Is this not possible in streamlit, or am I making a mistake in setting this up? The documentation for using threads with streamlit seems to be a little thin on the ground.
Thanks in advance!
EDIT: I also checked that the session state inside of and outside of the thread are indeed the same using python’s id
function.