{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "1aa3ee04-09e1-4278-94de-b047a73b6c44",
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import clear_output\n",
    "import ipywidgets as wdg\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import json\n",
    "from uk_covid19 import Cov19API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "253fb2f6-d4b0-4dbf-8ef6-4f378e4dae4a",
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "# make figures larger\n",
    "plt.rcParams['figure.dpi'] = 100"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "fa161876-b8fc-44ce-a60d-f6779542a5b0",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(\"mydata.json\", \"rt\") as INFILE:\n",
    "    data=json.load(INFILE)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "ad30dde5-07f5-4a3d-b5eb-d2b7ed8f9ed5",
   "metadata": {},
   "outputs": [],
   "source": [
    "def access_api():\n",
    "    \"\"\" Accesses the PHE API. Returns raw data in the same format as data loaded from the \"canned\" JSON file. \"\"\"\n",
    "    filters = [\n",
    "        'areaType=nation',\n",
    "        'areaName=England'\n",
    "    ]\n",
    "    deaths = {\n",
    "       \"date\":\"date\",\n",
    "        \"newDailyNsoDeathsByDeathDate\":\"newDailyNsoDeathsByDeathDate\",\n",
    "        \"newDeaths28DaysByDeathDateChange\":\"newDeaths28DaysByDeathDateChange\",\n",
    "        \"cumPeopleVaccinatedCompleteByVaccinationDate\":\"cumPeopleVaccinatedCompleteByVaccinationDate\"\n",
    "    }\n",
    "    api = Cov19API(filters=filters, structure=deaths)\n",
    "    mydata=api.get_json()\n",
    "   # print(mydata)\n",
    "    #data.to_pickle(\"mydata.pkl\")\n",
    "    #convert(mydata)\n",
    "    return mydata # return data read from the API\n",
    "\n",
    "def convert(whatever):\n",
    "    with open(\"mydata.json\", \"wt\") as OUTF:\n",
    "        json.dump(whatever, OUTF)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "611ee042-1d4d-485d-ae8c-d81438a3219d",
   "metadata": {},
   "outputs": [],
   "source": [
    "def wrangle_data(rawdata):\n",
    "    datalist=data['data']\n",
    "\n",
    "    dates=[dictionary['date'] for dictionary in datalist ]\n",
    "    dates.sort()\n",
    "\n",
    "    def parse_date(datestring):\n",
    "        \"\"\" Convert a date string into a pandas datetime object \"\"\"\n",
    "        return pd.to_datetime(datestring, format=\"%Y-%m-%d\")\n",
    "\n",
    "\n",
    "    startdate=parse_date(dates[0])\n",
    "    enddate=parse_date(dates[-1])\n",
    "\n",
    "\n",
    "    index=pd.date_range(startdate, enddate, freq='D')\n",
    "    patdata=pd.DataFrame(index=index, columns=['newDailyNsoDeathsByDeathDate', 'newDeaths28DaysByDeathDateChange', 'cumPeopleVaccinatedCompleteByVaccinationDate'])\n",
    "\n",
    "    for entry in datalist: # each entry is a dictionary with date, cases, hospital and deaths\n",
    "        date=parse_date(entry['date'])\n",
    "        for column in ['newDailyNsoDeathsByDeathDate', 'newDeaths28DaysByDeathDateChange', 'cumPeopleVaccinatedCompleteByVaccinationDate']:\n",
    "            # check that nothing is there yet - just in case some dates are duplicated,\n",
    "            # maybe with data for different columns in each entry\n",
    "            if pd.isna(patdata.loc[date, column]): \n",
    "                # replace None with 0 in our data \n",
    "                value= float(entry[column]) if entry[column]!=None else 0.0\n",
    "                # this is the way you access a specific location in the dataframe - use .loc\n",
    "                # and put index,column in a single set of [ ]\n",
    "                patdata.loc[date, column]=value\n",
    "            \n",
    "    patdata.fillna(0.0, inplace=True)\n",
    "    return patdata\n",
    "\n",
    "\n",
    "# putting the wrangling code into a function allows you to call it again after refreshing the data through \n",
    "# the API. You should call the function directly on the JSON data when the dashboard starts, by including \n",
    "# the call in the cell as below:\n",
    "patdata=wrangle_data(data) # df is the dataframe for plotting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "id": "2302aa9e-cf6a-4c9b-86a3-527caa1af49b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "996d7680ae8042c8a62aa30b9dc8ceff",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Button(button_style='info', description='Refresh data', icon='download', style=ButtonStyle(), tooltip='Keep ca…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Printout from this function will be lost in Voila unless captured in an\n",
    "# output widget - therefore, we give feedback to the user by changing the \n",
    "# appearance of the button\n",
    "def api_button_callback(button):\n",
    "    \"\"\" Button callback - it must take the button as its parameter (unused in this case).\n",
    "    Accesses API, wrangles data, updates global variable df used for plotting. \"\"\"\n",
    "    apidata=access_api()\n",
    "    global df\n",
    "    df=wrangle_data(apidata)\n",
    "    refresh_graph()\n",
    "    apibutton.icon=\"check\"\n",
    "\n",
    "    \n",
    "apibutton=wdg.Button(\n",
    "    description='Refresh data',\n",
    "    disabled=False,\n",
    "    button_style='info',\n",
    "    tooltip=\"Keep calm and carry on\",\n",
    "    icon='download'\n",
    ")\n",
    "\n",
    "# remember to register your button callback function with the button\n",
    "apibutton.on_click(api_button_callback) # the name of your function inside these brackets\n",
    "\n",
    "display(apibutton)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "id": "27f4771b-c987-4c45-971d-d746fa2cc69f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "583376c6524247659ff90a98cee173ca",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "SelectMultiple(description='Test stats:', index=(2,), layout=Layout(width='max-content'), options=('newDailyNs…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4a3bf98280f641a0b4641b9dbe896551",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Output()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot(data):\n",
    "    patdata=data\n",
    "    patdata.plot( logy=True)\n",
    "    patdata.plot( logx=True, logy=True, kind='scatter', y=['newDailyNsoDeathsByDeathDate'], x=['cumPeopleVaccinatedCompleteByVaccinationDate'])\n",
    "\n",
    "    agecols=wdg.SelectMultiple(\n",
    "        options=['newDailyNsoDeathsByDeathDate', 'newDeaths28DaysByDeathDateChange', 'cumPeopleVaccinatedCompleteByVaccinationDate'], # options available\n",
    "        value=['cumPeopleVaccinatedCompleteByVaccinationDate'], # initial value\n",
    "        rows=3, # rows of the selection box\n",
    "        description='Test stats:',\n",
    "        disabled=False,\n",
    "        layout={'width': 'max-content'}\n",
    ")\n",
    "\n",
    "def patdata_graph(graphcolumns):\n",
    "    # our callback function.\n",
    "    ncols=len(graphcolumns)\n",
    "    if ncols>0:\n",
    "        patdata.plot(logy=True,  y=list(graphcolumns)) # graphcolumns is a tuple - we need a list\n",
    "        plt.show() # important - graphs won't update properly if this is missing\n",
    "    else:\n",
    "        # if the user has not selected any column, print a message instead\n",
    "        print(\"Click to select data for graph\")\n",
    "        print(\"(CTRL-Click to select more than one category)\")\n",
    "    \n",
    "# keep calling age_graph(graphcolumns=value_of_agecols); capture output in widget output    \n",
    "output=wdg.interactive_output(patdata_graph, {'graphcolumns': agecols})\n",
    "\n",
    "def refresh_graph():\n",
    "    \"\"\" We change the value of the widget in order to force a redraw of the graph;\n",
    "    this is useful when the data have been updated. This is a bit of a gimmick; it\n",
    "    needs to be customised for one of your widgets. \"\"\"\n",
    "    current=agecols.value\n",
    "    if current==agecols.options[2]:\n",
    "        other=agecols.options[1]\n",
    "    elif current==agecols.options[1]:\n",
    "        other=agecols.options[0]\n",
    "    else:\n",
    "        other=agecols.options[2]\n",
    "    agecols.value=other # forces the redraw\n",
    "    agecols.value=current # now we can change it back\n",
    "\n",
    "\n",
    "\n",
    "graph=wdg.interactive_output(plot, {'daata': agecols})\n",
    "\n",
    "display(agecols, output)\n",
    "\n",
    "patdata.to_pickle(\"patdata.pkl\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}