I'm building trying to build a pdf report in Python using fpdf. I want to take some data from my analysis stored in a DataFrame and create tables and graphs. Just like what you would do in Excel. My issues is I can't see to get the headers to wrap text like you would get if you used the "Wrap Text" function in Excel if you were creating a table. I've tried multiple iterations and the best I've come up with is the below: data1 = { 'Category': ['A', 'B', 'C', 'D'], 'Values': [10.1234, 20.5678, 15.9101, 25.1121] } data2 = { 'Category': ['E', 'F', 'G', 'H'], 'I expect this to wrap': [30.2345, 40.6789, 35.3456, 45.7890] } df1 = pd.DataFrame(data1) df2 = pd.DataFrame(data2) # Create a PDF class class PDF(FPDF): def header(self): self.set_font('Arial', 'B', 12) self.cell(0, 10, 'PDF Report with Charts and Tables', 0, 1, 'C') self.ln(10) def chapter_title(self, title): self.set_font('Arial', 'B', 12) self.cell(0, 10, title, 0, 1, 'L') self.ln(5) def table(self, df): self.set_font('Helvetica', '', 10) # Calculate column widths index_col_width = max(self.get_string_width(str(index)) for index in df.index) + 10 col_widths = {col: self.get_string_width(col) + 10 for col in df.columns} max_col_width = max(col_widths.values()) # Row height row_height = self.font_size + 5 # Header self.set_fill_color(255, 255, 255) self.set_draw_color(0, 0, 0) # Wrap headers x_start = self.get_x() y_start = self.get_y() self.multi_cell(index_col_width, row_height, 'Member', border=1, align='C', fill=True) self.set_xy(x_start + index_col_width, y_start) for col_name in df.columns: x_start = self.get_x() y_start = self.get_y() self.multi_cell(max_col_width, row_height, col_name, border=1, align='C', fill=True) self.set_xy(x_start + max_col_width, y_start) self.ln(row_height) # Data fill = False for index, row in df.iterrows(): fill = not fill self.set_fill_color(240, 240, 240) if fill else self.set_fill_color(255, 255, 255) self.cell(index_col_width, row_height, str(index), border=1, fill=True, align='L') for cell in row: formatted_cell = f"{cell:.2f}" if isinstance(cell, float) else str(cell) self.cell(max_col_width, row_height, formatted_cell, border=1, fill=True, align='L') self.ln(row_height) # Create a PDF document pdf = PDF() pdf.set_auto_page_break(auto=True, margin=15) # Add first table pdf.add_page(orientation='L') pdf.chapter_title('Table 1: Category vs Values') pdf.table(df1) # Add second table pdf.add_page(orientation='L') pdf.chapter_title('Table 2: Category vs Values') pdf.table(df2) # Create chart for demonstration plt.figure(figsize=(10, 5.63)) # Adjust figure size to fit within page plt.bar(df1['Category'], df1['Values'], color='skyblue') plt.title('Sample Bar Chart') plt.xlabel('Category') plt.ylabel('Values') plt.savefig('bar_chart.png') # Save the figure plt.close() # Add chart pdf.add_page(orientation='L') pdf.chapter_title('Sample Bar Chart') pdf.image('bar_chart.png', x=10, y=30, w=250) # Adjust the positioning and size as needed # Output the PDF pdf.output('report_test_2_check.pdf') This gives me the below: Below is an excel example of what I expect for the second table: Continue reading...