I have a subplot that I want to save in a PDF. I am trying to do this inside a Streamlit app and to create the PDF I am using FPDF library. The subplot is working without any problems. The problem is that I can't save it as PDF because an error is shown saying that the figure that I want to save is not defined. This is how I created the figure containing the subplot:
fig1, (ax1, ax2) = plt.subplots(1, 2)
hip_angle, _, _ = angle_calculation(merged)
hip_angle_2, _, _ = angle_calculation(merged_2)
sub_plotting(freq_left, hip_angle_2, 'Hip angle - Left leg', ax1)
sub_plotting(freq_right, hip_angle, 'Hip angle - Right leg', ax2)
ax1.set_xlabel('Gait phase %')
ax2.set_xlabel('Gait phase %')
ax1.set_ylabel('Angle (degrees)')
ax2.set_ylabel('Angle (degrees)')
ax1.set_xticks(np.arange(0, 110, step=10))
ax2.set_xticks(np.arange(0, 110, step=10))
ax1.set_ylim([-20, 50])
ax2.set_ylim([-20, 50])
ax1.set_aspect('auto')
ax2.set_aspect('auto')
fig1.set_figheight(8)
fig1.set_figwidth(18)
st.pyplot(fig1)
# Here I am just creating a button to download the figure
fig = 'Hip angle.png'
plt.savefig(fig)
with open(fig, "rb") as f:
btn = st.download_button(
label="Descarregar imagem",
data=f,
file_name=fig,
mime="image/png")
This is what I am using to try to save the figure in the PDF.
checkbox = st.checkbox('Name', value='')
if checkbox:
name = st.text_input('Nome do utente', value=' ')
st.download_button(
label="Descarregar relatório",
data=create_pdf(fig1),
file_name="Relatório.pdf",
mime="application/pdf",
)
As I mentioned, there's an error saying that the fig1
is not defined.
This is the function that I am using to create the PDF template.
def create_pdf(figure1):
pdf = FPDF()
pdf.add_page()
figure = io.BytesIO()
figure1.savefig(figure, format="png")
saved_fig = tempfile.NamedTemporaryFile()
with open(f"{saved_fig.name}.png", 'wb') as sf:
sf.write(figure.getvalue())
pdf.set_xy(30, 50)
pdf.image(figure1, w=140, h=110)
figure.close()
return bytes(pdf.output())
CodePudding user response:
Here is a simplified code that works with pdf download. We create the pdf file first based on png file. Once created we use it for download.
Code
import matplotlib.pyplot as plt
import streamlit as st
from fpdf import FPDF
def create_pdf(img_fn, pdf_fn):
"""
Create pdf written to pdf_fn with the image file img_fn.
"""
pdf = FPDF()
pdf.add_page()
# Save to pdf
pdf.set_xy(30, 50)
pdf.image(img_fn, w=140, h=110)
pdf.output(pdf_fn)
def main():
x = [1, 2, 3, 4, 5, 6]
y = [1, 5, 3, 5, 7, 8]
fig1, (ax1, ax2) = plt.subplots(1, 2)
ax1.plot(x, y)
ax2.scatter(x, y)
st.pyplot(fig1)
# Save to png
img_fn = 'Hip angle.png'
fig1.savefig(img_fn)
# Prepare file for download.
dfn = 'angle.png'
with open(img_fn, "rb") as f:
st.download_button(
label="Descarregar imagem",
data=f,
file_name=dfn,
mime="image/png")
# pdf download
checkbox = st.checkbox('Name', value='')
if checkbox:
pdf_fn = 'mypdf.pdf'
create_pdf(img_fn, pdf_fn)
with open(pdf_fn, 'rb') as h_pdf:
st.download_button(
label="Descarregar relatório",
data=h_pdf,
file_name="Relatório.pdf",
mime="application/pdf",
)
if __name__ == '__main__':
main()