Repository: bokeh/bokeh

Issue:
Hover in plots stops working in angularjs upon navigation
Testcase is here:

https://gist.github.com/manderso-brcm/ca1235c2bc5ed9051cf7



Discussion:
I will try to investigate further in the coming days, which version of Bokeh are you using?

The testcase webapp is using bokeh 0.5.1.  The embeded snippet / uuid.embed.js file was generated with either bokeh 0.5.0 or 0.5.1.

Also, using other js library versions -- angular 1.2.21, jquery 1.11.1.

I am trying to test this on 0.5.2, but I need the plot code or the foo.embed.js file rebuilt on top of 0.5.2...
can you update the gist with some of these things? Thanks.

I posted this to the mailing list as well, but the gist is updated; rebuilt with v0.5.2. Thanks.

OK, I will take a look today... thanks.

OK, I played with the example and I can reproduce exactly what is described in the example itself.
I don't have experience with angular so I don't know if there is some incompatibility or something else, @bryevdv any hint on this?

Any insights on this quirky hover bug? I spent some time trying to understand the angular route switching code, but I didn't follow it well enough to suggest a possible cause of this behavior.

We have a milestone deadline at the end of the week. I was hoping to understand the issue by then, and what it might take (broad strokes) to fix.

Thanks,
Matt

I don't have any experience with angular so I don't have anything to add on that side of things really. I've only taken a quick look and all I noticed was that the resize tool continues to work, so it's not that case that mouse events are not making it through. Perhaps the auto-enable logic has some problem and get stuck "off".  @manderso-brcm are you able to build bokehjs? I could point you at some places in the source to add some debugging statements to try and get more information. That would probably be faster than trying to co-iterate.

@bryevdv I am Python programmer first, and my javascript skills are self-taught, recent, and a little rough (I wanted to branch out doing some "front-end" UI work). With a little time I could probably come up to speed with building bokehjs, but I'm in an enterprise environment, and the tool dependencies to build are not currently installed. I can't use the simple recipes to install (not being root for one reason) -- I think I'd have to request that IT install any dependencies. 

Can the toolchain be easily installed in a virtualenv-type environment?  I have very little experience with "conda", but I looked at it once and if memory serves, it can do virtualenv-type things?  I don't currently have a virtualbox up and running on my laptop either, where I could more easily do this.

What would co-iteration look like?  The testcase is as simple as I could make it.  Would you imagine editing angular as part of a debug, or only bokeh?

Can you describe, or point me at docs regarding, the "auto-enable logic"?  Can it be re-triggered? Or not auto-enabled, but just enabled manually?  If I had a rough idea what was happening, I might be able to get angular to do what is required to get the plot back in the correct state.

@manderso-brcm Yes conda can create isolated environments (that all live in simple directories in your home directory, and do not affect touch the system tools). I would suggest first installing Anaconda, then using conda to get the rest of the build tools. Here are the most up to date dev install docs:

https://github.com/ContinuumIO/bokeh/blob/master/sphinx/source/docs/dev_guide.rst#installation-for-developers

Then the two main files of interest are:

https://github.com/ContinuumIO/bokeh/blob/master/bokehjs/src/coffee/tool/event_generators.coffee
https://github.com/ContinuumIO/bokeh/blob/master/bokehjs/src/coffee/tool/hover_tool.coffee

You could start first with some printf logging in `_select` to see if it is getting triggered at all after the return to the page. If not, the problem is likely in the event generator. 

@bryevdv Thanks for the help so far.  I didn't have time to get the toolchain installed last week, but I have done so today.  

I have the bokeh git repo cloned from github, checked out to the 0.5.2 tag (development since that release breaks the hover in my built testcase example data).  I can build bokehjs from the source using the procedure described in the documentation.

I added a `console.log()` to the `_select` method in the `hover_tool.coffee` file, and it fires when I first navigate to the plot page, and continues to fire when I navigate away and back (although the hover ceases to work on the return navigation).  So, that not getting called does not seem to be the problem.

Can you give me additional guidance on things to check for debugging purposes?  I'm totally new to coffeescript.

@manderso-brcm That is good know. Next I would try `console.log selected` at this line:

