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)