Jade
Jade

Reputation: 71

Unable to populate Bokeh HoverTool Values from Passed in Pandaframe

I am using Bokeh on Jupyter Notebooks to help with data visualization. I wanted to be able to plot the data from a panda DataFrame, and then when I hover over the Bokeh plot, all the feature values should be visible in the hover Box. However, with the code below, only the index correctly displays, and all the other fields appear as ???, and I'm not sure why.

Here is my working example

//Importing all the neccessary things
import numpy as np
import pandas as pd
from bokeh.layouts import row, widgetbox, column
from bokeh.models import CustomJS, Slider, Select, HoverTool 
from bokeh.plotting import figure, output_file, show, ColumnDataSource
from bokeh.io import push_notebook, output_notebook, curdoc
from bokeh.client import push_session
#from bokeh.scatter_with_hover import scatter_with_hover
output_notebook()


np.random.seed(0)
samples = np.random.randint(low = 0, high = 1000, size =  1000)
samples = samples.reshape(200,5)
cols = ["A", "B", "C", "D", "E"]
df = pd.DataFrame(samples, columns=cols)

# Here is a dict of some keys that I want to be able to pick from for plotting
labels = list(df.columns.values)
axis_map = {key:key for key in labels}


code2 = ''' var data = source.data;

           //axis values with select widgets
           var value1 = val1.value;
           var value2 = val2.value;

           var original_data = original_source.data
           // get data corresponding to selection

           x = original_data[value1];
           y = original_data[value2];
           data['x'] = x;
           data['y'] = y;

           source.trigger('change');

           // set axis labels
           x_axis.axis_label = value1;
           y_axis.axis_label = value2;

           '''
datas = "datas"
source = ColumnDataSource(data=dict( x=df['A'], y=df['B'], 
                                    label = labels, datas = df))


original_source = ColumnDataSource(data=df.to_dict(orient='list'))

a=  source.data[datas].columns.values
#print a.columns.values
print a

TOOLS = [ HoverTool(tooltips= [(c, '@' + c) for c in  source.data[datas].columns.values] +
                               [('index', '$index')] )]
# hover.tooltips.append(('index', '$index'))
#plot the figures
plot = figure(plot_width=800, plot_height=800,   tools= TOOLS)
plot.scatter(x= "x",y="y", source=source, line_width=2, line_alpha=0.6, 
             size = 3)

callback = CustomJS(args=dict(source=source, original_source = original_source,
                              x_axis=plot.xaxis[0],y_axis=plot.yaxis[0]), code=code2)

#Create two select widgets to pick the features of interest 
x_axis = Select(title="X Axis", options=sorted(axis_map.keys()), value="A", callback = callback)
callback.args["val1"] = x_axis
callbackDRange.args["val1"]= x_axis

y_axis = Select(title="Y Axis", options=sorted(axis_map.keys()), value="B", callback = callback)
callback.args["val2"] = y_axis
callbackDRange.args["val2"]= y_axis



plot.xaxis[0].axis_label = 'A'
plot.yaxis[0].axis_label = 'B'



#Display the graph in a jupyter notebook
layout = column(plot, x_axis, y_axis )
show(layout, notebook_handle=True)

I'm even passing in the full dataframe into the source ColumnDataSource so I can access it later, but it won't work. Any guidance would be greatly appreciated!

Upvotes: 0

Views: 468

Answers (1)

bigreddot
bigreddot

Reputation: 34618

Running your code in recent version of Bokeh results in the warning:

enter image description here

Which suggests the root of the problem. If we actually look at the data source you create for the glyph:

source = ColumnDataSource(data=dict(x=df['A'], 
                                    y=df['B'], 
                                    label=labels, 
                                    datas = df))

It's apparent what two things are going wrong:

  • You are violating the fundamental assumption that all CDS columns must always be the same length at all times. The CDS is like a "Cheap DataFrame", i.e. it doesn't have ragged columns. All the columns must have the same length just like a DataFrame.

  • You are configuring a HoverTool to report values from columns named "A", "B", etc. but your data source has no such columns at all! The CDS you create above for your glyph has columns named:

    • "x", "y"
    • "labels" which is the wrong length
    • "datas" which has a bad value, columns should normally be 1-d arrays

The last column "datas" is irrelevant, BTW. I think you must think the hover tool will somehow look in that column for information to display but that is not how hover tool works. Bottom line:

If you configured a tooltip for a field @A then your CDS must have a column named "A"

And that's exactly what's not the case here.

It's hard to say exactly how you should change your code without more context about what exactly you want to do. I guess I'd suggest taking a closer look at the documention for hover tools in the User's Guide

Upvotes: 0

Related Questions