We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add a "callback" to a source.selected event
#2175 allows you to attach a callback to an input widget.

We also want to be able to attach one to source.selected event.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bokeh/models/sources.py`
Content:
```
1 from __future__ import absolute_import
2 
3 from ..plot_object import PlotObject
4 from ..properties import HasProps
5 from ..properties import Any, Int, String, Instance, List, Dict, Either, Bool, Enum
6 
7 class DataSource(PlotObject):
8     """ A base class for data source types. ``DataSource`` is
9     not generally useful to instantiate on its own.
10 
11     """
12 
13     column_names = List(String, help="""
14     An list of names for all the columns in this DataSource.
15     """)
16     
17     selected = Dict(String, Dict(String, Any), default={
18         '0d': {'flag': False, 'indices': []},
19         '1d': {'indices': []},
20         '2d': {'indices': []}
21     }, help="""
22     A dict to indicate selected indices on different dimensions on this DataSource. Keys are:
23 
24     - 0d: indicates whether a Line or Patch glyphs have been hit. Value is a
25             dict with the following keys:
26 
27             - flag (boolean): true if glyph was with false otherwise
28             - indices (list): indices hit (if applicable)
29 
30     - 1d: indicates whether any of all other glyph (except [multi]line or
31             patches) was hit:
32 
33             - indices (list): indices that were hit/selected
34 
35     - 2d: indicates whether a [multi]line or patches) were hit:
36 
37             - indices (list(list)): indices of the lines/patches that were
38                 hit/selected
39     """)
40 
41     def columns(self, *columns):
42         """ Returns a ColumnsRef object for a column or set of columns
43         on this data source.
44 
45         Args:
46             *columns
47 
48         Returns:
49             ColumnsRef
50 
51         """
52         return ColumnsRef(source=self, columns=list(columns))
53 
54 class ColumnsRef(HasProps):
55     """ A utility object to allow referring to a collection of columns
56     from a specified data source, all together.
57 
58     """
59 
60     source = Instance(DataSource, help="""
61     A data source to reference.
62     """)
63 
64     columns = List(String, help="""
65     A list of column names to reference from ``source``.
66     """)
67 
68 class ColumnDataSource(DataSource):
69     """ Maps names of columns to sequences or arrays.
70 
71     If the ColumnDataSource initializer is called with a single
72     argument that is a dict, that argument is used as the value for
73     the "data" attribute. For example::
74 
75         ColumnDataSource(mydict) # same as ColumnDataSource(data=mydict)
76 
77     .. note::
78         There is an implicit assumption that all the columns in a
79         a given ColumnDataSource have the same length.
80 
81     """
82 
83     data = Dict(String, Any, help="""
84     Mapping of column names to sequences of data. The data can be, e.g,
85     Python lists or tuples, NumPy arrays, etc.
86     """)
87 
88     def __init__(self, *args, **kw):
89         """ If called with a single argument that is a dict, treat
90         that implicitly as the "data" attribute.
91         """
92         if len(args) == 1 and "data" not in kw:
93             kw["data"] = args[0]
94         # TODO (bev) invalid to pass args and "data", check and raise exception
95         raw_data = kw.pop("data", {})
96         if not isinstance(raw_data, dict):
97             import pandas as pd
98             if isinstance(raw_data, pd.DataFrame):
99                 raw_data = self.from_df(raw_data)
100             else:
101                 raise ValueError("expected a dict or pandas.DataFrame, got %s" % raw_data)
102         for name, data in raw_data.items():
103             self.add(data, name)
104         super(ColumnDataSource, self).__init__(**kw)
105 
106     # TODO: (bev) why not just return a ColumnDataSource?
107     @classmethod
108     def from_df(cls, data):
109         """ Create a ``dict`` of columns from a Pandas DataFrame,
110         suitable for creating a ColumnDataSource.
111 
112         Args:
113             data (DataFrame) : data to convert
114 
115         Returns:
116             dict(str, list)
117 
118         """
119         index = data.index
120         new_data = {}
121         for colname in data:
122             new_data[colname] = data[colname].tolist()
123         if index.name:
124             new_data[index.name] = index.tolist()
125         elif index.names and not all([x is None for x in index.names]):
126             new_data["_".join(index.names)] = index.tolist()
127         else:
128             new_data["index"] = index.tolist()
129         return new_data
130 
131     def to_df(self):
132         """ Convert this data source to pandas dataframe.
133 
134         If ``column_names`` is set, use those. Otherwise let Pandas
135         infer the column names. The ``column_names`` property can be
136         used both to order and filter the columns.
137 
138         Returns:
139             DataFrame
140 
141         """
142         import pandas as pd
143         if self.column_names:
144             return pd.DataFrame(self.data, columns=self.column_names)
145         else:
146             return pd.DataFrame(self.data)
147 
148     def add(self, data, name=None):
149         """ Appends a new column of data to the data source.
150 
151         Args:
152             data (seq) : new data to add
153             name (str, optional) : column name to use.
154                 If not supplied, generate a name go the form "Series ####"
155 
156         Returns:
157             str:  the column name used
158 
159         """
160         if name is None:
161             n = len(self.data)
162             while "Series %d"%n in self.data:
163                 n += 1
164             name = "Series %d"%n
165         self.column_names.append(name)
166         self.data[name] = data
167         return name
168 
169     def remove(self, name):
170         """ Remove a column of data.
171 
172         Args:
173             name (str) : name of the column to remove
174 
175         Returns:
176             None
177 
178         .. note::
179             If the column name does not exist, a warning is issued.
180 
181         """
182         try:
183             self.column_names.remove(name)
184             del self.data[name]
185         except (ValueError, KeyError):
186             import warnings
187             warnings.warn("Unable to find column '%s' in data source" % name)
188 
189     def push_notebook(self):
190         """ Update date for a plot in the IPthon notebook in place.
191 
192         This function can be be used to update data in plot data sources
193         in the IPython notebook, without having to use the Bokeh server.
194 
195         Returns:
196             None
197 
198         .. warning::
199             The current implementation leaks memory in the IPython notebook,
200             due to accumulating JS code. This function typically works well
201             with light UI interactions, but should not be used for continuously
202             updating data. See :bokeh-issue:`1732` for more details and to
203             track progress on potential fixes.
204 
205         """
206         from IPython.core import display
207         from bokeh.protocol import serialize_json
208         id = self.ref['id']
209         model = self.ref['type']
210         json = serialize_json(self.vm_serialize())
211         js = """
212             var ds = Bokeh.Collections('{model}').get('{id}');
213             var data = {json};
214             ds.set(data);
215         """.format(model=model, id=id, json=json)
216         display.display_javascript(js, raw=True)
217 
218 class RemoteSource(DataSource):
219     data_url = String(help="""
220     The URL to the endpoint for the data.
221     """)
222     data = Dict(String, Any, help="""
223     Additional data to include directly in this data source object. The
224     columns provided here are merged with those from the Bokeh server.
225     """)
226     polling_interval = Int(help="""
227     polling interval for updating data source in milliseconds
228     """)
229 
230 class AjaxDataSource(RemoteSource):
231     method = Enum('POST', 'GET', help="http method - GET or POST")
232 
233     mode = Enum("replace", "append", help="""
234     Whether to append new data to existing data (up to ``max_size``),
235     or to replace existing data entirely.
236     """)
237     max_size = Int(help="""
238     Maximum size of the data array being kept after each pull requests.
239     Larger than that size, the data will be right shifted.
240     """)
241     if_modified = Bool(False, help="""
242     Whether to include an ``If-Modified-Since`` header in AJAX requests
243     to the server. If this header is supported by the server, then only
244     new data since the last request will be returned.
245     """)
246 
247 class BlazeDataSource(RemoteSource):
248     #blaze parts
249     expr = Dict(String, Any(), help="""
250     blaze expression graph in json form
251     """)
252     namespace = Dict(String, Any(), help="""
253     namespace in json form for evaluating blaze expression graph
254     """)
255     local = Bool(help="""
256     Whether this data source is hosted by the bokeh server or not.
257     """)
258 
259     def from_blaze(self, remote_blaze_obj, local=True):
260         from blaze.server import to_tree
261         # only one Client object, can hold many datasets
262         assert len(remote_blaze_obj._leaves()) == 1
263         leaf = remote_blaze_obj._leaves()[0]
264         blaze_client = leaf.data
265         json_expr = to_tree(remote_blaze_obj, {leaf : ':leaf'})
266         self.data_url = blaze_client.url + "/compute.json"
267         self.local = local
268         self.expr = json_expr
269 
270     def to_blaze(self):
271         from blaze.server.client import Client
272         from blaze.server import from_tree
273         from blaze import Data
274         # hacky - blaze urls have `compute.json` in it, but we need to strip it off
275         # to feed it into the blaze client lib
276         c = Client(self.data_url.rsplit('compute.json', 1)[0])
277         d = Data(c)
278         return from_tree(self.expr, {':leaf' : d})
279 
280 
281 class ServerDataSource(BlazeDataSource):
282     """ A data source that referes to data located on a Bokeh server.
283 
284     The data from the server is loaded on-demand by the client.
285     """
286     # Paramters of data transformation operations
287     # The 'Any' is used to pass primtives around.
288     # TODO: (jc) Find/create a property type for 'any primitive/atomic value'
289     transform = Dict(String,Either(Instance(PlotObject), Any), help="""
290     Paramters of the data transformation operations.
291 
292     The associated valuse is minimally a tag that says which downsample routine
293     to use.  For some downsamplers, parameters are passed this way too.
294     """)
295
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/bokeh/models/sources.py b/bokeh/models/sources.py
--- a/bokeh/models/sources.py
+++ b/bokeh/models/sources.py
@@ -1,5 +1,6 @@
 from __future__ import absolute_import
 
