将样式应用到表格中的不同列

问题描述 投票:0回答:1

使用 reportlab 创建表格时尝试将颜色应用于特定列时出现错误。

这是我的可重现示例的整个脚本(您需要在第 109 行添加输出路径):

import pandas as pd
from datetime import datetime
from reportlab.platypus import Frame
from reportlab.lib.pagesizes import A4, landscape
from reportlab.platypus import PageTemplate
from reportlab.platypus import BaseDocTemplate
from reportlab.platypus import Image
from reportlab.lib.units import inch
from reportlab.platypus import Table, Paragraph
from reportlab.lib import colors
from reportlab.platypus import NextPageTemplate, PageBreak
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle

def on_page(canvas, doc, pagesize=A4):
    page_num = canvas.getPageNumber()
    canvas.drawCentredString(pagesize[0]/2, 50, str(page_num))

    now = datetime.now()
    today = now.strftime("%B %d, %Y")  
    current_time = now.strftime("%I:%M %p") 

    canvas.drawString(50, pagesize[1] - 50, f"{today}")
    canvas.drawString(50, pagesize[1] - 70, f"{current_time}") 

def on_page_landscape(canvas, doc):

  return on_page(canvas, doc, pagesize=landscape(A4))

def format_nums(num):
    if num < 0: 
       x = '(${:.2f})'.format(abs(num))
    elif num > 0:
        x = '${:.2f}'.format(num)
    else:
       x = '${:.0f}'.format(num)

    return x

def df2table(df, custom_style):
    for col in df.columns:
        if df[col].dtype == 'float64':
            df[col] = df[col].apply(lambda x: format_nums(x)) 

    #('BACKGROUND', (start_col, start_row), (end_col, end_row), color)
    return Table(
        [[Paragraph(col, custom_style) for col in df.columns]] + df.values.tolist(),
        style = [
        ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),  # Header font
        ('FONTSIZE', (0, 1), (-1, -1), 8),  # Body font size
        ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),  # Header text color
        ('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey),  # Header background color
        ('BACKGROUND', (0, 0), (0, 0), colors.lightblue),  # first Header background color
        ('BACKGROUND', (0, 1), (0, -1), colors.lightblue),  # First column background color
        ('LINEBELOW', (0, 0), (-1, 0), 1, colors.black),  # Line below header
        ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black),  # Inner grid lines
        ('BOX', (0, 0), (-1, -1), 1, colors.black)],  # Outer box
        hAlign = 'LEFT')

def df2table2(df, custom_style, commodity_cols):
    for col in df.columns:
        if df[col].dtype == 'float64':
            df[col] = df[col].apply(lambda x: format_nums(x))

    data = [[Paragraph(col, custom_style) for col in df.columns]] + df.values.tolist()
    
    #('BACKGROUND', (start_col, start_row), (end_col, end_row), color)
    style = [
        ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),  # Header font
        ('FONTSIZE', (0, 1), (-1, -1), 8),  # Body font size
        ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),  # Header text color
        ('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey),  # Header background color
        ('LINEBELOW', (0, 0), (-1, 0), 1, colors.black),  # Line below header
        ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black),  # Inner grid lines
        ('BOX', (0, 0), (-1, -1), 1, colors.black)]  # Outer box
    
    # Apply colors based on column types
    for i, col in enumerate(df.columns): 
        if col in commodity_cols:
            style.append(('BACKGROUND', (i, 1), (i, -1), colors.lightgrey))  # Commodity column
        else:
            if col != 'Counterparty':
                style.append(('BACKGROUND', (i, 1), (i, -1), colors.lightgreen))  # Aggregation column

    return Table(data, style, hAlign='LEFT')

df = pd.DataFrame({
        'Counterparty': ['foo', 'fizz', 'fizz', 'fizz','fizz', 'foo'],
        'Commodity': ['bar', 'bar', 'bar', 'bar','bar', 'ab cred'],
        'DealType': ['Buy', 'Buy', 'Buy', 'Buy', 'Buy', 'Buy'],
        'StartDate': ['07/01/2024', '09/01/2024', '10/01/2024', '11/01/2024', '12/01/2024', '01/01/2025'],
        'FloatPrice': [18.73, 17.12, 17.76, 18.72, 19.47, 20.26],
        'MTMValue':[10, 10, 10, 10, 10, 10]
        })

commodity_cols = df['Commodity'].unique()

out = pd.pivot_table(df, values = 'MTMValue', index='Counterparty', columns = 'Commodity', aggfunc='sum').reset_index().rename_axis(None, axis=1).fillna(0)
out['Cumulative Exposure'] = out[out.columns[1:]].sum(axis = 1)

path = <INSERT PDF OUTPUT FILE HERE>

padding = dict(
    leftPadding=72, 
    rightPadding=72,
    topPadding=72,
    bottomPadding=18)

portrait_frame = Frame(0, 0, *A4, **padding)
landscape_frame = Frame(0, 0, *landscape(A4), **padding)
            
portrait_template = PageTemplate(
    id='portrait', 
    frames=portrait_frame,
    onPage=on_page, 
    pagesize=A4)

landscape_template = PageTemplate(
    id='landscape', 
    frames=landscape_frame, 
    onPage=on_page_landscape, 
    pagesize=landscape(A4))

doc = BaseDocTemplate(
    path,
    pageTemplates=[
    #portrait_template
    landscape_template
    ]
)

styles = getSampleStyleSheet()
custom_style = ParagraphStyle(name='CustomStyle', fontSize=8)

# NOT WOKRING
#story = [
#    Paragraph('Title 1', styles['Title']),
#    Paragraph('Title 2', styles['Title']),
#    Paragraph("<br/><br/>", styles['Normal']),
#    Paragraph('Current Total Positions', styles['Heading2']),
#    df2table2(out, custom_style, commodity_cols)
#]

# WORKING
story = [
    Paragraph('Title 1', styles['Title']),
    Paragraph('Tilte 2', styles['Title']),
    Paragraph("<br/><br/>", styles['Normal']),
    Paragraph('Current Total Positions', styles['Heading2']),
    df2table(out, custom_style)
]

doc.build(story)

我的问题出现在

df2table2
函数中,并带有完整的错误消息:

unsupported operand type(s) for -=: 'float' and 'tuple'

我已经看了几个小时了,但我一辈子都无法弄清楚可能出了什么问题。有什么想法可能是什么问题吗?

python pandas reportlab
1个回答
0
投票

你的解决方案似乎对我有用。 pdf image

© www.soinside.com 2019 - 2024. All rights reserved.