| import matplotlib.pyplot as plt | |
| import pandas as pd | |
| import numpy as np | |
| from datetime import datetime | |
| from data import extract_model_data | |
| COLORS = { | |
| 'passed': '#4CAF50', | |
| 'failed': '#E53E3E', | |
| 'skipped': '#FFD54F', | |
| 'error': '#8B0000', | |
| 'amd': '#ED1C24', | |
| 'nvidia': '#76B900' | |
| } | |
| FIGURE_WIDTH = 20 | |
| FIGURE_HEIGHT = 12 | |
| BLACK = '#000000' | |
| LABEL_COLOR = '#CCCCCC' | |
| TITLE_COLOR = '#FFFFFF' | |
| GRID_COLOR = '#333333' | |
| TITLE_FONT_SIZE = 24 | |
| LABEL_FONT_SIZE = 14 | |
| LEGEND_FONT_SIZE = 12 | |
| def create_time_series_summary(historical_df: pd.DataFrame) -> plt.Figure: | |
| if historical_df.empty or 'date' not in historical_df.columns: | |
| fig, ax = plt.subplots(figsize=(FIGURE_WIDTH, FIGURE_HEIGHT), facecolor=BLACK) | |
| ax.set_facecolor(BLACK) | |
| ax.text(0.5, 0.5, 'No historical data available', | |
| horizontalalignment='center', verticalalignment='center', | |
| transform=ax.transAxes, fontsize=20, color='#888888', | |
| fontfamily='monospace', weight='normal') | |
| ax.axis('off') | |
| return fig | |
| historical_df['date_dt'] = pd.to_datetime(historical_df['date']) | |
| historical_df = historical_df.sort_values('date_dt') | |
| daily_stats = [] | |
| dates = [] | |
| for date in historical_df['date_dt'].unique(): | |
| date_data = historical_df[historical_df['date_dt'] == date] | |
| total_amd_passed = total_amd_failed = total_amd_skipped = 0 | |
| total_nvidia_passed = total_nvidia_failed = total_nvidia_skipped = 0 | |
| for _, row in date_data.iterrows(): | |
| amd_stats, nvidia_stats = extract_model_data(row)[:2] | |
| total_amd_passed += amd_stats['passed'] | |
| total_amd_failed += amd_stats['failed'] | |
| total_amd_skipped += amd_stats['skipped'] | |
| total_nvidia_passed += nvidia_stats['passed'] | |
| total_nvidia_failed += nvidia_stats['failed'] | |
| total_nvidia_skipped += nvidia_stats['skipped'] | |
| amd_total = total_amd_passed + total_amd_failed | |
| nvidia_total = total_nvidia_passed + total_nvidia_failed | |
| amd_failure_rate = (total_amd_failed / amd_total * 100) if amd_total > 0 else 0 | |
| nvidia_failure_rate = (total_nvidia_failed / nvidia_total * 100) if nvidia_total > 0 else 0 | |
| daily_stats.append({ | |
| 'amd_failure_rate': amd_failure_rate, | |
| 'nvidia_failure_rate': nvidia_failure_rate, | |
| 'amd_passed': total_amd_passed, | |
| 'amd_failed': total_amd_failed, | |
| 'amd_skipped': total_amd_skipped, | |
| 'nvidia_passed': total_nvidia_passed, | |
| 'nvidia_failed': total_nvidia_failed, | |
| 'nvidia_skipped': total_nvidia_skipped | |
| }) | |
| dates.append(date) | |
| fig = plt.figure(figsize=(FIGURE_WIDTH, FIGURE_HEIGHT + 4), facecolor=BLACK) | |
| gs = fig.add_gridspec(3, 2, height_ratios=[1.2, 1, 1], width_ratios=[2, 1], | |
| hspace=0.3, wspace=0.25) | |
| ax1 = fig.add_subplot(gs[0, :]) | |
| ax2 = fig.add_subplot(gs[1, 0]) | |
| ax3 = fig.add_subplot(gs[2, 0]) | |
| ax4 = fig.add_subplot(gs[1:, 1]) | |
| for ax in [ax1, ax2, ax3, ax4]: | |
| ax.set_facecolor(BLACK) | |
| dates_array = np.array(dates) | |
| amd_rates = [stat['amd_failure_rate'] for stat in daily_stats] | |
| nvidia_rates = [stat['nvidia_failure_rate'] for stat in daily_stats] | |
| ax1.fill_between(dates_array, 0, amd_rates, color=COLORS['amd'], alpha=0.15) | |
| ax1.fill_between(dates_array, 0, nvidia_rates, color=COLORS['nvidia'], alpha=0.15) | |
| ax1.plot(dates_array, amd_rates, color=COLORS['amd'], linewidth=3, | |
| label='AMD', marker='o', markersize=7, markeredgewidth=2, markeredgecolor=BLACK) | |
| ax1.plot(dates_array, nvidia_rates, color=COLORS['nvidia'], linewidth=3, | |
| label='NVIDIA', marker='s', markersize=7, markeredgewidth=2, markeredgecolor=BLACK) | |
| if len(amd_rates) > 2: | |
| z_amd = np.polyfit(range(len(amd_rates)), amd_rates, 1) | |
| p_amd = np.poly1d(z_amd) | |
| ax1.plot(dates_array, p_amd(range(len(amd_rates))), | |
| color=COLORS['amd'], linestyle='--', alpha=0.5, linewidth=2) | |
| z_nvidia = np.polyfit(range(len(nvidia_rates)), nvidia_rates, 1) | |
| p_nvidia = np.poly1d(z_nvidia) | |
| ax1.plot(dates_array, p_nvidia(range(len(nvidia_rates))), | |
| color=COLORS['nvidia'], linestyle='--', alpha=0.5, linewidth=2) | |
| ax1.set_title('Overall Failure Rates Over Time', fontsize=TITLE_FONT_SIZE, | |
| color=TITLE_COLOR, fontfamily='monospace', fontweight='bold', pad=20) | |
| ax1.set_ylabel('Failure Rate (%)', fontsize=LABEL_FONT_SIZE, color=LABEL_COLOR, fontfamily='monospace') | |
| ax1.grid(True, color=GRID_COLOR, alpha=0.3, linestyle='-', linewidth=0.5) | |
| ax1.legend(fontsize=LEGEND_FONT_SIZE, loc='upper right', frameon=False, | |
| labelcolor=LABEL_COLOR, prop={'family': 'monospace'}) | |
| ax1.tick_params(colors=LABEL_COLOR, labelsize=LABEL_FONT_SIZE, axis='x', rotation=45) | |
| amd_passed = [stat['amd_passed'] for stat in daily_stats] | |
| amd_failed = [stat['amd_failed'] for stat in daily_stats] | |
| amd_skipped = [stat['amd_skipped'] for stat in daily_stats] | |
| ax2.stackplot(dates_array, amd_passed, amd_failed, amd_skipped, | |
| colors=[COLORS['passed'], COLORS['failed'], COLORS['skipped']], | |
| alpha=0.8, labels=['Passed', 'Failed', 'Skipped']) | |
| ax2.set_title('AMD Test Results', fontsize=TITLE_FONT_SIZE - 2, | |
| color=TITLE_COLOR, fontfamily='monospace', fontweight='bold', pad=15) | |
| ax2.set_ylabel('Tests', fontsize=LABEL_FONT_SIZE, color=LABEL_COLOR, fontfamily='monospace') | |
| ax2.grid(True, color=GRID_COLOR, alpha=0.3, linestyle='-', linewidth=0.5) | |
| ax2.tick_params(colors=LABEL_COLOR, labelsize=LABEL_FONT_SIZE - 1, axis='x', rotation=45) | |
| nvidia_passed = [stat['nvidia_passed'] for stat in daily_stats] | |
| nvidia_failed = [stat['nvidia_failed'] for stat in daily_stats] | |
| nvidia_skipped = [stat['nvidia_skipped'] for stat in daily_stats] | |
| ax3.stackplot(dates_array, nvidia_passed, nvidia_failed, nvidia_skipped, | |
| colors=[COLORS['passed'], COLORS['failed'], COLORS['skipped']], | |
| alpha=0.8, labels=['Passed', 'Failed', 'Skipped']) | |
| ax3.set_title('NVIDIA Test Results', fontsize=TITLE_FONT_SIZE - 2, | |
| color=TITLE_COLOR, fontfamily='monospace', fontweight='bold', pad=15) | |
| ax3.set_ylabel('Tests', fontsize=LABEL_FONT_SIZE, color=LABEL_COLOR, fontfamily='monospace') | |
| ax3.set_xlabel('Date', fontsize=LABEL_FONT_SIZE, color=LABEL_COLOR, fontfamily='monospace') | |
| ax3.grid(True, color=GRID_COLOR, alpha=0.3, linestyle='-', linewidth=0.5) | |
| ax3.tick_params(colors=LABEL_COLOR, labelsize=LABEL_FONT_SIZE - 1, axis='x', rotation=45) | |
| latest = daily_stats[-1] | |
| metrics = [ | |
| ('Latest AMD Failure Rate', f"{latest['amd_failure_rate']:.1f}%", COLORS['amd']), | |
| ('Latest NVIDIA Failure Rate', f"{latest['nvidia_failure_rate']:.1f}%", COLORS['nvidia']), | |
| ('', '', None), | |
| ('Total AMD Tests', str(latest['amd_passed'] + latest['amd_failed'] + latest['amd_skipped']), '#888888'), | |
| ('Total NVIDIA Tests', str(latest['nvidia_passed'] + latest['nvidia_failed'] + latest['nvidia_skipped']), '#888888'), | |
| ] | |
| ax4.axis('off') | |
| y_pos = 0.9 | |
| ax4.text(0.5, 0.95, 'SUMMARY', ha='center', va='top', fontsize=TITLE_FONT_SIZE - 2, | |
| color=TITLE_COLOR, fontfamily='monospace', fontweight='bold', | |
| transform=ax4.transAxes) | |
| for label, value, color in metrics: | |
| if label: | |
| ax4.text(0.1, y_pos, label, ha='left', va='center', fontsize=LABEL_FONT_SIZE, | |
| color=LABEL_COLOR, fontfamily='monospace', transform=ax4.transAxes) | |
| ax4.text(0.9, y_pos, value, ha='right', va='center', fontsize=LABEL_FONT_SIZE + 2, | |
| color=color or LABEL_COLOR, fontfamily='monospace', fontweight='bold', | |
| transform=ax4.transAxes) | |
| y_pos -= 0.15 | |
| handles = [plt.Rectangle((0,0),1,1, fc=COLORS['passed'], alpha=0.8), | |
| plt.Rectangle((0,0),1,1, fc=COLORS['failed'], alpha=0.8), | |
| plt.Rectangle((0,0),1,1, fc=COLORS['skipped'], alpha=0.8)] | |
| ax4.legend(handles, ['Passed', 'Failed', 'Skipped'], | |
| loc='lower center', fontsize=LEGEND_FONT_SIZE, | |
| frameon=False, labelcolor=LABEL_COLOR, prop={'family': 'monospace'}) | |
| plt.close('all') | |
| return fig | |
| def create_model_time_series(historical_df: pd.DataFrame, model_name: str) -> plt.Figure: | |
| if historical_df.empty or 'date' not in historical_df.columns: | |
| fig, ax = plt.subplots(figsize=(FIGURE_WIDTH, FIGURE_HEIGHT), facecolor=BLACK) | |
| ax.set_facecolor(BLACK) | |
| ax.text(0.5, 0.5, f'No historical data available for {model_name}', | |
| horizontalalignment='center', verticalalignment='center', | |
| transform=ax.transAxes, fontsize=20, color='#888888', | |
| fontfamily='monospace', weight='normal') | |
| ax.axis('off') | |
| return fig | |
| model_data = historical_df[historical_df.index.str.lower() == model_name.lower()] | |
| if model_data.empty: | |
| fig, ax = plt.subplots(figsize=(FIGURE_WIDTH, FIGURE_HEIGHT), facecolor=BLACK) | |
| ax.set_facecolor(BLACK) | |
| ax.text(0.5, 0.5, f'No data found for model: {model_name}', | |
| horizontalalignment='center', verticalalignment='center', | |
| transform=ax.transAxes, fontsize=20, color='#888888', | |
| fontfamily='monospace', weight='normal') | |
| ax.axis('off') | |
| return fig | |
| model_data = model_data.copy() | |
| model_data['date_dt'] = pd.to_datetime(model_data['date']) | |
| model_data = model_data.sort_values('date_dt') | |
| dates = model_data['date_dt'].values | |
| amd_stats_list = [] | |
| nvidia_stats_list = [] | |
| for _, row in model_data.iterrows(): | |
| amd_stats, nvidia_stats = extract_model_data(row)[:2] | |
| amd_stats_list.append(amd_stats) | |
| nvidia_stats_list.append(nvidia_stats) | |
| fig = plt.figure(figsize=(FIGURE_WIDTH, FIGURE_HEIGHT), facecolor=BLACK) | |
| gs = fig.add_gridspec(2, 2, height_ratios=[1, 1], width_ratios=[3, 1], | |
| hspace=0.3, wspace=0.2) | |
| ax1 = fig.add_subplot(gs[0, 0]) | |
| ax2 = fig.add_subplot(gs[1, 0]) | |
| ax3 = fig.add_subplot(gs[:, 1]) | |
| for ax in [ax1, ax2, ax3]: | |
| ax.set_facecolor(BLACK) | |
| amd_passed = [stats['passed'] for stats in amd_stats_list] | |
| amd_failed = [stats['failed'] for stats in amd_stats_list] | |
| amd_skipped = [stats['skipped'] for stats in amd_stats_list] | |
| ax1.stackplot(dates, amd_passed, amd_failed, amd_skipped, | |
| colors=[COLORS['passed'], COLORS['failed'], COLORS['skipped']], | |
| alpha=0.7, labels=['Passed', 'Failed', 'Skipped']) | |
| ax1.plot(dates, amd_failed, color=COLORS['failed'], linewidth=2.5, | |
| marker='o', markersize=7, markeredgewidth=2, markeredgecolor=BLACK, | |
| linestyle='-', label='_nolegend_') | |
| ax1.set_title(f'{model_name.upper()} - AMD Results', fontsize=TITLE_FONT_SIZE, | |
| color=TITLE_COLOR, fontfamily='monospace', fontweight='bold', pad=20) | |
| ax1.set_ylabel('Number of Tests', fontsize=LABEL_FONT_SIZE, color=LABEL_COLOR, fontfamily='monospace') | |
| ax1.grid(True, color=GRID_COLOR, alpha=0.3, linestyle='-', linewidth=0.5) | |
| ax1.legend(fontsize=LEGEND_FONT_SIZE, loc='upper left', frameon=False, | |
| labelcolor=LABEL_COLOR, prop={'family': 'monospace'}) | |
| ax1.tick_params(colors=LABEL_COLOR, labelsize=LABEL_FONT_SIZE, axis='x', rotation=45) | |
| nvidia_passed = [stats['passed'] for stats in nvidia_stats_list] | |
| nvidia_failed = [stats['failed'] for stats in nvidia_stats_list] | |
| nvidia_skipped = [stats['skipped'] for stats in nvidia_stats_list] | |
| ax2.stackplot(dates, nvidia_passed, nvidia_failed, nvidia_skipped, | |
| colors=[COLORS['passed'], COLORS['failed'], COLORS['skipped']], | |
| alpha=0.7, labels=['Passed', 'Failed', 'Skipped']) | |
| ax2.plot(dates, nvidia_failed, color=COLORS['failed'], linewidth=2.5, | |
| marker='s', markersize=7, markeredgewidth=2, markeredgecolor=BLACK, | |
| linestyle='-', label='_nolegend_') | |
| ax2.set_title(f'{model_name.upper()} - NVIDIA Results', fontsize=TITLE_FONT_SIZE, | |
| color=TITLE_COLOR, fontfamily='monospace', fontweight='bold', pad=20) | |
| ax2.set_ylabel('Number of Tests', fontsize=LABEL_FONT_SIZE, color=LABEL_COLOR, fontfamily='monospace') | |
| ax2.set_xlabel('Date', fontsize=LABEL_FONT_SIZE, color=LABEL_COLOR, fontfamily='monospace') | |
| ax2.grid(True, color=GRID_COLOR, alpha=0.3, linestyle='-', linewidth=0.5) | |
| ax2.tick_params(colors=LABEL_COLOR, labelsize=LABEL_FONT_SIZE, axis='x', rotation=45) | |
| ax3.axis('off') | |
| latest_amd = amd_stats_list[-1] | |
| latest_nvidia = nvidia_stats_list[-1] | |
| amd_total = latest_amd['passed'] + latest_amd['failed'] | |
| nvidia_total = latest_nvidia['passed'] + latest_nvidia['failed'] | |
| amd_fail_rate = (latest_amd['failed'] / amd_total * 100) if amd_total > 0 else 0 | |
| nvidia_fail_rate = (latest_nvidia['failed'] / nvidia_total * 100) if nvidia_total > 0 else 0 | |
| ax3.text(0.5, 0.95, 'LATEST RESULTS', ha='center', va='top', | |
| fontsize=TITLE_FONT_SIZE - 4, color=TITLE_COLOR, fontfamily='monospace', | |
| fontweight='bold', transform=ax3.transAxes) | |
| y = 0.80 | |
| sections = [ | |
| ('AMD', [ | |
| ('Pass Rate', f"{(latest_amd['passed']/amd_total*100) if amd_total > 0 else 0:.1f}%", COLORS['passed']), | |
| ('Fail Rate', f"{amd_fail_rate:.1f}%", COLORS['failed']), | |
| ('Total', str(latest_amd['passed'] + latest_amd['failed'] + latest_amd['skipped']), '#888888'), | |
| ]), | |
| ('NVIDIA', [ | |
| ('Pass Rate', f"{(latest_nvidia['passed']/nvidia_total*100) if nvidia_total > 0 else 0:.1f}%", COLORS['passed']), | |
| ('Fail Rate', f"{nvidia_fail_rate:.1f}%", COLORS['failed']), | |
| ('Total', str(latest_nvidia['passed'] + latest_nvidia['failed'] + latest_nvidia['skipped']), '#888888'), | |
| ]) | |
| ] | |
| for section_name, metrics in sections: | |
| ax3.text(0.5, y, section_name, ha='center', va='center', | |
| fontsize=LABEL_FONT_SIZE + 2, color=TITLE_COLOR, | |
| fontfamily='monospace', fontweight='bold', transform=ax3.transAxes) | |
| y -= 0.08 | |
| for label, value, color in metrics: | |
| ax3.text(0.15, y, label, ha='left', va='center', | |
| fontsize=LABEL_FONT_SIZE - 1, color=LABEL_COLOR, | |
| fontfamily='monospace', transform=ax3.transAxes) | |
| ax3.text(0.85, y, value, ha='right', va='center', | |
| fontsize=LABEL_FONT_SIZE, color=color, | |
| fontfamily='monospace', fontweight='bold', transform=ax3.transAxes) | |
| y -= 0.07 | |
| y -= 0.05 | |
| plt.close('all') | |
| return fig |