Basically, I’m trying to define a method that can plot each column of the pandas.dataframe in one html page with row index as X, column as Y; meanwhile, I’d like to make these 2 functions work:
(1) When select dots on one of the plot, those points with same row index will show as selected on other plots;
(2) In the customJS of the source.selected.js_on_change, I would like to store the row indexes of selection in an JS array; currently I use document.write() to test whether the row index has been stored successfully. For this part, I’ve use the official Bokeh example JavaScript callbacks — Bokeh 2.4.3 Documentation as reference.
My problem is: the customJS is not working when multiple plot is displayed. I tested and the row index of selection is not pushed in to JS array.
I’ve attached my code below as reference. Kindly let me know what I did wrong, and how to make the customJS for selection works on multiple plots that shares the same datasource! Appreciate your help in advance!
from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource, HoverTool, TapTool, CustomJS
from collections import Counter
from bokeh.layouts import gridplot
from bokeh.layouts import column, row
import pandas as pd
import numpy as np
from sklearn import preprocessing
def draw_distributiondot_new(dataf):
for column in range(len(dataf.columns.tolist())):
y = dataf.iloc[:,column].values.tolist()
if type(y[0]) == str:
encoder= preprocessing.LabelEncoder().fit(dataf.iloc[:,column])
dataf.iloc[:,column] = encoder.transform(dataf.iloc[:,column])
title=dataf.columns.tolist()
source=ColumnDataSource(dataf)
z = [[None]*len(title) for _ in range(len(title))]
for column in title:
y = source.data[column]
title_sub=column
x = source.data['index'].tolist()
TOOLTIPS_html = """
<div>
<span style="font-size: 10px; font-weight: bold;">Info</span><br>
<span style="font-size: 8px; color: #0059b3;">Index: [$index]</span><br>
<span style="font-size: 8px; color: #0059b3;">Value:@y</span><br>
</div>
</div>
"""
hover = HoverTool(tooltips=TOOLTIPS_html)
p = figure(plot_width=400, plot_height=400, title=title_sub, tools="tap,lasso_select,reset,save")
p.add_tools(hover)
p.xaxis.axis_label = "row_number"
p.yaxis.axis_label = "value" + title_sub
p.circle(x,y, size=5, line_color="navy", fill_color="red", fill_alpha=0.5)
z[title.index(column)][0]=p
source.selected.js_on_change('indices', CustomJS(args=dict(s1=source), code="""
const inds = cb_obj.indices;
const d1 = s1.data;
const indexes = [];
for (let i = 0; i < inds.length; i++) {
indexes.push(d1['x'][inds[i]])
}
setTimeout(() => document.write(indexes.join(',')), 1000);
//(the line above is for testing purpose only)
//setTimeout(() => console.log(indexes.join(',')), 1000);
""")
)
layout = gridplot(z)
show(layout)
return layout
data = [[623,10],[611,32],[600,33],[623,20],[611,12],[600,12],[423,23],[611,34],[600,54],[423,34],[611,24],[600,62]]
dummy = pd.DataFrame(data,columns=['Score','Age'],dtype=float)
draw_distributiondot_new(dummy)