Home > OS >  How to save subplot as PDF using FPDF and Streamlit
How to save subplot as PDF using FPDF and Streamlit

Time:05-31

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()
Output

enter image description here

Downloaded png output:

enter image description here

Downloaded pdf output

enter image description here

  • Related