1

Considering the example below from the Bokeh Docs, is there a way to adjust the TapTool so that when I click on a circle I'm taken to the url on the same tab rather than opening a new tab? The docstring suggests that the only behavior is to open a new tab, but perhaps there's a CustomJS workaround or some other hack to get around this?

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

output_file("openurl.html")

p = figure(plot_width=400, plot_height=400,
       tools="tap", title="Click the Dots")

source = ColumnDataSource(data=dict(
    x=[1, 2, 3, 4, 5],
    y=[2, 5, 8, 2, 7],
    color=["navy", "orange", "olive", "firebrick", "gold"]
    ))

p.circle('x', 'y', color='color', size=20, source=source)

url = "http://www.colors.commutercreative.com/@color/"
taptool = p.select(type=TapTool)
taptool.callback = OpenURL(url=url)

show(p)

I wrapping some javascript without success (borrowing from this question but kind of clueless on how exactly to implement it). This results in no link opening:

callback = CustomJS(args=dict(source=source), code="""          
        url = data['url']
        window.open(url,"_self");
    """)    

taptool = p.select(type=TapTool)
taptool.callback = callback

I also tried treating the link like an <a> tag using the tag keyword for OpenURL. This is a blind attempt since I could not find anything on how to use this tag term properly. No luck here.

url = "http://www.colors.commutercreative.com/@color/"
taptool = p.select(type=TapTool)
taptool.callback = OpenURL(url=url, tags=["_self"])

I understand Bokeh is still pretty new so perhaps this functionality isn't available yet. I still think there's got be a workaround if you know enough javascript (which I apparently don't).

Community
  • 1
  • 1
benten
  • 1,995
  • 2
  • 23
  • 38

1 Answers1

4

tags are a dusty feature, and they have nothing to do with this. They simply allow you to attach some arbitrary bit of information to a Bokeh Model, which can help if you are querying the object graph later looking for that particular model .


As of Bokeh 0.12.3, the OpenURL does not support this, it simply calls window.open:

https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/models/callbacks/open_url.coffee#L18

Adding a new property for the name parameter of window.open would be only a couple of lines of code. I'd suggest opening a feature request issue on the issue tracker. If you are interested in working up a PR to implement this feature we are always happy to help new contributors get started.


This could also be done with a CustomJS callback. If you just always want to open a fixed URL whenever a circle is clicked, it's something like

callback = CustomJS(args=dict(source=source), code="""          
    window.open("http://foo.com" ,"_self");
    """)    

If there is a column in your data source that has complete URLs and you want to pick one based on the selected index, you need to do something more like what the OpenURL callback does: get the selected indices off the data source, then get a URL out of a column in the data source using the selected indices, then call window.open. Here is a complete example:

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

source = ColumnDataSource(data=dict(
    x = [1, 2],
    y = [3, 4],
    url = ["http://google.com", "http://bing.com"],
))

p = figure(tools="tap")
p.circle('x', 'y', size=15, source=source)

code = """
selection = require("core/util/selection")
indices = selection.get_indices(source)
for (i = 0; i < indices.length; i++) {
    ind = indices[i]
    url = source.data['url'][ind]
    window.open(url, "_self")
}
"""

taptool = p.select(type=TapTool)
taptool.callback = CustomJS(args=dict(source=source), code=code)

output_file("/tmp/foo.html")

show(p)
bigreddot
  • 33,642
  • 5
  • 69
  • 122
  • Thank you so much. And I would like to start contributing, so thanks for the link. For some reason your full example doesn't send me anywhere when I click on the dots. Also, I need the "_self" argument in the `window.open()` command yeah? – benten Oct 29 '16 at 16:32
  • Oh, yes, sorry I removed it because I was looking at some JS console output and that made it difficult, I will put it back in the answer. – bigreddot Oct 29 '16 at 18:32
  • Thanks again. I hope to not bug you much after this. Is there a reason you have `window.open()` inside the loop instead of outside? An unrelated question is whether I have "core/util/selection" available to me as long as I have the latest version of Bokeh? The fixed url snippet works fine. If I add just the `selection = require()` line from the full example, things don't work. Kind of hard to diagnose since no error is thrown. – benten Oct 29 '16 at 19:37
  • Yes, multiple glyphs overlap there can be more than one section index. This will open a window for all of them. If you wanted something different, say just picking the first one arbitrarily or whatever, you could do that. I'm not clear from your other description, what setup is working and what isn't and what the difference is. – bigreddot Oct 29 '16 at 20:19
  • Ah, it works now. I just had to update to the latest version of Bokeh for `(core/util/selection)` to work. Thanks again. – benten Nov 02 '16 at 04:59
  • Yes, we are still working to stabilize a public JS API. BokehJS used to be entirely an implementation detail. Things should be settled down completely over the next couple of months. – bigreddot Nov 02 '16 at 14:06
  • (newbie JS coder question) What is the JS code here? It doesn't have the typical "var" in front of variables like in the Javascript Callbacks doc page, and it doesn't have the CustomJS.from_coffeescript – Michael Feb 16 '17 at 16:24
  • In the past Bokeh used to default to interpreting `CustomJS` code as CoffeeScript, but no longer does. – bigreddot Feb 19 '17 at 21:59
  • @bigreddot I have been trying to use a tap event to trigger a jscallback in another figure, but I am stuck for over two weeks. Any change of an minimal example? I have done two posts with a question related, not much luck thus far. – ReinholdN Oct 05 '21 at 04:29