散景中点击工具的 JS 回调

JS callback for tap tools in bokeh

我想做一个交互式图表。在第一个图中,使用“点击”小部件,选择“悬停”小部件显示的值“x”,在第二个图上绘制值 d(:,x)。当您再次单击“点击”小部件到图 1 中的另一个位置时,图 2 会更新。但我不知道如何为“点击”小部件编写回调。 我正在寻找的一个例子是这个

提供的代码创建了两个图,但不更新第二个图:

import numpy as np
from bokeh.plotting import figure, output_file, show, ColumnDataSource
from bokeh.plotting import figure, show
from bokeh.layouts import row
import os
from numpy.lib.function_base import select
import pandas as pd
from bokeh.models import ColumnDataSource, CustomJS, TapTool


N = 500
x = np.linspace(0, 10, N)
y = np.linspace(0, 10, N)
xx, yy = np.meshgrid(x, y)
d = np.sin(xx)*np.cos(yy)
len_d=len(d)

plot1 = figure(tooltips=[("x", "$x{0}"), ("y", "$y"), ("value", "@image")],
             plot_height=350, plot_width=400,title="Graph 1 d",tools = "tap")
plot2=figure(plot_height=350, plot_width=400, title="Graph 2 d(tap selection(x))", 
              tools="pan,box_select,crosshair,box_zoom,reset,save,wheel_zoom,hover") 

#f = d[:,select]
lines = plot2.line(x = 'x', y = 'y', source = ColumnDataSource({'x': d[0] , 'y': -np.arange(len_d)}))
lines.visible = False
plot1.x_range.range_padding = plot1.y_range.range_padding = 0

data = dict(
    image=[d], pattern=['smooth ramp'],
    x=[0], y=[5], dw=[20], dh=[10]
)

code = '''if (cb_data.source.selected.indices.length > 0){
            lines.visible = true;
            var selected_index = cb_data.source.selected.indices[0];
            lines.data_source.data['x'] = d[selected_index]
            lines.data_source.change.emit(); 
          }'''

cds = ColumnDataSource(data=data)
plot1.image(source=cds, x=0, y=-len(d), dw=len(d[0]), dh=len(d),palette='Spectral11', level="image")
plot1.grid.grid_line_width = 0.5
plot1.select(TapTool).callback = CustomJS(args = {'lines': lines, 'd': d}, code = code)
plots = row(plot1, plot2)
show(plots)

非常感谢您提供的任何帮助

这是一个从图像中选择数据的解决方案。

import numpy as np
import pandas as pd

from bokeh.plotting import figure, output_notebook, show
from bokeh.layouts import row
from bokeh.models import ColumnDataSource, CustomJS
output_notebook()

N = 500
x = np.linspace(0, 10, N)
y = np.linspace(0, 10, N)
xx, yy = np.meshgrid(x, y)
d = np.sin(xx)*np.cos(yy)
len_d=len(d)

data = dict(
    image=[d], pattern=['smooth ramp'],
    x=[0], y=[5], dw=[20], dh=[10]
)
# plot 1
cds_p1 = ColumnDataSource(data=data)
plot1 = figure(
    plot_height=350,
    plot_width=400,
    title="Graph 1 d",
    x_range =(0,500),
    y_range =(-500, 0),
    tooltips=[("x", "$x{0}")]
)
plot1.grid.grid_line_width = 0.5
plot1.image(
    source=cds_p1,
    x=0,
    y=-len_d,
    dw=len_d,
    dh=len_d,
    palette='Spectral11',
    level="image"
)
# plot 2
y_index = -np.arange(len_d)
cds_p2 = ColumnDataSource(
    {'x': d[0] , 'y':-np.arange(len_d) }
)

plot2=figure(
    plot_height=350,
    plot_width=400,
    title="Graph 2 d(tap selection(x))",
    x_range =(-1,1),
    y_range =(-500, 0),
    tools="") 
plot2.line(x = 'x', y = 'y', source=cds_p2)

# important JS part
callback = CustomJS(
    args=dict(cds_original=cds_p1, cds_p2=cds_p2),
    code="""
    // console.log('Tap event occurred at x-position: ' + cb_obj.x)
    
    const data = cds_original.data
    const next = cds_p2.data
    var xpos = Math.round(cb_obj.x)
    
    console.log((xpos-1)*500)
    console.log(data['image'])
    
    var x = []
    for(var i=xpos; i<500*500; i+=500){
        console.log(data['image'][0][i])
        x.push(data['image'][0][i])
    }
    next['x'] = x
    console.log(next)
    cds_p2.change.emit()
""")
plot1.js_on_event('tap', callback)

plots = row(plot1, plot2)
show(plots)

我认为这不是最终的解决方案,但也许这会让您更近一步。