Search code examples
javascriptpythoncallbackbokeh

How to change the color of a glyph using callback?


I've tried around using Bokeh, and now I want to search a word and change the color of its glyph. My code looks like that:

import bokeh.plotting as bp
from bokeh.models import HoverTool, CustomJS
from bokeh.models.widgets import TextInput
from bokeh.io import vform

words = ["werner", "herbert", "klaus"]
x=[1,2,3]
y=[1,2,3]
color = ['green', 'blue', 'red']
word_input= TextInput(value="word", title="Point out a word")

source = bp.ColumnDataSource(data= dict(x=x,y=y,words=words, color='color'))
hover= HoverTool(tooltips=[("word", "@words")])

# output to static HTML file (with CDN resources)
bp.output_file("plot.html", mode="cdn")

# create a new plot with the tools above, and explicit ranges
p = bp.figure(plot_height = 600, plot_width = 800, title="word2vec", tools=[hover], logo =None)
# add a circle renderer with vectorized colors and sizes
p.circle('x','y', radius= 0.1, color = color, source=source, line_color=None)
callback= CustomJS(args=dict(source=source), code ="""
    var data = source.get('data');
    var glyph = cb_obj.get('value')
    words = data['words']
    colors=data['color']
    for (i=0; i< words.length;i++){
        if(glyph==words[i]){colors[i]='yellow'}        
    }
    source.trigger('change');
""")
layout = vform(word_input, p)
# show the results
bp.show(layout)

This code just doesn't work, and I can't figure out why not.

What am I doing wrong? I've posted an other question earlier that day and this is kind of a first step solving it.


Solution

  • there are a couple of problems you have:

    • you create the CallbackJS but never set is as the callback property of the TextInput

    • you set the color key of data dict to the string "color" not to the list of colors

    • you passed the actual list of colors as the color argument to figure (it should be the string name of the data source column you want to use, e.g. "color")


    Here is a version that works:

    from bokeh.io import vform
    from bokeh.models import HoverTool, CustomJS
    from bokeh.models.widgets import TextInput
    from bokeh.plotting import output_file, figure, show, ColumnDataSource
    
    output_file("plot.html")
    
    words = ["werner", "herbert", "klaus"]
    x, y = [1,2,3], [1,2,3]
    color = ['green', 'blue', 'red']
    
    source = ColumnDataSource(data=dict(x=x, y=y, words=words, color=color))
    
    hover = HoverTool(tooltips=[("word", "@words")])
    
    p = figure(plot_height=600, plot_width=800, title="word2vec", tools=[hover])
    p.circle('x','y', radius=0.1, fill_color='color', source=source, line_color=None)
    
    callback = CustomJS(args=dict(source=source), code="""
        var data = source.get('data')
        var value = cb_obj.get('value')
        var words = data['words']
        for (i=0; i < words.length; i++) {
            if ( words[i]==value ) { data.color[i]='yellow' }
        }
        source.trigger('change')
    """)
    
    word_input = TextInput(value="word", title="Point out a word", callback=callback)
    
    layout = vform(word_input, p)
    
    show(layout)