无法在Bokeh中获得CrossHairTool来链接多个图

问题描述

我研究了这篇文章

“如何将bokeh中的CrossHairTool链接到多个图?” (请参见How do I link the CrossHairTool in bokeh over several plots?

在这篇帖子中使用了 Hamid Fadishei 编写的功能,但无法设法使CrossHairTool正确显示在多个图上。

在我的实现中,十字准线仅显示在悬停的绘图内。我目前正在使用bokeh版本 2.1.1 和Python Anaconda版本 3.7.6 ,并使用VSCode 1.48版本中的Python扩展。我不熟悉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',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,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,x_range=fig_1.x_range,y_axis_label='B',tools=select_tools)

fig_2.line(x='Date',y='B',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=[('','@B{0.00 a}')],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)

myGraph enter code here

解决方法

这里是a solution that works,从散景2.2.1开始:对于需要链接的所有图,只需使用相同的十字线工具对象。像这样:

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))