How to save panel object to png without file extension (when using BytesIO)

Dear community,
In my app I’d like to export a pane of plots to png. To expose the save() functionality to the user, I’m using a pn.widgets.FileDownload widget with a callback that saves my pane to a BytesIO object.
Only drawback is that there is no file extension and it always saves to html.

The reason I’m using this FileDownload is because it gives me a directory explorer when saving.

Any suggestions to get the desired functionality?

import param
import panel as pn
pn.extension()

import pandas as pd
import hvplot.pandas

from io import BytesIO

class Explorer(param.Parameterized):
    df = pd.DataFrame(range(10))
    
    def __init__(self,**params):
        super().__init__(**params)
        self.plot = pn.Column(self.df.hvplot(),self.df.hvplot())
        self.save_to_png = pn.widgets.FileDownload(
            filename="timeseries.png", label="Download .png", button_type="success", callback=self.download_column
        )
        self.layout = pn.Row(self.plot,self.save_to_png)
        
    def download_column(self):
        self.save_to_png.loading=True
        
        height=800
        width=int(.75*height)
        pane = self.plot

        b = BytesIO()
        pane.save(b)
        b.seek(0)

        self.save_to_png.loading=False
        return b

e=Explorer()

e.layout

Hi @mcav

A workaround is to save to a file, read it back and then download. Here is an example using a TemporaryDirectory.

Please note you will have to have a browser (firefox or chrome) in your path and its driver (gecko or chromium) installed and to be available in your PATH.

import panel as pn
import param

pn.extension()

import pathlib
import tempfile
from io import BytesIO

import hvplot.pandas
import pandas as pd

pn.extension(sizing_mode="stretch_width")

ACCENT_COLOR = "#0072B5"

class Explorer(param.Parameterized):
    df = pd.DataFrame({"y": range(10)})

    def __init__(self,**params):
        super().__init__(**params)
        self.plot = pn.Column(self.df.hvplot().opts(color=ACCENT_COLOR, line_width=6, responsive=True),self.df.hvplot().opts(color=ACCENT_COLOR, line_width=6, responsive=True))
        self.save_to_png = pn.widgets.FileDownload(
            filename="timeseries.png", label="Download .png", button_type="primary", callback=self.download_column
        )

    def download_column(self):
        self.save_to_png.loading=True

        pane = self.plot

        with tempfile.TemporaryDirectory() as tmpdir:
            file = pathlib.Path(tmpdir) / "tmp.png"
            pane.save(str(file))

            with open(file, 'rb') as fh:
                b = BytesIO(fh.read())

        b.seek(0)

        self.save_to_png.loading=False
        return b

explorer=Explorer()

pn.template.FastListTemplate(
    site="Awesome Panel", title="Application with .png download",
    sidebar=[explorer.save_to_png], main=[explorer.plot],
    accent_base_color=ACCENT_COLOR, header_background=ACCENT_COLOR
).servable()

Please share the example on twitter https://twitter.com/MarcSkovMadsen/status/1469602422427467783?s=20 or Linked In Panel on LinkedIn: Datascience app with .png file download button if you like it. Thanks.

1 Like

I’ve created a feature request to make this easier. See Enable saving to BytesIO png. · Issue #3005 · holoviz/panel (github.com)

Good day, I have one question. I use edge browser. Do you have any solutions about this?
I can use edge browser only because of my company rule.

I’m not sure if Edge will work. It would be great if we could support Kaleido, an easily embeddable offscreen renderer, but that would take some work to bring in to Bokeh.

Thanks for your reply. Edge doesn’t work at this program. I don’t like paper based report such as pdf and word to share my idea. But my company requests to me about this type. in the near feature , I think this mind-set will change soon to web based report.
But now , I want to have this method to change from panel to pdf. I wait this time.

Are you able to install Headless Chromium ? If your company allows that it should be sufficient.

Thank you for your reply. And I’m sorry for my late response. Do I need to install Chrome for using Headless Chromium? If yes, I can’t use it.

No, but you need to install Chromium, which could face the same restrictions. That said, Chromium may be shipped in a way that isn’t runnable as an end-user browser application; not sure.

Thank you for your explanation. I confirm about it to my company. If I can install Chromium ,I try it.

1 Like

Thank you for your advice. I confirmed my company rule. But our company safe list doesn’t have Chromium. So I tried other way to save our panel image. I think hv.save is similar to what I want. but I met another problem. option can’t render hv.save. I make new topic. link is below.

@jbednar @Marc
Thank you for all.
Instead of hv.save , I use plotly. I can save our plot image to file.
This is a link. I made it.
How can I render hv.option to image using hv.save - HoloViews - HoloViz Discourse