How to show column names in tooltip in Bokeh - python

I cannot find a way how to place a series name in a tooltip instead of ???. Here is a simple code that I tried and the output:
from bokeh.plotting import figure, output_file, show
from bokeh.models import HoverTool
x_data = [[2,4,6,8], [2,4,6,8]]
y_data = [[2,5,9,6], [5,7,6,2]]
names = ['y1', 'y2']
output_file('index.html')
p = figure(plot_width=300, plot_height=200)
p.multi_line(x_data, y_data)
p.add_tools(HoverTool(tooltips=[
('Name', '#names')
]))
show(p)
I tried several formats of names list (or list of lists), but no success.
Do you have any idea?

Based on the scatter plot example in the documentation (here), it looks like the way to go is to create a dictionnary with all the keys and values that you need for your plot and hover tool. And create a ColumnDataSource based on this dictionary. See code below:
from bokeh.plotting import figure, output_file, show, ColumnDataSource
from bokeh.models import HoverTool
source=ColumnDataSource({'x_data':[[2,4,6,8], [2,4,6,8]],'y_data':[[2,5,9,6], [5,7,6,2]],'names':['y1', 'y2']})
output_file('index.html')
p = figure(plot_width=300, plot_height=200)
p.multi_line('x_data', 'y_data',source=source)
p.add_tools(HoverTool(tooltips=[('Name', '#names')]))
show(p)
And the result shows the correct tooltips:

Related

bokeh line plot with string x value

I want to make out a bokeh line plot with string x-value but I just get an empty bokeh plot
sample={'A':['2012-01','2012-02','2012-03'],'B':[7,8,9]}
from bokeh.plotting import figure, output_file, show
source2 = ColumnDataSource(sample)
p = figure(width=400, height=400)
p.line(x='A',y='B',source=source2, line_width=2)
output_notebook()
show(p)
Please notice, you should always check the imports. In your example two imports are missing.
To use date representation in bokeh, you can set the x_axis_type to "datetime" but this will enable only the DatetimeFormatter. Befor this, you have to transform the date string somehow into a number. One easy option is to use pandas.to_datetime().
This tutorial shows how to enable datetime axes.
Example
import pandas as pd
from bokeh.plotting import figure, output_notebook, show
from bokeh.models import ColumnDataSource
sample={'A':[pd.to_datetime(x) for x in ['2012-01','2012-02','2012-03']],'B':[7,8,9]}
source = ColumnDataSource(sample)
p = figure(width=400, height=400, x_axis_type='datetime')
p.line(x='A', y='B', source=source, line_width=2)
output_notebook()
show(p)
Output

Unable to use Bokeh and Panda to read a csv and plot it

I'm trying to plot a line graph from a simple CSV file with two columns using Bokeh for data visualisation and Panda to read the CSV and handle the data. However, i can't seem to pass the data I've imported using pandas to Bokeh to plot my line graph.
This is running locally on my computer. I've tried and debugged each section of the code and the sole problem seems to occur when I pass the data from pandas to bokeh.
I've tried printing the columns I've selected from my csv to check that the entire column has been selected too.
#Requirements for App
from bokeh.plotting import figure, output_file, show
import pandas as pd
from bokeh.models import ColumnDataSource
#Import data-->Weight measurements over a period of time [ STUB ]
weight = pd.read_csv("weight.csv")
#Define parameters
x=weight["Date"]
y=weight["Weight"]
#Take data and present in a graph
output_file("test.html")
p = figure(plot_width=400, plot_height=400)
p.line(x,y,line_width=2)
show(p)
I expect to get a line graph that plots each weight entry each day but I get a blank plot.
This should work. Pandas doesn't know that it is working with dates so you have to specify this with pd.to_datetime().
#!/usr/bin/python3
from bokeh.plotting import figure, output_file, show
import pandas as pd
from bokeh.models import DatetimeTickFormatter, ColumnDataSource
#Import data-->Weight measurements over a period of time [ STUB ]
weight = pd.read_csv("weight.csv")
#Define parameters
weight["Date"] = pd.to_datetime(weight['Date'])
weight["Weight"] = pd.to_numeric(weight['Weight'])
source = ColumnDataSource(weight)
#Take data and present in a graph
output_file("test.html")
p = figure(plot_width=400, plot_height=400, x_axis_type='datetime')
p.line(x='Date',y='Weight',line_width=2, source=source)
p.xaxis.formatter=DatetimeTickFormatter(
minutes=["%M"],
hours=["%H:%M"],
days=["%d/%m/%Y"],
months=["%m/%Y"],
years=["%Y"]
)
show(p)

