Thomas
Thomas

Reputation: 1205

Update text dynamically in Bokeh with js_on_change

Is it possible to use js_on_change with bokeh to dynamically update text that is placed next to a plot?

For example, using this code snippet from a different question


from random import random
from bokeh.models import CustomJS, ColumnDataSource, Span
from bokeh.plotting import figure, output_file, show

output_file("callback.html")

x = [random() for x in range(500)]
y = [random() for y in range(500)]
color = ["navy"] * len(x)

s = ColumnDataSource(data=dict(x=x, y=y, color=color))
p = figure(plot_width=400,
           plot_height=400,
           tools="lasso_select",
           title="Select Here")
p.circle(x='x', y='y', color='color', size=8, source=s, alpha=0.4)

slope = Span(location=.5,
             dimension="width",
             line_alpha=.6,
             line_width=5)
p.add_layout(slope)

s.selected.js_on_change(
    'indices',
    CustomJS(args=dict(s=s, slope=slope),
             code="""       
        var inds = cb_obj.indices;
        
        if (inds.length == 0) {
            slope.location = 0.5
            return 
        }
        
        var total = 0;
        for (var i = 0; i < inds.length; i++) {
            total += s.data["y"][inds[i]]
        }
        var avg = total / inds.length;
        slope.location = avg;
    """))

show(p)

I'd like to include a text right of the figure that shows the value of the computed slope.location and updates whenever I select new points.

Upvotes: 1

Views: 1595

Answers (1)

Crysers
Crysers

Reputation: 535

You can Use a Text Widget like PreText, place it on the right side of the plot e.g via layout and update the .text property of that widget in your JSCallback. Make sure you use the .toString() methode to assign the value.

from random import random
from bokeh.models import CustomJS, ColumnDataSource, Span, PreText
from bokeh.plotting import figure, output_file, show
from bokeh.layouts import layout

output_file("callback.html")

x = [random() for x in range(500)]
y = [random() for y in range(500)]
color = ["navy"] * len(x)

s = ColumnDataSource(data=dict(x=x, y=y, color=color))
p = figure(plot_width=400,
           plot_height=400,
           tools="lasso_select",
           title="Select Here")
p.circle(x='x', y='y', color='color', size=8, source=s, alpha=0.4)

slope = Span(location=.5,
             dimension="width",
             line_alpha=.6,
             line_width=5)
p.add_layout(slope)

slope_text = PreText(text='Slope_Text')

s.selected.js_on_change(
    'indices',
    CustomJS(args=dict(s=s, slope=slope, slope_text=slope_text),
             code="""       
        var inds = cb_obj.indices;
        
        if (inds.length == 0) {
            slope.location = 0.5
            return 
        }
        
        var total = 0;
        for (var i = 0; i < inds.length; i++) {
            total += s.data["y"][inds[i]]
        }
        var avg = total / inds.length;
        slope.location = avg;
        slope_text.text = avg.toString();
    """))

layout_ = layout([[p,slope_text]])
show(layout_)

Upvotes: 1

Related Questions