Repository: bokeh/bokeh

Issue:
`BoxSelectTool` should accept renderers = None
currently defaults to `[]` which is expanded all available renderers. Need a way to specify both "all" and "none".



Discussion:
Suggest interpretations:

```
.renderers = None   # none
.renderers = []     # none
.renderers = "auto" # all
```

so something like: `renderers = Either(Auto, Instance(Renderer))`

complicated by #2136, moving to later milestone

Resolving patch:
diff --git a/bokeh/models/tools.py b/bokeh/models/tools.py
--- a/bokeh/models/tools.py
+++ b/bokeh/models/tools.py
@@ -44,7 +44,6 @@
 from .renderers import Renderer, GlyphRenderer
 from .layouts import LayoutDOM
 
-
 @abstract
 class Tool(Model):
     ''' A base class for all interactive tool types.
@@ -89,7 +88,6 @@ class Tap(Tool):
     '''
     pass
 
-
 @abstract
 class Inspection(Tool):
     ''' A base class for tools that perform "inspections", e.g. ``HoverTool``.
@@ -116,7 +114,6 @@ class ToolbarBase(Model):
     A list of tools to add to the plot.
     """)
 
-
 class Toolbar(ToolbarBase):
     ''' Collect tools to display for a single plot.
 
@@ -194,7 +191,6 @@ class WheelPanTool(Scroll):
     default the wheel pan tool will pan the plot along the x-axis.
     """)
 
-
 class WheelZoomTool(Scroll):
     ''' *toolbar icon*: |wheel_zoom_icon|
 
@@ -249,7 +245,6 @@ class SaveTool(Action):
 
     '''
 
-
 class ResetTool(Action):
     ''' *toolbar icon*: |reset_icon|
 
@@ -267,7 +262,6 @@ class ResetTool(Action):
 
     pass
 
-
 class TapTool(Tap):
     ''' *toolbar icon*: |tap_icon|
 
@@ -293,8 +287,8 @@ class TapTool(Tap):
     have a matching value for their ``name`` attribute will be used.
     """)
 
-    renderers = List(Instance(Renderer), help="""
-    An explicit list of renderers to hit test again. If unset,
+    renderers = Either(Auto, List(Instance(Renderer)), default="auto", help="""
+    An explicit list of renderers to hit test against. If unset,
     defaults to all renderers on a plot.
     """)
 
@@ -328,9 +322,6 @@ class TapTool(Tap):
 
     """)
 
-
-
-
 class CrosshairTool(Inspection):
     ''' *toolbar icon*: |crosshair_icon|
 
@@ -476,7 +467,6 @@ class ZoomOutTool(Action):
     Percentage to zoom for each click of the zoom-in tool.
     """)
 
-
 class BoxSelectTool(Drag):
     ''' *toolbar icon*: |box_select_icon|
 
@@ -499,8 +489,8 @@ class BoxSelectTool(Drag):
     have a matching value for their ``name`` attribute will be used.
     """)
 
-    renderers = List(Instance(Renderer), help="""
-    An explicit list of renderers to hit test again. If unset,
+    renderers = Either(Auto, List(Instance(Renderer)), default="auto", help="""
+    An explicit list of renderers to hit test against. If unset,
     defaults to all renderers on a plot.
     """)
 
@@ -570,8 +560,8 @@ class LassoSelectTool(Drag):
     have a matching value for their ``name`` attribute will be used.
     """)
 
-    renderers = List(Instance(Renderer), help="""
-    An explicit list of renderers to hit test again. If unset,
+    renderers = Either(Auto, List(Instance(Renderer)), default="auto", help="""
+    An explicit list of renderers to hit test against. If unset,
     defaults to all renderers on a plot.
     """)
 
@@ -592,7 +582,6 @@ class LassoSelectTool(Drag):
     A shaded annotation drawn to indicate the selection region.
     """)
 
-
 class PolySelectTool(Tap):
     ''' *toolbar icon*: |poly_select_icon|
 
@@ -621,8 +610,8 @@ class PolySelectTool(Tap):
     have a matching value for their ``name`` attribute will be used.
     """)
 
