无法将 Bokeh 中的 CrossHairTool 链接到多个图

Can't get CrossHairTool in Bokeh to be linked over several plots

我研究过 post:

“我如何 link CrossHairTool 在几个地块上的散景中?” (参见 How do I link the CrossHairTool in bokeh over several plots?

我使用了 Hamid Fadishei 于 2020 年 6 月在此 post 中编写的函数,但无法使 CrossHairTool 正确显示多个图。

在我的实现中,十字准线仅在悬停的绘图内显示。我目前正在使用 Bokeh 版本 2.1.1 和 Python Anaconda 版本 3.7.6 使用 Python 扩展 VSCode 版本 1.48。我不熟悉 Javascript,因此欢迎任何有助于调试我的代码以正确显示横跨两个图的十字准线的帮助。

我的代码:

# Importing libraries:
import pandas as pd
import random
from datetime import datetime, timedelta
from bokeh.models import CustomJS, CrosshairTool, ColumnDataSource, DatetimeTickFormatter, HoverTool
from bokeh.layouts import gridplot
from bokeh.plotting import figure, output_file, show

# Function wrote by Hamid Fadishei to enable a linked crosshair within gridplot:
def add_vlinked_crosshairs(figs):
    js_leave = ''
    js_move = 'if(cb_obj.x >= fig.x_range.start && cb_obj.x <= fig.x_range.end &&\n'
    js_move += 'cb_obj.y >= fig.y_range.start && cb_obj.y <= fig.y_range.end){\n'
    for i in range(len(figs)-1):
        js_move += '\t\t\tother%d.spans.height.computed_location = cb_obj.sx\n' % i
    js_move += '}else{\n'
    for i in range(len(figs)-1):
        js_move += '\t\t\tother%d.spans.height.computed_location = null\n' % i
        js_leave += '\t\t\tother%d.spans.height.computed_location = null\n' % i
    js_move += '}'
    crosses = [CrosshairTool() for fig in figs]
    for i, fig in enumerate(figs):
        fig.add_tools(crosses[i])
        args = {'fig': fig}
        k = 0
        for j in range(len(figs)):
            if i != j:
                args['other%d'%k] = crosses[j]
                k += 1
        fig.js_on_event('mousemove', CustomJS(args=args, code=js_move))
        fig.js_on_event('mouseleave', CustomJS(args=args, code=js_leave))

# Create dataframe consisting of 5 random numbers within column A and B as a function of an arbitrary time range:
startDate = datetime(2020,5,1)
timeStep = timedelta(minutes = 5)
df = pd.DataFrame({
    "Date": [startDate  + (i * timeStep) for i in range(5)],
    "A": [random.randrange(1, 50, 1) for i in range(5)],
    "B": [random.randrange(1, 50, 1) for i in range(5)]})

# Generate output file as html file:
output_file("test_linked_crosshair.html", title='Results')
# Define selection tools within gridplot:
select_tools = ["xpan", "xwheel_zoom", "box_zoom", "reset", "save"]

sample = ColumnDataSource(df)

# Define figures:
fig_1 = figure(plot_height=250,
             plot_width=800,
             x_axis_type="datetime",
             x_axis_label='Time',
             y_axis_label='A',
             toolbar_location='right',
             tools=select_tools)

fig_1.line(x='Date', y='A',
          source=sample,
          color='blue',
          line_width=1)

fig_2 = figure(plot_height=250,
             plot_width=800,
             x_range=fig_1.x_range,
             x_axis_type="datetime",
             x_axis_label='Time',
             y_axis_label='B',
             toolbar_location='right',
             tools=select_tools)

fig_2.line(x='Date', y='B',
          source=sample,
          color='red',
          line_width=1)

# Define hover tool for showing timestep and value of crosshair on graph:
fig_1.add_tools(HoverTool(tooltips=[('','@Date{%F,%H:%M}'),
                                   ('','@A{0.00 a}')],
                         formatters={'@Date':'datetime'},mode='vline'))

fig_2.add_tools(HoverTool(tooltips=[('','@Date{%F,%H:%M}'),
                                   ('','@B{0.00 a}')],
                         formatters={'@Date':'datetime'},mode='vline'))

# Calling function to enable linked crosshairs within gridplot:
add_vlinked_crosshairs([fig_1, fig_2])
# Generate gridplot:
p = gridplot([[fig_1], [fig_2]])
show(p)

myGraphenter code here

这是从 Bokeh 2.2.1 开始的 a solution that works:只需对所有需要它链接的绘图使用 相同的十字准线工具对象 。像这样:

import numpy as np
from bokeh.plotting import figure, show
from bokeh.layouts import gridplot
from bokeh.models import CrosshairTool

plots = [figure() for i in range(6)]
[plot.line(np.arange(10), np.random.random(10)) for plot in plots]

linked_crosshair = CrosshairTool(dimensions="both")

for plot in plots:
    plot.add_tools(linked_crosshair)

show(gridplot(children=[plot for plot in plots], ncols=3))