Search code examples
pythontooltipbokeh

Bokeh - Do not show tooltip if it has missing value


I'm working on a bokeh figure that shows cluster activity. When a user hovers over a particular processor, I want it to show statistics about the processor. Heres the code:

TOOLTIPS = [
    ("Usage", "@{usage}%"),
    ("Name", "@name"),
    ("PID", "@pid"),
    ("Command", "@command"),
    ("User", "@user"),
]

p = figure(title="Cluster Activity",
           plot_width=1200,
           plot_height=700,
           x_range=nodes,
           y_range=list(reversed(cores)),
           tools='hover',
           toolbar_location=None,
           tooltips=TOOLTIPS
           )

This works, but I don't want to show tooltips with a value of None. For example, if a particular processor, has a None value for User, the tooltip should not contain a user value, rather than showing "User : ???".

Is there any way to do this? I can't seem to find anything similar to this in the tutorials. I'd like to avoid writing custom JS.


Solution

  • You can also create the tooltips dynamically using JS callback attached to the HoverTool (Bokeh 1.1.0)

    from bokeh.plotting import figure, show
    from bokeh.models import ColumnDataSource, HoverTool, CustomJS, FactorRange
    
    pid = [1, 2, 3, 4, 5, 6]
    user = ['user1', 'user2', 'user3', 'user4', None, 'user6']
    name = ['name', 'name2', 'name3', 'name4', 'name5', 'name6']
    
    source = ColumnDataSource(data = dict(pid = pid, user = user, name = name))
    
    p = figure(x_range = FactorRange(*name), sizing_mode = 'stretch_both', title = "Test", toolbar_location = None, tools = "")
    p.vbar(x = 'name', top = 'pid', width = 0.2, source = source)
    
    code = '''  hover.tooltips = [["Name", "@name"], ["PID", "@pid"]];
                if (cb_data.index.indices.length > 0) { 
                    index = cb_data.index.indices[0];
                    counts = source.data.user[index]
    
                    if (counts != null)
                        hover.tooltips = [["Name", "@name"], ["User", "@user"], ["PID", "@pid"]];                                       
                } '''
    hover = HoverTool()
    hover.callback = CustomJS(args = dict(source = source, hover = hover), code = code)
    p.add_tools(hover)
    
    show(p)
    

    Due to the comment below I checked the code for Bokeh v2.1.1 and it seems it still works after modifying the callback to:

    code = '''  if (cb_data.index.indices.length > 0) { 
                    const index = cb_data.index.indices[0];
                    const counts = source.data.user[index]
    
                    if (counts != null) {
                        hover.tooltips = [["Name", "@name"], ["User", "@user"], ["PID", "@pid"]];  
                    }
                    else {
                        hover.tooltips = [["Name", "@name"], ["PID", "@pid"]];
                    }                                     
                } '''
    

    Result:

    enter image description here