Using st.empty() to auto updated components

Summary

Hello everybody, i’m trying to auto updated the components on the following code so that the temperature, humidity and condition refresh on the text, currently it’s rendering additional lines underneath for each refresh, i’m struggling to understand how st.empty() works and would be used in my code

Steps to reproduce

Code snippet:

import streamlit as st
import pandas as pd
import numpy as np
import time
import requests
import plost
from PIL import Image
# Page setting
st.set_page_config(layout="wide")
with open('style.css') as f:
    st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
##############################################################################
# Set the URL for the weather API
WEATHER_URL = "https://api.openweathermap.org/data/2.5/weather"
# Set the API key for the weather API
API_KEY = "f0ba838430092a829ff98dbca781120c"
placeholder = st.empty()
# Create the main Streamlit app
st.title("VCST Global Plants Weather Dashboard")
with placeholder.container():
# Row A
a1, a2, a3 = st.columns(3)
a1.image(Image.open('logo_vcst.png'))
# Row B
b1, b2, b3, b4 = st.columns(4)
# Set the list of city IDs / position for the cities to display
CITY_IDS = [
  {
    "ID": 2786546,
    "position": a2
  }, {
    "ID": 1815456,
    "position": a3
  }, {
    "ID": 2849152,
    "position": b1
  }, {
    "ID": 3998655,
    "position": b2
  }, {
    "ID": 686581,
    "position": b3
  }, {
    "ID": 4528923,
    "position": b4
  }
]
#############################################################################
while True:
  # Refresh the container using st.empty
  st.empty()
  # For each city ID, retrieve the weather information and display it on the dashboard
  for city_position in CITY_IDS: 
      city_id = city_position["ID"]
      # Make a request to the weather API for the current weather data for the city
      params = {"id": city_id, "appid": API_KEY, "units": "metric"}
      response = requests.get(WEATHER_URL, params=params)
      data = response.json()
      # Extract the current temperature, humidity, and weather condition from the API response
      temperature = data["main"]["temp"]
      humidity = data["main"]["humidity"]
      condition = data["weather"][0]["description"]
      city_position["position"].metric(f"{data['name']}", f"{temperature}°C", f"{humidity}% humidity, {condition}")
  # Pause for one minute before updating the weather information again
  time.sleep(20)

If applicable, please provide the steps we should take to reproduce the error or specified behavior.

Expected behavior: Refresh the values for each line.

Explain what you expect to happen when you run the code above.

Actual behavior: It’s rendering a new line everytime it refreshes.

Explain the undesired behavior or error you see when you run the code above.
If you’re seeing an error message, share the full contents of the error message here.

Debug info

  • Streamlit version:1.15.2
  • Python version: 3.10.9
  • Using Conda? PipEnv? PyEnv? Pex?
  • OS version:
  • Browser version:

Requirements file

Using Conda? PipEnv? PyEnv? Pex? Share the contents of your requirements file here.
Not sure what a requirements file is? Check out this doc and add a requirements file to your app.

Links

  • Link to your GitHub repo:
  • Link to your deployed app:

Additional information

If needed, add any other context about the problem here.

st.empty() is a container itself, and only allows a single object inside of it.

The first line inside your while True loop is just creating a new empty container object at the bottom of your page in each loop, then writing more data in your columns. You will need st.empty() in each location where you want to overwrite data. You can then call the empty method on each empty container, or just assign it new data which will overwrite what’s there by default.

Here’s a snippet comparing writing to columns directly, vs writing to an empty container within a column.

import streamlit as st
import time

# Initial Layout
st.write('### Write directly to columns')
direct = st.container()
st.write('### Write to empty container within to columns')
to_empty = st.container()

# Example writing directly to columns
with direct:
    # Create the columns
    A = st.columns(3)
    B = st.columns(4)

    # Loop through the columns to write time stamps to them
    timer = time.time()
    while time.time() < timer + 2:
        for col in A:
            col.write(time.time())
            time.sleep(.1)

        for col in B:
            col.write(time.time())
            time.sleep(.1)

# Example writing to empty element
with to_empty:
    # Create the columns
    C = st.columns(3)
    D = st.columns(4)

    # Initialize lists of empty elements to be created
    C_empty = []
    D_empty = []

    # Create empty element in each column and save to list
    for col_num in range(len(C)):
        C_empty.append(C[col_num].empty())
    for col_num in range(len(D)):
        D_empty.append(D[col_num].empty())

    # Loop through the empty elements to write timestamps to them
    timer = time.time()
    while time.time() < timer + 2:
        for col in C_empty:
            col.write(time.time())
            time.sleep(.1)

        for col in D_empty:
            col.write(time.time())
            time.sleep(.1)

st.button('Do it again')
1 Like