Bokeh hovertools which run arbitrary python code

若如初见. 提交于 2019-12-01 12:02:43

问题


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 information about that data point (i.e., in the main figure data points are the mean of a time-series over a set interval, I want the hover tool to show all the data in that interval).

The user guide (full code copied in below) provides one solution: use a custom HTML tooltip to reference figures on file. This would, however, require me creating all the figures on file (which could be up 10,000) to be referenced. This is too large a time overhead so I was hoping for a better solution. Namely: Is it possible for hover tools to run python code on the fly, such that they can display plots of the data interactively?

(Example image, take from user guide, below code)

The below code was copied from the bokeh user guide on 19th March 2019.

from bokeh.plotting import figure, output_file, show, ColumnDataSource

output_file("toolbar.html")

source = ColumnDataSource(data=dict(
    x=[1, 2, 3, 4, 5],
    y=[2, 5, 8, 2, 7],
    desc=['A', 'b', 'C', 'd', 'E'],
imgs=[
    'http://docs.bokeh.org/static/snake.jpg',
    'http://docs.bokeh.org/static/snake2.png',
    'http://docs.bokeh.org/static/snake3D.png',
     'http://docs.bokeh.org/static/snake4_TheRevenge.png',
    'http://docs.bokeh.org/static/snakebite.jpg'
],
fonts=[
    '<i>italics</i>',
    '<pre>pre</pre>',
    '<b>bold</b>',
    '<small>small</small>',
    '<del>del</del>'
]
))

TOOLTIPS = """
<div>
    <div>
        <img
            src="@imgs" height="42" alt="@imgs" width="42"
            style="float: left; margin: 0px 15px 15px 0px;"
            border="2"
        ></img>
    </div>
    <div>
        <span style="font-size: 17px; font-weight: bold;">@desc</span>
        <span style="font-size: 15px; color: #966;">[$index]</span>
    </div>
    <div>
        <span>@fonts{safe}</span>
    </div>
    <div>
        <span style="font-size: 15px;">Location</span>
        <span style="font-size: 10px; color: #696;">($x, $y)</span>
    </div>
</div>
"""

p = figure(plot_width=400, plot_height=400, tooltips=TOOLTIPS,
       title="Mouse over the dots")

p.circle('x', 'y', size=20, source=source)

show(p)


回答1:


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 <function callback at 0x114fdbb90> 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:



来源:https://stackoverflow.com/questions/55244088/bokeh-hovertools-which-run-arbitrary-python-code

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!