Interactive Visualizations of The Count and Growth of COVID-19 in the US.
#hide
import requests
import numpy as np
import pandas as pd
import altair as alt
alt.data_transformers.disable_max_rows()
#https://github.com/altair-viz/altair/issues/1005#issuecomment-403237407
def to_altair_datetime(dt):
return alt.DateTime(year=dt.year, month=dt.month, date=dt.day,
hours=dt.hour, minutes=dt.minute, seconds=dt.second,
milliseconds=0.001 * dt.microsecond)
#hide
abbr2state = {
'AK': 'Alaska',
'AL': 'Alabama',
'AR': 'Arkansas',
'AS': 'American Samoa',
'AZ': 'Arizona',
'CA': 'California',
'CO': 'Colorado',
'CT': 'Connecticut',
'DC': 'District of Columbia',
'DE': 'Delaware',
'FL': 'Florida',
'GA': 'Georgia',
'GU': 'Guam',
'HI': 'Hawaii',
'IA': 'Iowa',
'ID': 'Idaho',
'IL': 'Illinois',
'IN': 'Indiana',
'KS': 'Kansas',
'KY': 'Kentucky',
'LA': 'Louisiana',
'MA': 'Massachusetts',
'MD': 'Maryland',
'ME': 'Maine',
'MI': 'Michigan',
'MN': 'Minnesota',
'MO': 'Missouri',
'MP': 'Northern Mariana Islands',
'MS': 'Mississippi',
'MT': 'Montana',
'NA': 'National',
'NC': 'North Carolina',
'ND': 'North Dakota',
'NE': 'Nebraska',
'NH': 'New Hampshire',
'NJ': 'New Jersey',
'NM': 'New Mexico',
'NV': 'Nevada',
'NY': 'New York',
'OH': 'Ohio',
'OK': 'Oklahoma',
'OR': 'Oregon',
'PA': 'Pennsylvania',
'PR': 'Puerto Rico',
'RI': 'Rhode Island',
'SC': 'South Carolina',
'SD': 'South Dakota',
'TN': 'Tennessee',
'TX': 'Texas',
'UT': 'Utah',
'VA': 'Virginia',
'VI': 'Virgin Islands',
'VT': 'Vermont',
'WA': 'Washington',
'WI': 'Wisconsin',
'WV': 'West Virginia',
'WY': 'Wyoming'
}
state2abbr = {s:a for a,s in abbr2state.items()}
#hide
states_daily_url = 'https://covidtracking.com/api/states/daily'
states_daily_raw = pd.DataFrame(requests.get(states_daily_url).json())
us_daily_df = states_daily_raw.copy()
cols_keep = ['date','state','positive','dateChecked','positiveIncrease','death']
us_daily_df = us_daily_df[cols_keep]
us_daily_df['date'] = pd.to_datetime(us_daily_df['date'], format='%Y%m%d')
us_daily_df['dateChecked'] = pd.to_datetime(us_daily_df['dateChecked'])
us_state_capitals_url = 'https://vega.github.io/vega-datasets/data/us-state-capitals.json'
state_cap_df = pd.DataFrame(requests.get(us_state_capitals_url).json())
state_cap_df['state'] = state_cap_df['state'].apply(lambda s: state2abbr.get(s))
us_daily_df = us_daily_df.merge(state_cap_df, on='state', how='left')
us_daily_df.rename(columns={'positive':'confirmed_count',
'positiveIncrease':'new_cases'}, inplace=True)
state_df = us_daily_df.sort_values('date').groupby(['state']).tail(1)
#hide
states_data = 'https://vega.github.io/vega-datasets/data/us-10m.json'
states = alt.topo_feature(states_data, feature='states')
selector = alt.selection_single(empty='none', fields=['state'], nearest=True, init={'state':'CA'})
curr_date = state_df.date.max().date().strftime('%Y-%m-%d')
dmax = (us_daily_df.date.max() + pd.DateOffset(days=3))
dmin = us_daily_df.date.min()
# US states background
background = alt.Chart(states).mark_geoshape(
fill='lightgray',
stroke='white'
).properties(
width=500,
height=400
).project('albersUsa')
points = alt.Chart(state_df).mark_circle().encode(
longitude='lon:Q',
latitude='lat:Q',
size=alt.Size('confirmed_count:Q', title= 'Number of Confirmed Cases'),
color=alt.value('steelblue'),
tooltip=['state:N','confirmed_count:Q']
).properties(
title=f'Total Confirmed Cases by State as of {curr_date}'
).add_selection(selector)
timeseries = alt.Chart(us_daily_df).mark_bar().properties(
width=500,
height=350,
title="New Cases by Day",
).encode(
x=alt.X('date:T', title='Date', timeUnit='yearmonthdate',
axis=alt.Axis(format='%y/%m/%d', labelAngle=-30),
scale=alt.Scale(domain=[to_altair_datetime(dmin), to_altair_datetime(dmax)])),
y=alt.Y('new_cases:Q',
axis=alt.Axis(title='# of New Cases',titleColor='steelblue'),
),
color=alt.Color('state:O'),
tooltip=['state:N','date:T','confirmed_count:Q', 'new_cases:Q']
).transform_filter(
selector
).add_selection(alt.selection_single()
)
timeseries_cs = alt.Chart(us_daily_df).mark_line(color='red').properties(
width=500,
height=350,
).encode(
x=alt.X('date:T', title='Date', timeUnit='yearmonthdate',
axis=alt.Axis(format='%y/%m/%d', labelAngle=-30),
scale=alt.Scale(domain=[to_altair_datetime(dmin), to_altair_datetime(dmax)])),
y=alt.Y('confirmed_count:Q',
#scale=alt.Scale(type='log'),
axis=alt.Axis(title='# of Confirmed Cases', titleColor='red'),
),
).transform_filter(
selector
).add_selection(alt.selection_single(nearest=True)
)
final_chart = alt.vconcat(
background + points,
alt.layer(timeseries, timeseries_cs).resolve_scale(y='independent'),
).resolve_scale(
color='independent',
shape='independent',
).configure(
padding={'left':10, 'bottom':40}
).configure_axis(
labelFontSize=10,
labelPadding=10,
titleFontSize=12,
).configure_view(
stroke=None
)
#hide_input
final_chart
Prepared by Asif Imran[^1]
[^1]: Source: "https://covidtracking.com/api/".