-    renderers = List(Instance(Renderer), help="""
-    An explicit list of renderers to hit test again. If unset,
+    renderers = Either(Auto, List(Instance(Renderer)), default="auto", help="""
+    An explicit list of renderers to hit test against. If unset,
     defaults to all renderers on a plot.
     """)
 
@@ -704,8 +693,8 @@ class HoverTool(Inspection):
     have a matching value for their ``name`` attribute will be used.
     """)
 
-    renderers = List(Instance(Renderer), help="""
-    An explicit list of renderers to hit test again. If unset,
+    renderers = Either(Auto, List(Instance(Renderer)), defatult="auto", help="""
+    An explicit list of renderers to hit test against. If unset,
     defaults to all renderers on a plot.
     """)
 
@@ -1059,7 +1048,6 @@ def _check_compatible_renderers(self):
             glyph_types = ', '.join([type(renderer.glyph).__name__ for renderer in incompatible_renderers])
             return "%s glyph type(s) found." % glyph_types
 
-
 class PolyEditTool(EditTool, Drag, Tap):
     ''' *toolbar icon*: |poly_edit_icon|
 
diff --git a/bokeh/plotting/helpers.py b/bokeh/plotting/helpers.py
--- a/bokeh/plotting/helpers.py
+++ b/bokeh/plotting/helpers.py
@@ -766,9 +766,6 @@ def func(self, **kwargs):
         if legend_item_label:
             _update_legend(self, legend_item_label, glyph_renderer)
 
-        for tool in self.select(type=BoxSelectTool):
-            tool.renderers.append(glyph_renderer)
-
         self.renderers.append(glyph_renderer)
 
         return glyph_renderer


Test patch:
diff --git a/bokehjs/test/models/tools/index.coffee b/bokehjs/test/models/tools/index.coffee
--- a/bokehjs/test/models/tools/index.coffee
+++ b/bokehjs/test/models/tools/index.coffee
@@ -5,3 +5,4 @@ require "./gestures"
 require "./toolbar"
 require "./toolbar_base"
 require "./toolbar_box"
+require "./util"
diff --git a/bokehjs/test/models/tools/util.coffee b/bokehjs/test/models/tools/util.coffee
new file mode 100644
--- /dev/null
+++ b/bokehjs/test/models/tools/util.coffee
@@ -0,0 +1,46 @@
+{expect} = require "chai"
+utils = require "../../utils"
+
+{compute_renderers} = utils.require("models/tools/util")
+{GlyphRenderer} = utils.require("models/renderers/glyph_renderer")
+{GraphRenderer} = utils.require("models/renderers/graph_renderer")
+
+g = new GlyphRenderer({name: "g"})
+g2 = new GlyphRenderer({name: "g2"})
+gr = new GraphRenderer({name: "gr"})
+
+describe "compute_renderers", ->
+
+  it "should return empty list for renderers=null", ->
+    r = compute_renderers(null, [], [])
+    expect(r).to.be.deep.equal []
+
+    r = compute_renderers(null, [g, g2, gr], [])
+    expect(r).to.be.deep.equal []
+
+    r = compute_renderers(null, [g, g2, gr], ["g2"])
+    expect(r).to.be.deep.equal []
+
+  it "should return empty list for renderers=[]", ->
+    r = compute_renderers([], [], [])
+    expect(r).to.be.deep.equal []
+
+    r = compute_renderers([], [g, g2, gr], [])
+    expect(r).to.be.deep.equal []
+
+    r = compute_renderers([], [g, g2, gr], ["g2"])
+    expect(r).to.be.deep.equal []
+
+  it "should return all_renderers for renderers='auto'", ->
+    r = compute_renderers('auto', [g, g2, gr], [])
+    expect(r).to.be.deep.equal [g, g2, gr]
+
+  it "should filter renderers by names", ->
+    r = compute_renderers([g, g2], [g, g2, gr], ["g"])
+    expect(r).to.be.deep.equal [g]
+
+    r = compute_renderers([g, g2, gr], [], ["g", "gr"])
+    expect(r).to.be.deep.equal [g, gr]
+
+    r = compute_renderers('auto', [g, g2, gr], ["g", "gr"])
+    expect(r).to.be.deep.equal [g, gr]