I am currently doing where a need to update a ColumnDataSource in real-time using three sliders. I need to update the data for two reasons the first is to modify the glyph color according to the value of the slider and after that, I want to be able to display the points on a data table and download the data table.
So I use the function custumJS but it doesn't work. I think the problem is from the command source.on_change("value") but I am not sure because I have some trouble using the callback.
I use the bokeh example slider:
https://docs.bokeh.org/en/latest/docs/gallery/slider.html
here is my code:
from bokeh.plotting import figure, output_file, show,ColumnDataSource
from bokeh.models import HoverTool,Span,Slider, CustomJS,CategoricalColorMapper
from bokeh.layouts import row, widgetbox
from bokeh.models.widgets import *
import pandas as pd
import numpy as np
source = ColumnDataSource(
data=dict(
x = [0.154228,0.118865,0.071774,0.230292,0.070180,0.010010,0.141877,0.085712,0.166331,0.101799],
y = [1.358454,2.736966,1.556393,1.286304,1.785875,0.168123,2.120294,2.556393,5.058894,6.671531],
accession =[158489.0,442616758.0,349669.0,320544370.0,161077523.0,24648576.0,320545678.0, 17137000.0,442625663.0,17647529.0],
position = ["normal","normal","normal","normal","normal","normal","normal","normal","normal","normal"]
))
color_mapper = CategoricalColorMapper(factors=["up","normal","down"],palette=['yellow', 'green','blue'])
hover = HoverTool(tooltips=[
("accession", "@accession"),
("x","@x"),
("y","@y")
])
# setting the tools
TOOLS=",pan,wheel_zoom,box_zoom,reset,box_select,lasso_select"
# create a new plot with a title and axis labels
p = figure(
x_axis_label = 'log(fc)',
y_axis_label = '-log(pvalue)',
tools = TOOLS,)
p.add_tools(hover)
#setting the widgets slider
h_slider = Slider(start=0,end=5, value=1, step=.1, title="variation of log(pvalue)")
v_slider_right = Slider(start = 0.1, end = 0.2, value=0.15, step=.01,title="right fold change")
v_slider_left = Slider(start =0, end=0.1, value=0.05, step=.01,title="left log fold change")
# Horizontal line
hline = Span(location=h_slider.value, dimension='width', line_color='green', line_width=2)
# Vertical line
vline1 = Span(location =v_slider_right.value , dimension='height', line_color='blue', line_width=2)
vline2 = Span(location=v_slider_left.value, dimension='height', line_color='black', line_width=2)
p.renderers.extend([vline1,vline2, hline])
# add a circle points
p.circle('x','y',source = source,
color=dict(field='position', transform=color_mapper),
legend='position')
# callback of the sliders
h_slider.callback = CustomJS(args=dict(span=hline, slider=h_slider),code="""span.location = slider.value""")
v_slider_right.callback = CustomJS(args=dict(span=vline1, slider=v_slider_right),code="""span.location = slider.value""")
v_slider_left.callback = CustomJS(args=dict(span=vline2, slider=v_slider_left),code="""span.location = slider.value""")
callback = CustomJS(args=dict(source=source,v_slider_left=v_slider_left,h_slider=h_slider,v_slider_right=v_slider_right), code="""
var data = source.data;
var low = v_slider_left.value;
var up = v_slider_right.value
var back_value = h_slider.value;
x = data['x']
y = data['y']
pos = data['color']
for (i = 0; i < x.length; i++) {
if( (x < low) && (y > back_value)){
data["color"] = 'down'
} else if ((x > up) && (y > back_value)){
data["color"] = 'up'
}else{ data['color'] = 'normal'}
}
source.change.emit()
""")
columns = [TableColumn(field="accession", title="numero d'accession"),
TableColumn(field="x", title="log(fc)"),
TableColumn(field="y", title="-log(pvalue)")
]
data_table = DataTable(source=source, columns=columns, width=400, height=280)
#show the results
layout = row(p, widgetbox(v_slider_left,v_slider_right,h_slider,data_table ))
show(layout)