Reputation: 235
I'm getting into the Bokeh library with Python, but I'm having some trouble. I have the following code from the Bokeh tutorial website:
from bokeh.plotting import figure
from bokeh.io import output_notebook, show
output_notebook()
from bokeh.sampledata.autompg import autompg
from bokeh.models import HoverTool
from bokeh.plotting import ColumnDataSource
grouped = autompg.groupby("yr")
mpg2 = grouped["mpg"]
avg = mpg2.mean()
std = mpg2.std()
years = list(grouped.groups.keys())
american = autompg[autompg["origin"]==1]
japanese = autompg[autompg["origin"]==3]
p = figure(title="MPG by Year (Japan and US)")
p.vbar(x=years, bottom=avg-std, top=avg+std, width=0.8,
fill_alpha=0.2, line_color=None, legend="MPG 1 stddev")
p.circle(x=japanese["yr"], y=japanese["mpg"], size=10, alpha=0.5,
color="red", legend="Japanese")
p.triangle(x=american["yr"], y=american["mpg"], size=10, alpha=0.3,
color="blue", legend="American")
p.legend.location = "top_left"
show(p)
It works, but I'd like to add the functionality that when you hover over a point, it displays the horsepower. What I tried is
grouped = autompg.groupby("yr")
mpg = grouped["mpg"]
avg = mpg.mean()
std = mpg.std()
years = list(grouped.groups.keys())
american = autompg[autompg["origin"]==1]
japanese = autompg[autompg["origin"]==3]
source = ColumnDataSource(data=
dict(autompg)
)
hover1 = HoverTool(tooltips=[("hp", "@hp")])
p = figure(title="MPG by Year (Japan and US)",tools=[hover1])
p.vbar(x=years, bottom=avg-std, top=avg+std, width=0.8,
fill_alpha=0.2, line_color=None, legend="MPG 1 stddev")
p.circle(x=japanese["yr"], y=japanese["mpg"], size=10, alpha=0.5,
color="red", legend="Japanese")
p.triangle(x=american["yr"], y=american["mpg"], size=10, alpha=0.3,
color="blue", legend="American")
p.legend.location = "top_left"
show(p)
So defining a HoverTool that I hoped would do just that. Unfortunately, it only displays "hp: ???" for every entry. I think it's a problem with the data source, but I don't have much experience here and can't figure it out myself. I've tried the source without dict(), and I've tried to set it as american or japanese, but none of this made a difference.
Thanks!
Upvotes: 6
Views: 10897
Reputation: 34568
You need to pass the source
to the glyph functions, and refer to the column names for the coordinates. If you pass literal lists/arrays (as you are doing above) to circle
, etc. then Bokeh will create a CDS for that data under the covers, but only with the just the data you pass to the glyph function (i.e. without extra columns like "hp"). Since you are trying to plot different glyphs for different subsets of the data, the simplest thing will be to use a CDSView
to group them on the client. Something like this instead:
from bokeh.plotting import figure
from bokeh.io import show
from bokeh.sampledata.autompg import autompg
from bokeh.models import ColumnDataSource, CDSView, GroupFilter, HoverTool
p = figure()
# Bokeh factors must be strings
autompg.origin = [str(x) for x in autompg.origin]
source = ColumnDataSource(autompg)
# view for just japanese origin
japanese = CDSView(source=source, filters=[GroupFilter(column_name='origin', group="1")])
# draw circles for just the japanese view
p.circle(x="yr", y="mpg", size=10, alpha=0.5, color="red", legend="Japanese",
source=source, view=japanese)
# view for just japanese origin
american = CDSView(source=source, filters=[GroupFilter(column_name='origin', group="3")])
# draw triangles for just the american view
p.triangle(x="yr", y="mpg", size=10, alpha=0.5, color="blue", legend="american",
source=source, view=american)
p.add_tools(HoverTool(tooltips=[("hp", "@hp")]))
show(p)
Upvotes: 7