matplotlib 标准三线统计表格绘制尝试

表格样式

只有横线的表格(无垂直线),顶线、底线和标题行加粗,其余横线淡化。

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages

# 设置seaborn风格以获得更美观的图表
sns.set_style("white")

# 示例数据
data = {
    'Variable': ['A', 'B', 'C', 'D'],
    'Mean': [10.5, 20.3, 15.7, 12.8],
    'Std Dev': [1.2, 2.5, 1.8, 1.4],
    'N': [100, 150, 120, 130]
}
df = pd.DataFrame(data)

# 创建PDF
with PdfPages('output.pdf') as pdf:
    # 第一页:示例图像
    plt.figure(figsize=(8.5, 11))  # 标准A4尺寸(英寸)
    x = np.linspace(0, 10, 100)
    plt.plot(x, np.sin(x), label='sin(x)')
    plt.plot(x, np.cos(x), label='cos(x)')
    plt.title('Sample Plot', fontsize=14, pad=10)
    plt.xlabel('X-axis')
    plt.ylabel('Y-axis')
    plt.legend()
    plt.tight_layout()
    pdf.savefig()
    plt.close()

    # 第二页:三线式表格
    fig, ax = plt.subplots(figsize=(8.5, 11))
    ax.axis('off')  # 隐藏坐标轴

    # 创建表格
    table = ax.table(cellText=df.values,
                    colLabels=df.columns,
                    loc='center',
                    cellLoc='center',
                    colColours=['white'] * len(df.columns))

    # 设置表格样式
    table.auto_set_font_size(False)
    table.set_fontsize(10)
    table.scale(1.2, 1.2)  # 调整表格大小

    # 三线式表格样式
    for (i, j), cell in table.get_celld().items():
        cell.set_text_props(ha='center', va='center')
        cell.set_edgecolor('black')
        
        if i == 0:  # 标题行
            cell.set_text_props(weight='bold')
            cell.set_facecolor('white')
            cell.set_height(0.05)
            cell.set_linewidth(2)
            cell.visible_edges = 'horizontal'  # 上下边框
        elif i == len(df):  # 底线
            cell.set_linewidth(2)
            cell.visible_edges = 'B'  # 仅显示下边框
        else:  # 中间横线
            cell.set_linewidth(0.5)
            cell.visible_edges = 'B'  # 仅显示下边框

    pdf.savefig()
    plt.close()
  • 目标样式
    • 只有横线,无垂直线。
    • 顶线(表格最上方)、标题线下方线和底线加粗。
    • 标题行文字加粗。
    • 其他中间横线淡化。

案例分析

  • 尝试融合其他图表
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from matplotlib.backends.backend_pdf import PdfPages
import seaborn as sns

# Set Seaborn style for better aesthetics
sns.set_style("darkgrid")
sns.set_palette("husl")

# Monte Carlo simulation parameters
np.random.seed(42)
n_simulations = 5
years = np.arange(2001, 2101)
n_years = len(years)
initial_value = 1000  # Starting net value in 2001
annual_return = 0.05  # Expected annual return
volatility = 0.1      # Annual volatility
fixed_value_2100 = initial_value * (1 + annual_return) ** n_years  # Deterministic value in 2100

# Simulate net value paths using geometric Brownian motion
dt = 1  # Time step (1 year)
paths = np.zeros((n_simulations, n_years))
paths[:, 0] = initial_value
for t in range(1, n_years):
    random_shocks = np.random.normal(0, 1, n_simulations)
    paths[:, t] = paths[:, t-1] * np.exp((annual_return - 0.5 * volatility**2) * dt + volatility * np.sqrt(dt) * random_shocks)

# Create DataFrame for paths
paths_df = pd.DataFrame(paths, index=[f"Sim_{i+1}" for i in range(n_simulations)], columns=years)
base_path = initial_value * (1 + annual_return) ** np.arange(n_years)
base_df = pd.DataFrame([base_path], index=["Base"], columns=years)

# Extract 2100 net values
net_values_2100 = paths_df[2100]
base_net_value_2100 = base_df[2100].iloc[0]
ratios_2100 = (net_values_2100 / fixed_value_2100) - 1

