Unable to download/save image with the same width on Streamlit webapp

Summary

I need the user to be able to download the charts that are in the exact same format as the ones that render on web interface (i.e.web from streamlit run filename.py) . However I am unable to because settings in from altair_chart() do not come through:

a) when I set the widths of the column using st.columns and set use_container_width=True in alt.chart, then download the image using vl_convert, the adjusted width does not come through when you download image, thus dimensions of downloaded image are different.

b) This is a minor issue, but if theme in altair_chart() is set to β€˜streamlit’, the theme does not come through in the downloaded image. This is not a major issue as I can just switch this off.

Expected behavior:

Chart images that have been downloaded are identical to what appears on web streamlit interface

Actual behavior:

Chart images that have been downloaded are not identical because the adjusted widths (from use_container_width=True) and streamlit theme does not pull through. Priority is the widths though as theme can be switched off.

Additional information

I have also tried using altair_saver (chart.save() ) but get the same results. Note if you run code below in jupyter notebook, then run a chart object e.g. chart 1, the widths are also not reflected.

Steps to reproduce

Code to reproduce below with toy dataset

Code snippet:


import altair as alt
import pandas as pd
import streamlit as st
import vl_convert as vlc

st.write("#### Toy Example")

data = {'Fruit': ['apple', 'apple', 'apple', 'banana', 'banana', 'watermelon', 'watermelon', 'pineapple', 'pineapple'],
        'Fresh': ['no', 'yes', 'no', 'yes', 'yes', 'no', 'no', 'no', 'yes']}
df = pd.DataFrame(data)

col1, col2, col3 = st.columns([1.5, 1, 1])

with col1:
     chart1 = alt.Chart(
                          df,
                          title='Fruit Failures'
     ).mark_bar(
               stroke='black'
     ).encode(
              x=alt.X('Fruit:N', title="Category"),
              y=alt.Y('count():Q', title="Subjects", axis=alt.Axis(tickMinStep=1)),
              color='Fresh'

     )

     st.altair_chart(chart1, use_container_width=True, theme = None)
     vl_spec = chart1.to_json()
     png_data = vlc.vegalite_to_png(vl_spec=vl_spec, scale=2)
     st.download_button(label='DownloadChart', data=png_data, mime="image/png")

with col2:
    chart2 = alt.Chart(
        df,
        title='Fruit Madness'
    ).mark_bar(
        stroke='black'
    ).encode(
        x=alt.X('Fruit:N', title="Category"),
        y=alt.Y('count():Q', title="Subjects", axis=alt.Axis(tickMinStep=1)),
        color='Fresh'

    )

    st.altair_chart(chart2, use_container_width=True, theme = 'streamlit')

    vl_spec = chart2.to_json()
    png_data = vlc.vegalite_to_png(vl_spec=vl_spec, scale=2)
    st.download_button(label='DownloadChart', data=png_data, mime="image/png")


Users can get the image by right-clicking on it or using the action menu. Do you really need a download button?

Thanks for coming back to me Goyo. For this purpose they will need to be used in official documents and presentations, so we would be using the scale attribute to enable them to download larger high quality images. If it is not possible then we would make do, but wanted to understand if there is a workaround first.

You can export as .svg, which scales much better, but sometimes it is messed up (your charts look good, though).

Or maybe use an explicit size instead of relying on the container size, take a look at this SO answer:

Thanks for this Goyo, I think I wasnt clear on the context - in this case the user will not have access to internal code, only the web interface, and so they would need some way to download a good quality image that matches the image within the web interface. Will be hard to try manually match sizes for export and will be quite manual to do across all charts on website. Hoping there may be an alternative solution.

I was not suggesting the user would have access to the code. Export as SVG is available in the action menu and the chart size would be set by the developer in the code.

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