Integrating Matplotlib Charts in a PDF in Python With borb

Introduction

The Portable Document Format (PDF) is not a WYSIWYG (What You See is What You Get) format. It was developed to be platform-agnostic, independent of the underlying operating system and rendering engines.

To achieve this, PDF was constructed to be interacted with via something more like a programming language, and relies on a series of instructions and operations to achieve a result. In fact, PDF is based on a scripting language - PostScript, which was the first device-independent Page Description Language.

In this guide, we'll be using borb - a Python library dedicated to reading, manipulating and generating PDF documents. It offers both a low-level model (allowing you access to the exact coordinates and layout if you choose to use those) and a high-level model (where you can delegate the precise calculations of margins, positions, etc to a layout manager).

Matplotlib is a data visualization library that fueled an entire generation of engineers to start visualizing data, and the engine behind many other popular libraries such as Seaborn.

Given how common PDF documents are for creating reports (which oftentimes include graphs), we'll take a look at how to integrate Matplotlib charts in a PDF document using borb.

Installing borb (and Matplotlib)

borb can be downloaded from source on GitHub, or installed via pip:

$ pip install borb

Matplotlib can be installed via pip:

$ pip install matplotlib

Integrating Matplotlib Charts in PDF Documents with borb

Before we can create a chart, such as a Pie Chart, we're going to write a small utility function that generates N colors, evenly distributed among the color-spectrum.

This will help us whenever we need to create a plot and color each section:

from borb.pdf.canvas.color.color import HSVColor, HexColor
from decimal import Decimal
import typing

def create_n_colors(n: int) -> typing.List[str]:
  # The base color is borb-blue
  base_hsv_color: HSVColor = HSVColor.from_rgb(HexColor("56cbf9"))
  # This array comprehension creates n HSVColor objects, transforms then to RGB, and then returns their hex string
  return [HSVColor(base_hsv_color.hue + Decimal(x / 360), Decimal(1), Decimal(1)).to_rgb().to_hex_string() for x in range(0, 360, int(360/n))]

Note: HSL (hue, saturation, lightness) and HSV/HSB (hue, saturation, value/hue, saturation, brightness) are alternative representations of the RGB color model.

HSL and HSV/HSB were designed in the 1970s by computer graphics researchers to more closely align with the way human vision perceives color-making attributes. In these models, colors of each hue are arranged in a radial slice, around a central axis of neutral colors which ranges from black at the bottom to white at the top:


Credits: Wikimedia (CC BY-SA 3.0) license

The advantage of using this representation for Color is that we can easily divide the color-spectrum in equal parts.

Now we can define a create_pie_chart() function (or a function for other types of plots):

# New import(s)
import matplotlib.pyplot as plt
from borb.pdf.canvas.layout.image.chart import Chart
from borb.pdf.canvas.layout.layout_element import Alignment

def create_piechart(labels: typing.List[str], data: typing.List[float]):

  # Symetric figure to ensure equal aspect ratio
  fig1, ax1 = plt.subplots(figsize=(4, 4))
  ax1.pie(
    data,
    explode=[0 for _ in range(0, len(labels))],
    labels=labels,
    autopct="%1.1f%%",
    shadow=True,
    startangle=90,
    colors=create_n_colors(len(labels)),
  )

  ax1.axis("equal")  # Equal aspect ratio ensures that pie is drawn as a circle.

  return Chart(
    plt.gcf(),
    width=Decimal(200),
    height=Decimal(200),
    horizontal_alignment=Alignment.CENTERED,
  )

Here, we've used Matplotlib to create a pie chart, via the pie() function.

If you'd like to learn more about creating Pie Charts, read our Guide to Matplotlib Pie Charts!

The gcf() function of the PyPlot instance returns the current figure (get current figure). This figure can be embedded into a PDF document, by injecting it in a Chart constructor, alongside your customization arguments such as the width, height and horizontal_alignment.

That's it! You just supply a Matplotlib figure to the Chart constructor.

Adding a Matplotlib Chart to a PDF Document

Now it's time to create our basic PDF Document and add content to it.

