How do I store and reuse multiple user-modified images with Plotly in Streamlit apps?

How to store multiple (finalized) images generated within a Streamlit app using Plotly interactive charts, after the user has interactively modified them.

Description of the issue.

I have a music analytics application that analyzes music metrics. It generates tables of statistics and creates interactive graphs (using Plotly). The user then reviews and interacts with each Plotly Go chart, by selecting Legend items to hide or show traces.

I need to render a final PDF report after 10+ plotly charts are rendered and the user finishes interacting with each chart. I need to name and save all 10 images programmatically in the background, WITHOUT Streamlit or Plotly popping open a “Save File As…” dialog box.

CURRENT PROBLEM(S):

The Plotly charts can be saved to PNG or JPG manually one at a time. However, this is an unacceptable user interaction model when there are many images on the page. An automated save process that is invisible to the user is acceptable.

I have found examples for saving the original Plotly chart image to a file, but not the FINAL chart image after the user has interacted with it. I need to save the final MODIFIED chart image from Plotly.

PROBLEM:

The plotly_chart does not return the final (user-manipulated) chart image object to Streamlit as a Python data object to be used in the PDF report generator. The image format can be PNG or JPG. It does not return any object that can be used to programatically in memory to recreate the chart in memory.

QUESTION:

How do I get the Python object references to the FINAL MODIFIED images from Streamlit or Plotly for Python to work with?

POSSIBLE SOLUTIONS:

IF I could get the FINAL image object references, I could save them (as PNG or JPG) to the Streamlit “session_state” (dictionary). Then the image could be copied from session_state and sent to the PDF report generator.

WHAT I HAVE TRIED:

I can multiple image objects to session_state, read them back into Streamlit, and display the images successfully. However, these are not the FINAL user-manipulated images.

I assigned the result of st.plotly_chart() to a Streamlit session_state object, but Streamlit throws an error with something about the “_repr_html()” method. The Streamlit documentation says not to do this, and implies that it was an illegal or unsupported operation.

POSSIBLE HACK: Are the images being displayed in the Streamlit app stored in Streamlit’s “live cache” or in the browser’s live cache where they can be referenced and copied out to Python image objects, so they can be sent to the PDF report generator?

ANOTHER POSSIBLE HACK: Programmatically press the Plotly Chart “Save Image” button for each image to save it to the file system. This would HAVE TO be done for each image in bulk, without causing Streamlit to refresh the page.

The solutions above MUST NOT use Dash, because Dash has other limitations not worth going into here.

COMMENTS / QUESTION about Pythonic PDF report generators:

We are using FPDF2 as the PDF report writer package for this application. If anyone knows other PDF reporters that play better with Streamlit, please suggest and provide pointers.

ADDITIONAL QUESTION:

What are the real limitations (size, number, or complexity) of object storage in the Streamlit session_state ?

Also, I need to do image save operations without triggering a Streamlit refresh, because the Streamlit page refresh causes all chart changes by the user to be lost.

Steps to reproduce

Code snippet:

    # the following function does not return the FINAL user-manipulated chart, or an image of it, so that it can used in the next step.
    # Assigning this function result to a Streamlit session_state object causes Streamlit to throw an error about "_repr_html()" method
    
    st.plotly_chart(figure_list[n]) 

The st.plotly_chart(figure_list[n]) function returns an object that contains “DeltaGenerator: … blah, blah, blah.” I don’t know how to extract anything useful from this return value.

Expected behavior:

I expect to be able to save, query, or reference the final chart object (or its image) for reuse later.

Actual behavior:

See above.

Debug info

  • Streamlit version: v1.15.1
  • Plotly version: v5.11.0
  • Python version: v3.8.15
  • Conda: v22.9.0
  • OS: Windows 10 Pro
  • Browser: MS-EDGE Version 109.0.1518.78 (Official build) (64-bit)

Storing images via session state is not recommended – that’s not what session state is intended for, and there’s no guarantee that you’d be able to retrieve the image later if the app restarts. Instead, I’d recommend using something like Amazon S3 to store the images.