From 906e8301fb3977ae35373534d1f7cc0896e2406a Mon Sep 17 00:00:00 2001 From: recursix Date: Mon, 25 Nov 2024 13:37:33 -0500 Subject: [PATCH 1/5] removing old code --- ICML2024/script.ipynb | 732 ------------------ src/agentlab/analyze/error_categorization.py | 89 --- src/agentlab/analyze/inspect_results.py | 45 +- src/agentlab/analyze/plot_tools.py | 409 ---------- src/agentlab/experiments/get_ray_url.py | 5 + .../experiments/graph_execution_dask.py | 64 -- .../experiments/list_openai_models.py | 4 +- .../experiments/miniwob_tasks_all.csv | 126 --- src/agentlab/experiments/reproduce_study.py | 2 +- src/agentlab/experiments/view_dep_graph.py | 3 + src/agentlab/utils/__init__.py | 0 src/agentlab/utils/bootstrap.py | 120 --- tests/utils/test_bootstrap.py | 132 ---- 13 files changed, 13 insertions(+), 1718 deletions(-) delete mode 100644 ICML2024/script.ipynb delete mode 100644 src/agentlab/analyze/error_categorization.py delete mode 100644 src/agentlab/analyze/plot_tools.py delete mode 100644 src/agentlab/experiments/graph_execution_dask.py delete mode 100644 src/agentlab/experiments/miniwob_tasks_all.csv delete mode 100644 src/agentlab/utils/__init__.py delete mode 100644 src/agentlab/utils/bootstrap.py delete mode 100644 tests/utils/test_bootstrap.py diff --git a/ICML2024/script.ipynb b/ICML2024/script.ipynb deleted file mode 100644 index da53b994..00000000 --- a/ICML2024/script.ipynb +++ /dev/null @@ -1,732 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 370, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " benchmark Task group max DOM k-tokens max Pruned DOM k-tokens \\\n", - "0 miniwob [ALL TASKS] 7.586 5.468 \n", - "1 miniwob [ALL TASKS] 9.978 6.304 \n", - "2 workarena form 1337.341 1255.558 \n", - "3 workarena knowledge 72.976 60.304 \n", - "4 workarena list-filter 1442.547 1373.995 \n", - "\n", - " max AXTree k-tokens episode DOM k-tokens episode Pruned DOM k-tokens \\\n", - "0 1.009 10.597492 4.143874 \n", - "1 2.196 11.799989 6.235014 \n", - "2 56.093 2838.753426 2293.452617 \n", - "3 6.229 316.468900 179.223000 \n", - "4 78.882 2226.093472 1648.841453 \n", - "\n", - " episode AXTree k-tokens agent \n", - "0 0.721944 base_agent \n", - "1 1.186288 full_agent \n", - "2 104.499426 base_agent \n", - "3 14.687900 base_agent \n", - "4 181.179585 base_agent \n" - ] - } - ], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "import seaborn as sns\n", - "import matplotlib.pyplot as plt\n", - "import matplotlib.cm as cm\n", - "from matplotlib.colors import ListedColormap\n", - "\n", - "# Read the CSV file\n", - "df = pd.read_csv('data.csv')\n", - "\n", - "print(df.head())\n" - ] - }, - { - "cell_type": "code", - "execution_count": 371, - "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", - "
benchmarkTask groupagenttypeobsvalue
0miniwobminiwob [ALL TASKS]base_agentmaxDOM k-tokens7586.0
2workarenaworkarena formbase_agentmaxDOM k-tokens1337341.0
3workarenaworkarena knowledgebase_agentmaxDOM k-tokens72976.0
4workarenaworkarena list-filterbase_agentmaxDOM k-tokens1442547.0
5workarenaworkarena list-sortbase_agentmaxDOM k-tokens1336066.0
6workarenaworkarena menubase_agentmaxDOM k-tokens270660.0
7workarenaworkarena service catalogbase_agentmaxDOM k-tokens1284051.0
8workarenaworkarena [ALL TASKS]base_agentmaxDOM k-tokens1442547.0
32miniwobminiwob [ALL TASKS]base_agentmaxAXTree k-tokens1009.0
34workarenaworkarena formbase_agentmaxAXTree k-tokens56093.0
35workarenaworkarena knowledgebase_agentmaxAXTree k-tokens6229.0
36workarenaworkarena list-filterbase_agentmaxAXTree k-tokens78882.0
37workarenaworkarena list-sortbase_agentmaxAXTree k-tokens83581.0
38workarenaworkarena menubase_agentmaxAXTree k-tokens14110.0
39workarenaworkarena service catalogbase_agentmaxAXTree k-tokens58863.0
40workarenaworkarena [ALL TASKS]base_agentmaxAXTree k-tokens83581.0
\n", - "
" - ], - "text/plain": [ - " benchmark Task group agent type obs \\\n", - "0 miniwob miniwob [ALL TASKS] base_agent max DOM k-tokens \n", - "2 workarena workarena form base_agent max DOM k-tokens \n", - "3 workarena workarena knowledge base_agent max DOM k-tokens \n", - "4 workarena workarena list-filter base_agent max DOM k-tokens \n", - "5 workarena workarena list-sort base_agent max DOM k-tokens \n", - "6 workarena workarena menu base_agent max DOM k-tokens \n", - "7 workarena workarena service catalog base_agent max DOM k-tokens \n", - "8 workarena workarena [ALL TASKS] base_agent max DOM k-tokens \n", - "32 miniwob miniwob [ALL TASKS] base_agent max AXTree k-tokens \n", - "34 workarena workarena form base_agent max AXTree k-tokens \n", - "35 workarena workarena knowledge base_agent max AXTree k-tokens \n", - "36 workarena workarena list-filter base_agent max AXTree k-tokens \n", - "37 workarena workarena list-sort base_agent max AXTree k-tokens \n", - "38 workarena workarena menu base_agent max AXTree k-tokens \n", - "39 workarena workarena service catalog base_agent max AXTree k-tokens \n", - "40 workarena workarena [ALL TASKS] base_agent max AXTree k-tokens \n", - "\n", - " value \n", - "0 7586.0 \n", - "2 1337341.0 \n", - "3 72976.0 \n", - "4 1442547.0 \n", - "5 1336066.0 \n", - "6 270660.0 \n", - "7 1284051.0 \n", - "8 1442547.0 \n", - "32 1009.0 \n", - "34 56093.0 \n", - "35 6229.0 \n", - "36 78882.0 \n", - "37 83581.0 \n", - "38 14110.0 \n", - "39 58863.0 \n", - "40 83581.0 " - ] - }, - "execution_count": 371, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 383, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0 False\n", - "2 False\n", - "3 False\n", - "4 False\n", - "5 False\n", - "6 False\n", - "7 False\n", - "8 True\n", - "32 False\n", - "34 False\n", - "35 False\n", - "36 False\n", - "37 False\n", - "38 False\n", - "39 False\n", - "40 True\n", - "Name: Task group, dtype: bool" - ] - }, - "execution_count": 383, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_melt['Task group'] == \"workarena [ALL TASKS]\"" - ] - }, - { - "cell_type": "code", - "execution_count": 415, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " benchmark Task group agent type obs value\n", - "0 miniwob miniwob [ALL TASKS] base_agent max DOM k-tokens 7586.0\n", - "2 workarena workarena form base_agent max DOM k-tokens 1337341.0\n", - "3 workarena workarena knowledge base_agent max DOM k-tokens 72976.0\n", - "4 workarena workarena list-filter base_agent max DOM k-tokens 1442547.0\n", - "5 workarena workarena list-sort base_agent max DOM k-tokens 1336066.0\n", - " benchmark Task group agent type obs value\n", - "1 miniwob miniwob [ALL TASKS] full_agent max DOM k-tokens 9978.0\n", - "9 workarena workarena form full_agent max DOM k-tokens 1550687.0\n", - "10 workarena workarena knowledge full_agent max DOM k-tokens 178639.0\n", - "11 workarena workarena list-filter full_agent max DOM k-tokens 1593240.0\n", - "12 workarena workarena list-sort full_agent max DOM k-tokens 1493638.0\n" - ] - } - ], - "source": [ - "print(df_b.head())\n", - "print(df_f.head())" - ] - }, - { - "cell_type": "code", - "execution_count": 481, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " benchmark Task group agent type obs value\n", - "0 miniwob [ALL TASKS] base_agent max DOM k-tokens 7586.0\n", - "1 miniwob [ALL TASKS] full_agent max DOM k-tokens 9978.0\n", - "2 workarena form base_agent max DOM k-tokens 1337341.0\n", - "3 workarena knowledge base_agent max DOM k-tokens 72976.0\n", - "4 workarena list-filter base_agent max DOM k-tokens 1442547.0\n", - " benchmark Task group agent type obs value\n", - "0 miniwob miniwob [ALL TASKS] base_agent max DOM k-tokens 7586.0\n", - "1 miniwob miniwob [ALL TASKS] full_agent max DOM k-tokens 9978.0\n", - "2 workarena workarena form base_agent max DOM k-tokens 1337341.0\n", - "3 workarena workarena knowledge base_agent max DOM k-tokens 72976.0\n", - "4 workarena workarena list-filter base_agent max DOM k-tokens 1442547.0\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\Tom\\AppData\\Local\\Temp\\ipykernel_38828\\1123958528.py:46: FutureWarning: \n", - "\n", - "The `ci` parameter is deprecated. Use `errorbar=None` for the same effect.\n", - "\n", - " sns.barplot(x='obs', y='value', hue='Task group', hue_order=sorted_task_group, data=df_b, order=None, palette=palette, ci=None)\n", - "C:\\Users\\Tom\\AppData\\Local\\Temp\\ipykernel_38828\\1123958528.py:50: FutureWarning: \n", - "\n", - "The `ci` parameter is deprecated. Use `errorbar=None` for the same effect.\n", - "\n", - " sns.barplot(x='obs', y='value', hue='Task group', hue_order=sorted_task_group, data=df_f, order=None, palette=[(0.75, 0.75, 0.7)], ci=None)\n", - "C:\\Users\\Tom\\AppData\\Local\\Temp\\ipykernel_38828\\1123958528.py:50: UserWarning: \n", - "The palette list has fewer values (1) than needed (7) and will cycle, which may produce an uninterpretable plot.\n", - " sns.barplot(x='obs', y='value', hue='Task group', hue_order=sorted_task_group, data=df_f, order=None, palette=[(0.75, 0.75, 0.7)], ci=None)\n", - "C:\\Users\\Tom\\AppData\\Local\\Temp\\ipykernel_38828\\1123958528.py:53: FutureWarning: \n", - "\n", - "The `ci` parameter is deprecated. Use `errorbar=None` for the same effect.\n", - "\n", - " sns.barplot(x='obs', y='value', hue='Task group', hue_order=sorted_task_group, data=df_b, order=None, palette=palette, ci=None)\n" - ] - }, - { - "ename": "PermissionError", - "evalue": "[Errno 13] Permission denied: 'wa_complexity_0.pdf'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mPermissionError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[481], line 68\u001b[0m\n\u001b[0;32m 64\u001b[0m \u001b[38;5;66;03m#put legend on top two rows aligned legend word on the right\u001b[39;00m\n\u001b[0;32m 66\u001b[0m legend1 \u001b[38;5;241m=\u001b[39m plt\u001b[38;5;241m.\u001b[39mlegend(loc\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mupper center\u001b[39m\u001b[38;5;124m'\u001b[39m, fontsize\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m16\u001b[39m, bbox_to_anchor\u001b[38;5;241m=\u001b[39m(\u001b[38;5;241m0.5\u001b[39m, \u001b[38;5;241m1.24\u001b[39m), ncol\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m4\u001b[39m, labels\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMiniWoB\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mknowledge\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmenu\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mservice catalog\u001b[39m\u001b[38;5;124m\"\u001b[39m,\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlist-sort\u001b[39m\u001b[38;5;124m\"\u001b[39m , \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mform\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlist-filter\u001b[39m\u001b[38;5;124m\"\u001b[39m])\n\u001b[1;32m---> 68\u001b[0m \u001b[43mplt\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msavefig\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mwa_complexity_\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mi\u001b[49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m.pdf\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdpi\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m300\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbbox_inches\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mtight\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 69\u001b[0m plt\u001b[38;5;241m.\u001b[39msavefig(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mwa_complexity_\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mi\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.png\u001b[39m\u001b[38;5;124m'\u001b[39m, dpi\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m300\u001b[39m, bbox_inches\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtight\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\matplotlib\\pyplot.py:1119\u001b[0m, in \u001b[0;36msavefig\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m 1116\u001b[0m fig \u001b[38;5;241m=\u001b[39m gcf()\n\u001b[0;32m 1117\u001b[0m \u001b[38;5;66;03m# savefig default implementation has no return, so mypy is unhappy\u001b[39;00m\n\u001b[0;32m 1118\u001b[0m \u001b[38;5;66;03m# presumably this is here because subclasses can return?\u001b[39;00m\n\u001b[1;32m-> 1119\u001b[0m res \u001b[38;5;241m=\u001b[39m \u001b[43mfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msavefig\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# type: ignore[func-returns-value]\u001b[39;00m\n\u001b[0;32m 1120\u001b[0m fig\u001b[38;5;241m.\u001b[39mcanvas\u001b[38;5;241m.\u001b[39mdraw_idle() \u001b[38;5;66;03m# Need this if 'transparent=True', to reset colors.\u001b[39;00m\n\u001b[0;32m 1121\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m res\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\matplotlib\\figure.py:3390\u001b[0m, in \u001b[0;36mFigure.savefig\u001b[1;34m(self, fname, transparent, **kwargs)\u001b[0m\n\u001b[0;32m 3388\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m ax \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39maxes:\n\u001b[0;32m 3389\u001b[0m _recursively_make_axes_transparent(stack, ax)\n\u001b[1;32m-> 3390\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcanvas\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mprint_figure\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\matplotlib\\backend_bases.py:2193\u001b[0m, in \u001b[0;36mFigureCanvasBase.print_figure\u001b[1;34m(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)\u001b[0m\n\u001b[0;32m 2189\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m 2190\u001b[0m \u001b[38;5;66;03m# _get_renderer may change the figure dpi (as vector formats\u001b[39;00m\n\u001b[0;32m 2191\u001b[0m \u001b[38;5;66;03m# force the figure dpi to 72), so we need to set it again here.\u001b[39;00m\n\u001b[0;32m 2192\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m cbook\u001b[38;5;241m.\u001b[39m_setattr_cm(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfigure, dpi\u001b[38;5;241m=\u001b[39mdpi):\n\u001b[1;32m-> 2193\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mprint_method\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 2194\u001b[0m \u001b[43m \u001b[49m\u001b[43mfilename\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 2195\u001b[0m \u001b[43m \u001b[49m\u001b[43mfacecolor\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mfacecolor\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 2196\u001b[0m \u001b[43m \u001b[49m\u001b[43medgecolor\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43medgecolor\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 2197\u001b[0m \u001b[43m \u001b[49m\u001b[43morientation\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43morientation\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 2198\u001b[0m \u001b[43m \u001b[49m\u001b[43mbbox_inches_restore\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m_bbox_inches_restore\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 2199\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 2200\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[0;32m 2201\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m bbox_inches \u001b[38;5;129;01mand\u001b[39;00m restore_bbox:\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\matplotlib\\backend_bases.py:2043\u001b[0m, in \u001b[0;36mFigureCanvasBase._switch_canvas_and_return_print_method..\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m 2039\u001b[0m optional_kws \u001b[38;5;241m=\u001b[39m { \u001b[38;5;66;03m# Passed by print_figure for other renderers.\u001b[39;00m\n\u001b[0;32m 2040\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdpi\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfacecolor\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124medgecolor\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124morientation\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 2041\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbbox_inches_restore\u001b[39m\u001b[38;5;124m\"\u001b[39m}\n\u001b[0;32m 2042\u001b[0m skip \u001b[38;5;241m=\u001b[39m optional_kws \u001b[38;5;241m-\u001b[39m {\u001b[38;5;241m*\u001b[39minspect\u001b[38;5;241m.\u001b[39msignature(meth)\u001b[38;5;241m.\u001b[39mparameters}\n\u001b[1;32m-> 2043\u001b[0m print_method \u001b[38;5;241m=\u001b[39m functools\u001b[38;5;241m.\u001b[39mwraps(meth)(\u001b[38;5;28;01mlambda\u001b[39;00m \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: \u001b[43mmeth\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 2044\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m{\u001b[49m\u001b[43mk\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mv\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mk\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mv\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mitems\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mk\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mnot\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mskip\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[0;32m 2045\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m: \u001b[38;5;66;03m# Let third-parties do as they see fit.\u001b[39;00m\n\u001b[0;32m 2046\u001b[0m print_method \u001b[38;5;241m=\u001b[39m meth\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\matplotlib\\backends\\backend_pdf.py:2800\u001b[0m, in \u001b[0;36mFigureCanvasPdf.print_pdf\u001b[1;34m(self, filename, bbox_inches_restore, metadata)\u001b[0m\n\u001b[0;32m 2798\u001b[0m file \u001b[38;5;241m=\u001b[39m filename\u001b[38;5;241m.\u001b[39m_ensure_file()\n\u001b[0;32m 2799\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m-> 2800\u001b[0m file \u001b[38;5;241m=\u001b[39m \u001b[43mPdfFile\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfilename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmetadata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmetadata\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 2801\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m 2802\u001b[0m file\u001b[38;5;241m.\u001b[39mnewPage(width, height)\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\matplotlib\\backends\\backend_pdf.py:688\u001b[0m, in \u001b[0;36mPdfFile.__init__\u001b[1;34m(self, filename, metadata)\u001b[0m\n\u001b[0;32m 686\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moriginal_file_like \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 687\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtell_base \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m--> 688\u001b[0m fh, opened \u001b[38;5;241m=\u001b[39m \u001b[43mcbook\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_filehandle\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfilename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mwb\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mreturn_opened\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[0;32m 689\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m opened:\n\u001b[0;32m 690\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\matplotlib\\cbook.py:483\u001b[0m, in \u001b[0;36mto_filehandle\u001b[1;34m(fname, flag, return_opened, encoding)\u001b[0m\n\u001b[0;32m 481\u001b[0m fh \u001b[38;5;241m=\u001b[39m bz2\u001b[38;5;241m.\u001b[39mBZ2File(fname, flag)\n\u001b[0;32m 482\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 483\u001b[0m fh \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mopen\u001b[39m(fname, flag, encoding\u001b[38;5;241m=\u001b[39mencoding)\n\u001b[0;32m 484\u001b[0m opened \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[0;32m 485\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(fname, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mseek\u001b[39m\u001b[38;5;124m'\u001b[39m):\n", - "\u001b[1;31mPermissionError\u001b[0m: [Errno 13] Permission denied: 'wa_complexity_0.pdf'" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA3AAAAIECAYAAABYLsy0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAACko0lEQVR4nOzdd1QUVxsG8Gd26SAoXQE7il1QmoolEk1MYtSIXawxxt5iosYSW9QvMSb2biyxETVijL3EKBYURMWCaKJIR5Bed74/CKuE6rC4rDy/c3JOmLk78yzOMPvu3LlXEEVRBBEREREREVV4MnUHICIiIiIiotJhAUdERERERKQhWMARERERERFpCBZwREREREREGoIFHBERERERkYZgAUdERERERKQhWMARERERERFpCBZwREREREREGkJL3QEqoqysLOTk5Kg7BhERERERvcXkcjm0tbVf6zUs4F6RmJiImJhYpKenqzsKERERERFVAnp6erCwMIexsXGp2guiKIrlnEkjJCYmIiwsDNraejA0NIJcztqWiIiIiIjKT05ONlJSkpGVlQ5bW9tSFXGsUv4VExMLbW09mJlZQhAEdcchIiIiIqK3ni709AwQFxeN2NjYUhVwHMQEuc+8paenw9DQiMUbERERERG9MYIgwMDACGlp6cjKyiqxPQs4QDlgCbtNEhERERHRm6allVuHlGYgRRZwREREREREGoIFHBERERERkYZgAUdERERERKQh+NBXKQmCAJlMswY4UShEcJYIqsg07bziOUWkGpp27gOacf6Loqhxg7FpYuZX8VguH+o6LjTleGQBVwqCIMDIWA9aMs26YZmtUCA5MV0lJ+mRI4excOE8AICxsQmOHj2pfNiyMLdvB2HkyKEAgObNW2LDhi0AADc3JwDAX39dLfb1xZk/fy6OHvXFjBmz8fHHPTFhwhhcvXoZU6ZMR58+/Qq0z8zMRNeunZCWloZatWpj794DhW538eIFOHz4IEaN+hzDh3/62rk2blyHzZs3FFguk8lgbGyM2rXr4L33uqF7956QadixVB4EQYBRFT1oyTXnd5Gdo0BykmrOKaLKShAEGBvradzfQYVCgUQVXVP/ex3Lu34MHToCo0ePlbTNK1f8sHPndqxcubbM+d6EnJwcHDzog3/++QdTp05XdxxJeCxXrGM5JOQBfvjhO9y7FwxR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Ojrw8/NDRkYGpk6dCgcHB3XHJCIiIiIikuytKeAAwMvLC9bW1tiwYQMCAwMhl8vRuHFjDB8+XDnAChERERERkabSqAJuyZIlWLJkSbFtPDw83sjIl0RERERERG+apGkEiIiIiIiI6M1jAUdERERERKQhWMARERERERFpCBZwREREREREGkLSICbe3t4lthEEAVpaWqhSpQpq1aqFd999F02bNpWyOyIiIiIiIoLEAu7q1asAcos0URQLbfPfdRs3bsS4ceMwZswYKbskIiIiIiKq9CQVcKdOncK0adNw8+ZN9OrVC++//z5sbW0hiiIiIyNx6tQp7Nu3DzY2Npg2bRqePXuGLVu2YOXKlWjZsiXatGmj6vdBRERERET01pNUwB05cgQ3b97EsmXL8NFHH+VbV7duXbRp0wYeHh74/PPP8fTpUwwfPhwdO3bEhx9+iF27drGAIyIiIiIikkDSICYHDhxA06ZNCxRvr+rUqRMcHR2xd+9eAEDt2rXh6OiIoKAgaUmJiIiIiIgqOUkFXFRUFGxsbEpsZ2lpiYiICOXP5ubmePHihZRdEhERERERVXqSCjgrKysEBgYiKyuryDZZWVm4efMmzMzMlMvi4+NRrVo1KbskIiIiIiKq9CQVcF27dkVkZCRmzpyJjIyMAuszMjLw9ddfIyoqCp07dwYAPHv2DNevX4e9vX3ZEhMREREREVVSkgYxGTVqFM6ePQtfX19cuHABbdu2RY0aNaBQKBAeHg4/Pz8kJCSgZs2aGDduHF68eIHu3bsjOzsbXl5eqn4PRERERERElYKkAq5KlSrYvn07li5dCl9fX/z+++/51stkMnzwwQeYOXMmqlatirt37yIjIwNDhw5F165dVRKciIiIiIiospFUwAGAqakpli5diq+++gpXrlxBREQEsrKyUL16dbi4uMDKykrZtl69evD394eenp5KQhMREREREVVGkgu4PNWqVcN7771XbBsdHZ2y7oaIiIiIiKjSK1MBFxMTg927d+Pq1auIiYmBjo4OzMzM4Orqih49eqB69eqqyklERERERFTpSS7gzp8/j6lTpyIlJQWiKCqXh4SE4MqVK9i0aROWLVumHIWSiIiIiIiIykZSARcaGoqJEyciIyMDPXr0wAcffABbW1vk5OQgLCwMR48exeHDhzFt2jQcOHAAderUUXVuIiIiIiKi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KXZC723btiEsLAweHh6SwxEREREREdFLkgYxGT16NP744w8sXrwYly9fhouLCwAgOjoaPj4++PPPP3Hy5EkYGxvj008/VWlgIiIiIiKiykpSAWdhYYEtW7ZgwoQJOH36tHKqgCtXruDKlSsQRREWFhb46aefUKNGDZUGJiIiIiIiqqwkT+Tt4OCAo0eP4sSJE7hy5QoiIiKQk5MDS0tLODs7o1u3btDT01NlViIiIiIiokpNcgEHAFpaWujWrRu6detWZJuMjAzo6uqWZTdEREREREQEiYOYnDp1qlTtLl26hA8//FDKLoiIiIiIiOg/JBVwkyZNwsmTJ4tcn5iYiBkzZmDEiBEICwuTHI6IiIiIiIheklTAyeVyTJ48GcePHy+w7ujRo+jWrRsOHToEHR0dTJw4scwhiYiIiIiISGIBt2nTJujo6GDq1Kn4448/AABRUVH4/PPPMXXqVMTGxqJNmzY4cuQIRo8erdLARERERERElZWkQUycnZ2xbds2fPrpp/jiiy9w7do1HD58GMnJyTA3N8fMmTOLHdiEiIiIiIiIXp+kO3AA0Lx5c2zfvh0mJibYvXs30tLSMGDAABw7dozFGxERERERUTmQXMABQMOGDfHLL7/A2toaoiiiSZMmMDIyUlU2IiIiIiIiekWpulBOnz692PW2traIiIjA7NmzceHCBejo6CjXCYKApUuXli0lERERERERla6AO3z4cKk2plAocOzYsXzLWMARERERERGpRqkKuG+//ba8cxAREREREVEJSlXA9ezZs7xzEBERERERUQkkTSPwX0+fPkVMTAx0dHRgbm4Oa2trVWyWiIiIiIiIXlGmAm7Xrl3YtGkTIiMj8y23tbXFoEGDMGTIkDKFIyIiIiIiopckF3AzZszAoUOHIIoizM3NYWtrC4VCgbCwMDx9+hRLlizBnTt3sGzZMlXmJSIiIiIiqrQkFXC+vr44ePAg7OzssHjxYjg7O+dbf/nyZXz99dfw9fVF586d0bVrV5WEJSIiIiIiqswkTeS9Z88e6OrqYsuWLQWKNwBwc3PD1q1boa2tjT179pQ5JBEREREREUks4O7duwdnZ2fY2dkV2cbOzg4uLi64e/eu5HBERERERET0kqQCLjs7G/r6+iW209fXR3p6upRdEBERERER0X9IKuBq1qwJf39/pKWlFdkmNTUV/v7+xd6lIyIiIiIiotKTVMB169YN8fHx+OKLL5CSklJgfUpKCqZNm4aEhAS89957ZQ5JREREREREEkehHD58OI4ePYpTp06hU6dOaNOmDWxsbAAAz549w8WLF5GUlAR7e3sMGzZMpYGJiIiIiIgqK0kFnK6uLnbs2IHZs2fj5MmTOHbsWL71giDA09MT8+fPh4GBgUqCEhERERERVXaSJ/KuWrUqVq5cifDwcFy7dg3R0dEQRRGWlpZo3bo1bG1tVZmTiIiIiIio0pNUwF27dg1mZmaoW7cuatSogY8//rjQdjdv3sSDBw/g5eVVppBEREREREQkcRCTwYMHY/369SW227x5M5YsWSJlF0RERERERPQfpboDd/nyZYiimG9ZTEwM/Pz8inxNcnIybty4UeB1REREREREJE2pCrhff/0VR44cUf4sCAL8/PyKLeAAQBRFdO7cuWwJiYiIiCowmUyATCaoO0apaVJWIiqoVAXcF198gaioKOXdtFefgSuMIAjQ1dVFrVq1MGbMGNWlJSIiIqpAZDIB1aoZQCaT9FQKEdFrK1UBZ2lpie3btyt/dnBwQNu2bbFs2bJyC0ZERERU0eXefZMhODgAKSnJ6o5TKtWr28LWto66YxCRRJJGoTx9+jTndyMiIiL6lyY9869BUYmoEJIKOBsbG1XnICIiItI4MpkMOQoFmjRxUncUIqokJE/kTURERFQeNGlQEG1tGeQyGcZsP4eQyAR1xymVdxrbYsaHrdUdg4gkYgH3r2fPnuHDDz/E7Nmz0atXL3XHISIiqpQ0dVCQkMgE3AqLU3eMUqlvZaLuCERUBizg/rVgwQKkpqaqOwYREVGlpmmDgnBAECJ600pVwCkUCo37Jux1HDt2DHfu3FF3DCIiIvpXSkoykpMT1R2jRBkZ6eqOQESVTKmqsvfeew/z5s1T/nzt2jU8evSovDK9UcnJyVi0aBFmzJih7ihERERERETFKlUBFxkZiYSEBOXPgwcPxvr168sr0xu1fPlyNG3aFJ07d1Z3FCIiIiIiomKVqgulgYEB/P394e/vDysrKwBASkoKnj59Wqqd2NnZSU9YjoKCgnDw4EEcOXJE3VGIiIiIiIhKVKoCzsPDA76+vhg8eDAAQBAEnD59GqdPny7xtYIgIDg4uGwpy0FOTg7mzJmDzz//HDY2NsjIyFB3JCIiIiIiomKVqoD7+uuvIQgCgoKCkJmZifDwcOjr66NatWrlna/cbN++HRkZGfD29kZ2djZycnIA5A7YkpOTA7lcruaERERERERE+ZWqgDMxMcGyZcuUPzs4OODdd9/Nt0zTnDlzBo8ePUKLFi3yLZ81axbWrFmDM2fOqCkZERERERFR4STNA9ezZ084OTmpOssb9c033yAlJUX5c1ZWFvr3749x48ahS5cuakxGRERERERUOEkF3Lfffpvv56dPnyImJgY6OjowNzeHtbW1SsKVp7p16+b7Oe8ZOBsbGzRs2FAdkYiIiIiIiIolqYDLs2vXLmzatAmRkZH5ltvZ2WHgwIEYMmRImcIRERERERHRS6WaB64wX331FRYuXIiIiAiYmZmhRYsWaNasGapVq4YnT55gyZIlmD59uiqz4urVq3BwcMD+/fuLbTN8+HC4u7vD0dER/fr1w9GjR0vctq6uLu7fv49evXqpMjIREREREZHKSLoD5+vri0OHDsHOzg6LFy+Gs7NzvvWXL1/G119/DV9fX3Tu3Bldu3Ytc9BHjx5hypQpEEWxyDaHDx/G9OnToaWlBVdXV8jlcvj5+WHy5Ml4+PAhJkyYUOYcRERERERE6iKpgNuzZw90dXWxZcuWQifpdnNzw9atW/HBBx9gz549ZS7g/Pz8MHXqVMTFxRXZJjY2FrNnz4a+vj527tyJJk2aAABCQ0Ph7e2NNWvWoHPnzsrlqiYI5bLZMpHJBAgVMVgRZDLNyUpE6qVBf9qIiKgcVbTrwZvII6mAu3fvHpydnQst3vLY2dnBxcUFt2/flhwuLi4OK1euxN69eyGTyVCjRg2Eh4cX2nbXrl1IT0/HqFGj8hVp9erVw5QpUzBz5kz8/PPP5Tb1gZlZlXLZblmIoqhRBRwRUWkYGenByEhP3TGIiEjNKuv1QFIBl52dDX19/RLb6evrIz09XcouAADr1q3D7t27Ubt2bSxatAg+Pj44ePBgoW3Pnz8PAPD09CywztPTE7NmzcK5c+ckZylJXFwSiund+cbJ5TJUq2aI4OAApKQkqztOqVSvbgtb2zrqjkFEFVxycjrS07PUHYPKSd71i4ioJBXxeiAI5X9jR1IBV7NmTfj7+yMtLa3IQi41NRX+/v7F3qUriZ2dHebOnQsvLy9oa2vDx8en0HaiKOLhw4cAAHt7+wLrTUxMYG5ujpiYGERFRcHKykpypqKIIipUAZcnJSUZycmJ6o5RKhkZ0ot9IqpcKuLfWyIievMq4/VA0iiU3bp1Q3x8PL744ot8k2HnSUlJwbRp05CQkID33ntPcjhvb28MGDAA2traxbZ78eIFMjIyYGhoCAMDg0LbWFpaAsh9Vo6IiIiIiEgTSboDN3z4cBw9ehSnTp1Cp06d0KZNG9jY2AAAnj17hosXLyIpKQn29vYYNmyYSgMXJi0tDQCK7dapq6sLIPfOIBERERERkSaSVMDp6upix44dmD17Nk6ePIljx47lWy8IAjw9PTF//vwi74ipkkwmU+63JAqForzjEBERERERlQtJBRwAVK1aFStXrkR4eDiuXbuG6OhoiKIIS0tLtG7dGra2tqrMWSxDw9yHnYsbMCUjIwMA3khBSUREREREVB4kF3B5atSogY8//lgVWSQzNDSEoaEhkpKSkJ6eDj29gsOJRkdHA3j5LBwREREREZGmkTSISUUjCIJy9MnQ0NAC6xMSEhAbGwsTE5NyGYGSiIiIiIjoTXgrCjgA8PDwAACcOnWqwLpTp05BFEW0b9/+TcciIiIiIiJSmbemgOvduzf09fWxbds23LhxQ7n80aNHWLFiBQBg5MiRakpHRERERERUdmV+Bq6isLa2xqxZszB79mwMGjQIrq6u0NHRgZ+fHzIyMjB16lQ4ODioOyYREREREZFkb00BBwBeXl6wtrbGhg0bEBgYCLlcjsaNG2P48OHo0qWLuuOphYGBobojlJqOTsHBZ4iIiIiI6CVJBdzUqVNRp04djBs3TtV5irVkyRIsWbKk2DYeHh7K5+EqM5lMhhyFAk2aOKk7ChERERERqYikAu7s2bMIDw9/4wUclZ5cLkAuk+Hz37fhQVykuuOUSuc6jTHTo7u6YxARERERVViSCjgtLS0YGxurOguVgwdxkbgV/VTdMUrF3pRTPBARERERFUfSKJT9+/fHxYsXceLECVXnISIiIiIioiJIugNnamoKW1tbTJw4ERYWFmjYsCFMTEwgkxWsBwVBwNKlS8sclIiIiIiIqLKTVMB9++23yv+Pjo5GdHR0kW1ZwBEREREREalGmQs4IiIiIiIiejMkFXA9e/ZUdQ4iIiIiIiIqgUom8o6Li0NERAQMDQ1Rp04dpKWlQV9fXxWbJiIiokrIwMBQ3RFKRUdHT90RiKiSKVMB5+Pjgy1btuDx48cAgO7du2Pp0qUYM2YMqlSpgnnz5sHU1FQlQYmIiOjtJ5PJICpy0KSJk7qjEBFVSJILuBkzZuDQoUMQRRFmZmaIi4uDKIoAgPDwcPzzzz94+PAh9u3bByMjI5UFJiIioreXXC5AkMlx33cSUuMeqjtOiarV7Yja7aepOwYRVSKSCriDBw/i4MGDaNy4MRYtWoRGjRrBwcFBuX779u346quvcPnyZWzfvh1jxoxRWWAiIiJ6+6XGPURK1B11xyiRvmk9dUcgokpG0kTee/fuhYGBATZt2oRGjRoVWG9lZYXVq1fD2NgYx48fL3NIIiIiIiIikljA3b9/Hy4uLsU+32ZgYAAnJyeEhYVJDkdEREREREQvSSrgBEFAdnZ2ie3S0tKUz8URERERERFR2Ugq4OrVq4egoCAkJCQU2eb58+e4desW6tevLzUbERERERERvUJSAde7d28kJiZiypQpiIuLK7A+NjYWU6ZMQWpqKrp3717mkERERERERCRxFEovLy+cPXsW586dQ6dOnVC3bl0IggB/f38MHDgQd+/eRWpqKpydndGvXz9VZyYiIiIiIqqUJN2Bk8lkWL16NcaOHQtdXV3cu3cPoigiPDwc169fh0KhgLe3NzZt2gQtrTLNFU5ERERERET/klxdyeVyjB8/HqNHj0ZwcDDCw8OhUChgYWGBZs2aQV9fX5U5iYiIiIiIKr0y3x7T1tZGixYt0KJFC1XkISIiIiIioiKUqYALDw/Hr7/+iqtXryIqKgpaWlqoXr06XF1d0bt372LniSMiIiIiIqLXI7mA2717N5YsWYLMzMx8c709evQIly5dwubNm7Fs2TJ06NBBJUGJiIiIiIgqO0kF3MWLF/HNN99AS0sLAwcOROfOnWFtbQ0AePbsGY4fP44DBw5g/Pjx2Lt3Lxo1aqTS0ERERERERJWRpAJu06ZNkMlk2LBhA9q0aZNvXZ06ddCuXTu0a9cOEydOxMqVK7FmzRqVhCUiIiIiIqrMJE0jEBQUhNatWxco3l7VtWtXODo64tq1a5LDERERERER0UuS54EzNjYusZ2FhQVycnKk7IKIiIiIiIj+Q1IB16ZNG1y5cgXPnz8vsk1KSgr8/f3h7OwsORwRERERERG9JKmAmz59OvT19TF06FD4+/sXWB8eHo7Ro0dDoVDgyy+/LHNIIiIiIiIiKuUgJh07diywLC0tDTExMRg8eDAsLS1hY2MDXV1dREdH4/HjxxBFEXXq1MGiRYuwefNmVecmIiIiIiKqdEpVwEVGRha7PioqClFRUQWWP3r0CI8fP5aWjIiIiIiIiPIpVQF3+vTp8s5BREREREREJShVAWdjY1PeOYiIiIiIiKgEkgYxISIiIiIiojevVHfgCrNz507s3bsXT548QWZmZpHtBEFAcHCw1N0QERERERHRvyQVcLt378aiRYsgimKJbUvThoiIiIiIiEomqYDbtWsXZDIZZs+ejS5dusDY2BiCIKg6GxEREREREb1CUgEXFhYGNzc39OvXT9V5iIiIiIiIqAiSBjGxsrJi10giIiIiIqI3TFIB17t3b1y/fh2hoaGqzkNERERERERFkNSFcsSIEbh//z769++PgQMHomHDhjAxMSmyvbu7u+SARERERERElEtSAZeRkYGMjAwkJiZi3bp1xbblNAJERERERESqIamA+/7773Hy5EkIgoC6devC1NRU1bmIiIiIiIjoPyQVcMePH4eRkRG2b9+Oxo0bqzoTERERERERFULSICaJiYlwdnZm8UZERERERPQGSSrg6tati4SEBBVHISIiIiIiouJIKuC8vb0REBCAc+fOqTgOERERERERFUXSM3DNmjVDx44dMWbMGHTs2BEtWrSAiYkJtLQK31zv3r3LFJKIiIiIiIgkFnAffvghBEGAKIo4c+YMzp49W2x7FnBERERERERlJ6mA69GjBwRBUHUWIiIiIiIiKoakAm7JkiWqzkFEREREREQlkDSICREREREREb15ku7A+fn5vVZ7d3d3KbshIiIiIiKiV0gq4IYNG/Zaz8DdvXtXym6IiIiIiIjoFZIKOGdn50KXKxQKJCYm4vHjx8jOzkbnzp1Rt27dMgUkIiIiIiKiXJIKuB07dhS7PikpCbNnz4afnx9mzJghKRgRERERERHlVy6DmFSpUgXLli2DlpYWfvjhh/LYBRERERERUaVTbqNQ6ujowMnJCZcuXSqvXRAREREREVUqkrpQllZsbCzS0tLKcxdERERUAplMgExW+sHH1ElTchIRqUu5FHA5OTnYs2cPAgIC0KxZs/LYBREREZWCTCagWjUDyGSc+pWI6G0gqYDr2LFjketycnKQmJiIzMxMCIKAwYMHS81GREREZZR7902G4OAApKQkqztOiapXt4WtbR11xyAiqrAkFXCRkZEltrG2tsbIkSPRvXt3KbsgIiIiFUpJSUZycqK6Y5QoIyNd3RGIiCo0SQXc6dOni1wnk8lgYGAAExMTyaGIiIiIiIioIEkFnI2NjapzEBERERERUQlUNoiJQqEoch0fnCYiIiIiIio7yQXcyZMnsWHDBoSEhCAjI6PIdoIgIDg4WOpuiIiIiIiI6F+SCrizZ89iwoQJEEWxxLalaUNEREREREQlk1TAbdy4EaIoYtiwYfD29oalpSXkcrmqsxEREREREdErJBVwd+/eRaNGjfDll1+qOg8REREREREVQdLoItra2rC1tVV1FiIiIiIiIiqGpAKuefPmuHPnDnJyclSdh4iIiIiIiIogqYCbMGECoqOj8d133xU7fQARERERERGpjqRn4AIDA+Hh4YFt27bB19cXTZo0gbGxMQRBKNBWEAQsXbq0zEGJiIiIiIgqO0kF3OLFiyEIAkRRRGxsLM6fP19kWxZwREREREREqiGpgPv2229VnYOIiIiIiIhKIKmA69mzp6pzEBERERERUQkkDWJCREREREREbx4LOCIiIiIiIg3BAo6IiIiIiEhDsIAjIiIiIiLSECzgiIiIiIiINESlLuCysrLwww8/oEOHDnB0dMTo0aPx9OlTdcciIiIiIiIqlKQCLjg4uFTtcnJysGrVKim7eCP+97//4ZdffsHYsWPx448/4sWLFxgyZAjS0tLUHY2IiIiIiKgASQVc3759sXHjxmLbPHz4EF5eXli9erWkYOUtNTUVe/bswfjx49GnTx+0b98e33//PZ49e4a//vpL3fGIiIiIiIgKkNyFcvny5Rg8eDAiIyPzLRdFERs3bkSvXr0QHByMWrVqlTlkedDV1cXevXvx8ccfK5dpa2sDADIzM9UVi4iIiIiIqEiSCrgDBw7AwcEB165dQ/fu3XHkyBEAwN9//43+/ftj+fLlUCgUGD16NA4fPqzSwKoil8vRqFEjmJiYICcnB48ePcKsWbNgZWWF9u3bqzseERERERFRAVpSXmRvb4/9+/dj1apV2LRpE7744gscOHAAAQEBSEtLQ8uWLTF//nw0aNBA1XnLxffff4/NmzdDJpNh2bJlqFKlirojERERERERFSCpgAMALS0tTJo0CS4uLvj000/h5+cHAOjWrRuWL1+usoBvQvfu3dGh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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import seaborn as sns\n", - "import matplotlib.pyplot as plt\n", - "import random\n", - "\n", - "for i in range(0,10):\n", - " df_melt = df.melt(id_vars=['benchmark', 'Task group', 'agent'], \n", - " value_vars=['max DOM k-tokens', 'max Pruned DOM k-tokens', 'max AXTree k-tokens', 'episode DOM k-tokens', 'episode Pruned DOM k-tokens', 'episode AXTree k-tokens'], \n", - " var_name='experience', value_name='value')\n", - " #take all value and multiply by 1000\n", - " df_melt['value'] = df_melt['value'] * 1000\n", - "\n", - " df_melt[['type', 'obs']] = df_melt['experience'].str.split(' ', n=1, expand=True)\n", - " #drop columns\n", - " df_melt = df_melt.drop(columns=['experience'])\n", - " #rearraange columns\n", - " df_melt = df_melt[['benchmark', 'Task group', 'agent', 'type', 'obs', 'value']]\n", - " sorted_obs = df_melt.groupby('obs')['value'].mean().sort_values().index\n", - "\n", - " print(df_melt.head())\n", - "\n", - " #drop lines where obs contains 'pruned'\n", - " df_melt = df_melt[~df_melt['obs'].str.contains('Pruned')]\n", - "\n", - " #keeping only max \n", - " df_melt = df_melt.loc[df_melt['type'] == 'max']\n", - " #df_melt = df_melt.loc[df_melt['agent'] == 'base_agent']\n", - " df_melt['Task group'] = df_melt['benchmark'] + ' ' + df_melt['Task group']\n", - " #remove lines where task group = \"workarena [ALL TASKS]\"\n", - " df_melt = df_melt[df_melt['Task group'] != \"workarena [ALL TASKS]\"]\n", - " # Create the bar plot\n", - " # Create a sorted list of 'obs' values based on the mean 'value'\n", - "\n", - " # Change the order of 'obs' in df_melt based on sorted_obs\n", - " sns.set_style(\"darkgrid\")\n", - " np.random.seed(random.randint(0, 100))\n", - "\n", - " # Create a color palette with a random seed\n", - " palette = sns.color_palette('colorblind', n_colors=len(df_melt['Task group'].unique()))\n", - " random.shuffle(palette)\n", - " palette_grey = sns.color_palette('grey', n_colors=1)\n", - " print(df_melt.head())\n", - " # Sort df_melt by 'obs'\n", - " sorted_task_group = df_melt.groupby(['Task group'])['value'].mean().sort_values().index.get_level_values('Task group')\n", - " figure = plt.figure(figsize=(10, 5))\n", - " df_b = df_melt.loc[df_melt['agent'] == 'base_agent']\n", - " sns.barplot(x='obs', y='value', hue='Task group', hue_order=sorted_task_group, data=df_b, order=None, palette=palette, ci=None)\n", - "\n", - " # Create the bar plot with sorted 'obs' categories\n", - " df_f = df_melt.loc[df_melt['agent'] == 'full_agent']\n", - " sns.barplot(x='obs', y='value', hue='Task group', hue_order=sorted_task_group, data=df_f, order=None, palette=[(0.75, 0.75, 0.7)], ci=None)\n", - "\n", - " df_b = df_melt.loc[df_melt['agent'] == 'base_agent']\n", - " sns.barplot(x='obs', y='value', hue='Task group', hue_order=sorted_task_group, data=df_b, order=None, palette=palette, ci=None)\n", - "\n", - " plt.ylabel('Max number of token per step (log scale)', fontsize=16)\n", - " plt.xlabel('')\n", - " #custom x tick labels\n", - " plt.xticks([0, 1], ['Document Object Model', 'Accessibility Tree'] , fontsize=16)\n", - " plt.yticks(fontsize=16)\n", - "\n", - " #y axis log\n", - " plt.yscale('log')\n", - "\n", - " #put legend on top two rows aligned legend word on the right\n", - "\n", - " legend1 = plt.legend(loc='upper center', fontsize=16, bbox_to_anchor=(0.5, 1.24), ncol=4, labels=[\"MiniWoB\", \"knowledge\", \"menu\", \"service catalog\",\"list-sort\" , \"form\", \"list-filter\"])\n", - "\n", - " plt.savefig(f'wa_complexity_{i}.pdf', dpi=300, bbox_inches='tight')\n", - " plt.savefig(f'wa_complexity_{i}.png', dpi=300, bbox_inches='tight')\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 351, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\Tom\\AppData\\Local\\Temp\\ipykernel_38828\\25016155.py:4: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap(obj)`` instead.\n", - " cmap = cm.get_cmap('viridis') # Replace 'viridis' with any colormap you like\n" - ] - }, - { - "ename": "ValueError", - "evalue": "shape mismatch: objects cannot be broadcast to a single shape. Mismatch is between arg 0 with shape (16,) and arg 1 with shape (4,).", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[351], line 15\u001b[0m\n\u001b[0;32m 13\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, label \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(labels):\n\u001b[0;32m 14\u001b[0m color \u001b[38;5;241m=\u001b[39m color_dict[label]\n\u001b[1;32m---> 15\u001b[0m rects1 \u001b[38;5;241m=\u001b[39m \u001b[43max\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbar\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m10\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mwidth\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mi\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mwidth\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mgroup1_sorted\u001b[49m\u001b[43m[\u001b[49m\u001b[43mgroup1_sorted\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m[\u001b[49m\u001b[43mgroup1_sorted\u001b[49m\u001b[43m[\u001b[49m\u001b[43mgroup1_sorted\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m==\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mlabel\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mwidth\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcolor\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcolor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlabel\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mlabel\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 16\u001b[0m rects2 \u001b[38;5;241m=\u001b[39m ax\u001b[38;5;241m.\u001b[39mbar(x \u001b[38;5;241m+\u001b[39m \u001b[38;5;241m10\u001b[39m\u001b[38;5;241m*\u001b[39mwidth \u001b[38;5;241m+\u001b[39m i\u001b[38;5;241m*\u001b[39mwidth, group1_sorted[group1_sorted\u001b[38;5;241m.\u001b[39mcolumns[\u001b[38;5;241m4\u001b[39m]][group1_sorted[group1_sorted\u001b[38;5;241m.\u001b[39mcolumns[\u001b[38;5;241m1\u001b[39m]] \u001b[38;5;241m==\u001b[39m label], width, color\u001b[38;5;241m=\u001b[39mcolor, label\u001b[38;5;241m=\u001b[39mlabel)\n\u001b[0;32m 18\u001b[0m \u001b[38;5;66;03m# Display the legend\u001b[39;00m\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\matplotlib\\__init__.py:1478\u001b[0m, in \u001b[0;36m_preprocess_data..inner\u001b[1;34m(ax, data, *args, **kwargs)\u001b[0m\n\u001b[0;32m 1475\u001b[0m \u001b[38;5;129m@functools\u001b[39m\u001b[38;5;241m.\u001b[39mwraps(func)\n\u001b[0;32m 1476\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minner\u001b[39m(ax, \u001b[38;5;241m*\u001b[39margs, data\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[0;32m 1477\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m data \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m-> 1478\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[43max\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mmap\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43msanitize_sequence\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1480\u001b[0m bound \u001b[38;5;241m=\u001b[39m new_sig\u001b[38;5;241m.\u001b[39mbind(ax, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m 1481\u001b[0m auto_label \u001b[38;5;241m=\u001b[39m (bound\u001b[38;5;241m.\u001b[39marguments\u001b[38;5;241m.\u001b[39mget(label_namer)\n\u001b[0;32m 1482\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m bound\u001b[38;5;241m.\u001b[39mkwargs\u001b[38;5;241m.\u001b[39mget(label_namer))\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\matplotlib\\axes\\_axes.py:2457\u001b[0m, in \u001b[0;36mAxes.bar\u001b[1;34m(self, x, height, width, bottom, align, **kwargs)\u001b[0m\n\u001b[0;32m 2454\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m yerr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m 2455\u001b[0m yerr \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_convert_dx(yerr, y0, y, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconvert_yunits)\n\u001b[1;32m-> 2457\u001b[0m x, height, width, y, linewidth, hatch \u001b[38;5;241m=\u001b[39m \u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbroadcast_arrays\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 2458\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# Make args iterable too.\u001b[39;49;00m\n\u001b[0;32m 2459\u001b[0m \u001b[43m \u001b[49m\u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43matleast_1d\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheight\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mwidth\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43my\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlinewidth\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mhatch\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 2461\u001b[0m \u001b[38;5;66;03m# Now that units have been converted, set the tick locations.\u001b[39;00m\n\u001b[0;32m 2462\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m orientation \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mvertical\u001b[39m\u001b[38;5;124m'\u001b[39m:\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\numpy\\lib\\stride_tricks.py:540\u001b[0m, in \u001b[0;36mbroadcast_arrays\u001b[1;34m(subok, *args)\u001b[0m\n\u001b[0;32m 533\u001b[0m \u001b[38;5;66;03m# nditer is not used here to avoid the limit of 32 arrays.\u001b[39;00m\n\u001b[0;32m 534\u001b[0m \u001b[38;5;66;03m# Otherwise, something like the following one-liner would suffice:\u001b[39;00m\n\u001b[0;32m 535\u001b[0m \u001b[38;5;66;03m# return np.nditer(args, flags=['multi_index', 'zerosize_ok'],\u001b[39;00m\n\u001b[0;32m 536\u001b[0m \u001b[38;5;66;03m# order='C').itviews\u001b[39;00m\n\u001b[0;32m 538\u001b[0m args \u001b[38;5;241m=\u001b[39m [np\u001b[38;5;241m.\u001b[39marray(_m, copy\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m, subok\u001b[38;5;241m=\u001b[39msubok) \u001b[38;5;28;01mfor\u001b[39;00m _m \u001b[38;5;129;01min\u001b[39;00m args]\n\u001b[1;32m--> 540\u001b[0m shape \u001b[38;5;241m=\u001b[39m \u001b[43m_broadcast_shape\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 542\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mall\u001b[39m(array\u001b[38;5;241m.\u001b[39mshape \u001b[38;5;241m==\u001b[39m shape \u001b[38;5;28;01mfor\u001b[39;00m array \u001b[38;5;129;01min\u001b[39;00m args):\n\u001b[0;32m 543\u001b[0m \u001b[38;5;66;03m# Common case where nothing needs to be broadcasted.\u001b[39;00m\n\u001b[0;32m 544\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m args\n", - "File \u001b[1;32mc:\\Users\\Tom\\miniconda3\\envs\\ui-copilot\\Lib\\site-packages\\numpy\\lib\\stride_tricks.py:422\u001b[0m, in \u001b[0;36m_broadcast_shape\u001b[1;34m(*args)\u001b[0m\n\u001b[0;32m 417\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Returns the shape of the arrays that would result from broadcasting the\u001b[39;00m\n\u001b[0;32m 418\u001b[0m \u001b[38;5;124;03msupplied arrays against each other.\u001b[39;00m\n\u001b[0;32m 419\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 420\u001b[0m \u001b[38;5;66;03m# use the old-iterator because np.nditer does not handle size 0 arrays\u001b[39;00m\n\u001b[0;32m 421\u001b[0m \u001b[38;5;66;03m# consistently\u001b[39;00m\n\u001b[1;32m--> 422\u001b[0m b \u001b[38;5;241m=\u001b[39m \u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbroadcast\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m[\u001b[49m\u001b[43m:\u001b[49m\u001b[38;5;241;43m32\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 423\u001b[0m \u001b[38;5;66;03m# unfortunately, it cannot handle 32 or more arguments directly\u001b[39;00m\n\u001b[0;32m 424\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m pos \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m32\u001b[39m, \u001b[38;5;28mlen\u001b[39m(args), \u001b[38;5;241m31\u001b[39m):\n\u001b[0;32m 425\u001b[0m \u001b[38;5;66;03m# ironically, np.broadcast does not properly handle np.broadcast\u001b[39;00m\n\u001b[0;32m 426\u001b[0m \u001b[38;5;66;03m# objects (it treats them as scalars)\u001b[39;00m\n\u001b[0;32m 427\u001b[0m \u001b[38;5;66;03m# use broadcasting to avoid allocating the full array\u001b[39;00m\n", - "\u001b[1;31mValueError\u001b[0m: shape mismatch: objects cannot be broadcast to a single shape. Mismatch is between arg 0 with shape (16,) and arg 1 with shape (4,)." - ] - }, - { - "data": { - "image/png": "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Bx98MLq6uooyOAAw9uUKla6urti5c2ds3LgxamtrY8GCBbFmzZrYsWPHsHN3794dkyZNioceeihuuOGG2LhxY3zyk5/8P6MGAOD/Upbn5CNHjkR/f3/U19cPHmtoaIhnn302BgYGorT0f7vn0KFD0dDQECUlJRERUVJSEvPmzYuDBw/G8uXLL/ljlpRElHomzaj6cIVRWhqRZaM7y3hnF2mxj3TYRTou7KJYcoVKoVCIadOmxcSJEwePVVVVRW9vb5w5cyYqKiqGnDtr1qwh16+srIz29vZcA1ZUXJPrfK4eu0iHXaTFPtJhF2NPrvsquru7h0RKRAxe7uvru6RzP3oeAMDF5AqVSZMmDQuNC5fLy8sv6dyPngcAcDG5QqW6ujo6Ozujv79/8FihUIjy8vKYOnXqsHM7OjqGHOvo6Ijp06dfwbgAwHiSK1RqamqirKwsDh48OHispaUl5syZM+SJtBERdXV18fbbb0f24bOasiyLt956K+rq6q58agBgXMgVKpMnT46lS5dGU1NTtLa2xr59+6K5uTlWrVoVEefvXenp6YmIiIULF8YHH3wQW7ZsiWPHjsWWLVuiu7s7Fi1aVPzPAgAYk0qyLN8Lubq7u6OpqSn27t0bU6ZMidWrV8eXvvSliIi48cYb4/HHHx98+XFra2ts3rw53n333bjxxhvjkUceiZtvvrnonwQAMDblDhUAgJHin1IDAJIlVACAZAkVACBZoxoqvb29sWHDhpg/f340NjZGc3PzRc9955134u677466urq46667oq2tbQQnHfvy7OL111+PJUuWRH19fSxevDh+9KMfjeCkY1+eXVzwq1/9Kurr6+PNN98cgQnHlzz7OHr0aKxcuTLmzp0bixcvjjfeeGMEJx378uzihz/8YSxatCjq6+tj5cqVcfjw4RGcdPzo6+uLO++882N/91zx7Xc2ih599NFs8eLFWVtbW7Z3796svr4+e+2114add+7cuezWW2/NnnjiiezYsWPZY489ln3xi1/Mzp07NwpTj02Xuouf//znWW1tbbZ9+/bsl7/8ZfbCCy9ktbW12c9//vNRmHpsutRd/LbVq1dns2fPzt54440RmnL8uNR9fPDBB9kXv/jF7O///u+zX/7yl9nTTz+dNTQ0ZB0dHaMw9dh0qbv4z//8z2zOnDnZyy+/nB0/fjx75JFHsltvvTXr6uoahanHrp6enuyv//qvP/Z3TzFuv0ctVM6dO5fNmTNnyCf3T//0T9mf/dmfDTt3586d2R/+4R9mAwMDWZZl2cDAQLZgwYJs165dIzbvWJZnF08++WS2evXqIce+/OUvZ//4j/941eccD/Ls4oJXX301W7FihVC5CvLsY/v27dkf/dEfZf39/YPHli9fnr3++usjMutYl2cX3/3ud7Nly5YNXj579mw2e/bsrLW1dURmHQ/a29uzP/mTP8kWL178sb97inH7PWoP/Rw5ciT6+/ujvr5+8FhDQ0McOnQoBgYGhpx76NChaGhoiJIP/3Z0SUlJzJs3b8i/kMvly7OLZcuWxd/+7d8Oex9nz5696nOOB3l2ERHR2dkZTz75ZDz66KMjOea4kWcfBw4ciNtuuy0mTJgweGzXrl3xB3/wByM271iWZxef/vSn49ixY9HS0hIDAwPx0ksvxZQpU+K6664b6bHHrAMHDsQXvvCF+P73v/+x5xXj9rvsSga9EoVCIaZNmzbkLyxXVVVFb29vnDlzJioqKoacO2vWrCHXr6ysjPb29hGbdyzLs4sbbrhhyHXb29vjZz/7WaxYsWLE5h3L8uwiIuKJJ56IZcuWxec+97mRHnVcyLOPEydOxNy5c+Mb3/hG7N+/P2bMmBEPP/xwNDQ0jMboY06eXdxxxx2xf//+uPfee2PChAlRWloa27Zti0996lOjMfqYdO+9917SecW4/R61e1S6u7uHfMNFxODlj/7V5Yud+9HzuDx5dvHbTp8+HWvXro158+bFbbfddlVnHC/y7OKnP/1ptLS0xF/91V+N2HzjTZ59dHV1xXPPPRfXXnttPP/88/F7v/d7sXr16vj1r389YvOOZXl20dnZGYVCITZt2hQvvvhiLFmyJNavXx+nTp0asXk5rxi336MWKpMmTRo26IXL5eXll3TuR8/j8uTZxQUdHR1x//33R5Zl8e1vf3vYH6Xk8lzqLnp6emLTpk2xefNmPwdXUZ6fjQkTJkRNTU2sW7cubr755vi7v/u7uP766+PVV18dsXnHsjy7eOqpp2L27Nlx3333xec///l47LHHYvLkybFr164Rm5fzinH7PWq3LtXV1dHZ2Rn9/f2DxwqFQpSXl8fUqVOHndvR0THkWEdHR0yfPn1EZh3r8uwiIuI3v/lN3HfffdHX1xff+973hj0cweW71F20trbGiRMnYt26dVFfXz/4uP1XvvKV2LRp04jPPVbl+dm49tpr47Of/eyQY9dff717VIokzy4OHz4cN9100+Dl0tLSuOmmm+LkyZMjNi/nFeP2e9RCpaamJsrKyoY8oaalpSXmzJkz7P/O6+rq4u23347swz9LlGVZvPXWW1FXVzeSI49ZeXbR1dUVa9asidLS0njhhReiurp6hKcd2y51F3Pnzo29e/fGK6+8MvgWEfHNb34zvva1r43w1GNXnp+NW265JY4ePTrk2C9+8YuYMWPGSIw65uXZxfTp0+Pdd98dcuy9996Lz3zmMyMxKr+lGLffoxYqkydPjqVLl0ZTU1O0trbGvn37orm5OVatWhUR50u5p6cnIiIWLlwYH3zwQWzZsiWOHTsWW7Zsie7u7li0aNFojT+m5NnFtm3b4v33349vfetbg/+tUCh41U+RXOouysvLY+bMmUPeIs7/30tlZeVofgpjSp6fjRUrVsTRo0fjO9/5Thw/fjyefvrpOHHiRCxZsmQ0P4UxI88u7rnnnnjxxRfjlVdeiePHj8dTTz0VJ0+ejGXLlo3mpzBuFP32+0pfS30lurq6soceeii75ZZbssbGxuy73/3u4H+bPXv2kNdZHzp0KFu6dGk2Z86c7E//9E+zw4cPj8LEY9el7uKP//iPs9mzZw97e/jhh0dp8rEnz8/Fb/PvqFwdefbxH//xH9myZcuyz3/+89mSJUuyAwcOjMLEY1eeXbz44ovZwoULs1tuuSVbuXJl1tbWNgoTjw8f/d1T7Nvvkiz78P4YAIDEeKkGAJAsoQIAJEuoAADJEioAQLKECgCQLKECACRLqAAAyRIqAECyhAoAkCyhAgAkS6gAAMn6f2DRo1woHAopAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots()\n", - "labels = group1[group1.columns[1]].unique()\n", - "\n", - "cmap = cm.get_cmap('viridis') # Replace 'viridis' with any colormap you like\n", - "\n", - "# Create a normalized range of colors\n", - "colors = cmap(np.linspace(0, 1, len(labels)))\n", - "\n", - "# Create a dictionary that maps labels to colors\n", - "color_dict = dict(zip(labels, colors))\n", - "\n", - "# Create the bars with sorted data\n", - "for i, label in enumerate(labels):\n", - " color = color_dict[label]\n", - " rects1 = ax.bar(x - 10*width + i*width, group1_sorted[group1_sorted.columns[2]][group1_sorted[group1_sorted.columns[1]] == label], width, color=color, label=label)\n", - " rects2 = ax.bar(x + 10*width + i*width, group1_sorted[group1_sorted.columns[4]][group1_sorted[group1_sorted.columns[1]] == label], width, color=color, label=label)\n", - "\n", - "# Display the legend\n", - "ax.legend()" - ] - }, - { - "cell_type": "code", - "execution_count": 104, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "benchmark\n", - "miniwob [ALL TASKS]\n", - "miniwob [ALL TASKS]\n", - "workarena form\n", - "workarena knowledge\n", - "workarena list-filter\n", - "workarena list-sort\n", - "workarena menu\n", - "workarena service catalog\n", - "workarena [ALL TASKS]\n", - "workarena form\n", - "workarena knowledge\n", - "workarena list-filter\n", - "workarena list-sort\n", - "workarena menu\n", - "workarena service catalog\n", - "workarena [ALL TASKS]\n", - "Name: Task group, dtype: object" - ] - }, - "execution_count": 104, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Split the dataframe into three groups\n", - "group1 = df[[df.columns[0], df.columns[1], df.columns[2], df.columns[3], df.columns[4], df.columns[8]]]\n", - "group2 = df[[df.columns[0], df.columns[1], df.columns[5], df.columns[6], df.columns[7], df.columns[8]]]\n", - "\n", - "# Sort the data by the desired column\n", - "group1_sorted = group1.sort_values(by=group1.columns[2])\n", - "\n", - "# Create positions for the bars\n", - "x = np.arange(len(group1_sorted[group1_sorted.columns[1]]))\n", - "\n", - "# Plotting group1\n", - "fig, ax = plt.subplots()\n", - "\n", - "\n", - "# Create the bars with sorted data\n", - "import pandas as pd\n", - "\n", - "# Reshape the data\n", - "group1_sorted_melt = pd.melt(group1_sorted, id_vars=[group1_sorted.columns[0], group1_sorted.columns[5]], \n", - " value_vars=[group1_sorted.columns[2], group1_sorted.columns[4]], \n", - " var_name='variable', value_name='value')\n", - "\n", - "# Create the bar plot\n", - "sns.barplot(x=group1_sorted_melt[group1_sorted.columns[5]], y='value', hue='value', data=group1_sorted_melt, palette='colorblind')\n", - "# Display the legend\n", - "handles, _ = ax.get_legend_handles_labels()\n", - "ax.legend(handles, labels.unique(), title='Labels')\n", - "\n", - "# Add labels and title\n", - "ax.set_ylabel('Count')\n", - "ax.set_title('Group 1 Bar Plot')\n", - "ax.set_xticklabels(group1[group1.columns[1]])\n", - "\n", - "# Display the plot\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 103, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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j3N8WbeROR+O+FTSjBkzdPvtt5e6t0JkZKTGjh2rJUuW6Oabb5Z08gvizHtdhIWFKTIyUpL0888/lxofFRWlevXqlbueffv2aeHChfroo49K1TR06FD1799fBw4c0FdffaX33ntPAwcOVExMjIwxWrhwoT7++GPnB+GZHnvsMXl4eGjw4MEqKSnRXXfdpfHjx+vo0aPq1auXoqKidOjQIb3yyisqKipyObJ0oerWrauRI0dqzJgxCg0NVZMmTfTiiy/q6NGjGj58eJWtp6rExMTo888/V0JCgjw9Pct1j5UrrrhC/fr104gRI/TXv/5VgYGBevTRR3XppZeqX79+zukSEhL00EMPqV27ds4jKNddd51mz56tMWPGnHX5gwcP1ksvvaR+/fppwoQJaty4sX744Qd9+OGHevjhh9W4cWPdf//9ev7553XFFVfoyiuv1JQpU3To0CHnMgIDA5WUlOR8HRo0aKBx48apTp06zv+yY2JiNHjwYA0dOlSTJ09W27ZttW/fPmVmZqpVq1bO/eFsTv3D0KFDB/n7++udd96Rn5+foqKiJJ0M1itWrNDAgQPl4+Oj+vXrn7dtyys6Olpff/21tm/f7jwVmJycrOnTp+uuu+5yXvWTm5ur9957T2+99dY5Q0FVqYo2OXbsmMaMGaPbb79dl112mX766SdlZWXptttukyQ99NBDio+P18SJEzVgwACtXr1ar7322nmvBGrQoIH8/Py0ZMkSNW7cWL6+vs5batQEVfH6+fn56ZprrtHzzz+v/Px8ZWZm6quvvpIkrVy5Uvv27VOLFi0kSU899ZRGjx6t4OBg3XTTTSosLNSaNWt08OBBpaamnnM91113nRo2bKjBgwfrsssuK3W05nQpKSl69dVXNXDgQI0dO1bBwcH617/+pfbt26t58+YVrsPX11ePPPKIHn74YXl7e6tTp07at2+fNm7cqOHDh+uKK67Qjz/+qPfee0/x8fFavHix5s+f77KM6Ohobdu2TdnZ2WrcuLHzCruioiK9+uqr6tOnj1atWqVp06adsx3GjBmjO++8U23btlViYqIWLlyoDz/80Hnblu7du6tZs2ZKSkrSiy++qMOHD+vxxx+XpHNe1VhKuXsDWezMjo9r1qxxXjVSlp49e5r+/fsbY052opRU6jF8+HBjzMlOg2WN//vf/37Oms7sTDZp0iQTEhJSZoe3wsJCExISYv7yl7+YrVu3mhEjRpiYmBjj5+dnQkJCTHx8vMsVHGfrtPjCCy8YDw8PM3v2bLNs2TJz2223mcjISOPt7W3Cw8PNTTfdZFauXHne9juf0zs3G2PMsWPHzKhRo0z9+vWNj4+P6dSpk0vbn+rcfPDgwfOut6zOoKpgx7iynLmunJwc06BBA5OamlpmB/f777/fpSP8gQMHzN13322Cg4ONn5+f6dGjh8uVUMb8r9PuqY6XxpxsK0lmyZIl59ymXbt2maFDhzrbsGnTpmbEiBEmLy/PGHOyM/P9999vgoKCTEhIiElNTTVDhw51qTs/P98MGjTI+Pv7m4YNG5opU6aY9u3bm0cffdQ5zfHjx82TTz5poqOjjZeXl4mIiDD9+/c33377bZltdfrrMX/+fNOhQwcTFBRk6tata6655hqTkZHhnG/16tWmVatWxsfHx5zro6synZs3b95srrnmGuPn5+cy75YtW0z//v1NSEiI8fPzM1deeaV54IEHnB3FK/rePpvqbJPCwkIzcOBA577aqFEjk5KSYo4dO+acZt68eSY2NtZ4eXmZJk2amJdeesllGWfrRD19+nQTGRlp6tSpU+rCjqpWmf25Mq9fv379TFJSkvN5Tk6O6dixo/Hx8TGBgYEmODjYSDKRkZHm1VdfdZl39uzZpk2bNsbb29vUq1fPXHfddebDDz80xpy/M/jDDz9sJJknn3zSZXhZ861fv97ceOONxt/f3wQGBpouXbqYrVu3lquOshQXF5unn37aREVFOd8Dzz77rHP8mDFjTFhYmAkICDADBgwwL7/8skun5F9//dXcdtttJiQkxEhyfp9MmTLFREREOD/T3n77bZfP6jM7NxtjzOuvv26aNm1qvLy8TExMTKkrpTdt2mQ6depkvL29zZVXXmkWLlxY5mfguTiMOeNmHSglISFBbdq04TbylUT7/TYVFBTo0ksv1eTJk2vk0TcAv32rVq1S586dlZubq2bNmpVrHvr4lNPrr7+ugICAUlc+4exmz56tgIAArVy50t2loAr8+9//1rvvvqutW7dq3bp1zn4Ip5+OA4DqNH/+fC1dulTbt29XRkaG7rvvPnXq1KncoUeij0+5zJ4923lH5iZNmri5mtqjb9++znPV7vghOlS9SZMmafPmzfL29lZcXJxWrlxZpX1tAOBcDh8+rEceeUQ//vij6tevr8TExPNeYXYmTnUBAABrcKoLAABYg+ADAACsQfABAADWIPgAAABrEHwAAIA1CD4AAMAaBB8AAGANgg8AALDG/wNiKio7uZhuewAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Group 1 plot\n", - "fig, ax = plt.subplots()\n", - "\n", - "ax.set_yscale('log') # Apply log scale on y-axis\n", - "plt.title('Max')\n", - "plt.ylabel('Count')\n", - "plt.show()\n", - "\n", - "# Add spacing between plots\n", - "plt.subplots_adjust(hspace=0.5)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 98, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAICCAYAAAAu4dIrAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAABj50lEQVR4nO3deVxN+f8H8Ndt30ulEqkQslOYbGU0tuxmbFmGBkMh2WesMdOMNUm2QZZsM2OZLzO2kC1bhMEkRAbVzKBkqdTn94dH5+dqkbTcOq/n43Ee434+n3Nen3PL3LezXYUQQoCIiIhIxtRKewJEREREpY0FEREREckeCyIiIiKSPRZEREREJHssiIiIiEj2WBARERGR7LEgIiIiItljQURERESyx4KIiIiIZI8FERGVG25ubnBzcyvtaais2bNnQ6FQ4N9//y2V/GPHjkGhUOCXX34plXyi/LAgInpLaGgoFAoFFAoFTp48maNfCAEbGxsoFAp06dKlxOfn5uYmzU9NTQ1GRkaoVasWBg0ahEOHDuW5XkZGBoKCgtC0aVMYGhrCwMAATZs2RVBQEDIyMnKMt7Ozg0KhgLu7e67bW7NmjTSPCxcuFNn+lbTMzExYW1tDoVDgjz/+yNEvhEDr1q1RsWJF/Pfffzn6v/76a2hqaiI6Olp6P963HDt2rAT2rHiEhIQgNDS0tKdBVCw0SnsCRKpIR0cHW7ZsQatWrZTaIyIi8Pfff0NbW7uUZgZUqVIFAQEBAIDnz5/j1q1b2LlzJzZv3ow+ffpg8+bN0NTUlMY/f/4cHh4eiIiIQJcuXfDll19CTU0N+/fvx7hx47Bz507s27cP+vr6Sjk6Ojo4evQoEhISYGVlpdQXFhYGHR0dvHr1qvh3uBgdOXIEjx49gp2dHcLCwtCpUyelfoVCgVWrVqFRo0aYOHEi1q9fL/VFRkZi9erV8PPzQ6NGjbBp0yaldTdu3IhDhw7laHd0dCy+HSpmISEhMDc3x5dfflnaUyEqeoKIJOvXrxcARK9evYS5ubnIyMhQ6h8+fLhwcnIStra2wsPDo8Tn5+rqKurWrZuj/fXr12L06NECgJg8ebJS34gRIwQAsWzZshzrBQcHCwDi66+/Vmq3tbUV7dq1E0ZGRiIwMFCp7/79+0JNTU307t1bABDnz58vgj0rGq6ursLV1bXA4wcPHiyaNGkili5dKvT19UVqamqu47755hsBQBw7dkwIIUR6erqoV6+eqFq1ap7reHt7i4L8L/b58+cFnu/HmjVrlgAg/vnnn0KtX7du3Q96f9919OhRAUD8/PPPhd4GUXHhKTOiXPTv3x///fef0mmo9PR0/PLLLxgwYECu6yxcuBAtWrSAmZkZdHV14eTklONaifXr10OhUGDdunVK7d9//z0UCgV+//33Qs1XXV0dQUFBqFOnDoKDg5GcnAwA+Pvvv7F27Vp8+umn8PHxybGet7c32rZti59++gl///23Up+Ojg569eqFLVu2KLVv3boVFSpUQIcOHQo0t8ePH2PixImoX78+DAwMYGRkhE6dOuHy5ctK47KvL9mxYwe+++47VKlSBTo6OmjXrh1u3bqVY7urV69G9erVoauri2bNmuHEiRMFmk+2ly9fYteuXejXrx/69OmDly9fYs+ePbmOnTFjBqpXr46RI0ciPT0dixYtwp9//ong4OAcR9by4+bmhnr16iEqKgpt2rSBnp4evvnmGwBAWloaZs2ahRo1akBbWxs2NjaYPHky0tLScmxn8+bNcHJygq6uLkxNTdGvXz/cv3//g/Y/271791CjRg3Uq1cPiYmJeY6zs7PDtWvXEBERIZ3+e/t6rTt37uCLL76Aqakp9PT08Mknn2Dfvn3vzU9LS0OXLl1gbGyM06dPAwCysrIQGBiIunXrQkdHB5aWlhg5ciSePHmSY05dunTByZMn0axZM+jo6KBatWrYuHGj0riMjAzMmTMHDg4O0NHRgZmZGVq1apXvaWaSodKuyIhUSfYRovPnz4sWLVqIQYMGSX27d+8Wampq4sGDB7keIapSpYoYPXq0CA4OFosXLxbNmjUTAMTevXuVxnXp0kUYGxuL+Ph4IYQQV65cEVpaWsLLy+u988vrCFG2uXPnKmWuXr1aABChoaHv3ec1a9ZIbdn7d/DgQQFA3Lp1S+pr1KiRGDlypNJ7lZ/z58+L6tWri6lTp4pVq1YJf39/UblyZWFsbCwePHggjcs+etC4cWPh5OQklixZImbPni309PREs2bNlLb5008/CQCiRYsWIigoSPj6+goTExNRrVq1Ah/B2LZtm1AoFNLP4dNPPxWdO3fOc/yBAwcEAOHl5SV0dXVFz549891+bkeIXF1dhZWVlahYsaIYM2aMWLVqldi9e7fIzMwU7du3F3p6esLX11esWrVK+Pj4CA0NDdG9e3elbcybN08oFArRt29fERISIubMmSPMzc2FnZ2dePLkSb5zevcI0a1bt0TVqlVFo0aN3nvUaNeuXaJKlSqidu3aYtOmTWLTpk3i4MGDQgghEhIShKWlpTA0NBTffvutWLx4sWjYsKFQU1MTO3fulLbx7hGiFy9eiM8++0xUqFBBnDt3Thr31VdfCQ0NDTF8+HCxcuVKMWXKFKGvry+aNm0q0tPTpXG2traiVq1awtLSUnzzzTciODhYNGnSRCgUCvHnn39K47755huhUCjE8OHDxZo1a8SiRYtE//79xQ8//JDvPpO8sCAiesvbH/LBwcHC0NBQvHjxQgghxBdffCHatm0rhBC5FkTZ47Jln1b59NNPldofPXokTE1NxWeffSbS0tJE48aNRdWqVUVycvJ75/e+gmjXrl0CgFi6dKkQQghfX18BQFy6dCnPdS5evCgACD8/P6kte/9ev34trKysxNy5c4UQQly/fl0AEBEREQUuiF69eiUyMzOV2uLi4oS2trbw9/eX2rI/LB0dHUVaWprUvnTpUgFAXL16VQjx5n21sLAQjRo1UhqXXfwVtCDq0qWLaNmypdL6GhoaIikpKc91+vfvLwAIQ0NDcf/+/Xy3n1dBBECsXLlSqX3Tpk1CTU1NnDhxQql95cqVAoA4deqUEEKIu3fvCnV1dfHdd98pjbt69arQ0NDI0f6utwuiGzduCGtra9G0aVPx+PHjfNfLltcps+zfs7fn/+zZM2Fvby/s7Oykn//bBdGzZ8+Eq6urMDc3V/r9PHHihAAgwsLClDL279+fo93W1lYAEMePH5fakpKShLa2tpgwYYLU1rBhw1I5xU1lC0+ZEeUh+zTK3r178ezZM+zduzfP02UAoKurK/35yZMnSE5ORuvWrXHx4kWlcVZWVli+fDkOHTqE1q1bIzo6GuvWrYORkdFHz9nAwAAA8OzZM6X/Ghoa5rlOdl9KSkqOPnV1dfTp0wdbt24F8OZiahsbG7Ru3brAc9LW1oaa2pv/1WRmZuK///6DgYEBatWqleO9AYChQ4dCS0tLep2ddefOHQDAhQsXkJSUhK+//lpp3JdffgljY+MCzem///7DgQMH0L9/f6mtd+/e0im7vJibmwMA6tSpgypVqhQo613a2toYOnSoUtvPP/8MR0dH1K5dG//++6+0fPrppwCAo0ePAgB27tyJrKws9OnTR2mclZUVHBwcpHHv8+eff8LV1RV2dnY4fPgwKlSoUKh9yfb777+jWbNmSjchGBgYYMSIEbh79y6uX7+uND45ORnt27fHX3/9hWPHjqFRo0ZK74WxsTE+++wzpX10cnKCgYFBjn2sU6eO0u9jxYoVUatWLen3BQBMTExw7do1xMbGftR+UvnGu8yI8lCxYkW4u7tjy5YtePHiBTIzM/H555/nOX7v3r2YN28eoqOjla77UCgUOcb269cPmzdvxr59+zBixAi0a9euSOacmpoK4P+LnOz/ZhdGuXlf0TRgwAAEBQXh8uXL2LJlC/r165frPuUlKysLS5cuRUhICOLi4pCZmSn1mZmZ5RhftWpVpdfZH9bZ14/cu3cPAODg4KA0TlNTE9WqVSvQnLZv346MjAw0btxY6fqk5s2bIywsDN7e3jnWuXDhApYvX4569erh7Nmz2Lx5MwYOHFigvLdVrlxZqZADgNjYWNy4cQMVK1bMdZ2kpCRpnBAix75ne/vuwvx07doVlpaWOHDggFREZ0tNTZV+j4A3RXFe88p27949NG/ePEd79h119+7dQ7169aR2X19fvHr1CpcuXULdunWV1omNjUVycjIsLCxyzcp+L7K9+/sCvPmdeft6I39/f3Tv3h01a9ZEvXr10LFjRwwaNAgNGjTId79IXlgQEeVjwIABGD58OBISEtCpUyeYmJjkOu7EiRPo1q0b2rRpg5CQEFSqVAmamppYv359jouSgTdHKLKf33P9+nVkZWVJR1E+xp9//gkAqFGjBoD//0C6cuWK0r/C33blyhUAb/6lnZvmzZujevXq8PX1RVxcXL5HyXLz/fffY8aMGRg2bBjmzp0LU1NTqKmpwdfXF1lZWTnGq6ur57odIcQH5eYnLCwMANCyZctc++/cuaNUXGVmZmLEiBGwtrbGqVOn0L59e0yYMAFdunTJ83ciL28fScyWlZWF+vXrY/HixbmuY2NjI43LfmZSbu/Tu8VNXnr37o0NGzYgLCwMI0eOVOpbuHAh5syZI722tbXF3bt3C7TdgurevTu2bduGH374ARs3blT63c/KyoKFhYX0M3rXu8VZQX5f2rRpg9u3b2PPnj04ePAgfvrpJyxZsgQrV67EV199VQR7ROUBCyKifPTs2RMjR47E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OiV7e3tYWVkhPDxc6k9JScHZs2fh4uICAHBxccHTp08RFRUljTly5AiysrLQvHnzIpsrERERlV2FOkI0f/58eHh44PDhw1LhERkZifv37+P3338vssl17doV3333HapWrYq6devi0qVLWLx4MYYNGwYAUCgU8PX1xbx58+Dg4CDddm9tbY0ePXoAABwdHdGxY0cMHz4cK1euREZGBnx8fNCvX7887zAjIiIieSlUQeTq6oqbN29i+fLl+OuvvwAAvXr1wujRo4u0yFi2bBlmzJiB0aNHIykpCdbW1hg5ciRmzpwpjZk8eTKeP3+OESNG4OnTp2jVqhX2798vPYMIePNltD4+PmjXrh3U1NTQu3dvBAUFFdk8iYiIqGwrVEEUHx8PGxubXC+ejo+PR9WqVT96YgBgaGiIwMBABAYG5jlGoVDA398f/v7+eY4xNTXlQxiJiIgoT4W6hsje3h7//PNPjvb//vsP9vb2Hz0pIiIiopJUqIJICAGFQpGjPTU1VelUFREREVFZ8EGnzLIfVKhQKDBjxgzo6elJfZmZmTh79qx0uzsRERFRWfFBBdGlS5cAvDlCdPXqVWhpaUl9WlpaaNiwISZOnFi0MyQiIiIqZh9UEGV/4/3QoUOxdOlSGBkZFcukiIiIiEpSoa4hWr9+vVQMbd26Fc+fPy/SSRERERGVpEIVRG8bOXIkEhMTi2IuRERERKXiowsiIURRzIOIiIio1Hx0QURERERU1hWqINq6dav05z/++AOVK1eWXk+aNOnjZ0VERERUggpVEI0aNQp//PEHAKBVq1bQ1tYGAIwfPx6bN28uutkRERERlYBCFURhYWHo378/Tp48KbWNGTMGO3bskG7NJyIiIiorClUQeXh4ICQkBN26dUNUVBRGjx6NnTt34ujRo6hdu3ZRz5GIiIioWBXq2+4BYMCAAXj69ClatmyJihUrIiIiAjVq1CjKuRERERGViAIXRNnfY/auihUrokmTJggJCZHaFi9e/PEzIyIiIiohBS6Isr/H7F01atRASkqK1K9QKIpmZkREREQlpMAFES+WJiIiovKKD2YkIiIi2WNBRERERLLHgoiIiIhkjwURERERyR4LIiIiIpI9FkREREQkeyyIiIiISPZYEBEREZHssSAiIiIi2WNBRERERLLHgoiIiIhkjwURERERyR4LIiIiIpI9FkRE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JHssiIioRLm5ucHX17dU56BQKLB79+5SncPbQkNDS+RWZiLKGwsiIiIikj0WREREpSgjI6O0p0BEYEFERKXg9evX8PHxgbGxMczNzTFjxgxkPxItLS0NEydOROXKlaGvr4/mzZvj2LFj0rrZp5cOHDgAR0dHGBgYoGPHjnj06JFSxrp161C3bl1oa2ujUqVK8PHxUer/999/0bNnT+jp6cHBwQG//fab1Hfs2DEoFAocOHAAjRs3hq6uLj799FMkJSXhjz/+gKOjI4yMjDBgwAC8ePFCWm///v1o1aoVTExMYGZmhi5duuD27dtS/927d6FQKLB9+3a4urpCR0cHYWFhOd6ff/75B87OzujZsyfS0tI+6r0mooJhQUREJW7Dhg3Q0NDAuXPnsHTpUixevBg//fQTAMDHxweRkZHYtm0brly5gi+++AIdO3ZEbGystP6LFy+wcOFCbNq0CcePH0d8fDwmTpwo9a9YsQLe3t4YMWIErl69it9++w01atRQmsOcOXPQp08fXLlyBZ07d4anpyceP36sNGb27NkIDg7G6dOncf/+ffTp0weBgYHYsmUL9u3bh4MHD2LZsmXS+OfPn8PPzw8XLlxAeHg41NTU0LNnT2RlZSltd+rUqRg3bhxu3LiBDh06KPXdv38frVu3Rr169fDLL79AW1v7495sIiqYEn0uNhHJnqurq3B0dBRZWVlS25QpU4Sjo6O4d++eUFdXFw8ePFBap127dmLatGlCCCHWr18vAIhbt25J/cuXLxeWlpbSa2tra/Htt9/mOQcAYvr06dLr1NRUAUD88ccfQgghjh49KgCIw4cPS2MCAgIEAHH79m2pbeTIkaJDhw555vzzzz8CgLh69aoQQoi4uDgBQAQGBiqNW79+vTA2NhZ//fWXsLGxEWPHjlV6f4io+PEIERGVuE8++QQKhUJ67eLigtjYWFy9ehWZmZmoWbMmDAwMpCUiIkLp1JOenh6qV68uva5UqRKSkpIAAElJSXj48CHatWuX7xwaNGgg/VlfXx9GRkbSNnIbY2lpCT09PVSrVk2p7e11YmNj0b9/f1SrVg1GRkaws7MDAMTHxytt19nZOcd8Xr58idatW6NXr15YunSp0vtDRMVPo7QnQESULTU1Ferq6oiKioK6urpSn4GBgfRnTU1NpT6FQiFdg6Srq1ugrNy28e6prbfHKBSK967TtWtX2NraYs2aNbC2tkZWVhbq1auH9PR0pfX09fVzzEdbWxvu7u7Yu3cvJk2ahMqVKxdoP4ioaPAIERGVuLNnzyq9PnPmDBwcHNC4cWNkZmYiKSkJNWrUUFqsrKwKtG1DQ0PY2dkhPDy8OKaep//++w8xMTGYPn062rVrB0dHRzx58qTA66upqWHTpk1wcnJC27Zt8fDhw2KcLRG9iwUREZW4+Ph4+Pn5ISYmBlu3bsWyZcswbtw41KxZE56enhg8eDB27tyJuLg4nDt3DgEBAdi3b1+Btz979mwsWrQIQUFBiI2NxcWLF5Uufi4OFSpUgJmZGVavXo1bt27hyJEj8PPz+6BtqKurIywsDA0bNsSnn36KhISEYpotEb2LBRERlbjBgwfj5cuXaNasGby9vTFu3DiMGDECALB+/XoMHjwYEyZMQK1atdCjRw+cP38eVatWLfD2hwwZgsDAQISEhKBu3bro0qWL0l1qxUFNTQ3btm1DVFQU6tWrh/Hjx2PBggUfvB0NDQ1s3boVdevWlW71J6LipxDZJ96JiIiIZIpHiIiIiEj2WBARERGR7LEgIiIiItljQURERESyx4KIiIiIZI8FEREREckeCyIiIiKSPRZEREREJHssiIiIiEj2WBARERGR7LEgIiIiItn7P4e0CJ1+sWoiAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "df.set_index('benchmark', inplace=True)\n", - "\n", - "# Plot the 'max DOM k-tokens' and 'max AXTree k-tokens' columns\n", - "df[['max DOM k-tokens', 'max AXTree k-tokens']].plot(kind='bar')\n", - "\n", - "# Add labels and title\n", - "plt.ylabel('k-tokens')\n", - "plt.title('Max DOM and AXTree k-tokens')\n", - "\n", - "# Display the plot\n", - "plt.show()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ui-copilot", - "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.11.7" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/agentlab/analyze/error_categorization.py b/src/agentlab/analyze/error_categorization.py deleted file mode 100644 index c6a9cd1b..00000000 --- a/src/agentlab/analyze/error_categorization.py +++ /dev/null @@ -1,89 +0,0 @@ -import re - - -def is_critical_server_error(err_msg: str, stack_trace: str, return_error_type=False): - if stack_trace is None: - return False - server_error_conditions = [ - "502 Server Error: Bad Gateway", # url is not valid or server is not ready yet - "500 Server Error: Internal Server Error", # When the server is up, but somehow unresponsive - "424 Client Error: Failed Dependency", # Request failed during generation: Server error: CUDA error: invalid argument - "403 Client Error: Forbidden", - "401 Client Error: Unauthorized", # the server was auth-token protected - "400 Client Error: Bad Request", # there's no server. (the server probably failed) sometimes only visible in stack trace? - ] - if not return_error_type: - return any(condition in stack_trace for condition in server_error_conditions) - else: - for condition in server_error_conditions: - if condition in stack_trace: - return condition - return None - - -def is_minor_server_error(err_msg: str, stack_trace: str, return_error_type=False): - if stack_trace is None: - return False - server_error_conditions = [ - "504 Server Error: Gateway Time-out", - "Server error: Out of available cache blocks", # TODO(look into) - "openai.APIConnectionError: Connection error", - ] - if not return_error_type: - return any(condition in stack_trace for condition in server_error_conditions) - else: - for condition in server_error_conditions: - if condition in stack_trace: - return condition - return None - - -def is_retry_error(err_msg: str, stack_trace: str): - """Use regex on the stack trace to detect retry errors. - - The pattern is "ValueError: Could not parse a valid value after d+ - retries." - - Args: - err_msg (str): The error message - stack_trace (str): The stack trace - - Returns: - bool: True if the error is a retry error, False otherwise - """ - if stack_trace is None: - return False - pattern = r"ValueError: Could not parse a valid value after \d+ retries." - return re.search(pattern, stack_trace) is not None - - -def is_input_length_error(err_msg: str, stack_trace: str): - """Use regex on the stack trace to detect input length errors. - - The patterns are "422 Client Error: Unprocessable Entity" - and also "Input validation error: `inputs` tokens + `max_new_tokens` must be <=" - - Args: - err_msg (str): The error message - stack_trace (str): The stack trace - - Returns: - bool: True if the error is an input length error, False otherwise - """ - if stack_trace is None: - return False - patterns = [ - r"422 Client Error: Unprocessable Entity", - r"Input validation error: `inputs` tokens \+ `max_new_tokens` must be <=", - ] - return any( - re.search(pattern, err_msg) or re.search(pattern, stack_trace) for pattern in patterns - ) - - -ERR_CLASS_MAP = { - "critical_server_error": is_critical_server_error, - "minor_server_error": is_minor_server_error, - "retry_error": is_retry_error, - "input_length_error": is_input_length_error, -} diff --git a/src/agentlab/analyze/inspect_results.py b/src/agentlab/analyze/inspect_results.py index 862be27b..d48ef88e 100644 --- a/src/agentlab/analyze/inspect_results.py +++ b/src/agentlab/analyze/inspect_results.py @@ -1,12 +1,10 @@ import fnmatch -import io import json import random import re import traceback import warnings from collections import defaultdict -from datetime import datetime from logging import warn from pathlib import Path @@ -16,13 +14,7 @@ from IPython.display import display from tqdm import tqdm -from agentlab.analyze.error_categorization import ( - ERR_CLASS_MAP, - is_critical_server_error, - is_minor_server_error, -) from agentlab.experiments.exp_utils import RESULTS_DIR -from agentlab.utils.bootstrap import bootstrap_matrix, convert_df_to_array # TODO find a more portable way to code set_task_category_as_index at least # handle dynamic imports. We don't want to always import workarena @@ -30,11 +22,6 @@ warnings.filterwarnings("ignore", category=pd.errors.PerformanceWarning) -try: - import pyperclip -except ImportError: - pyperclip = None - pd.set_option("display.multi_sparse", False) AGENT_NAME_KEY = "agent.agent_name" @@ -224,17 +211,6 @@ def report_constant_and_variables(df, show_stack_traces=True): print(f" ...\n") -def get_bootstrap(df, metric, reduce_fn=np.nanmean, n_bootstrap=100, group_by=TASK_KEY, prior=0.5): - """Get the stratified bootstrap mean and std for the given metric.""" - grouped_df = df.reset_index(inplace=False).groupby(group_by) - array = convert_df_to_array(grouped_df, metric=metric, threshold=0.7) - if prior is not None: - prior = prior * np.ones((len(array), 1)) - array = np.concatenate([array, prior], axis=1) - - bootstrapped_values = bootstrap_matrix(array, n_bootstrap=n_bootstrap, reduce_fn=reduce_fn) - return np.nanmean(bootstrapped_values), np.nanstd(bootstrapped_values) - def get_std_err(df, metric): """Get the standard error for a binary metric.""" @@ -262,7 +238,7 @@ def get_sample_std_err(df, metric): return mean, std_err -def summarize(sub_df, use_bootstrap=False): +def summarize(sub_df): if not "cum_reward" in sub_df: record = dict( avg_reward=np.nan, @@ -279,10 +255,7 @@ def summarize(sub_df, use_bootstrap=False): if n_completed == 0: return None - if use_bootstrap: - _mean_reward, std_reward = get_bootstrap(sub_df, "cum_reward") - else: - _mean_reward, std_reward = get_std_err(sub_df, "cum_reward") + _mean_reward, std_reward = get_std_err(sub_df, "cum_reward") # sanity check, if there is an error the reward should be zero assert sub_df[sub_df["err_msg"].notnull()]["cum_reward"].sum() == 0 @@ -466,20 +439,6 @@ def _rename_bool_flags(report: pd.DataFrame, true_str="✓", false_str="-"): return report -def to_clipboard(df: pd.DataFrame): - """Copy the dataframe to the clipboard as a tab separated csv.""" - output = io.StringIO() - df.to_csv(output, sep="\t", index=True) - csv_string = output.getvalue() - if pyperclip is not None: - try: - pyperclip.copy(csv_string) - except Exception as e: - warn(f"Failed to copy to clipboard: {e}") - # else: - # print("pyperclip is not installed, cannot copy to clipboard.") - # return df - def flag_report(report: pd.DataFrame, metric: str = "avg_reward", round_digits: int = 2): # for all index in the multi-index with boolean value, get the average for diff --git a/src/agentlab/analyze/plot_tools.py b/src/agentlab/analyze/plot_tools.py deleted file mode 100644 index b60f60df..00000000 --- a/src/agentlab/analyze/plot_tools.py +++ /dev/null @@ -1,409 +0,0 @@ -from pathlib import Path -from typing import List - -import joblib -import numpy as np -import pandas as pd -import seaborn as sns -from matplotlib import pyplot as plt -from matplotlib.collections import PolyCollection -from matplotlib.ticker import FormatStrFormatter -from scipy.stats import trim_mean - -from agentlab.utils.bootstrap import bootstrap_all_benchmarks - -sns.set_style("dark", {"grid.color": "0.98", "axes.facecolor": "(0.95, 0.95, 0.97)"}) - - -def load_benchmark_masks(csv_path: Path | str, benchmark_names=list[str]): - """Load benchmark masks from a csv file and convert it. - - To create the csv file simply use file/download/"...csv" from google - spreadsheet. - - Args: - csv_path (Path | str): The path to the csv file. - benchmark_names (list[str]): The names of the benchmarks to be loaded. - - Returns: - pd.DataFrame: The benchmark masks. - """ - mask_df = pd.read_csv(csv_path) # type: pd.DataFrame - - for benchmark_name in benchmark_names: - mask_df[benchmark_name] = mask_df[benchmark_name].apply( - lambda x: True if str(x).strip() == "x" else False - ) - - mask_df["all"] = True - benchmark_names = ["all"] + benchmark_names - - # remove the Average row - mask_df = mask_df[mask_df["Task Name"] != "ZAverage"] - mask_df = mask_df[mask_df["Task Name"].isna() == False] - - # # print the excluded tasks - # excluded_tasks = set(mask_df["Task Name"].unique()) - set(MINIWOB_TASKNAME_TO_CLASSNAME.keys()) - # print("Excluded tasks:", excluded_tasks) - - # # filter task that are not in the MINIWOB_TASKNAME_TO_CLASSNAME - # mask_df = mask_df[mask_df["Task Name"].isin(MINIWOB_TASKNAME_TO_CLASSNAME.keys())] - - # # convert task name to class name and keep all columns - mask_df["task_name"] = mask_df["Task Name"].apply(lambda x: f"miniwob.{x}") - mask_df.set_index("task_name", inplace=True) - - # extract only the benchmark columns - mask_df = mask_df[benchmark_names] - - # rename columns - mask_df.rename(rename_func, inplace=True, axis="columns") - return mask_df - - -def add_benchmark_masks(df: pd.DataFrame, benchmark_masks: pd.DataFrame): - """Add benchmark masks to the dataframe.""" - return df.merge(benchmark_masks, left_on="task_name", right_index=True) - - -def sort_agents(agents, df, metric="cum_reward"): - agent_order = ( - df.groupby("agent_model_name")[metric].mean().sort_values(ascending=False).index.tolist() - ) - return [agent for agent in agent_order if agent in agents] - - -def iqm(scores): - """Interquantile mean.""" - return trim_mean(scores, proportiontocut=0.25, axis=None) - - -# add memory from joblib -memory = joblib.Memory(location=Path().home() / "cache", verbose=1) -bootstrap_all_benchmarks_cached = memory.cache(bootstrap_all_benchmarks) - - -def bootstrap_and_plot( - df: pd.DataFrame, - benchmark_names: List[str], - metric: str = "cum_reward", - model_axis: str = "agent_model_name", - agent_order: List[str] | None = None, - agent_colors=None, - agent_markers=None, - repeat: int = 100, - fig_size=None, - n_legend_rows: int = 2, -): - """Add aggregated data as a new benchmark.""" - - if agent_order is None: - agent_order = sorted(df[model_axis].unique()) - print("bootstrapping") - # create a new df containing bootstrapped samples of iqm - - df_bootstrap = bootstrap_all_benchmarks( - df, metric, benchmark_cols=benchmark_names, repeat=repeat - ) - print("plotting") - - # plot results per benchmark (aggregated results is an extra benchmark) - plot_per_benchmark( - df_bootstrap, - agent_order, - model_axis, - benchmark_order=benchmark_names, - agent_colors=agent_colors, - agent_markers=agent_markers, - metric=metric, - fig_size=fig_size, - n_legend_rows=n_legend_rows, - ) - - -def remove_violin_outline(ax): - """Remove the outline of the violin plot.""" - for pc in ax.collections: - pc.set_edgecolor("none") - - -def get_violin_centers(ax: plt.Axes) -> list[float]: - """Estimate the center of violin patches from axes. - - This is a hacky way to get the center of the violin patches. - It works by averaging the x coordinates of the vertices of PolyCollection - - Args: - ax (plt.Axes): The axes containing the violin plot. - - Returns: - list[float]: The x coordinates of the centers of the violins. - """ - violin_centers = [] - for child in ax.get_children(): - if isinstance(child, PolyCollection): - violin_centers.append(np.mean(child.get_paths()[0].vertices[:, 0])) - - return sorted(violin_centers) - - -def associate_action_markers(agent_order): - """Associate a marker to each agent, based on action space.""" - markers = {} - for agent in agent_order: - marker = None - if "high" in agent: - marker = "^" - elif "low" in agent: - marker = "v" - elif "both" in agent: - marker = "d" - elif "code" in agent: - marker = "o" - else: - marker = "*" - - markers[agent] = marker - return markers - - -def rename_func(name): - return RENAME_DICT.get(name, name) - - -# for display names in the paper -RENAME_DICT = { - "easy (auto)": "easy", - "hard (auto)": "hard", - "long context (auto)": "long context", - "rci-agent task (47)": "RCI\nsubset", - "WebGUM task (56)": "WebGUM\nsubset", - "long context": "long context", - "pixel": "pixel", - "2d under standing": "2D\nunderstanding", - "x,y actions": "x, y\nactions", - "domain specific knowledge or exploration ?": "domain specific\nknowledge", - "long episode": "long episode", - "rapid interaction": "rapid interaction", - "action space limited": "action space\nlimited", - "requies augmented HTML and/or AXTree": "requires\naugmented HTML", -} - - -def add_markers(ax, df, model_axis, metric, agent_order, agent_markers, agent_colors): - """Add markers to the scatter plot.""" - v_centers = get_violin_centers(ax) - scatter_handles = {} - - for center_x, agent in zip(v_centers, agent_order): - median_y = df[df[model_axis] == agent][metric].mean() - - scatter_plot = ax.scatter( - center_x, - median_y, - marker=agent_markers[agent], - color=agent_colors[agent], - edgecolor="black", - label=agent, - s=60, - ) - - scatter_handles[agent] = scatter_plot - - # markers overtake the legend - legend = ax.legend( - handles=list(scatter_handles.values()), - labels=list(scatter_handles.keys()), - loc="lower center", - bbox_to_anchor=(0.5, 1), - ncol=len(agent_order), - title="", - ) - - # bigger markers! - for handle in legend.legendHandles: - handle.set_sizes([100]) - return scatter_handles - - -def plot_per_benchmark( - df: pd.DataFrame, - agent_order: List[str], - model_axis: str, - benchmark_order: List[str] | None = None, - metric: str = "cum_reward", - aggregated_name: str = "all", - sharey: bool = True, - inner: str = None, - fig_size: tuple = None, - n_legend_rows: int = 1, - agent_colors: dict[str, tuple] = None, - agent_markers: dict[str, str] = None, -): - """Violin plots for each benchmarks and each agents. - - Args: - df: pd.DataFrame - The input DataFrame. - agent_order: List[str] - The order of the agents in the plot. - model_axis: str - The column containing the agent names. - benchmark_order: List[str], optional - The order of the benchmarks in the plot. Defaults to alhpabetical order. - metric: str, optional - The column containing the metric to which the function will be applied. - aggregated_name: str, optional - The name of the "special" benchmark. It will be placed first and - highlighted in pale blue - sharey: bool, optional - Whether to share the y axis between plots. - inner: str, optional - The type of inner display inside of the violins. See seaborn.violinplot - fig_size: tuple, optional - The size of the figure. see matplotlib.pyplot.figure - n_legend_rows: int, optional - The number of rows in the legend. - agent_colors: dict[str, tuple], optional - A dictionary mapping agent names to colors. Defaults to seaborn's colorblind palette. - agent_markers: dict[str, str], optional - A dictionary mapping agent names to markers. Defaults to no markers. - """ - if benchmark_order is None: - benchmark_order = sorted(df["benchmark"].unique()) - - if fig_size is None: - fig_width = len(benchmark_order) * 2 - fig_size = (fig_width, 3) - fig, axes = plt.subplots(1, len(benchmark_order), sharey=sharey, figsize=fig_size) - - if agent_colors is None: - colors = sns.color_palette("colorblind", n_colors=len(agent_order)) - agent_colors = dict(zip(agent_order, colors)) - - if agent_markers is not None: - violon_palette = {agent: (0.8, 0.8, 0.8) for agent in agent_order} - else: - violon_palette = agent_colors - - for benchmark, ax in zip(benchmark_order, axes): - sub_df = df[df["benchmark"] == benchmark] - - sns.violinplot( - x="benchmark", - y=metric, - hue=model_axis, - data=sub_df, - hue_order=agent_order, - linewidth=0.5, - saturation=1, - scale="count", - inner=inner, - palette=violon_palette, - ax=ax, - ) - remove_violin_outline(ax) - - if agent_markers is not None: - add_markers(ax, sub_df, model_axis, metric, agent_order, agent_markers, agent_colors) - - ax.tick_params(axis="y", labelsize=18) - ax.yaxis.set_major_formatter(FormatStrFormatter("%.2f")) - ax.grid(axis="y") - - if benchmark == aggregated_name: - ax.set_facecolor("#cff6fc") - - ax.set(xlabel=None) - - if benchmark != benchmark_order[int((len(benchmark_order) - 1) / 2)]: - ax.get_legend().remove() - else: - ncols = int(np.ceil(len(agent_order) / n_legend_rows)) - - sns.move_legend(ax, loc="lower center", bbox_to_anchor=(0.5, 1), ncol=ncols, title="") - - if benchmark != benchmark_order[0]: - ax.set(ylabel=None) - - if sharey: - fig.subplots_adjust(wspace=0.02) - else: - fig.subplots_adjust(wspace=0.3) - - -@memory.cache -def modify_names(df): - """Generate names that are paper-friendly, and fix model_name and agent_name for the different formats.""" - - def process_row(row): - model_name = row.get("model_name", np.nan) - agent_name = row["agent_name"] - - if not isinstance(model_name, str) or len(model_name) == 0: - # rim's type of model extract from agent name - model_name = "gpt-4" if "gpt4" in agent_name else "gpt-3.5" - agent_name = agent_name.replace("_gpt4", "") - else: - # massimo's type of model - if "/" in model_name: - model_name = model_name.split("/")[-1] - model_name = model_name.replace("-Instruct-hf", "").replace("-beta", "") - - agent_name = agent_name.replace("GenericAgent_", "") - - row["agent_name"] = agent_name - row["model_name"] = model_name - row["agent_model_name"] = f"{agent_name}-{model_name}" - - return row - - return df.apply(process_row, axis=1) - - -def find_incomplete_exp(df: pd.DataFrame, agent_columns_to_show=None): - agents = df["agent_model_name"].unique() - # print(agents) - dicts = [] - for agent in agents: - agent_df = df[df["agent_model_name"] == agent] # type: pd.DataFrame - tasks = agent_df["task_name"].unique() - - n_episode = [] - for task in tasks: - task_df = agent_df[agent_df["task_name"] == task] - n_episode.append(len(task_df)) - # find missing cum_reward - missing_cum_reward = agent_df["cum_reward"].isna().sum() - # num results - num_results = len(agent_df) - - info = { - "agent": agent, - "n_tasks": len(tasks), - "max_ep_count": np.max(n_episode), - "min_ep_count": np.min(n_episode), - "mean_ep_count": np.mean(n_episode), - "unique cum_reward": str(agent_df["cum_reward"].unique()), - "missing_cum_reward": missing_cum_reward, - "total_results": num_results, - } - - if agent_columns_to_show is not None: - for col in agent_columns_to_show: - info[f"{col}-unique"] = agent_df[col].unique()[:10] - - for task in tasks: - sub_df = agent_df[agent_df["task_name"] == task] - if len(sub_df) > 10: - unique_exp_dir = sub_df["exp_dir"].unique() - print( - f" {agent} {task} {len(sub_df)} n unique expseeds {len(sub_df['exp_seed'].unique())}" - ) - for i, dir in enumerate(unique_exp_dir): - print(f" Unique exp_dir {i}: {dir}") - - dicts.append(info) - df_summary = pd.DataFrame(dicts) - # df_summary = df_summary.sort_values("max_episode_count", ascending=False) - return df_summary diff --git a/src/agentlab/experiments/get_ray_url.py b/src/agentlab/experiments/get_ray_url.py index b652254c..2eb5cb58 100644 --- a/src/agentlab/experiments/get_ray_url.py +++ b/src/agentlab/experiments/get_ray_url.py @@ -1,3 +1,8 @@ +"""Temporary script to get the ray dashboard url for the current experiment. + +TODO figure out a more convenient way. +""" + import ray context = ray.init(address="auto", ignore_reinit_error=True) diff --git a/src/agentlab/experiments/graph_execution_dask.py b/src/agentlab/experiments/graph_execution_dask.py deleted file mode 100644 index dc51dd51..00000000 --- a/src/agentlab/experiments/graph_execution_dask.py +++ /dev/null @@ -1,64 +0,0 @@ -from concurrent.futures import ThreadPoolExecutor, TimeoutError as FuturesTimeoutError - -from contextlib import contextmanager -import threading -from dask import compute, delayed -from bgym import ExpArgs -from distributed import LocalCluster, Client -from agentlab.experiments.exp_utils import _episode_timeout - -# from agentlab.experiments.exp_utils import run_exp - - -def run_exp(exp_arg: ExpArgs, *dependencies, avg_step_timeout=60): - """Run exp_args.run() with a timeout and handle dependencies.""" - # dask can't use the timeout_manager define in exp_utils.py - # ValueError: signal only works in main thread of the main interpreter - # most alternative I try doesn't work - episode_timeout = _episode_timeout(exp_arg, avg_step_timeout=avg_step_timeout) - return exp_arg.run() - - -def make_dask_client(n_worker): - """Create a Dask client with a LocalCluster backend. - - I struggled to find an appropriate configuration. - I believe it has to do with the interplay of playwright async loop (even if - used in sync mode) and the fact that dask uses asyncio under the hood. - Making sure we use processes and 1 thread per worker seems to work. - - Args: - n_worker: int - Number of workers to create. - - Returns: - A Dask client object. - """ - cluster = LocalCluster( - n_workers=n_worker, - processes=True, - threads_per_worker=1, - ) - - return Client(cluster) - - -def execute_task_graph(exp_args_list: list[ExpArgs]): - """Execute a task graph in parallel while respecting dependencies.""" - exp_args_map = {exp_args.exp_id: exp_args for exp_args in exp_args_list} - - tasks = {} - - def get_task(exp_arg: ExpArgs): - if exp_arg.exp_id not in tasks: - dependencies = [get_task(exp_args_map[dep_key]) for dep_key in exp_arg.depends_on] - tasks[exp_arg.exp_id] = delayed(run_exp)(exp_arg, *dependencies) - return tasks[exp_arg.exp_id] - - for exp_arg in exp_args_list: - get_task(exp_arg) - - task_ids, task_list = zip(*tasks.items()) - results = compute(*task_list) - - return {task_id: result for task_id, result in zip(task_ids, results)} diff --git a/src/agentlab/experiments/list_openai_models.py b/src/agentlab/experiments/list_openai_models.py index 438f97bd..0c301926 100644 --- a/src/agentlab/experiments/list_openai_models.py +++ b/src/agentlab/experiments/list_openai_models.py @@ -5,8 +5,8 @@ models = OpenAI().models.list() df = pd.DataFrame([dict(model) for model in models.data]) - # Filter GPT models - df = df[df["id"].str.contains("gpt")] + # Filter GPT models or o1 models + df = df[df["id"].str.contains("gpt") | df["id"].str.contains("o1")] # Convert Unix timestamps to dates (YYYY-MM-DD) and remove time df["created"] = pd.to_datetime(df["created"], unit="s").dt.date diff --git a/src/agentlab/experiments/miniwob_tasks_all.csv b/src/agentlab/experiments/miniwob_tasks_all.csv deleted file mode 100644 index e4b3777b..00000000 --- a/src/agentlab/experiments/miniwob_tasks_all.csv +++ /dev/null @@ -1,126 +0,0 @@ -task_name,miniwob_category,comment -ascending-numbers,hidden test, -bisect-angle,original, -book-flight,original,delay -book-flight-nodelay,nodelay, -buy-ticket,hidden test, -choose-date,original,delay -choose-date-easy,debug,delay -choose-date-medium,debug,delay -choose-date-nodelay,nodelay, -choose-list,original, -circle-center,original, -click-button,original, -click-button-sequence,original, -click-checkboxes,original, -click-checkboxes-large,additional, -click-checkboxes-soft,additional, -click-checkboxes-transfer,additional, -click-collapsible,original,delay -click-collapsible-2,original,delay -click-collapsible-2-nodelay,nodelay, -click-collapsible-nodelay,nodelay, -click-color,original, -click-dialog,original, -click-dialog-2,original, -click-link,original, -click-menu,original, -click-menu-2,original, -click-option,original, -click-pie,original,delay -click-pie-nodelay,nodelay, -click-scroll-list,original, -click-shades,original, -click-shape,original, -click-tab,original, -click-tab-2,original, -click-tab-2-easy,debug, -click-tab-2-hard,additional, -click-tab-2-medium,debug, -click-test,original, -click-test-2,original, -click-test-transfer,debug, -click-widget,original, -copy-paste,original, -copy-paste-2,original, -count-shape,original, -count-sides,original, -daily-calendar,hidden test, -drag-box,original, -drag-circle,original, -drag-cube,original, -drag-items,original, -drag-items-grid,original, -drag-shapes,original, -drag-shapes-2,hidden test, -drag-single-shape,hidden test, -drag-sort-numbers,original, -draw-circle,hidden test, -draw-line,hidden test, -email-inbox,original, -email-inbox-delete,debug, -email-inbox-forward,debug, -email-inbox-forward-nl,additional, -email-inbox-forward-nl-turk,additional, -email-inbox-important,debug, -email-inbox-nl-turk,additional, -email-inbox-noscroll,debug, -email-inbox-reply,debug, -email-inbox-star-reply,debug, -enter-date,original, -enter-password,original, -enter-text,original, -enter-text-2,original, -enter-text-dynamic,original, -enter-time,original, -find-greatest,hidden test, -find-midpoint,original, -find-word,original, -focus-text,original, -focus-text-2,original, -form-sequence,hidden test, -form-sequence-2,hidden test, -form-sequence-3,hidden test, -generate-number,hidden test, -grid-coordinate,original, -guess-number,original, -highlight-text,original, -highlight-text-2,original, -hot-cold,hidden test, -identify-shape,original, -login-user,original, -login-user-popup,additional, -multi-layouts,additional, -multi-orderings,additional, -navigate-tree,original, -number-checkboxes,original, -odd-or-even,hidden test, -order-food,hidden test, -phone-book,hidden test, -read-table,original, -read-table-2,original, -resize-textarea,original, -right-angle,original, -scroll-text,original, -scroll-text-2,original, -search-engine,original, -sign-agreement,hidden test, -simple-algebra,original, -simple-arithmetic,original, -social-media,original, -social-media-all,additional, -social-media-some,additional, -stock-market,hidden test,delay -terminal,original, -text-editor,original, -text-transform,original, -tic-tac-toe,original, -unicode-test,debug, -use-autocomplete,original,delay -use-autocomplete-nodelay,nodelay, -use-colorwheel,original, -use-colorwheel-2,original, -use-slider,original, -use-slider-2,original, -use-spinner,original, -visual-addition,original, diff --git a/src/agentlab/experiments/reproduce_study.py b/src/agentlab/experiments/reproduce_study.py index 93ef07fb..8a8a7093 100644 --- a/src/agentlab/experiments/reproduce_study.py +++ b/src/agentlab/experiments/reproduce_study.py @@ -11,7 +11,7 @@ if __name__ == "__main__": - # old_study = "2024-06-03_13-53-50_final_run_workarena_L1_llama3-70b" + # replace by your study name old_study = "2024-06-03_12-28-51_final_run_miniwob_llama3-70b" study = reproduce_study(RESULTS_DIR / old_study) diff --git a/src/agentlab/experiments/view_dep_graph.py b/src/agentlab/experiments/view_dep_graph.py index 0639507b..abbf7f87 100644 --- a/src/agentlab/experiments/view_dep_graph.py +++ b/src/agentlab/experiments/view_dep_graph.py @@ -1,3 +1,6 @@ +"""Dirty script to visualize the dependency graph of a benchmark, e.g. webarena, vsisualwebarena, +etc. You may have to detust it to make it work for you.""" + import math import bgym import matplotlib.pyplot as plt diff --git a/src/agentlab/utils/__init__.py b/src/agentlab/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/agentlab/utils/bootstrap.py b/src/agentlab/utils/bootstrap.py deleted file mode 100644 index 666ba6cc..00000000 --- a/src/agentlab/utils/bootstrap.py +++ /dev/null @@ -1,120 +0,0 @@ -import warnings -from typing import Callable, List, Optional, Union - -import numpy as np -import pandas as pd - - -def stratified_bootstrap( - df: pd.DataFrame, - group_by: Union[str, List[str]], - strat: Union[str, List[str]], - metric: str, - func: Callable, - repeat: Optional[int] = 100, - rng: np.random.Generator = np.random.default_rng(), -) -> pd.DataFrame: - """ - Perform stratified bootstrapping on a DataFrame. - - Parameters: - df (pd.DataFrame): The input DataFrame. - group_by (Union[str, List[str]]): The column(s) by which to group the DataFrame. - strat (str): The column used to define strata within each group. - metric (str): The column containing the metric to which the function will be applied. - func (Callable): The function to apply to the metric within each stratum. - repeat (int, optional): Number of bootstrap iterations. Default is 100. - rng (np.random.Generator, optional): Random number generator. Default is NumPy's random generator. - - Returns: - pd.DataFrame: A DataFrame containing bootstrapped samples with applied function. - """ - if group_by is None: - group_by = [] - - if isinstance(group_by, str): - group_by = [group_by] - - if isinstance(strat, str): - strat = [strat] - - # extract subset of columns - df = df[group_by + strat + [metric]] - - group = df.groupby(group_by + strat) - - df_list = [] - for i in range(repeat): - new_df = group.sample(frac=1, replace=True, random_state=rng) - series = new_df.groupby(group_by)[metric].apply(func) - sub_df = series.to_frame().reset_index() - sub_df["bootstrap_index"] = i - df_list.append(sub_df) - - new_df = pd.concat(df_list) - return new_df - - -def bootstrap_all_benchmarks( - df: pd.DataFrame, - metric: str, - benchmark_cols, - group_by=["agent_model_name"], - repeat: int = 100, -): - """Add aggregated data as a new benchmark.""" - - # create a new df containing bootstrapped samples of iqm - df_bootstrap = [] - for benchmark in benchmark_cols: - # filter sub_df assuming that the benchmark column exists and is a boolean - sub_df = df[df[benchmark]] - - bs_df = stratified_bootstrap( - sub_df, - group_by=group_by, - strat=["task_name"], - metric=metric, - func=np.mean, - repeat=repeat, - ) - bs_df["benchmark"] = benchmark - df_bootstrap.append(bs_df) - df_bootstrap = pd.concat(df_bootstrap) - return df_bootstrap - - -def bootstrap_matrix(data: np.ndarray, n_bootstrap: int, reduce_fn=np.nanmean): - n_task, n_samples = data.shape - - indices = np.random.randint(0, n_samples, (n_bootstrap, n_task, n_samples)) - - assert indices.shape == (n_bootstrap, n_task, n_samples) - bootstrapped_samples = data[np.arange(n_task)[:, None], indices] - - with warnings.catch_warnings(): - # catches means of empty slices - warnings.simplefilter("ignore", category=RuntimeWarning) - results = [reduce_fn(b_data) for b_data in bootstrapped_samples] - - return results - - -def convert_df_to_array(grouped, metric="cum_reward", threshold=0.9): - max_samples_per_task = max(len(group) for _, group in grouped) - - arr = np.zeros((len(grouped), max_samples_per_task)) - - for task_idx, (group_id, group) in enumerate(grouped): - # Calculate the ratio of valid values - valid_ratio = len(group) / max_samples_per_task - # if valid_ratio < threshold: - # raise ValueError( - # f"Task {group_id} has insufficient data: ratio {valid_ratio} is below the threshold {threshold}" - # ) - - # Repeat the task data cyclically to fill up to max_samples_per_task - repeated_data = np.resize(group[metric].values, max_samples_per_task) - arr[task_idx, :] = repeated_data - - return arr diff --git a/tests/utils/test_bootstrap.py b/tests/utils/test_bootstrap.py deleted file mode 100644 index 41fe6b1f..00000000 --- a/tests/utils/test_bootstrap.py +++ /dev/null @@ -1,132 +0,0 @@ -import pandas as pd -import numpy as np -from agentlab.utils.bootstrap import stratified_bootstrap, bootstrap_matrix, convert_df_to_array - - -# Generate a DataFrame to use for all unit tests -df = pd.DataFrame( - { - "agent": ["A", "A", "A", "A", "B", "B", "B", "B"], - "episode": [1, 2, 1, 2, 1, 2, 1, 2], - "task": ["T1", "T1", "T2", "T2", "T1", "T1", "T2", "T2"], - "cum_reward": [10, 11, 12, 13, 14, 15, 16, 17], - } -) - - -df_no_var = pd.DataFrame( - { - "agent": ["A", "A", "A", "A", "B", "B", "B", "B"], - "episode": [1, 2, 1, 2, 1, 2, 1, 2], - "task": ["T1", "T1", "T2", "T2", "T1", "T1", "T2", "T2"], - "cum_reward": [10, 10, 12, 12, 14, 14, 16, 16], - } -) - - -def stratified_bootstrap_simple(df: pd.DataFrame, n_bootstrap_samples): - """ - Perform stratified bootstrap sampling to calculate mean cumulative rewards. - - Parameters: - df (DataFrame): DataFrame containing the columns 'task', 'episode', 'cum_reward'. - n_bootstrap_samples (int): Number of bootstrap samples to generate. - - Returns: - np.array: An array of overall bootstrap means. - """ - - # Initialize an empty list to store the overall means - overall_bootstrap_means = [] - - # Perform bootstrapping - for _ in range(n_bootstrap_samples): - bootstrap_sample_rows = [] - - # Stratified sampling for each task - for task in df["task"].unique(): - task_data = df[df["task"] == task] - - # Generate bootstrap sample for this task (sampling with replacement) - bootstrap_sample = task_data.sample(n=len(task_data), replace=True) - bootstrap_sample_rows.append(bootstrap_sample) - - # Concatenate all bootstrap samples to form the overall sample - overall_bootstrap_sample = pd.concat(bootstrap_sample_rows, ignore_index=True) - - # Compute the mean cum_reward for the overall sample - overall_bootstrap_mean = overall_bootstrap_sample["cum_reward"].mean() - - # Store this mean - overall_bootstrap_means.append(overall_bootstrap_mean) - - # Convert the list of overall means to a NumPy array - return np.array(overall_bootstrap_means) - - -# Test for expected number of rows in the output DataFrame -def test_with_no_var(): - df_bootstrap = stratified_bootstrap( - df_no_var, "agent", "task", "cum_reward", np.mean, repeat=10 - ) - df_mean = df_bootstrap.groupby(["agent"])["cum_reward"].mean() - df_mean_alt = df_no_var.groupby(["agent"])["cum_reward"].mean() - - pd.testing.assert_series_equal(df_mean, df_mean_alt, rtol=1e-1, atol=0) - - -# Test for statistical properties (mean, in this case) -def test_statistical_properties(): - df_bootstrap = stratified_bootstrap(df, "agent", "task", "cum_reward", np.mean, repeat=1000) - bs_mean = df_bootstrap.groupby(["agent"])["cum_reward"].mean() - bs_std = df_bootstrap.groupby(["agent"])["cum_reward"].std() - - # alternative method for stratified bootstrap - df_bs_alt = [] - for agent in ["A", "B"]: - bs_mean_alt = stratified_bootstrap_simple(df[df["agent"] == agent], 1000) - bs_mean_df = pd.DataFrame(bs_mean_alt, columns=["cum_reward"]) - bs_mean_df["agent"] = agent - bs_mean_df["bootstrap_index"] = np.arange(1000) - df_bs_alt.append(bs_mean_df) - - df_bs_alt = pd.concat(df_bs_alt, ignore_index=True) - bs_mean_alt = df_bs_alt.groupby(["agent"])["cum_reward"].mean() - bs_std_alt = df_bs_alt.groupby(["agent"])["cum_reward"].std() - - # high relative tolerance because of small sample size - pd.testing.assert_series_equal(bs_mean, bs_mean_alt, rtol=1e-1, atol=0) - pd.testing.assert_series_equal(bs_std, bs_std_alt, rtol=1e-1, atol=0) - - mean_alt = df.groupby(["agent"])["cum_reward"].mean() - pd.testing.assert_series_equal(bs_mean, mean_alt, rtol=1e-1, atol=0) - - -def test_statistical_properties_array(): - arr = convert_df_to_array(df.groupby("task")) - bootstrap_results = bootstrap_matrix(arr, 1000, np.mean) - bs_mean = np.mean(bootstrap_results) - original_mean = np.mean(arr) - assert np.isclose(bs_mean, original_mean, rtol=1e-1, atol=0) - - -# Test with no variation -def test_with_no_var_array(): - df_no_var = df.copy() - df_no_var["cum_reward"] = 10 # Setting a constant value for no variation - arr_no_var = convert_df_to_array(df_no_var.groupby("task")) - bootstrap_results = bootstrap_matrix(arr_no_var, 1000, np.mean) - bs_mean = np.mean(bootstrap_results) - assert np.isclose(bs_mean, 10, rtol=1e-1, atol=0) - - -def test_convert_df_to_array(): - df_uneven = df.drop(7) - result = convert_df_to_array(df_uneven.groupby("task"), threshold=0.7) - assert result.shape == (2, 4) # 2 tasks, 4 samples each - assert np.array_equal(result[1, :], [12, 13, 16, 12]) - - -if __name__ == "__main__": - test_with_no_var_array() - test_statistical_properties_array() From c4387673489211da10d6fface3a8783d4868ee5b Mon Sep 17 00:00:00 2001 From: Thibault LSDC <78021491+ThibaultLSDC@users.noreply.github.com> Date: Sun, 24 Nov 2024 21:03:50 -0500 Subject: [PATCH 2/5] playwright install in readme (#151) --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index c11c3318..0a25790b 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,11 @@ AgentLab Features: pip install agentlab ``` +If not done already, install playwright: +```bash +playwright install +``` + Make sure to prepare the required benchmark according to instructions provided in the [setup column](#🎯-supported-benchmarks). From 2b27ee236393315e4752c92e82f0dceb20b3a9eb Mon Sep 17 00:00:00 2001 From: Alexandre Lacoste Date: Mon, 25 Nov 2024 12:28:21 -0500 Subject: [PATCH 3/5] Refine ux again (#150) * yet another way to kill timedout jobs * Improve timeout handling in task polling logic * Add method to override max_steps in Study class * add support for tab visibility in observation flags and update related components * fix tests * black * Improve timeout handling in task polling logic * yet another way to kill timedout jobs (#108) * Add method to override max_steps in Study class * add support for tab visibility in observation flags and update related components * fix tests * black * black * Fix sorting bug. improve directory content retrieval with summary statistics * fix test * black * tmp * add error report, add cum cost to summary and ray backend by default * displaying exp names in ray dashboard (#123) * displaying exp names in ray dashboard * fixing tests * enabling chat o_0 (#124) * sequential studies * little bug * more flexible requirement * imrove readme * Enhance agent configuration and logging in study setup - Updated `get_vision_agent` to append "_vision" to agent names. - Modified `BaseMessage.__str__` to include a no-warning option for logging. - Improved `make_study` function to accept single agent args and benchmark types. - Added detailed docstrings for better clarity on parameters and functionality. - Introduced `avg_step_timeout` and `demo_mode` attributes in the Study class. * get_text was added by mistake * Update README and Jupyter notebook with improved documentation and result analysis instructions * Update requirements to include Jupyter support for black * Update README.md * Fix formatting and improve clarity in README.md * Update README.md to enhance visuals and improve navigation * Add badges to README.md for PyPI, GitHub stars, and CI status * Add video demonstration to AgentXray section in README.md * test video * xray video test * Update AgentXray section in README.md with new asset link * minor * fix setup link ... again * remove upper case letter before getting the benchmark * minor * Update ReproducibilityAgent link in README.md for better accessibility --------- Co-authored-by: Maxime Gasse Co-authored-by: Thibault LSDC <78021491+ThibaultLSDC@users.noreply.github.com> --- README.md | 51 ++++++++++++++++++------------- src/agentlab/experiments/study.py | 4 +-- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 0a25790b..f37d9921 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ + @@ -13,23 +14,32 @@ [🤖 Make Your Own Agent](#-implement-a-new-agent)   |   [↻ Reproducibility](#-reproducibility)   |   +[![pypi](https://badge.fury.io/py/agentlab.svg)](https://pypi.org/project/agentlab/) [![PyPI - License](https://img.shields.io/pypi/l/agentlab?style=flat-square)]([https://opensource.org/licenses/MIT](http://www.apache.org/licenses/LICENSE-2.0)) [![PyPI - Downloads](https://img.shields.io/pypi/dm/agentlab?style=flat-square)](https://pypistats.org/packages/agentlab) [![GitHub star chart](https://img.shields.io/github/stars/ServiceNow/AgentLab?style=flat-square)](https://star-history.com/#ServiceNow/AgentLab) +[![Code Format](https://github.com/ServiceNow/AgentLab/actions/workflows/code_format.yml/badge.svg)](https://github.com/ServiceNow/AgentLab/actions/workflows/code_format.yml) +[![Tests](https://github.com/ServiceNow/AgentLab/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/ServiceNow/AgentLab/actions/workflows/unit_tests.yml) + + +[🛠️ Setup](#%EF%B8%8F-setup-agentlab)   |   +[🤖 Assistant](#-ui-assistant)   |   +[🚀 Launch Experiments](#-launch-experiments)   |   +[🔍 Analyse Results](#-analyse-results)   |   +  |   +[🤖 Build Your Agent](#-implement-a-new-agent)   |   +[↻ Reproducibility](#-reproducibility) - +https://github.com/ServiceNow/BrowserGym/assets/26232819/e0bfc788-cc8e-44f1-b8c3-0d1114108b85 AgentLab is a framework for developing and evaluating agents on a variety of -[benchmarks](#🎯-supported-benchmarks) supported by +[benchmarks](#-supported-benchmarks) supported by [BrowserGym](https://github.com/ServiceNow/BrowserGym). AgentLab Features: -* Easy large scale parallel [agent experiments](#🚀-launch-experiments) using [ray](https://www.ray.io/) +* Easy large scale parallel [agent experiments](#-launch-experiments) using [ray](https://www.ray.io/) * Building blocks for making agents over BrowserGym * Unified LLM API for OpenRouter, OpenAI, Azure, or self hosted using TGI. * Prefered way for running benchmarks like WebArena @@ -37,6 +47,7 @@ AgentLab Features: * Unified LeaderBoard (soon) ## 🎯 Supported Benchmarks + | Benchmark | Setup
Link | # Task
Template| Seed
Diversity | Max
Step | Multi-tab | Hosted Method | BrowserGym
Leaderboard | |-----------|------------|---------|----------------|-----------|-----------|---------------|----------------------| | [WebArena](https://webarena.dev/) | [setup](https://github.com/ServiceNow/BrowserGym/blob/main/browsergym/webarena/README.md) | 812 | None | 30 | yes | self hosted (docker) | soon | @@ -45,10 +56,11 @@ AgentLab Features: | [WorkArena](https://github.com/ServiceNow/WorkArena) L3 | [setup](https://github.com/ServiceNow/WorkArena?tab=readme-ov-file#getting-started) | 341 | High | 50 | no | demo instance | soon | | [WebLinx](https://mcgill-nlp.github.io/weblinx/) | - | 31586 | None | 1 | no | self hosted (dataset) | soon | | [VisualWebArena](https://github.com/web-arena-x/visualwebarena) | [setup](https://github.com/ServiceNow/BrowserGym/blob/main/browsergym/visualwebarena/README.md) | 910 | None | 30 | yes | self hosted (docker) | soon | -| [Assistant Bench](https://assistantbench.github.io/) | [setup](https://github.com/ServiceNow/BrowserGym/blob/main/browsergym/assistantbench/README.md) | 214 | None | 30 | yes | live web | soon | +| [AssistantBench](https://assistantbench.github.io/) | [setup](https://github.com/ServiceNow/BrowserGym/blob/main/browsergym/assistantbench/README.md) | 214 | None | 30 | yes | live web | soon | | [GAIA](https://huggingface.co/spaces/gaia-benchmark/leaderboard) (soon) | - | - | None | - | - | live web | soon | | [Mind2Web-live](https://huggingface.co/datasets/iMeanAI/Mind2Web-Live) (soon) | - | - | None | - | - | live web | soon | | [MiniWoB](https://miniwob.farama.org/index.html) | [setup](https://github.com/ServiceNow/BrowserGym/blob/main/browsergym/miniwob/README.md) | 125 | Medium | 10 | no | self hosted (static files) | soon | + ## 🛠️ Setup ```bash @@ -61,7 +73,7 @@ playwright install ``` Make sure to prepare the required benchmark according to instructions provided in the [setup -column](#🎯-supported-benchmarks). +column](#-supported-benchmarks). ```bash export AGENTLAB_EXP_ROOT= # defaults to $HOME/agentlab_results @@ -86,6 +98,7 @@ export AZURE_OPENAI_ENDPOINT= # if using azure models ## 🤖 UI-Assistant + Use an assistant to work for you (at your own cost and risk). ```bash @@ -178,23 +191,15 @@ result_df = inspect_results.load_result_df("path/to/your/study") ### AgentXray -Inspect the behaviour of your agent using xray. You can load previous or ongoing experiments. The refresh mechanism is currently a bit clunky, but you can refresh the page, refresh the experiment directory list and select again your experiment to see an updated version of your currently running experiments. +https://github.com/user-attachments/assets/06c4dac0-b78f-45b7-9405-003da4af6b37 +In a terminal, execute: ```bash agentlab-xray ``` -**⚠️ Note**: Gradio is still in developement and unexpected behavior have been frequently noticed. Version 5.5 seems to work properly so far. If you're not sure that the proper information is displaying, refresh the page and select your experiment again. - - - - - -You will be able to select the recent experiments in the directory `AGENTLAB_EXP_ROOT` and visualize +You can load previous or ongoing experiments in the directory `AGENTLAB_EXP_ROOT` and visualize the results in a gradio interface. In the following order, select: @@ -206,6 +211,10 @@ In the following order, select: Once this is selected, you can see the trace of your agent on the given task. Click on the profiling image to select a step and observe the action taken by the agent. + +**⚠️ Note**: Gradio is still in developement and unexpected behavior have been frequently noticed. Version 5.5 seems to work properly so far. If you're not sure that the proper information is displaying, refresh the page and select your experiment again. + + ## 🤖 Implement a new Agent Get inspiration from the `MostBasicAgent` in @@ -213,7 +222,7 @@ Get inspiration from the `MostBasicAgent` in For a better integration with the tools, make sure to implement most functions in the [AgentArgs](src/agentlab/agents/agent_args.py#L5) API and the extended `bgym.AbstractAgentArgs`. -If you think your agent should be included directly in AgenLab, let use know and it can be added in +If you think your agent should be included directly in AgenLab, let us know and it can be added in agentlab/agents/ with the name of your agent. ## ↻ Reproducibility @@ -243,7 +252,7 @@ dynamic benchmarks. * **Reproduced results in the leaderboard**. For agents that are repdocudibile, we encourage users to try to reproduce the results and upload them to the leaderboard. There is a special column containing information about all reproduced results of an agent on a benchmark. -* **ReproducibilityAgent**: You can run this agent on an existing study and it will try to re-run +* **ReproducibilityAgent**: [You can run this agent](src/agentlab/agents/generic_agent/reproducibility_agent.py) on an existing study and it will try to re-run the same actions on the same task seeds. A vsiual diff of the two prompts will be displayed in the AgentInfo HTML tab of AgentXray. You will be able to inspect on some tasks what kind of changes between to two executions. **Note**: this is a beta feature and will need some adaptation for your diff --git a/src/agentlab/experiments/study.py b/src/agentlab/experiments/study.py index b369b540..c8c16d98 100644 --- a/src/agentlab/experiments/study.py +++ b/src/agentlab/experiments/study.py @@ -76,7 +76,7 @@ def make_study( agent_args = [agent_args] if isinstance(benchmark, str): - benchmark = bgym.DEFAULT_BENCHMARKS[benchmark]() + benchmark = bgym.DEFAULT_BENCHMARKS[benchmark.lower()]() if "webarena" in benchmark.name and len(agent_args) > 1: logger.warning( @@ -220,7 +220,7 @@ def __post_init__(self): """Initialize the study. Set the uuid, and generate the exp_args_list.""" self.uuid = uuid.uuid4() if isinstance(self.benchmark, str): - self.benchmark = bgym.DEFAULT_BENCHMARKS[self.benchmark]() + self.benchmark = bgym.DEFAULT_BENCHMARKS[self.benchmark.lower()]() if isinstance(self.dir, str): self.dir = Path(self.dir) self.make_exp_args_list() From 7e2263b11d00a370969a16f1460a0c1819e7d889 Mon Sep 17 00:00:00 2001 From: recursix Date: Mon, 25 Nov 2024 13:49:09 -0500 Subject: [PATCH 4/5] black --- src/agentlab/analyze/inspect_results.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/agentlab/analyze/inspect_results.py b/src/agentlab/analyze/inspect_results.py index d48ef88e..6dc3c3fc 100644 --- a/src/agentlab/analyze/inspect_results.py +++ b/src/agentlab/analyze/inspect_results.py @@ -211,7 +211,6 @@ def report_constant_and_variables(df, show_stack_traces=True): print(f" ...\n") - def get_std_err(df, metric): """Get the standard error for a binary metric.""" # extract non missing values @@ -439,7 +438,6 @@ def _rename_bool_flags(report: pd.DataFrame, true_str="✓", false_str="-"): return report - def flag_report(report: pd.DataFrame, metric: str = "avg_reward", round_digits: int = 2): # for all index in the multi-index with boolean value, get the average for # True and the average for False separately. Produce a new dataframe with From 416cedd8dd8e85de3f07724bc52c7c678d2c9eda Mon Sep 17 00:00:00 2001 From: recursix Date: Mon, 25 Nov 2024 13:56:32 -0500 Subject: [PATCH 5/5] remove dask --- tests/experiments/test_dask.py | 41 ---------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 tests/experiments/test_dask.py diff --git a/tests/experiments/test_dask.py b/tests/experiments/test_dask.py deleted file mode 100644 index 39822634..00000000 --- a/tests/experiments/test_dask.py +++ /dev/null @@ -1,41 +0,0 @@ -from agentlab.experiments.graph_execution_dask import execute_task_graph, make_dask_client -from agentlab.experiments.exp_utils import MockedExpArgs - -TASK_TIME = 3 - - -def test_execute_task_graph(): - # Define a list of ExpArgs with dependencies - exp_args_list = [ - MockedExpArgs(exp_id="task1", depends_on=[]), - MockedExpArgs(exp_id="task2", depends_on=["task1"]), - MockedExpArgs(exp_id="task3", depends_on=["task1"]), - MockedExpArgs(exp_id="task4", depends_on=["task2", "task3"]), - ] - - with make_dask_client(n_worker=5): - results = execute_task_graph(exp_args_list) - - exp_args_list = [results[task_id] for task_id in ["task1", "task2", "task3", "task4"]] - - # Verify that all tasks were executed in the proper order - assert exp_args_list[0].start_time < exp_args_list[1].start_time - assert exp_args_list[0].start_time < exp_args_list[2].start_time - assert exp_args_list[1].end_time < exp_args_list[3].start_time - assert exp_args_list[2].end_time < exp_args_list[3].start_time - - # # Verify that parallel tasks (task2 and task3) started within a short time of each other - # parallel_start_diff = abs(exp_args_list[1].start_time - exp_args_list[2].start_time) - # print(f"parallel_start_diff: {parallel_start_diff}") - # assert parallel_start_diff < 1.5 # Allow for a small delay - - # Ensure that the entire task graph took the expected amount of time - total_time = exp_args_list[-1].end_time - exp_args_list[0].start_time - assert ( - total_time >= TASK_TIME * 3 - ) # Since the critical path involves at least 1.5 seconds of work - - -if __name__ == "__main__": - test_execute_task_graph() - # test_add_dependencies()