https://github.com/ContinuumIO/bokeh/blob/master/bokehjs/src/coffee/tool/hover_tool.coffee#L114

If it is null or an empty list, then the problem is somehow in the hit-testing immediately above. Adding `console.log renderer` around that same line might also be useful, because I am wondering about the `break` way down at line 

https://github.com/ContinuumIO/bokeh/blob/master/bokehjs/src/coffee/tool/hover_tool.coffee#L193

Maybe it's not querying the right renderer every time... this hover tool was written in haste an needs alot of cleanup. 

@bryevdv When I add a log on that line (114), I get output when I first load the page, but no output when I return to the page; the log I did was:

```
console.log({"_select": true, renderer: renderer, selected: selected})
```

with a (chrome) output of:

```
Object {_select: true, renderer: Rect, selected: Array[0]}
```

I followed that with a different logging, seeing what the value for `@mget('renderers')` was outside of the for loop:

```
console.log("_select": true, renderers: @mget('renderers'))
```

 On page load it is:

```
Object {_select: true, renderers: Array[1]}
```

and after navigation and away and back it is:

```
Object {_select: true, renderers: Array[0]}
```

So, apparently the "renderers" have gone missing after the navigation event.  What does that suggest to you?

OK that's weird, I am not sure at all what might cause that, but here is a potential workaround:
- in `initialize`, add `@renderers = @mget('renderers')` here: https://github.com/ContinuumIO/bokeh/blob/master/bokehjs/src/coffee/tool/hover_tool.coffee#L36
- in the `_select` function replace `@mget('renderers')` with `@renderers`

This is attempting to only pull the renderers off the model once, at view initialization, so hopefully they will always stay the same. 

@bryevdv No; the behavior is the same. The `@renderers` Array gets cleared.  I think it is a different object in memory from the result of `@mget('renderers')`, however (a `===` test returns true if they are the same object, correct?; compiled js, not coffeescript, below):

```
    console.log({
      "_selected": true,
      "@renderers": this.renderers,
      "@mget('renderers')": this.mget('renderers'),
      "@mget('renderers') == @renderers": this.mget('renderers') === this.renderers
    });
```

Returns (before and after navigation respectively):

```
Object {_selected: true, @renderers: Array[1], @mget('renderers'): Array[1], @mget('renderers') == @renderers: false}
Object {_selected: true, @renderers: Array[0], @mget('renderers'): Array[0], @mget('renderers') == @renderers: false}
```

Is there any way we could perhaps set up a webex meeting or the like to do this iteration interactively?  Or, can you take my test example and do some debug diagnostic iterations on your end?

Thanks,
Matt

@manderso-brcm If you can get me a tarball or repo with a completely standalone example, then I can take a look tomorrow after our 0.6 code freeze. Or we can have a webex/ghangout meeting tomorrow too. 

@bryevdv The gist linked to at the top of this comment thread should be a minimal, completely stand-alone example:
- one HTML page with embedded angularjs app (113 lines total, including HTML, CSS, and javascript; references CDN hosted CSS and javascript)
- one bokeh-generated `<snippet_data>.js` file

The data in the plot / snippet is built against bokeh 0.5.2, so you'd need to check out that tag to get it to work as-is (the hover did not work with master HEAD as of yesterday). My coworker generated the snippet data; I could get new build and update the gist if that was needed.  The testing I did today was against the bokeh repo checked out to the 0.5.2 tag.

@bryevdv Did you get a chance to look at the example, and/or look at possible causes of this odd behavior?  Would you like to set up a screenshare / call at some point to discuss, or prefer to look at this issue on your own schedule?  I think I could find time to do a screenshare today or tomorrow, if you wished to do so, and depending on timing particulars.

Thanks,
Matt

@manderso-brcm sorry for the delay. We are having a 0.6 release later today, it's been a little hectic. Lets' first see if the new release solves the issue (fingers crossed) and if not I will have copious time starting tomorrow, we can have a screenshare/hangout to resolve this once and for all!

@bryevdv Been busy working towards another milestone / demo, which was given today. So, now I have time to look again at the bokeh integration bug(s) we're experiencing.

