Repository: bokeh/bokeh

Issue:
Can't add callbacks to CheckboxGroups
When I run

```
cb = Callback(code="console.log(cb_obj);")
checkbox_group = CheckboxGroup(labels=["1", "2", "3"], active=[0, 1], callback=cb)
```

I get an error: 

```
AttributeError: unexpected attribute 'callback' to CheckboxGroup, possible attributes are active, disabled, inline, labels, name, session or tags
```

Is this expected behavior? If we can't add callbacks to CheckboxGroups, what is the point of having them?



Discussion:
It's always been possible to add python callbacks in conjunction with a Bokeh server. The JS callbacks are a very recent feature, and the omission of a `callback` property on this particular widget was probably an oversight. Thank you for bringing it to our attention. If you'd like to contribute a PR to implement this feature, that would certainly be appreciated (and probably accelerate the work). If not, we will schedule it when we are first able. 

ping @bokeh/dev 

As suggested in #2649, +1 on adding `callback` at the root of the model

I personally don't like the idea of adding it indescriminately, because there are widgets for which callbacks have no sensible meaning (paragraphs? layouts?) I'd rather be explicit and add them where needed, or introduce a new "Callbackable" class that things could inherit from when it makes sense for them to have callbacks. 

Right. I forgot about widgets that are not "interactive" like paragraphs, panels or layouts..

I get the sense of the "Callbackable" class but it feels a bit weird... the concept of "interactive" seems a bit more natural to me. Also, the callback concept applies nicely to "on change" events while having just one "callback" for more complex widgets like Dialog or DataTable feels a limitation.

For the record, I really don't like the term "callback".  It's very "software geeky" and since this is stuff that shows up as a kwarg in the data scientist-facing API, we want to use something that's evocative.  I think `event_handler` or something along those lines would be much more approachable.  In a similar vein, if we determine that subclassing/mixing-in is the best way to manifest this behavior, then the name "Callbackable" would change to something like "Evented" or "Reactive" or whatnot.

@pzwang there is an open PR ( #2675) to rename callbacks as "CustomJS". I don't know if you have any opinions on that name.

Hi, any progress on this? I noticed that CheckboxGroup seems to still not have a callback option. I'm not sure what the purpose of having the checkboxes is if they cannot be used to interact with a plot...

It actually looks like the required JS is in place for checkbox and radio button groups:

https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/models/widgets/checkbox_group.coffee#L40
https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/models/widgets/radio_button_group.coffee#L42

In which case all that is missing is the property declaration on the python class. Basically a line like this:

https://github.com/bokeh/bokeh/blob/master/bokeh/models/ranges.py#L26

needs to be added to the corresponding python classes. @guillochon can you try that and report back? Or ideally, submit the small PR? I am underwater trying to get to the `0.12` freeze but if you have time to work on this there is a chance it could make it into `0.12`. 


Resolving patch:
diff --git a/bokeh/models/widgets/groups.py b/bokeh/models/widgets/groups.py
--- a/bokeh/models/widgets/groups.py
+++ b/bokeh/models/widgets/groups.py
@@ -4,9 +4,10 @@
 from __future__ import absolute_import
 
 from ...core.properties import abstract
-from ...core.properties import Bool, Int, String, List
+from ...core.properties import Bool, Int, String, List, Instance
 from .widget import Widget
 from .buttons import ButtonLike
+from ..callbacks import Callback
 
 @abstract
 class AbstractGroup(Widget):
@@ -32,6 +33,10 @@ def on_click(self, handler):
         """
         self.on_change('active', lambda attr, old, new: handler(new))
 
+    callback = Instance(Callback, help="""
+    A callback to run in the browser whenever a button group is manipulated.
+    """)
+
 @abstract
 class ButtonGroup(AbstractGroup, ButtonLike):
     """ Abstract base class for groups with items rendered as buttons.


Test patch: