Tap event on patch

Hi,

I want to trigger tab event when I click “only” patch elements.
How can I do that?

regards

Hi @ahmettemiz88 ,

Can you clarify what you mean by “tab event”? And “only” patch elements? Can you provide an example? For triggering events by clicking patch elements generally, we can refer back to your earlier question here, but I think this question needs some elaboration and example.

I meant Tap event.
I am trying to get ‘yes’ when I click on a patch otherwise ‘no’

glyph = Patches(xs="xs", ys="ys", fill_color="#fb9a99",line_color="red", fill_alpha=0.6   )
plot.add_glyph(buf_source, glyph)
..
def map_click(event):
    print ( "***   event >>   ", event.x, event.y)
    # if it is clicked on a patch 
        return 'yes'
    else :
        return 'no'
   
plot.on_event(Tap, map_click)

regards

You’ll probably want a callback linked to the selected attribute of your data source. If something’s selected, then that’s a yes; if not, then no. Here’s a rough example, going back to that same Texas patch plot:

from bokeh.io import show
from bokeh.models import LogColorMapper, ColumnDataSource, TapTool, Div, CustomJS
from bokeh.palettes import Viridis6 as palette
from bokeh.plotting import figure
from bokeh.sampledata.unemployment import data as unemployment
from bokeh.sampledata.us_counties import data as counties
from bokeh.layouts import Column

palette = tuple(reversed(palette))

counties = {
    code: county for code, county in counties.items() if county["state"] == "tx"
}

county_xs = [county["lons"] for county in counties.values()]
county_ys = [county["lats"] for county in counties.values()]

county_names = [county['name'] for county in counties.values()]
county_rates = [unemployment[county_id] for county_id in counties]
color_mapper = LogColorMapper(palette=palette)

data = dict(
    x=county_xs,
    y=county_ys,
    name=county_names,
    rate=county_rates,
)

cds = ColumnDataSource(data)

TOOLS = "pan,wheel_zoom,reset,hover,save"

p = figure(
    title="Texas Unemployment, 2009", tools=TOOLS,
    x_axis_location=None, y_axis_location=None,
    tooltips=[
        ("Name", "@name"), ("Unemployment rate", "@rate%"), ("(Long, Lat)", "($x, $y)")
    ])
p.grid.grid_line_color = None
p.hover.point_policy = "follow_mouse"

patch_renderer = p.patches('x', 'y', source=cds,
                           fill_color={'field': 'rate', 'transform': color_mapper},
                           fill_alpha=0.7, line_color="white", line_width=0.5)

tap_tool = TapTool(renderers=[patch_renderer])
p.add_tools(tap_tool)

indicator_div = Div(text="no")

patch_indicator_callback = CustomJS(args=dict(cds=cds, div=indicator_div), code="""
  console.log(cb_obj.indices)
  console.log(cds.selected.indices)  
  // note that these are the same. cds.selected is the object that this callback is set for,
  // so you could use either one of these to refer to the data in your data source (below). 
  
  // if the indices array is empty, user clicked somewhere not on a patch
  if (cb_obj.indices.length == 0)
    div.text = "no"
  else
    div.text = "yes: "+cds.data.name[cb_obj.indices]
    
  """)

cds.selected.js_on_change('indices', patch_indicator_callback)

col = Column(children=[p, indicator_div])
show(col)

Also noting (since it is not clear in the question): if you want the tap tool to only do hit-testing on the patches glyph, and ignore other ones, then you can set the renderers property on the tap tool.

1 Like

Thank you,

How can I get the x,y coordinates of the clicked point in patch_indicator_callback ?

The value returned in the callback object’s indices will correspond to the data in your ColumnDataSource. I’ve updated the code above to add the county’s name on a “yes” condition as an example.

EDIT: I realized later this doesn’t actual your actual question; I’m making the assumption that you want the data that determines the x,y position of the glyph, rather than the actual x and y values on the html canvas. Let me know if that’s not correct.

Thank you
yes ,
I need to know clicked coordinates of anywhere in the patch.
I solved like this . But I am not sure if it is a proper solution. However it works in "bokeh serve .
After the customjs you supplied:

def map_click(event):
    print ( "***   ",indicator_div.text)
    if 'yes' in indicator_div.text :
       print ( "***   event >>   ", event.x, event.y)
    else :
       return


p.on_event(Tap, map_click)

kind regards

1 Like