使用 Bokeh RadioGroup 在 Jupyter 中绘制 Pandas DataFrame 的选定子集
Use Bokeh RadioGroup to plot selected subset of Pandas DataFrame within Jupyter
目标
通过 select 列的特定值绘制 Pandas DataFrame 中的行子集。
最好在 jupyter notebook 中绘制它。
我做了什么
我对 Javascript 知之甚少,所以我设法通过 运行 Bokeh 服务器绘制了 Python 中编写的所有内容。
但是,我无法通过 Javascript 回调在 Jupyter notebook 中实现。我的做法听起来有点愚蠢:按列的值将 DataFrame 拆分为子集并将它们放入字典中,然后我可以 select 来自 RadioGroup 的活动 selection 的子集。
这是我的代码示例:
import pandas as pd
import bokeh
from bokeh.io import output_notebook, show
import bokeh.plotting as bp
import bokeh.models as bm
from bokeh.layouts import column, row
data = {
'Datetime': ['2020-04-09T10:23:38Z', '2020-04-09T22:23:38Z','2020-04-09T23:23:38Z', '2020-01-09T10:23:38Z', '2020-01-09T22:23:38Z', '2020-01-09T23:23:38Z'],
'Month': ['Apr', 'Apr', 'Apr', 'Jan', 'Jan', 'Jan'],
'Values': [1.2, 1.3, 1.5, 1.1, 3, 1.3]
}
df = pd.DataFrame.from_dict(data)
month_list = df['Month'].unique().tolist()
plot_height = 600
plot_width = 1000
col2plot = 'Values'
month_dict = {}
for m in month_list:
subset = df[df['Month'] == m].reset_index(drop=True)
month_dict[m] = subset[['Datetime', col2plot]].to_dict()
p1 = bp.figure(
plot_height=plot_height,
plot_width=plot_width,
title='Values',
toolbar_location=None,
tools="hover",
tooltips=[("DateTime", "@Datetime")]
)
src = bm.ColumnDataSource(df[df['Month'] == 'Jan'].reset_index(drop=True))
p1.line(x='index', y=col2plot, alpha=0.8, source=src)
month_selector = bm.widgets.RadioGroup(labels=month_list, active=1)
jscode = """
var month = cb_obj.labels[cb_obj.active] //selected month
const new_data = source[month]
src.data = new_data
src.change.omit()
"""
callback = bm.CustomJS(args=dict(src=src, source=month_dict), code=jscode)
month_selector.js_on_change('active', callback)
output_notebook()
show(row(p1, month_selector))
代码可以运行,但是到 select 某个月时,情节不会更新。这可能是由于 JS 回调处理不当造成的,有什么解决办法吗?非常感谢您的帮助!
您的代码有问题:
- 在
p.line
中,您正在使用 index
列。但是当您调用 pd.DataFrame.to_dict()
时,该列不存在。可以通过在 .to_dict()
之前添加另一个 .reset_index()
来修复
to_dict()
returns 字典形式的数据,但是 ColumnDataSource
需要列表字典。将调用替换为to_dict('list')
src.change.omit()
- 这里打错字了,应该是emit
。但是由于您要替换整个 data
属性而不是仅仅更改一些数据,您可以简单地完全删除该行
目标
通过 select 列的特定值绘制 Pandas DataFrame 中的行子集。
最好在 jupyter notebook 中绘制它。
我做了什么
我对 Javascript 知之甚少,所以我设法通过 运行 Bokeh 服务器绘制了 Python 中编写的所有内容。
但是,我无法通过 Javascript 回调在 Jupyter notebook 中实现。我的做法听起来有点愚蠢:按列的值将 DataFrame 拆分为子集并将它们放入字典中,然后我可以 select 来自 RadioGroup 的活动 selection 的子集。
这是我的代码示例:
import pandas as pd
import bokeh
from bokeh.io import output_notebook, show
import bokeh.plotting as bp
import bokeh.models as bm
from bokeh.layouts import column, row
data = {
'Datetime': ['2020-04-09T10:23:38Z', '2020-04-09T22:23:38Z','2020-04-09T23:23:38Z', '2020-01-09T10:23:38Z', '2020-01-09T22:23:38Z', '2020-01-09T23:23:38Z'],
'Month': ['Apr', 'Apr', 'Apr', 'Jan', 'Jan', 'Jan'],
'Values': [1.2, 1.3, 1.5, 1.1, 3, 1.3]
}
df = pd.DataFrame.from_dict(data)
month_list = df['Month'].unique().tolist()
plot_height = 600
plot_width = 1000
col2plot = 'Values'
month_dict = {}
for m in month_list:
subset = df[df['Month'] == m].reset_index(drop=True)
month_dict[m] = subset[['Datetime', col2plot]].to_dict()
p1 = bp.figure(
plot_height=plot_height,
plot_width=plot_width,
title='Values',
toolbar_location=None,
tools="hover",
tooltips=[("DateTime", "@Datetime")]
)
src = bm.ColumnDataSource(df[df['Month'] == 'Jan'].reset_index(drop=True))
p1.line(x='index', y=col2plot, alpha=0.8, source=src)
month_selector = bm.widgets.RadioGroup(labels=month_list, active=1)
jscode = """
var month = cb_obj.labels[cb_obj.active] //selected month
const new_data = source[month]
src.data = new_data
src.change.omit()
"""
callback = bm.CustomJS(args=dict(src=src, source=month_dict), code=jscode)
month_selector.js_on_change('active', callback)
output_notebook()
show(row(p1, month_selector))
代码可以运行,但是到 select 某个月时,情节不会更新。这可能是由于 JS 回调处理不当造成的,有什么解决办法吗?非常感谢您的帮助!
您的代码有问题:
- 在
p.line
中,您正在使用index
列。但是当您调用pd.DataFrame.to_dict()
时,该列不存在。可以通过在.to_dict()
之前添加另一个 to_dict()
returns 字典形式的数据,但是ColumnDataSource
需要列表字典。将调用替换为to_dict('list')
src.change.omit()
- 这里打错字了,应该是emit
。但是由于您要替换整个data
属性而不是仅仅更改一些数据,您可以简单地完全删除该行
.reset_index()
来修复