File size: 4,315 Bytes
23e73f9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import os
def create_variance_attribution_chart():
# ==========================================
# 物理级环境重置:抹除所有全局样式污染
# ==========================================
mpl.style.use('default')
mpl.rcParams.update(mpl.rcParamsDefault)
mpl.rcParams['axes.grid'] = False
mpl.rcParams['axes.axisbelow'] = True
mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.sans-serif'] = ['Helvetica', 'Arial']
# ==========================================
# 数据准备
# ==========================================
categories = ['Opacity', 'Anisotropy', 'Scale', 'SH Energy Ratio', 'PSNR']
method_variance = [86, 68, 43, 17, 1.4]
scene_variance = [10, 20, 45, 57, 98.6]
categories.reverse()
method_variance.reverse()
scene_variance.reverse()
color_method = '#4C72B0'
color_scene = '#DD8452'
# ==========================================
# 画图配置
# ==========================================
fig, ax = plt.subplots(figsize=(8, 4.5))
y_pos = np.arange(len(categories))
bar_height = 0.6
bars_method = ax.barh(y_pos, method_variance, height=bar_height,
color=color_method, edgecolor='none', label=r'Method ($SS_{method}$)', zorder=3)
bars_scene = ax.barh(y_pos, scene_variance, left=method_variance, height=bar_height,
color=color_scene, edgecolor='none', label=r'Scene ($SS_{scene}$)', zorder=3)
# ==========================================
# 细节修饰
# ==========================================
ax.set_yticks(y_pos)
ax.set_yticklabels(categories, fontsize=11)
ax.set_xlim(0, 100)
ax.set_xticks([0, 20, 40, 60, 80, 100])
ax.set_xticklabels(['0%', '20%', '40%', '60%', '80%', '100%'], color='#555555')
for i, (m_val, s_val) in enumerate(zip(method_variance, scene_variance)):
if m_val > 5:
ax.text(m_val / 2, i, f'{m_val}%' if m_val == int(m_val) else f'{m_val}%',
ha='center', va='center', color='white', fontweight='bold', fontsize=10, zorder=4)
elif m_val > 0:
ax.text(m_val + 2, i, f'{m_val}%',
ha='left', va='center', color=color_method, fontweight='bold', fontsize=10, zorder=4)
if s_val > 5:
ax.text(m_val + s_val / 2, i, f'{s_val}%' if s_val == int(s_val) else f'{s_val}%',
ha='center', va='center', color='white', fontweight='bold', fontsize=10, zorder=4)
# ==========================================
# 彻底的坐标轴与网格清理机制 (终极防御)
# ==========================================
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_linewidth(1.5)
ax.spines['bottom'].set_color('#333333')
# 关闭 X 轴和 Y 轴的刻度短线
ax.tick_params(axis='y', length=0)
ax.tick_params(axis='x', length=0)
# 强制遍历底层实例并将其不可见化
ax.grid(False)
for line in ax.get_xgridlines() + ax.get_ygridlines():
line.set_visible(False)
line.set_color('none')
line.set_linewidth(0)
# ==========================================
# 分割线
# ==========================================
ax.axhline(y=0.5, color='#CCCCCC', linestyle='--', linewidth=1, zorder=2)
ax.set_title("Asymmetric Variance Attribution", fontsize=14, fontweight='bold', pad=20)
ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.08), ncol=2, frameon=False, fontsize=11)
plt.tight_layout()
out_dir = "/root/autodl-tmp/SplatAtlas/tex/figures"
os.makedirs(out_dir, exist_ok=True)
out_pdf = os.path.join(out_dir, "fig2_variance_attribution.pdf")
out_png = os.path.join(out_dir, "fig2_variance_attribution.png")
plt.savefig(out_pdf, format='pdf', bbox_inches='tight', dpi=300)
plt.savefig(out_png, format='png', bbox_inches='tight', dpi=300)
print(f"✅ Fig 2 生成成功 (全局样式污染已重置,底层网格实例已物理擦除): {out_pdf}")
if __name__ == "__main__":
create_variance_attribution_chart()
|