COVID-19 in Baden-Würtenberg

CoVID-19_BW

Coronavirus in Baden-Würtenberg

In [33]:
import numpy as np
import pandas as pd
from bokeh.io import output_notebook, show
from bokeh.plotting import figure, ColumnDataSource
from bokeh.layouts import column, row
from bokeh.models import CustomJS, Slider, Band, Select, Legend
from bokeh.models.formatters import FuncTickFormatter
from math import pi
output_notebook()
Loading BokehJS …
In [34]:
pd.options.display.max_rows = 15
pd.options.display.max_columns = 15
rawdata = pd.read_csv('./Data/COVID_BW.csv', index_col=0, skiprows=6, skipfooter=2, engine='python')
rawdata.fillna(value=0, inplace=True)
total_row = rawdata[-1:]
bwdata = rawdata.iloc[:-1, :]
bwdata
Out[34]:
9/9/2020 9/8/2020 9/7/2020 9/6/2020 9/5/2020 9/4/2020 9/3/2020 ... 3/2/2020 3/1/2020 2/29/2020 2/28/2020 2/27/2020 2/26/2020 2/25/2020
Alb-Donau-Kreis 813 808 804 804 793 787 786 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0
Biberach 747 747 746 737 737 737 731 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0
Böblingen 1889 1872 1859 1855 1845 1827 1809 ... 1.0 1.0 1.0 1.0 1.0 0.0 0.0
Bodenseekreis 444 441 437 434 428 428 422 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0
Breisgau-Hochschwarzwald 1318 1301 1293 1287 1282 1277 1274 ... 1.0 3.0 3.0 3.0 3.0 0.0 0.0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
Karlsruhe (Stadtkreis) 588 588 582 578 578 578 573 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0
Mannheim (Stadtkreis) 854 845 842 831 815 815 803 ... 3.0 3.0 0.0 0.0 0.0 0.0 0.0
Pforzheim (Stadtkreis) 573 571 568 565 552 550 550 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0
Stuttgart 2292 2253 2229 2167 2167 2167 2152 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0
Ulm (Stadtkreis) 495 489 489 486 479 467 461 ... 1.0 0.0 0.0 0.0 0.0 0.0 0.0

44 rows × 180 columns

In [35]:
data = bwdata[bwdata.columns[0]]
total = sum(data)
cds = ColumnDataSource(data=dict(x=list(bwdata.index), y=data.values))
dates = bwdata.columns
title='CoVID-19 infections in Baden-Würtenberg @ {}, total: {} '.format(bwdata.columns[0],total)
p = figure(x_range=list(bwdata.index),height=750, width=900, title=title)
p.xaxis.major_label_orientation = pi/2
p.xaxis.major_label_text_font_size = '12pt'
p.yaxis.major_label_text_font_size = '12pt'
values= bwdata.values
p.vbar(x='x', top='y', source=cds, width=0.7)
p.y_range.start = 0
p.title.text_font_size = '16pt'
p.title.align='center'
date_slider = Slider(title='Change date', start=0, end=len(bwdata.columns)-1, value=0, step=1, direction='rtl', show_value=False)

callback = CustomJS(args=dict(source=cds, values=values, slider = date_slider, title=p.title, dates=dates,),
                    code="""
    const data = source.data;
    
    const y = data['y'];
    const x = data['x'];
    var total= 0;
    for (var i=0;i<x.length;i++){
        y[i] = values[i][slider.value];
        total += y[i];
    }
    
    title.text = 'CoVID-19 infections in Baden-Würtenberg @ ' + dates[slider.value] +' total: ' +total;
    source.change.emit(); 
    """
)
date_slider.js_on_change('value', callback)
layout = column(row(date_slider),p )

show(layout)
In [36]:
data = np.flip(total_row.values[list(total_row.index).index('Summe')])
cds = ColumnDataSource(data=dict(x=list(reversed(list(bwdata.columns))), y=data))

tickvals = list(reversed(list(bwdata.columns)))[0::7]
p = figure(x_range=list(reversed(list(bwdata.columns))), height=750, width=1200, title="Total number of cases in Baden-Würtenberg")
p.xaxis.major_label_orientation = pi/4
p.xaxis.major_label_text_font_size = '12pt'
p.yaxis.major_label_text_font_size = '12pt'
p.xaxis.formatter = FuncTickFormatter(code="""   
    if (index % 7 == 0){
        return tick;
    }else{
        return ""
    }
""")

line = p.line(x='x', y='y', source=cds, width=2, line_color='#DD0000')
band = Band(base='x', upper='y', source=cds, level='underlay', fill_alpha=0.5, fill_color='#AA0000')

p.y_range.start = 0
p.title.text_font_size = '16pt'
p.title.align='center'
p.add_layout(band)
show(p)
In [37]:
#simple prediction is: for a given day the predicted number of new cases is the average of the new cases for the previous 3 days
flipped_sum = np.flip(total_row.values[0])
new_cases=[]
prediction=[]
new_cases.append(flipped_sum[0])
prediction.append(flipped_sum[0])
for i in range(1, len(flipped_sum)):
    new_cases.append(flipped_sum[i]-flipped_sum[i-1])
    if i >5 :
        prediction.append( (new_cases[i-1]+new_cases[i-2]+new_cases[i-3])/3)
    else:
        prediction.append(0)
