{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "828c33ea", "metadata": {}, "outputs": [], "source": [ "from dotenv import load_dotenv\n", "from openai import OpenAI\n", "load_dotenv()\n", "openai_client = OpenAI()" ] }, { "cell_type": "code", "execution_count": 2, "id": "d3ba7531", "metadata": {}, "outputs": [], "source": [ "import os\n", "import re\n", "import json\n", "import time\n", "import traceback\n", "import subprocess\n", "import textwrap\n", "from pathlib import Path\n", "import traceback\n", "from datetime import datetime, timezone\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd" ] }, { "cell_type": "code", "execution_count": 3, "id": "ef2bc44a", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
datecategoryregionproductsalesunitsad_spendmarginrevenuemonthweekdayhour
02024-03-06HardwareSouthA111.34711512399.6166390.2692411267.5930202024-03Wednesday3
12025-07-19HardwareNorthC642.9691844294.4459520.3027912909.8728512025-07Saturday5
22025-04-23ServicesEastC475.81499812191.3208600.2833135772.7690292025-04Wednesday9
32024-11-16ServicesEastD414.9666351490.3542810.2882075855.6485922024-11Saturday19
42024-11-12SubscriptionsSouthC499.24805311497.9611570.2715044788.2955062024-11Tuesday4
\n", "
" ], "text/plain": [ " date category region product sales units ad_spend \\\n", "0 2024-03-06 Hardware South A 111.347115 12 399.616639 \n", "1 2025-07-19 Hardware North C 642.969184 4 294.445952 \n", "2 2025-04-23 Services East C 475.814998 12 191.320860 \n", "3 2024-11-16 Services East D 414.966635 14 90.354281 \n", "4 2024-11-12 Subscriptions South C 499.248053 11 497.961157 \n", "\n", " margin revenue month weekday hour \n", "0 0.269241 1267.593020 2024-03 Wednesday 3 \n", "1 0.302791 2909.872851 2025-07 Saturday 5 \n", "2 0.283313 5772.769029 2025-04 Wednesday 9 \n", "3 0.288207 5855.648592 2024-11 Saturday 19 \n", "4 0.271504 4788.295506 2024-11 Tuesday 4 " ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def make_sales_dataset(n=5000, seed=42):\n", " rng = np.random.default_rng(seed)\n", "\n", " dates = pd.date_range(\"2024-01-01\", \"2025-12-31\", freq=\"D\")\n", " categories = [\"Hardware\", \"Software\", \"Services\", \"Subscriptions\"]\n", " regions = [\"North\", \"South\", \"East\", \"West\"]\n", " products = [\"A\", \"B\", \"C\", \"D\", \"E\"]\n", "\n", " df = pd.DataFrame({\n", " \"date\": rng.choice(dates, size=n),\n", " \"category\": rng.choice(categories, size=n),\n", " \"region\": rng.choice(regions, size=n),\n", " \"product\": rng.choice(products, size=n),\n", " \"sales\": rng.gamma(shape=4.0, scale=100.0, size=n),\n", " \"units\": rng.poisson(lam=10, size=n),\n", " \"ad_spend\": rng.gamma(shape=3.0, scale=80.0, size=n),\n", " \"margin\": rng.normal(loc=0.25, scale=0.08, size=n),\n", " })\n", "\n", " df[\"revenue\"] = df[\"sales\"] * df[\"units\"] * rng.normal(1.0, 0.1, size=n)\n", " df[\"month\"] = df[\"date\"].dt.to_period(\"M\").astype(str)\n", " df[\"weekday\"] = df[\"date\"].dt.day_name()\n", " df[\"hour\"] = rng.integers(0, 24, size=n)\n", "\n", " return df\n", "\n", "df = make_sales_dataset()\n", "df.to_csv(\"sales_dataset.csv\", index=False)\n", "df.head()" ] }, { "cell_type": "code", "execution_count": 4, "id": "18e34714", "metadata": {}, "outputs": [], "source": [ "TASKS = [\n", " {\n", " \"task_id\": \"T1\",\n", " \"task_name\": \"Bar chart\",\n", " \"task\": \"Create a bar chart showing total revenue by product category. Sort the categories by descending total revenue and include a clear title and axis labels.\"\n", " },\n", " {\n", " \"task_id\": \"T2\",\n", " \"task_name\": \"Line chart\",\n", " \"task\": \"Create a line chart showing monthly total revenue over time. The x-axis should represent month and the y-axis should represent total revenue.\"\n", " },\n", " {\n", " \"task_id\": \"T3\",\n", " \"task_name\": \"Scatter plot with tooltip\",\n", " \"task\": \"Create a scatter plot showing the relationship between advertising spend and revenue. Add a tooltip showing month, category, ad spend, and revenue.\"\n", " },\n", " {\n", " \"task_id\": \"T4\",\n", " \"task_name\": \"Histogram\",\n", " \"task\": \"Create a histogram showing the distribution of transaction values.\"\n", " },\n", " {\n", " \"task_id\": \"T5\",\n", " \"task_name\": \"Grouped bar chart\",\n", " \"task\": \"Create a grouped bar chart showing total revenue by product category and region.\"\n", " },\n", " {\n", " \"task_id\": \"T6\",\n", " \"task_name\": \"Layered line chart\",\n", " \"task\": \"Create a line chart showing monthly revenue by product category. Each category should be shown as a different line.\"\n", " },\n", " {\n", " \"task_id\": \"T7\",\n", " \"task_name\": \"Faceted chart\",\n", " \"task\": \"Create a faceted chart showing monthly revenue trends separately for each region.\"\n", " },\n", " {\n", " \"task_id\": \"T8\",\n", " \"task_name\": \"Heatmap\",\n", " \"task\": \"Create a heatmap showing average revenue by weekday and hour of day.\"\n", " },\n", " {\n", " \"task_id\": \"T9\",\n", " \"task_name\": \"Interactive category selection\",\n", " \"task\": \"Create an interactive scatter plot where selecting a product category highlights the corresponding points. Add tooltips showing category, revenue, and margin.\"\n", " },\n", " {\n", " \"task_id\": \"T10\",\n", " \"task_name\": \"Dropdown filter\",\n", " \"task\": \"Create a line chart of monthly revenue with a dropdown selector that allows the user to choose the region.\"\n", " },\n", " {\n", " \"task_id\": \"T11\",\n", " \"task_name\": \"Linked views\",\n", " \"task\": \"Create a linked visualization with a scatter plot and a bar chart. Selecting points in the scatter plot should update the bar chart to show totals for the selected subset.\"\n", " },\n", "]\n", "\n", "LIBRARIES = [\"Matplotlib\", \"Altair\"]" ] }, { "cell_type": "code", "execution_count": 5, "id": "2fdb34d2", "metadata": {}, "outputs": [], "source": [ "BASE_PROMPT_TEMPLATE = \"\"\"\n", "You are given a pandas DataFrame named df with the following columns:\n", "\n", "date: datetime\n", "month: string in YYYY-MM format\n", "region: categorical\n", "category: categorical\n", "product: categorical\n", "sales: numeric\n", "revenue: numeric\n", "margin: numeric\n", "ad_spend: numeric\n", "units: numeric\n", "weekday: categorical\n", "hour: integer from 0 to 23\n", "\n", "Task:\n", "{task}\n", "\n", "Constraint:\n", "Use {library} only.\n", "\n", "Visualization quality requirements:\n", "- Produce the simplest complete implementation that satisfies the task.\n", "- The chart must be clear and readable.\n", "- Include an informative title.\n", "- Include appropriate axis labels.\n", "- Include a legend when color, grouping, or multiple series are used.\n", "- Ensure tick labels are readable and not unnecessarily overlapping.\n", "- Use an appropriate figure size or chart size.\n", "- Sort categorical axes when the task asks for ranking or comparison.\n", "- Do not add interactions, transformations, annotations, or custom styling unless explicitly requested.\n", "- If the task requests a tooltip, implement an actual hover tooltip, not static text labels.\n", "\n", "Code constraints:\n", "- Assume df already exists.\n", "- Do not create, simulate, redefine, or show example data.\n", "- Do not include commented-out code.\n", "- Do not include explanatory comments.\n", "- Do not include markdown code fences.\n", "- Return only executable Python code.\n", "\"\"\".strip()" ] }, { "cell_type": "code", "execution_count": 6, "id": "8488a607", "metadata": {}, "outputs": [], "source": [ "REPAIR_PROMPT_TEMPLATE = \"\"\"\n", "The following Python visualization code failed during execution:\n", "\n", "{failed_code}\n", "\n", "The execution produced this error:\n", "\n", "{error_message}\n", "\n", "Fix the code while preserving the original visualization task and the required library, {library}.\n", "\n", "Return executable Python code only. Do not include explanations.\n", "\"\"\".strip()" ] }, { "cell_type": "code", "execution_count": 7, "id": "28af77d7", "metadata": {}, "outputs": [], "source": [ "def extract_code(text: str) -> str:\n", " \"\"\"\n", " Extract Python code from an LLM response.\n", " If the model returns fenced code, use the first python/code block.\n", " Otherwise, return the whole text.\n", " \"\"\"\n", " if not text:\n", " return \"\"\n", "\n", " fence = re.search(r\"```(?:python)?\\s*(.*?)```\", text, flags=re.DOTALL | re.IGNORECASE)\n", " if fence:\n", " return fence.group(1).strip()\n", "\n", " return text.strip()\n", "\n", "\n", "def make_execution_script(generated_code: str, output_dir: str, run_label: str) -> str:\n", " \"\"\"\n", " Wrap generated code in a script with df loaded.\n", " For Matplotlib, save current figure if one exists.\n", " For Altair, try to save chart-like objects if common names are used.\n", " \"\"\"\n", " safe_output_dir = Path(output_dir)\n", " safe_output_dir.mkdir(parents=True, exist_ok=True)\n", "\n", " wrapper = f\"\"\"\n", "import os\n", "from pathlib import Path\n", "\n", "import pandas as pd\n", "import numpy as np\n", "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", "import matplotlib.pyplot as plt\n", "\n", "import altair as alt\n", "\n", "df = pd.read_csv(\"sales_dataset.csv\")\n", "df[\"date\"] = pd.to_datetime(df[\"date\"])\n", "\n", "OUTPUT_DIR = Path(\"{safe_output_dir.as_posix()}\")\n", "OUTPUT_DIR.mkdir(parents=True, exist_ok=True)\n", "\n", "# ---------------- GENERATED CODE START ----------------\n", "{generated_code}\n", "# ---------------- GENERATED CODE END ----------------\n", "\n", "# Save Matplotlib output if any figures exist.\n", "try:\n", " if plt.get_fignums():\n", " plt.savefig(OUTPUT_DIR / \"{run_label}.png\", bbox_inches=\"tight\")\n", "except Exception as e:\n", " print(\"WARNING: Could not save matplotlib figure:\", repr(e))\n", "\n", "# Save Altair output if a chart object exists under common variable names.\n", "for _name in [\"chart\", \"fig\", \"plot\", \"vis\", \"visualization\"]:\n", " if _name in globals():\n", " _obj = globals()[_name]\n", " try:\n", " if hasattr(_obj, \"save\"):\n", " _obj.save(str(OUTPUT_DIR / \"{run_label}.html\"))\n", " break\n", " except Exception as e:\n", " print(\"WARNING: Could not save altair chart:\", repr(e))\n", "\"\"\"\n", " return textwrap.dedent(wrapper)\n", "\n", "\n", "def execute_generated_code(generated_code: str, output_dir: str, run_label: str, timeout_seconds: int = 30):\n", " \"\"\"\n", " Execute generated code in a subprocess to isolate failures.\n", " Returns dict with success, stdout, stderr, and error text.\n", " \"\"\"\n", " script_path = Path(output_dir) / f\"{run_label}.py\"\n", " script_path.parent.mkdir(parents=True, exist_ok=True)\n", " script_path.write_text(\n", " make_execution_script(generated_code, output_dir, run_label),\n", " encoding=\"utf-8\"\n", " )\n", "\n", " try:\n", " proc = subprocess.run(\n", " [\"python\", str(script_path)],\n", " capture_output=True,\n", " text=True,\n", " timeout=timeout_seconds\n", " )\n", " success = proc.returncode == 0\n", " return {\n", " \"success\": success,\n", " \"returncode\": proc.returncode,\n", " \"stdout\": proc.stdout,\n", " \"stderr\": proc.stderr,\n", " \"error_message\": proc.stderr if not success else \"\",\n", " \"script_path\": str(script_path),\n", " }\n", " except subprocess.TimeoutExpired as e:\n", " return {\n", " \"success\": False,\n", " \"returncode\": -1,\n", " \"stdout\": e.stdout or \"\",\n", " \"stderr\": e.stderr or \"\",\n", " \"error_message\": f\"TimeoutExpired after {timeout_seconds} seconds\",\n", " \"script_path\": str(script_path),\n", " }\n", " except Exception:\n", " return {\n", " \"success\": False,\n", " \"returncode\": -2,\n", " \"stdout\": \"\",\n", " \"stderr\": traceback.format_exc(),\n", " \"error_message\": traceback.format_exc(),\n", " \"script_path\": str(script_path),\n", " }" ] }, { "cell_type": "code", "execution_count": 8, "id": "0fe39a0c", "metadata": {}, "outputs": [], "source": [ "def extract_code(text: str) -> str:\n", " \"\"\"\n", " Extract Python code from an LLM response.\n", " If the model returns fenced code, use the first python/code block.\n", " Otherwise, return the whole text.\n", " \"\"\"\n", " if not text:\n", " return \"\"\n", "\n", " fence = re.search(r\"```(?:python)?\\s*(.*?)```\", text, flags=re.DOTALL | re.IGNORECASE)\n", " if fence:\n", " return fence.group(1).strip()\n", "\n", " return text.strip()\n", "\n", "\n", "def make_execution_script(generated_code: str, output_dir: str, run_label: str) -> str:\n", " \"\"\"\n", " Wrap generated code in a script with df loaded.\n", " For Matplotlib, save current figure if one exists.\n", " For Altair, try to save chart-like objects if common names are used.\n", " \"\"\"\n", " safe_output_dir = Path(output_dir)\n", " safe_output_dir.mkdir(parents=True, exist_ok=True)\n", "\n", " wrapper = f\"\"\"\n", "import os\n", "from pathlib import Path\n", "\n", "import pandas as pd\n", "import numpy as np\n", "\n", "import matplotlib\n", "matplotlib.use(\"Agg\")\n", "import matplotlib.pyplot as plt\n", "\n", "import altair as alt\n", "\n", "df = pd.read_csv(\"sales_dataset.csv\")\n", "df[\"date\"] = pd.to_datetime(df[\"date\"])\n", "\n", "OUTPUT_DIR = Path(\"{safe_output_dir.as_posix()}\")\n", "OUTPUT_DIR.mkdir(parents=True, exist_ok=True)\n", "\n", "# ---------------- GENERATED CODE START ----------------\n", "{generated_code}\n", "# ---------------- GENERATED CODE END ----------------\n", "\n", "# Save Matplotlib output if any figures exist.\n", "try:\n", " if plt.get_fignums():\n", " plt.savefig(OUTPUT_DIR / \"{run_label}.png\", bbox_inches=\"tight\")\n", "except Exception as e:\n", " print(\"WARNING: Could not save matplotlib figure:\", repr(e))\n", "\n", "# Save Altair output if a chart object exists under common variable names.\n", "for _name in [\"chart\", \"fig\", \"plot\", \"vis\", \"visualization\"]:\n", " if _name in globals():\n", " _obj = globals()[_name]\n", " try:\n", " if hasattr(_obj, \"save\"):\n", " _obj.save(str(OUTPUT_DIR / \"{run_label}.html\"))\n", " break\n", " except Exception as e:\n", " print(\"WARNING: Could not save altair chart:\", repr(e))\n", "\"\"\"\n", " return textwrap.dedent(wrapper)\n", "\n", "\n", "def execute_generated_code(generated_code: str, output_dir: str, run_label: str, timeout_seconds: int = 30):\n", " \"\"\"\n", " Execute generated code in a subprocess to isolate failures.\n", " Returns dict with success, stdout, stderr, and error text.\n", " \"\"\"\n", " script_path = Path(output_dir) / f\"{run_label}.py\"\n", " script_path.parent.mkdir(parents=True, exist_ok=True)\n", " script_path.write_text(\n", " make_execution_script(generated_code, output_dir, run_label),\n", " encoding=\"utf-8\"\n", " )\n", "\n", " try:\n", " proc = subprocess.run(\n", " [\"python\", str(script_path)],\n", " capture_output=True,\n", " text=True,\n", " timeout=timeout_seconds\n", " )\n", " success = proc.returncode == 0\n", " return {\n", " \"success\": success,\n", " \"returncode\": proc.returncode,\n", " \"stdout\": proc.stdout,\n", " \"stderr\": proc.stderr,\n", " \"error_message\": proc.stderr if not success else \"\",\n", " \"script_path\": str(script_path),\n", " }\n", " except subprocess.TimeoutExpired as e:\n", " return {\n", " \"success\": False,\n", " \"returncode\": -1,\n", " \"stdout\": e.stdout or \"\",\n", " \"stderr\": e.stderr or \"\",\n", " \"error_message\": f\"TimeoutExpired after {timeout_seconds} seconds\",\n", " \"script_path\": str(script_path),\n", " }\n", " except Exception:\n", " return {\n", " \"success\": False,\n", " \"returncode\": -2,\n", " \"stdout\": \"\",\n", " \"stderr\": traceback.format_exc(),\n", " \"error_message\": traceback.format_exc(),\n", " \"script_path\": str(script_path),\n", " }" ] }, { "cell_type": "markdown", "id": "051d9f5e", "metadata": {}, "source": [ "#### OPENAI CALLS" ] }, { "cell_type": "code", "execution_count": 9, "id": "642f253a", "metadata": {}, "outputs": [], "source": [ "def call_openai_model(prompt: str, model: str, temperature: float = 0.0, max_tokens: int = 2000):\n", " \"\"\"\n", " Calls OpenAI Chat Completions API.\n", " Supports both older models using max_tokens and newer models using max_completion_tokens.\n", " \"\"\"\n", " kwargs = {\n", " \"model\": model,\n", " \"messages\": [\n", " {\n", " \"role\": \"system\",\n", " \"content\": \"You generate concise, executable Python visualization code.\"\n", " },\n", " {\n", " \"role\": \"user\",\n", " \"content\": prompt\n", " }\n", " ],\n", " }\n", "\n", " if model.startswith(\"gpt-5\") or model.startswith(\"o\"):\n", " kwargs[\"max_completion_tokens\"] = max_tokens\n", " else:\n", " kwargs[\"max_tokens\"] = max_tokens\n", " kwargs[\"temperature\"] = temperature\n", "\n", " response = openai_client.chat.completions.create(**kwargs)\n", "\n", " text = response.choices[0].message.content or \"\"\n", " usage = response.usage\n", "\n", " return {\n", " \"text\": text,\n", " \"prompt_tokens\": getattr(usage, \"prompt_tokens\", None),\n", " \"completion_tokens\": getattr(usage, \"completion_tokens\", None),\n", " \"total_tokens\": getattr(usage, \"total_tokens\", None),\n", " \"raw_usage\": usage.model_dump() if usage else None,\n", " }" ] }, { "cell_type": "markdown", "id": "8d432c4d", "metadata": {}, "source": [ "#### CLAUDE RUNNER" ] }, { "cell_type": "code", "execution_count": 10, "id": "bd796461", "metadata": {}, "outputs": [], "source": [ "from anthropic import Anthropic\n", "\n", "anthropic_client = Anthropic()\n", "\n", "\n", "def call_claude_model(prompt: str, model: str, temperature: float = 0.0, max_tokens: int = 2000):\n", " \"\"\"\n", " Uses Anthropic Messages API.\n", " Returns text and token usage.\n", " \"\"\"\n", " response = anthropic_client.messages.create(\n", " model=model,\n", " max_tokens=max_tokens,\n", " temperature=temperature,\n", " system=\"You generate concise, executable Python visualization code.\",\n", " messages=[\n", " {\n", " \"role\": \"user\",\n", " \"content\": prompt\n", " }\n", " ],\n", " )\n", "\n", " text_parts = []\n", " for block in response.content:\n", " if getattr(block, \"type\", None) == \"text\":\n", " text_parts.append(block.text)\n", "\n", " text = \"\\n\".join(text_parts)\n", " usage = response.usage\n", "\n", " input_tokens = getattr(usage, \"input_tokens\", None)\n", " output_tokens = getattr(usage, \"output_tokens\", None)\n", "\n", " return {\n", " \"text\": text,\n", " \"prompt_tokens\": input_tokens,\n", " \"completion_tokens\": output_tokens,\n", " \"total_tokens\": (\n", " input_tokens + output_tokens\n", " if input_tokens is not None and output_tokens is not None\n", " else None\n", " ),\n", " \"raw_usage\": usage.model_dump() if hasattr(usage, \"model_dump\") else str(usage),\n", " }" ] }, { "cell_type": "code", "execution_count": 11, "id": "b762c545", "metadata": {}, "outputs": [], "source": [ "CLAUDE_MODELS = [\n", " \"claude-3-5-sonnet-latest\",\n", " # \"claude-3-7-sonnet-latest\",\n", " # \"claude-opus-4-1-20250805\",\n", "]" ] }, { "cell_type": "markdown", "id": "ae879d39", "metadata": {}, "source": [ "#### EXPERIMENT" ] }, { "cell_type": "code", "execution_count": 12, "id": "7c29223c", "metadata": {}, "outputs": [], "source": [ "def run_single_generation(\n", " provider: str,\n", " model: str,\n", " task: dict,\n", " library: str,\n", " run_id: int,\n", " temperature: float = 0.0,\n", " max_repair_attempts: int = 1,\n", " output_dir: str = \"experiment_outputs\",\n", "):\n", " prompt = BASE_PROMPT_TEMPLATE.format(\n", " task=task[\"task\"],\n", " library=library\n", " )\n", "\n", " if provider == \"openai\":\n", " initial = call_openai_model(prompt, model=model, temperature=temperature)\n", " elif provider == \"claude\":\n", " initial = call_claude_model(prompt, model=model, temperature=temperature)\n", " else:\n", " raise ValueError(f\"Unknown provider: {provider}\")\n", "\n", " initial_text = initial[\"text\"]\n", " initial_code = extract_code(initial_text)\n", "\n", " run_label = f\"{provider}_{model}_{task['task_id']}_{library}_run{run_id}\"\n", " run_label = re.sub(r\"[^a-zA-Z0-9_.-]+\", \"_\", run_label)\n", "\n", " exec_result = execute_generated_code(\n", " generated_code=initial_code,\n", " output_dir=output_dir,\n", " run_label=run_label,\n", " )\n", "\n", " repair_attempts = 0\n", " repair_prompt_tokens = 0\n", " repair_completion_tokens = 0\n", " repair_total_tokens = 0\n", " repair_texts = []\n", " repair_codes = []\n", " final_code = initial_code\n", " final_success = exec_result[\"success\"]\n", " final_error_message = exec_result[\"error_message\"]\n", "\n", " while not final_success and repair_attempts < max_repair_attempts:\n", " repair_attempts += 1\n", "\n", " repair_prompt = REPAIR_PROMPT_TEMPLATE.format(\n", " failed_code=final_code,\n", " error_message=final_error_message,\n", " library=library\n", " )\n", "\n", " if provider == \"openai\":\n", " repair = call_openai_model(repair_prompt, model=model, temperature=temperature)\n", " else:\n", " repair = call_claude_model(repair_prompt, model=model, temperature=temperature)\n", "\n", " repair_text = repair[\"text\"]\n", " repaired_code = extract_code(repair_text)\n", "\n", " repair_texts.append(repair_text)\n", " repair_codes.append(repaired_code)\n", "\n", " repair_prompt_tokens += repair[\"prompt_tokens\"] or 0\n", " repair_completion_tokens += repair[\"completion_tokens\"] or 0\n", " repair_total_tokens += repair[\"total_tokens\"] or 0\n", "\n", " final_code = repaired_code\n", "\n", " repair_label = f\"{run_label}_repair{repair_attempts}\"\n", " exec_result = execute_generated_code(\n", " generated_code=final_code,\n", " output_dir=output_dir,\n", " run_label=repair_label,\n", " )\n", "\n", " final_success = exec_result[\"success\"]\n", " final_error_message = exec_result[\"error_message\"]\n", "\n", " result = {\n", " \"datetime.utcnow().isoformat()\": datetime.now(timezone.utc).isoformat(),\n", " \"provider\": provider,\n", " \"model\": model,\n", " \"task_id\": task[\"task_id\"],\n", " \"task_name\": task[\"task_name\"],\n", " \"library\": library,\n", " \"run_id\": run_id,\n", " \"temperature\": temperature,\n", "\n", " \"initial_prompt\": prompt,\n", " \"initial_response\": initial_text,\n", " \"initial_code\": initial_code,\n", "\n", " \"initial_prompt_tokens\": initial[\"prompt_tokens\"],\n", " \"initial_completion_tokens\": initial[\"completion_tokens\"],\n", " \"initial_total_tokens\": initial[\"total_tokens\"],\n", "\n", " \"initial_code_chars\": len(initial_code),\n", " \"initial_code_lines\": len(initial_code.splitlines()),\n", "\n", " \"initial_execution_success\": exec_result[\"success\"] if repair_attempts == 0 else False,\n", " \"repair_attempts\": repair_attempts,\n", " \"repair_prompt_tokens\": repair_prompt_tokens,\n", " \"repair_completion_tokens\": repair_completion_tokens,\n", " \"repair_total_tokens\": repair_total_tokens,\n", "\n", " \"final_success\": final_success,\n", " \"final_error_message\": final_error_message,\n", " \"final_code\": final_code,\n", " \"final_code_chars\": len(final_code),\n", " \"final_code_lines\": len(final_code.splitlines()),\n", "\n", " \"total_agentic_tokens\": (initial[\"total_tokens\"] or 0) + repair_total_tokens,\n", " \"execution_script_path\": exec_result.get(\"script_path\"),\n", " }\n", "\n", " return result" ] }, { "cell_type": "markdown", "id": "84f321ed", "metadata": {}, "source": [ "#### FIRST OPENAI" ] }, { "cell_type": "code", "execution_count": 13, "id": "6fb050a6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Total existing rows: 330\n", "Valid rows kept: 264\n", "Rows to retry: 66\n" ] } ], "source": [ "RESULTS_CSV = \"openai_quality_v2_all_models_all_tasks.csv\"\n", "\n", "existing_df = pd.read_csv(RESULTS_CSV)\n", "\n", "# A valid row is a row without top-level harness/API error\n", "successful_df = existing_df[\n", " existing_df[\"error\"].isna()\n", "].copy()\n", "\n", "print(\"Total existing rows:\", len(existing_df))\n", "print(\"Valid rows kept:\", len(successful_df))\n", "print(\"Rows to retry:\", len(existing_df) - len(successful_df))\n", "\n", "all_results = successful_df.to_dict(\"records\")\n", "\n", "def make_key(model, task_id, library, run_id):\n", " return f\"{model}__{task_id}__{library}__{int(run_id)}\"\n", "\n", "existing_keys = set(\n", " make_key(row[\"model\"], row[\"task_id\"], row[\"library\"], row[\"run_id\"])\n", " for _, row in successful_df.iterrows()\n", ")\n", "\n", "openai_full_df = pd.DataFrame(all_results)\n", "openai_full_df.to_csv(RESULTS_CSV, index=False)" ] }, { "cell_type": "code", "execution_count": 14, "id": "f9a8b1c2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Skipping existing | gpt-4o-mini | T1 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T1 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T1 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T1 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T1 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T1 | Altair | run 3\n", "Skipping existing | gpt-4o-mini | T2 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T2 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T2 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T2 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T2 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T2 | Altair | run 3\n", "Skipping existing | gpt-4o-mini | T3 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T3 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T3 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T3 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T3 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T3 | Altair | run 3\n", "Skipping existing | gpt-4o-mini | T4 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T4 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T4 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T4 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T4 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T4 | Altair | run 3\n", "Skipping existing | gpt-4o-mini | T5 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T5 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T5 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T5 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T5 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T5 | Altair | run 3\n", "Skipping existing | gpt-4o-mini | T6 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T6 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T6 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T6 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T6 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T6 | Altair | run 3\n", "Skipping existing | gpt-4o-mini | T7 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T7 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T7 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T7 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T7 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T7 | Altair | run 3\n", "Skipping existing | gpt-4o-mini | T8 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T8 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T8 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T8 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T8 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T8 | Altair | run 3\n", "Skipping existing | gpt-4o-mini | T9 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T9 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T9 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T9 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T9 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T9 | Altair | run 3\n", "Skipping existing | gpt-4o-mini | T10 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T10 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T10 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T10 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T10 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T10 | Altair | run 3\n", "Skipping existing | gpt-4o-mini | T11 | Matplotlib | run 1\n", "Skipping existing | gpt-4o-mini | T11 | Matplotlib | run 2\n", "Skipping existing | gpt-4o-mini | T11 | Matplotlib | run 3\n", "Skipping existing | gpt-4o-mini | T11 | Altair | run 1\n", "Skipping existing | gpt-4o-mini | T11 | Altair | run 2\n", "Skipping existing | gpt-4o-mini | T11 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T1 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T1 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T1 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T1 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T1 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T1 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T2 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T2 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T2 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T2 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T2 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T2 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T3 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T3 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T3 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T3 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T3 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T3 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T4 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T4 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T4 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T4 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T4 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T4 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T5 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T5 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T5 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T5 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T5 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T5 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T6 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T6 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T6 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T6 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T6 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T6 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T7 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T7 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T7 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T7 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T7 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T7 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T8 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T8 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T8 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T8 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T8 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T8 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T9 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T9 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T9 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T9 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T9 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T9 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T10 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T10 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T10 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T10 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T10 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T10 | Altair | run 3\n", "Skipping existing | gpt-4.1-mini | T11 | Matplotlib | run 1\n", "Skipping existing | gpt-4.1-mini | T11 | Matplotlib | run 2\n", "Skipping existing | gpt-4.1-mini | T11 | Matplotlib | run 3\n", "Skipping existing | gpt-4.1-mini | T11 | Altair | run 1\n", "Skipping existing | gpt-4.1-mini | T11 | Altair | run 2\n", "Skipping existing | gpt-4.1-mini | T11 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T1 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T1 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T1 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T1 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T1 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T1 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T2 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T2 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T2 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T2 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T2 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T2 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T3 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T3 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T3 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T3 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T3 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T3 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T4 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T4 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T4 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T4 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T4 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T4 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T5 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T5 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T5 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T5 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T5 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T5 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T6 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T6 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T6 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T6 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T6 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T6 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T7 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T7 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T7 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T7 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T7 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T7 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T8 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T8 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T8 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T8 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T8 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T8 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T9 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T9 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T9 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T9 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T9 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T9 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T10 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T10 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T10 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T10 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T10 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T10 | Altair | run 3\n", "Skipping existing | gpt-5.4-mini | T11 | Matplotlib | run 1\n", "Skipping existing | gpt-5.4-mini | T11 | Matplotlib | run 2\n", "Skipping existing | gpt-5.4-mini | T11 | Matplotlib | run 3\n", "Skipping existing | gpt-5.4-mini | T11 | Altair | run 1\n", "Skipping existing | gpt-5.4-mini | T11 | Altair | run 2\n", "Skipping existing | gpt-5.4-mini | T11 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T1 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T1 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T1 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T1 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T1 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T1 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T2 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T2 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T2 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T2 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T2 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T2 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T3 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T3 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T3 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T3 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T3 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T3 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T4 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T4 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T4 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T4 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T4 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T4 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T5 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T5 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T5 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T5 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T5 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T5 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T6 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T6 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T6 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T6 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T6 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T6 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T7 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T7 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T7 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T7 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T7 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T7 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T8 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T8 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T8 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T8 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T8 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T8 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T9 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T9 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T9 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T9 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T9 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T9 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T10 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T10 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T10 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T10 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T10 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T10 | Altair | run 3\n", "Skipping existing | gpt-5.5 | T11 | Matplotlib | run 1\n", "Skipping existing | gpt-5.5 | T11 | Matplotlib | run 2\n", "Skipping existing | gpt-5.5 | T11 | Matplotlib | run 3\n", "Skipping existing | gpt-5.5 | T11 | Altair | run 1\n", "Skipping existing | gpt-5.5 | T11 | Altair | run 2\n", "Skipping existing | gpt-5.5 | T11 | Altair | run 3\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
datetime.utcnow().isoformat()providermodeltask_idtask_namelibraryrun_idtemperatureinitial_promptinitial_response...final_error_messagefinal_codefinal_code_charsfinal_code_linestotal_agentic_tokensexecution_script_pathprompt_trackexperiment_nametimestamperror
02026-07-05T21:27:29.452167openaigpt-4.1-miniT1Bar chartMatplotlib10.0You are given a pandas DataFrame named df with...import matplotlib.pyplot as plt\\n\\nrevenue_by_......NaNimport matplotlib.pyplot as plt\\n\\nrevenue_by_...385.011.0392.0experiment_outputs_openai_quality_v2_full/open...quality_controlled_v2openai_quality_v2_all_models_all_tasks2026-07-05T21:27:29.452251+00:00NaN
12026-07-05T21:27:33.107684openaigpt-4.1-miniT1Bar chartMatplotlib20.0You are given a pandas DataFrame named df with...import matplotlib.pyplot as plt\\n\\nrevenue_by_......NaNimport matplotlib.pyplot as plt\\n\\nrevenue_by_...385.011.0392.0experiment_outputs_openai_quality_v2_full/open...quality_controlled_v2openai_quality_v2_all_models_all_tasks2026-07-05T21:27:33.107738+00:00NaN
22026-07-05T21:27:36.402421openaigpt-4.1-miniT1Bar chartMatplotlib30.0You are given a pandas DataFrame named df with...import matplotlib.pyplot as plt\\n\\nrevenue_by_......NaNimport matplotlib.pyplot as plt\\n\\nrevenue_by_...385.011.0392.0experiment_outputs_openai_quality_v2_full/open...quality_controlled_v2openai_quality_v2_all_models_all_tasks2026-07-05T21:27:36.402488+00:00NaN
32026-07-05T21:27:39.615520openaigpt-4.1-miniT1Bar chartAltair10.0You are given a pandas DataFrame named df with...import altair as alt\\n\\nchart = alt.Chart(df).......NaNimport altair as alt\\n\\nchart = alt.Chart(df)....279.012.0382.0experiment_outputs_openai_quality_v2_full/open...quality_controlled_v2openai_quality_v2_all_models_all_tasks2026-07-05T21:27:39.615571+00:00NaN
42026-07-05T21:27:43.206672openaigpt-4.1-miniT1Bar chartAltair20.0You are given a pandas DataFrame named df with...import altair as alt\\n\\nchart = alt.Chart(df).......NaNimport altair as alt\\n\\nchart = alt.Chart(df)....286.012.0384.0experiment_outputs_openai_quality_v2_full/open...quality_controlled_v2openai_quality_v2_all_models_all_tasks2026-07-05T21:27:43.206726+00:00NaN
..................................................................
2592026-07-06T07:54:47.076169+00:00openaigpt-4o-miniT11Linked viewsMatplotlib20.0You are given a pandas DataFrame named df with...import pandas as pd\\nimport matplotlib.pyplot ......NaNimport pandas as pd\\nimport matplotlib.pyplot ...1232.036.01637.0experiment_outputs_openai_quality_v2_full/open...quality_controlled_v2openai_quality_v2_all_models_all_tasks2026-07-06T07:54:47.076282+00:00NaN
2602026-07-06T07:54:54.032455+00:00openaigpt-4o-miniT11Linked viewsMatplotlib30.0You are given a pandas DataFrame named df with...import pandas as pd\\nimport matplotlib.pyplot ......NaNimport pandas as pd\\nimport matplotlib.pyplot ...947.029.0551.0experiment_outputs_openai_quality_v2_full/open...quality_controlled_v2openai_quality_v2_all_models_all_tasks2026-07-06T07:54:54.032598+00:00NaN
2612026-07-06T07:55:06.024020+00:00openaigpt-4o-miniT11Linked viewsAltair10.0You are given a pandas DataFrame named df with...import altair as alt\\nimport pandas as pd\\n\\ns......NaNimport altair as alt\\nimport pandas as pd\\n\\n#...1081.041.01352.0experiment_outputs_openai_quality_v2_full/open...quality_controlled_v2openai_quality_v2_all_models_all_tasks2026-07-06T07:55:06.024195+00:00NaN
2622026-07-06T07:55:19.110010+00:00openaigpt-4o-miniT11Linked viewsAltair20.0You are given a pandas DataFrame named df with...import altair as alt\\nimport pandas as pd\\n\\ns....../Users/eduardodisanti/git/altair_as_agentic_se...import altair as alt\\nimport pandas as pd\\n\\n#...1097.039.01378.0experiment_outputs_openai_quality_v2_full/open...quality_controlled_v2openai_quality_v2_all_models_all_tasks2026-07-06T07:55:19.110167+00:00NaN
2632026-07-06T07:55:33.102056+00:00openaigpt-4o-miniT11Linked viewsAltair30.0You are given a pandas DataFrame named df with...import altair as alt\\nimport pandas as pd\\n\\ns....../Users/eduardodisanti/git/altair_as_agentic_se...import altair as alt\\nimport pandas as pd\\n\\n#...1100.039.01357.0experiment_outputs_openai_quality_v2_full/open...quality_controlled_v2openai_quality_v2_all_models_all_tasks2026-07-06T07:55:33.102323+00:00NaN
\n", "

264 rows × 32 columns

\n", "
" ], "text/plain": [ " datetime.utcnow().isoformat() provider model task_id \\\n", "0 2026-07-05T21:27:29.452167 openai gpt-4.1-mini T1 \n", "1 2026-07-05T21:27:33.107684 openai gpt-4.1-mini T1 \n", "2 2026-07-05T21:27:36.402421 openai gpt-4.1-mini T1 \n", "3 2026-07-05T21:27:39.615520 openai gpt-4.1-mini T1 \n", "4 2026-07-05T21:27:43.206672 openai gpt-4.1-mini T1 \n", ".. ... ... ... ... \n", "259 2026-07-06T07:54:47.076169+00:00 openai gpt-4o-mini T11 \n", "260 2026-07-06T07:54:54.032455+00:00 openai gpt-4o-mini T11 \n", "261 2026-07-06T07:55:06.024020+00:00 openai gpt-4o-mini T11 \n", "262 2026-07-06T07:55:19.110010+00:00 openai gpt-4o-mini T11 \n", "263 2026-07-06T07:55:33.102056+00:00 openai gpt-4o-mini T11 \n", "\n", " task_name library run_id temperature \\\n", "0 Bar chart Matplotlib 1 0.0 \n", "1 Bar chart Matplotlib 2 0.0 \n", "2 Bar chart Matplotlib 3 0.0 \n", "3 Bar chart Altair 1 0.0 \n", "4 Bar chart Altair 2 0.0 \n", ".. ... ... ... ... \n", "259 Linked views Matplotlib 2 0.0 \n", "260 Linked views Matplotlib 3 0.0 \n", "261 Linked views Altair 1 0.0 \n", "262 Linked views Altair 2 0.0 \n", "263 Linked views Altair 3 0.0 \n", "\n", " initial_prompt \\\n", "0 You are given a pandas DataFrame named df with... \n", "1 You are given a pandas DataFrame named df with... \n", "2 You are given a pandas DataFrame named df with... \n", "3 You are given a pandas DataFrame named df with... \n", "4 You are given a pandas DataFrame named df with... \n", ".. ... \n", "259 You are given a pandas DataFrame named df with... \n", "260 You are given a pandas DataFrame named df with... \n", "261 You are given a pandas DataFrame named df with... \n", "262 You are given a pandas DataFrame named df with... \n", "263 You are given a pandas DataFrame named df with... \n", "\n", " initial_response ... \\\n", "0 import matplotlib.pyplot as plt\\n\\nrevenue_by_... ... \n", "1 import matplotlib.pyplot as plt\\n\\nrevenue_by_... ... \n", "2 import matplotlib.pyplot as plt\\n\\nrevenue_by_... ... \n", "3 import altair as alt\\n\\nchart = alt.Chart(df).... ... \n", "4 import altair as alt\\n\\nchart = alt.Chart(df).... ... \n", ".. ... ... \n", "259 import pandas as pd\\nimport matplotlib.pyplot ... ... \n", "260 import pandas as pd\\nimport matplotlib.pyplot ... ... \n", "261 import altair as alt\\nimport pandas as pd\\n\\ns... ... \n", "262 import altair as alt\\nimport pandas as pd\\n\\ns... ... \n", "263 import altair as alt\\nimport pandas as pd\\n\\ns... ... \n", "\n", " final_error_message \\\n", "0 NaN \n", "1 NaN \n", "2 NaN \n", "3 NaN \n", "4 NaN \n", ".. ... \n", "259 NaN \n", "260 NaN \n", "261 NaN \n", "262 /Users/eduardodisanti/git/altair_as_agentic_se... \n", "263 /Users/eduardodisanti/git/altair_as_agentic_se... \n", "\n", " final_code final_code_chars \\\n", "0 import matplotlib.pyplot as plt\\n\\nrevenue_by_... 385.0 \n", "1 import matplotlib.pyplot as plt\\n\\nrevenue_by_... 385.0 \n", "2 import matplotlib.pyplot as plt\\n\\nrevenue_by_... 385.0 \n", "3 import altair as alt\\n\\nchart = alt.Chart(df).... 279.0 \n", "4 import altair as alt\\n\\nchart = alt.Chart(df).... 286.0 \n", ".. ... ... \n", "259 import pandas as pd\\nimport matplotlib.pyplot ... 1232.0 \n", "260 import pandas as pd\\nimport matplotlib.pyplot ... 947.0 \n", "261 import altair as alt\\nimport pandas as pd\\n\\n#... 1081.0 \n", "262 import altair as alt\\nimport pandas as pd\\n\\n#... 1097.0 \n", "263 import altair as alt\\nimport pandas as pd\\n\\n#... 1100.0 \n", "\n", " final_code_lines total_agentic_tokens \\\n", "0 11.0 392.0 \n", "1 11.0 392.0 \n", "2 11.0 392.0 \n", "3 12.0 382.0 \n", "4 12.0 384.0 \n", ".. ... ... \n", "259 36.0 1637.0 \n", "260 29.0 551.0 \n", "261 41.0 1352.0 \n", "262 39.0 1378.0 \n", "263 39.0 1357.0 \n", "\n", " execution_script_path prompt_track \\\n", "0 experiment_outputs_openai_quality_v2_full/open... quality_controlled_v2 \n", "1 experiment_outputs_openai_quality_v2_full/open... quality_controlled_v2 \n", "2 experiment_outputs_openai_quality_v2_full/open... quality_controlled_v2 \n", "3 experiment_outputs_openai_quality_v2_full/open... quality_controlled_v2 \n", "4 experiment_outputs_openai_quality_v2_full/open... quality_controlled_v2 \n", ".. ... ... \n", "259 experiment_outputs_openai_quality_v2_full/open... quality_controlled_v2 \n", "260 experiment_outputs_openai_quality_v2_full/open... quality_controlled_v2 \n", "261 experiment_outputs_openai_quality_v2_full/open... quality_controlled_v2 \n", "262 experiment_outputs_openai_quality_v2_full/open... quality_controlled_v2 \n", "263 experiment_outputs_openai_quality_v2_full/open... quality_controlled_v2 \n", "\n", " experiment_name timestamp \\\n", "0 openai_quality_v2_all_models_all_tasks 2026-07-05T21:27:29.452251+00:00 \n", "1 openai_quality_v2_all_models_all_tasks 2026-07-05T21:27:33.107738+00:00 \n", "2 openai_quality_v2_all_models_all_tasks 2026-07-05T21:27:36.402488+00:00 \n", "3 openai_quality_v2_all_models_all_tasks 2026-07-05T21:27:39.615571+00:00 \n", "4 openai_quality_v2_all_models_all_tasks 2026-07-05T21:27:43.206726+00:00 \n", ".. ... ... \n", "259 openai_quality_v2_all_models_all_tasks 2026-07-06T07:54:47.076282+00:00 \n", "260 openai_quality_v2_all_models_all_tasks 2026-07-06T07:54:54.032598+00:00 \n", "261 openai_quality_v2_all_models_all_tasks 2026-07-06T07:55:06.024195+00:00 \n", "262 openai_quality_v2_all_models_all_tasks 2026-07-06T07:55:19.110167+00:00 \n", "263 openai_quality_v2_all_models_all_tasks 2026-07-06T07:55:33.102323+00:00 \n", "\n", " error \n", "0 NaN \n", "1 NaN \n", "2 NaN \n", "3 NaN \n", "4 NaN \n", ".. ... \n", "259 NaN \n", "260 NaN \n", "261 NaN \n", "262 NaN \n", "263 NaN \n", "\n", "[264 rows x 32 columns]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "OPENAI_MODELS = [\n", " \"gpt-4o-mini\",\n", " \"gpt-4.1-mini\",\n", " \"gpt-5.4-mini\",\n", " #\"gpt-5.3-codex\",\n", " \"gpt-5.5\", \n", "]\n", "\n", "N_RUNS = 3\n", "OUTPUT_DIR = \"experiment_outputs_openai_quality_v2_full\"\n", "RESULTS_CSV = \"openai_quality_v2_all_models_all_tasks.csv\"\n", "\n", "Path(OUTPUT_DIR).mkdir(parents=True, exist_ok=True)\n", "\n", "if Path(RESULTS_CSV).exists():\n", " existing_df = pd.read_csv(RESULTS_CSV)\n", " all_results = existing_df.to_dict(\"records\")\n", "else:\n", " existing_df = pd.DataFrame()\n", " all_results = []\n", "\n", "def make_key(model, task_id, library, run_id):\n", " return f\"{model}__{task_id}__{library}__{run_id}\"\n", "\n", "existing_keys = set()\n", "\n", "if not existing_df.empty:\n", " for _, row in existing_df.iterrows():\n", " existing_keys.add(\n", " make_key(\n", " row.get(\"model\"),\n", " row.get(\"task_id\"),\n", " row.get(\"library\"),\n", " int(row.get(\"run_id\")),\n", " )\n", " )\n", "\n", "for model in OPENAI_MODELS:\n", " for task in TASKS:\n", " for library in LIBRARIES:\n", " for run_id in range(1, N_RUNS + 1):\n", " key = make_key(model, task[\"task_id\"], library, run_id)\n", "\n", " if key in existing_keys:\n", " print(f\"Skipping existing | {model} | {task['task_id']} | {library} | run {run_id}\")\n", " continue\n", "\n", " print(f\"Running OpenAI | {model} | {task['task_id']} | {library} | run {run_id}\")\n", "\n", " try:\n", " row = run_single_generation(\n", " provider=\"openai\",\n", " model=model,\n", " task=task,\n", " library=library,\n", " run_id=run_id,\n", " temperature=0.0,\n", " max_repair_attempts=1,\n", " output_dir=OUTPUT_DIR,\n", " )\n", "\n", " row[\"prompt_track\"] = \"quality_controlled_v2\"\n", " row[\"experiment_name\"] = \"openai_quality_v2_all_models_all_tasks\"\n", " row[\"timestamp\"] = datetime.now(timezone.utc).isoformat()\n", "\n", " except Exception:\n", " row = {\n", " \"timestamp\": datetime.now(timezone.utc).isoformat(),\n", " \"provider\": \"openai\",\n", " \"model\": model,\n", " \"task_id\": task[\"task_id\"],\n", " \"task_name\": task[\"task_name\"],\n", " \"library\": library,\n", " \"run_id\": run_id,\n", " \"prompt_track\": \"quality_controlled_v2\",\n", " \"experiment_name\": \"openai_quality_v2_all_models_all_tasks\",\n", " \"error\": traceback.format_exc(),\n", " }\n", "\n", " all_results.append(row)\n", " existing_keys.add(key)\n", "\n", " pd.DataFrame(all_results).to_csv(RESULTS_CSV, index=False)\n", "\n", " time.sleep(1)\n", "\n", "openai_full_df = pd.DataFrame(all_results)\n", "openai_full_df.to_csv(RESULTS_CSV, index=False)\n", "\n", "openai_full_df" ] }, { "cell_type": "markdown", "id": "8fc68eca", "metadata": {}, "source": [ "#### RESULTS FOR OPENAI ####" ] }, { "cell_type": "code", "execution_count": 15, "id": "fe0269ed", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
modelcomplexitylibrarymean_initial_tokensstd_initial_tokensmedian_initial_tokensmean_code_linesstd_code_linesfirst_pass_success_ratefinal_success_ratemean_repair_tokensstd_repair_tokensn
0gpt-4.1-minilowAltair375.88888914.953632377.011.4444441.1303881.0000001.0000000.0000000.0000009
1gpt-4.1-minilowMatplotlib376.66666719.371371387.010.3333331.0000001.0000001.0000000.0000000.0000009
2gpt-4.1-minimediumAltair424.11111137.681044403.015.6666672.1794491.0000001.0000000.0000000.0000009
3gpt-4.1-minimediumMatplotlib512.33333362.285632473.025.3333337.3993241.0000001.0000000.0000000.0000009
4gpt-4.1-minimedium-highAltair419.50000026.120873415.515.0000001.0954451.0000001.0000000.0000000.0000006
5gpt-4.1-minimedium-highMatplotlib467.00000046.008695467.020.0000003.2863351.0000001.0000000.0000000.0000006
6gpt-4.1-minihighAltair472.22222233.825943454.022.7777785.5176480.6666670.666667359.666667539.5000009
7gpt-4.1-minihighMatplotlib663.222222111.024522591.042.88888913.2045871.0000001.0000000.0000000.0000009
8gpt-4o-minilowAltair421.77777821.735787433.016.0000000.8660250.8888891.00000048.222222144.6666679
9gpt-4o-minilowMatplotlib381.33333316.755596392.011.5555561.2360331.0000001.0000000.0000000.0000009
10gpt-4o-minimediumAltair435.55555620.952990422.016.4444441.8782381.0000001.0000000.0000000.0000009
11gpt-4o-minimediumMatplotlib470.11111185.430446436.019.8888898.8944431.0000001.0000000.0000000.0000009
12gpt-4o-minimedium-highAltair434.0000007.348469435.019.1666671.9407901.0000001.0000000.0000000.0000006
13gpt-4o-minimedium-highMatplotlib422.00000039.436024422.016.5000003.8340581.0000001.0000000.0000000.0000006
14gpt-4o-minihighAltair469.88888914.172548467.022.5555564.8505440.3333330.777778552.777778418.3410039
15gpt-4o-minihighMatplotlib561.11111173.304919551.028.4444444.2163700.3333330.777778657.000000543.0639939
16gpt-5.4-minilowAltair427.11111124.609167429.016.8888894.0756731.0000001.0000000.0000000.0000009
17gpt-5.4-minilowMatplotlib402.55555638.373530414.012.0000002.7386131.0000001.0000000.0000000.0000009
18gpt-5.4-minimediumAltair463.00000021.627529466.023.1111111.6914821.0000001.0000000.0000000.0000009
19gpt-5.4-minimediumMatplotlib562.88888997.173099524.034.44444414.7488231.0000001.0000000.0000000.0000009
20gpt-5.4-minimedium-highAltair441.66666722.303961454.020.3333333.3266601.0000001.0000000.0000000.0000006
21gpt-5.4-minimedium-highMatplotlib508.83333366.291528491.024.1666675.7416611.0000001.0000000.0000000.0000006
22gpt-5.4-minihighAltair572.88888979.808277539.033.6666678.4409720.8888891.000000119.777778359.3333339
23gpt-5.4-minihighMatplotlib856.000000163.908511936.062.66666717.6351920.6666671.000000374.000000592.7872729
24gpt-5.5lowAltair755.777778118.164904712.012.2222221.2018500.8888891.00000076.111111228.3333339
25gpt-5.5lowMatplotlib636.888889195.865671533.014.2222224.2654951.0000001.0000000.0000000.0000009
26gpt-5.5mediumAltair778.111111118.744941816.017.8888892.0883270.8888891.000000130.888889392.6666679
27gpt-5.5mediumMatplotlib1168.333333213.3184241099.041.0000007.0710681.0000001.0000000.0000000.0000009
28gpt-5.5medium-highAltair873.66666757.618284876.016.6666672.9439201.0000001.0000000.0000000.0000006
29gpt-5.5medium-highMatplotlib1069.166667298.1774081031.029.8333336.3060821.0000001.0000000.0000000.0000006
30gpt-5.5highAltair1365.333333613.3165991096.027.11111111.0955451.0000001.0000000.0000000.0000009
31gpt-5.5highMatplotlib2098.333333332.9613342297.029.11111143.9131091.0000001.0000000.0000000.0000009
\n", "
" ], "text/plain": [ " model complexity library mean_initial_tokens \\\n", "0 gpt-4.1-mini low Altair 375.888889 \n", "1 gpt-4.1-mini low Matplotlib 376.666667 \n", "2 gpt-4.1-mini medium Altair 424.111111 \n", "3 gpt-4.1-mini medium Matplotlib 512.333333 \n", "4 gpt-4.1-mini medium-high Altair 419.500000 \n", "5 gpt-4.1-mini medium-high Matplotlib 467.000000 \n", "6 gpt-4.1-mini high Altair 472.222222 \n", "7 gpt-4.1-mini high Matplotlib 663.222222 \n", "8 gpt-4o-mini low Altair 421.777778 \n", "9 gpt-4o-mini low Matplotlib 381.333333 \n", "10 gpt-4o-mini medium Altair 435.555556 \n", "11 gpt-4o-mini medium Matplotlib 470.111111 \n", "12 gpt-4o-mini medium-high Altair 434.000000 \n", "13 gpt-4o-mini medium-high Matplotlib 422.000000 \n", "14 gpt-4o-mini high Altair 469.888889 \n", "15 gpt-4o-mini high Matplotlib 561.111111 \n", "16 gpt-5.4-mini low Altair 427.111111 \n", "17 gpt-5.4-mini low Matplotlib 402.555556 \n", "18 gpt-5.4-mini medium Altair 463.000000 \n", "19 gpt-5.4-mini medium Matplotlib 562.888889 \n", "20 gpt-5.4-mini medium-high Altair 441.666667 \n", "21 gpt-5.4-mini medium-high Matplotlib 508.833333 \n", "22 gpt-5.4-mini high Altair 572.888889 \n", "23 gpt-5.4-mini high Matplotlib 856.000000 \n", "24 gpt-5.5 low Altair 755.777778 \n", "25 gpt-5.5 low Matplotlib 636.888889 \n", "26 gpt-5.5 medium Altair 778.111111 \n", "27 gpt-5.5 medium Matplotlib 1168.333333 \n", "28 gpt-5.5 medium-high Altair 873.666667 \n", "29 gpt-5.5 medium-high Matplotlib 1069.166667 \n", "30 gpt-5.5 high Altair 1365.333333 \n", "31 gpt-5.5 high Matplotlib 2098.333333 \n", "\n", " std_initial_tokens median_initial_tokens mean_code_lines \\\n", "0 14.953632 377.0 11.444444 \n", "1 19.371371 387.0 10.333333 \n", "2 37.681044 403.0 15.666667 \n", "3 62.285632 473.0 25.333333 \n", "4 26.120873 415.5 15.000000 \n", "5 46.008695 467.0 20.000000 \n", "6 33.825943 454.0 22.777778 \n", "7 111.024522 591.0 42.888889 \n", "8 21.735787 433.0 16.000000 \n", "9 16.755596 392.0 11.555556 \n", "10 20.952990 422.0 16.444444 \n", "11 85.430446 436.0 19.888889 \n", "12 7.348469 435.0 19.166667 \n", "13 39.436024 422.0 16.500000 \n", "14 14.172548 467.0 22.555556 \n", "15 73.304919 551.0 28.444444 \n", "16 24.609167 429.0 16.888889 \n", "17 38.373530 414.0 12.000000 \n", "18 21.627529 466.0 23.111111 \n", "19 97.173099 524.0 34.444444 \n", "20 22.303961 454.0 20.333333 \n", "21 66.291528 491.0 24.166667 \n", "22 79.808277 539.0 33.666667 \n", "23 163.908511 936.0 62.666667 \n", "24 118.164904 712.0 12.222222 \n", "25 195.865671 533.0 14.222222 \n", "26 118.744941 816.0 17.888889 \n", "27 213.318424 1099.0 41.000000 \n", "28 57.618284 876.0 16.666667 \n", "29 298.177408 1031.0 29.833333 \n", "30 613.316599 1096.0 27.111111 \n", "31 332.961334 2297.0 29.111111 \n", "\n", " std_code_lines first_pass_success_rate final_success_rate \\\n", "0 1.130388 1.000000 1.000000 \n", "1 1.000000 1.000000 1.000000 \n", "2 2.179449 1.000000 1.000000 \n", "3 7.399324 1.000000 1.000000 \n", "4 1.095445 1.000000 1.000000 \n", "5 3.286335 1.000000 1.000000 \n", "6 5.517648 0.666667 0.666667 \n", "7 13.204587 1.000000 1.000000 \n", "8 0.866025 0.888889 1.000000 \n", "9 1.236033 1.000000 1.000000 \n", "10 1.878238 1.000000 1.000000 \n", "11 8.894443 1.000000 1.000000 \n", "12 1.940790 1.000000 1.000000 \n", "13 3.834058 1.000000 1.000000 \n", "14 4.850544 0.333333 0.777778 \n", "15 4.216370 0.333333 0.777778 \n", "16 4.075673 1.000000 1.000000 \n", "17 2.738613 1.000000 1.000000 \n", "18 1.691482 1.000000 1.000000 \n", "19 14.748823 1.000000 1.000000 \n", "20 3.326660 1.000000 1.000000 \n", "21 5.741661 1.000000 1.000000 \n", "22 8.440972 0.888889 1.000000 \n", "23 17.635192 0.666667 1.000000 \n", "24 1.201850 0.888889 1.000000 \n", "25 4.265495 1.000000 1.000000 \n", "26 2.088327 0.888889 1.000000 \n", "27 7.071068 1.000000 1.000000 \n", "28 2.943920 1.000000 1.000000 \n", "29 6.306082 1.000000 1.000000 \n", "30 11.095545 1.000000 1.000000 \n", "31 43.913109 1.000000 1.000000 \n", "\n", " mean_repair_tokens std_repair_tokens n \n", "0 0.000000 0.000000 9 \n", "1 0.000000 0.000000 9 \n", "2 0.000000 0.000000 9 \n", "3 0.000000 0.000000 9 \n", "4 0.000000 0.000000 6 \n", "5 0.000000 0.000000 6 \n", "6 359.666667 539.500000 9 \n", "7 0.000000 0.000000 9 \n", "8 48.222222 144.666667 9 \n", "9 0.000000 0.000000 9 \n", "10 0.000000 0.000000 9 \n", "11 0.000000 0.000000 9 \n", "12 0.000000 0.000000 6 \n", "13 0.000000 0.000000 6 \n", "14 552.777778 418.341003 9 \n", "15 657.000000 543.063993 9 \n", "16 0.000000 0.000000 9 \n", "17 0.000000 0.000000 9 \n", "18 0.000000 0.000000 9 \n", "19 0.000000 0.000000 9 \n", "20 0.000000 0.000000 6 \n", "21 0.000000 0.000000 6 \n", "22 119.777778 359.333333 9 \n", "23 374.000000 592.787272 9 \n", "24 76.111111 228.333333 9 \n", "25 0.000000 0.000000 9 \n", "26 130.888889 392.666667 9 \n", "27 0.000000 0.000000 9 \n", "28 0.000000 0.000000 6 \n", "29 0.000000 0.000000 6 \n", "30 0.000000 0.000000 9 \n", "31 0.000000 0.000000 9 " ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "openai_full_df = pd.read_csv(\"openai_quality_v2_all_models_all_tasks.csv\")\n", "TASK_COMPLEXITY = {\n", " \"T1\": \"low\",\n", " \"T2\": \"low\",\n", " \"T3\": \"medium\",\n", " \"T4\": \"low\",\n", " \"T5\": \"medium\",\n", " \"T6\": \"medium-high\",\n", " \"T7\": \"medium-high\",\n", " \"T8\": \"medium\",\n", " \"T9\": \"high\",\n", " \"T10\": \"high\",\n", " \"T11\": \"high\",\n", "}\n", "\n", "COMPLEXITY_ORDER = [\"low\", \"medium\", \"medium-high\", \"high\"]\n", "\n", "df = openai_full_df.copy()\n", "df[\"complexity\"] = df[\"task_id\"].map(TASK_COMPLEXITY)\n", "\n", "df[\"complexity\"] = pd.Categorical(\n", " df[\"complexity\"],\n", " categories=COMPLEXITY_ORDER,\n", " ordered=True\n", ")\n", "\n", "\n", "for col in [\"initial_execution_success\", \"final_success\"]:\n", " if col in df.columns:\n", " if df[col].dtype == \"object\":\n", " df[col] = df[col].map({\n", " \"True\": True,\n", " \"False\": False,\n", " True: True,\n", " False: False,\n", " })\n", " df[col] = df[col].astype(float)\n", "\n", "summary_model_complexity = (\n", " df\n", " .groupby([\"model\", \"complexity\", \"library\"], observed=False)\n", " .agg(\n", " mean_initial_tokens=(\"initial_total_tokens\", \"mean\"),\n", " std_initial_tokens=(\"initial_total_tokens\", \"std\"),\n", " median_initial_tokens=(\"initial_total_tokens\", \"median\"),\n", " mean_code_lines=(\"initial_code_lines\", \"mean\"),\n", " std_code_lines=(\"initial_code_lines\", \"std\"),\n", " first_pass_success_rate=(\"initial_execution_success\", \"mean\"),\n", " final_success_rate=(\"final_success\", \"mean\"),\n", " mean_repair_tokens=(\"repair_total_tokens\", \"mean\"),\n", " std_repair_tokens=(\"repair_total_tokens\", \"std\"),\n", " n=(\"run_id\", \"count\"),\n", " )\n", " .reset_index()\n", ")\n", "\n", "summary_model_complexity" ] }, { "cell_type": "code", "execution_count": 16, "id": "09dc8702", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
librarymodelcomplexityAltairMatplotlibtoken_reduction_abstoken_reduction_pct
0gpt-4.1-minilow375.888889376.6666670.7777780.206490
1gpt-4.1-minimedium424.111111512.33333388.22222217.219692
2gpt-4.1-minimedium-high419.500000467.00000047.50000010.171306
3gpt-4.1-minihigh472.222222663.222222191.00000028.798794
4gpt-4o-minilow421.777778381.333333-40.444444-10.606061
5gpt-4o-minimedium435.555556470.11111134.5555567.350508
6gpt-4o-minimedium-high434.000000422.000000-12.000000-2.843602
7gpt-4o-minihigh469.888889561.11111191.22222216.257426
8gpt-5.4-minilow427.111111402.555556-24.555556-6.099917
9gpt-5.4-minimedium463.000000562.88888999.88888917.745756
10gpt-5.4-minimedium-high441.666667508.83333367.16666713.200131
11gpt-5.4-minihigh572.888889856.000000283.11111133.073728
12gpt-5.5low755.777778636.888889-118.888889-18.667132
13gpt-5.5medium778.1111111168.333333390.22222233.399905
14gpt-5.5medium-high873.6666671069.166667195.50000018.285269
15gpt-5.5high1365.3333332098.333333733.00000034.932486
\n", "
" ], "text/plain": [ "library model complexity Altair Matplotlib \\\n", "0 gpt-4.1-mini low 375.888889 376.666667 \n", "1 gpt-4.1-mini medium 424.111111 512.333333 \n", "2 gpt-4.1-mini medium-high 419.500000 467.000000 \n", "3 gpt-4.1-mini high 472.222222 663.222222 \n", "4 gpt-4o-mini low 421.777778 381.333333 \n", "5 gpt-4o-mini medium 435.555556 470.111111 \n", "6 gpt-4o-mini medium-high 434.000000 422.000000 \n", "7 gpt-4o-mini high 469.888889 561.111111 \n", "8 gpt-5.4-mini low 427.111111 402.555556 \n", "9 gpt-5.4-mini medium 463.000000 562.888889 \n", "10 gpt-5.4-mini medium-high 441.666667 508.833333 \n", "11 gpt-5.4-mini high 572.888889 856.000000 \n", "12 gpt-5.5 low 755.777778 636.888889 \n", "13 gpt-5.5 medium 778.111111 1168.333333 \n", "14 gpt-5.5 medium-high 873.666667 1069.166667 \n", "15 gpt-5.5 high 1365.333333 2098.333333 \n", "\n", "library token_reduction_abs token_reduction_pct \n", "0 0.777778 0.206490 \n", "1 88.222222 17.219692 \n", "2 47.500000 10.171306 \n", "3 191.000000 28.798794 \n", "4 -40.444444 -10.606061 \n", "5 34.555556 7.350508 \n", "6 -12.000000 -2.843602 \n", "7 91.222222 16.257426 \n", "8 -24.555556 -6.099917 \n", "9 99.888889 17.745756 \n", "10 67.166667 13.200131 \n", "11 283.111111 33.073728 \n", "12 -118.888889 -18.667132 \n", "13 390.222222 33.399905 \n", "14 195.500000 18.285269 \n", "15 733.000000 34.932486 " ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model_complexity_tokens = summary_model_complexity.pivot_table(\n", " index=[\"model\", \"complexity\"],\n", " columns=\"library\",\n", " values=\"mean_initial_tokens\",\n", " observed=False\n", ").reset_index()\n", "\n", "model_complexity_tokens[\"token_reduction_abs\"] = (\n", " model_complexity_tokens[\"Matplotlib\"] - model_complexity_tokens[\"Altair\"]\n", ")\n", "\n", "model_complexity_tokens[\"token_reduction_pct\"] = (\n", " 100\n", " * model_complexity_tokens[\"token_reduction_abs\"]\n", " / model_complexity_tokens[\"Matplotlib\"]\n", ")\n", "\n", "model_complexity_tokens = model_complexity_tokens.sort_values([\"model\", \"complexity\"])\n", "\n", "model_complexity_tokens" ] }, { "cell_type": "code", "execution_count": 17, "id": "468ac8f0", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
librarycomplexityAltairMatplotlibAltair_stdMatplotlib_stdtoken_reduction_abstoken_reduction_pct
0low495.138889449.361111164.888040146.322765-45.777778-10.187303
1medium525.194444678.416667160.908815313.872620153.22222222.585268
2medium-high542.208333616.750000198.166153305.38347274.54166712.086205
3high720.0833331044.666667481.942165653.990913324.58333331.070517
\n", "
" ], "text/plain": [ "library complexity Altair Matplotlib Altair_std Matplotlib_std \\\n", "0 low 495.138889 449.361111 164.888040 146.322765 \n", "1 medium 525.194444 678.416667 160.908815 313.872620 \n", "2 medium-high 542.208333 616.750000 198.166153 305.383472 \n", "3 high 720.083333 1044.666667 481.942165 653.990913 \n", "\n", "library token_reduction_abs token_reduction_pct \n", "0 -45.777778 -10.187303 \n", "1 153.222222 22.585268 \n", "2 74.541667 12.086205 \n", "3 324.583333 31.070517 " ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "summary_all_models_complexity = (\n", " df\n", " .groupby([\"complexity\", \"library\"], observed=False)\n", " .agg(\n", " mean_initial_tokens=(\"initial_total_tokens\", \"mean\"),\n", " std_initial_tokens=(\"initial_total_tokens\", \"std\"),\n", " median_initial_tokens=(\"initial_total_tokens\", \"median\"),\n", " mean_code_lines=(\"initial_code_lines\", \"mean\"),\n", " first_pass_success_rate=(\"initial_execution_success\", \"mean\"),\n", " final_success_rate=(\"final_success\", \"mean\"),\n", " mean_repair_tokens=(\"repair_total_tokens\", \"mean\"),\n", " std_repair_tokens=(\"repair_total_tokens\", \"std\"),\n", " n=(\"run_id\", \"count\"),\n", " )\n", " .reset_index()\n", ")\n", "\n", "all_models_complexity_tokens = summary_all_models_complexity.pivot_table(\n", " index=\"complexity\",\n", " columns=\"library\",\n", " values=\"mean_initial_tokens\",\n", " observed=False\n", ").reset_index()\n", "\n", "all_models_complexity_std = summary_all_models_complexity.pivot_table(\n", " index=\"complexity\",\n", " columns=\"library\",\n", " values=\"std_initial_tokens\",\n", " observed=False\n", ").reset_index()\n", "\n", "all_models_complexity_tokens = all_models_complexity_tokens.merge(\n", " all_models_complexity_std,\n", " on=\"complexity\",\n", " suffixes=(\"\", \"_std\"),\n", ")\n", "\n", "all_models_complexity_tokens[\"token_reduction_abs\"] = (\n", " all_models_complexity_tokens[\"Matplotlib\"] - all_models_complexity_tokens[\"Altair\"]\n", ")\n", "\n", "all_models_complexity_tokens[\"token_reduction_pct\"] = (\n", " 100\n", " * all_models_complexity_tokens[\"token_reduction_abs\"]\n", " / all_models_complexity_tokens[\"Matplotlib\"]\n", ")\n", "\n", "all_models_complexity_tokens = all_models_complexity_tokens.sort_values(\"complexity\")\n", "\n", "all_models_complexity_tokens" ] }, { "cell_type": "code", "execution_count": 18, "id": "5eae75f8", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
librarymodeltask_idtask_namecomplexityAltairMatplotlibtoken_reduction_abstoken_reduction_pct
0gpt-4.1-miniT1Bar chartlow382.666667392.0000009.3333332.380952
3gpt-4.1-miniT2Line chartlow386.000000387.0000001.0000000.258398
5gpt-4.1-miniT4Histogramlow359.000000351.000000-8.000000-2.279202
4gpt-4.1-miniT3Scatter plot with tooltipmedium395.000000594.666667199.66666733.576233
6gpt-4.1-miniT5Grouped bar chartmedium403.333333469.00000065.66666714.001421
9gpt-4.1-miniT8Heatmapmedium474.000000473.333333-0.666667-0.140845
7gpt-4.1-miniT6Layered line chartmedium-high396.000000425.00000029.0000006.823529
8gpt-4.1-miniT7Faceted chartmedium-high443.000000509.00000066.00000012.966601
1gpt-4.1-miniT10Dropdown filterhigh454.000000577.666667123.66666721.407963
2gpt-4.1-miniT11Linked viewshigh517.000000609.33333392.33333315.153173
10gpt-4.1-miniT9Interactive category selectionhigh445.666667802.666667357.00000044.476744
11gpt-4o-miniT1Bar chartlow436.666667393.000000-43.666667-11.111111
14gpt-4o-miniT2Line chartlow435.666667392.000000-43.666667-11.139456
16gpt-4o-miniT4Histogramlow393.000000359.000000-34.000000-9.470752
15gpt-4o-miniT3Scatter plot with tooltipmedium421.000000580.333333159.33333327.455485
17gpt-4o-miniT5Grouped bar chartmedium423.333333394.000000-29.333333-7.445008
20gpt-4o-miniT8Heatmapmedium462.333333436.000000-26.333333-6.039755
18gpt-4o-miniT6Layered line chartmedium-high436.666667386.000000-50.666667-13.126079
19gpt-4o-miniT7Faceted chartmedium-high431.333333458.00000026.6666675.822416
12gpt-4o-miniT10Dropdown filterhigh467.000000487.33333320.3333334.172367
13gpt-4o-miniT11Linked viewshigh487.333333554.00000066.66666712.033694
21gpt-4o-miniT9Interactive category selectionhigh455.333333642.000000186.66666729.075805
22gpt-5.4-miniT1Bar chartlow446.333333414.000000-32.333333-7.809984
25gpt-5.4-miniT2Line chartlow433.333333438.0000004.6666671.065449
27gpt-5.4-miniT4Histogramlow401.666667355.666667-46.000000-12.933458
26gpt-5.4-miniT3Scatter plot with tooltipmedium465.000000686.666667221.66666732.281553
28gpt-5.4-miniT5Grouped bar chartmedium450.333333483.66666733.3333336.891799
31gpt-5.4-miniT8Heatmapmedium473.666667518.33333344.6666678.617363
29gpt-5.4-miniT6Layered line chartmedium-high443.333333459.00000015.6666673.413217
30gpt-5.4-miniT7Faceted chartmedium-high440.000000558.666667118.66666721.241050
23gpt-5.4-miniT10Dropdown filterhigh552.333333646.66666794.33333314.587629
24gpt-5.4-miniT11Linked viewshigh671.666667951.000000279.33333329.372590
32gpt-5.4-miniT9Interactive category selectionhigh494.666667970.333333475.66666749.020955
33gpt-5.5T1Bar chartlow677.666667574.333333-103.333333-17.991875
36gpt-5.5T2Line chartlow801.333333826.00000024.6666672.986279
38gpt-5.5T4Histogramlow788.333333510.333333-278.000000-54.474200
37gpt-5.5T3Scatter plot with tooltipmedium646.3333331185.666667539.33333345.487771
39gpt-5.5T5Grouped bar chartmedium843.6666671037.666667194.00000018.695792
42gpt-5.5T8Heatmapmedium844.3333331281.666667437.33333334.122237
40gpt-5.5T6Layered line chartmedium-high890.333333872.333333-18.000000-2.063431
41gpt-5.5T7Faceted chartmedium-high857.0000001266.000000409.00000032.306477
34gpt-5.5T10Dropdown filterhigh1808.3333332297.000000488.66666721.274126
35gpt-5.5T11Linked viewshigh1434.0000002309.000000875.00000037.895193
43gpt-5.5T9Interactive category selectionhigh853.6666671689.000000835.33333349.457273
\n", "
" ], "text/plain": [ "library model task_id task_name complexity \\\n", "0 gpt-4.1-mini T1 Bar chart low \n", "3 gpt-4.1-mini T2 Line chart low \n", "5 gpt-4.1-mini T4 Histogram low \n", "4 gpt-4.1-mini T3 Scatter plot with tooltip medium \n", "6 gpt-4.1-mini T5 Grouped bar chart medium \n", "9 gpt-4.1-mini T8 Heatmap medium \n", "7 gpt-4.1-mini T6 Layered line chart medium-high \n", "8 gpt-4.1-mini T7 Faceted chart medium-high \n", "1 gpt-4.1-mini T10 Dropdown filter high \n", "2 gpt-4.1-mini T11 Linked views high \n", "10 gpt-4.1-mini T9 Interactive category selection high \n", "11 gpt-4o-mini T1 Bar chart low \n", "14 gpt-4o-mini T2 Line chart low \n", "16 gpt-4o-mini T4 Histogram low \n", "15 gpt-4o-mini T3 Scatter plot with tooltip medium \n", "17 gpt-4o-mini T5 Grouped bar chart medium \n", "20 gpt-4o-mini T8 Heatmap medium \n", "18 gpt-4o-mini T6 Layered line chart medium-high \n", "19 gpt-4o-mini T7 Faceted chart medium-high \n", "12 gpt-4o-mini T10 Dropdown filter high \n", "13 gpt-4o-mini T11 Linked views high \n", "21 gpt-4o-mini T9 Interactive category selection high \n", "22 gpt-5.4-mini T1 Bar chart low \n", "25 gpt-5.4-mini T2 Line chart low \n", "27 gpt-5.4-mini T4 Histogram low \n", "26 gpt-5.4-mini T3 Scatter plot with tooltip medium \n", "28 gpt-5.4-mini T5 Grouped bar chart medium \n", "31 gpt-5.4-mini T8 Heatmap medium \n", "29 gpt-5.4-mini T6 Layered line chart medium-high \n", "30 gpt-5.4-mini T7 Faceted chart medium-high \n", "23 gpt-5.4-mini T10 Dropdown filter high \n", "24 gpt-5.4-mini T11 Linked views high \n", "32 gpt-5.4-mini T9 Interactive category selection high \n", "33 gpt-5.5 T1 Bar chart low \n", "36 gpt-5.5 T2 Line chart low \n", "38 gpt-5.5 T4 Histogram low \n", "37 gpt-5.5 T3 Scatter plot with tooltip medium \n", "39 gpt-5.5 T5 Grouped bar chart medium \n", "42 gpt-5.5 T8 Heatmap medium \n", "40 gpt-5.5 T6 Layered line chart medium-high \n", "41 gpt-5.5 T7 Faceted chart medium-high \n", "34 gpt-5.5 T10 Dropdown filter high \n", "35 gpt-5.5 T11 Linked views high \n", "43 gpt-5.5 T9 Interactive category selection high \n", "\n", "library Altair Matplotlib token_reduction_abs token_reduction_pct \n", "0 382.666667 392.000000 9.333333 2.380952 \n", "3 386.000000 387.000000 1.000000 0.258398 \n", "5 359.000000 351.000000 -8.000000 -2.279202 \n", "4 395.000000 594.666667 199.666667 33.576233 \n", "6 403.333333 469.000000 65.666667 14.001421 \n", "9 474.000000 473.333333 -0.666667 -0.140845 \n", "7 396.000000 425.000000 29.000000 6.823529 \n", "8 443.000000 509.000000 66.000000 12.966601 \n", "1 454.000000 577.666667 123.666667 21.407963 \n", "2 517.000000 609.333333 92.333333 15.153173 \n", "10 445.666667 802.666667 357.000000 44.476744 \n", "11 436.666667 393.000000 -43.666667 -11.111111 \n", "14 435.666667 392.000000 -43.666667 -11.139456 \n", "16 393.000000 359.000000 -34.000000 -9.470752 \n", "15 421.000000 580.333333 159.333333 27.455485 \n", "17 423.333333 394.000000 -29.333333 -7.445008 \n", "20 462.333333 436.000000 -26.333333 -6.039755 \n", "18 436.666667 386.000000 -50.666667 -13.126079 \n", "19 431.333333 458.000000 26.666667 5.822416 \n", "12 467.000000 487.333333 20.333333 4.172367 \n", "13 487.333333 554.000000 66.666667 12.033694 \n", "21 455.333333 642.000000 186.666667 29.075805 \n", "22 446.333333 414.000000 -32.333333 -7.809984 \n", "25 433.333333 438.000000 4.666667 1.065449 \n", "27 401.666667 355.666667 -46.000000 -12.933458 \n", "26 465.000000 686.666667 221.666667 32.281553 \n", "28 450.333333 483.666667 33.333333 6.891799 \n", "31 473.666667 518.333333 44.666667 8.617363 \n", "29 443.333333 459.000000 15.666667 3.413217 \n", "30 440.000000 558.666667 118.666667 21.241050 \n", "23 552.333333 646.666667 94.333333 14.587629 \n", "24 671.666667 951.000000 279.333333 29.372590 \n", "32 494.666667 970.333333 475.666667 49.020955 \n", "33 677.666667 574.333333 -103.333333 -17.991875 \n", "36 801.333333 826.000000 24.666667 2.986279 \n", "38 788.333333 510.333333 -278.000000 -54.474200 \n", "37 646.333333 1185.666667 539.333333 45.487771 \n", "39 843.666667 1037.666667 194.000000 18.695792 \n", "42 844.333333 1281.666667 437.333333 34.122237 \n", "40 890.333333 872.333333 -18.000000 -2.063431 \n", "41 857.000000 1266.000000 409.000000 32.306477 \n", "34 1808.333333 2297.000000 488.666667 21.274126 \n", "35 1434.000000 2309.000000 875.000000 37.895193 \n", "43 853.666667 1689.000000 835.333333 49.457273 " ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "task_model_tokens = df.pivot_table(\n", " index=[\"model\", \"task_id\", \"task_name\", \"complexity\"],\n", " columns=\"library\",\n", " values=\"initial_total_tokens\",\n", " aggfunc=\"mean\",\n", " observed=False\n", ").reset_index()\n", "\n", "task_model_tokens[\"token_reduction_abs\"] = (\n", " task_model_tokens[\"Matplotlib\"] - task_model_tokens[\"Altair\"]\n", ")\n", "\n", "task_model_tokens[\"token_reduction_pct\"] = (\n", " 100\n", " * task_model_tokens[\"token_reduction_abs\"]\n", " / task_model_tokens[\"Matplotlib\"]\n", ")\n", "\n", "task_model_tokens = task_model_tokens.sort_values([\"model\", \"complexity\", \"task_id\"])\n", "\n", "task_model_tokens" ] }, { "cell_type": "code", "execution_count": 19, "id": "8e1994b2", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
modelcomplexitylibraryfirst_pass_success_ratefinal_success_ratemean_repair_attemptsmean_repair_tokensmax_repair_tokensn
0gpt-4.1-minilowAltair1.0000001.0000000.0000000.0000000.09
1gpt-4.1-minilowMatplotlib1.0000001.0000000.0000000.0000000.09
2gpt-4.1-minimediumAltair1.0000001.0000000.0000000.0000000.09
3gpt-4.1-minimediumMatplotlib1.0000001.0000000.0000000.0000000.09
4gpt-4.1-minimedium-highAltair1.0000001.0000000.0000000.0000000.06
5gpt-4.1-minimedium-highMatplotlib1.0000001.0000000.0000000.0000000.06
6gpt-4.1-minihighAltair0.6666670.6666670.333333359.6666671079.09
7gpt-4.1-minihighMatplotlib1.0000001.0000000.0000000.0000000.09
8gpt-4o-minilowAltair0.8888891.0000000.11111148.222222434.09
9gpt-4o-minilowMatplotlib1.0000001.0000000.0000000.0000000.09
10gpt-4o-minimediumAltair1.0000001.0000000.0000000.0000000.09
11gpt-4o-minimediumMatplotlib1.0000001.0000000.0000000.0000000.09
12gpt-4o-minimedium-highAltair1.0000001.0000000.0000000.0000000.06
13gpt-4o-minimedium-highMatplotlib1.0000001.0000000.0000000.0000000.06
14gpt-4o-minihighAltair0.3333330.7777780.666667552.777778886.09
15gpt-4o-minihighMatplotlib0.3333330.7777780.666667657.0000001258.09
16gpt-5.4-minilowAltair1.0000001.0000000.0000000.0000000.09
17gpt-5.4-minilowMatplotlib1.0000001.0000000.0000000.0000000.09
18gpt-5.4-minimediumAltair1.0000001.0000000.0000000.0000000.09
19gpt-5.4-minimediumMatplotlib1.0000001.0000000.0000000.0000000.09
20gpt-5.4-minimedium-highAltair1.0000001.0000000.0000000.0000000.06
21gpt-5.4-minimedium-highMatplotlib1.0000001.0000000.0000000.0000000.06
22gpt-5.4-minihighAltair0.8888891.0000000.111111119.7777781078.09
23gpt-5.4-minihighMatplotlib0.6666671.0000000.333333374.0000001561.09
24gpt-5.5lowAltair0.8888891.0000000.11111176.111111685.09
25gpt-5.5lowMatplotlib1.0000001.0000000.0000000.0000000.09
26gpt-5.5mediumAltair0.8888891.0000000.111111130.8888891178.09
27gpt-5.5mediumMatplotlib1.0000001.0000000.0000000.0000000.09
28gpt-5.5medium-highAltair1.0000001.0000000.0000000.0000000.06
29gpt-5.5medium-highMatplotlib1.0000001.0000000.0000000.0000000.06
30gpt-5.5highAltair1.0000001.0000000.0000000.0000000.09
31gpt-5.5highMatplotlib1.0000001.0000000.0000000.0000000.09
\n", "
" ], "text/plain": [ " model complexity library first_pass_success_rate \\\n", "0 gpt-4.1-mini low Altair 1.000000 \n", "1 gpt-4.1-mini low Matplotlib 1.000000 \n", "2 gpt-4.1-mini medium Altair 1.000000 \n", "3 gpt-4.1-mini medium Matplotlib 1.000000 \n", "4 gpt-4.1-mini medium-high Altair 1.000000 \n", "5 gpt-4.1-mini medium-high Matplotlib 1.000000 \n", "6 gpt-4.1-mini high Altair 0.666667 \n", "7 gpt-4.1-mini high Matplotlib 1.000000 \n", "8 gpt-4o-mini low Altair 0.888889 \n", "9 gpt-4o-mini low Matplotlib 1.000000 \n", "10 gpt-4o-mini medium Altair 1.000000 \n", "11 gpt-4o-mini medium Matplotlib 1.000000 \n", "12 gpt-4o-mini medium-high Altair 1.000000 \n", "13 gpt-4o-mini medium-high Matplotlib 1.000000 \n", "14 gpt-4o-mini high Altair 0.333333 \n", "15 gpt-4o-mini high Matplotlib 0.333333 \n", "16 gpt-5.4-mini low Altair 1.000000 \n", "17 gpt-5.4-mini low Matplotlib 1.000000 \n", "18 gpt-5.4-mini medium Altair 1.000000 \n", "19 gpt-5.4-mini medium Matplotlib 1.000000 \n", "20 gpt-5.4-mini medium-high Altair 1.000000 \n", "21 gpt-5.4-mini medium-high Matplotlib 1.000000 \n", "22 gpt-5.4-mini high Altair 0.888889 \n", "23 gpt-5.4-mini high Matplotlib 0.666667 \n", "24 gpt-5.5 low Altair 0.888889 \n", "25 gpt-5.5 low Matplotlib 1.000000 \n", "26 gpt-5.5 medium Altair 0.888889 \n", "27 gpt-5.5 medium Matplotlib 1.000000 \n", "28 gpt-5.5 medium-high Altair 1.000000 \n", "29 gpt-5.5 medium-high Matplotlib 1.000000 \n", "30 gpt-5.5 high Altair 1.000000 \n", "31 gpt-5.5 high Matplotlib 1.000000 \n", "\n", " final_success_rate mean_repair_attempts mean_repair_tokens \\\n", "0 1.000000 0.000000 0.000000 \n", "1 1.000000 0.000000 0.000000 \n", "2 1.000000 0.000000 0.000000 \n", "3 1.000000 0.000000 0.000000 \n", "4 1.000000 0.000000 0.000000 \n", "5 1.000000 0.000000 0.000000 \n", "6 0.666667 0.333333 359.666667 \n", "7 1.000000 0.000000 0.000000 \n", "8 1.000000 0.111111 48.222222 \n", "9 1.000000 0.000000 0.000000 \n", "10 1.000000 0.000000 0.000000 \n", "11 1.000000 0.000000 0.000000 \n", "12 1.000000 0.000000 0.000000 \n", "13 1.000000 0.000000 0.000000 \n", "14 0.777778 0.666667 552.777778 \n", "15 0.777778 0.666667 657.000000 \n", "16 1.000000 0.000000 0.000000 \n", "17 1.000000 0.000000 0.000000 \n", "18 1.000000 0.000000 0.000000 \n", "19 1.000000 0.000000 0.000000 \n", "20 1.000000 0.000000 0.000000 \n", "21 1.000000 0.000000 0.000000 \n", "22 1.000000 0.111111 119.777778 \n", "23 1.000000 0.333333 374.000000 \n", "24 1.000000 0.111111 76.111111 \n", "25 1.000000 0.000000 0.000000 \n", "26 1.000000 0.111111 130.888889 \n", "27 1.000000 0.000000 0.000000 \n", "28 1.000000 0.000000 0.000000 \n", "29 1.000000 0.000000 0.000000 \n", "30 1.000000 0.000000 0.000000 \n", "31 1.000000 0.000000 0.000000 \n", "\n", " max_repair_tokens n \n", "0 0.0 9 \n", "1 0.0 9 \n", "2 0.0 9 \n", "3 0.0 9 \n", "4 0.0 6 \n", "5 0.0 6 \n", "6 1079.0 9 \n", "7 0.0 9 \n", "8 434.0 9 \n", "9 0.0 9 \n", "10 0.0 9 \n", "11 0.0 9 \n", "12 0.0 6 \n", "13 0.0 6 \n", "14 886.0 9 \n", "15 1258.0 9 \n", "16 0.0 9 \n", "17 0.0 9 \n", "18 0.0 9 \n", "19 0.0 9 \n", "20 0.0 6 \n", "21 0.0 6 \n", "22 1078.0 9 \n", "23 1561.0 9 \n", "24 685.0 9 \n", "25 0.0 9 \n", "26 1178.0 9 \n", "27 0.0 9 \n", "28 0.0 6 \n", "29 0.0 6 \n", "30 0.0 9 \n", "31 0.0 9 " ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "reliability_model_complexity = (\n", " df\n", " .groupby([\"model\", \"complexity\", \"library\"], observed=False)\n", " .agg(\n", " first_pass_success_rate=(\"initial_execution_success\", \"mean\"),\n", " final_success_rate=(\"final_success\", \"mean\"),\n", " mean_repair_attempts=(\"repair_attempts\", \"mean\"),\n", " mean_repair_tokens=(\"repair_total_tokens\", \"mean\"),\n", " max_repair_tokens=(\"repair_total_tokens\", \"max\"),\n", " n=(\"run_id\", \"count\"),\n", " )\n", " .reset_index()\n", ")\n", "\n", "reliability_model_complexity" ] }, { "cell_type": "code", "execution_count": 20, "id": "aebe282f", "metadata": {}, "outputs": [], "source": [ "summary_model_complexity.to_csv(\"table_summary_model_complexity.csv\", index=False)\n", "model_complexity_tokens.to_csv(\"table_model_complexity_token_reduction.csv\", index=False)\n", "summary_all_models_complexity.to_csv(\"table_summary_all_models_complexity.csv\", index=False)\n", "all_models_complexity_tokens.to_csv(\"table_all_models_complexity_token_reduction.csv\", index=False)\n", "task_model_tokens.to_csv(\"table_task_model_tokens.csv\", index=False)\n", "reliability_model_complexity.to_csv(\"table_reliability_model_complexity.csv\", index=False)" ] }, { "cell_type": "markdown", "id": "8765e470", "metadata": {}, "source": [ "#### PAPER FIGURE PLOTTING" ] }, { "cell_type": "code", "execution_count": 21, "id": "4504f8d9", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Saved: figures/altair_token_reduction_by_complexity.pdf\n", "Saved: figures/altair_token_reduction_by_complexity.png\n" ] } ], "source": [ "# -------------------------------------------------------------------\n", "# Input / output\n", "# -------------------------------------------------------------------\n", "INPUT_CSV = \"table_model_complexity_token_reduction.csv\"\n", "OUTPUT_DIR = Path(\"figures\")\n", "OUTPUT_DIR.mkdir(exist_ok=True)\n", "\n", "OUTPUT_PDF = OUTPUT_DIR / \"altair_token_reduction_by_complexity.pdf\"\n", "OUTPUT_PNG = OUTPUT_DIR / \"altair_token_reduction_by_complexity.png\"\n", "\n", "# -------------------------------------------------------------------\n", "# Load data\n", "# -------------------------------------------------------------------\n", "df = pd.read_csv(INPUT_CSV)\n", "\n", "# Expected columns:\n", "# model, complexity, Altair, Matplotlib, token_reduction_abs, token_reduction_pct\n", "\n", "complexity_order = [\"low\", \"medium\", \"medium-high\", \"high\"]\n", "\n", "df[\"complexity\"] = pd.Categorical(\n", " df[\"complexity\"],\n", " categories=complexity_order,\n", " ordered=True\n", ")\n", "\n", "df = df.sort_values([\"model\", \"complexity\"])\n", "\n", "# Optional: remove failed/incomplete models if present\n", "df = df[df[\"token_reduction_pct\"].notna()].copy()\n", "\n", "# -------------------------------------------------------------------\n", "# Plot\n", "# -------------------------------------------------------------------\n", "fig, ax = plt.subplots(figsize=(8.5, 4.8))\n", "\n", "for model, model_df in df.groupby(\"model\", sort=False):\n", " model_df = model_df.sort_values(\"complexity\")\n", " ax.plot(\n", " model_df[\"complexity\"].astype(str),\n", " model_df[\"token_reduction_pct\"],\n", " marker=\"o\",\n", " linewidth=2,\n", " label=model,\n", " )\n", "\n", "ax.axhline(0, linewidth=1, linestyle=\"--\")\n", "\n", "ax.set_title(\"Altair token reduction relative to Matplotlib\")\n", "ax.set_xlabel(\"Task complexity\")\n", "ax.set_ylabel(\"First-pass token reduction (%)\")\n", "\n", "ax.legend(title=\"Model\", frameon=False, loc=\"upper left\")\n", "ax.grid(axis=\"y\", alpha=0.3)\n", "\n", "fig.tight_layout()\n", "\n", "#fig.savefig(\"academia/altair_agentic_report/altair_token_reduction_by_complexity.pdf\", bbox_inches=\"tight\")\n", "fig.savefig(\"academia/altair_agentic_report/altair_token_reduction_by_complexity.png\", dpi=300, bbox_inches=\"tight\")\n", "\n", "plt.show()\n", "\n", "print(\"Saved:\", OUTPUT_PDF)\n", "print(\"Saved:\", OUTPUT_PNG)" ] }, { "cell_type": "code", "execution_count": null, "id": "52205af1", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "f1383035", "metadata": {}, "source": [ "#### SECOND CLAUDE" ] }, { "cell_type": "code", "execution_count": null, "id": "b98bd493", "metadata": {}, "outputs": [], "source": [ "claude_results = []\n", "\n", "for model in CLAUDE_MODELS:\n", " for task in TASKS[:3]: # start small\n", " for library in LIBRARIES:\n", " for run_id in range(1, 2):\n", " print(f\"Running Claude | {model} | {task['task_id']} | {library} | run {run_id}\")\n", " try:\n", " row = run_single_generation(\n", " provider=\"claude\",\n", " model=model,\n", " task=task,\n", " library=library,\n", " run_id=run_id,\n", " temperature=0.0,\n", " max_repair_attempts=1,\n", " output_dir=\"experiment_outputs\",\n", " )\n", " claude_results.append(row)\n", " except Exception:\n", " claude_results.append({\n", " \"timestamp\": datetime.utcnow().isoformat(),\n", " \"provider\": \"claude\",\n", " \"model\": model,\n", " \"task_id\": task[\"task_id\"],\n", " \"task_name\": task[\"task_name\"],\n", " \"library\": library,\n", " \"run_id\": run_id,\n", " \"error\": traceback.format_exc(),\n", " })\n", "\n", " time.sleep(1)\n", "\n", "claude_results_df = pd.DataFrame(claude_results)\n", "claude_results_df.to_csv(\"claude_altair_matplotlib_results.csv\", index=False)\n", "claude_results_df.head()" ] }, { "cell_type": "markdown", "id": "851f6c57", "metadata": {}, "source": [ "### AGREATE RESULTS" ] }, { "cell_type": "code", "execution_count": null, "id": "a2d37d4f", "metadata": {}, "outputs": [], "source": [ "all_results_df = pd.concat(\n", " [\n", " pd.read_csv(\"openai_altair_matplotlib_results_full.csv\"),\n", " pd.read_csv(\"claude_altair_matplotlib_results_full.csv\"),\n", " ],\n", " ignore_index=True\n", ")\n", "\n", "all_results_df.to_csv(\"all_model_altair_matplotlib_results.csv\", index=False)\n", "\n", "summary = (\n", " all_results_df\n", " .groupby([\"provider\", \"model\", \"task_id\", \"task_name\", \"library\"], dropna=False)\n", " .agg(\n", " mean_total_tokens=(\"total_agentic_tokens\", \"mean\"),\n", " std_total_tokens=(\"total_agentic_tokens\", \"std\"),\n", " mean_code_tokens_proxy=(\"initial_completion_tokens\", \"mean\"),\n", " mean_code_lines=(\"initial_code_lines\", \"mean\"),\n", " mean_repairs=(\"repair_attempts\", \"mean\"),\n", " success_rate=(\"final_success\", \"mean\"),\n", " n=(\"run_id\", \"count\"),\n", " )\n", " .reset_index()\n", ")\n", "\n", "summary.to_csv(\"summary_results.csv\", index=False)\n", "summary" ] }, { "cell_type": "code", "execution_count": null, "id": "26117e0b", "metadata": {}, "outputs": [], "source": [ "pivot = summary.pivot_table(\n", " index=[\"provider\", \"model\", \"task_id\", \"task_name\"],\n", " columns=\"library\",\n", " values=\"mean_total_tokens\"\n", ").reset_index()\n", "\n", "pivot[\"token_reduction_abs\"] = pivot[\"Matplotlib\"] - pivot[\"Altair\"]\n", "pivot[\"token_reduction_pct\"] = 100 * (pivot[\"Matplotlib\"] - pivot[\"Altair\"]) / pivot[\"Matplotlib\"]\n", "\n", "pivot.to_csv(\"altair_vs_matplotlib_token_reduction.csv\", index=False)\n", "pivot" ] }, { "cell_type": "code", "execution_count": null, "id": "d2032e5c", "metadata": {}, "outputs": [], "source": [ "latex_table = pivot[\n", " [\"provider\", \"model\", \"task_id\", \"task_name\", \"Matplotlib\", \"Altair\", \"token_reduction_pct\"]\n", "].copy()\n", "\n", "latex_table[\"Matplotlib\"] = latex_table[\"Matplotlib\"].round(1)\n", "latex_table[\"Altair\"] = latex_table[\"Altair\"].round(1)\n", "latex_table[\"token_reduction_pct\"] = latex_table[\"token_reduction_pct\"].round(1)\n", "\n", "print(\n", " latex_table.to_latex(\n", " index=False,\n", " escape=True,\n", " caption=\"Mean total agentic tokens by model, task, and visualization library.\",\n", " label=\"tab:token-results\"\n", " )\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "de556003", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "data_visualization_altair", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.13" } }, "nbformat": 4, "nbformat_minor": 5 }