{ "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 }