I’d like to add a feature to my streamlit app where a list ends with a “Show more” button, and pressing the button queries for more data, and puts the “Show more” button at the end of the extended list. Exactly like how google scholar implements it: https://scholar.google.com/citations?user=JicYPdAAAAAJ&hl=en&oi=ao
import random
import time
import streamlit as st
import SessionState
@st.cache
def long_calculation(i):
time.sleep(1)
return 1000 * i + random.randrange(100)
def main():
session_state = SessionState.get(length=5)
if st.button("Show more"):
session_state.length += 5
for i in range(1, session_state.length + 1):
st.write("item %d: %d" % (i, long_calculation(i)))
main()
The only difference between this and my imagined ideal solution is that here the “Show more” button is at the beginning, not at the end where it should be. Unfortunately this is extremely bad UX for long lists, and I’m stuck here. Is there a way to fix this issue, either along these lines, or starting from scratch?
If I’m correctly understanding what you’re after, you can accomplish this with some minor abuse of RerunException (which is currently undocumented and subject to change):
from streamlit.ScriptRequestQueue import RerunData
from streamlit.ScriptRunner import RerunException
def main():
session_state = SessionState.get(length=5)
for i in range(1, session_state.length + 1):
st.write("item %d: %d" % (i, long_calculation(i)))
if st.button("Show more"):
session_state.length += 5
# Force an immediate rerun of the report. This is a bit
# ugly, but it ensures that the report will be rerun
# *after* session state gets updated.
raise RerunException(RerunData(widget_state=None))
Hopefully, when SessionState becomes a proper Streamlit citizen, simply modifying it will be enough to trigger a rerun, and these gymnastics won’t be necessary!
I like this expand content idea, what would be nice if a component like st.markdown which has content which is easily truncated had an option like st.markdown(txt, show_lines=5), so it only displays the first few lines and puts in a expand icon to show all the text.
Useful for things like putting in a block of explainer text for different objects. And other uses, like showing the head/tail of a log with an expand option to show all the log.
It’s currently being tracked in this Github issue . I don’t know there’s a fixed timeline decided for this feature yet, but it’s being discussed and I think we’ll be working on it in earnest soon!
I am using the current version. There’s no error or traceback, but the script behaves in a weird way. For each click it does the long calculations, appends the results at the end as it is supposed to, but then removes everything, restarts the calculations, and only does it for the first five items. So it re-runs twice for each button-click, and the second rerun destroys the results of the first rerun. I am not sure if I’m using st.SessionState() right:
import streamlit as st
import st_state_patch
from streamlit.ScriptRequestQueue import RerunData
from streamlit.ScriptRunner import RerunException
import time
def long_calculation(x):
time.sleep(1)
return 10 * x
def main():
session_state = st.SessionState()
if not session_state:
session_state.length = 5
for i in range(1, session_state.length + 1):
st.write("item %d: %d" % (i, long_calculation(i)))
if st.button("Show more"):
session_state.length += 5
# Force an immediate rerun of the report. This is a bit
# ugly, but it ensures that the report will be rerun
# *after* session state gets updated.
raise RerunException(RerunData(widget_state=None))
main()
import streamlit as st
from state import get
from streamlit.ScriptRequestQueue import RerunData
from streamlit.ScriptRunner import RerunException
import time
def long_calculation(x):
time.sleep(0.1)
return 10 * x
session_state = get(length=5)
for i in range(1, session_state.length + 1):
st.write("item %d: %d" % (i, long_calculation(i)))
if st.button("Show more"):
session_state.length += 5
raise RerunException(RerunData(widget_state=None))
And state.py below
"""Hack to add per-session state to Streamlit.
Usage
-----
>>> import SessionState
>>>
>>> session_state = SessionState.get(user_name='', favorite_color='black')
>>> session_state.user_name
''
>>> session_state.user_name = 'Mary'
>>> session_state.favorite_color
'black'
Since you set user_name above, next time your script runs this will be the
result:
>>> session_state = get(user_name='', favorite_color='black')
>>> session_state.user_name
'Mary'
"""
import streamlit.ReportThread as ReportThread
from streamlit.server.Server import Server
class SessionState(object):
def __init__(self, **kwargs):
"""A new SessionState object.
Parameters
----------
**kwargs : any
Default values for the session state.
Example
-------
>>> session_state = SessionState(user_name='', favorite_color='black')
>>> session_state.user_name = 'Mary'
''
>>> session_state.favorite_color
'black'
"""
for key, val in kwargs.items():
setattr(self, key, val)
def get(**kwargs):
"""Gets a SessionState object for the current session.
Creates a new object if necessary.
Parameters
----------
**kwargs : any
Default values you want to add to the session state, if we're creating a
new one.
Example
-------
>>> session_state = get(user_name='', favorite_color='black')
>>> session_state.user_name
''
>>> session_state.user_name = 'Mary'
>>> session_state.favorite_color
'black'
Since you set user_name above, next time your script runs this will be the
result:
>>> session_state = get(user_name='', favorite_color='black')
>>> session_state.user_name
'Mary'
"""
# Hack to get the session object from Streamlit.
ctx = ReportThread.get_report_ctx()
this_session = None
current_server = Server.get_current()
if hasattr(current_server, '_session_infos'):
# Streamlit < 0.56
session_infos = Server.get_current()._session_infos.values()
else:
session_infos = Server.get_current()._session_info_by_id.values()
for session_info in session_infos:
s = session_info.session
if (
# Streamlit < 0.54.0
(hasattr(s, '_main_dg') and s._main_dg == ctx.main_dg)
or
# Streamlit >= 0.54.0
(not hasattr(s, '_main_dg') and s.enqueue == ctx.enqueue)
):
this_session = s
if this_session is None:
raise RuntimeError(
"Oh noes. Couldn't get your Streamlit Session object"
'Are you doing something fancy with threads?')
# Got the session object! Now let's attach some state into it.
if not hasattr(this_session, '_custom_session_state'):
this_session._custom_session_state = SessionState(**kwargs)
return this_session._custom_session_state
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking “Accept all”, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.