Slider under differential equations - problem with Javascript in CustomJS callback

Hi,

Apologies if my question isn’t perfectly put but I’m relatively new to both Python and Bokeh and am learning as I go along.

I’ve been trying to build an SID model to track the COVID-19 pandemic.

I have created by plot in Bokeh without any problems however I am having trouble inserting a slider for one of the constants in the differential equations. I get the plot but nothing happens when I move the slider, obviously.

My problem is that most of the slider examples I’ve seen are for relatively straight forward line graphs where y can be plotted in terms of x quite simply.

In this case I am using odeint from the scipy library to calculate the points on the curve and need to call function in order to generate the values.

I’d really like to get this done and was wondering whether it is possible to call the function using Javascript.

My code is below. Any feedback or pointers would be greatly appreciated.

from scipy.integrate import odeint
import numpy as np
import pandas as pd
from bokeh.models import HoverTool, ColumnDataSource, CustomJS, Slider
from bokeh.plotting import figure, output_file, show
from bokeh.layouts import row, gridplot, column

def deriv(y, t, N, beta, gamma):
S, I, R = y
dSdt = -beta * S * I / N
dIdt = beta * S * I / N - gamma * I
dRdt = gamma * I
return dSdt, dIdt, dRdt

N = 493599
beta = .28
D = 5.78
gamma = 1.0 / D
S0, I0, R0 = 493589, 10, 0
t = np.linspace(0, 200, 50)
y0 = S0, I0, R0

Integrate the SIR equations over the time grid, t.

ret = odeint(deriv, y0, t, args=(N, beta, gamma))
S, I, R = ret.T

def plot_model(t, S, I, R):
output_file(‘COVID19_SIR.html’)
p = figure(plot_width=1400, plot_height=350)
p.line(x=t, y=I, line_width=2, line_dash=‘solid’,
legend_label=‘R-naught: ’ + str("{:.2f}".format(beta / gamma)) + " / Beta: " + str("{:.4f}".format(beta)),
line_color=’#01579B’)
beta_slider = Slider(start=0.1, end=1, value=0.5, step=.1, title=“beta”)

p.add_tools(HoverTool(
    tooltips=[
        ('Day ', "$x{0}"),
        ('Proportion of population ', "$y{0.00000000}"),
    ],
    mode='mouse'
))
source = ColumnDataSource(data=dict(x=t, y=I))
callback = CustomJS(args=dict(source=source), code="""
    var data = source.data;
    var B = cb_obj.value
    var x = data['x']
    var y = data['y']
    for (var i = 0; i < x.length; i++) {
       
       ??????????????????
    }
    source.change.emit();
""")
beta_slider.js_on_change('value', callback)
layout = column(beta_slider, p)
show(layout)

plot_model(t, S, I, R)

The js_on_change callback framework exists to allow you to run JavaScript code in the browser with the convenience that you don’t need to run a bokeh server.

Your code explicitly relies on a Python ODE solver from scipy.

I think you have two possible paths forward to address this incompatibility.

  1. Use an on_change callback, written in Python, that gets invoked when you manipulate the slider to change the beta parameter and re-integrates the system of ODEs for that value of beta, updates the ColumnDataSource, which then handles the plot refreshing automatically with the bokeh machinery. This would all be run in a bokeh server, but that’s straightforward even on a local machine.

  2. Implement ODE integration in the JavaScript code. Your equations are simple enough at first glance. Perhaps you can get away with a problem-specific set of Euler integration and an appropriate step size. If so, that could be put in the loop where you currently have the ???????

Answered on SO: https://stackoverflow.com/a/61285022/564509

For future reference, please include the link to the question yourself if you decide to crosspost.

Apologies, as I said, new to this sort of thing. Will remember to post SO link next time. Thanks!