Multiple HoverTools for different lines (bokeh)

I have more than one line on a bokeh plot, and I want the HoverTool to show the value for each line, but using the method from a previous stackoverflow answer isn't working:
https://stackoverflow.com/a/27549243/3087409
Here's the relevant code snippet from that answer:
fig = bp.figure(tools="reset,hover")
s1 = fig.scatter(x=x,y=y1,color='#0000ff',size=10,legend='sine')
s1.select(dict(type=HoverTool)).tooltips = {"x":"$x", "y":"$y"}
s2 = fig.scatter(x=x,y=y2,color='#ff0000',size=10,legend='cosine')
fig.select(dict(type=HoverTool)).tooltips = {"x":"$x", "y":"$y"}
And here's my code:
from bokeh.models import HoverTool
from bokeh.plotting import figure
source = ColumnDataSource(data=dict(
x = [list of datetimes]
wind = [some list]
coal = [some other list]
)
)
hover = HoverTool(mode = "vline")
plot = figure(tools=[hover], toolbar_location=None,
x_axis_type='datetime')
plot.line('x', 'wind')
plot.select(dict(type=HoverTool)).tooltips = {"y":"#wind"}
plot.line('x', 'coal')
plot.select(dict(type=HoverTool)).tooltips = {"y":"#coal"}
As far as I can tell, it's equivalent to the code in the answer I linked to, but when I hover over the figure, both hover tools boxes show the same value, that of the wind.
You need to add renderers for each plot. Check this. Also do not use samey label for both values change the names.
from bokeh.models import HoverTool
from bokeh.plotting import figure
source = ColumnDataSource(data=df)
plot = figure(x_axis_type='datetime',plot_width=800, plot_height=300)
plot1 =plot.line(x='x',y= 'wind',source=source,color='blue')
plot.add_tools(HoverTool(renderers=[plot1], tooltips=[('wind',"#wind")],mode='vline'))
plot2 = plot.line(x='x',y= 'coal',source=source,color='red')
plot.add_tools(HoverTool(renderers=[plot2], tooltips=[("coal","#coal")],mode='vline'))
show(plot)
The output look like this.

Configure the tooltip of Bokeh from pandas.DataFrame column

I have a simple pandas.DataFrame:
df = pd.DataFrame(
{
"name": ['foo','bar'],
"kpi1": [1,2],
"kpi2": [2,1]
}
)
Which I want to scatter plot using Bokeh. First step is:
import bokeh.plotting as bpl
import bokeh.models as bmo
bpl.output_notebook()
p = bpl.figure(tools=["hover"])
p.scatter(
'kpi1',
'kpi2', source=source)
bpl.show(p) # open a browser
Next, I want to configure the tooltip. In particular I want to see the index of each point and the associated name. Here's the second step:
source = bpl.ColumnDataSource.from_df(df)
hover = bmo.HoverTool(
tooltips=[
("index", "$index"),
('Name', '$name')
]
)
p = bpl.figure(tools=[hover])
p.scatter(
'kpi1',
'kpi2', source=source)
bpl.show(p) # open a browser
This works partially. The tooltip contains two fields (index and Name) but the latter is filled with ???. How can I make it read the right column from the dataframe and use it for the tooltip's field?
That is because you call the tooltips with $ instead of #.
The correct definition would be
hover = bmo.HoverTool(
tooltips=[
("index", "#index"),
('Name', '#name')
]
)
By the way, you don't need to to import bokeh.plotting and bokeh.models as a variable. You can sinmply do:
from bokeh.plotting import figure, ColumnDataSource
from bokeh.io import output_file, show
from bokeh.models import HoverTool
and then
# Create a ColumnDataSource from df: source
source = ColumnDataSource(df)
# Create the figure: p
p = figure(tools=["hover"])
# Add circle glyphs to the figure p
p.circle('kpi1', 'kpi2', source= source)
show(p)
hover = HoverTool(tooltips=[("index", "#index"),
('Name', '#name')])
p.add_tools(hover)
show(p)

Bokeh hovertool in multiple_line plot

