Is there any support for apps that have multiple pages? My use case is a 3-part workflow that I’d like to separate into three separate views with state carried across them.
Stages generally are: 1- overview of data and category specification, 2- model refinement with active learning, and 3- overview of trained model results).
Is this use case out of scope for streamlit, something that’s possible now, or something that’s planned?
There are ways of doing this based on a modification of the SessionState gist and the rerun() gist. My method uses a stack of state objects to provide the navigation. I built this handling into a “StreamlitPage” base class and subclass all my pages from it. I use a long if … elif … to do the dispatch (as the navigation varies with each page) but the dict method could be made to work as well.
I shared the modified SessionState (it’s attached to one of the Issues on Github). I haven’t shared the base class as: a) it will need rework once Streamlit finalize their approach; b) there are still some glitches which should be fixed when we get to upgrading to the 0.54+ releases and the latest SessionState implementation; and c) there are also several other application services (configuration, logging) built into the class that are specific to our environment and I need to refactor to take those out.
I’ve build pages into classes and I’ve made a manager than verify choice options with ‘st.ratio’, I’ve created a dictionary and return the options.
look the code:
import streamlit as st
from posting import Posting
from tables import Tables
pages = {'tables':Tables,'posting':Posting}
choice = st.sidebar.radio("Choice your page: ",tuple(pages.keys()))
pages[choice]()
Another option I have used is to leverage the file system to save the stateful aspect of your app and save it / load it.
import os
import pickle
import streamlit as st
class State:
def __init__(self, path='state.pickle', default_state_class=dict):
self.path = path
self.default_state_class = default_state_class
def load(self):
if os.path.exists(self.path):
with open(self.path, 'rb') as inf:
self.state = pickle.load(inf)
else:
self.state = self.default_state_class()
def get_state(self):
return self.state
def save(self):
with open(self.path, 'wb') as outf:
pickle.dump(self.state, outf)
def rerun():
raise st.script_runner.RerunException(st.script_request_queue.RerunData(None))
def app():
store = State()
store.load()
name = store.get_state().get('name', None)
if name:
st.text(f'Hello {name}')
else:
st.text(f'Please enter your name')
name_input = st.text_input('your name')
name = name_input
if name != '':
store.get_state()['name'] = name
store.save()
next_page = st.button('Next page')
if next_page:
rerun()
if __name__ == "__main__":
app()
I have followed the example from @Vojaganto so far and works very well.However, I ran into the problem that Reload ® does not take into account changes made on subpages. What is the reason for it and is there any way to fix it?
Hello @chris_klose, you’d need some session state to keep changes between subpages.
I’ve made a topic on this covering specifically the case of a multi-page app with a settings page here:
Hey Peeps,
I don’t want the values added in the app itself to be saved.
My problem is, that if I change the code itself and rerun (by pressing R) the app, the changes made in the code do not become active. I have to start the app again (Streamlit run app.py) so they get active.
So I’d like to know if there is a workaround to solve that. Any ideas?