Disappearing Altair Charts

I’ve recently found a bug in streamlit 1.46 with how overlayed altair charts are rendered when new data is supplied to their dataframes. when a feature that adds data to the table that the charts use is selected, the altair charts will disappear until you hover your mouse over the image. Especially annoying when its not me who will be using this app. I first noticed this issue in my app when updating from streamlit 1.41.1 to 1.44.1 and it’s persisted in the 1.46 update, so I’m hoping I can get an answer here as to why and if there’s a solution for my particular use case. Thanks!

To Reproduce:

import streamlit as st # 1.46
import pandas as pd
import altair as alt # 5.5
import numpy as np

x_input = st.selectbox("Select X-axis category:", ['A', 'B', 'C', 'D', 'E'])
y_input = st.selectbox("Select Y-axis category:", ['X', 'Y', 'Z', 'W', 'V'])

# Ensure scatter_data persists using session state
if 'scatter_data' not in st.session_state:
    st.session_state.scatter_data = pd.DataFrame(columns=['category_x', 'category_y', 'point_value'])

scatter_data = st.session_state.scatter_data

# Temporary live-updating point
temp_point = pd.DataFrame({'category_x': [x_input], 'category_y': [y_input], 'point_value': ['Current']})

# Lock button functionality
if st.button('Lock'):
    # Generate a new point value
    new_value = len(scatter_data[(scatter_data['category_x'] == x_input) & 
                                 (scatter_data['category_y'] == y_input)]) + 1
    # Add new row to scatter data
    new_row = pd.DataFrame({'category_x': [x_input], 'category_y': [y_input], 'point_value': [new_value]})
    st.session_state.scatter_data = pd.concat([scatter_data, new_row], ignore_index=True)

# Reset button functionality
if st.button('Reset'):
    st.session_state.scatter_data = pd.DataFrame(columns=['category_x', 'category_y', 'point_value'])

# Create heatmap (static values for consistency)
heatmap_data = pd.DataFrame({
    'category_x': ['A', 'B', 'C', 'D', 'E'] * 5,
    'category_y': np.repeat(['X', 'Y', 'Z', 'W', 'V'], 5),
    'heat_value': [5, 6, 7, 8, 9, 4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 4, 3, 2, 1, 0, 5, 6, 7, 8, 9]
})

heatmap = alt.Chart(heatmap_data).mark_rect().encode(
    x='category_x:O',
    y='category_y:O',
    color='heat_value:Q'
)

scatter = alt.Chart(scatter_data).mark_point(size=100).encode(
    x='category_x:O',
    y='category_y:O',
    color=alt.value('red'),
    tooltip=['point_value']
)

# Add temporary live-updating point
temp_scatter = alt.Chart(temp_point).mark_point(size=100, shape='circle').encode(
    x='category_x:O',
    y='category_y:O',
    color=alt.value('blue'),
    tooltip=['point_value']
)

# Add text labels below each dot
text_labels = alt.Chart(scatter_data).mark_text(dy=15).encode(
    x='category_x:O',
    y='category_y:O',
    text='point_value:N',
    color=alt.value('black')
)

# Combine heatmap, scatter plot, temporary point, and text labels
combined_chart = heatmap + scatter + temp_scatter + text_labels

# Display chart
st.altair_chart(combined_chart, use_container_width=True)

Current solution I’ve recently found is to just copy the code and paste into an ai tool and ask for the vega_lite_spec JSON to supply in the st.vega_lite_chart parameters. Personally I feel the JSON format is less intuitive, so would still love to hear whether there’s an actual altair fix for this use case or if it is truly a bug.