I'm new to bokeh and I just jumped right into using hovertool as that's why I wanted to use bokeh in the first place.
Now I'm plotting genes and what I want to achieve is multiple lines with the same y-coordinate and when you hover over a line you get the name and position of this gene.
I have tried to mimic this example, but for some reason the I can't even get it to show coordinates.
I'm sure that if someone who actually knows their way around bokeh looks at this code, the mistake will be apparent and I'd be very thankful if they showed it to me.
from bokeh.plotting import figure, HBox, output_file, show, VBox, ColumnDataSource
from bokeh.models import Range1d, HoverTool
from collections import OrderedDict
import random
ys = [10 for x in range(len(levelsdf2[(name, 'Start')]))]
xscale = zip(levelsdf2[('Log', 'Start')], levelsdf2[('Log', 'Stop')])
yscale = zip(ys,ys)
TOOLS="pan,wheel_zoom,box_zoom,reset,hover"
output_file("scatter.html")
hover_tips = levelsdf2.index.values
colors = ["#%06x" % random.randint(0,0xFFFFFF) for c in range(len(xscale))]
source = ColumnDataSource(
data=dict(
x=xscale,
y=yscale,
gene=hover_tips,
colors=colors,
)
)
p1 = figure(plot_width=1750, plot_height=950,y_range=[0, 15],tools=TOOLS)
p1.multi_line(xscale[1:10],yscale[1:10], alpha=1, source=source,line_width=10, line_color=colors[1:10])
hover = p1.select(dict(type=HoverTool))
hover.tooltips = [
("index", "$index"),
("(x,y)", "($x, $y)"),
]
show(p1)
the levelsdf2 is a pandas.DataFrame, if it matters.
I figured it out on my own. It turns out that version 0.8.2 of Bokeh doesn't allow hovertool for lines so I did the same thing using quads.
from bokeh.plotting import figure, HBox, output_file, show, VBox, ColumnDataSource
from bokeh.models import Range1d, HoverTool
from collections import OrderedDict
import random
xscale = zip(levelsdf2[('series1', 'Start')], levelsdf2[('series1', 'Stop')])
xscale2 = zip(levelsdf2[('series2', 'Start')], levelsdf2[('series2', 'Stop')])
yscale2 = zip([9.2 for x in range(len(levelsdf2[(name, 'Start')]))],[9.2 for x in range(len(levelsdf2[(name, 'Start')]))])
TOOLS="pan,wheel_zoom,box_zoom,reset,hover"
output_file("linesandquads.html")
hover_tips = levelsdf2.index.values
colors = ["#%06x" % random.randint(0,0xFFFFFF) for c in range(len(xscale))]
proc1 = 'Log'
proc2 = 'MazF2h'
expression1 = levelsdf2[(proc1, 'Level')]
expression2 = levelsdf2[(proc2, 'Level')]
source = ColumnDataSource(
data=dict(
start=[min(xscale[x]) for x in range(len(xscale))],
stop=[max(xscale[x]) for x in range(len(xscale))],
start2=[min(xscale2[x]) for x in range(len(xscale2))],
stop2=[max(xscale2[x]) for x in range(len(xscale2))],
gene=hover_tips,
colors=colors,
expression1=expression1,
expression2=expression2,
)
)
p1 = figure(plot_width=900, plot_height=500,y_range=[8,10.5],tools=TOOLS)
p1.quad(left="start", right="stop", top=[9.211 for x in range(len(xscale))],
bottom = [9.209 for x in range(len(xscale))], source=source, color="colors")
p1.multi_line(xscale2,yscale2, source=source, color="colors", line_width=20)
hover = p1.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
(proc1+" (start,stop, expression)", "(#start| #stop| #expression1)"),
("Gene","#gene"),
])
show(p1)
Works like a charm.
EDIT: Added a picture of the result, as requested and edited code to match the screenshot posted.
It's not the best solution as it turns out it's not all that easy to plot several series of quads on one plot. It's probably possible but as it didn't matter much in my use case I didn't investigate too vigorously.
As all genes are represented on all series at the same place I just added tooltips for all series to the quads and plotted the other series as multi_line plots on the same figure.
This means that if you hovered on the top line at 9.21 you'd get tooltips for the line at 9.2 as well, but If you hovered on the 9.2 line you wouldn't get a tooltip at all.

Categories

Resources