{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Практическое задание 1\n",
    "\n",
    "На примере анализа и перепроектировании модели визуализации рассмотрим инфографику, представленную в отчёте Программы международной оценки (Pisa) за 2012 год. Данная инфографика, представлена на рисунке 1. Она показывает результаты прохождения детьми 15-ти лет из различных стран и регионов тестов по математике, навыкам чтения и естественным наукам. \n",
    "\n",
    "<center>\n",
    "<img src=\"./initial.png\" />\n",
    "\n",
    "Рисунок 1. Результаты Pisa 2012 - как соотносятся результаты по странам и предметам\n",
    "</center>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 205296 characters]",
      "text/plain": [
       "<Figure size 1600x1169 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%reset -f\n",
    "\n",
    "import pandas as pd\n",
    "from matplotlib import pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "subjects = [\"Maths\", \"Reading\", \"Science\"]\n",
    "\n",
    "data = pd.read_csv(\"./practice1.csv\", names=[\"country\", *subjects])\n",
    "\n",
    "country_codes = pd.read_csv(\"./country_codes.csv\", names=[\"country\", \"code\"])\n",
    "\n",
    "data = data.merge(country_codes, how=\"outer\", on=\"country\")\n",
    "\n",
    "data = data.dropna(subset=subjects)\n",
    "\n",
    "data[\"Average of three subjects\"] = data.loc[:, subjects].mean(axis=1)\n",
    "\n",
    "data = data.sort_values(by=\"Average of three subjects\", ascending=False, ignore_index=True)\n",
    "\n",
    "data.to_csv(\"res.csv\", index=False, header=False)\n",
    "\n",
    "if data[data[\"code\"].isna()].size != 0:\n",
    "    raise ValueError(\"NaN country code\")\n",
    "\n",
    "fig, ax = plt.subplots(nrows=4)\n",
    "\n",
    "fig.set_size_inches(16, 11.69)\n",
    "\n",
    "# colors=(\"#ef476f\", \"#ffd166\", \"#06d6a0\", \"#118ab2\", \"#073B4C\")\n",
    "\n",
    "colors=(\"tab:blue\", \"tab:orange\", \"tab:green\", \"tab:red\", \"tab:grey\")\n",
    "\n",
    "for i, subj in enumerate((*subjects, \"Average of three subjects\")):\n",
    "    sdata = data.sort_values(by=subj, ascending=False, ignore_index=True)\n",
    "    positions = np.array([str(sdata[sdata[\"code\"] == code].index[0]+1) for code in data[\"code\"]])\n",
    "\n",
    "    x = data[\"code\"] + \"\\n\" + positions\n",
    "\n",
    "    bar = ax[i].bar(x, data[subj], color=colors[i])\n",
    "\n",
    "    bar_labels = list(map(lambda j: str(int(data[subj][data.index[j]])) if data[\"code\"][data.index[j]] == \"UK\" else \"\", range(len(data.index))))\n",
    "\n",
    "    ax[i].bar_label(bar, labels=bar_labels, weight=\"bold\", padding=5)\n",
    "\n",
    "    ax[i].set_title(subj)\n",
    "\n",
    "    ax[i].set_ylabel(\"Score\")\n",
    "\n",
    "    ax[i].autoscale(tight=True)\n",
    "\n",
    "    ax[i].set_ylim(350)\n",
    "\n",
    "    mean = int(data[subj].mean())\n",
    "\n",
    "    ax[i].set_yticks(list(set((*ax[i].get_yticks(), mean, 650))))\n",
    "\n",
    "    ax[i].xaxis.set_tick_params(labelbottom=True)\n",
    "\n",
    "    for label in ax[i].get_xticklabels():\n",
    "        if \"UK\" in label.get_text():\n",
    "            label.set(fontweight=\"bold\")\n",
    "\n",
    "    for label in ax[i].get_yticklabels():\n",
    "        if label.get_text() == str(mean):\n",
    "            label.set(fontweight=\"bold\")\n",
    "            label.set_text(f\"avg: {mean}\")\n",
    "\n",
    "    ax[i].hlines([mean], 0, 1, transform=ax[i].get_yaxis_transform(), color=colors[-1], label=\"Average score for subject\")\n",
    "\n",
    "    ax[i].spines['top'].set_visible(False)\n",
    "    ax[i].spines['right'].set_visible(False)\n",
    "\n",
    "ax[0].legend()\n",
    "ax[-1].set_xlabel(\"Country code (ISO 3166-1) and overall average ranking\")\n",
    "\n",
    "fig.suptitle(\"Pisa 2012 test scores\", x=0.52)\n",
    "plt.figtext(0.01, 0.014, \"Source: OECD, PISA 2012 DATABASE\")\n",
    "\n",
    "fig.tight_layout()\n",
    "\n",
    "for i in range(3):\n",
    "    ax[i].text(-3, 295, \"Ranking\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%reset -f\n",
    "\n",
    "import pandas as pd\n",
    "from matplotlib import pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "subjects = [\"Maths\", \"Reading\", \"Science\"]\n",
    "\n",
    "data = pd.read_csv(\"./practice1.csv\", names=[\"country\", *subjects])\n",
    "\n",
    "country_codes = pd.read_csv(\"./country_codes.csv\", names=[\"country\", \"code\"])\n",
    "\n",
    "data = data.merge(country_codes, how=\"outer\", on=\"country\")\n",
    "\n",
    "data = data.dropna(subset=subjects)\n",
    "\n",
    "data[\"Average of three subjects\"] = data.loc[:, subjects].mean(axis=1)\n",
    "\n",
    "data = data.sort_values(by=\"Average of three subjects\", ascending=False)\n",
    "\n",
    "data.to_csv(\"res.csv\", index=False, header=False)\n",
    "\n",
    "if data[data[\"code\"].isna()].size != 0:\n",
    "    raise ValueError(\"NaN country code\")\n",
    "\n",
    "fig, ax = plt.subplots(ncols=4)\n",
    "\n",
    "fig.set_size_inches(16, 11.69)\n",
    "\n",
    "positions = np.array(list(map(str,range(1, len(data.index)+1))))\n",
    "\n",
    "x = data[\"code\"] + \" \" + positions\n",
    "\n",
    "# colors=(\"#ef476f\", \"#ffd166\", \"#06d6a0\", \"#118ab2\", \"#073B4C\")\n",
    "\n",
    "colors=(\"tab:blue\", \"tab:orange\", \"tab:green\", \"tab:red\", \"tab:grey\")\n",
    "\n",
    "for i, subj in enumerate((*subjects, \"Average of three subjects\")):\n",
    "    bar = ax[i].barh(x[::-1], data[subj][::-1], color=colors[i])\n",
    "\n",
    "    bar_labels = list(map(lambda j: str(int(data[subj][data.index[j]])) if data[\"code\"][data.index[j]] == \"UK\" else \"\", range(len(data.index))))\n",
    "\n",
    "    ax[i].bar_label(bar, labels=bar_labels, weight=\"bold\", padding=5)\n",
    "\n",
    "    ax[i].set_title(subj)\n",
    "\n",
    "    ax[i].set_ylabel(\"Country code (ISO 3166-1) and ranking\")\n",
    "    ax[i].set_xlabel(\"Score\")\n",
    "\n",
    "    ax[i].autoscale(tight=True)\n",
    "\n",
    "    ax[i].set_xlim(350)\n",
    "\n",
    "    mean = int(data[subj].mean())\n",
    "\n",
    "    ax[i].set_xticks((*range(350, 650+1, 100), mean))\n",
    "\n",
    "    for label in ax[i].get_yticklabels():\n",
    "        if \"UK\" in label.get_text():\n",
    "            label.set(fontweight=\"bold\")\n",
    "\n",
    "    for label in ax[i].get_xticklabels():\n",
    "        if label.get_text() == str(mean):\n",
    "            label.set(fontweight=\"bold\")\n",
    "            label.set_text(f\"avg: {mean}\")\n",
    "\n",
    "    ax[i].vlines([mean], 0, 1, transform=ax[i].get_xaxis_transform(), color=colors[-1], label=\"Average score of this subject\")\n",
    "\n",
    "    ax[i].spines['top'].set_visible(False)\n",
    "    ax[i].spines['right'].set_visible(False)\n",
    "\n",
    "ax[0].legend()\n",
    "\n",
    "fig.suptitle(\"Pisa 2012 test scores\")\n",
    "plt.figtext(0.01, 0, \"Source: OECD, PISA 2012 DATABASE\")\n",
    "\n",
    "fig.tight_layout()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "indexes = (*range(5), *range(18, 23), *range(60, 65))\n",
    "countries = [data[\"country\"][data.index[i]] + '\\n' + str(i+1) + (\"st\" if (i%10==0 and i!=10) else \"nd\" if (i%10==1 and i!=11) else \"rd\" if (i%10==2 and i!=12) else \"th\") for i in indexes]\n",
    "tests = {subj: [data[subj][data.index[i]] for i in indexes] for subj in subjects}\n",
    "\n",
    "fig, ax = plt.subplots(constrained_layout=True)\n",
    "\n",
    "fig.set_size_inches(19, 5)\n",
    "\n",
    "x = np.arange(len(countries))\n",
    "width = 0.25\n",
    "\n",
    "for i, subj in enumerate(subjects):\n",
    "    offset= width*i\n",
    "    bar = ax.bar(x+offset, tests[subj], width, label=subj)\n",
    "    ax.bar_label(bar, padding=3)\n",
    "    \n",
    "    # ax.plot((0, x[-1]*width*4+width*2), [data[subj].mean()]*2, color=colors[i], linewidth=3, label=subj+\" average\")\n",
    "\n",
    "ax.legend()\n",
    "\n",
    "ax.set_title(\"Pisa 2012 test scores\", pad=10)\n",
    "\n",
    "ax.set_xticks(x+width, countries)\n",
    "ax.set_xlabel(\"Country and its ranking sorted by average of three subjects\")\n",
    "\n",
    "for label in ax.get_xticklabels():\n",
    "    if \"UK\" in label.get_text():\n",
    "        label.set(fontweight=\"bold\")\n",
    "\n",
    "ax.autoscale(tight=True)\n",
    "ax.set_ylim(350)\n",
    "\n",
    "ax2 = ax.secondary_xaxis('top')\n",
    "ax2.set_xticks(np.arange(3)*5+width*9, [\"Top of the class\", \"UK\", \"Need to work\"])\n",
    "ax2.tick_params(top=False)\n",
    "ax2.set_frame_on(False)\n",
    "\n",
    "ax.get_yaxis().set_visible(False)\n",
    "ax.spines[['left', 'top', 'right']].set_visible(False)\n",
    "\n",
    "ax.vlines([i+width*3 for i in (4, 9)], 0, 1, transform=ax.get_xaxis_transform(), linestyles='dashed', colors='#b0b0b0', linewidth=0.5)\n",
    "\n",
    "plt.figtext(0.013, 0, \"Source: OECD, PISA 2012 DATABASE\")\n",
    "\n",
    "fig.tight_layout()"
   ]
  }
 ],
 "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.10.9 (main, Dec 19 2022, 17:35:49) [GCC 12.2.0]"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "790cd746b2da0ff3eb9bbf387c60cee7631d987c0703af7e1ad95fb6ee31bd6e"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
