通过bokeh中的CustomJS触发HoverTool工具提示的显示

时间:2019-06-09 20:45:26

标签: python bokeh

在bokeh应用程序中,我想重用HoverTool创建的工具提示的呈现。

尤其是,我想通过某种方式在数据源中选择一个数据点,然后显示该点的更多信息。例如,可以从滑块进行选择。 我可以添加一个自制标签(请参见代码示例),但是如果可以显示由HoverTool生成的工具提示,那将更好,因为它们已经被很好地格式化了。

示例代码显示了一个滑块,该滑块选择一个数据点并设置一个自定义标签。我想避免使用自定义标签,而是以某种方式触发悬停工具提示。

from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import HoverTool, ColumnDataSource, Slider, CustomJS, LabelSet
from bokeh.plotting import figure
import numpy as np

x = np.linspace(0,1)
y = np.linspace(0,2)
ds = ColumnDataSource(data=dict(x=x,y=y))

fig = figure()
fig.scatter(x='x', y='y', source=ds)

# a datasource to show labels at a x/y position, set in the JS callback
labels = ColumnDataSource(data=dict(x=[], y=[], t=[], ind=[]))
fig.add_layout(LabelSet(x='x', y='y', text='t', source=labels))

# slider that selects a datapoint and creates the label for the point
slider = Slider(start=0, end=len(x), value=0, step=1)
code = """
    labels.data = {'x':[],'y':[],'t':[]}
    source.selected.indices = [slider.value]
    labels.data = {'ind':[slider.value],
            'x':[source.data.x[slider.value]],
            'y':[source.data.y[slider.value]],
            't':[source.data.x[slider.value]]}
    labels.change.emit()
    source.change.emit()
    """

callback = CustomJS(args=dict(source=ds, slider=slider, labels=labels), code=code)
slider.js_on_change('value', callback)

# hover to show default tooltips, can those be triggered?
hover = HoverTool(mode='vline')
fig.add_tools(hover)

show(column(slider, fig))

1 个答案:

答案 0 :(得分:0)

调用HoverToolView._inspect(x, y),其中(x,y)是该点的画布坐标。我们需要使用xscale.compute()yscale.compute()将数据坐标转换为画布坐标。

import numpy as np

from bokeh.plotting import figure, show, output_notebook
from bokeh.models import Slider, HoverTool, CustomJS, ColumnDataSource
from bokeh.layouts import column
output_notebook()

N = 100
x = np.random.random(size=N) * 100
y = np.random.random(size=N) * 100

radii = np.random.random(size=N) * 1.5
colors = [
    "#%02x%02x%02x" % (int(r), int(g), 150) for r, g in zip(50+2*x, 30+2*y)
]

TOOLS="hover,crosshair,pan,wheel_zoom,zoom_in,zoom_out,box_zoom,undo,redo,reset,tap,save,box_select,poly_select,lasso_select,"

p = figure(tools=TOOLS)

source = ColumnDataSource(dict(x=x, y=y, radius=radii, colors=colors))

renderer = p.scatter("x", "y", radius="radius",
          fill_color="colors", fill_alpha=0.6,
          line_color=None, source=source)

slider = Slider(start=0, end=len(x), value=0, step=1)
code = """
let ind = slider.value;
let x = source.data.x[ind];
let y = source.data.y[ind];
let fig_view = Bokeh.index["myplot"].child_views[1];
let hover_view = fig_view.tool_views[hovertool.id];
let renderer_view = fig_view.renderer_views[renderer.id];
let xs = renderer_view.xscale.compute(x);
let ys = renderer_view.yscale.compute(y);
hover_view._inspect(xs, ys);
"""

callback = CustomJS(args=dict(
    fig=p,
    slider=slider, 
    hovertool=p.select_one(HoverTool),
    source=source,
    renderer=renderer
    ), code=code)
slider.js_on_change('value', callback)

show(column(slider, p, id="myplot"))