# Statistical table data
stats_data = {
    'Simulation': [f"Sim_{i+1}" for i in range(n_simulations)],
    'Net Value (2100)': net_values_2100.values,
    'Ratio (2100)': ratios_2100.values
}
stats_df = pd.DataFrame(stats_data)

# Create PDF
with PdfPages('monte_carlo_output.pdf') as pdf:
    # First page: Three subfigures
    fig = plt.figure(figsize=(12, 8))  # A4 size in inches
    gs = GridSpec(1, 3, width_ratios=[6, 1, 1])  # Left plot wider

    # Left: Monte Carlo paths
    ax1 = fig.add_subplot(gs[0])
    colors = sns.color_palette("husl", n_simulations)
    for idx, color in zip(paths_df.index, colors):
        ax1.plot(years, paths_df.loc[idx], color=color, label=idx, linewidth=1.5)
    ax1.plot(years, base_df.loc["Base"], color='black', linestyle='--', label='Base', linewidth=1.5)
    ax1.set_title("Monte Carlo Net Value Paths (2001-2100)", fontsize=12)
    ax1.set_xlabel("Year", fontsize=10)
    ax1.set_ylabel("Net Value", fontsize=10)
    ax1.legend(loc='upper left', fontsize=8)
    ax1.grid(True)

    # Middle: Net value number line (2100)
    ax2 = fig.add_subplot(gs[1])
    ax2.axhline(base_net_value_2100, color='black', linestyle='--', alpha=0.3, label='Base')
    for idx, color, value in zip(net_values_2100.index, colors, net_values_2100):
        ax2.scatter(0, value, color=color, s=100, label=idx)
        ax2.annotate(f'{value:.2f}', (0.05, value), fontsize=8, color=color)
    ax2.set_xlim(-0.5, 0.5)
    ax2.set_ylim(net_values_2100.min() * 0.9, net_values_2100.max() * 1.1)
    ax2.set_xticks([])
    ax2.set_title("Net Value (2100)", fontsize=12)
    ax2.set_ylabel("Net Value", fontsize=10)
    ax2.grid(True, axis='y')

    # Right: Ratio number line (2100)
    ax3 = fig.add_subplot(gs[2])
    ax3.axhline(0, color='black', linestyle='--', alpha=0.3, label='Zero')
    for idx, color, ratio in zip(ratios_2100.index, colors, ratios_2100):
        ax3.scatter(0, ratio, color=color, s=100, label=idx)
        ax3.annotate(f'{ratio:.2%}', (0.05, ratio), fontsize=8, color=color)
    ax3.set_xlim(-0.5, 0.5)
    ax3.set_ylim(ratios_2100.min() * 0.9, ratios_2100.max() + 0.1 * 1.1)
    ax3.set_xticks([])
    ax3.set_title("Ratio (Sim/Fixed - 1, 2100)", fontsize=12)
    ax3.set_ylabel("Ratio", fontsize=10)
    ax3.grid(True, axis='y')

    plt.tight_layout()
    pdf.savefig(dpi=300)
    plt.close()

    # Second page: Three-line statistical table
    fig, ax = plt.subplots(figsize=(8.5, 11))
    ax.axis('off')  # Hide axes

    # Create table
    table = ax.table(cellText=stats_df.values,
                     colLabels=stats_df.columns,
                     loc='center',
                     cellLoc='center',
                     colColours=['white'] * len(stats_df.columns))

    # Set table styles
    table.auto_set_font_size(False)
    table.set_fontsize(10)
    table.scale(1.2, 1.2)

    # Three-line table style
    for (i, j), cell in table.get_celld().items():
        cell.set_text_props(ha='center', va='center')
        cell.set_edgecolor('black')
        if i == 0:  # Header row
            cell.set_text_props(weight='bold')
            cell.set_facecolor('white')
            cell.set_height(0.05)
            cell.set_linewidth(2)
            cell.visible_edges = 'horizontal'
        elif i == len(stats_df):  # Bottom line
            cell.set_linewidth(2)
            cell.visible_edges = 'B'
        else:  # Middle rows
            cell.set_linewidth(0.5)
            cell.visible_edges = 'B'

    pdf.savefig(dpi=300)
    plt.close()

print("Output saved as 'monte_carlo_output.pdf'.")
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值