散景:在回调时,新的情节覆盖在旧情节的顶部

时间:2017-11-16 08:54:28

标签: python bokeh

我试图嵌入我的阴谋。我有选择小部件的x轴和y轴选择。当我改变y轴时,情节会按预期更新(图1);然而,改变x轴给我带来了问题。 在更改x轴选项后,新线图将叠加在旧图形的顶部(图2)。只有当我刷新页面时,图形才会按预期呈现(图3)。如何在不刷新整个页面的情况下刷新绘图?

这是我正在尝试的实例:

import io
import pandas as pd

from bokeh.plotting import figure
from bokeh.layouts import row, column
from bokeh.models import ColumnDataSource, Range1d
from bokeh.models.widgets import Select
from bokeh.client import push_session
from bokeh.document import Document
from bokeh.embed import server_session

document = Document()
session = push_session(document)

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=[], y_range=Range1d(), plot_height=600, plot_width=700, title="")

def update():
    print "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=list(x_y_values.keys()),
        y=list(x_y_values.values())
    )
    p.y_range.start = min(x_y_values.values())-1
    p.y_range.end = max(x_y_values.values())+1
    p.xaxis.axis_label = x_axis.value
    p.yaxis.axis_label = y_axis.value
    p.x_range.factors = list(x_y_values.keys())
    p.line(x="x", y="y", source=source)
    print source.data
    return p

def on_x_change(attr, old, new):
    global x_axis
    x_axis.value = new
    update()


def on_y_change(attr, old, new):
    global y_axis
    y_axis.value = new
    update()


def create_layout():
    print 'CREATE LAYOUT'
    x_axis.on_change('value', on_x_change)
    y_axis.on_change('value', on_y_change)
    controls = column(children=[x_axis, y_axis])
    layout = column(children=[controls, update()])
    return layout


layout = create_layout()

html = u"""
<html>
    <head></head>
    <body>
        %s
    </body>
</html>
""" % server_session(layout, session_id=session.id, relative_urls=False)

with io.open("sample.html", mode='w+', encoding='utf-8') as f:
    f.write(html)

print(__doc__)

document.add_root(layout)

if __name__ == "__main__":
    print("\npress ctrl-C to exit")
    session.loop_until_closed()

附件: First plot

Second plot overlaid over first

Second plot after refreshing the webpage

1 个答案:

答案 0 :(得分:2)

您应该使用source.data.update(dict)更新行的来源,而不是使用p.line()重新绘制行。只需要一个空的源来在开头绘制线而没有数据。

更新图形范围后也更新源

p = figure(x_range=[], y_range=Range1d(), plot_height=600, plot_width=700, title="")
source = ColumnDataSource(data={'x':[],'y':[]})
p.line(x="x", y="y", source=source)

def update():
    print "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.y_range.start = min(x_y_values.values())-1
    p.y_range.end = max(x_y_values.values())+1
    p.xaxis.axis_label = x_axis.value
    p.yaxis.axis_label = y_axis.value
    p.x_range.factors = list(x_y_values.keys())
    source.data.update( dict(
        x=list(x_y_values.keys()),
        y=list(x_y_values.values())
    ))