Home > Software engineering >  Python - Insert 2 figures objects in one PDF page
Python - Insert 2 figures objects in one PDF page

Time:06-07

I want to take 2 figures objects and save them together on one pdf page. This is my code that currently saves them on 2 separate pages:

if (output_pdf_name is not None):
    pdf = matplotlib.backends.backend_pdf.PdfPages(output_pdf_name)
    explained_seq_fetures_letters_list1 = explained_seq_fetures_letters1 if multiple_samples else [
        explained_seq_fetures_letters1]
    explained_seq_fetures_letters_list2 = explained_seq_fetures_letters2 if multiple_samples else [
        explained_seq_fetures_letters2]

    for explained_seq_fetures_letters_item1, explained_seq_fetures_letters_item2 in zip(explained_seq_fetures_letters_list1,explained_seq_fetures_letters_list2):
        # create Logo object
        explained_seq_fetures_letters_item = pd.DataFrame(explained_seq_fetures_letters_item1, columns=Logo_letters)
        IG_logo1 = create_DNA_logo(PWM_df=explained_seq_fetures_letters_item,
                                  secondary_color=secondary_color)

        pdf.savefig(IG_logo1.ax.figure)

        explained_seq_fetures_letters_item2 = explained_seq_fetures_letters_item2[explained_seq_fetures_letters_item2 != 0].reshape(-1, 1)
        explained_seq_fetures_letters_item = pd.DataFrame(explained_seq_fetures_letters_item2, columns=Logo_symbol)
        IG_logo2 = create_DNA_logo(PWM_df=explained_seq_fetures_letters_item,
                                  secondary_color=True)

        pdf.savefig(IG_logo2.ax.figure)

        plt.close('all')
    pdf.close()

IG_logo.ax.figure is figure object as you can see in the image: enter image description here

It is created by logomaker library.

This is an example of my figure: enter image description here

I tried to find a solution but it seems that there is no simple solution. Any ideas?

Thanks!

CodePudding user response:

disclaimer: I am the author of the library borb (used in this answer)

borb is a pure python library that makes it easy to work with a PDF document. It also has convenient wrappers to interact with other famous libraries (PIL, matplotlib, etc)

There is a huge examples repo where one of the sections deals with exactly your problem; inserting matplotlib charts in a PDF. You can find that section here.

For completeness I'll copy/paste the code below. Keep in mind this example first builds the chart object, you obviously won't be needing that part:

from borb.pdf.document.document import Document
from borb.pdf.page.page import Page
from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout
from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout
from borb.pdf.canvas.layout.text.paragraph import Paragraph
from borb.pdf.pdf import PDF
from borb.pdf.canvas.layout.image.chart import Chart

from decimal import Decimal

import matplotlib.pyplot as MatPlotLibPlot
import numpy as np
import pandas as pd


def create_plot() -> None:
    # build DataFrame
    df = pd.DataFrame(
        {
            "X": range(1, 101),
            "Y": np.random.randn(100) * 15   range(1, 101),
            "Z": (np.random.randn(100) * 15   range(1, 101)) * 2,
        }
    )

    # plot
    fig = MatPlotLibPlot.figure()
    ax = fig.add_subplot(111, projection="3d")
    ax.scatter(df["X"], df["Y"], df["Z"], c="skyblue", s=60)
    ax.view_init(30, 185)

    # return
    return MatPlotLibPlot.gcf()


def main():
    # create Document
    doc: Document = Document()

    # create Page
    page: Page = Page()

    # add Page to Document
    doc.append_page(page)

    # set a PageLayout
    layout: PageLayout = SingleColumnLayout(page)

    # add a Paragraph
    layout.add(Chart(create_plot(), width=Decimal(256), height=Decimal(256)))

    # store
    with open("output.pdf", "wb") as pdf_file_handle:
        PDF.dumps(pdf_file_handle, doc)


if __name__ == "__main__":
    main()

Other things worth mentioning:

  • PageLayout decides how your Page will be laid out. In this example I've opted for SingleColumnLayout which does what you'd expect, content takes up the entire page (minus margins) and flows from top to bottom.
  • You can try other PageLayout implementations (such as MultiColumnLayout) if you prefer more of a scientific journal kind of aesthetic.
  • You can nest the charts inside a Table object (another way to display them side by side).
  • You can add content as an attachment to a PDF. You could include your raw data (as csv) to the PDF, thus ensuring other people can easily build their own visualizations of the data in their preferred style.
  • Related