Bokeh以交互方式更改正在绘制的列

时间:2016-06-26 12:16:05

标签: python plot interactive bokeh

我有一个我想要探索的大型数据集。但是我不想创建多个图。我只想要一个单独的绘图,我可以交互式地更改用于x和y轴的列,并且绘图将自动更新。

我正在尝试用Python / Bokeh使用Bokeh将我的脚本提供给浏览器。但是我不清楚如何让情节更新。我看到很多基础数据源发生变化的例子,但我不想这样做,我只想更改正在绘制哪些列。

我已经在下面简要介绍了我想要做的事情。它使用两个“Select”小部件来选择数据源的x和y列。这些回调试图改变'Line'字形所指的列。然而,这似乎不起作用。欢迎任何建议。

import numpy as np

from bokeh.models import ColumnDataSource
from bokeh.plotting import Figure

from bokeh.models.widgets import Select,TextInput
from bokeh.models.glyphs import Line
from bokeh.models.layouts import HBox, VBox
from bokeh.io import curdoc


#==============================================================================
#%% Define some Data
#==============================================================================
N = 200

# Define the data to be used
x = np.linspace(0,4.*np.pi,N)
y = 3*np.cos(2*np.pi*x + np.pi*0.2)
z = 0.5*np.sin(2*np.pi*0.8*x + np.pi*0.4)

source = ColumnDataSource({'x':x,'cos':y,'sin':z})


#==============================================================================
#%% Layout
#==============================================================================


TOOLS = "box_select,lasso_select,help"

# create a new plot 
plot = Figure(tools=TOOLS,  title=None)

# Make a line and connect to data source
glyph = Line(x="x", y="cos", line_color="#F46D43", line_width=6, line_alpha=0.6)
plot.add_glyph(source, glyph)

# Add list boxes for selecting which columns to plot on the x and y axis
yaxis_select = Select(title="Y axis:", value="cos",
                           options=['x','cos','sin'])


xaxis_select = Select(title="X axis:", value="x",
                           options=['x','cos','sin'])


# Text input as a title
text = TextInput(title="title", value='my sine wave plotter')

# Layout widgets next to the plot                     
controls = VBox(text,yaxis_select,xaxis_select)

layout = HBox(controls,plot,width=800)


#==============================================================================
#%% Callbacks
#==============================================================================
# Put callbacks on the list boxes so that when they are changed the columns being
# plotted get changed.

def update_x_axis(attr, old, new):
    # Change the column used for the x axis
    glyph.x = xaxis_select.value


def update_y_axis(attr, old, new):
    # Change the column used for the y axis
    glyph.y = yaxis_select.value



yaxis_select.on_change('value', update_y_axis)
xaxis_select.on_change('value', update_x_axis)



#==============================================================================
#%% Add to document root
#==============================================================================

curdoc().add_root(layout)
curdoc().title = "Plotting app"

3 个答案:

答案 0 :(得分:3)

以下脚本似乎运行正常。它不使用Bokeh服务器,而是使用CustomJS客户端样式。

import numpy as np

from bokeh.models import ColumnDataSource
from bokeh.plotting import Figure

from bokeh.models.widgets import Select,TextInput
from bokeh.models.layouts import HBox, VBox
import bokeh.io 
from bokeh.models import CustomJS

N = 200

# Define the data to be used
x = np.linspace(0,4.*np.pi,N)
y = 3*np.cos(2*np.pi*x + np.pi*0.2)
z = 0.5*np.sin(2*np.pi*0.8*x + np.pi*0.4)

source = ColumnDataSource(data={'x':x,'y':y, 'X': x, 'cos':y,'sin':z})


code="""
        var data = source.get('data');
        var r = data[cb_obj.get('value')];
        var {var} = data[cb_obj.get('value')];
        //window.alert( "{var} " + cb_obj.get('value') + {var}  );
        for (i = 0; i < r.length; i++) {{
            {var}[i] = r[i] ;
            data['{var}'][i] = r[i];
        }}
        source.trigger('change');
    """

callbackx = CustomJS(args=dict(source=source), code=code.format(var="x"))
callbacky = CustomJS(args=dict(source=source), code=code.format(var="y"))

# create a new plot 
plot = Figure(title=None)

