目标
在Pandas DataFrame中通过选择一列的特定值来绘制行的子集。
理想的情况是在jupyter笔记本上绘制。
我做了什么
我对Javascript的了解非常少,所以我通过运行Bokeh服务器,用Python编写的所有内容来绘制。
然而,我无法在Jupyter笔记本上用Javascript回调来实现。我的方法听起来有点愚蠢:通过列的值将DataFrame分割成子集,并将它们放入一个dict中,然后我可以通过RadioGroup中的活动选择来选择一个子集。
这是我的代码例子。
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))
代码运行了,但是通过选择某个月份,情节没有更新。这可能是由于JS回调的处理不好,有什么办法可以解决这个问题吗?非常感谢大家的帮助
你的代码的问题。
p.line
,你使用的是 index
列。但当你调用 pd.DataFrame.to_dict()
栏目不存在。可以通过再添加一个 .reset_index()
之前 .to_dict()
to_dict()
以 dict 的形式返回数据,但 ColumnDataSource
需要一个list的dict。将该调用替换为to_dict('list')
src.change.omit()
- 错别字,应该是 emit
. 但由于你要更换整个 data
属性,而不是仅仅改变一些数据,你可以简单地将这一行完全删除。