IMPORTANT: for my solution, we need to iterate through the DataFrame. And I know this is not ideal since it's very time consuming for larger size DataFrames. But since you are printing the results in a table I'm assuming it's a small sample. But consider using more efficient methods.
First, let's import the needed modules and create de DataFrame:
import pandas as pd
import math
from fpdf import FPDF
data = [
[1, 'denumire1', 'cant1', 'pret1', 'valoare1'],
[2, 'denumire2', 'cant2', 'pret2', 'valoare2'],
[3, 'denumire3', 'cant3', 'pret3', 'valoare3'],
[4, 'denumire4', 'cant4', 'pret4', 'valoare4'],
]
df = pd.DataFrame(data, columns=['Nr. crt.', 'Denumire', 'Cant.', 'Pretunitar',
'Valoarea'])
Now we can create our document, add a page and set margins and font
# Creating document
pdf = FPDF("P", "mm", "A4")
pdf.set_margins(left= 10, top= 10)
pdf.set_font("Helvetica", style= "B", size= 14)
pdf.set_text_color(r= 0, g= 0, b= 0)
pdf.add_page()
Now we can create the first element of our table: the header. I'm assuming we will print on the table only the given columns so I'll use their names as headers.
Since we have 5 columns with multiple characters, we must take in consideration the fact that we might need more than one line for the header, in case a cell has too many characters for a single line.
To solve that, line height must be equal to the font size times the number of lines needed (eg.: if you have a str with width of 150 and the cell has width of 100, you will need 2 lines (1.5 rounded up)). But we need to do this to every column name and use the higher value as our number of lines.
Also, I'm assuming you will equally divide the whole width of the page minus margins for the 5 columns (cells).
# Creating our table headers
cell_width = (210 -10 -10) / len(df.columns)
line_height = pdf.font_size
number_lines = 1
for i in df.columns:
new_number_lines = math.ceil(pdf.get_string_width(str(i)) / cell_width)
if new_number_lines > number_lines:
number_lines = new_number_lines
Now, with our line height for the header, we can iterate through the columns names and print each one. I'll use style "B" and size 14 for the headers (defined earlier).
for i in df.columns:
pdf.multi_cell(w= cell_width, h= line_height * number_lines * 1.5,
txt=str(i), align="C", border="B", new_x="RIGHT", new_y="TOP",
max_line_height= line_height)
pdf.ln(line_height * 1.5 * number_lines)
After that we must iterate through all the dataframe and for each iteration we must create cells with the content. Also, for each iteration we have to account for differences in text size and, therefore, number of lines. But by now you probably figured out that the process is the same as before: we iterate through the line to calculate the number of lines needed and then use that value to define cells with the content.
Before printing the body of the table, I'm removing the bold style.
# Changing font style
pdf.set_font("Helvetica", style= "", size= 14)
# Creating our table row by row
for index, row in df.iterrows():
number_lines = 1
for i in range(len(df.columns)):
new_number_lines = math.ceil(pdf.get_string_width(str(row[i])) / cell_width)
if new_number_lines > number_lines:
number_lines = new_number_lines
for i in range(len(df.columns)):
pdf.multi_cell(w=cell_width, h=line_height * number_lines * 1.5,
txt=str(row[i]), align="C", border="B", new_x="RIGHT", new_y="TOP", max_line_height= line_height)
pdf.ln(line_height * 1.5 * number_lines)
pdf.output("table.pdf")