python - Jupyter Notebook 中的 Bokeh 图未更新

标签 python jupyter-notebook bokeh python-interactive

我想绘制一些具有多个特征的数据,并希望制作一个交互式二维图,用户可以从特征列表中选择轴,以查看任意两个特征之间的相关性。但是,在我的代码中,绘图不会根据用户输入进行更新。

我正在使用 Jupyter 笔记本,并尝试使用 bokeh 包进行绘图。我想坚持使用 Bokeh 小部件,而不是 iPython 小部件。任何帮助将不胜感激。

这是一些最少的代码

import numpy as np
import pandas as pd
from bokeh.layouts import row, widgetbox
from bokeh.models import CustomJS, Slider, Select
from bokeh.plotting import figure, output_file, show, ColumnDataSource
from bokeh.io import push_notebook, output_notebook, curdoc
from bokeh.client import push_session
output_notebook()

#create sample pandaframe to work with, this will store the actual data
a = np.arange(50).reshape((5,10))
labels = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
val_a = pd.DataFrame(a, columns=labels )

# Here is a dict of some keys that I want to be able to pick from for plotting
axis_map = {
    "A": "A",
    "B": "B",
    "C": "C"
}

#This is to update during the callback
code = ''' var data = val_a;
           var val1 = x_axis.value;
           var val2 = y_axis.value;
           x = data['val1'];
           y = data['val2'];
           source.trigger('change');
           print x
            '''
source = ColumnDataSource(data=dict(x=[], y=[]))
callback = CustomJS(args=dict(source=source), code=code)

#Create two select widgets to pick the features of interest 
x_axis = Select(title="X Axis", options=sorted(axis_map.keys()), value="A", callback = callback)
callback.args["val1"] = x_axis

y_axis = Select(title="Y Axis", options=sorted(axis_map.keys()), value="B", callback = callback)
callback.args["val2"] = y_axis

#plot the figures
plot = figure(plot_width=400, plot_height=400)
plot.circle(x= "x",y="y", source=source, line_width=3, line_alpha=0.6)


#update the plot
def update():
    x_name = axis_map[x_axis.value]
    y_name = axis_map[y_axis.value]

    plot.xaxis.axis_label = x_axis.value
    plot.yaxis.axis_label = y_axis.value
    print x_name
    print val_a[x_name]
    source.data = dict(
        x=val_a[x_name],
        y=val_a[y_name],

    )

controls = [ x_axis, y_axis]
for control in controls:
    control.on_change('value', lambda attr, old, new: update())


update()
push_notebook()

#Display the graph in a jupyter notebook
layout = row(plot, x_axis, y_axis)
show(layout, notebook_handle=True)

最佳答案

我认为为了简化你的代码,你可以只使用 JS 回调或 python 回调,不需要两者都使用。

要更改数据源,您需要将原始数据提供给 JS 回调,然后选择与小部件中所选值相对应的适当值。

你也可以在JS中以相同的方式设置轴标签。不确定这是否正是您想要的实现,但应该会让您更接近。

import numpy as np
import pandas as pd
from bokeh.layouts import row, widgetbox
from bokeh.models import CustomJS, Slider, Select
from bokeh.plotting import figure, output_file, show, ColumnDataSource
from bokeh.io import push_notebook, output_notebook, curdoc
from bokeh.client import push_session
output_notebook()

#create sample pandaframe to work with, this will store the actual data
a = np.arange(50).reshape((5,10))
labels = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
val_a = pd.DataFrame(a, columns=labels )

# Here is a dict of some keys that I want to be able to pick from for plotting
axis_map = {
    "A": "A",
    "B": "B",
    "C": "C"
}

#This is to update during the callback
code = ''' var data = source.data;
           var value1 = val1.value;
           var value2 = val2.value;
           var original_data = original_source.data
           // get data corresponding to selection
           x = original_data[value1];
           y = original_data[value2];
           data['x'] = x;
           data['y'] = y;
           source.trigger('change');
           // set axis labels
           x_axis.axis_label = value1
           y_axis.axis_label = value2
            '''
source = ColumnDataSource(data=dict(x=val_a['A'], y=val_a['B']))
original_source = ColumnDataSource(data=val_a.to_dict(orient='list'))


#plot the figures
plot = figure(plot_width=400, plot_height=400)
plot.circle(x= "x",y="y", source=source, line_width=3, line_alpha=0.6)


callback = CustomJS(args=dict(source=source, original_source = original_source, x_axis=plot.xaxis[0],y_axis=plot.yaxis[0]), code=code)

#Create two select widgets to pick the features of interest 
x_axis = Select(title="X Axis", options=sorted(axis_map.keys()), value="A", callback = callback)
callback.args["val1"] = x_axis

y_axis = Select(title="Y Axis", options=sorted(axis_map.keys()), value="B", callback = callback)
callback.args["val2"] = y_axis

plot.xaxis[0].axis_label = 'A'
plot.yaxis[0].axis_label = 'B'

#Display the graph in a jupyter notebook
layout = row(plot, x_axis, y_axis)
show(layout, notebook_handle=True)

关于python - Jupyter Notebook 中的 Bokeh 图未更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44192285/

相关文章:

anaconda - Graphviz 未在 jupyter 笔记本 python = 3.6 中运行?

Python Bokeh - 混合

python - 从 Flask api 将参数传递给 Bokeh autoload_server

python bokeh 在服务器端或客户端运行

python - 为什么 urllib 不适用于本地网站?

python - Cherrypy 应用程序重定向到 http 而不是 nginx 后面的 https

python - 'str' 对象不能被解释为 python 中的整数

python - 如何在 Windows 10 上安装 Theano for Python 3.5

python - 导入错误 : cannot import name 'ensure_dir_exists'

python - 具有多个 iPyWidgets 下拉菜单的交互式 Covid 绘图