0

I haven't been able to find an example in python that shows what I'm trying to do. I have a plot generated by a function within the app that I'd like to be able to download as a PNG file.

Various methods I've tried have generated empty files that cannot be opened, but that's as close as I've gotten. Has anyone been able to do this successfully?

Here's an incomplete example that is scaled down quite a bit from what I'm actually trying to do:

from datetime import date
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from shiny import App, Inputs, Outputs, Session, ui, render

app_ui = ui.page_fluid(
    ui.output_plot('testvis'),
    ui.download_button("downloadData", "Download"),
)


def server(input: Inputs, output: Outputs, session: Session):

    @output
    @render.plot
    def testvis():
        # Sample data in a DataFrame
        data = {'x': [1, 2, 3, 4, 5],
                'y': [2, 4, 6, 8, 10]}
        
        df = pd.DataFrame(data)
        
        # Create a simple line plot from the DataFrame
        plot = df.plot(x='x', y='y', marker='o', linestyle='-', color='b')
        return plot

    @session.download(
        filename=lambda: f"testdownload-{date.today().isoformat()}-{np.random.randint(100,999)}.png"
    )
    def downloadData():
        yield ## this is where I need help
       

    
app = App(app_ui, server)

smartse
  • 1,026
  • 7
  • 12
hn2112
  • 1
  • 2
  • the question needs sufficient code for a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) – D.L Aug 08 '23 at 14:55

1 Answers1

0
  1. You have to save the plot to a png file first (in this case you are using matplotlib so .savefig works) before you can grab it
  2. After saving the plot, you have to grab the complete path of the file when in the downloadData() function and return it (not yield as it will break)

Here is a solution I propose (but it only works if you do not have reload=True or --reload):

from datetime import date
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from shiny import App, Inputs, Outputs, Session, ui, render

app_ui = ui.page_fluid(
    ui.output_plot('testvis'),
    ui.download_button("downloadData", "Download"),
)


def server(input: Inputs, output: Outputs, session: Session):
    @output
    @render.plot
    def testvis():
        # Sample data in a DataFrame
        data = {'x': [1, 2, 3, 4, 5],
                'y': [2, 4, 6, 8, 10]}

        df = pd.DataFrame(data)

        # Create a simple line plot from the DataFrame
        plot = plt.plot(df['x'], df['y'], marker='o', linestyle='-', color='b')
        plt.savefig('test.png')
        return plot

    @session.download(
        filename=lambda: f"testdownload-{date.today().isoformat()}-{np.random.randint(100, 999)}.png"
    )
    def downloadData():
        path_to_png = 'complete/path/to/png/test.png'
        return path_to_png


app = App(app_ui, server)
jesliu
  • 11
  • 1