如何为 canvas 之外的散景图生成动态描述文本?

How can I generate a dynamic description text for bokeh plot outside of the canvas?

我有一个包含多个字形的散景图和一个 java 脚本回调函数,该函数根据鼠标悬停在图中的位置混合其他字形。

现在我想根据鼠标在左侧图中悬停(或可能单击)的位置,在该图外部的右侧添加包含附加信息的描述。

如何为 canvas 之外的散景图生成动态变化的描述文本?

我的想法是编写一个 java 脚本回调函数来更改情节外 div 的文本,但我不确定这是否可行或如何实现。

可以使用悬停工具,但我的描述太长,无法显示为覆盖框。

下面是一些示例代码 div 我想动态更改:

from bokeh.models import ColumnDataSource, CustomJS, HoverTool, Div, Spacer
from bokeh.plotting import figure, output_file, show
from bokeh.layouts import row

output_file("hover_callback.html")

# define some points and a little graph between them
x = [2, 3, 5, 6, 8, 7]
y = [6, 4, 3, 8, 7, 5]
links = {
    0: [1, 2],
    1: [0, 3, 4],
    2: [0, 5],
    3: [1, 4],
    4: [1, 3],
    5: [2, 3, 4]
}

p = figure(plot_width=400, plot_height=400, tools="", toolbar_location=None, title='Hover over points')

source = ColumnDataSource({'x0': [], 'y0': [], 'x1': [], 'y1': []})
sr = p.segment(x0='x0', y0='y0', x1='x1', y1='y1', color='olive', alpha=0.6, line_width=3, source=source, )
cr = p.circle(x, y, color='olive', size=30, alpha=0.4, hover_color='olive', hover_alpha=1.0)

# Add a hover tool, that sets the link data for a hovered circle
code = """
const links = %s
const data = {'x0': [], 'y0': [], 'x1': [], 'y1': []}
const indices = cb_data.index.indices

console.log(cb_data.index.indices)

for (var i = 0; i < indices.length; i++) {
    const start = indices[i]
    for (var j = 0; j < links[start].length; j++) {
        const end = links[start][j]
        data['x0'].push(circle.data.x[start])
        data['y0'].push(circle.data.y[start])
        data['x1'].push(circle.data.x[end])
        data['y1'].push(circle.data.y[end])
    }
}
segment.data = data
""" % links

callback = CustomJS(args={'circle': cr.data_source, 'segment': sr.data_source}, code=code)
p.add_tools(HoverTool(tooltips=None, callback=callback, renderers=[cr]))


div = Div(text="""<br>
Here is were I want to display some additional information about the point that is currently hovered over.""",
width=200, height=100)

show(row(p,Spacer(width=20), div))

查看此示例,它完全符合您的要求:https://docs.bokeh.org/en/latest/docs/user_guide/interaction/callbacks.html?highlight=event#customjs-for-user-interaction-events

简而言之,您可以使用 Div 模型并将其 text 属性更改为您想要的任何值。

我想通了:

from bokeh.models import ColumnDataSource, CustomJS, HoverTool, Div, Spacer
from bokeh.plotting import figure, output_file, show
from bokeh.layouts import row

output_file("hover_callback.html")

# define some points and a little graph between them
x = [2, 3, 5, 6, 8, 7]
y = [6, 4, 3, 8, 7, 5]
links = {
    0: [1, 2],
    1: [0, 3, 4],
    2: [0, 5],
    3: [1, 4],
    4: [1, 3],
    5: [2, 3, 4]
}

p = figure(plot_width=400, plot_height=400, tools="", toolbar_location=None, title='Hover over points')

source = ColumnDataSource({'x0': [], 'y0': [], 'x1': [], 'y1': []})
sr = p.segment(x0='x0', y0='y0', x1='x1', y1='y1', color='olive', alpha=0.6, line_width=3, source=source, )
cr = p.circle(x, y, color='olive', size=30, alpha=0.4, hover_color='olive', hover_alpha=1.0)

# Add a hover tool, that sets the link data for a hovered circle
code = """
const links = %s
const data = {'x0': [], 'y0': [], 'x1': [], 'y1': []}
const indices = cb_data.index.indices

console.log(cb_data.index.indices)

for (var i = 0; i < indices.length; i++) {
    const start = indices[i]
    for (var j = 0; j < links[start].length; j++) {
        const end = links[start][j]
        data['x0'].push(circle.data.x[start])
        data['y0'].push(circle.data.y[start])
        data['x1'].push(circle.data.x[end])
        data['y1'].push(circle.data.y[end])
    }
}
segment.data = data
""" % links

callback = CustomJS(args={'circle': cr.data_source, 'segment': sr.data_source}, code=code)
p.add_tools(HoverTool(tooltips=None, callback=callback, renderers=[cr]))


div = Div(text="""<br>
Here is were I want to display some additional information about the point that is currently hovered over.""",
width=200, height=100)

new_code = """
console.log(div_object.text)

const indices = cb_data.index.indices

console.log(indices)

if (indices == undefined || indices.length == 0){{
    div_object.text = ""
}}
else {{
    div_object.text = " currently point with index <b>" + indices.toString(10) + "</b> is selected. Here follows a very long description... <br> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ornare metus at justo semper finibus. Donec malesuada ut nisl ac convallis. Nulla laoreet in metus non dictum. In odio libero, elementum sit amet mi vitae, iaculis tincidunt sem. Quisque eget auctor massa. Nunc pulvinar cursus eros vitae bibendum. Integer vitae pharetra nulla. Integer vitae iaculis ligula. Cras elementum neque magna, posuere semper leo iaculis nec. Curabitur vel neque ut massa efficitur luctus. In at enim sed est pulvinar rhoncus. Aliquam dictum venenatis interdum. Pellentesque accumsan imperdiet varius."
}}

"""

callback = CustomJS(args={'div_object': div}, code=new_code)

p.add_tools(HoverTool(tooltips=None, callback=callback, renderers=[cr]))


show(row(p,Spacer(width=20), div))