How to use multiple TapTools and disable the "grayed out on select" behavior?

Hello everyone,

I have two questions about the TapTool, that I couldn’t find an answer in the documentation.
i) My main question is, how to use multiple TapTools. I have two data sources and want to have different callbacks on each one.
I’ve tried the “add_Tools” function, but it didn’t work.

plot.add_tools(TapTool(renderers=[plot1], callback = OpenURL(url=url)))
plot.add_tools(TapTool(renderers=[plot2], callback = OpenURL(url=url)))

ii) My second question is, how to disable the “selective” behavior. When I click on a node, every other node gets grayed out.
Is there a way to disable this behavior?

Thank you
Sandra

@Sandra_Winkelberry If I understand your ask, then you want to set behavior="inspect" on the tap tools:

bokeh.models.tools — Bokeh 2.3.2 Documentation

There should not be any issue with adding multiple tap tools on a single plot. But it’s not clear what “it didn’t work” actually means (JS errors? Python errors? Unexpected behavior? If so, what?) What is really necessary to speculate is more information, as well as a Minimal Reproducible Example.

Hey Bryan, thanks for the response.
I have created a small replica of my problem:

from bokeh.io import show
from bokeh.models import ColumnDataSource, Circle, OpenURL, TapTool
from bokeh.plotting import figure

x1 = [1,1,1]
y1 = [1,2,3]
x2 = [3,3,3]
y2 = [1,2,3]
url1 = ["http://www.colors.commutercreative.com/navy/", "http://www.colors.commutercreative.com/orange/",
        "http://www.colors.commutercreative.com/olive/"]
url2 = ["http://www.colors.commutercreative.com/firebrick/", "http://www.colors.commutercreative.com/gold/",
        "http://www.colors.commutercreative.com/green/"]

source1 = ColumnDataSource(data=dict(x=x1, y=y1, url = url1))
source2 = ColumnDataSource(data=dict(x=x2, y=y2, url = url2))

plot = figure(plot_width=400, plot_height=400, tools="tap", title='TapTool example')

plot1 = plot.circle('x', 'y', size=20, fill_color="lightcoral", source=source1)
plot2 = plot.circle('x', 'y', size=20, fill_color='lightblue', source=source2)

url = "@url"
plot.add_tools(TapTool(renderers=[plot1], behavior = "inspect", callback = OpenURL(url=url)))
plot.add_tools(TapTool(renderers=[plot2], behavior = "inspect", callback = OpenURL(url=url)))

show(plot)

I can click on the circles, but they are still get grayed out when I click on them and they don’t send me to the website.

As it happens, TapTool with inspection and OpenURL are not yet compatible. There is an open WIP Pull Request right now to make things work together in that case:

Added flag to TapTool such that OpenURL uses source.inspected.indices by dmellogu · Pull Request #11171 · bokeh/bokeh · GitHub

This will hopefully land in one of the upcoming releases in the near future. In the immediate term, I can only suggest using standard selection (as in the OP) and if you don’t want the appearance change of “selection” than changing the default selection appearance to simply not look any different:

1 Like

Okay, thanks. Glad I could help on improving TapTool :slight_smile:

Now that I know, that this is simply not compatible yet, I will stick to the default behavior.
But I still have one question left. I’m unable to use both TapTools at the same time.
I can only select one TapTool at the time.
How can I activate both TapTools at the same time as default.
I’ve tried to follow the documentation here:
But I don’t know how to use it in my case.
I’ve tried something like this:

plot.toolbar.active_tap = plot.add_tools(TapTool(renderers=[plot1], callback = OpenURL(url=url)))
plot.toolbar.active_tap = plot.add_tools(TapTool(renderers=[plot2], callback = OpenURL(url=url)))

I’m still using the code example above.

This was the missing clarification of “didn’t work” that I was looking for. Currently, only one tool of each gesture type (tap, pan, scroll, etc) can be active at one time, so this is expected. You will have to rework things to use a single tap tool. If you code above is an actual representation of your real code, you could potentially use a single source for and one call to circle, with a color column so color mapper to shade different circles differently, Alternatively, a CustomJS that calls window.open on URLs could be made work with multiple glyphs.

1 Like

I managed to code a working solution for my problem with js and window.open and thought I’d share it here:

from bokeh.io import show
from bokeh.models import ColumnDataSource, Circle, OpenURL, TapTool
from bokeh.plotting import figure
from bokeh.models.callbacks import CustomJS

x1 = [1,1,1]
y1 = [1,2,3]
x2 = [3,3,3]
y2 = [1,2,3]
url1 = ["http://www.colors.commutercreative.com/navy/", "http://www.colors.commutercreative.com/orange/",
        "http://www.colors.commutercreative.com/olive/"]
url2 = ["http://www.colors.commutercreative.com/firebrick/", "http://www.colors.commutercreative.com/gold/",
        "http://www.colors.commutercreative.com/green/"]

source1 = ColumnDataSource(data=dict(x=x1, y=y1, url = url1))
source2 = ColumnDataSource(data=dict(x=x2, y=y2, url = url2))

plot = figure(plot_width=400, plot_height=400, title='TapTool example')

plot1 = plot.circle('x', 'y', size=20, fill_color="lightcoral", source=source1)
plot2 = plot.circle('x', 'y', size=20, fill_color='lightblue', source=source2)


tapcb = CustomJS(args=dict(source1=plot1.data_source, source2=plot2.data_source),
    code="""
        if(source1.selected.indices != ""){
            window.open(source1.data["url"][source1.selected.indices])
        }
        if(source2.selected.indices != ""){
            window.open(source2.data["url"][source2.selected.indices])
        }
    """)
taptool = TapTool(callback=tapcb)
plot.tools.append(taptool)
show(plot)

I still can’t change the behavior to “inspect” even without using openUrl. I guess its also not compatible with js or window.open()…

1 Like