Download button

I’ve created a script so I can share a sklearn model with colleagues and they can run inference on their data without it leaving the premises. I’m using panel to allow users to upload their data and then I eventually tack on the model output to the original pandas dataframe. I would like the users to be able to download this as a csv, but I can’t seem to get that working with the panel FileDownload widget (including using a callback function as per the FileDownload docs). Any ideas?

1 Like

Got the FileDownload widget working. Sorted.

1 Like

Hi there, I’m trying to allow users to generate a pdf using fpdf2 and download it. Is the method you used something that could work in my instance? Thanks.

1 Like

Thanks for the reply John.

So far fpdf2 is semi-working with PyScript, the module loads, a pdf can be generated and downloaded. So the core functionality is there I guess.

My current issue is getting fpdf2 to access images and “build out” the pdf for the user. My understanding of the “file to browser” relationship is still lacking so not sure if it’s just me or the module itself. Probably me.

I deleted my post because I tested fpdf instead of fpdf2.

What problem are you having? Can you post your code?

1 Like

I wrote a working example with FPDF2. Everything works including the print and save buttons.

Demo link: PyScript FPDF2 Demo

The key is converting the PDF output into a format that the browser understands:

# Get the PDF and Base64 encode
b64data = base64.b64encode(pdf.output())

# Create an iframe to display the PDF
iframe = document.createElement('iframe');
iframe.width = '800'
iframe.height = '600'
iframe.style = 'border: 0'
iframe.src = 'data:application/pdf;base64,' + b64data.decode()

# Append the iframe to the HTML body
document.body.appendChild(iframe);

Complete example:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
    <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
    <title>PyScript FPDF2 Demo</title>
<style>
</style>
</head>

<body>
 <py-env>
   - fpdf2
 </py-env>

 <py-script >
from js import document
from fpdf import FPDF, HTMLMixin
import base64

class PDF(FPDF, HTMLMixin):
    def header(self):
        # Rendering logo:
        # Setting font: helvetica bold 15
        self.set_font("helvetica", "B", 15)
        # Moving cursor to the right:
        self.cell(40)
        # Printing title:
        self.cell(80, 10, "PyScript FDPF2 Demo", border=1, align="C")
        # Performing a line break:
        self.ln(20)

    def footer(self):
        # Position cursor at 1.5 cm from bottom:
        self.set_y(-15)
        # Setting font: helvetica italic 8
        self.set_font("helvetica", "I", 8)
        # Printing page number:
        self.cell(0, 10, f"Page {self.page_no()}/{{nb}}", align="C")

pdf = PDF()
pdf.add_page()
pdf.set_font('helvetica', size=12)
pdf.cell(txt="Now is the time for all great developers to learn PyScript!")
pdf.ln(10)
pdf.cell(txt="Learning PyScript is easy if you read my articles:")
pdf.cell(txt="PyScript Archive", border=0, align="C", link="https://www.jhanley.com/category/pyscript/")

# Get the PDF and Base64 encode
b64data = base64.b64encode(pdf.output())

# Create an iframe to display the PDF
iframe = document.createElement('iframe');
iframe.width = '800'
iframe.height = '600'
iframe.style = 'border: 0'
iframe.src = 'data:application/pdf;base64,' + b64data.decode()

# Append the iframe to the HTML body
document.body.appendChild(iframe);

 </py-script>
</body>
1 Like

Here is an example of how to read an image from a URL and embed in the PDF

# Import the required functions
from io import BytesIO
from pyodide.http import pyfetch

url = "https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png"

# Does not work because of urllib
# pdf.image(url)

response = await pyfetch(url=url, method="GET")
io = BytesIO(await response.bytes())

pdf.image(io)
1 Like

You can also use 's paths feature to fetch the file for you, if you like. This feature is described in the documentation as intended to be used for “local modules”, but it’s really just a convenience wrapper for pyfetch, so you can use it with any URL:

<! -- index.html -->
<py-env>
    - fpdf2
    - paths:
        - cert.png
</py-env>
# app.py
...
image_url = 'cert.png'
with open(image_url, 'rb') as fp:
    image_io = io.BytesIO(fp.read())
pdf.image(image_io, 0, 0, 297, 210)
...

2 Likes

As Arte Johnson was famous for saying: “Very interesting”.

I learn new tips often on these forums.

1 Like