绘制蒙特卡洛模拟可视化图的案例

原始模版

Python (Matplotlib 和 Seaborn) 的模板,用于展示蒙特卡洛模拟数据的折线图和分布图。这个模板将包含:

  1. 将所有模拟路径的图分离为单独的图表,确保更清晰地展示每条路径。
  2. 均值和置信区间的折线图,添加统计指标(均值、偏度、峰度)。
  3. 最终年份值的分布直方图。
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from scipy.stats import skew, kurtosis
import os

# 设置 Seaborn 样式和调色板
sns.set_style("darkgrid")
sns.set_palette("husl")

def plot_monte_carlo_simulation(data, years, title="Monte Carlo Simulation", save_dir="output"):
    """
    绘制蒙特卡洛模拟可视化图并保存为 PNG 和 PDF 格式
    data: shape (n_simulations, n_years) 的数组
    years: 年份列表
    title: 图表标题
    save_dir: 保存图片的文件夹路径
    """
    # 确保保存文件夹存在
    os.makedirs(save_dir, exist_ok=True)

    # 图1: 所有模拟路径(单独图表)
    plt.figure(figsize=(10, 6))
    for i in range(data.shape[0]):
        plt.plot(years, data[i, :], alpha=0.3, linewidth=0.5, label=f'Simulation {i+1}' if i < 5 else None)
    plt.title('All Simulation Paths')
    plt.xlabel('Year')
    plt.ylabel('Value')
    plt.grid(True, alpha=0.3)
    # plt.legend(loc='upper left', fontsize=8, ncol=2)  # 只显示前5条路径的图例,避免过于拥挤
    # 保存图1
    plt.savefig(os.path.join(save_dir, "simulation_paths.png"), dpi=300, bbox_inches='tight')
    plt.savefig(os.path.join(save_dir, "simulation_paths.pdf"), bbox_inches='tight')
    plt.tight_layout()
    plt.show()

    # 图2: 均值和置信区间
    fig, (ax2, ax3) = plt.subplots(1, 2, figsize=(15, 5))
    
    # 计算统计指标
    mean_values = np.mean(data, axis=0)
    std_values = np.std(data, axis=0)
    ci_upper = mean_values + 1.96 * std_values
    ci_lower = mean_values - 1.96 * std_values
    
    # 最终年份的统计指标
    final_values = data[:, -1]
    mean_final = np.mean(final_values)
    skew_final = skew(final_values)
    kurt_final = kurtosis(final_values)
    
    # 均值和置信区间图
    ax2.plot(years, mean_values, label='Mean', linewidth=2)
    ax2.fill_between(years, ci_lower, ci_upper, alpha=0.2, label='95% CI')
    ax2.set_title('Mean and 95% Confidence Interval')
    ax2.set_xlabel('Year')
    ax2.set_ylabel('Value')
    ax2.grid(True, alpha=0.3)
    ax2.legend()
    
    # 添加统计指标文本
    stats_text = f'Mean (Final Year): {mean_final:.2f}\nSkewness (Final Year): {skew_final:.2f}\nKurtosis (Final Year): {kurt_final:.2f}'
    ax2.text(0.02, 0.98, stats_text, transform=ax2.transAxes, verticalalignment='top', 
             bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
    
    # 图3: 最终年份分布
    sns.histplot(final_values, kde=True, ax=ax3)
    ax3.set_title(f'Distribution at Year {years[-1]}')
    ax3.set_xlabel('Value')
    ax3.set_ylabel('Frequency')
    
    plt.suptitle(title, fontsize=16)
    # 保存图2
    plt.savefig(os.path.join(save_dir, "mean_and_distribution.png"), dpi=300, bbox_inches='tight')
    plt.savefig(os.path.join(save_dir, "mean_and_distribution.pdf"), bbox_inches='tight')
    plt.tight_layout()
    plt.show()

# 示例数据生成
if __name__ == "__main__":
    # 生成示例数据
    np.random.seed(42)
    n_simulations = 1000
    n_years = 100
    years = np.arange(2001, 2101)
    
    # 模拟数据 (这里用随机游走作为示例)
    data = np.zeros((n_simulations, n_years))
    for i in range(n_simulations):
        data[i, :] = np.cumsum(np.random.normal(0, 1, n_years))
    
    # 调用可视化函数,指定保存文件夹
    plot_monte_carlo_simulation(data, years, "Example Monte Carlo Simulation", save_dir="monte_carlo_output")

代码说明

  1. 包含三个子图:
    • 左上:所有1000条模拟路径(半透明显示)
    • 左下:均值线和95%置信区间
    • 右下:2100年值的分布直方图(带核密度估计)
  2. 需要安装的库:numpy, matplotlib, seaborn, pandas, scipy
  3. 数据格式:输入数据为 shape (1000, 100) 的 numpy 数组,代表1000条模拟路径,每条路径包含2001到2100年的值。
  4. 可通过修改 title 参数自定义图表标题
  5. 在均值与置信区间图和最终年份分布图中,添加了最终年份(2100年)数据的统计指标:均值、偏度、峰度。
  6. 保存功能
    • 图表将自动保存到指定的 save_dir 文件夹(默认值为 "output")。
      • 确保 save_dir 是有效的文件夹路径(如 "C:/Users/YourName/Output""./results"),建议使用原始字符串(r"C:\path\to\folder")。
      • 如果文件夹不存在,代码会自动创建。
      • PNG 文件使用高分辨率(dpi=300),PDF 文件为矢量格式,适合出版。

注意事项

  1. 传入 plot_monte_carlo_simulation 函数
  2. 确保 years 参数与目标数据的年份范围匹配
  3. 可根据需要调整图表大小、颜色等参数
  4. 修改 dpi 参数调整 PNG 文件的分辨率

修改方案一

修改计划

  1. 图1(All Simulation Paths)

    • 保留所有1000条模拟路径。
    • 添加一条重要的分界线(新模拟数据),以醒目方式(例如粗线、不同颜色)显示。
    • 保存为 PNG 和 PDF 格式。
  2. 图2(Mean and Boundary Lines)

    • 修改为只显示:
      • 所有模拟路径的上边界线(最大值)。
      • 所有模拟路径的下边界线(最小值)。
      • 所有模拟路径的均值线。
      • 新添加的分界线。
    • 移除置信区间和其他统计指标。
    • 保存为 PNG 和 PDF 格式。
  3. 图3(Final Year Scatter Plot)

    • 修改为2100年所有1000条模拟数据的散点图。
    • 将突出显示的分界线值为一条水平线,
    • 保存为 PNG 和 PDF 格式。
  4. 表格(与图3一起显示在PDF中)

    • 均值(np.mean(final_values)
    • 标准差(np.std(final_values)
    • 偏度(scipy.stats.skew
    • 峰度(scipy.stats.kurtosis
    • 分界线值(boundary_data[-1]
    • 大于分界线值的模拟数量
    • 小于或等于分界线值的模拟数量
    • 使用 plt.table 绘制,与图3一起保存

方案假设

  • 新分界线数据(boundary_data)为一条与原有模拟数据相同长度(100年)的数组,格式为 numpy 数组或列表。
  • 保存文件夹仍使用 save_dir 参数,默认值为 monte_carlo_output

更新后的代码

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from scipy.stats import skew, kurtosis
import os
from matplotlib.backends.backend_pdf import PdfPages

# 设置 Seaborn 样式和调色板
sns.set_style("darkgrid")
sns.set_palette("husl")

def plot_monte_carlo_simulation(data, years, boundary_data, title="Monte Carlo Simulation", save_dir="output"):
    """
    绘制蒙特卡洛模拟可视化图并保存为 PNG 和 PDF 格式
    data: shape (n_simulations, n_years) 的数组
    years: 年份列表
    boundary_data: 新增的分界线数据,shape (n_years,)
    title: 图表标题
    save_dir: 保存图片的文件夹路径
    """
    # 确保保存文件夹存在
    os.makedirs(save_dir, exist_ok=True)

    # 图1: 所有模拟路径 + 分界线
    plt.figure(figsize=(10, 6))
    for i in range(data.shape[0]):
        plt.plot(years, data[i, :], alpha=0.3, linewidth=0.5, label=f'Simulation {i+1}' if i < 5 else None)
    plt.plot(years, boundary_data, color='red', linewidth=2, label='Boundary Line')
    plt.title('All Simulation Paths')
    plt.xlabel('Year')
    plt.ylabel('Value')
    plt.grid(True, alpha=0.3)
    plt.legend(loc='upper left', fontsize=8, ncol=2)
    
    # 保存图1
    plt.savefig(os.path.join(save_dir, "simulation_paths.png"), dpi=300, bbox_inches='tight')
    plt.savefig(os.path.join(save_dir, "simulation_paths.pdf"), bbox_inches='tight')
    plt.tight_layout()
    plt.show()
    plt.close()

    # 图2: 均值线 + 上下边界线 + 分界线
    plt.figure(figsize=(10, 6))
    mean_values = np.mean(data, axis=0)
    upper_bound = np.max(data, axis=0)
    lower_bound = np.min(data, axis=0)
    
    plt.plot(years, mean_values, label='Mean', linewidth=2, color='blue')
    plt.plot(years, upper_bound, label='Upper Bound', linewidth=1.5, color='green', linestyle='--')
    plt.plot(years, lower_bound, label='Lower Bound', linewidth=1.5, color='purple', linestyle='--')
    plt.plot(years, boundary_data, label='Boundary Line', linewidth=2, color='red')
    
    plt.title('Mean and Boundary Lines')
    plt.xlabel('Year')
    plt.ylabel('Value')
    plt.grid(True, alpha=0.3)
    plt.legend(loc='upper left', fontsize=8)
    
    # 保存图2
    plt.savefig(os.path.join(save_dir, "mean_and_boundaries.png"), dpi=300, bbox_inches='tight')
    plt.savefig(os.path.join(save_dir, "mean_and_boundaries.pdf"), bbox_inches='tight')
    plt.tight_layout()
    plt.show()
    plt.close()

    # 图3: 最终年份散点图 + 水平分界线 + 表格
    final_values = data[:, -1]
    boundary_final = boundary_data[-1]
    
    # 计算统计指标
    mean_final = np.mean(final_values)
    std_final = np.std(final_values)
    skew_final = skew(final_values)
    kurt_final = kurtosis(final_values)
    count_above = np.sum(final_values > boundary_final)
    count_below_or_equal = np.sum(final_values <= boundary_final)
    
    # 创建 PDF 文件保存图3和表格
    pdf_path = os.path.join(save_dir, "final_year_scatter_and_stats.pdf")
    with PdfPages(pdf_path) as pdf:
        # 图3: 散点图 + 水平分界线
        plt.figure(figsize=(10, 6))
        plt.scatter(range(1, len(final_values) + 1), final_values, alpha=0.5, s=10, label='Simulations')
        plt.axhline(y=boundary_final, color='red', linewidth=2, label='Boundary Line')
        plt.title(f'Final Year ({years[-1]}) Values')
        plt.xlabel('Simulation Index')
        plt.ylabel('Value')
        plt.grid(True, alpha=0.3)
        plt.legend(loc='upper left', fontsize=8)
        
        # 保存到 PDF
        pdf.savefig(bbox_inches='tight')
        plt.savefig(os.path.join(save_dir, "final_year_scatter.png"), dpi=300, bbox_inches='tight')
        plt.tight_layout()
        plt.show()
        plt.close()
        
        # 表格
        stats_data = {
            'Statistic': ['Mean', 'Standard Deviation', 'Skewness', 'Kurtosis', 'Boundary Value', 
                         'Count > Boundary', 'Count ≤ Boundary'],
            'Value': [f'{mean_final:.2f}', f'{std_final:.2f}', f'{skew_final:.2f}', f'{kurt_final:.2f}', 
                      f'{boundary_final:.2f}', f'{count_above}', f'{count_below_or_equal}']
        }
        stats_df = pd.DataFrame(stats_data)
        
        plt.figure(figsize=(6, 4))
        plt.axis('off')
        table = plt.table(cellText=stats_df.values, colLabels=stats_df.columns, loc='center', cellLoc='center')
        table.auto_set_font_size(False)
        table.set_fontsize(10)
        table.scale(1.2, 1.2)
        plt.title('Final Year Statistics')
        
        # 保存到 PDF
        pdf.savefig(bbox_inches='tight')
        plt.close()

# 示例数据生成
if __name__ == "__main__":
    # 生成示例数据
    np.random.seed(42)
    n_simulations = 1000
    n_years = 100
    years = np.arange(2001, 2101)
    
    # 模拟数据 (随机游走)
    data = np.zeros((n_simulations, n_years))
    for i in range(n_simulations):
        data[i, :] = np.cumsum(np.random.normal(0, 1, n_years))
    
    # 示例分界线数据 (线性增长加噪声)
    boundary_data = np.linspace(0, 10, n_years) + np.random.normal(0, 0.5, n_years)
    
    # 调用可视化函数
    plot_monte_carlo_simulation(data, years, boundary_data, "Example Monte Carlo Simulation", save_dir="monte_carlo_output")

代码说明

  1. 图1(All Simulation Paths)

    • 保留1000条模拟路径(透明度 alpha=0.3)。
    • 添加分界线(boundary_data),使用红色粗线(color='red', linewidth=2)突出显示。
    • 保存为 simulation_paths.pngsimulation_paths.pdf
  2. 图2(Mean and Boundary Lines)

    • 显示:
      • 均值线(蓝色实线)。
      • 上边界线(绿色虚线,np.max(data, axis=0))。
      • 下边界线(紫色虚线,np.min(data, axis=0))。
      • 分界线(红色实线)。
    • 保存为 mean_and_boundaries.pngmean_and_boundaries.pdf
  3. 图3(Final Year Scatter Plot)

    • 使用 plt.scatter 绘制2100年所有模拟值的散点图(s=10, alpha=0.5)。
    • 将分界线值的突出显示(红色星形标记)改为水平线,使用 plt.axhline(y=boundary_final, color='red', linewidth=2)
    • 保留1000条模拟数据的散点图(s=10, alpha=0.5)。
    • 保存为 final_year_scatter.pngfinal_year_scatter_and_stats.pdf(包含散点图和表格)。
  4. 表格

    • 表格与图3一起保存到 final_year_scatter_and_stats.pdf 中,使用 PdfPages 实现多页 PDF。

使用说明

  1. 输入数据

    • data:shape 为 (1000, 100) 的 numpy 数组,代表1000条模拟路径。
    • years:年份数组(如 np.arange(2001, 2101))。
    • boundary_data:新分界线数据,shape 为 (100,) 的 numpy 数组或列表。
    • 示例中,boundary_data 为线性增长加噪声的数据,您需要替换为您的实际分界线数据。
  2. 保存路径

    • 默认保存到 monte_carlo_output 文件夹。
    • 可自定义,例如:
      plot_monte_carlo_simulation(data, years, boundary_data, save_dir="custom_folder")
      
    • 输出文件:
      • simulation_paths.png, simulation_paths.pdf
      • mean_and_boundaries.png, mean_and_boundaries.pdf
      • final_year_scatter.png, final_year_scatter_and_stats.pdf(包含散点图和表格)
  3. 依赖库

    • numpy, matplotlib, seaborn, pandas, scipy
    • 安装:pip install numpy matplotlib seaborn pandas scipy
  4. 注意事项

    • 分界线数据:确保 boundary_data 的长度与 years 一致(100年)。
    • 文件覆盖:同名文件会被覆盖,建议使用唯一的 save_dir
    • PDF 多页final_year_scatter_and_stats.pdf 包含两页(散点图和表格)。
    • 表格格式:表格字体大小和缩放已优化(fontsize=10, scale=1.2)。

修改方案二

只修改了输出方式,从分散输出到合并输出。

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from scipy.stats import skew, kurtosis
import os
from matplotlib.backends.backend_pdf import PdfPages

# 设置 Seaborn 样式和调色板
sns.set_style("darkgrid")
sns.set_palette("husl")

def plot_monte_carlo_simulation(data, years, boundary_data, title="Monte Carlo Simulation", save_dir="output", scenario="monte_carlo_results"):
    """
    绘制蒙特卡洛模拟可视化图并保存为 PNG 和合并的 PDF 格式
    data: shape (n_simulations, n_years) 的数组
    years: 年份列表
    boundary_data: 新增的分界线数据,shape (n_years,)
    title: 图表标题
    save_dir: 保存图片的文件夹路径
    scenario: 合并 PDF 文件的名称
    """
    # 确保保存文件夹存在
    os.makedirs(save_dir, exist_ok=True)

    # 创建合并的 PDF 文件
    pdf_path = os.path.join(save_dir, f"{scenario}.pdf")
    with PdfPages(pdf_path) as pdf:
        # 图1: 所有模拟路径 + 分界线
        plt.figure(figsize=(10, 6))
        for i in range(data.shape[0]):
            plt.plot(years, data[i, :], alpha=0.3, linewidth=0.5, label=f'Simulation {i+1}' if i < 5 else None)
        plt.plot(years, boundary_data, color='red', linewidth=2, label='Boundary Line')
        plt.title('All Simulation Paths')
        plt.xlabel('Year')
        plt.ylabel('Value')
        plt.grid(True, alpha=0.3)
        plt.legend(loc='upper left', fontsize=8, ncol=2)
        
        # 保存图1为 PNG 和 PDF
        plt.savefig(os.path.join(save_dir, "simulation_paths.png"), dpi=300, bbox_inches='tight')
        pdf.savefig(bbox_inches='tight')
        plt.tight_layout()
        plt.show()
        plt.close()

        # 图2: 均值线 + 上下边界线 + 分界线
        plt.figure(figsize=(10, 6))
        mean_values = np.mean(data, axis=0)
        upper_bound = np.max(data, axis=0)
        lower_bound = np.min(data, axis=0)
        
        plt.plot(years, mean_values, label='Mean', linewidth=2, color='blue')
        plt.plot(years, upper_bound, label='Upper Bound', linewidth=1.5, color='green', linestyle='--')
        plt.plot(years, lower_bound, label='Lower Bound', linewidth=1.5, color='purple', linestyle='--')
        plt.plot(years, boundary_data, label='Boundary Line', linewidth=2, color='red')
        
        plt.title('Mean and Boundary Lines')
        plt.xlabel('Year')
        plt.ylabel('Value')
        plt.grid(True, alpha=0.3)
        plt.legend(loc='upper left', fontsize=8)
        
        # 保存图2为 PNG 和 PDF
        plt.savefig(os.path.join(save_dir, "mean_and_boundaries.png"), dpi=300, bbox_inches='tight')
        pdf.savefig(bbox_inches='tight')
        plt.tight_layout()
        plt.show()
        plt.close()

        # 图3: 最终年份散点图 + 水平分界线
        final_values = data[:, -1]
        boundary_final = boundary_data[-1]
        
        # 计算统计指标
        mean_final = np.mean(final_values)
        std_final = np.std(final_values)
        skew_final = skew(final_values)
        kurt_final = kurtosis(final_values)
        count_above = np.sum(final_values > boundary_final)
        count_below_or_equal = np.sum(final_values <= boundary_final)
        
        plt.figure(figsize=(10, 6))
        plt.scatter(range(1, len(final_values) + 1), final_values, alpha=0.5, s=10, label='Simulations')
        plt.axhline(y=boundary_final, color='red', linewidth=2, label='Boundary Line')
        plt.title(f'Final Year ({years[-1]}) Values')
        plt.xlabel('Simulation Index')
        plt.ylabel('Value')
        plt.grid(True, alpha=0.3)
        plt.legend(loc='upper left', fontsize=8)
        
        # 保存图3为 PNG 和 PDF
        plt.savefig(os.path.join(save_dir, "final_year_scatter.png"), dpi=300, bbox_inches='tight')
        pdf.savefig(bbox_inches='tight')
        plt.tight_layout()
        plt.show()
        plt.close()
        
        # 表格
        stats_data = {
            'Statistic': ['Mean', 'Standard Deviation', 'Skewness', 'Kurtosis', 'Boundary Value', 
                         'Count > Boundary', 'Count ≤ Boundary'],
            'Value': [f'{mean_final:.2f}', f'{std_final:.2f}', f'{skew_final:.2f}', f'{kurt_final:.2f}', 
                      f'{boundary_final:.2f}', f'{count_above}', f'{count_below_or_equal}']
        }
        stats_df = pd.DataFrame(stats_data)
        
        plt.figure(figsize=(6, 4))
        plt.axis('off')
        table = plt.table(cellText=stats_df.values, colLabels=stats_df.columns, loc='center', cellLoc='center')
        table.auto_set_font_size(False)
        table.set_fontsize(10)
        table.scale(1.2, 1.2)
        plt.title('Final Year Statistics')
        
        # 保存表格到 PDF
        pdf.savefig(bbox_inches='tight')
        plt.close()

# 示例数据生成
if __name__ == "__main__":
    # 生成示例数据
    np.random.seed(42)
    n_simulations = 1000
    n_years = 100
    years = np.arange(2001, 2101)
    
    # 模拟数据 (随机游走)
    data = np.zeros((n_simulations, n_years))
    for i in range(n_simulations):
        data[i, :] = np.cumsum(np.random.normal(0, 1, n_years))
    
    # 示例分界线数据 (线性增长加噪声)
    boundary_data = np.linspace(0, 10, n_years) + np.random.normal(0, 0.5, n_years)
    
    # 调用可视化函数,指定 scenario
    plot_monte_carlo_simulation(data, years, boundary_data, "Example Monte Carlo Simulation", 
                                save_dir="monte_carlo_output", scenario="example_scenario")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值