My variables change but the streamlit app doesnt change

Summary


I’m creating a website that shows data regarding a backtest. This isnt the problem though, the problem is that for example, the progress bar says Backtesting (0%)… bla blabla. This is because when I create the progress bar, self.progress has 0 as the value. But after some times, self.progress changes value, but for some reason the streamlit website stays the same and it doesnt update the progress bar. This is happening for all the other self attributes that change.

Expected behavior:
Every time a self attribute changes, the data shown should change.

Actual behavior:
Self attributes change but the website stays the same

That might be a mistake in your code.

1 Like

Should the website update automatically if it detects a change in my variables? My variables clearly change, so how could that be a mistake :thinking:

Even tried with st.session_state

    def _progress(self):
        print(f"Progress bar {st.session_state.progress}")
        # Progress bar
        if "progress_bar" in vars():
            self.progress_bar.progress(0, text = f"Backtesting ({st.session_state.progress}%), please wait")
        else:
            progress_bar = st.progress(st.session_state.progress, text = f"Backtesting ({st.session_state.progress}%), please wait")

But this runs once, and it prints out 0, which is the initial value of st.session_state.progress. So I dont know to be honest whats going on

Can you please share a minimal reproducible code snippet which shows this behavior?

1 Like

I’ve lots of files, but hopefully this is enough :slight_smile:
I deleted the previous post and now I’m sending this again, I think I was just replying to the post and not directly to you

def _progress(self):
    print(f"Progress bar {st.session_state.progress}")
    # Progress bar
    if "progress_bar" in vars():
        self.progress_bar.progress(0, text = f"Backtesting ({st.session_state.progress}%), please wait")
    else:
        progress_bar = st.progress(st.session_state.progress, text = f"Backtesting ({st.session_state.progress}%), please wait")

This below runs in a thread, but its passed to streamlit.runtime.scriptrunner.add_script_run_ctx

def bdata_listener(_self, interval):
    print(Fore.GREEN + "Started the bdata listener")
    while True:
        _self.new_bdata = _self._get_data("bdata.json")
        if _self.new_bdata != _self.bdata and "progress" in _self.new_bdata:
            print(Fore.BLUE + "Message : bdata :", _self.new_bdata)
            print("UPDATING SELF ATTRIBUTES")
            _self.started = True
            _self.bdata = _self.new_bdata
            # Update self attributes
            st.session_state.progress = _self.bdata["progress"]
            print(f"Updated: {st.session_state.progress}")
            _self.eta = _self.bdata["eta"]
            _self.status = _self.bdata["status"]
            _self.status_color = _self.bdata["status_color"]
            _self.left_combinations = _self.bdata["left_combinations"]
            _self.second_average = _self.bdata["second_average"]
            _self.best_score = _self.bdata["best_score"]
            _self.score_average = _self.bdata["score_average"]
        
        time.sleep(interval)

I’m investigating the behavior of other functions and it seems to me that self attributes are not being recognized along the script, no idea why this is the case. I’ve no problem on sharing my whole code, its not much, but I doubt you want to read all the code :smile:

This is getting a bit frustrating to be honest. Can I be sure that if self attributes or st.session_state attributes change, the website will update what it shows?

Do I need to add an extra piece of code for this to happen?

:disappointed:

I suspect what @Goyo said is right, and there is probably a mistake in your code. I would recommend trying to strip your code down to just the progress bar and see if you can get it working, and then slowly build back up.

That being said, here’s a simple example of an object using its own attribute to update a progress bar

from dataclasses import dataclass
from time import sleep
from typing import Any

import streamlit as st


@dataclass
class Program:
    progress_bar: Any
    progress: int = 0

    def increment(self):
        self.progress += 1
        self.update_progress_bar()

    def update_progress_bar(self):
        self.progress_bar.progress(self.progress, text=f"Progress: {self.progress}%")


my_bar = st.progress(0, text="Operation in progress. Please wait...")
p = Program(progress_bar=my_bar)

while p.progress < 100:
    p.increment()
    sleep(0.1)

So, there’s no inherent reason why it can’t work.

1 Like

And here’s a version using session state

if "progress" not in st.session_state:
    st.session_state.progress = 0

my_bar = st.progress(
    st.session_state.progress, text="Operation in progress. Please wait..."
)

while st.session_state.progress < 100:
    st.session_state.progress += 1
    my_bar.progress(
        st.session_state.progress, text=f"Progress: {st.session_state.progress}%"
    )
    sleep(0.1)
1 Like

So the website doesnt update automatically when variable values change? I need to tell in this case the progress bar whats the new progress value?

In one sense, not very much in streamlit is ā€œautomaticā€. It just runs like a script, from top to bottom. If you call bar.progress with a new value, it will be updated. But, it doesn’t automatically get updated just because the first value you passed to it changes.

For example, this doesn’t work:

x = 10
bar = st.progress(x)
x = 100

The bar will not automatically get updated to 100, even though the value of the initial variable changed. You would have to actually call bar.progress(x) to update it.

1 Like

Then I guess my best option would be just rerunning the website again every time data updates, cause there are lots of variables changing, each variables is used in a different component, and idk how easy (not even how to) it is to update (not rerunning the website) for example, a manually created markdown table, text, etc.

For example:

    def _status(self):
        st.markdown(f"The current status of the backtest is: **:{self.status_color}[{self.status}]**")
        st.markdown(f"The estimated time to finish the backtest is **{self.eta}**.")

There is no such way to update this right? I need to rerun the website?

[EDIT]
Sorry for all the questions I’m just trying to figure out how can I get to update my website as variables change. And thanks for all the help you are giving me.

If nothing else, you can call st.experimental_rerun() to force the script to rerun.

However, if you interact with a widget the whole script is rerun, which typically means you shouldn’t need to use experimental_rerun. If something is happening behind the scenes that is changing a variable, then it gets more tricky, and you may need to use experimental_rerun.

If you have a simple case like this:

x = st.slider("Pick a number")

st.write(x)

then the app will update automatically as the slider changes.

I want to thank you a lot @blackary for your help. Even though I’m recoding everything, I’m certain this will solve my issue. Thanks a lot!

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.