# Make a line and connect to data source
plot.line(x="x", y="y", line_color="#F46D43", line_width=6, line_alpha=0.6, source=source)


# Add list boxes for selecting which columns to plot on the x and y axis
yaxis_select = Select(title="Y axis:", value="cos",
                           options=['X','cos','sin'], callback=callbacky)


xaxis_select = Select(title="X axis:", value="x",
                           options=['X','cos','sin'], callback=callbackx)


# Text input as a title
text = TextInput(title="title", value='my sine wave plotter')

# Layout widgets next to the plot                     
controls = VBox(text,yaxis_select,xaxis_select)

layout = HBox(controls,plot,width=800)

bokeh.io.show(layout)

然而,我一直修改它,直到它做了它应该做的事情。而且我不确定为什么CustomJS代码中的部分需要如此复杂。

特别是看起来JS-part中的for循环内部的两条线实际上都是需要的,尽管它们似乎做同样的事情。

因此,在有人能够提出可以解释的事情之前,我不会回答这个问题。

答案 1 :(得分:3)

要编辑字形从中获取坐标的实际源字段,您需要更改this question中的代码。 ImportanceOfBeingErnest的代码修订版产生正确的结果,无需更改原始ColumnDataSource或隐藏Select小部件中的任何键:

import numpy as np

from bokeh.models import ColumnDataSource
from bokeh.plotting import Figure

from bokeh.models.widgets import Select, TextInput
from bokeh.models.layouts import HBox, VBox
import bokeh.io
from bokeh.io import curdoc
from bokeh.models import CustomJS

N = 200

# Define the data to be used
x = np.linspace(0, 4. * np.pi, N)
y = 3 * np.cos(2 * np.pi * x + np.pi * 0.2)
z = 0.5 * np.sin(2 * np.pi * 0.8 * x + np.pi * 0.4)

data = {'x': x, 'cos': y, 'sin': z}
source = ColumnDataSource(data=data)

codex = """
            var column = cb_obj.value;
            line1.glyph.x.field = column;
            source.trigger('change')
        """
codey = """
            var column = cb_obj.value;
            line1.glyph.y.field = column;
            source.trigger('change')
        """

# create a new plot
plot = Figure(title=None)

# Make a line and connect to data source
line1 = plot.line(x="x", y="cos", line_color="#F46D43", line_width=6, line_alpha=0.6, source=source)

callbackx = CustomJS(args=dict(line1=line1, source=source), code=codex)
callbacky = CustomJS(args=dict(line1=line1, source=source), code=codey)

# Add list boxes for selecting which columns to plot on the x and y axis
yaxis_select = Select(title="Y axis:", value="cos",
                      options=data.keys(),
                      callback=callbacky
                      )

xaxis_select = Select(title="X axis:", value="x",
                      options=data.keys(),
                      callback=callbackx
                      )

# Text input as a title
text = TextInput(title="title", value='my sine wave plotter')

# Layout widgets next to the plot
controls = VBox(text, yaxis_select, xaxis_select)

layout = HBox(controls, plot, width=800)

# bokeh.io.show(layout)
curdoc().add_root(layout)
curdoc().title = "Sliders"

为了清楚起见,我将代码字符串分开了,但是ImportanceOfBeingErnest的string.format()使用非常简洁。

不幸的是,我无法获得用于编辑这些特定字段的完全Python解决方案,尽管ImportanceOfBeingErnest的解决方案实际上根本不需要JavaScript(但确实需要更改数据源)

答案 2 :(得分:0)

我无法在Bokeh 2.02上获得以上答案。对答案进行一些修改后,导致以下代码在BOKEH 2.02上有效。

您也可以尝试使用页面底部的“运行代码段”,以查看该示例的实际效果。

import numpy as np

from bokeh.models import ColumnDataSource
from bokeh.plotting import Figure

from bokeh.models.widgets import Select,TextInput
from bokeh.models.layouts import Column, Row
import bokeh.io 
from bokeh.models import CustomJS

N = 200

# Define the data to be used
x = np.linspace(0,4.*np.pi,N)
y = 3*np.cos(2*np.pi*x + np.pi*0.2)
z = 0.5*np.sin(2*np.pi*0.8*x + np.pi*0.4)

source = ColumnDataSource(data={'x':x,'y':y, 'X': x, 'cos':y,'sin':z})


code="""
        var column = cb_obj.value;
        line.glyph.{var}.field = column;
        source.change.emit();
    """

# create a new plot 
plot = Figure(title=None)

# Make a line and connect to data source
line = plot.line(x="x", y="y", line_color="#F46D43", line_width=6, line_alpha=0.6, source=source)

#Make a callbacks
callbackx = CustomJS(args=dict(source=source, line=line), code=code.format(var="x"))
callbacky = CustomJS(args=dict(source=source, line =line), code=code.format(var="y"))


# Add list boxes for selecting which columns to plot on the x and y axis
yaxis_select = Select(title="Y axis:", value="cos",
                           options=['X','cos','sin'])
yaxis_select.js_on_change('value', callbacky)


xaxis_select = Select(title="X axis:", value="x",
                           options=['X','cos','sin'])
xaxis_select.js_on_change('value', callbackx)


# Text input as a title
text = TextInput(title="title", value='my sine wave plotter for Bokeh 2.02')

# Layout widgets next to the plot                     
controls = Row(text,yaxis_select,xaxis_select)

layout = Column(controls,plot,width=800)

bokeh.io.show(layout)

# Generate standlone html documents to put into stackoverflow "RUN SNIPPET" 

#from bokeh.resources import CDN
#from bokeh.embed import file_html

#with open('callbacks_example.html','w') as f:
    #f.write(file_html(layout, CDN))
# Copy and pas the html contents into stackover flow

<!DOCTYPE html>
<html lang="en">

<head>

  <meta charset="utf-8">
  <title>Bokeh Application</title>

  <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.0.1.min.js" integrity="sha384-JpP8FXbgAZLkfur7LiK3j9AGBhHNIvF742meBJrjO2ShJDhCG2I1uVvW+0DUtrmc" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.0.1.min.js" integrity="sha384-xZlADit0Q04ISQEdKg2k3L4W9AwQBAuDs9nJL9fM/WwzL1tEU9VPNezOFX0nLEAz" crossorigin="anonymous"></script>
  <script type="text/javascript">
    Bokeh.set_log_level("info");
  </script>
</head>


