散景:选择小部件的绘图在更改轴时不会更新散景服务器中的绘图

时间:2017-10-02 14:54:54

标签: python bokeh

编辑:添加了一个最小的工作示例代码来重现该问题。

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。数"情节没有更新。我错过了什么吗?

1 个答案:

答案 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对这里的更新顺序有点敏感:更新因素首先起作用,但首先更新数据似乎没有。