# New import(s)
from borb.pdf.document import Document
from borb.pdf.page.page import Page
from borb.pdf.pdf import PDF
from borb.pdf.canvas.layout.page_layout.multi_column_layout import MultiColumnLayout
from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout
from borb.pdf.canvas.layout.text.paragraph import Paragraph

# Create empty Document
pdf = Document()

# Create empty Page
page = Page()

# Add Page to Document
pdf.append_page(page)

# Create PageLayout
layout: PageLayout = MultiColumnLayout(page)

# Write title
layout.add(Paragraph("About Lorem Ipsum", 
                     font_size=Decimal(20), 
                     font="Helvetica-Bold"))

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

We'll be using hyphenation in this PDF to ensure the text can be laid out even more smoothly. Hyphenation in borb is pretty straightforward:

# New import(s)
from borb.pdf.canvas.layout.hyphenation.hyphenation import Hyphenation

# Create hyphenation algorithm
hyphenation_algorithm: Hyphenation = Hyphenation("en-gb")

# Write paragraph
layout.add(Paragraph(
    """
    Lorem Ipsum is simply dummy text of the printing and typesetting industry. 
    Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, 
    when an unknown printer took a galley of type and scrambled it to make a type specimen book. 
    It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. 
    It was popularized in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, 
    and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
    """, text_alignment=Alignment.JUSTIFIED, hyphenation=hyphenation_algorithm))

Now we can add a pie chart using the function we declared earlier;

# Write graph
layout.add(create_piechart(["Loren", "Ipsum", "Dolor"], 
                           [0.6, 0.3, 0.1]))

Next we're going to write three more Paragraph objects.
One of them is going to be more of a quote (border on the side, different font, etc).

# Write paragraph
layout.add(Paragraph(
    """
    Contrary to popular belief, Lorem Ipsum is not simply random text. 
    It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. 
    Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, 
    consectetur, from a Lorem Ipsum passage, and going through the cities of the word in classical literature, 
    discovered the undoubtable source.
    """, text_alignment=Alignment.JUSTIFIED, hyphenation=hyphenation_algorithm))

# Write paragraph
layout.add(Paragraph(
    """
    Lorem Ipsum is simply dummy text of the printing and typesetting industry. 
    """, 
    font="Courier-Bold",
    text_alignment=Alignment.JUSTIFIED, 
    hyphenation=hyphenation_algorithm,
    border_color=HexColor("56cbf9"),
    border_width=Decimal(3),
    border_left=True,
    padding_left=Decimal(5),
    padding_bottom=Decimal(5),
))

# Write paragraph
layout.add(Paragraph(
    """
    Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" 
    (The Extremes of Good and Evil) by Cicero, written in 45 BC. 
    This book is a treatise on the theory of ethics, very popular during the Renaissance.
    """, text_alignment=Alignment.JUSTIFIED, hyphenation=hyphenation_algorithm))

Let's add another plot

# Write graph
layout.add(create_piechart(["Loren", "Ipsum", "Dolor", "Sit", "Amet"], 
                           [600, 30, 89, 100, 203]))

And one more Paragraph of content

# Write paragraph
layout.add(Paragraph(
    """
    It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. 
    The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', 
    making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, 
    and a search for 'lorem ipsum' will uncover many websites still in their infancy. 
    Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humor and the like).
    """, text_alignment=Alignment.JUSTIFIED, hyphenation=hyphenation_algorithm))

Finally, we can store the Document:

# Write to disk
with open("output.pdf", "wb") as pdf_file_handle:
  PDF.dumps(pdf_file_handle, pdf)

Running this code results in a PDF document that looks like this:

Conclusion

In this guide you've learned how to integrate Matplotlib charts in a PDF using borb. From here, the sky's the limit! The more creative you get with data visualization, the nicer your PDFs will be.

Last Updated: July 16th, 2023
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

Joris SchellekensAuthor

I'm a software architect from Belgium, with a passion for machine learning, knowledge-based systems and graph algorithms. I'm also the author of borb, the pure python PDF library.

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms