prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Bokeh 0.11: Enables webgl causes inconsistent update of scatter points
  This problem might be related to this issue: https://github.com/bokeh/bokeh/issues/3795
  
  Lets consider this minimal example:
  
  ``` python
  from bokeh.plotting import figure, show, ColumnDataSource
  from bokeh.models import Select
  from bokeh.models.widgets import RadioGroup
  from bokeh.io import vform
  import numpy as np
  
  N = 100
  x1 = np.random.normal(0.0, 1.0,N)
  x2 = x1 * (1.0 + np.random.normal(0.0, 0.1,N))
  y1 = 5.0*x1 + np.random.normal(0, 0.1, N)
  y2 = 50.0*x2 + np.random.normal(0, 1, N)
  
  source = ColumnDataSource({'x' : x1, 'y' : y1})
  
  TOOLS = "box_select,box_zoom,lasso_select,help,reset,pan"
  p = figure(tools=TOOLS, plot_width=400, plot_height=400, webgl=True)
  p.circle(x='x', y='y', source=source)
  
  x_radio_group = RadioGroup(labels=["x1", "x2"], active=0)
  y_radio_group = RadioGroup(labels=["y1", "y2"], active=0)
  controls = vform(x_radio_group, y_radio_group)
  
  def update(attr, old, new):
      source.data["y"] = y1 if y_radio_group.active==0 else y2
      source.data["x"] = x1 if x_radio_group.active==0 else x2
  
      # Updating the source in one step does not change this behavior
      #data = dict(x=x1 if x_radio_group.active==0 else x2, y=y1 if y_radio_group.active==0 else y2)
      #source.data = data
  
  source.on_change('selected', update)
  
  def select_x(value):
      update('x-change', None, None)
  
  def select_y(value):
      update('y-change', None, None)
  
  x_radio_group.on_click(select_x)
  y_radio_group.on_click(select_y)
  ```
  
  You can reproduce this problem in the following way (using the bokeh server):
  - Fire up the bokeh server (e.g. bokeh server file --show)
  - Select a subset of the data points (using box select or lasso)
  - Switch between y1 and y2 radio buttons
  - Notice that even though the y-axis scaled as expected, the scatter points did not!
  
  Now if you repeat this exercise with webgl=False, you should see that both the y-axis and the scatter points are updated as expected.
  
  maps_cities.py data disappears after pan/zoom
  ping @almarklein 
  
  Other WebGL examples work fine. 
  
  Could consider a _very_ short self-contained fix for `0.11`
  
  ```
  examples/glyphs/maps_cities.py:
   data disappears after pan/zoom
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `examples/plotting/file/line_compare.py`
  Content:
  ```
  1 """ Compare WebGL with canvas line.
  2 
  3 """
  4 
  5 import numpy as np
  6 
  7 from bokeh.models import Slider, Dropdown, HBox, VBox, CustomJS
  8 from bokeh.plotting import Figure, show, output_file
  9 
  10 p1 = Figure(title="Canvas", webgl=False)
  11 
  12 p2 = Figure(title="WebGL", webgl=True)
  13 
  14 ys = 10  # yscale, to increase anisotropy
  15 
  16 for p in (p1, p2):
  17 
  18     t = np.linspace(0, 2 * np.pi, 50)
  19     x = np.sin(t) * 10
  20     y = np.cos(t) * 10
  21     l1 = p.line(x, y * ys, color="#2222aa",
  22                 line_width=6, line_cap='butt',
  23                 line_join='round', line_dash=(10, 6, 3, 6, 3, 6))
  24 
  25     t = np.arange(10)
  26     t = np.linspace(0, 4 * np.pi, 150)
  27     x = t - 5
  28     y = (t + 1) * ((t % 2) * 2 - 1)
  29     y = np.sin(t) + 5
  30     l2 = p.line(x, y * ys, color="#22aa22",
  31                 line_width=6, line_cap='butt', line_join='round')
  32 
  33     t = np.arange(10)
  34     x = t - 5
  35     y = 0.3 * (t + 1) * ((t % 2) * 2 - 1) - 6
  36     l3 = p.line(x, y * ys, color="#aa2222",
  37                 line_width=6, line_cap='butt',
  38                 line_join='round', line_dash=(10, 10))
  39     l4 = p.line(y, x * ys, color="#aa2222",
  40                 line_width=6, line_cap='butt',
  41                 line_join='round', line_dash=(10, 10))
  42 
  43 def add_callback(widget, prop):
  44     lines = [l1, l2, l3, l4]
  45     widget.callback = CustomJS(args=dict(widget=widget), code="""
  46         for ( var i = 0; i < %s; i++ ) {
  47             var g = eval( 'line' + i ).get( 'glyph' );
  48             g.set( '%s', widget.get( 'value' ) );
  49             window.g = g;
  50         }
  51         """ % (len(lines), prop))
  52     for i, line in enumerate(lines):
  53         widget.callback.args['line%i' % i] = line
  54 
  55 def make_slider(prop, start, end, value):
  56     slider = Slider(title=prop, start=start, end=end, value=value)
  57     add_callback(slider, prop)
  58     return slider
  59 
  60 def make_dropdown(prop, menu):
  61     dropdown = Dropdown(label=prop, menu=menu)
  62     add_callback(dropdown, prop)
  63     return dropdown
  64 
  65 sliders = [
  66     make_slider('line_width', start=0.2, end=16, value=5),
  67     make_slider('line_dash_offset', start=0, end=100, value=1),
  68     make_dropdown('line_cap', [("butt", "butt"), ("round", "round"), ("square", "square")]),
  69     make_dropdown('line_join', [("miter", "miter"), ("round", "round"), ("bevel", "bevel")]),
  70 ]
  71 
  72 sliders = VBox(*sliders)
  73 
  74 output_file("line_compare.html", title="line_compare.py example")
  75 
  76 show(HBox(sliders, p1, p2))
  77
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/examples/plotting/file/line_compare.py b/examples/plotting/file/line_compare.py
  --- a/examples/plotting/file/line_compare.py
  +++ b/examples/plotting/file/line_compare.py
  @@ -13,6 +13,7 @@
   
   ys = 10  # yscale, to increase anisotropy
   
  +lines = []
   for p in (p1, p2):
   
       t = np.linspace(0, 2 * np.pi, 50)
  @@ -39,9 +40,10 @@
       l4 = p.line(y, x * ys, color="#aa2222",
                   line_width=6, line_cap='butt',
                   line_join='round', line_dash=(10, 10))
  +    
  +    lines.extend([l1, l2, l3, l4])
   
   def add_callback(widget, prop):
  -    lines = [l1, l2, l3, l4]
       widget.callback = CustomJS(args=dict(widget=widget), code="""
           for ( var i = 0; i < %s; i++ ) {
               var g = eval( 'line' + i ).get( 'glyph' );
  
verification_info: {"golden_diff": "diff --git a/examples/plotting/file/line_compare.py b/examples/plotting/file/line_compare.py\n--- a/examples/plotting/file/line_compare.py\n+++ b/examples/plotting/file/line_compare.py\n@@ -13,6 +13,7 @@\n \n ys = 10  # yscale, to increase anisotropy\n \n+lines = []\n for p in (p1, p2):\n \n     t = np.linspace(0, 2 * np.pi, 50)\n@@ -39,9 +40,10 @@\n     l4 = p.line(y, x * ys, color=\"#aa2222\",\n                 line_width=6, line_cap='butt',\n                 line_join='round', line_dash=(10, 10))\n+    \n+    lines.extend([l1, l2, l3, l4])\n \n def add_callback(widget, prop):\n-    lines = [l1, l2, l3, l4]\n     widget.callback = CustomJS(args=dict(widget=widget), code=\"\"\"\n         for ( var i = 0; i < %s; i++ ) {\n             var g = eval( 'line' + i ).get( 'glyph' );\n", "issue": "Bokeh 0.11: Enables webgl causes inconsistent update of scatter points\nThis problem might be related to this issue: https://github.com/bokeh/bokeh/issues/3795\n\nLets consider this minimal example:\n\n``` python\nfrom bokeh.plotting import figure, show, ColumnDataSource\nfrom bokeh.models import Select\nfrom bokeh.models.widgets import RadioGroup\nfrom bokeh.io import vform\nimport numpy as np\n\nN = 100\nx1 = np.random.normal(0.0, 1.0,N)\nx2 = x1 * (1.0 + np.random.normal(0.0, 0.1,N))\ny1 = 5.0*x1 + np.random.normal(0, 0.1, N)\ny2 = 50.0*x2 + np.random.normal(0, 1, N)\n\nsource = ColumnDataSource({'x' : x1, 'y' : y1})\n\nTOOLS = \"box_select,box_zoom,lasso_select,help,reset,pan\"\np = figure(tools=TOOLS, plot_width=400, plot_height=400, webgl=True)\np.circle(x='x', y='y', source=source)\n\nx_radio_group = RadioGroup(labels=[\"x1\", \"x2\"], active=0)\ny_radio_group = RadioGroup(labels=[\"y1\", \"y2\"], active=0)\ncontrols = vform(x_radio_group, y_radio_group)\n\ndef update(attr, old, new):\n    source.data[\"y\"] = y1 if y_radio_group.active==0 else y2\n    source.data[\"x\"] = x1 if x_radio_group.active==0 else x2\n\n    # Updating the source in one step does not change this behavior\n    #data = dict(x=x1 if x_radio_group.active==0 else x2, y=y1 if y_radio_group.active==0 else y2)\n    #source.data = data\n\nsource.on_change('selected', update)\n\ndef select_x(value):\n    update('x-change', None, None)\n\ndef select_y(value):\n    update('y-change', None, None)\n\nx_radio_group.on_click(select_x)\ny_radio_group.on_click(select_y)\n```\n\nYou can reproduce this problem in the following way (using the bokeh server):\n- Fire up the bokeh server (e.g. bokeh server file --show)\n- Select a subset of the data points (using box select or lasso)\n- Switch between y1 and y2 radio buttons\n- Notice that even though the y-axis scaled as expected, the scatter points did not!\n\nNow if you repeat this exercise with webgl=False, you should see that both the y-axis and the scatter points are updated as expected.\n\nmaps_cities.py data disappears after pan/zoom\nping @almarklein \n\nOther WebGL examples work fine. \n\nCould consider a _very_ short self-contained fix for `0.11`\n\n```\nexamples/glyphs/maps_cities.py:\n data disappears after pan/zoom\n```\n\n", "before_files": [{"content": "\"\"\" Compare WebGL with canvas line.\n\n\"\"\"\n\nimport numpy as np\n\nfrom bokeh.models import Slider, Dropdown, HBox, VBox, CustomJS\nfrom bokeh.plotting import Figure, show, output_file\n\np1 = Figure(title=\"Canvas\", webgl=False)\n\np2 = Figure(title=\"WebGL\", webgl=True)\n\nys = 10  # yscale, to increase anisotropy\n\nfor p in (p1, p2):\n\n    t = np.linspace(0, 2 * np.pi, 50)\n    x = np.sin(t) * 10\n    y = np.cos(t) * 10\n    l1 = p.line(x, y * ys, color=\"#2222aa\",\n                line_width=6, line_cap='butt',\n                line_join='round', line_dash=(10, 6, 3, 6, 3, 6))\n\n    t = np.arange(10)\n    t = np.linspace(0, 4 * np.pi, 150)\n    x = t - 5\n    y = (t + 1) * ((t % 2) * 2 - 1)\n    y = np.sin(t) + 5\n    l2 = p.line(x, y * ys, color=\"#22aa22\",\n                line_width=6, line_cap='butt', line_join='round')\n\n    t = np.arange(10)\n    x = t - 5\n    y = 0.3 * (t + 1) * ((t % 2) * 2 - 1) - 6\n    l3 = p.line(x, y * ys, color=\"#aa2222\",\n                line_width=6, line_cap='butt',\n                line_join='round', line_dash=(10, 10))\n    l4 = p.line(y, x * ys, color=\"#aa2222\",\n                line_width=6, line_cap='butt',\n                line_join='round', line_dash=(10, 10))\n\ndef add_callback(widget, prop):\n    lines = [l1, l2, l3, l4]\n    widget.callback = CustomJS(args=dict(widget=widget), code=\"\"\"\n        for ( var i = 0; i < %s; i++ ) {\n            var g = eval( 'line' + i ).get( 'glyph' );\n            g.set( '%s', widget.get( 'value' ) );\n            window.g = g;\n        }\n        \"\"\" % (len(lines), prop))\n    for i, line in enumerate(lines):\n        widget.callback.args['line%i' % i] = line\n\ndef make_slider(prop, start, end, value):\n    slider = Slider(title=prop, start=start, end=end, value=value)\n    add_callback(slider, prop)\n    return slider\n\ndef make_dropdown(prop, menu):\n    dropdown = Dropdown(label=prop, menu=menu)\n    add_callback(dropdown, prop)\n    return dropdown\n\nsliders = [\n    make_slider('line_width', start=0.2, end=16, value=5),\n    make_slider('line_dash_offset', start=0, end=100, value=1),\n    make_dropdown('line_cap', [(\"butt\", \"butt\"), (\"round\", \"round\"), (\"square\", \"square\")]),\n    make_dropdown('line_join', [(\"miter\", \"miter\"), (\"round\", \"round\"), (\"bevel\", \"bevel\")]),\n]\n\nsliders = VBox(*sliders)\n\noutput_file(\"line_compare.html\", title=\"line_compare.py example\")\n\nshow(HBox(sliders, p1, p2))\n", "path": "examples/plotting/file/line_compare.py"}], "after_files": [{"content": "\"\"\" Compare WebGL with canvas line.\n\n\"\"\"\n\nimport numpy as np\n\nfrom bokeh.models import Slider, Dropdown, HBox, VBox, CustomJS\nfrom bokeh.plotting import Figure, show, output_file\n\np1 = Figure(title=\"Canvas\", webgl=False)\n\np2 = Figure(title=\"WebGL\", webgl=True)\n\nys = 10  # yscale, to increase anisotropy\n\nlines = []\nfor p in (p1, p2):\n\n    t = np.linspace(0, 2 * np.pi, 50)\n    x = np.sin(t) * 10\n    y = np.cos(t) * 10\n    l1 = p.line(x, y * ys, color=\"#2222aa\",\n                line_width=6, line_cap='butt',\n                line_join='round', line_dash=(10, 6, 3, 6, 3, 6))\n\n    t = np.arange(10)\n    t = np.linspace(0, 4 * np.pi, 150)\n    x = t - 5\n    y = (t + 1) * ((t % 2) * 2 - 1)\n    y = np.sin(t) + 5\n    l2 = p.line(x, y * ys, color=\"#22aa22\",\n                line_width=6, line_cap='butt', line_join='round')\n\n    t = np.arange(10)\n    x = t - 5\n    y = 0.3 * (t + 1) * ((t % 2) * 2 - 1) - 6\n    l3 = p.line(x, y * ys, color=\"#aa2222\",\n                line_width=6, line_cap='butt',\n                line_join='round', line_dash=(10, 10))\n    l4 = p.line(y, x * ys, color=\"#aa2222\",\n                line_width=6, line_cap='butt',\n                line_join='round', line_dash=(10, 10))\n    \n    lines.extend([l1, l2, l3, l4])\n\ndef add_callback(widget, prop):\n    widget.callback = CustomJS(args=dict(widget=widget), code=\"\"\"\n        for ( var i = 0; i < %s; i++ ) {\n            var g = eval( 'line' + i ).get( 'glyph' );\n            g.set( '%s', widget.get( 'value' ) );\n            window.g = g;\n        }\n        \"\"\" % (len(lines), prop))\n    for i, line in enumerate(lines):\n        widget.callback.args['line%i' % i] = line\n\ndef make_slider(prop, start, end, value):\n    slider = Slider(title=prop, start=start, end=end, value=value)\n    add_callback(slider, prop)\n    return slider\n\ndef make_dropdown(prop, menu):\n    dropdown = Dropdown(label=prop, menu=menu)\n    add_callback(dropdown, prop)\n    return dropdown\n\nsliders = [\n    make_slider('line_width', start=0.2, end=16, value=5),\n    make_slider('line_dash_offset', start=0, end=100, value=1),\n    make_dropdown('line_cap', [(\"butt\", \"butt\"), (\"round\", \"round\"), (\"square\", \"square\")]),\n    make_dropdown('line_join', [(\"miter\", \"miter\"), (\"round\", \"round\"), (\"bevel\", \"bevel\")]),\n]\n\nsliders = VBox(*sliders)\n\noutput_file(\"line_compare.html\", title=\"line_compare.py example\")\n\nshow(HBox(sliders, p1, p2))\n", "path": "examples/plotting/file/line_compare.py"}]}