Bokeh:用于调整 x 轴范围的 CustomJS TextInput 回调

Bokeh: CustomJS TextInput callback to adjust x axis range

我正在尝试制作一个网页,其中包含由 AjaxDataSource 对象提供支持的绘图。但是,我想要一个可用于更改此图的 xrange 的 TextInput 小部件。以下是一个片段:

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)

查看此文件和 bokeh_ajax() 函数以获得完整的实现:https://github.com/hhprogram/PyramidSite/blob/master/webgraphing/views/ajaxView.py

当我运行它并更改相应的'Start'文本输入框。 CustomJS 运行s 相应地和根据我看到的警报,它正在捕获正确的新数据(假设您输入了 ISO 格式的日期,如 YYYY-mm-dd)但它无法更新绘图轴范围(即情节根本没有改变)。我将如何实施? (我想维护绘图以使其也具有底层 AjaxDataSources,而不使用散景服务器 - 如果 运行 使用散景服务器,我已经知道如何实现这种类型的轴更改功能。)

对于任何好奇的人,找到我的问题。认为主要问题是我没有将我想用来控制绘图 xrange 的小部件和实际绘图本身放在同一个布局对象中。因此,当我在绘图对象上调用组件时,它不包含小部件。然后,当我将小部件包含在绘图中时,它就起作用了。请参阅以下更新和更新后的 github 存储库:

(感谢这个 post 对我有很大帮助:

完整文件:https://github.com/hhprogram/PyramidSite/blob/master/webgraphing/views/ajaxView.py)

代码片段:

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)