Inline figures as tooltip

For my recent showcase post → Geologic Cross Section Tool --> Inline time-series plots , I am using bokeh 3.4.1 using basically this MRE to do the inline figures that appear on hover:

import numpy as np

from bokeh.plotting import figure,save
from bokeh.models import ColumnDataSource, CustomJS, HoverTool
from bokeh.models.dom import Span, Div, Template, ValueRef, DOMElement

def genFigureTemplate(fig):
    '''transforms a figure into a template that can be assigned as a tooltip'''
    htpl = Div()
    htpl.children = [
                    fig,
                    ]
    
    tpl = Template(children=[htpl])
    # tpl = DOMElement(children=[htpl]) #needed for 3.7 +?
    return tpl

data = {'ID':['A','B','C'],'x':[1,2,3],'y':[1,3,1]
        ,'time':[[5,6,7],[3,5,8],[2,3,4]],'value':[[10,9,8],[7,7,9],[1,2,4]]}

src = ColumnDataSource(data)
inline_src = ColumnDataSource(data={'time':[],'value':[]})
fig = figure(tools=['fullscreen'])

r = fig.scatter(x='x',y='y',source=src,size=10)

inline_fig = figure(height=200,width=300)
ilr = inline_fig.line(x='time',y='value',source=inline_src)

hvr_cb = CustomJS(args=dict(src=src,inline_src=inline_src
                            ,inline_fig = inline_fig)
                  ,code='''
                  if (src.inspected.indices.length>0){
                      var hvr_ind = src.inspected.indices[0]
                      inline_src.data = {'time':src.data['time'][hvr_ind]
                                         ,'value':src.data['value'][hvr_ind]}
                      var id = src.data['ID'][hvr_ind]
                      inline_fig.title.text = 'ID '+id
                      inline_src.change.emit()
                      
                      }
                  ''')
                  
tpl = genFigureTemplate(inline_fig)                  
hvr = HoverTool(renderers=[r]
                ,tooltips = tpl
                ,callback=hvr_cb)

fig.add_tools(hvr)

save(fig,r'C:\Repo\example.html')

The basic idea is to embed a figure into a Template, and assign a renderer following an empty CDS. Assign that Template to the HoverTool’s tooltip, and add a callback to the HoverTool that updates the empty CDS with the associated index of the inspected (i.e. hovered) source.

BUT, in 3.4.2, tooltips are broken in fullscreen mode, which was asked about in the showcase post: [BUG] Tooltips not shown when plot is in fullscreen · Issue #13885 · bokeh/bokeh · GitHub

This was resolved however in 3.7: Allow `Tooltip` to show in full-screen mode by mattpap · Pull Request #14145 · bokeh/bokeh · GitHub

BUT, the above setup doesn’t work in 3.7. 1) It appears the expected arguments for the tooltips property on a HoverTool was changed to take a DOMElement instance as opposed to a Template? Is this documented anywhere? If I purposely trigger a ValueError on it in 3.7 I get:

image

And it 3.4 if I do same thing:

image

BUT, in 3.7 I can still supply a Template instance to the tooltip and not trigger the ValueError and the html will write (why?!), but the inline figure does not appear when I hover (blank tooltip).

AND if I modify the genFigureTemplate to return a DOMElement instance instead of a Template, the html fails to render entirely:

Which I am 99% sure is this → Rendering is broken when `HoverTool.tooltips` is a `DOMElement` · Issue #14121 · bokeh/bokeh · GitHub

So for me… I’m gonna be sticking to 3.4.1 and not using fullscreen :smiley: . Any guidance/explanations from core devs would be great here though. :slight_smile:

I also went down a bit of a rabbit hole… there were two use cases I had in mind for having images come up when hovering: static images (eg photos to adorn my displays of kayaking gps routes) or of figures where values can be recomputed in a cds.

I figured out case 1 by supplying hover.tooltips with a div block havig an img section pointing at a url, then updating the hover.tooltips text with the appropriate url in the js callback depending on which object was hovered over.

But I’ve had no luck or inspiration for using figures instead. It seems that Div (at least in 3.6.2) no longer supports the children attribute, so I can’t go the Template route with a Div per this topics’ example.

Is there any other mechanism to do this, or a way to make an in-memory image of the figure or… ?

Richard

It appears the expected arguments for the tooltips property on a HoverTool was changed to take a DOMElement instance as opposed to a Template?

@gmerritt123 a Template is a DOMElement:

So if you are seeing a validation error passing a Template, that is unexpected and seems like a bug.

That said there’s a lot going on here it’s a bit hard for me to follow. I’d just suggest making an issue (or issues) that are as narrowly focused a possible (“this one thing doesn’t work” is a lot easier to consider than “these three things didn’t work”)

I can distill it down to 2 things:

  1. Tooltips didn’t work in full screen mode, it was a noted issue that was fixed in 3.7 (no action required)

  2. Passing a Template (or any DOMElement, thx for clarifying) as a tooltip does not work in 3.7, and this is already a raised/noted issue → Rendering is broken when `HoverTool.tooltips` is a `DOMElement` · Issue #14121 · bokeh/bokeh · GitHub . So no real action needed other than a fix for the issue itself :smiley: I did comment on the issue and pointed to this thread in the event my MRE can help with debug/diagnostics/testing.

1 Like