案例任务:
- 读取四个CSV文件(两个模拟:2020模拟,2025模拟;两个实际:2020实际,2025实际),并将它们转换为DataFrame,其中第一列’simulation’作为行索引,第一行作为列索引。
注意:实际数据的simulation值为101,模拟数据的simulation值为1到100。 - 从2020年(模拟和实际)数据中取出“基金资产价值”和“基金申购赎回价值”,从2025年(模拟和实际)数据中取出“基金应收管理费价值”和“银行托管费价值”,计算一个特殊指标DBX。
公式:DBX = (2020年的基金资产价值 - 2020年的基金申购赎回价值) - (2025年的基金应收管理费 - 2025年的银行托管费价值)
同时,取出2025年的基金资产价值。 - 绘制两种图:
- 单变量图:将2025年的基金资产价值、2025年的基金应收管理费价值和特殊指标DBX这三个变量分别绘制在同一个画布的三个子图中。
对于每个变量,先将模拟数据(100次模拟)从小到大排序,x轴为排序后的序号(1到100),然后将其实际数据(simulation=101)用不同颜色标注在图中。 - 双变量图:首先依据2025年的基金应收管理费价值(模拟数据)从小到大排序,然后以这个排序后的序号为x轴,在同一个图中绘制两条线:
- 左y轴:2025年的基金资产价值(模拟数据)
- 右y轴:特殊指标DBX(模拟数据)
- 同时,将实际数据(2025年的基金资产价值和DBX)分别标注在对应的线上(用实际2025年的基金应收管理费价值在排序后的位置来确定x坐标)。
- 单变量图:将2025年的基金资产价值、2025年的基金应收管理费价值和特殊指标DBX这三个变量分别绘制在同一个画布的三个子图中。
版本1.0
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 1. Read and transform CSV files into DataFrames
def load_and_transform_csv(file_path):
df = pd.read_csv(file_path)
# Set 'simulation' as index and transpose to make variables as columns
df = df.set_index('simulation').transpose()
return df
# Load simulated and actual data for 2020 and 2025
df_2020_sim = load_and_transform_csv('2020_simulated_data.csv')
df_2020_actual = load_and_transform_csv('2020_actual_data.csv')
df_2025_sim = load_and_transform_csv('2025_simulated_data.csv')
df_2025_actual = load_and_transform_csv('2025_actual_data.csv')
# 2. Calculate DBX indicator
def calculate_dbx():
# Extract required variables
fund_asset_2020 = df_2020_sim.loc['fund_asset_value'] # 2020 Fund Asset Value (simulated)
fund_net_2020 = df_2020_sim.loc['fund_subscription_redemption'] # 2020 Fund Subscription/Redemption
mgmt_fee_2025 = df_2025_sim.loc['fund_management_fee'] # 2025 Fund Management Fee
custody_fee_2025 = df_2025_sim.loc['bank_custody_fee'] # 2025 Bank Custody Fee
# Extract actual values (simulation=101)
fund_asset_2020_actual = df_2020_actual.loc['fund_asset_value', 101]
fund_net_2020_actual = df_2020_actual.loc['fund_subscription_redemption', 101]
mgmt_fee_2025_actual = df_2025_actual.loc['fund_management_fee', 101]
custody_fee_2025_actual = df_2025_actual.loc['bank_custody_fee', 101]
# Calculate DBX for simulated data
dbx = (fund_asset_2020 - fund_net_2020) - (mgmt_fee_2025 - custody_fee_2025)
# Calculate DBX for actual data
dbx_actual = (fund_asset_2020_actual - fund_net_2020_actual) - (mgmt_fee_2025_actual - custody_fee_2025_actual)
# Extract 2025 Fund Asset Value
fund_asset_2025 = df_2025_sim.loc['fund_asset_value']
fund_asset_2025_actual = df_2025_actual.loc['fund_asset_value', 101]
return dbx, dbx_actual, fund_asset_2025, fund_asset_2025_actual, mgmt_fee_2025, mgmt_fee_2025_actual
# Compute DBX and extract variables
dbx, dbx_actual, fund_asset_2025, fund_asset_2025_actual, mgmt_fee_2025, mgmt_fee_2025_actual = calculate_dbx()
# 3. Plotting
# Single-variable scatter plots
fig1, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15, 5), sharey=False)
fig1.suptitle('Single Variable Scatter Plots (2025 and DBX)')
# Sort values for plotting
fund_asset_2025_sorted = np.sort(fund_asset_2025)
mgmt_fee_2025_sorted = np.sort(mgmt_fee_2025)
dbx_sorted = np.sort(dbx)
# Plot Fund Asset Value 2025
ax1.scatter(range(len(fund_asset_2025_sorted)), fund_asset_2025_sorted, c='blue', label='Simulated')
ax1.scatter([0], [fund_asset_2025_actual], c='red', marker='*', s=200, label='Actual')
ax1.set_title('Fund Asset Value 2025')
ax1.set_xlabel('Sorted Order')
ax1.set_ylabel('Value')
ax1.legend()
# Plot Fund Management Fee 2025
ax2.scatter(range(len(mgmt_fee_2025_sorted)), mgmt_fee_2025_sorted, c='blue', label='Simulated')
ax2.scatter([0], [mgmt_fee_2025_actual], c='red', marker='*', s=200, label='Actual')
ax2.set_title('Fund Management Fee 2025')
ax2.set_xlabel('Sorted Order')
ax2.set_ylabel('Value')
ax2.legend()
# Plot DBX
ax3.scatter(range(len(dbx_sorted)), dbx_sorted, c='blue', label='Simulated')
ax3.scatter([0], [dbx_actual], c='red', marker='*', s=200, label='Actual')
ax3.set_title('DBX Indicator')
ax3.set_xlabel('Sorted Order')
ax3.set_ylabel('Value')
ax3.legend()
plt.tight_layout()
# Double-variable scatter plots
fig2, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5), sharey=False)
fig2.suptitle('Double Variable Scatter Plots (Sorted by Fund Management Fee 2025)')
# Sort by Fund Management Fee 2025
sorted_indices = np.argsort(mgmt_fee_2025)
mgmt_fee_2025_sorted = mgmt_fee_2025[sorted_indices]
fund_asset_2025_sorted = fund_asset_2025[sorted_indices]
dbx_sorted = dbx[sorted_indices]
# Plot Fund Asset Value vs Fund Management Fee
ax1.scatter(range(len(mgmt_fee_2025_sorted)), mgmt_fee_2025_sorted, c='blue', label='Management Fee')
ax1.set_xlabel('Sorted Order')
ax1.set_ylabel('Management Fee Value', color='blue')
ax1.tick_params(axis='y', labelcolor='blue')
ax1_twin = ax1.twinx()
ax1_twin.scatter(range(len(fund_asset_2025_sorted)), fund_asset_2025_sorted, c='green', label='Fund Asset Value')
ax1_twin.scatter([0], [fund_asset_2025_actual], c='red', marker='*', s=200, label='Actual Fund Asset')
ax1_twin.set_ylabel('Fund Asset Value', color='green')
ax1_twin.tick_params(axis='y', labelcolor='green')
ax1.set_title('Fund Asset Value vs Management Fee')
ax1.legend(loc='upper left')
ax1_twin.legend(loc='upper right')
# Plot DBX vs Fund Management Fee
ax2.scatter(range(len(mgmt_fee_2025_sorted)), mgmt_fee_2025_sorted, c='blue', label='Management Fee')
ax2.set_xlabel('Sorted Order')
ax2.set_ylabel('Management Fee Value', color='blue')
ax2.tick_params(axis='y', labelcolor='blue')
ax2_twin = ax2.twinx()
ax2_twin.scatter(range(len(dbx_sorted)), dbx_sorted, c='orange', label='DBX')
ax2_twin.scatter([0], [dbx_actual], c='red', marker='*', s=200, label='Actual DBX')
ax2_twin.set_ylabel('DBX Value', color='orange')
ax2_twin.tick_params(axis='y', labelcolor='orange')
ax2.set_title('DBX vs Management Fee')
ax2.legend(loc='upper left')
ax2_twin.legend(loc='upper right')
plt.tight_layout()
plt.show()
版本2.0
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import glob
import os
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 1. 读取和处理CSV文件
def load_and_process_data(file_path):
"""读取CSV文件并处理为DataFrame,设置simulation为索引"""
df = pd.read_csv(file_path)
df.set_index('simulation', inplace=True)
return df
# 2. 计算特殊指标DBX
def calculate_dbx(data_2020, data_2025):
"""
计算DBX指标:(2020基金资产价值 - 2020基金申购赎回价值) - (2025基金应收管理费 - 2025银行托管费价值)
返回DBX和2025基金资产价值
"""
# 假设列名如下,请根据实际数据调整
asset_2020 = data_2020['基金资产价值']
sub_red_2020 = data_2020['基金申购赎回价值']
mgmt_fee_2025 = data_2025['基金应收管理费价值']
custody_fee_2025 = data_2025['银行托管费价值']
asset_2025 = data_2025['基金资产价值']
dbx = (asset_2020 - sub_red_2020) - (mgmt_fee_2025 - custody_fee_2025)
return dbx, asset_2025
# 3. 绘制单变量图
def plot_single_variable(asset_2025_sim, mgmt_fee_2025_sim, dbx_sim,
asset_2025_actual, mgmt_fee_2025_actual, dbx_actual):
"""绘制单变量图"""
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
# 对模拟数据进行排序
asset_2025_sorted = np.sort(asset_2025_sim)
mgmt_fee_2025_sorted = np.sort(mgmt_fee_2025_sim)
dbx_sorted = np.sort(dbx_sim)
# 绘制2025基金资产价值
axes[0].scatter(range(len(asset_2025_sorted)), asset_2025_sorted, alpha=0.7, label='模拟数据')
axes[0].axhline(y=asset_2025_actual, color='r', linestyle='-', label='实际数据')
axes[0].set_title('2025年基金资产价值')
axes[0].set_xlabel('排序序号')
axes[0].set_ylabel('价值')
axes[0].legend()
# 绘制2025基金应收管理费价值
axes[1].scatter(range(len(mgmt_fee_2025_sorted)), mgmt_fee_2025_sorted, alpha=0.7, label='模拟数据')
axes[1].axhline(y=mgmt_fee_2025_actual, color='r', linestyle='-', label='实际数据')
axes[1].set_title('2025年基金应收管理费价值')
axes[1].set_xlabel('排序序号')
axes[1].set_ylabel('价值')
axes[1].legend()
# 绘制DBX指标
axes[2].scatter(range(len(dbx_sorted)), dbx_sorted, alpha=0.7, label='模拟数据')
axes[2].axhline(y=dbx_actual, color='r', linestyle='-', label='实际数据')
axes[2].set_title('DBX指标')
axes[2].set_xlabel('排序序号')
axes[2].set_ylabel('价值')
axes[2].legend()
plt.tight_layout()
plt.savefig('单变量图.png', dpi=300)
plt.show()
# 4. 绘制双变量图
def plot_dual_variable(mgmt_fee_2025_sim, asset_2025_sim, dbx_sim,
mgmt_fee_2025_actual, asset_2025_actual, dbx_actual):
"""绘制双变量图"""
fig, ax1 = plt.subplots(figsize=(12, 8))
# 按2025基金应收管理费价值排序
sorted_indices = np.argsort(mgmt_fee_2025_sim)
mgmt_fee_sorted = mgmt_fee_2025_sim[sorted_indices]
asset_sorted = asset_2025_sim[sorted_indices]
dbx_sorted = dbx_sim[sorted_indices]
# 绘制2025基金资产价值(左轴)
color1 = 'tab:blue'
ax1.set_xlabel('排序序号(按2025基金应收管理费价值排序)')
ax1.set_ylabel('2025基金资产价值', color=color1)
line1 = ax1.plot(range(len(asset_sorted)), asset_sorted, color=color1, alpha=0.7, label='2025基金资产价值(模拟)')
ax1.tick_params(axis='y', labelcolor=color1)
# 创建右轴
ax2 = ax1.twinx()
color2 = 'tab:red'
ax2.set_ylabel('DBX指标', color=color2)
line2 = ax2.plot(range(len(dbx_sorted)), dbx_sorted, color=color2, alpha=0.7, label='DBX指标(模拟)')
ax2.tick_params(axis='y', labelcolor=color2)
# 找到实际数据在排序后的位置
actual_idx = np.searchsorted(mgmt_fee_sorted, mgmt_fee_2025_actual)
# 标注实际数据点
ax1.scatter(actual_idx, asset_2025_actual, color=color1, s=100, marker='o', edgecolors='black', label='2025基金资产价值(实际)')
ax2.scatter(actual_idx, dbx_actual, color=color2, s=100, marker='s', edgecolors='black', label='DBX指标(实际)')
# 合并图例
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
plt.title('双变量图:按2025基金应收管理费价值排序')
plt.savefig('双变量图.png', dpi=300)
plt.show()
# 主程序
def main():
# 加载数据(请根据实际文件路径修改)
# 假设文件名为:sim_2020.csv, sim_2025.csv, actual_2020.csv, actual_2025.csv
sim_2020 = load_and_process_data('sim_2020.csv')
sim_2025 = load_and_process_data('sim_2025.csv')
actual_2020 = load_and_process_data('actual_2020.csv')
actual_2025 = load_and_process_data('actual_2025.csv')
# 提取实际数据(simulation=101)
actual_2020_row = actual_2020.loc[101]
actual_2025_row = actual_2025.loc[101]
# 计算DBX指标
# 模拟数据
dbx_sim, asset_2025_sim = calculate_dbx(sim_2020, sim_2025)
mgmt_fee_2025_sim = sim_2025['基金应收管理费价值']
# 实际数据
dbx_actual, asset_2025_actual = calculate_dbx(actual_2020_row, actual_2025_row)
mgmt_fee_2025_actual = actual_2025_row['基金应收管理费价值']
# 绘制单变量图
plot_single_variable(asset_2025_sim, mgmt_fee_2025_sim, dbx_sim,
asset_2025_actual, mgmt_fee_2025_actual, dbx_actual)
# 绘制双变量图
plot_dual_variable(mgmt_fee_2025_sim, asset_2025_sim, dbx_sim,
mgmt_fee_2025_actual, asset_2025_actual, dbx_actual)
if __name__ == "__main__":
main()
注意事项
- 根据实际数据文件路径修改代码中的文件名
- 根据实际列名修改代码中的变量名(如’基金资产价值’等)
- 代码假设CSV文件第一列名为"simulation" 和假设实际数据的simulation值为101
- 代码使用了中文字体设置,可选
- 代码会生成两个图像文件:
- 单变量图.png:包含三个子图,分别显示2025年基金资产价值、2025年基金应收管理费价值和DBX指标
- 双变量图.png:显示按2025年基金应收管理费价值排序后的2025年基金资产价值和DBX指标
版本2.1
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
# 设置中文字体支持
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
plt.rcParams['axes.unicode_minus'] = False # 正确显示负号
def add_rank_columns(df, sort_vars):
"""
Add ranking columns for specified variables using pd.assign method
Parameters:
df: pandas DataFrame
Input dataframe containing the variables to be ranked
sort_vars: str or list of str
Variable name(s) for which ranking columns should be created
Returns:
pandas DataFrame
New dataframe with added ranking columns. Each ranking column is named
with the original variable name plus the '_排名' suffix, containing
integer rankings calculated using the 'first' method for handling ties.
Notes:
- Uses pandas.Series.rank() with method='first' to break ties by order of appearance
- Ranking columns are created using dictionary comprehension and assigned with pd.assign()
- Original dataframe remains unchanged (returns a new dataframe)
"""
# Ensure sort_vars is converted to list format if single string provided
if isinstance(sort_vars, str):
sort_vars = [sort_vars]
# Create ranking columns using dictionary comprehension
rank_columns = {
f"{var}_排名": df[var].rank(method='first').astype(int)
for var in sort_vars
}
# Return new dataframe with all ranking columns added using assign
return df.assign(**rank_columns)
def plot_single_variables(df, variables, highlight_index=101, filename=None):
"""
绘制单变量分布图
参数:
df: pandas DataFrame
variables: 字符串列表,需要绘制的变量名称
highlight_index: 整数,需要特别标注的模拟索引
filename: 字符串,保存PDF的文件名(可选)
"""
if filename:
pdf_pages = PdfPages(filename)
fig, axes = plt.subplots(len(variables), 1, figsize=(10, 4*len(variables)))
if len(variables) == 1:
axes = [axes] # 确保axes是可迭代的
fig.suptitle('单变量分布图', fontsize=16)
for i, var in enumerate(variables):
# 对变量数据进行排序
sorted_data = df[var].sort_values().reset_index(drop=True)
ranks = np.arange(1, len(sorted_data) + 1)
# 绘制所有数据点
axes[i].plot(ranks, sorted_data, 'o', markersize=4, alpha=0.7, label=f'{var}所有模拟')
# 标注highlight_index的数据点
highlight_value = df.loc[highlight_index, var]
highlight_rank = (sorted_data == highlight_value).idxmax() + 1 # 找到排名
axes[i].plot(highlight_rank, highlight_value, 's', markersize=8,
color='orange', label=f'{var} (模拟{highlight_index})')
axes[i].set_xlabel('排名')
axes[i].set_ylabel(var)
axes[i].legend()
axes[i].grid(True, alpha=0.3)
plt.tight_layout()
if filename:
pdf_pages.savefig(fig)
plt.close(fig)
pdf_pages.close()
else:
plt.show()
def plot_double_variables(df, var_left1, var_left2, var_right, highlight_index=101, filename=None):
"""
绘制双变量关系图
参数:
df: pandas DataFrame
var_left1: 字符串,第一个图的左y轴变量
var_left2: 字符串,第二个图的左y轴变量
var_right: 字符串,两个图的右y轴变量(排序依据)
highlight_index: 整数,需要特别标注的模拟索引
filename: 字符串,保存PDF的文件名(可选)
"""
if filename:
pdf_pages = PdfPages(filename)
# 按var_right排序
sorted_df = df.sort_values(by=var_right)
ranks = np.arange(1, len(sorted_df) + 1)
# 获取highlight_index的数据在排序后的位置
highlight_idx_pos = sorted_df.index.get_loc(highlight_index)
highlight_rank = highlight_idx_pos + 1
highlight_right_value = sorted_df.iloc[highlight_idx_pos][var_right]
highlight_left1_value = sorted_df.iloc[highlight_idx_pos][var_left1]
highlight_left2_value = sorted_df.iloc[highlight_idx_pos][var_left2]
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))
fig.suptitle('双变量关系图', fontsize=16)
# 图一:var_left1 vs var_right
ax1.plot(ranks, sorted_df[var_left1], 'b-', label=var_left1)
ax1.set_xlabel(f'按{var_right}排序后的排名')
ax1.set_ylabel(var_left1, color='b')
ax1.tick_params(axis='y', labelcolor='b')
# 创建右轴
ax1_r = ax1.twinx()
ax1_r.plot(ranks, sorted_df[var_right], 'r-', label=var_right)
ax1_r.set_ylabel(var_right, color='r')
ax1_r.tick_params(axis='y', labelcolor='r')
# 标注highlight_index的点
ax1.plot(highlight_rank, highlight_left1_value, 'ko', markersize=8,
label=f'模拟{highlight_index} ({var_left1})')
ax1_r.plot(highlight_rank, highlight_right_value, 'ks', markersize=8,
label=f'模拟{highlight_index} ({var_right})')
# 添加图例
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax1_r.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
ax1.grid(True, alpha=0.3)
# 图二:var_left2 vs var_right
ax2.plot(ranks, sorted_df[var_left2], 'g-', label=var_left2)
ax2.set_xlabel(f'按{var_right}排序后的排名')
ax2.set_ylabel(var_left2, color='g')
ax2.tick_params(axis='y', labelcolor='g')
# 创建右轴
ax2_r = ax2.twinx()
ax2_r.plot(ranks, sorted_df[var_right], 'r-', label=var_right)
ax2_r.set_ylabel(var_right, color='r')
ax2_r.tick_params(axis='y', labelcolor='r')
# 标注highlight_index的点
ax2.plot(highlight_rank, highlight_left2_value, 'ko', markersize=8,
label=f'模拟{highlight_index} ({var_left2})')
ax2_r.plot(highlight_rank, highlight_right_value, 'ks', markersize=8,
label=f'模拟{highlight_index} ({var_right})')
# 添加图例
lines1, labels1 = ax2.get_legend_handles_labels()
lines2, labels2 = ax2_r.get_legend_handles_labels()
ax2.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
ax2.grid(True, alpha=0.3)
plt.tight_layout()
if filename:
pdf_pages.savefig(fig)
plt.close(fig)
pdf_pages.close()
else:
plt.show()
# 示例使用
if __name__ == "__main__":
# 创建示例数据
np.random.seed(42)
data = {
'基金资产价值': np.random.normal(100, 20, 101),
'基金应收管理费价值': np.random.normal(50, 10, 101),
'DBX': np.random.normal(0.5, 0.2, 101)
}
df = pd.DataFrame(data, index=range(1, 102))
# 添加排名列
df_ranked = add_rank_columns(df, '基金应收管理费价值')
print(df_ranked.head())
# 绘制单变量图并保存到PDF
plot_single_variables(
df,
['基金资产价值', '基金应收管理费价值', 'DBX'],
highlight_index=101,
filename='单变量图.pdf'
)
# 绘制双变量图并保存到PDF
plot_double_variables(
df,
var_left1='基金资产价值',
var_left2='DBX',
var_right='基金应收管理费价值',
highlight_index=101,
filename='双变量图.pdf'
)
代码说明:
- add_rank_columns 函数:
- 输入DataFrame和需要排序的变量名称
- 使用pandas的rank方法计算排名
- 返回添加了排名列的新DataFrame
- plot_single_variables 函数:
- 输入DataFrame、变量列表、需要高亮的索引和可选的文件名
- 绘制单变量分布图
- 如果提供了文件名,则将图保存到PDF
- plot_double_variables 函数:
- 输入DataFrame、两个左轴变量、一个右轴变量、需要高亮的索引和可选的文件名
- 绘制双变量关系图
- 如果提供了文件名,则将图保存到PDF
- 使用示例:
- 创建示例数据
- 使用add_rank_columns函数添加排名列
- 分别调用两个绘图函数并将结果保存到PDF
版本 3.0 复杂绘图系统:多数据源单变量和双变量图
三个主要函数:图像转PDF保存函数、单变量图函数和双变量图函数。系统支持最多4个DataFrame的对比分析,并自动调整画布布局。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
# 设置中文字体支持
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
plt.rcParams['axes.unicode_minus'] = False # 正确显示负号
def add_rank_columns(df, sort_vars):
"""
Add ranking columns for specified variables using pd.assign method
Parameters:
df: pandas DataFrame
Input dataframe containing the variables to be ranked
sort_vars: str or list of str
Variable name(s) for which ranking columns should be created
"""
# Ensure sort_vars is converted to list format if single string provided
if isinstance(sort_vars, str):
sort_vars = [sort_vars]
# Create ranking columns using dictionary comprehension
rank_columns = {
f"{var}_排名": df[var].rank(method='first').astype(int)
for var in sort_vars
}
# Return new dataframe with all ranking columns added using assign
return df.assign(**rank_columns)
def save_figures_to_pdf(figures, filename, dpi=300):
"""
将多个图形保存到高分辨率PDF文件
参数:
figures: matplotlib Figure对象列表
filename: 字符串,保存PDF的文件名
dpi: 整数,图像分辨率,默认300
"""
with PdfPages(filename) as pdf:
for i, fig in enumerate(figures):
pdf.savefig(fig, dpi=dpi)
plt.close(fig)
print(f"已保存 {len(figures)} 个图形到 {filename}")
def plot_single_variables(df_list, variables, highlight_index=101, labels=None):
"""
绘制单变量分布图,支持最多4个DataFrame对比
参数:
df_list: DataFrame或DataFrame列表,最多4个
variables: 字符串列表,需要绘制的变量名称
highlight_index: 整数,需要特别标注的模拟索引
labels: 字符串列表,每个DataFrame的标签(可选)
返回:
matplotlib Figure对象
"""
# 确保df_list是列表格式
if not isinstance(df_list, list):
df_list = [df_list]
# 限制最多4个DataFrame
if len(df_list) > 4:
df_list = df_list[:4]
print("警告: 只使用前4个DataFrame")
num_dfs = len(df_list)
# 如果没有提供标签,创建默认标签
if labels is None:
labels = [f"数据集 {i+1}" for i in range(num_dfs)]
elif len(labels) != num_dfs:
labels = [f"数据集 {i+1}" for i in range(num_dfs)]
print("警告: 标签数量与DataFrame数量不匹配,使用默认标签")
# 创建画布
fig, axes = plt.subplots(len(variables), num_dfs, figsize=(5*num_dfs, 4*len(variables)))
# 如果只有一个子图,确保axes是二维数组
if len(variables) == 1:
axes = axes.reshape(1, -1)
if num_dfs == 1:
axes = axes.reshape(-1, 1)
# 为每个DataFrame和每个变量绘制图形
for col_idx, (df, label) in enumerate(zip(df_list, labels)):
for row_idx, var in enumerate(variables):
ax = axes[row_idx, col_idx]
# 获取排序后的数据和排名
rank_col = f"{var}_排名"
sorted_df = df.sort_values(by=rank_col)
ranks = sorted_df[rank_col]
values = sorted_df[var]
# 绘制所有数据点
ax.plot(ranks, values, 'o', markersize=3, alpha=0.7, label=f'{var}所有模拟')
# 标注highlight_index的数据点
highlight_row = df[df.index == highlight_index]
if not highlight_row.empty:
highlight_rank = highlight_row[rank_col].values[0]
highlight_value = highlight_row[var].values[0]
ax.plot(highlight_rank, highlight_value, 's', markersize=6,
color='orange', label=f'{var} (模拟{highlight_index})')
ax.set_xlabel('排名')
ax.set_ylabel(var)
ax.set_title(f'{label}: {var}')
ax.legend(fontsize=8)
ax.grid(True, alpha=0.3)
plt.tight_layout()
return fig
def plot_double_variables(df_list, var_left1, var_left2, var_right, highlight_index=101, labels=None):
"""
绘制双变量关系图,支持最多4个DataFrame对比
参数:
df_list: DataFrame或DataFrame列表,最多4个
var_left1: 字符串,第一个图的左y轴变量
var_left2: 字符串,第二个图的左y轴变量
var_right: 字符串,两个图的右y轴变量(排序依据)
highlight_index: 整数,需要特别标注的模拟索引
labels: 字符串列表,每个DataFrame的标签(可选)
返回:
matplotlib Figure对象
"""
# 确保df_list是列表格式
if not isinstance(df_list, list):
df_list = [df_list]
# 限制最多4个DataFrame
if len(df_list) > 4:
df_list = df_list[:4]
print("警告: 只使用前4个DataFrame")
num_dfs = len(df_list)
# 如果没有提供标签,创建默认标签
if labels is None:
labels = [f"数据集 {i+1}" for i in range(num_dfs)]
elif len(labels) != num_dfs:
labels = [f"数据集 {i+1}" for i in range(num_dfs)]
print("警告: 标签数量与DataFrame数量不匹配,使用默认标签")
# 创建画布 - 2行(两个子图类型)x num_dfs列
fig, axes = plt.subplots(2, num_dfs, figsize=(5*num_dfs, 8))
# 如果只有一个子图,确保axes是二维数组
if num_dfs == 1:
axes = axes.reshape(2, 1)
# 为每个DataFrame绘制两个子图
for col_idx, (df, label) in enumerate(zip(df_list, labels)):
# 获取排序后的数据和排名
rank_col = f"{var_right}_排名"
sorted_df = df.sort_values(by=rank_col)
ranks = sorted_df[rank_col]
# 获取highlight_index的数据
highlight_row = df[df.index == highlight_index]
if not highlight_row.empty:
highlight_rank = highlight_row[rank_col].values[0]
highlight_right_value = highlight_row[var_right].values[0]
highlight_left1_value = highlight_row[var_left1].values[0]
highlight_left2_value = highlight_row[var_left2].values[0]
# 第一个子图:var_left1 vs var_right
ax1 = axes[0, col_idx]
ax1.plot(ranks, sorted_df[var_left1], 'b-', label=var_left1, alpha=0.7)
ax1.set_xlabel(f'按{var_right}排序后的排名')
ax1.set_ylabel(var_left1, color='b')
ax1.tick_params(axis='y', labelcolor='b')
# 创建右轴
ax1_r = ax1.twinx()
ax1_r.plot(ranks, sorted_df[var_right], 'r-', label=var_right, alpha=0.7)
ax1_r.set_ylabel(var_right, color='r')
ax1_r.tick_params(axis='y', labelcolor='r')
# 标注highlight_index的点
if not highlight_row.empty:
ax1.plot(highlight_rank, highlight_left1_value, 'ko', markersize=6,
label=f'模拟{highlight_index} ({var_left1})')
ax1_r.plot(highlight_rank, highlight_right_value, 'ks', markersize=6,
label=f'模拟{highlight_index} ({var_right})')
# 添加图例
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax1_r.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, fontsize=8, loc='upper left')
ax1.grid(True, alpha=0.3)
ax1.set_title(f'{label}: {var_left1} vs {var_right}')
# 第二个子图:var_left2 vs var_right
ax2 = axes[1, col_idx]
ax2.plot(ranks, sorted_df[var_left2], 'g-', label=var_left2, alpha=0.7)
ax2.set_xlabel(f'按{var_right}排序后的排名')
ax2.set_ylabel(var_left2, color='g')
ax2.tick_params(axis='y', labelcolor='g')
# 创建右轴
ax2_r = ax2.twinx()
ax2_r.plot(ranks, sorted_df[var_right], 'r-', label=var_right, alpha=0.7)
ax2_r.set_ylabel(var_right, color='r')
ax2_r.tick_params(axis='y', labelcolor='r')
# 标注highlight_index的点
if not highlight_row.empty:
ax2.plot(highlight_rank, highlight_left2_value, 'ko', markersize=6,
label=f'模拟{highlight_index} ({var_left2})')
ax2_r.plot(highlight_rank, highlight_right_value, 'ks', markersize=6,
label=f'模拟{highlight_index} ({var_right})')
# 添加图例
lines1, labels1 = ax2.get_legend_handles_labels()
lines2, labels2 = ax2_r.get_legend_handles_labels()
ax2.legend(lines1 + lines2, labels1 + labels2, fontsize=8, loc='upper left')
ax2.grid(True, alpha=0.3)
ax2.set_title(f'{label}: {var_left2} vs {var_right}')
plt.tight_layout()
return fig
# 示例使用
if __name__ == "__main__":
# 创建示例数据 - 4个不同时间点的数据集
np.random.seed(42)
dfs = []
labels = ["时间点1", "时间点2", "时间点3", "时间点4"]
for i in range(4):
# 为每个时间点创建略有不同的数据
data = {
'基金资产价值': np.random.normal(100 + i*5, 20, 101),
'基金应收管理费价值': np.random.normal(50 + i*2, 10, 101),
'DBX': np.random.normal(0.5 + i*0.1, 0.2, 101)
}
df = pd.DataFrame(data, index=range(1, 102))
# 添加排名列
df = add_rank_columns(df, ['基金资产价值', '基金应收管理费价值', 'DBX'])
dfs.append(df)
# 创建图形列表
figures = []
# 创建单变量图 - 使用所有4个DataFrame
fig1 = plot_single_variables(
dfs,
['基金资产价值', '基金应收管理费价值', 'DBX'],
highlight_index=101,
labels=labels
)
figures.append(fig1)
# 创建单变量图 - 只使用前2个DataFrame
fig2 = plot_single_variables(
dfs[:2],
['基金资产价值', '基金应收管理费价值', 'DBX'],
highlight_index=101,
labels=labels[:2]
)
figures.append(fig2)
# 创建双变量图 - 使用所有4个DataFrame
fig3 = plot_double_variables(
dfs,
var_left1='基金资产价值',
var_left2='DBX',
var_right='基金应收管理费价值',
highlight_index=101,
labels=labels
)
figures.append(fig3)
# 创建双变量图 - 只使用前2个DataFrame
fig4 = plot_double_variables(
dfs[:2],
var_left1='基金资产价值',
var_left2='DBX',
var_right='基金应收管理费价值',
highlight_index=101,
labels=labels[:2]
)
figures.append(fig4)
# 将所有图形保存到高分辨率PDF
save_figures_to_pdf(figures, '多数据源对比分析.pdf', dpi=300)
代码说明:
- add_rank_columns 函数
- 使用pd.assign方法添加排名列
- 为每个变量创建{变量名}_排名列
- 使用rank(method=‘first’)处理并列排名
- save_figures_to_pdf 函数
- 接收图形列表和高分辨率参数
- 使用PdfPages将所有图形保存到单个PDF文件
- 支持自定义DPI(默认300)
- plot_single_variables 函数
- 支持最多4个DataFrame的对比
- 自动调整画布布局(3×N,N为DataFrame数量)
- 使用排名列作为x轴
- 标注指定模拟索引的数据点
- 支持自定义标签
- plot_double_variables 函数
- 支持最多4个DataFrame的对比
- 自动调整画布布局(2×N,N为DataFrame数量)
- 使用排名列作为x轴
- 创建双y轴图表
- 标注指定模拟索引的数据点
- 支持自定义标签
使用示例:
- 准备数据:
- 创建多个DataFrame(最多4个)
- 使用add_rank_columns函数添加排名列
- 创建图形:
- 调用plot_single_variables创建单变量图
- 调用plot_double_variables创建双变量图
- 可以创建不同组合的图形(使用全部或部分DataFrame)
- 保存PDF:
- 将所有图形添加到列表中
- 调用save_figures_to_pdf保存为高分辨率PDF
优势:
- 灵活性:支持1-4个DataFrame的对比分析
- 自动化:自动调整画布布局和图形尺寸
- 高质量输出:支持高分辨率PDF输出
- 易于扩展:可以轻松添加更多DataFrame或变量类型
- 清晰的标签:支持为每个DataFrame添加自定义标签
Python蒙特卡洛模拟数据处理与可视化
187

被折叠的 条评论
为什么被折叠?



