Javascript – Bokeh: CustomJS TextInput callback for adjusting the x-axis range

Bokeh: CustomJS TextInput callback for adjusting the x-axis range… here is a solution to the problem.

Bokeh: CustomJS TextInput callback for adjusting the x-axis range

I’m trying to make a web page with a drawing powered by an AjaxDataSource object. However, I want a TextInput widget that can be used to change the xrange of this graph. Below is a snippet:

source = AjaxDataSource(data={"time": [], "temperature": [], "id": []},
                        data_url='http://localhost:6543/AJAXdata',
                        polling_interval=100,
                        mode='append')
livePlot = figure(x_axis_type="datetime",
                  x_range=[startDt, endDt],
                  y_range=(0,25),
                  y_axis_label='Temperature (Celsius)',
                  title="Sea Surface Temperature at 43.18, -70.43",
                  plot_width=800)
livePlot.line("time", "temperature", source=source)
....
updateStartJS = CustomJS(args=dict(xrange=livePlot.x_range), code="""
    var startStr = cb_obj.value
    alert(startStr)
    var newStartMilliSeconds = Date.parse(startStr)
    alert(newStartMilliSeconds)
    alert(xrange)
    alert(xrange.start)
    xrange.start = newStartMilliSeconds
    alert(xrange.start)
    xrange.change.emit();
""")
startInput = TextInput(value=startDt.strftime(dateFmt), callback=updateStartJS)

Check out this file and the bokeh_ajax() function for the complete implementation: https://github.com/hhprogram/PyramidSite/blob/master/webgraphing/views/ajaxView.py

When I run it and change the corresponding “Start” text input box. CustomJS runs accordingly, and based on the alerts I’ve seen, it’s capturing the correct new data (assuming you enter a date in ISO format, like YYYY-mm-dd), but it can’t update the plot axis range (i.e. the plot hasn’t changed at all). How will I achieve it? (I want to maintain plots to have the underlying AjaxDataSources without using a Bokeh server – if running a Bokeh server, I already know how to implement this type of axis change functionality.) )

Solution

For anyone curious, find my problem. Thinking the main problem is that I didn’t put the widget I wanted to use to control the drawing xrange and the actual drawing itself in the same layout object. So when I call the component on the drawing object, it doesn’t contain widgets. Then, when I included the widget in the drawing, it worked. See the following updates and updated GitHub repositories:

(Thanks for this article that helped me a lot: Flask + Bokeh AjaxDataSource)

Full file: https://github.com/hhprogram/PyramidSite/blob/master/webgraphing/views/ajaxView.py )

Code snippet:

source = AjaxDataSource(data={"time": [], "temperature": [], "id": []},
                        data_url='http://localhost:6543/AJAXdata',
                        polling_interval=100,
                        mode='append')
livePlot = figure(x_axis_type="datetime",
                  x_range=[startDt, endDt],
                  y_range=(0,25),
                  y_axis_label='Temperature (Celsius)',
                  title="Sea Surface Temperature at 43.18, -70.43",
                  plot_width=800)
livePlot.line("time", "temperature", source=source)
jsResources = INLINE.render_js()
cssResources = INLINE.render_css()

updateStartJS = CustomJS(args=dict(plotRange=livePlot.x_range), code="""
    var newStart = Date.parse(cb_obj.value)
    plotRange.start = newStart
    plotRange.change.emit()
""")

updateEndJS = CustomJS(args=dict(plotRange=livePlot.x_range), code="""
    var newEnd = Date.parse(cb_obj.value)
    plotRange.end = newEnd
    plotRange.change.emit()
""")

startInput = TextInput(value=startDt.strftime(dateFmt), title="Enter Date in format: YYYY-mm-dd")
startInput.js_on_change('value', updateStartJS)
endInput = TextInput(value=endDt.strftime(dateFmt), title="Enter Date in format: YYYY-mm-dd")
endInput.js_on_change('value', updateEndJS)
textWidgets = row(startInput, endInput)
# NOTE: this is important. Need to have the widgets and plot within same object that is the argument for components() method
layout =  column(textWidgets, livePlot)
script, div = components(layout)

Related Problems and Solutions