ai_member_xiaoxi/scripts/single_duration_chart.py
2026-05-29 08:00:01 +08:00

79 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 from query
labels = ['0分钟\n(无数据)', '5-10', '10-15', '15-20', '20-25', '25-30',
'30-35', '35-40', '40-50', '50-60', '60-90', '90+']
counts = [14990, 8945, 33817, 21566, 11563, 5411, 2412, 1210, 957, 385, 313, 153]
pcts = [14.7, 8.8, 33.2, 21.2, 11.4, 5.3, 2.4, 1.2, 0.9, 0.4, 0.3, 0.2]
fig, ax = plt.subplots(figsize=(16, 7))
x = np.arange(len(labels))
colors = ['#E74C3C' if i == 0 else plt.cm.Blues(0.3 + 0.7*i/len(labels)) for i in range(len(labels))]
bars = ax.bar(x, counts, color=colors, edgecolor='white', linewidth=0.5)
# Labels
for bar, v, p in zip(bars, counts, pcts):
if v > 200:
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + max(counts)*0.015,
f'{v:,}\n({p}%)', ha='center', fontsize=9, color='#333', fontweight='bold')
ax.set_xticks(x)
ax.set_xticklabels(labels, fontsize=10)
ax.set_ylabel('完成次数', fontsize=13)
ax.set_title('最近3个月2026.03-05完成一个课时学习时长分布', fontsize=16, fontweight='bold')
ax.grid(axis='y', alpha=0.2, linestyle='--')
ax.set_ylim(0, max(counts) * 1.22)
# Summary box
stats_text = (
f'总完成: 101,724次\n'
f'平均: 14.8分钟\n'
f'中位数: 13.8分钟\n'
f'排除空数据平均: 17.4分钟\n'
f'无时长数据: 14,990次(14.7%)'
)
ax.text(0.98, 0.95, stats_text, transform=ax.transAxes, fontsize=11,
verticalalignment='top', horizontalalignment='right',
bbox=dict(boxstyle='round', facecolor='#FFFDE7', alpha=0.9, edgecolor='#CCC'),
fontfamily='monospace')
# Key insight annotation
ax.annotate('峰值: 10-15分钟\n占33.2%', xy=(2, 33817), xytext=(5, 28000),
arrowprops=dict(arrowstyle='->', color='#333', lw=1.5),
fontsize=11, color='#333', fontweight='bold',
bbox=dict(boxstyle='round,pad=0.3', facecolor='#FFF2CC', alpha=0.8))
# Distribution curve
from scipy import interpolate
nonzero_x = x[1:] # skip 0-min
nonzero_counts = np.array(counts[1:], dtype=float)
smooth_x = np.linspace(nonzero_x[0], nonzero_x[-1], 200)
try:
tck = interpolate.splrep(nonzero_x, nonzero_counts, s=5000)
smooth_y = interpolate.splev(smooth_x, tck)
ax.plot(smooth_x, smooth_y, '-', color='#C0392B', linewidth=2, alpha=0.6, label='平滑趋势')
ax.legend(fontsize=10)
except:
pass
fig.text(0.5, 0.01, '统计口径: 最近3个月 play_status=1 的课时完成记录, 时长=单次完成所有组件 interval_time 之和/60000(分钟)',
ha='center', fontsize=9, color='#888')
plt.tight_layout(rect=[0, 0.04, 1, 0.95])
plt.savefig('/root/.openclaw/workspace/output/single_duration_3m.png', dpi=150, bbox_inches='tight')
print('Saved.')