In [0]:
!pip install -U plotly
!pip install dash
!pip install dash-html-components
!pip install dash-core-components
!pip install dash-table
!pip install dash_bootstrap_components
!pip install pycountry
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import os
import plotly
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px
import imageio
import time
import dash
import dash_core_components as dcc
import dash_html_components as html
from flask import request
import json
import pycountry
from google.colab import drive
from os.path import join
ROOT = '/content/drive'
PROJ = 'My Drive/Coronavirus/coronavirus-data/data'
GIT_USERNAME = "jvonk"
GIT_TOKEN = "b8d5c3aa010122878932823b884f9a35e770b78f"
GIT_REPOSITORY = "coronavirus-data"
drive.mount(ROOT)
PROJECT_PATH = join(ROOT, PROJ)
!mkdir "{PROJECT_PATH}"
GIT_PATH = f"https://{GIT_TOKEN}@github.com/{GIT_USERNAME}/{GIT_REPOSITORY}.git"
!mkdir ./temp
!git clone "{GIT_PATH}"
!mv ./temp/* "{PROJECT_PATH}"
!rm -rf ./temp
%cd "{PROJECT_PATH}"
if not os.path.isfile("ngrok"):
!wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
!unzip ngrok-stable-linux-amd64.zip
In [0]:
!git config --global user.email "johan.d.s.vonk@gmail.com"
!git config --global user.name "Johan Vonk"
In [0]:
processed = os.path.isfile("processed.xlsx")
!wget -N https://raw.github.com/Perishleaf/data-visualisation-scripts/master/dash-2019-coronavirus/data.xls
xl_file = pd.ExcelFile('processed.xlsx' if processed else 'data.xls',)
dfs = {sheet_name: xl_file.parse(sheet_name) for sheet_name in xl_file.sheet_names}
if not processed:
dfs = {xl_file.sheet_names[key]:dfs[xl_file.sheet_names[key]] for key in range(len(xl_file.sheet_names)) if xl_file.sheet_names[key-1][:10] != xl_file.sheet_names[key][:10]}
keyList = list(dfs.keys());
In [0]:
if not processed:
GeoDB = pd.read_csv('coordinatesDB.csv')
with pd.ExcelWriter('processed.xlsx') as writer, open('name_to_alpha_2.json') as first, open('iso3.json') as second:
name_to_alpha_2=json.loads(first.read())
alpha_2_to_3=json.loads(second.read())
for key, df in dfs.items():
dfs[key].loc[:,'Confirmed'].fillna(value=0, inplace=True)
dfs[key].loc[:,'Deaths'].fillna(value=0, inplace=True)
dfs[key].loc[:,'Recovered'].fillna(value=0, inplace=True)
dfs[key]=dfs[key].astype({'Confirmed':'int64', 'Deaths':'int64', 'Recovered':'int64'})
# Change as China for coordinate search
dfs[key]=dfs[key].replace({'Country/Region':'Mainland China'}, 'China')
dfs[key]=dfs[key].replace({'Province/State':'Queensland'}, 'Brisbane')
dfs[key]=dfs[key].replace({'Province/State':'New South Wales'}, 'Sydney')
dfs[key]=dfs[key].replace({'Province/State':'Victoria'}, 'Melbourne')
dfs[key] = pd.merge(dfs[key], GeoDB, how='left', on=['Province/State', 'Country/Region'] )
dfs[key]['Days_since_start'] = [(datetime.strptime(d, '%m/%d/%Y %H:%M')-(datetime.strptime('2020-01-21 00:00:00','%Y-%m-%d %H:%M:%S'))).days for d in ('0' + dfs[key]['Last Update'])]
dfs[key]['iso_alpha']=[alpha_2_to_3[name_to_alpha_2[country]] if country in name_to_alpha_2 else None for country in dfs[key]['Country/Region']]
dfs[key].to_excel(writer,sheet_name=key)
In [0]:
print(os.getcwd())
!wget -N "https://population.un.org/wpp/Download/Files/1_Indicators%20(Standard)/EXCEL_FILES/1_Population/WPP2019_POP_F01_1_TOTAL_POPULATION_BOTH_SEXES.xlsx"
population_xl = pd.ExcelFile('WPP2019_POP_F01_1_TOTAL_POPULATION_BOTH_SEXES.xlsx')
num_to_alpha={"4":"af","8":"al","10":"aq","12":"dz","16":"as","20":"ad","24":"ao","28":"ag","31":"az","32":"ar","36":"au","40":"at","44":"bs","48":"bh","50":"bd","51":"am","52":"bb","56":"be","60":"bm","64":"bt","68":"bo","70":"ba","72":"bw","74":"bv","76":"br","84":"bz","86":"io","90":"sb","92":"vg","96":"bn","100":"bg","104":"mm","108":"bi","112":"by","116":"kh","120":"cm","124":"ca","132":"cv","136":"ky","140":"cf","144":"lk","148":"td","152":"cl","156":"cn","158":"tw","162":"cx","166":"cc","170":"co","174":"km","175":"yt","178":"cg","180":"cd","184":"ck","188":"cr","191":"hr","192":"cu","196":"cy","203":"cz","204":"bj","208":"dk","212":"dm","214":"do","218":"ec","222":"sv","226":"gq","231":"et","232":"er","233":"ee","234":"fo","238":"fk","239":"gs","242":"fj","246":"fi","248":"ax","249":"fx","250":"fr","254":"gf","258":"pf","260":"tf","262":"dj","266":"ga","268":"ge","270":"gm","275":"ps","276":"de","288":"gh","292":"gi","296":"ki","300":"gr","304":"gl","308":"gd","312":"gp","316":"gu","320":"gt","324":"gn","328":"gy","332":"ht","334":"hm","336":"va","340":"hn","344":"hk","348":"hu","352":"is","356":"in","360":"id","364":"ir","368":"iq","372":"ie","376":"il","380":"it","384":"ci","388":"jm","392":"jp","398":"kz","400":"jo","404":"ke","408":"kp","410":"kr","414":"kw","417":"kg","418":"la","422":"lb","426":"ls","428":"lv","430":"lr","434":"ly","438":"li","440":"lt","442":"lu","446":"mo","450":"mg","454":"mw","458":"my","462":"mv","466":"ml","470":"mt","474":"mq","478":"mr","480":"mu","484":"mx","492":"mc","496":"mn","498":"md","499":"me","500":"ms","504":"ma","508":"mz","512":"om","516":"na","520":"nr","524":"np","528":"nl","530":"an","533":"aw","540":"nc","548":"vu","554":"nz","558":"ni","562":"ne","566":"ng","570":"nu","574":"nf","578":"no","580":"mp","581":"um","583":"fm","584":"mh","585":"pw","586":"pk","591":"pa","598":"pg","600":"py","604":"pe","608":"ph","612":"pn","616":"pl","620":"pt","624":"gw","626":"tl","630":"pr","634":"qa","638":"re","642":"ro","643":"ru","646":"rw","654":"sh","659":"kn","660":"ai","662":"lc","666":"pm","670":"vc","674":"sm","678":"st","682":"sa","686":"sn","688":"rs","690":"sc","694":"sl","702":"sg","703":"sk","704":"vn","705":"si","706":"so","710":"za","716":"zw","724":"es","728":"ss","729":"sd","732":"eh","736":"sd","740":"sr","744":"sj","748":"sz","752":"se","756":"ch","760":"sy","762":"tj","764":"th","768":"tg","772":"tk","776":"to","780":"tt","784":"ae","788":"tn","792":"tr","795":"tm","796":"tc","798":"tv","800":"ug","804":"ua","807":"mk","818":"eg","826":"gb","834":"tz","840":"us","850":"vi","854":"bf","858":"uy","860":"uz","862":"ve","876":"wf","882":"ws","887":"ye","891":"cs","894":"zm"}
population = population_xl.parse(population_xl.sheet_names[0])
population.columns=population.iloc[15]
population=population.iloc[16:][population['Type'] == 'Country/Area'][['Country code','2020']]
population['iso_alpha']=population['Country code'].map(str).map(num_to_alpha).str.upper().map(alpha_2_to_3)
population=population[['iso_alpha','2020']].rename({'2020': 'Population'}, axis=1)
In [0]:
frames=[]
for key in reversed(keyList):
frames.append(pd.DataFrame().from_dict(dfs[key]))
df=pd.merge(pd.concat(frames,sort=False)
.drop(['Last Update','lat','lon','City'], 1)
.groupby(['Days_since_start','Country/Region'])
.aggregate({**dict.fromkeys(['Province/State','Country/Region','Days_since_start','iso_alpha'],'first'),
**dict.fromkeys(['Confirmed', 'Deaths', 'Recovered', 'Suspected'],'sum')})
.reset_index(drop=True),
population, on='iso_alpha', how='left')
df['Rate']=(df['Confirmed']/df['Population']*1000000).fillna(0).apply(lambda x: x if x < 0.01 else np.log(x)*10).astype(int)
df['Death Rate']=(df['Deaths']/df['Population']*1000000).fillna(0).apply(lambda x: x if x < 0.01 else np.log(x)*10).astype(int)
In [0]:
scatter_confirmed = px.scatter_geo(df, title="Cases as a Scatter", locations="iso_alpha", color_discrete_sequence=["#cb181d"], size="Confirmed", animation_frame="Days_since_start", hover_name="Country/Region")
scatter_death = px.scatter_geo(df, title="Deaths as a Scatter", locations="iso_alpha", color_discrete_sequence=["#cb181d"], size="Deaths", animation_frame="Days_since_start", hover_name="Country/Region")
In [0]:
choropleth_confirmed = px.choropleth(df, title="Cases as a Choropleth", locations="iso_alpha", color="Rate", animation_frame="Days_since_start", hover_name="Country/Region")
choropleth_death = px.choropleth(df, title="Deaths as a Choropleth", locations="iso_alpha", color="Death Rate", animation_frame="Days_since_start", hover_name="Country/Region")
In [0]:
traces = (scatter_confirmed, scatter_death, choropleth_confirmed, choropleth_death)
buttons = {"Cases and Deaths":[True]*4,"Cases":[True, False]*2,"Deaths":[False,True]*2,**{traces[j].layout.title.text:[i is j for i in range(4)] for j in range(len(traces))}}
fig = go.Figure({
"data": [t.data[0] for t in traces],
"frames": [{
"name": f,
"data": [trace.frames[f].data[0] for trace in traces],
"traces": [0,1,2,3]}
for f in range(len(keyList))],
"layout": {
"title_text": "COVID 19 - Cases and Deaths",
"updatemenus": scatter_confirmed.layout.updatemenus + ({
"buttons": [{
"args": [{"visible": visible},
{"title": "COVID 19 - Time vs. "+label+" Map"}],
"label": label.replace(" as a",""),
"method": "update"
} for label, visible in buttons.items()],
"active":0,
"direction":"up",
'x': 0.1,
'y': 0,
'pad': {'r': 83, 't': 70},
},),
"sliders": scatter_confirmed.layout.sliders,
"showlegend": False,
"coloraxis": {
"showscale": False,
"colorscale": "Reds",
"cmax": df_countries['Rate'].max(),
"cmin": 0
}
}
})
fig.show()
In [0]:
%cd ../docs
fig.write_html("index.html",include_plotlyjs='cdn',include_mathjax='cdn',default_width="100%",default_height="100%")
%cd ..
!git add --all
!git commit -am "Updated docs/index.html to reflect changes"
!git push
%cd data
In [0]:
app = dash.Dash(__name__, assets_folder='./assets/',
meta_tags=[
{"name": "viewport", "content": "width=device-width, height=device-height, initial-scale=1.0"}
1 ]
)
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div(id='page-content')
])
def shutdown():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
@app.callback( dash.dependencies.Output('page-content', 'children'),
[dash.dependencies.Input('url', 'pathname')])
def display_page(pathname):
if pathname =='/shutdown':
shutdown()
return [dcc.Graph(figure=choropleth), dcc.Graph(figure=choropleth)]
In [0]:
get_ipython().system_raw('./ngrok http 8050 &')
! curl -s http://localhost:4040/api/tunnels | python3 -c \
"import sys, json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])"
In [0]:
f=open('output.html', 'w')
f.write(html)
f.close()
In [0]:
if __name__ == '__main__':
app.run_server()