pythonpyfpdf

pyFPDF: autopagebreak causes, that only one row is per page


I am in struggle with FPDF. When I am looping over a dataframe and I want to put in the data in the page of a PDF file; but when FPDF adds a new page would be happen:

I shows what happens below:

PAGE 1: val 1, val 2, val 3, val 4, val 5, val 6
PAGE 2: val 7,
PAGE 3: val 8,
PAGE 4: val 9,
[...]

Here is my code:

pdf = PDF('L', 'mm', 'A4')
pdf.alias_nb_pages()
pdf.add_page()
pdf.set_font("Arial","",12)
pdf.content(df)
pdf.output('tuto2.pdf', 'F')

and this is my PDF Class which is a child of FPDF:

class PDF(FPDF):

    def header(self):
        self.set_font('Arial', 'B', 30)
        self.cell(0,30,"HALLO PDF",0,0,"C")
        self.ln(30)

    def footer(self):
        self.set_y(-20)
        self.set_font('Arial', 'I', 8)
        self.cell(0,10,"Seite " + str(self.page_no()) + "/{nb}",0,0,"C",0,"")
        self.set_y(-10)
        self.cell(0,10,"Dokument erzeugt am XXXX",0,0,"C",0,"")

    def content(self,df):
        y=30
        for i in range(len(df)):
            self.set_y(y)
            self.cell(40,15,df['LG'].iloc[i],1,ln=0,align='C')
            self.cell(40, 15, df['LGP'].iloc[i], 1, ln=0, align='C')
            self.cell(40, 15, df['ZEIT'].iloc[i], 1, ln=1, align='C')
            y=y+15

What is the problem in my code?

And maybe another one can answer me a quick question: Can I get the size of the body (like: pagesize - header - footer)?


Solution

  • Explanation of the error

    The problem starts at the end of the first page when the value of y is high (may be y value is 180 mm). At this point your code executed the instructions:

    self.cell(40,15,df['LG'].iloc[i],1,ln=0,align='C')
    self.cell(40, 15, df['LGP'].iloc[i], 1, ln=0, align='C')
    self.cell(40, 15, df['ZEIT'].iloc[i], 1, ln=1, align='C')
    

    and inserts the last row in the first page. After that the library creates a new page and it is ready to place the next row at the start of this new page.
    At this point are executed the following 2 instructions:

    # here y value is 'high' (180 mm)
    y = y + 15
    # the value of y now is 195
    self.set_y(y)
    

    The instruction self.set_y(y) places the code at the start of the second page.
    Now is inserted a new row, but y is equal to 195 and it is yet increased by 15. So when is executed the instruction self.set_y(210) the library creates the third page.

    How to avoid the error

    To avoid this you have to check the value of self.get_y() that is the current position in the page. On the other hand, y save the Y position in the page before the insertion of the last line of the text. If the current position becomes <= of the value of y means that the PyFPDF library has automatically added a new page and it has set the Y position at the top of the new page.
    In this case the value of y must not increase but it must be set equal to the current_position.

    Modification to the content() method

    One possible solution is modify your content() function as followed:

    def content(self,df):
        y=30
        for i in range(len(df)):
            self.set_y(y)
            self.cell(40,15,df['LG'].iloc[i],1,ln=0,align='C')
            self.cell(40, 15, df['LGP'].iloc[i], 1, ln=0, align='C')
            self.cell(40, 15, df['ZEIT'].iloc[i], 1, ln=1, align='C')
            curr_y = self.get_y()
            if curr_y > y:
                # here we are in the of the page
                y = y + 15
            else:
                # here the library adds a new page so curr_y has a low value
                y = curr_y