| #!/usr/bin/env python3 | |
| """ | |
| Plot boxplot for agent duration distributions. | |
| """ | |
| import pandas as pd | |
| import matplotlib.pyplot as plt | |
| import matplotlib.font_manager as fm | |
| import numpy as np | |
| # Use Liberation Serif (Times New Roman compatible) | |
| try: | |
| fm.fontManager.addfont('/usr/share/fonts/truetype/liberation/LiberationSerif-Regular.ttf') | |
| fm.fontManager.addfont('/usr/share/fonts/truetype/liberation/LiberationSerif-Bold.ttf') | |
| plt.rcParams['font.family'] = 'Liberation Serif' | |
| except: | |
| plt.rcParams['font.family'] = 'serif' | |
| # Bold font for labels | |
| bold_font = fm.FontProperties(fname='/usr/share/fonts/truetype/liberation/LiberationSerif-Bold.ttf', size=20) | |
| # Style settings - consistent with other charts | |
| plt.rcParams.update({ | |
| 'font.size': 20, | |
| 'axes.labelsize': 24, | |
| 'xtick.labelsize': 20, | |
| 'ytick.labelsize': 21, | |
| 'figure.dpi': 300, | |
| 'savefig.dpi': 300, | |
| }) | |
| # Read data | |
| df = pd.read_excel('zsq_stats.xlsx') | |
| # Agent names | |
| agents = ['analyzer', 'generator', 'builder', 'validator', 'solver', 'checker'] | |
| agent_labels = ['Analyzer', 'Generator', 'Builder', 'Validator', 'Solver', 'Checker'] | |
| # Duration filter thresholds (in minutes) | |
| duration_thresholds = { | |
| 'analyzer': 30, | |
| 'generator': 20, | |
| 'builder': 60, | |
| 'validator': 60, | |
| 'solver': 60, | |
| 'checker': 60 | |
| } | |
| # Collect filtered duration data for each agent | |
| duration_data = [] | |
| for agent in agents: | |
| duration_col = f'{agent}_duration_ms' | |
| duration_min = df[duration_col].dropna() / 1000 / 60 | |
| threshold = duration_thresholds[agent] | |
| duration_filtered = duration_min[duration_min <= threshold] | |
| duration_data.append(duration_filtered.values) | |
| # Create figure | |
| fig, ax = plt.subplots(figsize=(10, 7)) | |
| # Create boxplot (hide outliers with showfliers=False, narrower boxes) | |
| bp = ax.boxplot(duration_data, tick_labels=agent_labels, patch_artist=True, showfliers=False, | |
| widths=0.6) | |
| # Colors - slightly darker (稍深的淡绿、淡橙、淡蓝、淡紫、淡红、浅绿) | |
| colors = ['#7AB08A', '#D49A70', '#8AB4D8', '#A0A0C8', '#E0AAAA', '#A8D098'] | |
| edge_colors = ['#5A8868', '#B07848', '#6888A8', '#787898', '#C08080', '#80A870'] | |
| for patch, color, edge in zip(bp['boxes'], colors, edge_colors): | |
| patch.set_facecolor(color) | |
| patch.set_edgecolor(edge) | |
| patch.set_linewidth(2.5) | |
| patch.set_alpha(0.9) | |
| # Style whiskers, caps, medians | |
| for whisker in bp['whiskers']: | |
| whisker.set_color('#666666') | |
| whisker.set_linewidth(2) | |
| for cap in bp['caps']: | |
| cap.set_color('#666666') | |
| cap.set_linewidth(2) | |
| for median in bp['medians']: | |
| median.set_color('#333333') | |
| median.set_linewidth(2.5) | |
| # Add mean values as text above each box (at the top whisker position) | |
| for i, data in enumerate(duration_data): | |
| mean_val = np.mean(data) | |
| # Get the top whisker position (Q3 + 1.5*IQR or max within that range) | |
| q1 = np.percentile(data, 25) | |
| q3 = np.percentile(data, 75) | |
| iqr = q3 - q1 | |
| whisker_top = min(np.max(data), q3 + 1.5 * iqr) | |
| ax.text(i + 1, whisker_top + 1.5, f'{mean_val:.1f}', ha='center', va='bottom', | |
| fontproperties=bold_font, color='#222222') | |
| # Style the plot | |
| ax.set_ylabel('Duration (min)', fontsize=24) | |
| ax.tick_params(axis='x', labelsize=20) | |
| ax.tick_params(axis='y', labelsize=21) | |
| # Remove top and right spines | |
| ax.spines['top'].set_visible(False) | |
| ax.spines['right'].set_visible(False) | |
| plt.tight_layout() | |
| plt.savefig('agent_duration_boxplot.png', dpi=300, bbox_inches='tight') | |
| plt.savefig('agent_duration_boxplot.pdf', bbox_inches='tight') | |
| print('Saved: agent_duration_boxplot.png') | |
| print('Saved: agent_duration_boxplot.pdf') | |
| plt.close() | |
Xet Storage Details
- Size:
- 3.62 kB
- Xet hash:
- 7281faa3ca2b86b5cb439c7488fe5c2c52057ae49c999e5114d870f04a7f527d
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.