+from .actions import Callback
 from ..plot_object import PlotObject
 from ..properties import HasProps
 from ..properties import Any, Int, String, Instance, List, Dict, Either, Bool, Enum
@@ -13,7 +14,7 @@
     column_names = List(String, help="""
     An list of names for all the columns in this DataSource.
     """)
-    
+
     selected = Dict(String, Dict(String, Any), default={
         '0d': {'flag': False, 'indices': []},
         '1d': {'indices': []},
@@ -38,6 +39,10 @@
                 hit/selected
     """)
 
+    callback = Instance(Callback, help="""
+    A callback to run in the browser whenever the selection is changed.
+    """)
+
     def columns(self, *columns):
         """ Returns a ColumnsRef object for a column or set of columns
         on this data source.

{"golden_diff": "diff --git a/bokeh/models/sources.py b/bokeh/models/sources.py\n--- a/bokeh/models/sources.py\n+++ b/bokeh/models/sources.py\n@@ -1,5 +1,6 @@\n from __future__ import absolute_import\n \n+from .actions import Callback\n from ..plot_object import PlotObject\n from ..properties import HasProps\n from ..properties import Any, Int, String, Instance, List, Dict, Either, Bool, Enum\n@@ -13,7 +14,7 @@\n     column_names = List(String, help=\"\"\"\n     An list of names for all the columns in this DataSource.\n     \"\"\")\n-    \n+\n     selected = Dict(String, Dict(String, Any), default={\n         '0d': {'flag': False, 'indices': []},\n         '1d': {'indices': []},\n@@ -38,6 +39,10 @@\n                 hit/selected\n     \"\"\")\n \n+    callback = Instance(Callback, help=\"\"\"\n+    A callback to run in the browser whenever the selection is changed.\n+    \"\"\")\n+\n     def columns(self, *columns):\n         \"\"\" Returns a ColumnsRef object for a column or set of columns\n         on this data source.\n", "issue": "Add a \"callback\" to a source.selected event\n#2175 allows you to attach a callback to an input widget.\n\nWe also want to be able to attach one to source.selected event.\n\n", "before_files": [{"content": "from __future__ import absolute_import\n\nfrom ..plot_object import PlotObject\nfrom ..properties import HasProps\nfrom ..properties import Any, Int, String, Instance, List, Dict, Either, Bool, Enum\n\nclass DataSource(PlotObject):\n    \"\"\" A base class for data source types. ``DataSource`` is\n    not generally useful to instantiate on its own.\n\n    \"\"\"\n\n    column_names = List(String, help=\"\"\"\n    An list of names for all the columns in this DataSource.\n    \"\"\")\n    \n    selected = Dict(String, Dict(String, Any), default={\n        '0d': {'flag': False, 'indices': []},\n        '1d': {'indices': []},\n        '2d': {'indices': []}\n    }, help=\"\"\"\n    A dict to indicate selected indices on different dimensions on this DataSource. Keys are:\n\n    - 0d: indicates whether a Line or Patch glyphs have been hit. Value is a\n            dict with the following keys:\n\n            - flag (boolean): true if glyph was with false otherwise\n            - indices (list): indices hit (if applicable)\n\n    - 1d: indicates whether any of all other glyph (except [multi]line or\n            patches) was hit:\n\n            - indices (list): indices that were hit/selected\n\n    - 2d: indicates whether a [multi]line or patches) were hit:\n\n            - indices (list(list)): indices of the lines/patches that were\n                hit/selected\n    \"\"\")\n\n    def columns(self, *columns):\n        \"\"\" Returns a ColumnsRef object for a column or set of columns\n        on this data source.\n\n        Args:\n            *columns\n\n        Returns:\n            ColumnsRef\n\n        \"\"\"\n        return ColumnsRef(source=self, columns=list(columns))\n\nclass ColumnsRef(HasProps):\n    \"\"\" A utility object to allow referring to a collection of columns\n    from a specified data source, all together.\n\n    \"\"\"\n\n    source = Instance(DataSource, help=\"\"\"\n    A data source to reference.\n    \"\"\")\n\n    columns = List(String, help=\"\"\"\n    A list of column names to reference from ``source``.\n    \"\"\")\n\nclass ColumnDataSource(DataSource):\n    \"\"\" Maps names of columns to sequences or arrays.\n\n    If the ColumnDataSource initializer is called with a single\n    argument that is a dict, that argument is used as the value for\n    the \"data\" attribute. For example::\n\n        ColumnDataSource(mydict) # same as ColumnDataSource(data=mydict)\n\n    .. note::\n        There is an implicit assumption that all the columns in a\n        a given ColumnDataSource have the same length.\n\n    \"\"\"\n\n    data = Dict(String, Any, help=\"\"\"\n    Mapping of column names to sequences of data. The data can be, e.g,\n    Python lists or tuples, NumPy arrays, etc.\n    \"\"\")\n\n    def __init__(self, *args, **kw):\n        \"\"\" If called with a single argument that is a dict, treat\n        that implicitly as the \"data\" attribute.\n        \"\"\"\n        if len(args) == 1 and \"data\" not in kw:\n            kw[\"data\"] = args[0]\n        # TODO (bev) invalid to pass args and \"data\", check and raise exception\n        raw_data = kw.pop(\"data\", {})\n        if not isinstance(raw_data, dict):\n            import pandas as pd\n            if isinstance(raw_data, pd.DataFrame):\n                raw_data = self.from_df(raw_data)\n            else:\n                raise ValueError(\"expected a dict or pandas.DataFrame, got %s\" % raw_data)\n        for name, data in raw_data.items():\n            self.add(data, name)\n        super(ColumnDataSource, self).__init__(**kw)\n\n    # TODO: (bev) why not just return a ColumnDataSource?\n    @classmethod\n    def from_df(cls, data):\n        \"\"\" Create a ``dict`` of columns from a Pandas DataFrame,\n        suitable for creating a ColumnDataSource.\n\n        Args:\n            data (DataFrame) : data to convert\n\n        Returns:\n            dict(str, list)\n\n        \"\"\"\n        index = data.index\n        new_data = {}\n        for colname in data:\n            new_data[colname] = data[colname].tolist()\n        if index.name:\n            new_data[index.name] = index.tolist()\n        elif index.names and not all([x is None for x in index.names]):\n            new_data[\"_\".join(index.names)] = index.tolist()\n        else:\n            new_data[\"index\"] = index.tolist()\n        return new_data\n\n    def to_df(self):\n        \"\"\" Convert this data source to pandas dataframe.\n\n        If ``column_names`` is set, use those. Otherwise let Pandas\n        infer the column names. The ``column_names`` property can be\n        used both to order and filter the columns.\n\n        Returns:\n            DataFrame\n\n        \"\"\"\n        import pandas as pd\n        if self.column_names:\n            return pd.DataFrame(self.data, columns=self.column_names)\n        else:\n            return pd.DataFrame(self.data)\n\n    def add(self, data, name=None):\n        \"\"\" Appends a new column of data to the data source.\n\n        Args:\n            data (seq) : new data to add\n            name (str, optional) : column name to use.\n                If not supplied, generate a name go the form \"Series ####\"\n\n        Returns:\n            str:  the column name used\n\n        \"\"\"\n        if name is None:\n            n = len(self.data)\n            while \"Series %d\"%n in self.data:\n                n += 1\n            name = \"Series %d\"%n\n        self.column_names.append(name)\n        self.data[name] = data\n        return name\n\n    def remove(self, name):\n        \"\"\" Remove a column of data.\n\n        Args:\n            name (str) : name of the column to remove\n\n        Returns:\n            None\n\n        .. note::\n            If the column name does not exist, a warning is issued.\n\n        \"\"\"\n        try:\n            self.column_names.remove(name)\n            del self.data[name]\n        except (ValueError, KeyError):\n            import warnings\n            warnings.warn(\"Unable to find column '%s' in data source\" % name)\n\n    def push_notebook(self):\n        \"\"\" Update date for a plot in the IPthon notebook in place.\n\n        This function can be be used to update data in plot data sources\n        in the IPython notebook, without having to use the Bokeh server.\n\n        Returns:\n            None\n\n        .. warning::\n            The current implementation leaks memory in the IPython notebook,\n            due to accumulating JS code. This function typically works well\n            with light UI interactions, but should not be used for continuously\n            updating data. See :bokeh-issue:`1732` for more details and to\n            track progress on potential fixes.\n\n        \"\"\"\n        from IPython.core import display\n        from bokeh.protocol import serialize_json\n        id = self.ref['id']\n        model = self.ref['type']\n        json = serialize_json(self.vm_serialize())\n        js = \"\"\"\n            var ds = Bokeh.Collections('{model}').get('{id}');\n            var data = {json};\n            ds.set(data);\n        \"\"\".format(model=model, id=id, json=json)\n        display.display_javascript(js, raw=True)\n\nclass RemoteSource(DataSource):\n    data_url = String(help=\"\"\"\n    The URL to the endpoint for the data.\n    \"\"\")\n    data = Dict(String, Any, help=\"\"\"\n    Additional data to include directly in this data source object. The\n    columns provided here are merged with those from the Bokeh server.\n    \"\"\")\n    polling_interval = Int(help=\"\"\"\n    polling interval for updating data source in milliseconds\n    \"\"\")\n\nclass AjaxDataSource(RemoteSource):\n    method = Enum('POST', 'GET', help=\"http method - GET or POST\")\n\n    mode = Enum(\"replace\", \"append\", help=\"\"\"\n    Whether to append new data to existing data (up to ``max_size``),\n    or to replace existing data entirely.\n    \"\"\")\n    max_size = Int(help=\"\"\"\n    Maximum size of the data array being kept after each pull requests.\n    Larger than that size, the data will be right shifted.\n    \"\"\")\n    if_modified = Bool(False, help=\"\"\"\n    Whether to include an ``If-Modified-Since`` header in AJAX requests\n    to the server. If this header is supported by the server, then only\n    new data since the last request will be returned.\n    \"\"\")\n\nclass BlazeDataSource(RemoteSource):\n    #blaze parts\n    expr = Dict(String, Any(), help=\"\"\"\n    blaze expression graph in json form\n    \"\"\")\n    namespace = Dict(String, Any(), help=\"\"\"\n    namespace in json form for evaluating blaze expression graph\n    \"\"\")\n    local = Bool(help=\"\"\"\n    Whether this data source is hosted by the bokeh server or not.\n    \"\"\")\n\n    def from_blaze(self, remote_blaze_obj, local=True):\n        from blaze.server import to_tree\n        # only one Client object, can hold many datasets\n        assert len(remote_blaze_obj._leaves()) == 1\n        leaf = remote_blaze_obj._leaves()[0]\n        blaze_client = leaf.data\n        json_expr = to_tree(remote_blaze_obj, {leaf : ':leaf'})\n        self.data_url = blaze_client.url + \"/compute.json\"\n        self.local = local\n        self.expr = json_expr\n\n    def to_blaze(self):\n        from blaze.server.client import Client\n        from blaze.server import from_tree\n        from blaze import Data\n        # hacky - blaze urls have `compute.json` in it, but we need to strip it off\n        # to feed it into the blaze client lib\n        c = Client(self.data_url.rsplit('compute.json', 1)[0])\n        d = Data(c)\n        return from_tree(self.expr, {':leaf' : d})\n\n\nclass ServerDataSource(BlazeDataSource):\n    \"\"\" A data source that referes to data located on a Bokeh server.\n\n    The data from the server is loaded on-demand by the client.\n    \"\"\"\n    # Paramters of data transformation operations\n    # The 'Any' is used to pass primtives around.\n    # TODO: (jc) Find/create a property type for 'any primitive/atomic value'\n    transform = Dict(String,Either(Instance(PlotObject), Any), help=\"\"\"\n    Paramters of the data transformation operations.\n\n    The associated valuse is minimally a tag that says which downsample routine\n    to use.  For some downsamplers, parameters are passed this way too.\n    \"\"\")\n", "path": "bokeh/models/sources.py"}], "after_files": [{"content": "from __future__ import absolute_import\n\nfrom .actions import Callback\nfrom ..plot_object import PlotObject\nfrom ..properties import HasProps\nfrom ..properties import Any, Int, String, Instance, List, Dict, Either, Bool, Enum\n\nclass DataSource(PlotObject):\n    \"\"\" A base class for data source types. ``DataSource`` is\n    not generally useful to instantiate on its own.\n\n    \"\"\"\n\n    column_names = List(String, help=\"\"\"\n    An list of names for all the columns in this DataSource.\n    \"\"\")\n\n    selected = Dict(String, Dict(String, Any), default={\n        '0d': {'flag': False, 'indices': []},\n        '1d': {'indices': []},\n        '2d': {'indices': []}\n    }, help=\"\"\"\n    A dict to indicate selected indices on different dimensions on this DataSource. Keys are:\n\n    - 0d: indicates whether a Line or Patch glyphs have been hit. Value is a\n            dict with the following keys:\n\n            - flag (boolean): true if glyph was with false otherwise\n            - indices (list): indices hit (if applicable)\n\n    - 1d: indicates whether any of all other glyph (except [multi]line or\n            patches) was hit:\n\n            - indices (list): indices that were hit/selected\n\n    - 2d: indicates whether a [multi]line or patches) were hit:\n\n            - indices (list(list)): indices of the lines/patches that were\n                hit/selected\n    \"\"\")\n\n    callback = Instance(Callback, help=\"\"\"\n    A callback to run in the browser whenever the selection is changed.\n    \"\"\")\n\n    def columns(self, *columns):\n        \"\"\" Returns a ColumnsRef object for a column or set of columns\n        on this data source.\n\n        Args:\n            *columns\n\n        Returns:\n            ColumnsRef\n\n        \"\"\"\n        return ColumnsRef(source=self, columns=list(columns))\n\nclass ColumnsRef(HasProps):\n    \"\"\" A utility object to allow referring to a collection of columns\n    from a specified data source, all together.\n\n    \"\"\"\n\n    source = Instance(DataSource, help=\"\"\"\n    A data source to reference.\n    \"\"\")\n\n    columns = List(String, help=\"\"\"\n    A list of column names to reference from ``source``.\n    \"\"\")\n\nclass ColumnDataSource(DataSource):\n    \"\"\" Maps names of columns to sequences or arrays.\n\n    If the ColumnDataSource initializer is called with a single\n    argument that is a dict, that argument is used as the value for\n    the \"data\" attribute. For example::\n\n        ColumnDataSource(mydict) # same as ColumnDataSource(data=mydict)\n\n    .. note::\n        There is an implicit assumption that all the columns in a\n        a given ColumnDataSource have the same length.\n\n    \"\"\"\n\n    data = Dict(String, Any, help=\"\"\"\n    Mapping of column names to sequences of data. The data can be, e.g,\n    Python lists or tuples, NumPy arrays, etc.\n    \"\"\")\n\n    def __init__(self, *args, **kw):\n        \"\"\" If called with a single argument that is a dict, treat\n        that implicitly as the \"data\" attribute.\n        \"\"\"\n        if len(args) == 1 and \"data\" not in kw:\n            kw[\"data\"] = args[0]\n        # TODO (bev) invalid to pass args and \"data\", check and raise exception\n        raw_data = kw.pop(\"data\", {})\n        if not isinstance(raw_data, dict):\n            import pandas as pd\n            if isinstance(raw_data, pd.DataFrame):\n                raw_data = self.from_df(raw_data)\n            else:\n                raise ValueError(\"expected a dict or pandas.DataFrame, got %s\" % raw_data)\n        for name, data in raw_data.items():\n            self.add(data, name)\n        super(ColumnDataSource, self).__init__(**kw)\n\n    # TODO: (bev) why not just return a ColumnDataSource?\n    @classmethod\n    def from_df(cls, data):\n        \"\"\" Create a ``dict`` of columns from a Pandas DataFrame,\n        suitable for creating a ColumnDataSource.\n\n        Args:\n            data (DataFrame) : data to convert\n\n        Returns:\n            dict(str, list)\n\n        \"\"\"\n        index = data.index\n        new_data = {}\n        for colname in data:\n            new_data[colname] = data[colname].tolist()\n        if index.name:\n            new_data[index.name] = index.tolist()\n        elif index.names and not all([x is None for x in index.names]):\n            new_data[\"_\".join(index.names)] = index.tolist()\n        else:\n            new_data[\"index\"] = index.tolist()\n        return new_data\n\n    def to_df(self):\n        \"\"\" Convert this data source to pandas dataframe.\n\n        If ``column_names`` is set, use those. Otherwise let Pandas\n        infer the column names. The ``column_names`` property can be\n        used both to order and filter the columns.\n\n        Returns:\n            DataFrame\n\n        \"\"\"\n        import pandas as pd\n        if self.column_names:\n            return pd.DataFrame(self.data, columns=self.column_names)\n        else:\n            return pd.DataFrame(self.data)\n\n    def add(self, data, name=None):\n        \"\"\" Appends a new column of data to the data source.\n\n        Args:\n            data (seq) : new data to add\n            name (str, optional) : column name to use.\n                If not supplied, generate a name go the form \"Series ####\"\n\n        Returns:\n            str:  the column name used\n\n        \"\"\"\n        if name is None:\n            n = len(self.data)\n            while \"Series %d\"%n in self.data:\n                n += 1\n            name = \"Series %d\"%n\n        self.column_names.append(name)\n        self.data[name] = data\n        return name\n\n    def remove(self, name):\n        \"\"\" Remove a column of data.\n\n        Args:\n            name (str) : name of the column to remove\n\n        Returns:\n            None\n\n        .. note::\n            If the column name does not exist, a warning is issued.\n\n        \"\"\"\n        try:\n            self.column_names.remove(name)\n            del self.data[name]\n        except (ValueError, KeyError):\n            import warnings\n            warnings.warn(\"Unable to find column '%s' in data source\" % name)\n\n    def push_notebook(self):\n        \"\"\" Update date for a plot in the IPthon notebook in place.\n\n        This function can be be used to update data in plot data sources\n        in the IPython notebook, without having to use the Bokeh server.\n\n        Returns:\n            None\n\n        .. warning::\n            The current implementation leaks memory in the IPython notebook,\n            due to accumulating JS code. This function typically works well\n            with light UI interactions, but should not be used for continuously\n            updating data. See :bokeh-issue:`1732` for more details and to\n            track progress on potential fixes.\n\n        \"\"\"\n        from IPython.core import display\n        from bokeh.protocol import serialize_json\n        id = self.ref['id']\n        model = self.ref['type']\n        json = serialize_json(self.vm_serialize())\n        js = \"\"\"\n            var ds = Bokeh.Collections('{model}').get('{id}');\n            var data = {json};\n            ds.set(data);\n        \"\"\".format(model=model, id=id, json=json)\n        display.display_javascript(js, raw=True)\n\nclass RemoteSource(DataSource):\n    data_url = String(help=\"\"\"\n    The URL to the endpoint for the data.\n    \"\"\")\n    data = Dict(String, Any, help=\"\"\"\n    Additional data to include directly in this data source object. The\n    columns provided here are merged with those from the Bokeh server.\n    \"\"\")\n    polling_interval = Int(help=\"\"\"\n    polling interval for updating data source in milliseconds\n    \"\"\")\n\nclass AjaxDataSource(RemoteSource):\n    method = Enum('POST', 'GET', help=\"http method - GET or POST\")\n\n    mode = Enum(\"replace\", \"append\", help=\"\"\"\n    Whether to append new data to existing data (up to ``max_size``),\n    or to replace existing data entirely.\n    \"\"\")\n    max_size = Int(help=\"\"\"\n    Maximum size of the data array being kept after each pull requests.\n    Larger than that size, the data will be right shifted.\n    \"\"\")\n    if_modified = Bool(False, help=\"\"\"\n    Whether to include an ``If-Modified-Since`` header in AJAX requests\n    to the server. If this header is supported by the server, then only\n    new data since the last request will be returned.\n    \"\"\")\n\nclass BlazeDataSource(RemoteSource):\n    #blaze parts\n    expr = Dict(String, Any(), help=\"\"\"\n    blaze expression graph in json form\n    \"\"\")\n    namespace = Dict(String, Any(), help=\"\"\"\n    namespace in json form for evaluating blaze expression graph\n    \"\"\")\n    local = Bool(help=\"\"\"\n    Whether this data source is hosted by the bokeh server or not.\n    \"\"\")\n\n    def from_blaze(self, remote_blaze_obj, local=True):\n        from blaze.server import to_tree\n        # only one Client object, can hold many datasets\n        assert len(remote_blaze_obj._leaves()) == 1\n        leaf = remote_blaze_obj._leaves()[0]\n        blaze_client = leaf.data\n        json_expr = to_tree(remote_blaze_obj, {leaf : ':leaf'})\n        self.data_url = blaze_client.url + \"/compute.json\"\n        self.local = local\n        self.expr = json_expr\n\n    def to_blaze(self):\n        from blaze.server.client import Client\n        from blaze.server import from_tree\n        from blaze import Data\n        # hacky - blaze urls have `compute.json` in it, but we need to strip it off\n        # to feed it into the blaze client lib\n        c = Client(self.data_url.rsplit('compute.json', 1)[0])\n        d = Data(c)\n        return from_tree(self.expr, {':leaf' : d})\n\n\nclass ServerDataSource(BlazeDataSource):\n    \"\"\" A data source that referes to data located on a Bokeh server.\n\n    The data from the server is loaded on-demand by the client.\n    \"\"\"\n    # Paramters of data transformation operations\n    # The 'Any' is used to pass primtives around.\n    # TODO: (jc) Find/create a property type for 'any primitive/atomic value'\n    transform = Dict(String,Either(Instance(PlotObject), Any), help=\"\"\"\n    Paramters of the data transformation operations.\n\n    The associated valuse is minimally a tag that says which downsample routine\n    to use.  For some downsamplers, parameters are passed this way too.\n    \"\"\")\n", "path": "bokeh/models/sources.py"}]}