fig, ax = plt.subplots(figsize=(7.9, 3.6)) # 在实际发图单元创建画布与坐标轴
scenarios_names = [row['场景'] for row in results] # 提取三种相关性情景标签
portfolio_stds = [row['组合波动率'] for row in results] # 提取考虑协方差的波动率
weighted_stds = [row['加权平均波动率'] for row in results] # 提取不考虑相关性的对照波动率
x = np.arange(len(scenarios_names)) # 生成情景横轴位置
width = 0.35 # 设置组内柱宽
bars1 = ax.bar(x - width/2, weighted_stds, width, label='加权平均波动率', color='coral', alpha=0.7) # 绘制未考虑相关性的对照柱
bars2 = ax.bar(x + width/2, portfolio_stds, width, label='组合波动率', color='steelblue', alpha=0.7) # 绘制组合波动率柱
ax.set_title('相关性对投资组合风险的影响', fontsize=18,pad=18) # 增加标题内边距并与柱顶标签分离
ax.set_ylabel('年化波动率', fontsize=16) # 标注风险量纲并满足投影字号
ax.set_xticks(x) # 固定情景刻度位置
ax.set_xticklabels(scenarios_names,fontsize=16) # 显示相关性情景名称并满足投影字号
ax.tick_params(axis='y',labelsize=16) # 保证纵轴刻度投影可读
ax.legend(fontsize=16) # 显示两类风险口径并满足投影字号
ax.grid(axis='y', alpha=0.3) # 添加风险比较网格
ax.set_ylim(0,max(weighted_stds)*1.35) # 为柱顶数值与图内标题保留明确垂直间距
for bars in [bars1, bars2]: # 逐组处理柱形标签
for bar in bars: # 逐柱提取高度
height = bar.get_height() # 读取柱形风险值
ax.text(bar.get_x() + bar.get_width()/2., height,
f'{height:.2%}', ha='center', va='bottom', fontsize=16,clip_on=False) # 在柱顶标出百分比且不侵入标题区
plt.tight_layout() # 收紧图形布局
plt.show() # 在当前单元发出完整图形