<body>
  <div class="bk-root" id="9f731289-378a-4669-8d6f-c89fab0041df" data-root-id="22440"></div>
  <script type="application/json" id="22529">
    {
      "c6047a88-1e40-473b-81b7-34ea9c8699eb": {
        "roots": {
          "references": [{
            "attributes": {},
            "id": "22415",
            "type": "PanTool"
          }, {
            "attributes": {
              "line_alpha": 0.1,
              "line_color": "#F46D43",
              "line_width": 6,
              "x": {
                "field": "x"
              },
              "y": {
                "field": "y"
              }
            },
            "id": "22431",
            "type": "Line"
          }, {
            "attributes": {},
            "id": "22445",
            "type": "BasicTickFormatter"
          }, {
            "attributes": {},
            "id": "22443",
            "type": "BasicTickFormatter"
          }, {
            "attributes": {
              "children": [{
                "id": "22439"
              }, {
                "id": "22397"
              }],
              "width": 800
            },
            "id": "22440",
            "type": "Column"
          }, {
            "attributes": {
              "title": "title",
              "value": "my sine wave plotter for Bokeh 2.02"
            },
            "id": "22438",
            "type": "TextInput"
          }, {
            "attributes": {
              "args": {
                "line": {
                  "id": "22432"
                },
                "source": {
                  "id": "22396"
                }
              },
              "code": "\n        var column = cb_obj.value;\n        line.glyph.x.field = column;\n        source.change.emit();\n    "
            },
            "id": "22434",
            "type": "CustomJS"
          }, {
            "attributes": {
              "children": [{
                "id": "22438"
              }, {
                "id": "22436"
              }, {
                "id": "22437"
              }]
            },
            "id": "22439",
            "type": "Row"
          }, {
            "attributes": {
              "axis": {
                "id": "22411"
              },
              "dimension": 1,
              "ticker": null
            },
            "id": "22414",
            "type": "Grid"
          }, {
            "attributes": {
              "source": {
                "id": "22396"
              }
            },
            "id": "22433",
            "type": "CDSView"
          }, {
            "attributes": {
              "formatter": {
                "id": "22443"
              },
              "ticker": {
                "id": "22412"
              }
            },
            "id": "22411",
            "type": "LinearAxis"
          }, {
            "attributes": {
              "js_property_callbacks": {
                "change:value": [{
                  "id": "22434"
                }]
              },
              "options": ["X", "cos", "sin"],
              "title": "X axis:",
              "value": "x"
            },
            "id": "22437",
            "type": "Select"
          }, {
            "attributes": {
              "args": {
                "line": {
                  "id": "22432"
                },
                "source": {
                  "id": "22396"
                }
              },
              "code": "\n        var column = cb_obj.value;\n        line.glyph.y.field = column;\n        source.change.emit();\n    "
            },
            "id": "22435",
            "type": "CustomJS"
          }, {
            "attributes": {
              "bottom_units": "screen",
              "fill_alpha": 0.5,
              "fill_color": "lightgrey",
              "left_units": "screen",
              "level": "overlay",
              "line_alpha": 1.0,
              "line_color": "black",
              "line_dash": [4, 4],
              "line_width": 2,
              "render_mode": "css",
              "right_units": "screen",
              "top_units": "screen"
            },
            "id": "22421",
            "type": "BoxAnnotation"
          }, {
            "attributes": {},
            "id": "22447",
            "type": "UnionRenderers"
          }, {
            "attributes": {},
            "id": "22418",
            "type": "SaveTool"
          }, {
            "attributes": {
              "active_drag": "auto",
              "active_inspect": "auto",
              "active_multi": null,
              "active_scroll": "auto",
              "active_tap": "auto",
              "tools": [{
                "id": "22415"
              }, {
                "id": "22416"
              }, {
                "id": "22417"
              }, {
                "id": "22418"
              }, {
                "id": "22419"
              }, {
                "id": "22420"
              }]
            },
            "id": "22422",
            "type": "Toolbar"
          }, {
            "attributes": {
              "overlay": {
                "id": "22421"
              }
            },
            "id": "22417",
            "type": "BoxZoomTool"
          }, {
            "attributes": {
              "below": [{
                "id": "22407"
              }],
              "center": [{
                "id": "22410"
              }, {
                "id": "22414"
              }],
              "left": [{
                "id": "22411"
              }],
              "renderers": [{
                "id": "22432"
              }],
              "title": null,
              "toolbar": {
                "id": "22422"
              },
              "x_range": {
                "id": "22399"
              },
              "x_scale": {
                "id": "22403"
              },
              "y_range": {
                "id": "22401"
              },
              "y_scale": {
                "id": "22405"
              }
            },
            "id": "22397",
            "subtype": "Figure",
            "type": "Plot"
          }, {
            "attributes": {},
            "id": "22405",
            "type": "LinearScale"
          }, {
            "attributes": {},
            "id": "22412",
            "type": "BasicTicker"
          }, {
            "attributes": {},
            "id": "22403",
            "type": "LinearScale"
          }, {
            "attributes": {},
            "id": "22416",
            "type": "WheelZoomTool"
          }, {
            "attributes": {},
            "id": "22419",
            "type": "ResetTool"
          }, {
            "attributes": {},
            "id": "22401",
            "type": "DataRange1d"
          }, {
            "attributes": {},
            "id": "22448",
            "type": "Selection"
          }, {
            "attributes": {
              "axis": {
                "id": "22407"
              },
              "ticker": null
            },
            "id": "22410",
            "type": "Grid"
          }, {
            "attributes": {
              "data_source": {
                "id": "22396"
              },
              "glyph": {
                "id": "22430"
              },
              "hover_glyph": null,
              "muted_glyph": null,
              "nonselection_glyph": {
                "id": "22431"
              },
              "selection_glyph": null,
              "view": {
                "id": "22433"
              }
            },
            "id": "22432",
            "type": "GlyphRenderer"
          }, {
            "attributes": {
              "line_alpha": 0.6,
              "line_color": "#F46D43",
              "line_width": 6,
              "x": {
                "field": "x"
              },
              "y": {
                "field": "y"
              }
            },
            "id": "22430",
            "type": "Line"
          }, {
            "attributes": {
              "data": {
                "X": {
                  "__ndarray__": "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",
                  "dtype": "float64",
                  "shape": [200]
                },
                "cos": {
                  "__ndarray__": "fvextJlqA0ARStgyx+n4P1EH8KW/fdw/4EPgkmyM579SSq+yitf8v6uRyPnXtgTArFa+3gLKB8B7X4OS+CoHwLRlk+Fu8gLARBICBpCQ97/AcExo6EvWvx+esi+jkOo/n3DhK04T/j8pRfUSBhkFQOtG4Ds84QdAmxC9d6HzBkD40iR1IHUCQCx22Z30MPY/F0r5/QQU0D9oH149pY3tv4WqRVbpRv+/N4YqPHt1BcC/vR58+/EHwMWIUbIQtgbABKgibNDyAcA6OnVYVMv0v/z6v1mKr8O/UHuAnlFB8D+j8oBhBDkAQCQei2EezAVAw2ChFDz8B0D+Qhn1VnIGQJTt5h6iawFAUCbbNRBg8z90usBNz8asP9ScJ+5nt/G/nzgkqC3KAMAOGV4D2BwGwJR+hz37/wfA+6GmnoYoBsCYFdM3ut8AwBvAsL2K7/G/AJw661g4pT8DxaEWsCjzP/S7rB/JVgFAuW9uPJJnBkCQJKnyN/0HQJ1xSrSz2AVA/hReqT5PAECfzYHkJ3rwPx4OUe1vzMG/atSU7sWU9L8GW++ksN4BwCxZ+8c4rAbA8q7d8/LzB8ATv6Xc84IFwF0Ck0etdP+/rLpH4ZkA7r/AzFTE9UXOPyAEerVG+/U/1NVNW79hAkCkpzcHueoGQDLAx8Qu5AdANIDKWV4nBUBI9QAVVUL+PzBjfL3ABOs/kiamx6Jb1b+e0mYu0Vv3v/hUtrbR3wLAprJWBgIjB8C4rSas780HwLKi7AIMxgTA4JBG0scH/b9j/PqLkwHov6SQ56t/jts/6MtsugW2+D8Cp0eFxVgDQEpwJYEEVQdAVJGtsjuxB0C1N6U9F18EQFs3hdBaxfs/zRD2d+P35D/i9fuS8dzgv+8KiXKGCfq/4piX+HnMA8DIfS7nsoAHwOxPYKEajgfAEJLJ9pvyA8AeFJuDZXv6v4SCvXCD6OG/8e3taRDu4z/yZhxB91X7P2rjmK7POgRAAvhnXwGmB0DRBnf/lWQHQOJE2Jq3gANAeMZqakEq+T+XRRDhj6jdP/AtYmfH+ea/n2fl+v2a/L/dRR66qKMEwPYkasvlxAfAUnPID7k0B8AhFP4NiQkDwLAvlfZJ0ve/31qkhQ14178W1UkPQ//pP4w0dXdC2P0/C334qugGBUBADi7KV90HQC4GvM2Q/gZARv60ozCNAkCn+qtz3HP2P8KQwJQtQdE/ZiVLlrH97L8q6xipbg3/vzbkrJV0ZAXAn05TulDvB8DzeMTpK8IGwJ6n/xXQCwLACJfj7VcP9b/NDdsbPwvGvzjMqBpD9O8/N2MYWhcdAEDjp8IaM7wFQIh07LvL+gdAedhjxZp/BkB0hEN8ioUBQHqESxgdpfM/UCun1lAcsz9/I1LuFHHxv55w94IYrwDAnY+kbQwOBsDkfNGxxf8HwLAZum7vNgbAFkDEQYT6AMDo75MyjjXyv3f9ef8tjJc/kBwmO03j8j/8pzs1kzwBQPqAFVvqWQZALQp4Qj3+B0ACbZ+bPegFQKb3whvjagBA4bVn7g7B8D95xqQTz+C+v6TDUwlmUPS/Ac8tEWHFAcDM+jVPuJ8GwFYdUdgy9gfAiKRLpJqTBcCs3Yf+m63/v/EjxKgIkO6/PgCqTRnryz+tHBdS/Lf1P5rrtftcSQJAjugYW2PfBkDONqyhqOcHQO4fjH0dOQVAShv7LNp8/j8YjU5RqZXrP354x0QcL9S/UL1Aja4Z97+WvGsoY8gCwJxH5jnaGAfADegfkKLSB8Al0Ymy3tgEwIr+5mvTQ/2/LV5Pns6T6L/rtrJkMmPaP1z3qcscdfg/6mlMI1FCA0DKO4pVDUwHQN79d1cmtwdAqQchXvhyBEBc0IGi3AL8P9yOKV9Ji+U/XjpVJBBI4L97IjrR6Mn5v+zNEtoFtwPAZ03vyu54B8CAjilsO5UHwOzTzCOGBwTAnH4p30y6+r/XZx8y7Hziv2p13JEcWuM/0tp1LrYX+z/wyS+lYSYEQLiqwm1ynwdAgFZNAetsB0AV7CcopZYDQILKxj99avk/h0VklhbT3j96dBZH6Wbmv5ZUkVkqXvy/8zpgUEaQBMCOaMHLjb8HwNDwIAZAPgfAXRsFCXQgA8DaZqHZyBP4vw==",
                  "dtype": "float64",
                  "shape": [200]
                },
                "sin": {
                  "__ndarray__": "/1REEw5v3j8wEKrj9P/fP0LD681oXt4/l0KvSCG02T/kEcwBcHjSP0+unSuqyMI/IUzHMZT/g788VxTWpCjFv4w2R18SetO/UGX1Qatt2r9pP2frUL3ev5/42L+/+t+/6jxr30AG3r8YJNdL1RHZvx7iavk2nNG/uO5SJF/IwL+6HIEOdKeaP2uS/gIFHcc/nh2Z9PhK1D8YHohaaQDbP5Ls6lc9A98/1Js5F97s3z83RGIs9KXdP1clIpS8aNg/kLXnKTe70D919cCWDYe9PwpZXaLxo6W/Z11mSyALyb8SjkR9XhbVv7y01pLUi9u/SY6eYcBA379v0qqtU9bfv8nBctOcPd2/IoPn/gS5178wo300W6vPv0OjkqBadbm/2lB9n0rurT8hiKaqcPLKP2UATM4L3NU/AKM7GscP3D/7PWNZyXXfP2BXTaAmt98/aVOeIVfN3D+YqzI13gLXP+XwDhmx180/P6Q68b9ctT8qcPKrQhizv75mwPNx0sy/9ujWScub1r8Cd9omHYzcv+10stxJot+/JUTbY1+P37/aNZmKQVXcv+Pp1Z55Rta/tu8h2u77y7/m2E/zWT6xv+FBRSwyNLc/t4o19aGqzj9XoLztaFXXP83TVP+0AN0/Ld+E2TXG3z9m61zCCF/fP4jQh6B81ds/ceMDVQqE1T/3ql2ClRjKP9I8d0eNNqo/GlLQftZJu78c6itOQD3Qvw6hn2GyCNi/LBnwA29t3b/deZiRg+Hfv0yxO9gvJt+/fyApCytO27+IiXMUxbvUv3qFcSsoLsi/iQpQiErpob/vMq4GFFi/P94jAwzIINE/u0iVBHe12D/aOCm3LdLdP8EZFZ0r9N8/j6yzEOTk3j+yaHB+cb/aP89BEi/g7dM/Xy2G2is9xj+L11c0WC6TP2DXc5TorsG/v59mfar/0b+6Z1b6h1vZv+5jtMXVLt6/oKKO7Cj+379lB6UhN5vev/2ykLB2Kdq/ISZIfZMa07/HQSlcJ0bEv2gxDPY7J2S/w6BqTPuswz9OWTAuq9nSPxUL9Te4+tk/cWbmDU6D3j/TY2TKeP/fP7FCxgY9Sd4/htZ8T2OM2T+qWtJOGELSP0d2vR+jScI/83NyRHBKjL/HOvDRt6XFv7u/M/2OrtO/+g4UkNyS2r/arYWmf8/ev9A6fdsa+N+/wag4/Avv3b/12971YejYv9eXN1upZNG/HRl5EilIwL+LGD2RgcueP1xJSD6VmMc/C2tHLBx+1D8hKZ2+yyPbPwghAeVVE98/o0hgHxHo3z8RaIB4vIzdP8W8iR+fPdg/2R3bsYKC0D8xF/rziIS8P2Ybq124tKe/LShnQgyFyb+zhe5vGkjVv0I98nNerdu/rRoLY75O37+MM6rvX8/fv/j44SVpIt2/n6JoHUmM17/LxGRTwzfPvxucHJ0Dcbi/SnvE6EH9rz8uLaVLl2rLP7Ssnf5SDNY/ZvSWX28v3D9gAJcDqYHfP7sa3/4Nrt8/Qpsm2y6w3D/P5+4IkNTWPynOQ6EJYs0/NsX4Kd1WtD+rYHEgjx60v3ph+aeySM2/kCGXn5DK1r80sE8626ncv60cOPcHrN+/do2ZViSE37+C4MmTLDbcv0hIDLelFta/znMLtVeEy79zqX1wMjewvyVJuksIObg/V+Kxqdwezz9FRVq5n4LXP8Ecs8+AHN0/yovgv8/N3z9sBBdVrlHfPyNkkmeDtNs/vsSoqr1S1T//b9QfL5/JP1ZiUYtDJqg/SjPeie9MvL/NGFDlSnbQv650ol9ONNi/dckrB0GH3b/vNv8z9+bfvz6HIqq5Ft+/9veXgVYr27/96KsGDYnUv/SM83gTs8e/46hvvyqvn78qDljblCzAP4r3V2ewWNE/DnfxYGzf2D+DVWfs/undP9EG/IB3998/2FNeU1bT3j9ds7kWy5raPwk9k3/KudM/3INIOorAxT+FPgzHbBKOP5xzgOFOLsK/yU/vcmE20r9O1KFTy4PZv4znMLefRN6/eJ8RLUz/378hiu2Xlofev+18hlsIA9q/IcibTC7l0r/4/AmcGsjDvy4ykxMgDVo/9nNtgBorxD8ZnsXmIQ/TP6CIfaI+Ido/58+00gqX3j+xJYQYc/7fPw==",
                  "dtype": "float64",
                  "shape": [200]
                },
                "x": {
                  "__ndarray__": "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",
                  "dtype": "float64",
                  "shape": [200]
                },
                "y": {
                  "__ndarray__": "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",
                  "dtype": "float64",
                  "shape": [200]
                }
              },
              "selected": {
                "id": "22448"
              },
              "selection_policy": {
                "id": "22447"
              }
            },
            "id": "22396",
            "type": "ColumnDataSource"
          }, {
            "attributes": {},
            "id": "22399",
            "type": "DataRange1d"
          }, {
            "attributes": {},
            "id": "22408",
            "type": "BasicTicker"
          }, {
            "attributes": {},
            "id": "22420",
            "type": "HelpTool"
          }, {
            "attributes": {
              "js_property_callbacks": {
                "change:value": [{
                  "id": "22435"
                }]
              },
              "options": ["X", "cos", "sin"],
              "title": "Y axis:",
              "value": "cos"
            },
            "id": "22436",
            "type": "Select"
          }, {
            "attributes": {
              "formatter": {
                "id": "22445"
              },
              "ticker": {
                "id": "22408"
              }
            },
            "id": "22407",
            "type": "LinearAxis"
          }],
          "root_ids": ["22440"]
        },
        "title": "Bokeh Application",
        "version": "2.0.1"
      }
    }
  </script>
  <script type="text/javascript">
    (function() {
      var fn = function() {
        Bokeh.safely(function() {
          (function(root) {
            function embed_document(root) {

              var docs_json = document.getElementById('22529').textContent;
              var render_items = [{
                "docid": "c6047a88-1e40-473b-81b7-34ea9c8699eb",
                "root_ids": ["22440"],
                "roots": {
                  "22440": "9f731289-378a-4669-8d6f-c89fab0041df"
                }
              }];
              root.Bokeh.embed.embed_items(docs_json, render_items);

            }
            if (root.Bokeh !== undefined) {
              embed_document(root);
            } else {
              var attempts = 0;
              var timer = setInterval(function(root) {
                if (root.Bokeh !== undefined) {
                  clearInterval(timer);
                  embed_document(root);
                } else {
                  attempts++;
                  if (attempts > 100) {
                    clearInterval(timer);
                    console.log("Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing");
                  }
                }
              }, 10, root)
            }
          })(window);
        });
      };
      if (document.readyState != "loading") fn();
      else document.addEventListener("DOMContentLoaded", fn);
    })();
  </script>

</body>

</html>