import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import numpy as np plt.rcParams['font.family'] = 'sans-serif' for f in ['WenQuanYi Micro Hei', 'Noto Sans CJK SC', 'SimHei', 'DejaVu Sans']: try: plt.rcParams['font.sans-serif'] = [f] break except: continue plt.rcParams['axes.unicode_minus'] = False # Data l1 = {2:1887, 3:340, 4:91, 5:41, 6:7, 7:13, 8:4, 9:4, 10:2, 11:2, 12:1, 13:2, 19:1} l2 = {2:2249, 3:313, 4:39, 5:10, 6:7, 7:4, 8:1, 9:1, 12:1, 14:1} def group_5plus(d): g = {'2次': d.get(2,0), '3次': d.get(3,0), '4次': d.get(4,0), '5次': d.get(5,0), '6次+': sum(v for k,v in d.items() if k>=6)} return g l1g = group_5plus(l1) l2g = group_5plus(l2) cats = list(l1g.keys()) l1_vals = [l1g[c] for c in cats] l2_vals = [l2g[c] for c in cats] fig, axes = plt.subplots(1, 3, figsize=(18, 7)) # === Left: Side-by-side bar === x = np.arange(len(cats)) w = 0.35 bars1 = axes[0].bar(x - w/2, l1_vals, w, color='#4472C4', label='L1', edgecolor='white') bars2 = axes[0].bar(x + w/2, l2_vals, w, color='#ED7D31', label='L2', edgecolor='white') for bar in bars1: h = bar.get_height() if h > 0: axes[0].text(bar.get_x()+bar.get_width()/2, h+max(l1_vals)*0.02, str(int(h)), ha='center', fontsize=9, color='#4472C4') for bar in bars2: h = bar.get_height() if h > 0: axes[0].text(bar.get_x()+bar.get_width()/2, h+max(l2_vals)*0.02, str(int(h)), ha='center', fontsize=9, color='#ED7D31') axes[0].set_xticks(x) axes[0].set_xticklabels(cats, fontsize=11) axes[0].set_ylabel('重复学习组合数', fontsize=12) axes[0].set_title('重复次数分布对比', fontsize=14, fontweight='bold') axes[0].legend(fontsize=11) axes[0].grid(axis='y', alpha=0.2, linestyle='--') axes[0].set_ylim(0, max(max(l1_vals), max(l2_vals))*1.15) # === Middle: L1 pie === l1_pie = [l1g[c] for c in cats] l1_total = sum(l1_pie) wedges1, _, autotexts1 = axes[1].pie(l1_pie, labels=None, colors=['#4472C4','#5B9BD5','#9DC3E6','#BDD7EE','#D6E4F0'], autopct='%1.1f%%', startangle=90, textprops={'fontsize': 10}) axes[1].set_title(f'L1 分布\n(951人, 2,395组合)', fontsize=14, fontweight='bold') axes[1].legend(wedges1, [f'{c}: {v} ({v/l1_total*100:.1f}%)' for c,v in zip(cats, l1_pie)], loc='lower center', fontsize=9) # === Right: L2 pie === l2_pie = [l2g[c] for c in cats] l2_total = sum(l2_pie) wedges2, _, autotexts2 = axes[2].pie(l2_pie, labels=None, colors=['#ED7D31','#F4B183','#F8CBAD','#FBE5D6','#F2F2F2'], autopct='%1.1f%%', startangle=90, textprops={'fontsize': 10}) axes[2].set_title(f'L2 分布\n(397人, 2,626组合)', fontsize=14, fontweight='bold') axes[2].legend(wedges2, [f'{c}: {v} ({v/l2_total*100:.1f}%)' for c,v in zip(cats, l2_pie)], loc='lower center', fontsize=9) fig.suptitle('最近3个月(2026.03-05)L1 vs L2 重复学习分布对比', fontsize=16, fontweight='bold', y=1.02) # Summary stats fig.text(0.5, 0.01, f'L1: 活跃7,280人, 重复951人(13.1%), 人均2.5组合, 最高19次 | ' f'L2: 活跃3,776人, 重复397人(10.5%), 人均6.6组合, 最高14次', ha='center', fontsize=10, color='#555') plt.tight_layout(rect=[0, 0.05, 1, 0.95]) plt.savefig('/root/.openclaw/workspace/output/repeat_l1_l2_3m.png', dpi=150, bbox_inches='tight') print('Saved.')