How to download as pdf whole streamlit webpage by adding just a utility in webpage like "download as PDF"

How to download as pdf whole streamlit webpage by adding just a utility in webpage like “download as PDF”. I tried with reportlab but some filters and in my pdf I want the sidebar also.
This is the code I am working on:
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import pdfkit
import base64
from io import BytesIO
import io
import os

Define the path to wkhtmltopdf (adjust the path based on your installation)

path_wkhtmltopdf = r’C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe’ # Update this path
config = pdfkit.configuration(wkhtmltopdf=path_wkhtmltopdf)

Generate sample data

np.random.seed(0)
students = [f’Student {i+1}’ for i in range(30)]
subjects = [‘Math’, ‘Science’, ‘English’, ‘History’, ‘Geography’, ‘Art’, ‘Physics’]
years = list(range(2017, 2024))

data = {
‘student_name’: np.random.choice(students, 210), # 30 students * 7 subjects (for variation)
‘subject’: np.random.choice(subjects, 210),
‘year’: np.random.choice(years, 210),
‘marks’: np.random.randint(50, 100, 210)
}
df = pd.DataFrame(data)

def fig_to_base64(fig):
# Save the figure to a BytesIO object
img_bytes = io.BytesIO()
fig.savefig(img_bytes, format=‘png’)
img_bytes.seek(0) # Move to the beginning of the BytesIO object
# Encode the image as base64
return base64.b64encode(img_bytes.read()).decode(‘utf-8’)

Sidebar filters with “All” option for students

st.sidebar.header(“Filters”)
selected_student = st.sidebar.selectbox(“Select Student”, options=[“All”] + students)
selected_subject = st.sidebar.multiselect(“Select Subject(s)”, options=subjects)
selected_year = st.sidebar.selectbox(“Select Year (Optional)”, options=[None] + years)

Filter data based on selections

filtered_data = df.copy()
if selected_student != “All”:
filtered_data = filtered_data[filtered_data[‘student_name’] == selected_student]
if selected_subject:
filtered_data = filtered_data[filtered_data[‘subject’].isin(selected_subject)]
if selected_year:
filtered_data = filtered_data[filtered_data[‘year’] == selected_year]

Layout for charts

st.header(“Subject vs Marks”)
sns.set(style=“whitegrid”)

Create a list to capture HTML content

html_content = “”

if selected_student == “All”:
# Display bar graph for each student individually
for student in filtered_data[‘student_name’].unique():
student_data = filtered_data[filtered_data[‘student_name’] == student]
fig, ax = plt.subplots(figsize=(8, 4))
sns.barplot(data=student_data, x=‘subject’, y=‘marks’, ax=ax)
ax.set(title=f"Marks for each Subject - {student}")
st.pyplot(fig)

    # Capture chart as HTML (add any HTML content you want here)
    html_content += f"<h3>Marks for each Subject - {student}</h3>"
    html_content += f"<img src='data:image/png;base64,{fig_to_base64(fig)}'/>"

else:
# Display bar graph for selected student
fig, ax = plt.subplots(figsize=(8, 4))
sns.barplot(data=filtered_data, x=‘subject’, y=‘marks’, ax=ax)
ax.set(title=f"Marks for each Subject - {selected_student}")
st.pyplot(fig)

# Capture chart as HTML
html_content += f"<h3>Marks for each Subject - {selected_student}</h3>"
html_content += f"<img src='data:image/png;base64,{fig_to_base64(fig)}'/>"

Capture year-wise chart

st.header(“Year-wise Subject Marks”)
if selected_subject:
fig, ax = plt.subplots(figsize=(10, 5))
sns.lineplot(data=filtered_data, x=‘year’, y=‘marks’, hue=‘subject’, marker=‘o’, ax=ax)
ax.set(title=“Year-wise Marks for Selected Subjects”)
st.pyplot(fig)

# Capture chart as HTML
html_content += "<h3>Year-wise Marks for Selected Subjects</h3>"
html_content += f"<img src='data:image/png;base64,{fig_to_base64(fig)}'/>"

Function to create and download PDF

def create_pdf(html_content, filename=“dashboard.pdf”):
“”“Create a PDF from HTML content”“”
pdfkit.from_string(html_content, filename, configuration=config)

# Convert the PDF to a downloadable link
with open(filename, "rb") as f:
    pdf_data = f.read()
    pdf_b64 = base64.b64encode(pdf_data).decode()
    href = f'<a href="data:application/octet-stream;base64,{pdf_b64}" download="{filename}">Download as PDF</a>'
    return href

Add download button

if st.button(“Download Dashboard as PDF”):
pdf_link = create_pdf(html_content)
st.markdown(pdf_link, unsafe_allow_html=True)

Please edit your post and use a code block with three backticks at the beginning and end for better readability.