使用Python-fpdf实现PDF表格表头自动换行的问题求助
解决FPDF库中表格表头自动换行的问题
我在用Python的fpdf库生成PDF报告时,需要将DataFrame中的数据转换成表格和图表,操作逻辑类似Excel,但遇到了表头无法自动换行的问题——长表头会超出单元格宽度,无法像Excel那样自动换行适配单元格。以下是修改后的可行代码,以及关键调整说明:
修改后的完整代码
import pandas as pd from fpdf import FPDF import matplotlib.pyplot as plt 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) # 自定义PDF类 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) # 计算列宽度,限制最大列宽避免过宽 index_col_width = max(self.get_string_width(str(index)) for index in df.index) + 10 col_widths = {} for col in df.columns: calc_width = self.get_string_width(col) + 10 col_widths[col] = calc_width if calc_width < 80 else 80 max_col_width = max(col_widths.values()) # 预计算每个表头需要的行高 header_heights = [] temp_x, temp_y = self.get_x(), self.get_y() # 计算索引列表头高度 h = self.multi_cell(index_col_width, self.font_size + 2, 'Member', border=0, align='C') header_heights.append(h) self.set_xy(temp_x, temp_y) # 计算各数据列表头高度 for col_name in df.columns: offset_x = temp_x + index_col_width + sum(col_widths[col] for col in list(df.columns)[:list(df.columns).index(col_name)]) self.set_xy(offset_x, temp_y) h = self.multi_cell(col_widths[col_name], self.font_size + 2, col_name, border=0, align='C') header_heights.append(h) # 取最大高度作为统一表头行高 header_row_height = max(header_heights) data_row_height = self.font_size + 5 # 数据行高度可按需调整 # 绘制表头 self.set_fill_color(255, 255, 255) self.set_draw_color(0, 0, 0) x_start, y_start = temp_x, temp_y self.multi_cell(index_col_width, header_row_height, 'Member', border=1, align='C', fill=True) current_x = x_start + index_col_width for col_name in df.columns: self.set_xy(current_x, y_start) self.multi_cell(col_widths[col_name], header_row_height, col_name, border=1, align='C', fill=True) current_x += col_widths[col_name] # 定位到数据行起始位置 self.set_xy(x_start, y_start + header_row_height) # 绘制数据行 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, data_row_height, str(index), border=1, fill=True, align='L') current_x = x_start + index_col_width for col_name, cell in zip(df.columns, row): self.set_xy(current_x, self.get_y()) formatted_cell = f"{cell:.2f}" if isinstance(cell, float) else str(cell) self.cell(col_widths[col_name], data_row_height, formatted_cell, border=1, fill=True, align='L') current_x += col_widths[col_name] self.ln(data_row_height) # 生成PDF文档 pdf = PDF() pdf.set_auto_page_break(auto=True, margin=15) # 添加第一个表格 pdf.add_page(orientation='L') pdf.chapter_title('Table 1: Category vs Values') pdf.table(df1) # 添加第二个表格 pdf.add_page(orientation='L') pdf.chapter_title('Table 2: Category vs Values') pdf.table(df2) # 生成示例图表 plt.figure(figsize=(10, 5.63)) plt.bar(df1['Category'], df1['Values'], color='skyblue') plt.title('Sample Bar Chart') plt.xlabel('Category') plt.ylabel('Values') plt.savefig('bar_chart.png') plt.close() # 添加图表到PDF pdf.add_page(orientation='L') pdf.chapter_title('Sample Bar Chart') pdf.image('bar_chart.png', x=10, y=30, w=250) # 输出PDF pdf.output('report_test_2_check.pdf')
关键调整说明
- 限制列宽+预计算表头高度:给列宽设置最大阈值(80)避免过宽,先临时绘制表头获取每个表头的实际高度,取最大值作为统一表头行高,保证所有表头单元格高度一致。
- 修正坐标定位:绘制每个表头单元格时重新定位x坐标,避免
multi_cell自动换行导致的偏移;表头绘制完成后,将坐标精准移动到表头下方,确保数据行与表头对齐。 - 适配数据行高度:数据行高度可单独调整,保证表格整体布局美观。
效果对比
- 原问题效果:长表头文本超出单元格宽度,无法自动换行,导致内容显示不全或列宽异常。
- 期望效果(Excel示例):长表头文本自动换行,在单元格内多行显示,列宽保持合理,表格整齐美观。
- 修改后效果:完美实现类似Excel的表头自动换行功能,长表头适配单元格宽度自动换行,表格布局规整。
内容的提问来源于stack exchange,提问作者Farrep7
相关产品推荐
相关产品推荐

