py-pdf / fpdf2

Simple PDF generation for Python
https://py-pdf.github.io/fpdf2/
GNU Lesser General Public License v3.0
1.13k stars 253 forks source link

How to horizontally center a table? align="CENTER" is not working for me #1306

Closed Lucas-C closed 6 days ago

Lucas-C commented 1 week ago

Discussed in https://github.com/py-pdf/fpdf2/discussions/1304

Originally posted by **DerekRobin** November 19, 2024 I was wondering how to horizontally center a table on the page? I know about the `align` parameter that can be passed when instantiating a [table](https://github.com/py-pdf/fpdf2/blob/316b6e47a04c9f6a874dd8bc85e26b24d85e558d/fpdf/table.py#L58). However, for some reason passing `align="CENTER"` does not align the table to the center of the page. I have included the code I am using to generate the table below from a pandas dataframe (df) ```python df = df.applymap(str) COLUMNS = [list(df)] ROWS = df.values.tolist() DATA = COLUMNS + ROWS with self.table( borders_layout="NONE", headings_style=FontFace(emphasis="BOLD", color="#000000", fill_color="#ececec"), cell_fill_color="#ffffff", cell_fill_mode="EVEN_ROWS", line_height=self.font_size * 1.5, text_align=( "LEFT", "CENTER", "CENTER", "CENTER", "CENTER", "CENTER", "CENTER", "CENTER", "CENTER", "CENTER", ), col_widths=(190, 70, 70, 70, 70, 70, 70, 70), align="CENTER" ) as table: for i, data_row in enumerate(DATA): # some entries of data_row are conditionally modified here # in order to ensure the table has the correct data # the code within this function does not interface with any FPDF code data_row = modify_data_row() if i == 0: table.row(data_row) else: table.row(data_row, style=FontFace(color=color, fill_color=fill_color)) ```
Lucas-C commented 1 week ago

Hi @DerekRobin

Thank you for the report.

Despite being mentioned in our documentation: https://py-pdf.github.io/fpdf2/Tables.html#setting-table-column-widths

align can be passed to table() to set the table horizontal position relative to the page, when it's not using the full page width. It's centered by default.

...it seems that this never worked properly... 😅

I tested the following code with fpdf2 version 2.7.0, where tables were originally introduced in this documentation was redacted:

from fpdf import FPDF

TABLE_DATA = (
    ("First name", "Last name", "Age", "City"),
    ("Jules", "Smith", "34", "San Juan"),
    ("Mary", "Ramos", "45", "Orlando"),
    ("Carlson", "Banks", "19", "Los Angeles"),
    ("Lucas", "Cimon", "31", "Angers"),
)

pdf = FPDF()
pdf.add_page()
pdf.set_font("Times", size=16)
with pdf.table(col_widths=pdf.epw / 5, align="C") as table:
    for data_row in TABLE_DATA:
        row = table.row()
        for datum in data_row:
            row.cell(datum)
pdf.output("./test/table/table_with_fixed_col_width_and_align.pdf")

...and the table is NOT horizontally centered on the page!

Wooops.

I will look into fix it.

Lucas-C commented 1 week ago

@allcontributors please add @DerekRobin for bug report

allcontributors[bot] commented 1 week ago

@Lucas-C

I've put up a pull request to add @DerekRobin! :tada:

Lucas-C commented 6 days ago

Fixed in PR https://github.com/py-pdf/fpdf2/pull/1308

Lucas-C commented 6 days ago

@DerekRobin: while the fix has not been released in a new version published on Pypi, you can test that it works for you using:

pip install git+https://github.com/py-pdf/fpdf2.git@master

Also, note that you will have to either specify a fixed column width (single number col_widths in the document unit) or a table width= in order for the table to not fill the page width.

When col_widths is provided as an array, those values are not considered to be widths in the document unit but as "fractions" (meaning that col_widths=(1, 1, 2) is strictly equivalent to col_widths=(25, 25, 50))

DerekRobin commented 6 days ago

What wonderful news to wake up to! Thank you so much :)