How to display large diagram so users can scroll if necessary

Hello,

I’m working on an application to display dynamically created flowcharts based on user input. The user selects a certain process from around 100 options. The app then references a database and builds a graphviz Digraph to render a diagram of the process. These diagrams vary from 2 elements to over 50, which makes the diagram size vary widely.

I’m trying to find a solution that always displays the diagram at its native size and allows the user to scroll vertically and horizontally if necessary. I’m able to display the smaller diagrams with st.image(), but for larger diagrams, it shrinks down the size to where it isn’t readable. I also tried st.graphviz_chart(), but it cuts off parts of the image for the larger diagrams.

I also tried using st.markdown with the following code:

dot = graphviz.Digraph()  #build graphviz Digraph
dot.render('static/graph', format='png', cleanup=True)  #save as file in static folder
html_string = f'<a href="app/static/graph.png" target="_blank"><img src="app/static/graph.png" caption="legend"></a>'
st.markdown(html_string, unsafe_allow_html=True)  #show image with HTML

This solution displays the diagram exactly as I want. However, if the user selects a different input to generate a new diagram, the app serves the old diagram. I believe either streamlit or the browser is caching the files in “app/static”. I found that if I gave the diagram image a new name each time, it worked, but then I ended up with a lot of old diagram files in the static folder, which would need to be periodically deleted.

Does anyone have any suggestions to stop the app from caching the files in static? Or does anyone have a different approach to display the varying-sized diagram images?

Thanks

You could keep the bytes in memory that result from exporting the graph (using dot.pipe), instead of writing them to a file (with dot.render). And you could pass those bytes directly to the <img> tag in the html string:

from base64 import b64encode

png = my_graph.pipe(format="png")
b64 = b64encode(png).decode()
html_string = f'<img src="data:image/png;base64, {b64}">'
st.html(html_string)  # show image with HTML

However, that breaks the <a> tag because there will be no image file to serve by the href parameter.


Could you share an example?

@edsaac Thanks for your response. I just figured out a solution that’s working well.
I added “?dummy={timestamp}” where timestamp is int(time.time()) so it creates a unique integer each time. The dummy flag signals the HTML to reload the image rather than use the cache since it makes a unique src value. (I’m not at all an expert in HTML so this is what I understand is going on)

dot.render('static/graph', format='png', cleanup=True) 
timestamp = int(time.time())
html_string = f'<a href="app/static/graph.png" target="_blank"><img src="app/static/graph.png?dummy={timestamp}" caption="legend"></a>'
st.markdown(html_string, unsafe_allow_html=True)

This is giving me exactly the behavior I want

1 Like