예제 #1
0
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"