Repository: bokeh/bokeh

Issue:
[BUG] Toolbar activation breaks if models are specified in certain order
This issue has been around for a very long time and still exists on current master. The conditions under which is bug occurs are somewhat obscure so it took me a very long time to finally reproduce in a minimal example but I believe it should still be fixed.

Basically if the root layout is created before the contents then models are potentially initialized in an order which causes the tool and toolbar active states to be out-of-sync after initialization. 

In the minimal example below the box_select tool is the first tool and appears active when initialized but in actual fact the pan tool is active. This is highly confusing and becomes even more confusing once you click on the pan tool which will then appear active but become deactivated.

```python
from bokeh.plotting import figure, output_notebook, show, save
from bokeh.resources import INLINE
from bokeh.layouts import row, gridplot
from bokeh.models import BoxSelectTool

output_notebook(resources=INLINE)

r = row()

p1 = figure(tools=['box_select,save,pan,wheel_zoom,box_zoom,reset'], width=200, height=200)
p1.scatter([1, 2, 3], [1, 2, 3])
p1.scatter([1, 2, 3], [1, 2, 3])
p1.rect([], [], 0, 0)

p2 = figure(tools=['box_select,save,pan,wheel_zoom,box_zoom,reset'], width=200, height=200)
p2.scatter([1, 2, 3], [1, 2, 3])
p2.scatter([1, 2, 3], [1, 2, 3])
p2.rect([], [], 0, 0)

grid = gridplot([[p1, p2]])

r.children = [grid]

show(r)
```


Discussion:
This may be an obscure case, but it happens every time for me with certain types of HoloViews plots, so I'm very much hoping it can be fixed soon!
The underlying cause here seems to be that the subplots still initialize their Toolbars and if the ProxyToolbar activates before the other hidden toolbars then they will mess up the initialization state.
@mattpap I have to admit I don't know the best way around this. I've tried deferring `ToolbarBase._init_tools` until the view is being rendered but couldn't get that to work. The reason why this is such a big issue for us is that Panel generally creates the root layout before adding the contents. Changing this would require a fairly substantial rewrite so it would definitely be nice to fix this somehow.
I will take a look. This is reproducible outside notebook with a simple `save()`, which is great.

Resolving patch:
diff --git a/bokeh/layouts.py b/bokeh/layouts.py
--- a/bokeh/layouts.py
+++ b/bokeh/layouts.py
@@ -272,7 +272,7 @@ def gridplot(children, sizing_mode=None, toolbar_location='above', ncols=None,
         children = []
 
     # Make the grid
-    tools = []
+    toolbars = []
     items = []
 
     for y, row in enumerate(children):
@@ -282,7 +282,7 @@ def gridplot(children, sizing_mode=None, toolbar_location='above', ncols=None,
             elif isinstance(item, LayoutDOM):
                 if merge_tools:
                     for plot in item.select(dict(type=Plot)):
-                        tools += plot.toolbar.tools
+                        toolbars.append(plot.toolbar)
                         plot.toolbar_location = None
 
                 if isinstance(item, Plot):
@@ -302,7 +302,8 @@ def gridplot(children, sizing_mode=None, toolbar_location='above', ncols=None,
         return GridBox(children=items, sizing_mode=sizing_mode)
 
     grid = GridBox(children=items)
-    proxy = ProxyToolbar(tools=tools, **toolbar_options)
+    tools = sum([ toolbar.tools for toolbar in toolbars ], [])
+    proxy = ProxyToolbar(toolbars=toolbars, tools=tools, **toolbar_options)
     toolbar = ToolbarBox(toolbar=proxy, toolbar_location=toolbar_location)
 
     if toolbar_location == 'above':
diff --git a/bokeh/models/tools.py b/bokeh/models/tools.py
--- a/bokeh/models/tools.py
+++ b/bokeh/models/tools.py
@@ -241,6 +241,9 @@ class ProxyToolbar(ToolbarBase):
 
     '''
 
+    toolbars = List(Instance(Toolbar), help="""
+    """)
+
 class ToolbarBox(LayoutDOM):
     ''' A layoutable toolbar that can accept the tools of multiple plots, and
     can merge the tools into a single button for convenience.


Test patch: