编辑:添加了一个最小的工作示例代码来重现该问题。
df有像trip,driverName,carRegNo,totalDistanceTravelled,totalTimeTaken等的列。我想有一些情节'司机与距离旅行','司机与时间拍摄'在改变x和/或y轴时。同样适用于“汽车注册号”'对比距离和时间。
import pandas as pd
from bokeh.plotting import figure
from bokeh.layouts import layout, widgetbox
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Select
from bokeh.io import curdoc
trip_data = [{"trip": '1', "totalDistanceTravelled": "4.66", "totalTimeTaken": "765083","time": "1504189219256", "carRegNo": "ABC123", "driverName": "Anne"},
{"trip": '2', "totalDistanceTravelled": "14.63", "totalTimeTaken": "1282369","time": "1504189219256", "carRegNo": "DEF345", "driverName": "Harry"},
{"trip": '3', "totalDistanceTravelled": "3.66", "totalTimeTaken": "602713","time": "1504189219256", "carRegNo": "XYZ890", "driverName": "Ron"},
{"trip": '4', "totalDistanceTravelled": "7.11", "totalTimeTaken": "2234282","time": "1504189219256", "carRegNo": "ABC123", "driverName": "Anne"},
{"trip": '5', "totalDistanceTravelled": "14.14", "totalTimeTaken": "1282369","time": "1504189219256", "carRegNo": "DEF345", "driverName": "Harry"},
{"trip": '6', "totalDistanceTravelled": "4.33", "totalTimeTaken": "748446","time": "1504189219256", "carRegNo": "DEF345", "driverName": "Harry"},
{"trip": '7', "totalDistanceTravelled": "10.66", "totalTimeTaken": "960362","time": "1504189219256", "carRegNo": "XYZ890", "driverName": "Ron"}]
df = pd.DataFrame(trip_data)
drivers = df['driverName'].str.strip()
vehicles = df['carRegNo'].str.strip()
time_stamp = df['time'].astype(float)
total_distance_travelled = df['totalDistanceTravelled'].astype(float)
df['totalTimeTaken'] = df['totalTimeTaken'].astype(float)
df['totalTimeTaken'] /= 1000 * 3600
# Create Input controls
x_axis = Select(title="X Axis", options=sorted(["Drivers", "Vehicle Reg. Number"]), value="Drivers")
y_axis = Select(title="Y Axis", options=sorted(["Distance Travelled (kms)", "Time Taken (hours)"]), value="Time Taken (hours)")
source = ColumnDataSource(data=dict(x=[], y=[]))
def update():
col_key_values = {
"Time Taken (hours)": 'totalTimeTaken',
"Distance Travelled (kms)": 'totalDistanceTravelled'
}
x_map = {
"Drivers": drivers,
"Vehicle Reg. Number": vehicles
}
x_name = x_map[x_axis.value]
x_y_values = {}
for x in x_name.unique():
x_y_values[x] = round(df.loc[x_name == x, col_key_values[y_axis.value]].astype(float).sum(), 2)
source.data = dict(
x=x_y_values.keys(),
y=x_y_values.values()
)
print source.data
update() # initial load of the data
p = figure(x_range=source.data['x'], plot_height=600, plot_width=700, title="", toolbar_location=None)
p.xaxis.axis_label = x_axis.value
p.yaxis.axis_label = y_axis.value
p.line(x="x", y="y", source=source)
controls = [x_axis, y_axis]
for control in controls:
print 'control: ', control.value
control.on_change('value', lambda attr, old, new: update())
sizing_mode = 'fixed'
inputs = widgetbox(*controls, sizing_mode=sizing_mode)
l = layout(children=[[inputs, p]],sizing_mode='fixed')
curdoc().add_root(l)
curdoc().title = "Travel Data"
此代码使用默认设置(即,Drivers vs Time Taken)渲染绘图,但将x轴更改为" Vehicle Reg。数"情节没有更新。我错过了什么吗?
答案 0 :(得分:1)
我没有注意到你正在使用X轴的分类范围。分类范围由列出的因素定义,并且仅由那些因素定义。因此,如果要更新数据以使用不同因子集中的坐标,则还需要更新范围。否则,您对上面代码的情况是,您尝试将数据值绘制到不存在的x坐标,只要范围和图知道即可。
以下是我认为按照您的意图行事的脚本的修改版本(注意,我使用py3,因此它也已更新):
import pandas as pd
from bokeh.plotting import figure
from bokeh.layouts import layout, widgetbox
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Select
from bokeh.io import curdoc
trip_data = [{"trip": '1', "totalDistanceTravelled": "4.66", "totalTimeTaken": "765083","time": "1504189219256", "carRegNo": "ABC123", "driverName": "Anne"},
{"trip": '2', "totalDistanceTravelled": "14.63", "totalTimeTaken": "1282369","time": "1504189219256", "carRegNo": "DEF345", "driverName": "Harry"},
{"trip": '3', "totalDistanceTravelled": "3.66", "totalTimeTaken": "602713","time": "1504189219256", "carRegNo": "XYZ890", "driverName": "Ron"},
{"trip": '4', "totalDistanceTravelled": "7.11", "totalTimeTaken": "2234282","time": "1504189219256", "carRegNo": "ABC123", "driverName": "Anne"},
{"trip": '5', "totalDistanceTravelled": "14.14", "totalTimeTaken": "1282369","time": "1504189219256", "carRegNo": "DEF345", "driverName": "Harry"},
{"trip": '6', "totalDistanceTravelled": "4.33", "totalTimeTaken": "748446","time": "1504189219256", "carRegNo": "DEF345", "driverName": "Harry"},
{"trip": '7', "totalDistanceTravelled": "10.66", "totalTimeTaken": "960362","time": "1504189219256", "carRegNo": "XYZ890", "driverName": "Ron"}]
df = pd.DataFrame(trip_data)
drivers = df['driverName'].str.strip()
vehicles = df['carRegNo'].str.strip()
time_stamp = df['time'].astype(float)
total_distance_travelled = df['totalDistanceTravelled'].astype(float)
df['totalTimeTaken'] = df['totalTimeTaken'].astype(float)
df['totalTimeTaken'] /= 1000 * 3600
# Create Input controls
x_axis = Select(title="X Axis", options=sorted(["Drivers", "Vehicle Reg. Number"]), value="Drivers")
y_axis = Select(title="Y Axis", options=sorted(["Distance Travelled (kms)", "Time Taken (hours)"]), value="Time Taken (hours)")
source = ColumnDataSource(data=dict(x=[], y=[]))
p = figure(x_range=source.data['x'], plot_height=600, plot_width=700, title="", toolbar_location=None)
def update():
col_key_values = {
"Time Taken (hours)": 'totalTimeTaken',
"Distance Travelled (kms)": 'totalDistanceTravelled'
}
x_map = {
"Drivers": drivers,
"Vehicle Reg. Number": vehicles
}
x_name = x_map[x_axis.value]
x_y_values = {}
for x in x_name.unique():
x_y_values[x] = round(df.loc[x_name == x, col_key_values[y_axis.value]].astype(float).sum(), 2)
p.x_range.factors = list(x_y_values.keys())
source.data = dict(
x=list(x_y_values.keys()),
y=list(x_y_values.values())
)
print(source.data)
print(p.x_range.factors)
update() # initial load of the data
p.xaxis.axis_label = x_axis.value
p.yaxis.axis_label = y_axis.value
p.line(x="x", y="y", source=source)
controls = [x_axis, y_axis]
for control in controls:
print('control: ', control.value)
control.on_change('value', lambda attr, old, new: update())
sizing_mode = 'fixed'
inputs = widgetbox(*controls, sizing_mode=sizing_mode)
l = layout(children=[[inputs, p]],sizing_mode='fixed')
curdoc().add_root(l)
curdoc().title = "Travel Data"
这是添加的重要内容:
p.x_range.factors = list(x_y_values.keys())
告诉x轴范围新的有效因子名称是什么,因此当您更改为使用这些新因子的数据时,它知道它们应该去哪里。我应该补充一点,我认为Bokeh对这里的更新顺序有点敏感:更新因素首先起作用,但首先更新数据似乎没有。