Applying a function to a hover tool tooltip value

In a tooltip, I’d like to be able to transform the value of one of the data columns and display that transformed value. In my case, given a dictionary, I want to use the column value as a dictionary key and return the corresponding dictionary value. I’m using a bokeh HoverTool to customize the hover tool, with bokeh 2.4.3. But I don’t see anything in Configuring plot tools — Bokeh 2.4.2 Documentation that suggests this is possible. The tooltip value can mix and match values from different columns and apply formatting customizations.

Does anyone know if this is possible, and how?
Thanks.

Maybe this can help.
periodic_shells — Bokeh 3.2.2 Documentation

More discussion below:
[FEATURE] Documentation and examples for embedding plots inside tooltips · Issue #13375 · bokeh/bokeh (github.com)
Drilldown support · Issue #5884 · holoviz/holoviews (github.com)

Thanks! I’m looking into it

I see what you mean with the use of bokeh Template and other bokeh.models.dom elements. This might be lower level than I’d prefer, but it could work.

I like what’s in your example with hvplot/holoviews in Drilldown support · Issue #5884 · holoviz/holoviews · GitHub. But it refers to a PR that’s not merged, so I assume this example code would not work on a released version of hvplot/holoviews?

1 Like

That is correct; it will not work at the moment. Feel free to bump the issue / PR.

Here is a simple example:

import pandas as pd
import holoviews as hv
hv.extension( "bokeh", "plotly", logo=False)
from bokeh.models import HoverTool, CustomJSHover
# Syntax: $. are 'special fields':  $x inserts the x-coordinate
#         @. are fields from the color data source:
#            provide an extra column of values and declare it's name as a vdim (or sue a pd.DataFrame)

data  = pd.DataFrame( { 'x': [1.1, 3.2, 5.8 ], 'state': ['NY', 'NJ', 'PA'], 'stuff': ['a','b','c']} )
hover = HoverTool(tooltips=[ ("error", "$x"),
                            ("state", "@state"),
                            ("stuff", "@stuff{custom}")
                           ],
                  formatters = {
                      "@stuff" : CustomJSHover(code="return value.toUpperCase()")
                  }
                 )
hv.Scatter( data, kdims='x', vdims=['state', 'stuff']).opts(tools=[hover], size=10).redim.range(x=(0,7))
2 Likes

Thank you @ea42gh ! That’s a really interesting mix of the HoverTool and very targeted/focused JavaScript functionality. I’ll see what I can do with it, but it looks promising.

Success!! @ea42gh 's code pointed me in the right direction (the use of CustomJSHover for a specific field), but it was limiting in that it only had access to the value from the column (value). Ultimately what I need it to be able to pass a Python variable (in my case, a dictionary) to the code in CustomJSHover.

This old bokeh thread gave me the missing piece: the use of arg in CustomJSHover.

I’ve modified @ea42gh 's code to work with what I needed. Note that I don’t know if the use of ColumnDataSource is strictly needed, but I’m not proficient enough with bokeh to know if there’s a simpler alternative.

Thanks for your help, @ea42gh and @ahuang11 ! This is great. I’d rather not have to dive too much into JavaScript, but here it’s limited to just enough. I can live with that.

import pandas as pd
import holoviews as hv
hv.extension( "bokeh")
from bokeh.models import HoverTool, CustomJSHover, ColumnDataSource

data  = pd.DataFrame( { 'x': [1.1, 3.2, 5.8 ], 'state': ['NY', 'NJ', 'PA'], 'stuff': ['a','b','c']} )

mydict = dict(a=1, b=2, c=3)

hover = HoverTool(
    tooltips=[ 
        ("error", "$x"),
        ("state", "@state"),
        ("stuff", "@stuff{custom}")
    ],
    formatters = {
        "@stuff" : CustomJSHover(
            args=dict(mappedDict=ColumnDataSource(dict(mydict=[mydict]))),
            code="return mappedDict.data.mydict[0][value]"
        )
    }
)

hv.Scatter( data, kdims='x', vdims=['state', 'stuff']).opts(tools=[hover], size=10).redim.range(x=(0,7))
2 Likes