prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Method to update data source contents in the notebook
  There is a reference implementation by @akloster in https://github.com/akloster/nb-bokeh-animations
  
  ```
  def update_data_source(ds):
      id = ds.ref['id']
      model = ds.ref['type']
      js = """
          var ds = Bokeh.Collections('{model}').get('{id}');
          var data = {json};
          ds.set(data);
          """.format(
              model=model, 
              id=id, 
              json= serialize_json(ds.vm_serialize()))
      display.display_javascript(js, raw=True)
  ```
  
  Plan to use this as a starting place for a method on data sources that will update the BokehJS data source and trigger a re-draw, from python. Propose `ds.notebook_update()` for method name. 
  
  
  </issue>
  <code>
  [start of bokeh/models/sources.py]
  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
  6 
  7 class DataSource(PlotObject):
  8     """ Base class for data sources """
  9     # List of names of the fields of each tuple in self.data
  10     # ordering is incoporated here
  11     column_names = List(String)
  12     selected = List(Int) # index of selected points
  13 
  14     def columns(self, *columns):
  15         """ Returns a ColumnsRef object that points to a column or set of
  16         columns on this data source
  17         """
  18         return ColumnsRef(source=self, columns=list(columns))
  19 
  20 class ColumnsRef(HasProps):
  21     source = Instance(DataSource)
  22     columns = List(String)
  23 
  24 class ColumnDataSource(DataSource):
  25     # Maps names of columns to sequences or arrays
  26     data = Dict(String, Any)
  27 
  28     # Maps field/column name to a DataRange or FactorRange object. If the
  29     # field is not in the dict, then a range is created automatically.
  30     cont_ranges = Dict(String, Instance(".models.Range"))
  31     discrete_ranges = Dict(String, Instance(".models.Range"))
  32 
  33     def __init__(self, *args, **kw):
  34         """ Modify the basic DataSource/PlotObj constructor so that if we
  35         are called with a single argument that is a dict, then we treat
  36         that implicitly as our "data" attribute.
  37         """
  38         if len(args) == 1 and "data" not in kw:
  39             kw["data"] = args[0]
  40         raw_data = kw.pop("data", {})
  41         if not isinstance(raw_data, dict):
  42             import pandas as pd
  43             if isinstance(raw_data, pd.DataFrame):
  44                 raw_data = self.from_df(raw_data)
  45             else:
  46                 raise ValueError("expected a dict or pandas.DataFrame, got %s" % raw_data)
  47         for name, data in raw_data.items():
  48             self.add(data, name)
  49         super(ColumnDataSource, self).__init__(**kw)
  50 
  51     @classmethod
  52     def from_df(cls, raw_data):
  53         dfindex = raw_data.index
  54         new_data = {}
  55         for colname in raw_data:
  56             new_data[colname] = raw_data[colname].tolist()
  57         if dfindex.name:
  58             new_data[dfindex.name] = dfindex.tolist()
  59         elif dfindex.names and not all([x is None for x in dfindex.names]):
  60             new_data["_".join(dfindex.names)] = dfindex.tolist()
  61         else:
  62             new_data["index"] = dfindex.tolist()
  63         return new_data
  64 
  65     def to_df(self):
  66         """convert data source to pandas dataframe
  67         local import of pandas because of possible compatability issues (pypy?)
  68         if we have column_names set, we use those, otherwise we let
  69         pandas infer the column names.  column_names can be used to
  70         either order or filter the columns here.
  71         """
  72         import pandas as pd
  73         if self.column_names:
  74             return pd.DataFrame(self.data, columns=self.column_names)
  75         else:
  76             return pd.DataFrame(self.data)
  77 
  78     def add(self, data, name=None):
  79         """ Appends the data to the list of columns.  Returns the name
  80         that was inserted.
  81         """
  82         if name is None:
  83             n = len(self.data)
  84             while "Series %d"%n in self.data:
  85                 n += 1
  86             name = "Series %d"%n
  87         self.column_names.append(name)
  88         self.data[name] = data
  89         return name
  90 
  91     def remove(self, name):
  92         try:
  93             self.column_names.remove(name)
  94             del self.data[name]
  95         except (ValueError, KeyError):
  96             import warnings
  97             warnings.warn("Unable to find column '%s' in datasource" % name)
  98 
  99 class ServerDataSource(DataSource):
  100     data_url = String()
  101     owner_username = String()
  102 
  103     # allow us to add some data that isn't on the remote source
  104     # and join it to the remote data
  105     data = Dict(String, Any)
  106 
  107     # Paramters of data transformation operations
  108     # The 'Any' is used to pass primtives around.  Minimally, a tag to say which downsample routine to use.  In some downsamplers, parameters are passed this way too.
  109     # TODO: Find/create a property type for 'any primitive/atomic value'
  110     transform = Dict(String,Either(Instance(PlotObject), Any))
  111
  [end of bokeh/models/sources.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/bokeh/models/sources.py b/bokeh/models/sources.py
  --- a/bokeh/models/sources.py
  +++ b/bokeh/models/sources.py
  @@ -96,6 +96,19 @@
               import warnings
               warnings.warn("Unable to find column '%s' in datasource" % name)
   
  +    def push_notebook(self):
  +        from IPython.core import display
  +        from bokeh.protocol import serialize_json
  +        id = self.ref['id']
  +        model = self.ref['type']
  +        json = serialize_json(self.vm_serialize())
  +        js = """
  +            var ds = Bokeh.Collections('{model}').get('{id}');
  +            var data = {json};
  +            ds.set(data);
  +        """.format(model=model, id=id, json=json)
  +        display.display_javascript(js, raw=True)
  +
   class ServerDataSource(DataSource):
       data_url = String()
       owner_username = String()
  
verification_info: {"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@@ -96,6 +96,19 @@\n             import warnings\n             warnings.warn(\"Unable to find column '%s' in datasource\" % name)\n \n+    def push_notebook(self):\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+\n class ServerDataSource(DataSource):\n     data_url = String()\n     owner_username = String()\n", "issue": "Method to update data source contents in the notebook\nThere is a reference implementation by @akloster in https://github.com/akloster/nb-bokeh-animations\n\n```\ndef update_data_source(ds):\n    id = ds.ref['id']\n    model = ds.ref['type']\n    js = \"\"\"\n        var ds = Bokeh.Collections('{model}').get('{id}');\n        var data = {json};\n        ds.set(data);\n        \"\"\".format(\n            model=model, \n            id=id, \n            json= serialize_json(ds.vm_serialize()))\n    display.display_javascript(js, raw=True)\n```\n\nPlan to use this as a starting place for a method on data sources that will update the BokehJS data source and trigger a re-draw, from python. Propose `ds.notebook_update()` for method name. \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\n\nclass DataSource(PlotObject):\n    \"\"\" Base class for data sources \"\"\"\n    # List of names of the fields of each tuple in self.data\n    # ordering is incoporated here\n    column_names = List(String)\n    selected = List(Int) # index of selected points\n\n    def columns(self, *columns):\n        \"\"\" Returns a ColumnsRef object that points to a column or set of\n        columns on this data source\n        \"\"\"\n        return ColumnsRef(source=self, columns=list(columns))\n\nclass ColumnsRef(HasProps):\n    source = Instance(DataSource)\n    columns = List(String)\n\nclass ColumnDataSource(DataSource):\n    # Maps names of columns to sequences or arrays\n    data = Dict(String, Any)\n\n    # Maps field/column name to a DataRange or FactorRange object. If the\n    # field is not in the dict, then a range is created automatically.\n    cont_ranges = Dict(String, Instance(\".models.Range\"))\n    discrete_ranges = Dict(String, Instance(\".models.Range\"))\n\n    def __init__(self, *args, **kw):\n        \"\"\" Modify the basic DataSource/PlotObj constructor so that if we\n        are called with a single argument that is a dict, then we treat\n        that implicitly as our \"data\" attribute.\n        \"\"\"\n        if len(args) == 1 and \"data\" not in kw:\n            kw[\"data\"] = args[0]\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    @classmethod\n    def from_df(cls, raw_data):\n        dfindex = raw_data.index\n        new_data = {}\n        for colname in raw_data:\n            new_data[colname] = raw_data[colname].tolist()\n        if dfindex.name:\n            new_data[dfindex.name] = dfindex.tolist()\n        elif dfindex.names and not all([x is None for x in dfindex.names]):\n            new_data[\"_\".join(dfindex.names)] = dfindex.tolist()\n        else:\n            new_data[\"index\"] = dfindex.tolist()\n        return new_data\n\n    def to_df(self):\n        \"\"\"convert data source to pandas dataframe\n        local import of pandas because of possible compatability issues (pypy?)\n        if we have column_names set, we use those, otherwise we let\n        pandas infer the column names.  column_names can be used to\n        either order or filter the columns here.\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 the data to the list of columns.  Returns the name\n        that was inserted.\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        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 datasource\" % name)\n\nclass ServerDataSource(DataSource):\n    data_url = String()\n    owner_username = String()\n\n    # allow us to add some data that isn't on the remote source\n    # and join it to the remote data\n    data = Dict(String, Any)\n\n    # Paramters of data transformation operations\n    # The 'Any' is used to pass primtives around.  Minimally, a tag to say which downsample routine to use.  In some downsamplers, parameters are passed this way too.\n    # TODO: Find/create a property type for 'any primitive/atomic value'\n    transform = Dict(String,Either(Instance(PlotObject), Any))\n", "path": "bokeh/models/sources.py"}]}