Single tap to show 'name' of 'image' with ColumnDataSource using CustomJS

I’m trying to show the ‘name’ of image upon single tap with ColumnDataSource using CustomJS.
I’m accessing the ‘name’ using source.data['name']. It should be quite straight forward, but I just can’t get it to work. Could any one please help look what is wrong with my script? Thanks!

from bokeh.plotting import figure, show
from bokeh.models import TextInput, CustomJS
from bokeh.models import ColumnDataSource
from bokeh.events import Tap
from bokeh.layouts import column
import numpy as np

ramp = np.array([np.linspace(0, 10, 200)]*20)
steps = np.array([np.linspace(0, 10, 10)]*20)
bitmask = np.random.rand(25, 10) > 0.5

source = ColumnDataSource(dict(image=[ramp, steps, bitmask],
            name=['ramp', 'steps', 'bitmask'],
            x=[0, 0, 25],
            y=[5, 20, 5],
            dw=[20,  20, 10],
            dh=[10,  10, 25]))


p = figure( x_range=(0, 35), y_range=(0, 35), tools='wheel_zoom')
p.image(source=source, image='image', x='x', y='y', dw='dw', dh='dh', name='name', palette="Inferno256")
text_name = TextInput(title='name', value='', disabled=True)
text_name_cb = CustomJS(args=dict(text_name=text_name, source=source), code="""
                        text_name.value = source.data['name'];
                        """)
p.js_on_event(Tap, text_name_cb)

show(column(p, text_name))

@thisuser

Your callback is being invoked. The problem is an error is being thrown b/c you are trying to set the value of the TextInput with an incompatible type.

The name key of your dictionary is a list of strings. You can see this in the JavaScript console of the browser. What do you want to go there, specifically?

@thisuser

If you want the textbox to be populated with the name of the image as the topic suggests, I think you’re simply constructing the callback logic erroneously. It should reference the name property of the image rather than the name key of the data source dictionary as done in the original code. Try the following.

from bokeh.plotting import figure, show
from bokeh.models import TextInput, CustomJS
from bokeh.models import ColumnDataSource
from bokeh.events import Tap
from bokeh.layouts import column
import numpy as np

ramp = np.array([np.linspace(0, 10, 200)]*20)
steps = np.array([np.linspace(0, 10, 10)]*20)
bitmask = np.random.rand(25, 10) > 0.5

source = ColumnDataSource(dict(image=[ramp, steps, bitmask],
            name=['ramp', 'steps', 'bitmask'],
            x=[0, 0, 25],
            y=[5, 20, 5],
            dw=[20,  20, 10],
            dh=[10,  10, 25]))


p = figure( x_range=(0, 35), y_range=(0, 35), tools='wheel_zoom')
r = p.image(source=source, image='image', x='x', y='y', dw='dw', dh='dh', name='name', palette="Inferno256")
text_name = TextInput(title='name', value='', disabled=True)
text_name_cb = CustomJS(args=dict(text_name=text_name, source=source, r=r), code="""
                        text_name.value = r.name;
                        """)
p.js_on_event(Tap, text_name_cb)

show(column(p, text_name))

Thanks for your help. However, I tried your modified code and found that the text box only shows the string ‘name’ instead of the actual name of each image, upon single tap on the image.

Like this

Yes. That follows what I implemented. I simply applied the name property of the p.image Glyph renderer to the text box. If you want it to do something else, you’ll have to add logic that gets at the specific area of the figure you’re tapping. I don’t immediately recall, but I’m not certain that individual images support hit-tests or selection directly.