HELP: Add HoverTool with Custom Legend

I want to be able to add a Hovertool when I create a Custom Legend. I have tried to do the following with no success:

  • Create new Column Data Source within the for loop
  • Change where I put the add_tools

Here is me trying to convert each dataframe to ColumnDataSource:

import pandas as pd
import bokeh

from bokeh.palettes import Spectral4
from bokeh.plotting import figure, output_file, show, ColumnDataSource
from bokeh.models.tools import HoverTool

bokeh.sampledata.download()

AAPL = pd.read_csv("C:/Users/chelsey.marie/.bokeh/data/AAPL.csv")
IBM = pd.read_csv("C:/Users/chelsey.marie/.bokeh/data/IBM.csv")
MSFT = pd.read_csv("C:/Users/chelsey.marie/.bokeh/data/MSFT.csv")
GOOG = pd.read_csv("C:/Users/chelsey.marie/.bokeh/data/GOOG.csv")  

p = figure(plot_width=800, plot_height=250, x_axis_type="datetime")
p.title.text = 'Click on legend entries to hide the corresponding lines'

TOOLTIPS = [
    ("DATE: ", "@date"),
    ("VALUE: ", "@Close")
]

for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4):
    df = pd.DataFrame(data)
    df['date'] = pd.to_datetime(df['Date'])
    p.line('date', 'Close',source = sample, line_width=2, color=color, alpha=0.8, legend=name)

p.legend.location = "top_left"
p.legend.click_policy="hide"


output_file("interactive_legend.html", title="interactive_legend.py example")

show(p)

This results in the plot generating but no HoverTool

It’s not clear to me what you actually want. What does “create custom legend” mean? Does “I” above refer to “you”, the developer of the plot, or “you” the viewer of the plot? Please explain in more detail what exactly it is that you want to happen in terms of user interactions.

I = developer of the plot.

The custom legend is the for loop = the ability to click on each level in the legend to hide data when the plot is generated.

I want to be able to use the HoverTool as well but I am having issues because now the data is being split of different sizes.

What does

mean? Is the hover not showing up at all? Or is it showing up, but with ??? placeholders? Something else? Are you getting Python errors when you run the code? Or are there JavaScipt error messages in the browser JS console when the output is viewed? For us to be able to help, you need to describe what is happening in great detail. Screenshots are also often very useful for conveying information very efficiently.

Also I just noticed that this is a cross-post. If you must cross-post questions in different forums (e.g. StackOverflow), we appreciate if you add cross-links everywhere, so that future users can always get to an answer, regardless of where they find find the question. (Please add these links)

Bryan, I can only provide certain information and code for the privacy of the product.
I just posted the question in both locations to see if anyone is able to help.

When you execute the code, you will be able to see the errors.

The information I know about HoverTool:

  • you must convert the pandas dataframe to ColumnDataSource to be able to use the HoverTool capability.

The information I know about the “Interactive Legend” (Capability documented in Bokeh):

  • You must subset the data through a for loop and command the plot (p.line, p.circle, etc) for each dataframe
  • then command p.legend.click_policy = “hide”

Knowing this information about both processes, I am failing to be able to use both BECAUSE:

  • When I try to convert each dataframe into ColumnDataSource, a
Supplying a user-defined source AND iterable values to glyph methods is\nnot possible
  • When I try to declare each plot to a unique variable, using vars() and then using the p.add_tools(HoverTool(renderers = vars(), tools= TOOLTIPS)) I get
error handling message Message'PATCH-DOC' (revision 1) KeyError('x0',)
  • When I try to update the source (i.e. ColumnDataSource) using source.data.update(**df), nothing happens

I will be more than happy to put the exact code example once we have an understanding that you know something about HoverTool and the Interactive Legend features. If you dont know about them, you are less likely going to be able to help.

Just for reference, I am the co-creator of Bokeh and have been the project lead for the last decade.

Bryan, I can only provide certain information and code for the privacy of the product.

That’s perfectly understandable, but it may mean that you need to seek paid consulting services where, e.g. an NDA can be put in place, rather than rely on help in public forums. There is simply only so much speculation that can be made on incomplete information.

As a prime example, this message:

error handling message Message'PATCH-DOC' (revision 1) KeyError('x0',)

is completely inconsistent with the code above. This message relates to, and can only happen in the context of a Bokeh server application. But the code above is for standalone output with show (static HTML, no Bokeh server). So which is it?

Also, this is unintelligible because the formatting tools available in Discourse have not been used:

You seem to have multiple issues/questions but are not providing full information for any of them. So I will make it simple and state plainly that what is needed to speculate further is a complete Minimal Reproducible Example that can be run, as-is to investigate and see what you are seeing, and experiment with directly. (i.e. with any mock or synthesized data necessary to run as well). Absent that, I will not be able to help you, myself.

I was able to find the solution myself :relaxed: Thank you Bryan

I’m glad to hear that. Please self-answer your SO question for the benefit of others (or delete it, if you don’t think it is useful to others).

p = figure(plot_width=800, plot_height=250, x_axis_type="datetime")
p.title.text = 'Click on legend entries to hide the corresponding lines'

TOOLTIPS = [
    ("DATE: ", "@date"),
    ("VALUE: ", "@Close")
]

for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4):
    df = pd.DataFrame(data)
    df['date'] = pd.to_datetime(df['Date'])
    sample = ColumnDataSource(df)
    p.line('date', 'Close',source = sample, line_width=2, color=color, alpha=0.8, legend=name)
    p.add_tools(HoverTool(tooltips = TOOLTIPS))


p.legend.location = "top_left"
p.legend.click_policy="hide"


output_file("interactive_legend.html", title="interactive_legend.py example")

show(p)
1 Like