shiny for python downloadable report

Hi there,

I am searching for a way to create a downloadable report from a Shiny for Python app deployed on shinyapps.io.

The idea is that in the app, the users have all the data they can explore, and if required, they could then generate a word report on the fly with some of the choices made in exploring the data. In Shiny for R, it can be achieved using quarto::quarto_render as explained here: Generating a downloadable Quarto document from a shiny app on shinyapps.io.

However, using Python, it seems to be possible only using the terminal. See: Quarto – Using Python

Do you have any suggestions on generating a quarto downloadable report from a Shiny for Python app deployed on shinyapps.io?

Thank you so much.

Hi @massa,

I'm having a similar issue. I created a shiny python app and deployed it to shinyapps.io. This all works nicely.

However, I want to generate a downloadable pdf report and apparently there is an implementation for shiny R.

I tried a bit for myself and found python packages like pdfkit, weasyprint (both use markdown2) and reportlab but I did not manage to run any of these :disappointed:. pdfkit and weasyprint furthermore require wkhtmltox, which I cannot install on my machine because I don't have admin rights ... Still, I doubt this would work after deploying the app to shinyapps.io.

Furthermore, I found out about reticulate, which allows to use python from R. This way I could integrate my pyhton scripts into a shiny R app to use the approach mentioned already above. Yet, this does not seem like a straight forward implementation.

So, does anyone have a neat solution? Appreciate any suggestions and ideas :nerd_face:

Cheers,
Tobi

Hi thundert,
Thanks for adding to my original query. I am learning Shiny for Python starting from R. As you mentioned, our aim is very well documented online in Shiny for R, not so much in Shiny for Python. I am a newbie, so take my example for what it is. However, this is what I have so far.

Quarto is the best choice to do what you mean. So, first, I created a Quarto document that I called test.qmd. I have two parameters: alpha and ratio.
Then, I used the following minimum reproducible example to modify these parameters and render a Word document (you might change it to a PDF very easily).


from shiny import App, Inputs, Outputs, Session, render, ui, reactive
import subprocess
import tempfile
import shutil
from pathlib import Path
import os
from io import BytesIO

app_ui = ui.page_fluid(
    ui.input_slider("n", "Number of points", min=1, max=100, value=50),
    ui.download_button("downloadData", "Download")
)


def server(input: Inputs, output: Outputs, session: Session):
    @render.download(filename="test.docx")
    async def downloadData():
        with tempfile.TemporaryDirectory() as tmpdirname:
            # Create a temp directory and copy the file .qmd
            source_file = "/".join([tmpdirname, "test.qmd"])
            shutil.copy("./test.qmd", source_file)
            if os.path.isfile(source_file):
                print("found: value")
                #If the file has been created, call the quarto subprocess to render the document
                subprocess.run(["quarto", "render", source_file, "-P", f"alpha:{str(round(int(input.n())/100,2))}", "-P", "ratio:0.3"])
                output_file = "/".join([tmpdirname, "test.docx"])
                #  If the file has been created it reads it as BytesIO and passes for downloading the file
                if os.path.isfile(output_file):
                    with open(output_file, "rb") as fh:
                        buf = BytesIO(fh.read())
                        yield buf.getvalue()
                else:
                    print("file not found", output_file)
                



www_dir = Path(__file__).parent / "www"
app = App(app_ui, server, static_assets=www_dir)

I read that the team of quarto is working to create a built-in function as a wrapper to make the render much easier. Hopefully it will happen in the near future. In the meantime if someone with more experience in shiny for pthon can contribute I believe it will be beneficial also for others.