Streamlit is great. I am trying to connect it to an external process, which modifies the data (every few seconds). When I detect such change (for example by running a while True loop at the end of my script), I would like to either
force refresh of the page, so new data re-renders, or
address the selected widget already on the page and modify their values (thus perhaps forcing the re-run of the script, but then I would have to modify all the widgets in one batch before the page reloads)
Is there a mechanism I could use?
I cannot expect the user to refresh the page in their browser every few seconds just to see if there was a change.
Not sure what happens with long running processes and the memory, but have you tried just putting things in a loop?
Cribbed from the docs on adding rows and modified a little:
import streamlit as st
import numpy as np
delay_time = st.number_input("Delay", value=2)
run = st.checkbox("Run")
status_text = st.empty()
chart = st.line_chart(np.random.randn(10, 2))
full_replacement_chart = st.empty()
new_rows = np.random.randn(10, 2)
# Update status text.
status_text.text("The latest random number is: %s" % new_rows[-1, 1])
# Append data to the chart.
# Just replace the chart
Thanks. I do pretty much exactly what you are showing and it works for incrementally adding to a chart (the documentation was pretty good for that). But what I cannot do with the placeholder trick is to add/remove buttons for example.
Let me expand on my previous description. My Streamlit script is visualizing data from an evolving system. The user can look at the data and interact with the system. As the system exposes, it gets to states, where certain user actions are possible (desirable) e.g. user has to take a decision, because the system got to some abnormal condition.
So what I am trying to achieve (and it looked like I was getting very very close) is to add additional buttons on the page, when I detect that those options just became possible (and hide them as soon as those issues are resolved).
Streamlit has two patterns that seem close:
with bar = st.progress(0):
# do something
The progress is one of the few widgets that I can interact with. If I could similarly interact with a st.button to enable/disable show/hide it for example, I could create that interactive experience.
The second pattern is the st.empty() as you suggested. But that cannot host buttons, unless I somehow generate the widget keys to be unique and figure out how to remove the button from the placeholder, when it should not show anymore.
And all of this only works if I knew up front all those buttons that will ever need to be displayed. The st.empty() placeholders must be created upfront. And if you need to show a button and a progress bar for each action the user can take, your script will turn into algorithm that manages what is showing in those placeholders. So it would be great, if there was a possibility to create a custom (composite) widget too :-]
My script is observing this file in the while run loop as you suggested.
Upon every update to the file, the page should display widgets for all the elements in the features part of the json. Checkboxes should change their values to reflect what is in the json file. The numeric selector would be used to show the threasholdA value and shall update its value accordingly, when the value changes in JSON. The user may change those values (checkboxes or numeric) to alter the display of the data on the page.
The list of actions shall be rendered as button widgets, so the user can elect to apply such action if they feel that is the appropriate reaction to what they see.
I was just trying to clarify the issues with reloading but the duplicate widget ID is probably the main one.
I have a half-solution, though as far as I can tell the answer to whether it can support the pattern is “no, not in a supported way”.
This takes code from the sessionstate hacks, and adds to the end of the page a while loop that waits for data to change before forcing a reload. While this does work, the problem is that as the script hasn’t finished none of your other widgets do anything until it does. You may be able to get the session id, then start a thread in the background that checks for any update before triggering a reload, but I’m unsure.
This is also using internal calls so you’d want to be wary.
I should add that there doesn’t seem to be anything architecturally or conceptually that doesn’t work with streamlit - waiting for some input to be changed by an outside source that isn’t a user is very similar to an outside source that is.
I had another thought on this, which was you could look at modifying the HTML (either by forking streamlit or something like greasemonkey) to do this, and write the data grabbing and triggering in streamlit - just faking a button press or something.
If you haven’t already, consider putting it up as a feature request on the repo.