Try converting the pandas DataFrame to html, and then use the {safe} tag in a special bokeh tooltip when you call it. I gave an example below to run on the last bokeh ( built from github , but it should be available later via pip).
import datetime import numpy as np import pandas as pd from bokeh.io import show, output_notebook from bokeh.plotting import ColumnDataSource, figure from bokeh.models import HoverTool, Range1d # Create dataframe of dates and random download numbers. startdate = datetime.datetime.now() nextdate = lambda x:startdate+datetime.timedelta(x) value = 10 dates = [nextdate(i) for i in range(value)] downloads = np.random.randint(0,1000,value) data = np.array([dates,downloads]).T data = pd.DataFrame(data,columns = ["Date","Downloads"]) data["Date"] = data.Date.apply(lambda x:"{:%Y %b %d}".format(x)) # Convert dataframe to html data_html = data.to_html(index=False) output_notebook() fig = figure(x_range=(0, 5), y_range=(0, 5),tools=[HoverTool(tooltips="""@html{safe}""")]) source=ColumnDataSource(data=dict(x=[1,3], y=[2,4], html=["<b>Some other html.</b>", data_html])) fig.circle('x', 'y', size=20, source=source) show(fig)
If you want a table that you can more easily style, here is an example using the dominate html generation package:
import datetime import numpy as np import pandas as pd from dominate.tags import * %env BOKEH_RESOURCES=inline from collections import OrderedDict from bokeh.plotting import figure from bokeh.models import ColumnDataSource, HoverTool, TapTool, OpenURL # For displaying in jupyter notebook from bokeh.io import push_notebook,show,output_notebook from bokeh.resources import INLINE output_notebook(resources=INLINE) # Create dataframe of dates and random download numbers. startdate = datetime.datetime.now() nextdate = lambda x:startdate+datetime.timedelta(x) value = 5 dates = [nextdate(i) for i in range(value)] downloads = np.random.randint(0,1000,value) data = np.array([dates,downloads]).T data = pd.DataFrame(data,columns = ["Date","Downloads"]) data["Date"] = data.Date.apply(lambda x:"{:%Y %b %d}".format(x)) # STYLES header_style = ["border:1px solid black", "font-size:10px", "font-weight:bold", "color:black", "padding:3px", ] header_style = ";".join(header_style)+";" td_style = ["border: 1px solid black", "font-size:10px", "padding:3px",] td_style = ";".join(td_style)+";" # Create HTML table my_table = table() my_table.add(tr([th(i,style=header_style) for i in data.columns])) [my_table.add(tr([td("{}".format(j),style=td_style) for j in i])) for i in data.values] # Create figure fig = figure(x_range=(0, 5), y_range=(0, 5),tools=[HoverTool(tooltips="""@html{safe}""")]) source=ColumnDataSource(data=dict(x=[1,3], y=[2,4], html=["<b>Some other html.</b>", my_table.render()])) fig.circle('x', 'y', size=20, source=source) show(fig)