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.
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:
I see two ways of doing this:
1. Checking if Name is None with Python and using multiple HoverTool
Since HoverTool is a bokeh.models.tools you can add it via
p.add_tools(hovertool)
So you could make two instances of HoverTool and split your data to two data sources:
p = figure(title="Cluster Activity",
plot_width=1200,
plot_height=700,
toolbar_location=None)
without = p.square(name="without", ##your filtered data source without names)
with = p.square(name="with", ##your filtered data source with names)
hoverwith = HoverTool(names=["with"],tooltips=TOOLTIPS = [
("Usage", "@{usage}%"),
("Name", "@name"),
("PID", "@pid"),
("Command", "@command"),
("User", "@user"),
])
hoverwithout = HoverTool(names=["without"],tooltips=TOOLTIPS = [
("Usage", "@{usage}%"),
("PID", "@pid"),
("Command", "@command"),
("User", "@user"),
])
p.add_tools(hoverwith, hoverwithout)
With the names attribute of HoverTool you can specify for which glyps the hover is rendered. I haven't tested the code.
2. Using custom JS (just mentioning for the sake of completeness)
In case you have many different combinations of possible missing values, I only see JS as a way to do this, have a look here: https://groups.google.com/a/continuum.io/forum/#!msg/bokeh/4VxEbPaLqnA/-qYLDsbZAwAJ
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With