In [38]:
p = figure(x_range=list(reversed(list(bwdata.columns))), height=750, width=900, title="New cases per day in Baden-Würtenberg")
p.xaxis.major_label_orientation = pi/4
p.xaxis.major_label_text_font_size = '12pt'
p.yaxis.major_label_text_font_size = '12pt'
p.title.text_font_size = '16pt'
p.title.align='center'
p.xaxis.formatter = FuncTickFormatter(code="""   
    if (index % 7 == 0){
        return tick;
    }else{
        return ""
    }
""")

vbar = p.vbar(x=list(reversed(list(bwdata.columns))),top=new_cases, width=0.75, legend_label = 'Actual new cases')
line = p.line(x=list(reversed(list(bwdata.columns))), y=prediction, width=2, legend_label = 'Predicted new cases', line_color='#DD0000')
p.legend.location = "top_left"
show(p)
In [39]:
def calc_change(data, index):
    if data[index]==data[index-1]:
        return 0
    if data[index-1]==0:
        return 0
    return ((data[index]/data[index-1])-1)*100
In [40]:
new_cases_dynamics = []
new_cases_dynamics.append(0)
for i in range(1, len(new_cases)):
    new_cases_dynamics.append(calc_change(new_cases, i))

p = figure(x_range=list(reversed(list(bwdata.columns))), height=750, width=1200, title="Rate of change in percent of new cases Baden-Würtenberg")
p.xaxis.major_label_orientation = pi/4
p.xaxis.major_label_text_font_size = '12pt'
p.yaxis.major_label_text_font_size = '12pt'
p.title.text_font_size = '16pt'
p.title.align='center'
p.xaxis.formatter = FuncTickFormatter(code="""   
    if (index % 7 == 0){
        return tick;
    }else{
        return ""
    }
""")

vbar = p.line(x=list(reversed(list(bwdata.columns))),y=new_cases_dynamics, width=2, legend_label = 'Actual new cases')
p.legend.location = "top_left"
p.yaxis.axis_label = 'percent compared to previous day'
show(p)
In [41]:
p = figure( height=750, width=900, title="Scatter plot of actual and predicted new cases")
p.xaxis.major_label_orientation = pi/4
p.xaxis.major_label_text_font_size = '12pt'
p.yaxis.major_label_text_font_size = '12pt'
p.xaxis.axis_label = "actual new cases"
p.yaxis.axis_label = "predicted new cases"
p.title.text_font_size = '16pt'
p.title.align='center'

# Fitting a 1-degree polynomial that is a line, minimizing squared error
newcases_fit= np.polyfit(new_cases, prediction, 1)
slope=newcases_fit[0]
intercept=newcases_fit[1]
newcases_pred = [slope*i + intercept  for i in new_cases]

confirmed_scatter = p.scatter(x=new_cases, y=prediction, width=2, line_color='#0000DD')
confirmed_fit_line = p.line(x=new_cases, y=newcases_pred, legend_label='fit: y='+str(round(slope,2))+'x+'+str(round(intercept,2)), width=2, line_color='#0000DD')

show(p)
In [43]:
data = np.flip(bwdata.values[list(bwdata.index).index('Stuttgart')])
cds = ColumnDataSource(data=dict(x=list(reversed(list(bwdata.columns))), y=data))

p = figure(x_range=list(reversed(list(bwdata.columns))),height=750, width=1200, title="Trend in Stuttgart")
p.xaxis.major_label_orientation = pi/4
p.xaxis.major_label_text_font_size = '12pt'
p.yaxis.major_label_text_font_size = '12pt'
p.xaxis.formatter = FuncTickFormatter(code="""   
    if (index % 7 == 0){
        return tick;
    }else{
        return ""
    }
""")

line = p.line(x='x', y='y', source=cds, width=2, line_color='#DD0000')
band = Band(base='x', upper='y', source=cds, level='underlay', fill_alpha=0.5, fill_color='#AA0000')

p.y_range.start = 0
p.title.text_font_size = '16pt'
p.title.align='center'
values = np.flip(bwdata.values, 1)
cities = np.array(bwdata.index)
menuitems = []
for stadt in list(bwdata.index):
    menuitems.append((stadt, stadt))
    
select = Select(title="Select city", value='Stuttgart', options=menuitems)
callback = CustomJS(args=dict(source=cds, values=values, cities=cities, title=p.title, sel=select),
                    code="""
    const data = source.data;
    const y = data['y'];
    const x = data['x'];
    var selCity=sel.value;
    title.text = "Trend in "+ selCity
    function getCityIndex(city){
        return city == selCity;
    }
    for (var i=0; i<y.length; i++){
        y[i] = values[cities.findIndex(getCityIndex)][i];
    }
    source.change.emit(); 
    """
)

select.js_on_change('value', callback)
p.add_layout(band)
layout = column(row(select),p )
show(layout)