def slider_app_bokeh(start_date=datetime(2020, 3, 1), lock_date=datetime(2020, 3, 26), post_lock_date=datetime(2020, 4, 26), init_rho=3.7, lock_rho=0.7, post_lock_rho=1.6, init_inf=61, conf_case_delay=7, init_exp=0, init_rec=0, mort_rate=0.013, symp_2_death=14, MaxDays=500, tau=8, k=0.5, nu=1.7, mu=5.1, model='NBD_SEIR', county='El Paso'): models = {'SIR_nu': 0, 'SEIR_nu': 1, 'NBD_SEIR': 2} model_text = { 'SIR_nu': 'Simple S-I-R Infection Model with \n' + 'Heterogeneous Mixing Simulated using \n' + 'a Power-Law Scaling Term (' 'nu' ')', 'SEIR_nu': 'S-E-I-R Infection Model with \n' + 'Heterogeneous Mixing Simulated using \n' + 'a Power-Law Scaling Term (' 'nu' ')', 'NBD_SEIR': 'S-E-I-R Infection Model with \n' + 'Heterogeneous Mixing Simulated using \n' + 'Negative Binomially-Distributed \n' + 'Infection Events (PDF shape ' 'k' ')' } t = 7 / 24 today = datetime.now() pct_tst = 0.15 global zm_toggle, legend_toggle zm_toggle = -1 legend_toggle = 1 rho_sched = {lock_date: lock_rho, post_lock_date: post_lock_rho} lock_time = (lock_date-start_date).days + \ (lock_date-start_date).seconds/86400 post_lock_time = (post_lock_date-start_date).days + \ (post_lock_date-start_date).seconds/86400 if model == 'SIR_nu': I_ind = 2 R_ind = 3 D_ind = 4 out = SIR_nu(start_date, P=720403, I=init_inf, R=0, rho=init_rho, tau=tau, nu=1.7, MaxDays=MaxDays, suppress_output=1, rho_sched=rho_sched, mort_rate=mort_rate, symp_2_death=symp_2_death, t=t) elif model == 'SEIR_nu': I_ind = 3 R_ind = 4 D_ind = 5 out = SEIR_nu(start_date, P=720403, E=0, I=init_inf, R=0, mu=mu, rho=init_rho, tau=tau, nu=1.7, MaxDays=MaxDays, suppress_output=1, rho_sched=rho_sched, mort_rate=mort_rate, symp_2_death=symp_2_death, t=t) elif model == 'NBD_SEIR': I_ind = 3 R_ind = 4 D_ind = 6 out = NBD_SEIR(start_date, 720403, 0, init_inf, 0, init_rho, tau, k, mu, county, MaxDays, suppress_output=1, rho_sched=rho_sched, t=t, mort_rate=mort_rate, symp_2_death=symp_2_death) C = int(tau / t) max_ind = int((today - start_date).days / t) T = out[0] I = out[I_ind] R = out[R_ind] D = out[D_ind] T1 = T T2 = T[0:max_ind] T3 = T[0:-C] CC1 = array(R[C:max_ind + C]) CC1p = pct_tst * CC1 CC2 = array(R[C:]) CC2p = pct_tst * CC2 [death_times, case_times, deaths, cases] = dataHandler(start_date, conf_case_delay) # def days_2_ms(T): # Dt = [] # for i in T: # Dt.append(i*24*3600*1000) # return Dt # Dt1 = days_2_ms(T1) # Dt2 = days_2_ms(T2) # Dt3 = days_2_ms(T3) # DTd = days_2_ms(death_times) # DTc = days_2_ms(case_times) # Set up data: --- # source1 = ColumnDataSource(data=dict(T1=Dt1, I=I, D=D)) # source2 = ColumnDataSource(data=dict(T2=Dt2, CC1=CC1,CC1p=CC1p)) # source3 = ColumnDataSource(data=dict(T3=Dt3, CC2=CC2, CC2p=CC2p)) # scatter_source1 = ColumnDataSource(data=dict(Td=DTd, d=deaths)) # scatter_source2 = ColumnDataSource(data=dict(Tc=DTc, c=cases)) source1 = ColumnDataSource(data=dict(T1=T1, I=I, D=D)) source2 = ColumnDataSource(data=dict(T2=T2, CC1=CC1, CC1p=CC1p)) source3 = ColumnDataSource(data=dict(T3=T3, CC2=CC2, CC2p=CC2p)) scatter_source1 = ColumnDataSource(data=dict(Td=death_times, d=deaths)) scatter_source2 = ColumnDataSource(data=dict(Tc=case_times, c=cases)) # Set up plots: --- # Top-left plot plot1 = figure( plot_height=400, plot_width=400, title="Predicted vs. Reported Deaths in " + county + " County", tools="crosshair,pan,reset,save,wheel_zoom", # x_axis_type='datetime', x_range=[0, T[max_ind]], y_range=[0, max(deaths)]) plot1.line('T1'[0:max_ind], 'D'[0:max_ind], source=source1, line_color='red', line_width=3, line_alpha=0.6, muted_alpha=0.2, legend_label='Predicted Cumulative Deaths') plot1.circle('Td', 'd', source=scatter_source1, line_color='red', muted_alpha=0.2, legend_label='Reported Deaths in ' + county + ' County') plot1.legend.location = 'top_left' plot1.legend.click_policy = 'mute' plot1.xaxis.ticker = [0, 31, 61] plot1.xaxis.major_label_overrides = {0: 'Mar', 31: 'Apr', 61: 'May'} # Top-right plot plot2 = figure( plot_height=400, plot_width=400, title="Predicted Deaths over the Long Term", tools="crosshair,pan,reset,save,wheel_zoom", #x_axis_type='datetime', x_range=[0, MaxDays], y_range=[0, max(D)]) plot2.line('T1', 'D', source=source1, line_color='red', line_width=3, line_alpha=0.6, muted_alpha=0.2, legend_label='Predicted Cumulative Deaths') plot2.circle('Td', 'd', source=scatter_source1, line_color='red', muted_alpha=0.2, legend_label='Reported Deaths in' + county + ' County') plot2.legend.location = 'top_left' plot2.legend.click_policy = 'mute' plot2.xaxis.ticker = [0, 31, 61, 92, 122, 153, 183, 214, 245, 275] plot2.xaxis.major_label_overrides = { 0: 'Mar', 31: 'Apr', 61: 'May', 92: 'Jun', 122: 'Jul', 153: 'Aug', 183: 'Sep', 214: 'Oct', 245: 'Nov', 275: 'Dec' } # Bottom-left plot plot3 = figure( plot_height=400, plot_width=400, title="Predicted vs. Reported Infectious in El Paso County", tools="crosshair,pan,reset,save,wheel_zoom", #x_axis_type='datetime', x_range=[0, T[max_ind]], y_range=[0, R[max_ind]]) plot3.line('T1'[0:max_ind], 'I'[0:max_ind], source=source1, line_color='blue', line_width=3, line_alpha=0.6, muted_alpha=0.2, legend_label='Predicted Infectious Population') plot3.line('T2', 'CC1', source=source2, line_color='green', line_width=3, line_alpha=0.6, muted_alpha=0.2, legend_label='Predicted Cumulative Cases') plot3.line( 'T2', 'CC1p', source=source2, line_color='green', line_dash='dotted', line_width=3, line_alpha=0.6, muted_alpha=0.2, legend_label='Predicted Confirmed Cases based on Tested Percentage') plot3.circle('Tc', 'c', source=scatter_source2, line_color='blue', muted_alpha=0.2, legend_label='Reported Confirmed Cases in ' + county + ' County') plot3.legend.location = 'top_left' plot3.legend.click_policy = 'mute' plot3.xaxis.ticker = [0, 31, 61] plot3.xaxis.major_label_overrides = {0: 'Mar', 31: 'Apr', 61: 'May'} # Bottom-right plot plot4 = figure( plot_height=400, plot_width=400, title="Predicted Infectious over the Long Term", tools="crosshair,pan,reset,save,wheel_zoom", #x_axis_type='datetime', x_range=[0, MaxDays], y_range=[0, max(R)]) plot4.line('T1', 'I', source=source1, line_color='blue', line_width=3, line_alpha=0.6, muted_alpha=0.2, legend_label='Predicted Infectious Population') plot4.line('T3', 'CC2', source=source3, line_color='green', line_width=3, line_alpha=0.6, muted_alpha=0.2, legend_label='Predicted Cumulative Cases') plot4.line( 'T3', 'CC2p', source=source3, line_color='green', line_dash='dotted', line_width=3, line_alpha=0.6, muted_alpha=0.2, legend_label='Predicted Confirmed Cases based on Tested Percentage') plot4.circle('Tc', 'c', source=scatter_source2, line_color='blue', muted_alpha=0.2, legend_label='Reported Confirmed Cases in ' + county + ' County') plot4.legend.location = 'top_left' plot4.legend.click_policy = 'mute' plot4.xaxis.ticker = [0, 31, 61, 92, 122, 153, 183, 214, 245, 275] plot4.xaxis.major_label_overrides = { 0: 'Mar', 31: 'Apr', 61: 'May', 92: 'Jun', 122: 'Jul', 153: 'Aug', 183: 'Sep', 214: 'Oct', 245: 'Nov', 275: 'Dec' } # Set up widgets delta = 0.1 sliders = [] text = TextInput(title="title", value='my sine wave') s_init_rho = Slider(title="Initial R_0", value=init_rho, start=0.1, end=6.0, step=delta / 10) sliders.append(s_init_rho) s_lock_rho = Slider(title="Stay-at-home R_0", value=lock_rho, start=0.1, end=6.0, step=delta / 10) sliders.append(s_lock_rho) s_post_lock_rho = Slider(title="R_0 after End of Stay-at-home order", value=post_lock_rho, start=0.1, end=6.0, step=delta / 10) sliders.append(s_post_lock_rho) s_post_lock_time = Slider( title="End of Stay-at-home posture (Days after 1 Mar)", value=post_lock_time, start=50, end=200, step=1) sliders.append(s_post_lock_time) s_init_inf = Slider(title="Initial Infectious", value=init_inf, start=1, end=100, step=1) sliders.append(s_init_inf) s_init_exp = Slider(title="Initial Exposed", value=init_exp, start=0, end=100, step=1) sliders.append(s_init_exp) s_init_rec = Slider(title="Initial Recovered", value=init_rec, start=0, end=100, step=1) sliders.append(s_init_rec) s_pct_tst = Slider( title="Percent of Infected Population Tested & Positive", value=pct_tst * 100, start=1, end=100, step=delta) sliders.append(s_pct_tst) s_tau = Slider(title="Infectious Period (days)", value=tau, start=2, end=14, step=delta) sliders.append(s_tau) s_mu = Slider(title="Incubation Period (days)", value=mu, start=0, end=7, step=delta) sliders.append(s_mu) if model == 'SIR_nu' or model == 'SEIR_nu': s_het = Slider(title="Power-Law Heterogeneity", value=nu, start=1.0, end=3.3, step=delta) elif model == 'NBD_SEIR': s_het = Slider(title="NBD Homogeneity", value=k, start=0.001, end=5, step=0.01) sliders.append(s_het) s_mort_rate = Slider(title="Mortality Rate (%)", value=mort_rate * 100, start=0.1, end=10, step=delta) sliders.append(s_mort_rate) s_symp_2_death = Slider(title="Avg Delay from Symptoms until Death (days)", value=symp_2_death, start=3, end=20, step=delta) sliders.append(s_symp_2_death) s_conf_case_delay = Slider(title="Avg Delay from Test Processing (days)", value=conf_case_delay, start=0, end=14, step=delta) sliders.append(s_conf_case_delay) s_t = Slider(title="Timestep (minutes)", value=t * (60 * 24), start=15, end=60 * 24, step=5) sliders.append(s_t) # Set up callbacks def update_title(attrname, old, new): plot1.title.text = text.value #text.on_change('value', update_title) def update_data(attrname, old, new): # Get the current slider values init_rho = s_init_rho.value lock_rho = s_lock_rho.value post_lock_rho = s_post_lock_rho.value post_lock_time = s_post_lock_time.value post_lock_date = start_date + timedelta(days=post_lock_time) init_inf = s_init_inf.value init_exp = s_init_exp.value init_red = s_init_rec.value pct_tst = s_pct_tst.value / 100 tau = s_tau.value mu = s_mu.value if model_sel.active in [0, 1]: # Power law models (nu) nu = s_het.value elif model_sel.active == 2: # NBD model (k) k = s_het.value mort_rate = s_mort_rate.value / 100 symp_2_death = s_symp_2_death.value conf_case_delay = s_conf_case_delay.value t = s_t.value / (60 * 24) max_ind = int((today - start_date).days / t) [death_times, case_times, deaths, cases] = dataHandler(start_date, conf_case_delay) rho_sched = {lock_date: lock_rho, post_lock_date: post_lock_rho} if model_sel.active == 0: # SIR_nu I_ind = 2 R_ind = 3 D_ind = 4 out2 = SIR_nu(start_date, P=720403, I=init_inf, R=init_rec, rho=init_rho, tau=tau, nu=nu, MaxDays=MaxDays, suppress_output=1, rho_sched=rho_sched, mort_rate=mort_rate, symp_2_death=symp_2_death, t=t) elif model_sel.active == 1: # SEIR_nu I_ind = 3 R_ind = 4 D_ind = 5 out2 = SEIR_nu(start_date, P=720403, E=init_exp, I=init_inf, R=init_rec, mu=mu, rho=init_rho, tau=tau, nu=nu, MaxDays=MaxDays, suppress_output=1, rho_sched=rho_sched, mort_rate=mort_rate, symp_2_death=symp_2_death, t=t) elif model_sel.active == 2: # NBD_SEIR I_ind = 3 R_ind = 4 D_ind = 6 out2 = NBD_SEIR(start_date, 720403, init_exp, init_inf, init_rec, init_rho, tau, k, mu, county, MaxDays, suppress_output=1, rho_sched=rho_sched, mort_rate=mort_rate, symp_2_death=symp_2_death, t=t) T = out2[0] I = out2[I_ind] R = out2[R_ind] D = out2[D_ind] T1 = T T2 = T[0:max_ind] T3 = T[0:-C] CC1 = array(R[C:max_ind + C]) CC1p = pct_tst * CC1 CC2 = array(R[C:]) CC2p = pct_tst * CC2 [death_times, case_times, deaths, cases] = dataHandler(start_date, conf_case_delay) plot1.y_range.start = 0 plot1.y_range.end = max(deaths) plot2.y_range.start = 0 plot2.y_range.end = max(D) if zm_toggle == -1: plot3.y_range.start = 0 plot3.y_range.end = R[max_ind] plot4.y_range.start = 0 plot4.y_range.end = max(R) # Generate the new curve source1.data = dict(T1=T1, I=I, D=D) source2.data = dict(T2=T2, CC1=CC1, CC1p=CC1p) source3.data = dict(T3=T3, CC2=CC2, CC2p=CC2p) scatter_source1.data = dict(Td=death_times, d=deaths) scatter_source2.data = dict(Tc=case_times, c=cases) def update_radio_buttons(attrname, old, new): if model_sel.active in [0, 1]: s_het.title = "Power-Law Heterogeneity" s_het.value = nu s_het.start = 1.0 s_het.end = 3.3 s_het.step = delta elif model_sel.active == 2: s_het.title = "NBD Heterogeneity" s_het.value = k s_het.start = 0.0001 s_het.end = 5 s_het.step = delta / 10 update_data(attrname, old, new) def zm_button_event(event): global zm_toggle zm_toggle = -zm_toggle if zm_toggle == 1: plot3.y_range.start = 0 plot3.y_range.end = max(cases) elif zm_toggle == -1: plot3.y_range.start = 0 plot3.y_range.end = R[max_ind] def legend_button_event(event): global legend_toggle legend_toggle = -legend_toggle if legend_toggle == 1: plot1.legend.visible = True plot2.legend.visible = True plot3.legend.visible = True plot4.legend.visible = True elif legend_toggle == -1: plot1.legend.visible = False plot2.legend.visible = False plot3.legend.visible = False plot4.legend.visible = False for s in sliders: s.on_change('value', update_data) model_sel = RadioButtonGroup(labels=['SIR-nu', 'SEIR-nu', 'NBD_SEIR'], active=2) model_sel.on_change('active', update_radio_buttons) zm_button = Button(label='Zoom to Confirmed Cases', button_type='success') zm_button.on_event(ButtonClick, zm_button_event) legend_button = Button(label='Hide Plot Legends', button_type='success') legend_button.on_event(ButtonClick, legend_button_event) # Set up layouts and add to document inputs = column( model_sel, s_init_rho, s_lock_rho, s_post_lock_rho, s_post_lock_time, s_init_inf, s_init_exp, s_init_rec, s_pct_tst, s_tau, s_mu, s_het, #s_nu, s_k, s_mort_rate, s_symp_2_death, s_conf_case_delay, s_t) grid = gridplot([[plot1, plot2], [plot3, plot4]]) middle = column(grid, zm_button) curdoc().add_root(row(inputs, middle, legend_button, width=800)) curdoc().title = "El Paso County COVID-19 App"