""" Create animated bar chart race showing leaderboard evolution over time """ import pandas as pd import numpy as np from typing import List, Tuple import json import os def prepare_animation_data(history_df: pd.DataFrame, top_n: int = 15) -> dict: """ Prepare data for D3.js bar chart race animation. Args: history_df: DataFrame with columns: date, model, rating, rank top_n: Number of top models to show at each time point Returns: Dictionary with animation data """ # Convert date column to Timestamp to support ISO date strings and date objects if history_df is not None and len(history_df) > 0 and 'date' in history_df.columns: history_df = history_df.copy() history_df['date'] = pd.to_datetime(history_df['date']) # Get all unique dates dates = sorted(history_df['date'].unique()) if len(dates) == 0: return { 'frames': [], 'total_frames': 0, 'top_n': top_n, 'start_date': None, 'end_date': None, } # For each date, get top N models frames = [] for date in dates: date_data = history_df[history_df['date'] == date].nlargest(top_n, 'rating') frame = { 'date': date.strftime('%Y-%m-%d'), 'timestamp': int(date.timestamp()), 'models': [] } for rank, row in enumerate(date_data.itertuples(), 1): frame['models'].append({ 'rank': rank, 'name': row.model, 'rating': float(row.rating), 'matches': int(row.matches), 'wins': float(row.wins) }) frames.append(frame) animation_data = { 'frames': frames, 'total_frames': len(frames), 'top_n': top_n, 'start_date': dates[0].strftime('%Y-%m-%d'), 'end_date': dates[-1].strftime('%Y-%m-%d') } return animation_data def generate_html_animation(animation_data: dict, output_path: str = "leaderboard_animation.html"): """ Generate standalone HTML file with D3.js bar chart race animation. Args: animation_data: Dictionary from prepare_animation_data output_path: Path to save HTML file """ html_template = """ Model Leaderboard Evolution

🏆 Model Leaderboard Evolution

Loading...
5x
About: This animation shows the evolution of model rankings based on Elo ratings calculated from Chatbot Arena voting data. Each frame represents a snapshot in time, with models ranked by their current Elo rating. Bars show the rating value, and the animation reveals how models compete and evolve over time.
""" # Keep generated evidence friendly to `git diff --check` and deterministic # across editors that otherwise strip indentation-only lines. html_template = "\n".join(line.rstrip() for line in html_template.splitlines()) + "\n" # Write to file with open(output_path, 'w', encoding='utf-8') as f: f.write(html_template) print(f"Generated animation HTML at: {output_path}") print(f"Open the file in a web browser to view the animation.") def create_simple_animation(history_df: pd.DataFrame, output_path: str = "leaderboard_animation.html", top_n: int = 15): """ Convenience function to create animation in one step. Args: history_df: DataFrame with rating history output_path: Path to save HTML file top_n: Number of top models to show """ print("Preparing animation data...") animation_data = prepare_animation_data(history_df, top_n) print(f"Generating HTML animation with {animation_data['total_frames']} frames...") generate_html_animation(animation_data, output_path) return output_path