I've regenerated the plot snippet/js with the v0.6 code, and the navigation / hover bug is still present.

Would you have time sometime between now (1:30 Central) and 3:00 (Central) to do a webex meeting and look at the issue together?  I have another meeting at 3:30, so the earlier the better for me.

Please email me at manderso at broadcom dot com so I have an email to send the meeting invite to.

If the time window for today does not work, can you email me with a candidate time or two that does?

Thanks,
Matt

Will try to have a PR, for reference a bare-bones solution is this:

```
diff --git a/bokehjs/src/coffee/main.coffee b/bokehjs/src/coffee/main.coffee
index a94d38c..1772d54 100644
--- a/bokehjs/src/coffee/main.coffee
+++ b/bokehjs/src/coffee/main.coffee
@@ -4,6 +4,8 @@ define (require, exports, module) ->
   Bokeh.require = require
   Bokeh.version = '0.6.1'

+  Bokeh.index = {}
+
   # set up logger
   logging = require("common/logging")
   Bokeh.logger = logging.logger
diff --git a/bokehjs/src/coffee/server/embed.coffee b/bokehjs/src/coffee/server/embed.coffee
index 4a07f2f..667fdaa 100644
--- a/bokehjs/src/coffee/server/embed.coffee
+++ b/bokehjs/src/coffee/server/embed.coffee
@@ -26,15 +26,21 @@ define [
   add_plot_static = (element, model_id, model_type, all_models) ->
     load_models(all_models);
     model = base.Collections(model_type).get(model_id)
-    view = new model.default_view({model : model})
-    _.delay(-> $(element).replaceWith(view.$el))
+    if model_id not in Bokeh.index
+      view = new model.default_view({model : model})
+      Bokeh.index[model_id] = view
+      _.delay(-> $(element).replaceWith(view.$el))
+    else
+      Bokeh.index[model_id].render()

   add_plot_server = (element, doc_id, model_id) ->
     resp = serverutils.utility.load_one_object_chain(doc_id, model_id)
     resp.done((data) ->
       model = base.Collections(data.type).get(model_id)
-      view = new model.default_view(model : model)
-      _.delay(-> $(element).replaceWith(view.$el))
+      if model_id not in Bokeh.index
+        view = new model.default_view(model : model)
+        _.delay(-> $(element).replaceWith(view.$el))
+        Bokeh.index[model_id] = view
       wswrapper = serverutils.wswrapper
       wswrapper.subscribe("debug:debug", "")
       wswrapper.on('msg:debug:debug', (msg) ->
```

Need to investigate how to populate `Bokeh.index` in other non-autoload situations. 


Resolving patch:
diff --git a/bokeh/objects.py b/bokeh/objects.py
--- a/bokeh/objects.py
+++ b/bokeh/objects.py
@@ -746,6 +746,7 @@ class BoxSelectionOverlay(Renderer):
     tool = Instance(Tool)
 
 class HoverTool(Tool):
+    names = List(String)
     renderers = List(Instance(Renderer))
     tooltips = Dict(String, String)
     always_active = Bool(True)
diff --git a/examples/glyphs/maps.py b/examples/glyphs/maps.py
--- a/examples/glyphs/maps.py
+++ b/examples/glyphs/maps.py
@@ -5,17 +5,17 @@
 from bokeh.embed import file_html
 from bokeh.glyphs import Circle
 from bokeh.objects import (
-    GeoJSPlot, Range1d, ColumnDataSource,
+    GMapPlot, Range1d, ColumnDataSource,
     PanTool, WheelZoomTool, BoxSelectTool,
-    BoxSelectionOverlay, GeoJSOptions)
+    BoxSelectionOverlay, GMapOptions)
 from bokeh.resources import INLINE
 
 x_range = Range1d()
 y_range = Range1d()
 
-map_options = GeoJSOptions(lat=30.2861, lng=-97.7394, zoom=15)
+map_options = GMapOptions(lat=30.2861, lng=-97.7394, zoom=15)
 
-plot = GeoJSPlot(
+plot = GMapPlot(
     x_range=x_range, y_range=y_range,
     map_options=map_options,
     title = "Austin"


Test patch: