You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 06:37:08