Streamlit Plotly figure doesn't update on input but fig.show() does, cannot debug

Summary

When I update one of my inputs the plotly streamlit figure only partially updates:

  • The title updates
  • The hover labels updates
  • The plot as a visual remains the same (does not update)

If I insert a fig.show() before st.plotly_chart I get the expected figure.

If fig.show() shows the correct figure and st.plotly_chart does not, how can I go about debugging this?

Unfortunately, I’ve been unable to create a minimum working example (MWE) of this behaviour.

Steps to reproduce

Code snippet:

Despite trying for a while I cannot reproduce this in a MWE and it is not possible for me to share my entire project, here is something similar, but doesn’t exhibit the behaviour. My actual plot has far more points on it. The code plots multiple lines on a map with each having hover text and custom styling.

As this is not a valid MWE, I’m just asking for general debugging ideas

import streamlit as st 
from plot import plot
import plotly.express as px
import plotly.graph_objs as go
import numpy as np

mapbox_token = open(".mapbox_token").read()

def plot(lat):
    init_lat = 0
    init_lon = 0
    lon = 75

    lats =[]
    lons =[]
    hover_names = []

    lats.extend(np.linspace(init_lat, lat, 100))
    lons.append(None)

    lons.extend(np.linspace(init_lon, lon, 100))
    lons.append(None)

    hover_names.extend(['selected']*100)
    hover_names.append(None)


    lats.extend(np.linspace(20, 20, 100))
    lons.append(None)

    lats.extend(np.linspace(-20, -20, 100))
    lons.append(None)

    hover_names.extend(['default']*100)
    hover_names.append(None)



    _fig = go.Figure()
    _fig.add_trace(go.Scattermapbox(
            mode='lines',
            lon=lons,
            lat=lats,
            line = {'width': 2, 'color': 'red'},
            hoverinfo='text',
            text=hover_names,
            opacity=1
        ))
    _fig.add_trace(go.Scattermapbox(
            mode='lines',
            lon=lats,
            lat=lons,
            line = {'width': 2, 'color': 'green'},
            hoverinfo='text',
            text=hover_names,
            opacity=1
        ))
    _fig.update_layout(title=lat, showlegend=False, height=1000,hoverlabel_align='left',  margin={"r":0,"l":0,"b":0, 't':30})
    _fig.update_mapboxes(zoom=1.9, accesstoken=mapbox_token)

    _fig.show()
    return _fig

st.set_page_config(layout="wide")


with st.form("Optional"):
    lats = list(range(100))
    lat = st.select_slider("lat",lats, value=lats[40])
    submitted = st.form_submit_button("Submit")

fig = plot(lat)
st.plotly_chart(fig, use_container_width=True)

Debug info

  • Streamlit version: 1.23.0,1.24.0,1.25.0 (have tried them all
  • Python version: 3.11.4
  • Mamba(Conda) and poetry
  • OS version: macOS 13.5
  • Browser version: Safari 16.6, Arc 1.4.1 (Chromium 116.0.5845.96)

Requirements file

python = ">=3.10,<3.13"
streamlit = "=1.25.0"
plotly = "=5.15.0"
dill = "=0.3.7"

Hi @this_josh

There are code snippets for creating various plots using Plotly in the following app

https://plotly.streamlit.app/

See if you can use some of these as a starting point to create a working plot, then once that works you can add additional customizations.

More details and code snippets also in the Docs page

Hi @dataprofessor,

Thank you for your reply, I have created many streamliit apps with plotly figures in the past, the basics are not the problem here.

Do you have any suggestions on how to debug

fig.show()
st.plotly_chart(fig)

showing different figures?

While I cannot create a MWE, it is my assumption that something strange must be going on in st.plotly_chart.

Hi @this_josh

Typically, fig.show() and st.plot_chart(fig) are synonymous but the former is for a typical Jupyter notebook or script implementation while the latter is for display in a Streamlit app.

It would be helpful to help debug to have a reproducible code that does not work via st.plotly_chart(). Could you try commenting out most of the code (so that you would be able to build and display a basic plot in the app) used to build the plot and uncomment them line by line in order to see at which point would a specific line break the code.

I have tried this, and then I’ve tried reproducing it line by line (in the example code above) and I cannot see what is causing the issue.

I have inserted a pio.show inside streamlit here and it shows the correct plot, but the app plot is having the same issues. Given this, I am inclined to believe the issue lies within streamlit, but as I cannot provide an MWE this cannot be confirmed.

Do you have any ideas how I can debug the issue within streamlit? I’ve tried removing caching and the rather useless del method.

Thanks

Hi @this_josh ,

Wasn’t able to solve this because I’m missing the .mapbox_token and haven’t worked with Scattermapbox before, but some pointers and code to help you debug this:

  • First try without the form and without the function that creates the figure, just let everything recalculate dynamically on each rerun.
  • Also try without fig.show(), in case it is somehow mutating the Figure object before using it in st.plotly_chart.
  • Consider the uirevision parameter of Plotly Layout objects. It takes in a string, and whenever you change the string it will force a refresh of the plotly ui. I’ve found it to be quite useful.

The example below considers these points so you can test . Note that I commented out some of the lines. Hope this helps - let me know!

import streamlit as st 
import numpy as np
from plotly.graph_objects import Figure, Layout, Scattermapbox

st.set_page_config(layout="wide")

# Input data

lats = list(range(100))
lat = st.select_slider("lat",lats, value=lats[40])

init_lat = 0
init_lon = 0
lon = 75

lats = []
lons = []
hover_names = []

lats.extend(np.linspace(init_lat, lat, 100))
lons.append(None)

lons.extend(np.linspace(init_lon, lon, 100))
lons.append(None)

hover_names.extend(['selected']*100)
hover_names.append(None)

lats.extend(np.linspace(20, 20, 100))
lons.append(None)

lats.extend(np.linspace(-20, -20, 100))
lons.append(None)

hover_names.extend(['default']*100)
hover_names.append(None)


# Plotly figure (each Plotly figure has data and layout, data can be an iterable of trace objects)

fig=Figure(
    data=(
        Scattermapbox(
            mode='lines',
            lon=lons,
            lat=lats,
            line={'width': 2, 'color': 'red'},
            hoverinfo='text',
            text=hover_names,
            opacity=1
        ),
        Scattermapbox(
            mode='lines',
            lon=lats,
            lat=lons,
            line={'width': 2, 'color': 'green'},
            hoverinfo='text',
            text=hover_names,
            opacity=1 
        ),
    ),
    layout=Layout(
        title="Default title",
        hoverlabel={'align':'left'},
        height=1000,
        # uirevision="input a string variable here, and change its value whenever you want to refresh plotly UI"
        )
    )

# Add mapbox to figure
# mapbox_token = open(".mapbox_token").read()
# fig.update_mapboxes(zoom=1.9, accesstoken=mapbox_token)

st.plotly_chart(
    figure_or_data=fig,
    use_container_width=True
)```
1 Like

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