{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 136,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.rcParams[\"font.family\"] = \"Times New Roman\"\n",
    "plt.rcParams[\"font.size\"] = 16\n",
    "\n",
    "g_label_fontsize = 16\n",
    "\n",
    "colors = [\n",
    "    \"#999999\",\n",
    "    \"#FF9999\",\n",
    "]\n",
    "\n",
    "hatches = [\"\\\\\", \"x\", \"+\", \"/\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 137,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 65392 characters]",
      "text/plain": [
       "<Figure size 4200x1050 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots(\n",
    "    figsize=(14, 14 / 4), ncols=1, nrows=1, constrained_layout=True, dpi=300\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "metadata": {},
   "outputs": [],
   "source": [
    "data_a = {\n",
    "    \"8TP(Vanilla)+2DP#16GPUs\": [3.33, 3.025], \n",
    "    \"8TP(MicroBatch)+2DP#16GPUs\": [3.88, 3.03], \n",
    "    \"2TP+4FSDP#8GPUs\": [3.02, 2.85], \n",
    "    \"8TP#16GPUs\": [2.98, 2.81] \n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 144,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.09159159159159164\n",
      "0.21907216494845363\n",
      "0.056291390728476796\n",
      "0.057046979865771785\n"
     ]
    }
   ],
   "source": [
    "for k, vs in data_a.items():\n",
    "    print((vs[0] - vs[1]) / vs[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 139,
   "metadata": {},
   "outputs": [],
   "source": [
    "legend_labels = [\"FSDP\", \"DLRover-Lynx\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 140,
   "metadata": {},
   "outputs": [],
   "source": [
    "bar_width = 0.2\n",
    "group_spaing = 0.15\n",
    "\n",
    "group_positions = {}\n",
    "current_pos = 0\n",
    "\n",
    "for x_label, y_data in data_a.items():\n",
    "    group_positions[x_label] = []\n",
    "    for i in range(len(y_data)):\n",
    "        group_positions[x_label].append(current_pos)\n",
    "        current_pos += bar_width\n",
    "    current_pos += group_spaing\n",
    "\n",
    "group_centers = {}\n",
    "for x_label, positions in group_positions.items():\n",
    "    group_centers[x_label] = sum(positions) / len(positions)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 141,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(13.333333333333346, 0.5, 'ITERATION TIME (S)')"
      ]
     },
     "execution_count": 141,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "label_set = set()\n",
    "for x_label, y_data in data_a.items():\n",
    "    positions = group_positions[x_label]\n",
    "    for i, (pos, value, color, hatch, label) in enumerate(\n",
    "        zip(positions, y_data, colors, hatches, legend_labels)\n",
    "    ):\n",
    "        if label in label_set:\n",
    "            local_label = None\n",
    "        else:\n",
    "            local_label = label\n",
    "            label_set.add(label)\n",
    "        ax.bar(\n",
    "            pos,\n",
    "            value,\n",
    "            width=bar_width,\n",
    "            color=color,\n",
    "            edgecolor=\"black\",\n",
    "            hatch=hatch,\n",
    "            label=local_label,\n",
    "        )\n",
    "\n",
    "ax.set_xticks(list(group_centers.values()))\n",
    "ax.set_xticklabels(list(data_a.keys()))\n",
    "\n",
    "ax.set_ylim(0, 4.5)\n",
    "ax.set_yticks([0, 1, 2, 3, 4])\n",
    "ax.set_yticklabels(\n",
    "    [\"0\", \"1\", \"2\", \"3\", \"4\"], rotation=90, ha=\"center\", va=\"center\"\n",
    ")\n",
    "\n",
    "ax.tick_params(axis=\"x\", bottom=False, labelsize=g_label_fontsize, pad=1)\n",
    "ax.tick_params(axis=\"y\", left=True, labelsize=g_label_fontsize, pad=5)\n",
    "\n",
    "ax.set_ylabel(\"ITERATION TIME (S)\", fontsize=g_label_fontsize)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 142,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7f9948d403e0>"
      ]
     },
     "execution_count": 142,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fig.legend(\n",
    "    ncol=2,\n",
    "    loc=\"upper center\",\n",
    "    frameon=True,\n",
    "    shadow=False,\n",
    "    bbox_to_anchor=(0.5, 1.14),\n",
    "    fontsize=g_label_fontsize,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 240380 characters]",
      "text/plain": [
       "<Figure size 4200x1050 with 1 Axes>"
      ]
     },
     "execution_count": 143,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fig.savefig(\"lynx_hybrid_parallel_nfsc.pdf\", bbox_inches=\"tight\", dpi=1000)\n",
    "fig"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
