Now that you have understood how to lay out a PDF document, let’s fill the cells with some content.
from fpdf import FPDF
pdf = FPDF()
pdf.add_page()
pdf.set_font('Arial', '', 16)
pdf.cell(w=0, h=10, txt="This is regular text.", ln=1)
pdf.set_font('Arial', 'B', 16)
pdf.cell(w=0, h=10, txt="This is bold text.", ln=1)
pdf.set_font('Arial', 'I', 16)
pdf.cell(w=0, h=10, txt="This is italic text.", ln=1)
pdf.set_font('Arial', '', 16) # Reset text back to regular
pdf.cell(w=0, h=10, txt="This is left aligned text.", ln=1, align='L')
pdf.cell(w=0, h=10, txt="This is center aligned text.", ln=1, align='C')
pdf.cell(w=0, h=10, txt="This is right aligned text.", ln=1, align='R')
pdf.set_fill_color(r= 0, g= 128, b = 0)
pdf.cell(w=0, h=10, txt="This is text with filled background.", ln=1, fill=True)
pdf.set_text_color(r= 0, g= 128, b = 0)
pdf.cell(w=0, h=10, txt="This is colored text.", ln=1)
pdf.output(f'./example.pdf', 'F')
# Margin
m = 10
# Page width: Width of A4 is 210mm
pw = 210 - 2*MARGIN
# Cell height
ch = 50pdf = FPDF()
pdf.add_page()
pdf.set_font('Arial', '', 12)pdf.cell(w=0, h=ch, txt="Cell 1", border=1, ln=1)pdf.cell(w=(pw/2), h=ch, txt="Cell 2a", border=1, ln=0)
pdf.cell(w=(pw/2), h=ch, txt="Cell 2b", border=1, ln=1)pdf.cell(w=(pw/3), h=ch, txt="Cell 3a", border=1, ln=0)
pdf.cell(w=(pw/3), h=ch, txt="Cell 3b", border=1, ln=0)
pdf.cell(w=(pw/3), h=ch, txt="Cell 3c", border=1, ln=1)pdf.cell(w=(pw/3), h=ch, txt="Cell 4a", border=1, ln=0)
pdf.cell(w=(pw/3)*2, h=ch, txt="Cell 4b", border=1, ln=1)pdf.set_xy(x=10, y= 220) # or use pdf.ln(50)
pdf.cell(w=0, h=ch, txt="Cell 5", border=1, ln=1)pdf.output(f'./example.pdf', 'F')
Creating a PDF layout with cells (Image by the author)
You can also specify a header and footer shown on each page in the PDF document. For this, you need to overwrite the
header()
and
footer()
methods in a custom class. Don’t forget to use an instance of your custom class instead of the
FPDF
class.
# Custom class to overwrite the header and footer methods
class PDF(FPDF):
def __init__(self):
super().__init__()
def header(self):
self.set_font('Arial', '', 12)
self.cell(0, 10, 'Header', 1, 1, 'C')
def footer(self):
self.set_y(-15)
self.set_font('Arial', '', 12)
self.cell(0, 10, 'Footer', 1, 0, 'C')pdf = PDF() # Instance of custom class
pdf.add_page()
pdf.set_font('Arial', '', 12)
pdf.cell(w=0, h=255, txt = "Body", border = 1, ln = 1, align = 'C')pdf.output(f'./example.pdf', 'F')
Header, Body, and Footer of PDF document generated in Python (Image by the author)
Now that you have understood how to lay out a PDF document, let’s fill the cells with some content.
The
fpdf
library offers you the basics to style your text:
With the set_font() method, you can set the font, the font size, and the emphasis (regular, bold, italic).
In the cell method, you can define the text alignment with the align parameter.
To fill the background of a cell, you need to define a color with the set_fill_color() method and also define fill = True in the cell() method.
To change the color of a cell’s text, you can define a color with the set_text_color() method.
pdf = FPDF()
pdf.add_page()pdf.set_font('Arial', '', 16)
pdf.cell(w=0, h=10, txt="This is regular text.", ln=1)pdf.set_font('Arial', 'B', 16)
pdf.cell(w=0, h=10, txt="This is bold text.", ln=1)pdf.set_font('Arial', 'I', 16)
pdf.cell(w=0, h=10, txt="This is italic text.", ln=1)pdf.set_font('Arial', '', 16) # Reset text back to regularpdf.cell(w=0, h=10, txt="This is left aligned text.", ln=1,
align='L')
pdf.cell(w=0, h=10, txt="This is center aligned text.", ln=1,
align='C')
pdf.cell(w=0, h=10, txt="This is right aligned text.", ln=1,
align='R')pdf.set_fill_color(r= 0, g= 128, b = 0)
pdf.cell(w=0, h=10, txt="This is text with filled background.", ln=1,
fill=True)pdf.set_text_color(r= 0, g= 128, b = 0)
pdf.cell(w=0, h=10, txt="This is colored text.", ln=1)pdf.output(f'./example.pdf', 'F')
Different styles of text in generated PDF: left, center, right alignment, bold and italic text, font and background color (Image by the author)
If you need a block of longer text, the
cell()
method is insufficient because it doesn’t allow for line or page breaks, as you can see below.
For this purpose, you should use the
multi_cell()
method instead, which can handle line and page breaks.
import lorem # Use this package to showcase long textspdf = FPDF()
pdf.add_page()
pdf.set_font('Arial', '', 16)pdf.cell(w=0, h=50, txt="This and the below cells are regular cells." , border=1, ln=1)pdf.cell(w=0, h=50, txt="Example: " + lorem.text(), border=1, ln=1)pdf.multi_cell(w=0, h=50, txt="This and the below cells are multi cells.", border=1, )pdf.multi_cell(w=0, h=5, txt="Example: " + lorem.text(), border=1, )pdf.output(f'./example.pdf', 'F')
Use multi_cells for longer texts with line and page breakes instead of regular cells (Image by the author)
With everything you have learned so far, you can now create a simple template like the one shown below. We will use this for the following examples.
# cell height
ch = 8class PDF(FPDF):
def __init__(self):
super().__init__()
def header(self):
self.set_font('Arial', '', 12)
self.cell(0, 8, 'Header', 0, 1, 'C')
def footer(self):
self.set_y(-15)
self.set_font('Arial', '', 12)
self.cell(0, 8, f'Page {self.page_no()}', 0, 0, 'C')pdf = PDF()
pdf.add_page()
pdf.set_font('Arial', 'B', 24)
pdf.cell(w=0, h=20, txt="Title", ln=1)pdf.set_font('Arial', '', 16)
pdf.cell(w=30, h=ch, txt="Date: ", ln=0)
pdf.cell(w=30, h=ch, txt="01/01/2022", ln=1)
pdf.cell(w=30, h=ch, txt="Author: ", ln=0)
pdf.cell(w=30, h=ch, txt="Max Mustermann", ln=1)pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.output(f'./example.pdf', 'F')
PDF template generated in Python (Image by the author)
For the following examples, we will be using a small fictional dataset.
import pandas as pddf = pd.DataFrame(
{'feature 1' : ['cat 1', 'cat 2', 'cat 3', 'cat 4'],
'feature 2' : [400, 300, 200, 100]
})
Fictional dataset imported as pandas DataFrame (Image by the author)
Aside from text, you might need to add plots to your PDF report.
To add plots to your PDF report, you first need to save your Matplotlib plots as images (e.g., PNG files).
import matplotlib.pyplot as plt
import seaborn as snsfig, ax = plt.subplots(1,1, figsize = (6, 4))sns.barplot(data = df, x = 'feature 1', y = 'feature 2')
plt.title("Chart")plt.savefig('./example_chart.png',
transparent=False,
facecolor='white',
bbox_inches="tight")
Matplotlib plot saved as PNG file (Image by the author)
Once your Matplotlib plot is saved as an image, you can add it to the report with the
image()
method.
pdf = PDF()
pdf.add_page()
pdf.set_font('Arial', 'B', 24)
pdf.cell(w=0, h=20, txt="Title", ln=1)pdf.set_font('Arial', '', 16)
pdf.cell(w=30, h=ch, txt="Date: ", ln=0)
pdf.cell(w=30, h=ch, txt="01/01/2022", ln=1)
pdf.cell(w=30, h=ch, txt="Author: ", ln=0)
pdf.cell(w=30, h=ch, txt="Max Mustermann", ln=1)pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.image('./example_chart.png',
x = 10, y = None, w = 100, h = 0, type = 'PNG')pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.output(f'./example.pdf', 'F')
Matplotlib plot added to PDF report in Python (Image by the author)
Unfortunately, there is no simple way to add a pandas DataFrame to a PDF report with the
FPDF
library. Although adding a pandas DataFrame as a table to a PDF report requires some light coding, it is not difficult either: By using the
cell()
method with
border=1
and effectively utilizing the
ln
parameter, you can iterate over the DataFrame to create a table.
pdf = PDF()
pdf.add_page()
pdf.set_font('Arial', 'B', 24)
pdf.cell(w=0, h=20, txt="Title", ln=1)pdf.set_font('Arial', '', 16)
pdf.cell(w=30, h=ch, txt="Date: ", ln=0)
pdf.cell(w=30, h=ch, txt="01/01/2022", ln=1)
pdf.cell(w=30, h=ch, txt="Author: ", ln=0)
pdf.cell(w=30, h=ch, txt="Max Mustermann", ln=1)pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.image('./example_chart.png', x = 10, y = None, w = 100, h = 0, type = 'PNG', link = '')pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.ln(ch)# Table Header
pdf.set_font('Arial', 'B', 16)
pdf.cell(w=40, h=ch, txt='Feature 1', border=1, ln=0, align='C')
pdf.cell(w=40, h=ch, txt='Feature 2', border=1, ln=1, align='C')# Table contents
pdf.set_font('Arial', '', 16)
for i in range(0, len(df)):
pdf.cell(w=40, h=ch,
txt=df['feature 1'].iloc[i],
border=1, ln=0, align='C')
pdf.cell(w=40, h=ch,
txt=df['feature 2'].iloc[i].astype(str),
border=1, ln=1, align='C')pdf.output(f'./example.pdf', 'F')
Pandas DataFrame added to PDF report as a table in Python (Image by the author)
Technically, you could also convert your pandas DataFrame to a Matplotlib table, save it as an image and insert the table as an image to the PDF. But I tried this out, so you don’t have to: It’s not very pretty.
Although critics say there are better alternatives to the
fpdf
library, it is simple to use.
This article showed you:
How to Create a PDF File: Layout and Placing Text and Header and Footer
How to Add Text to a PDF File: Styling Text and Line and Page Breaks
How to Add Matplotlib Plots as Images to a PDF File
How to Add a Pandas DataFrame as a Table to a PDF File
Below you can copy the template code that generates the following PDF and adjust it for your purposes.
If you’d like to get my new stories directly to your inbox, subscribe!
Become a Medium member to read more stories from other writers and me. You can support me by using my referral link when you sign up. I’ll receive a commission at no extra cost to you.
Find me on Twitter, LinkedIn, and Kaggle!
[1] “FPDF for Python”, “PyFPDF” https://pyfpdf.readthedocs.io/en/latest/ (accessed October 22, 2022)
575
575