How to cyclic update data in column.bar_chart

Hello im trying to plot data in a column layout but i only want to update the bar chart and not to create new instances of the bar charts. but everything i tried from the documentation only results in a plot of new bar charts instead of updating.

what am i doing wrong? can anyone help me?

import streamlit as st
import pandas as pd
import numpy as np
from opcua import Client
import time
import OPC_Nodes as nodes

client = Client("opc.tcp://172.25.73.114:4840")

#***************************************************************************************************************** 

def getOpcStates(nodes):
    client.connect()
    states = {}

    for node in nodes:
        states[node] = client.get_node(node).get_value()
    
    client.disconnect()
    return states      

#*****************************************************************************************************************  

st.set_page_config(layout="wide")

st.title("OPC Testsignale")

st.divider()

col1, col2 = st.columns(2 ,gap="small")

col1.subheader("Basic 1")
col2.subheader("Basic 2")

# if ('Basic1' not in st.session_state):
#     st.session_state['Basic1']=pd.DataFrame([[0,100]]) #empty data frame
# if ('Basic2' not in st.session_state):
#     st.session_state['Basic2']=pd.DataFrame([[0,100]]) #empty data frame

# col3.subheader("Regal3")
# col4.subheader("Regal4")
# col5.subheader("Regal5")

# Test = np.random.randn(20,3)
# print(Test)

# chart_data1 = pd.DataFrame([[30,70]])
# st.bar_chart(chart_data1)
# col3.bar_chart([[80,20]], x_label="", y_label="FĂĽllstand %", stack="normalize", color=["#ff0000","#00ff00"])
# col4.bar_chart([[50,50]], x_label="", y_label="FĂĽllstand %", stack="normalize", color=["#ff0000","#00ff00"])
# col5.bar_chart([[60,40]], x_label="", y_label="FĂĽllstand %", stack="normalize", color=["#ff0000","#00ff00"])

try:
    while True:
        time.sleep(1)

        #************************************************************ BasicLine1
        states = getOpcStates(nodes.BasicLine1)
        
        sum = 0
        for node in states:
            print(node, "->", states[node])
            if states[node] == True:
                sum += 1

        pos = 100/len(states) * sum
        neg = 100 - pos
      
        with col1.empty():
            st.bar_chart([[pos,neg]], x_label="", y_label="FĂĽllstand %", stack="normalize", color=["#00ff00","#ff0000"])
     
        #************************************************************ BasicLine2
        states = getOpcStates(nodes.BasicLine2)
        
        sum = 0
        for node in states:
            print(node, "->", states[node])
            if states[node] == True:
                sum += 1

        pos = 100/len(states) * sum
        neg = 100 - pos
        
        with col2.empty():
            st.bar_chart([[pos,neg]], x_label="", y_label="FĂĽllstand %", stack="normalize", color=["#00ff00","#ff0000"])
        
        #************************************************************
           
except KeyboardInterrupt:
    client.disconnect()

Hey @Tim2, I believe you have to create the empty() container outside of the loop and then call bar_chart on that container. Here is a minimal example:

import streamlit as st

import time
import pandas as pd
import numpy as np

col1, col2 = st.columns(2)
empty1 = col1.empty()
while True:
    time.sleep(1)
    chart_data = pd.DataFrame(np.random.randn(20, 3), columns=["a", "b", "c"])
    empty1.bar_chart(chart_data)

Hi, that does the Trick. Thanks for help, for me as a newbie such informations are hard to find in the documentation.

Would it be possible to put those informations in the manuals or even better in a tutorial? How to update a GUI when the script isn´t event triggered…

greetings
Tim

Glad to hear that this helped :raised_hands:
And thanks for the suggestion for the docs, we are always keen on improving them!
cc @mathcatsand for visibility :slightly_smiling_face:

1 Like

Just to add for reference:

There are three approaches to updating (just) a bar chart.

  1. Replace the whole bar chart with the updated version through a loop. The method shared above does this since st.empty() can only hold one item at a time.
  2. Use fragments
    import streamlit as st
    
    import pandas as pd
    import numpy as np
    
    @st.fragment(run_every="1s")
    def show_bar_chart():
       chart_data = pd.DataFrame(np.random.randn(20, 3), columns=["a", "b", "c"])
       st.bar_chart(chart_data)
    
    col1, col2 = st.columns(2)
    with col1:
       show_bar_chart()
    
  3. (If your change is additive) use .add_row():
    import streamlit as st
    
    import time
    import pandas as pd
    import numpy as np
    
    col1, col2 = st.columns(2)
    chart_data = pd.DataFrame(np.random.randn(20, 3), columns=["a", "b", "c"])
    chart = col1.bar_chart(chart_data)
    
    for i in range(100):
        time.sleep(1)
        row = pd.DataFrame(
            np.random.randn(1, 3), columns=["a", "b", "c"]
        )
        chart.add_rows(row)
    
1 Like

For a streaming change to a chart, fragments are probably the recommended way to go and we have a tutorial for that here: Start and stop a streaming fragment - Streamlit Docs

If there is something specific about your use case that doesn’t match this approach, please let me know.

(Fragments will be included in a rewrite of the Get started very soon.) :slight_smile:

1 Like

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