Bokeh hovertools which run arbitrary python code

前端 未结 1 1007
灰色年华
灰色年华 2021-01-15 19:49

I am using Bokeh to try and create a figure whose data points when \'hovered\' over by the user will display another graph within the hover tool, showing additional informa

1条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-15 20:02

    You can use Python callback only in Bokeh server applications. It seems impossible to use Python callbacks for a HoverTool (it must be always a JS callback, or you get this error: ValueError: expected an instance of type Callback, got of type function).

    The following solution uses JS callback and it shows a small "tooltip plot" when hovering the circles on the main plot (works for Bokeh v1.0.4 and only if there are 2 plots in the Bokeh document):

    from bokeh.plotting import figure, show
    from bokeh.layouts import gridplot, Row
    from bokeh.models import ColumnDataSource, CDSView, BooleanFilter, CustomJS, BoxSelectTool, HoverTool
    import pandas as pd
    
    data = {'x': [1, 2, 3],
            'y':[1, 2, 3],
            'xs':[[9, 8, 7], [6, 5, 4], [3, 2, 1]],
            'ys':[[29, 28, 29], [27, 28, 27], [25, 25, 20]]}
    source = ColumnDataSource(data)
    plot = figure(title = 'PLOT IN HOVER TOOLTIP', tools = '')
    circles = plot.circle('x', 'y', size = 20, source = source)
    
    plot_tooltip = figure(name = 'plot_tooltip', plot_width = 200, plot_height = 200, x_axis_location = None, y_axis_location = None, title = None, tools = 'hover', tooltips = [("x", "@x"), ("y", "@y")], toolbar_location = None)
    lines = plot_tooltip.line('x', 'y', source = ColumnDataSource({'x': [], 'y': []}))
    circles2 = plot_tooltip.circle('x', 'y', source = ColumnDataSource({'x': [], 'y': []}))
    
    code = """  
    var indices = cb_data.index['1d'].indices;
    if (indices.length > 0){
        if(plot_tooltip.x_range.bounds == null)
        {
            Bokeh.documents[0].add_root(plot_tooltip)
        }
        const idx = indices[0]
        lines.data_source.data['x'] = source.data['xs'][idx]
        lines.data_source.data['y'] = source.data['ys'][idx]
        lines.data_source.change.emit();
    
        circles.data_source.data['x'] = source.data['xs'][idx]
        circles.data_source.data['y'] = source.data['ys'][idx]
        circles.data_source.change.emit();  
    
        div = document.getElementsByClassName('bk-root')[1];
        div.style = "position:absolute; left:" + cb_data.geometry['sx'] + "px; top:" + cb_data.geometry['sy'] + "px;";              
    } """
    
    callback = CustomJS(args = dict(source = source, lines = lines, circles = circles2, plot_tooltip = plot_tooltip), code = code)
    
    hover = HoverTool()
    hover.callback = callback
    hover.tooltips = None
    hover.renderers = [circles]
    plot.add_tools(hover)
    
    show(plot)
    

    Result:

    0 讨论(0)
提交回复
热议问题