javascript - Bokeh 更改 CallbackJS 中的源数据

标签 javascript python django bokeh

我正在尝试在 Django 应用程序中创建 Bokeh 图,以绘制运动员的游泳事件图。我正在绘制持续时间(游泳时间)与日期(游泳比赛日期)。这个想法是拥有一个图并能够使用 SelectBox 小部件来选择在图表上显示哪个事件。问题是,当我更改 CallbackJS 函数中的数据源时,图表不会更新,而是变为空白。

数据来自表单的Event对象

class Event(models.Model):
    swimmer = models.ForeignKey(Swimmer, on_delete=models.SET_NULL, null=True, blank=True)
    team = models.ForeignKey(Team, on_delete=models.CASCADE, null=True, blank=True)
    name = models.CharField(max_length=50, null=True, blank=True)
    gender = models.CharField(max_length=1, choices=GENDER_CHOICE, null=True, blank=True)
    event = models.CharField(max_length=10, choices=EVENT_CHOICE)
    time = models.DurationField()
    place = models.IntegerField(null=True, blank=True)
    date = models.DateField(null=True)

首先,我迭代每个事件(当前为 17 个)并创建日期 (datetime.date) 和时间 (datetime.timedelta) 字段的列表。未修改的字段分别用于 x 和 y,并对值进行轻微编辑(主要是类型转换为字符串)以用于悬停工具。如果特定事件没有数据,data_source{} 条目将设置为 None

示例数据:

data_source = {
    'x_50_free': [date(2017,9,7), date(2017,9,8)]
    'y_50_free': [timedelta(seconds=22.96), timedelta(seconds=22.32)]
    'date_50_free': ['9/7/2017', '9/8/2017']
    'time_50_free': ['00:22.96', '00:22.32']
    'x_100_free': [date(2017,9,7)]
    'y_100_free': [timedelta(seconds=49.86)]
    'date_100_free': ['9/7/2017']
    'time_100_free': ['00:49.86']
}

然后,我绘制一条初始线,以便在页面加载时显示一条线。

source = ColumnDataSource(data=dict(
    x=data_source['x_'+first_event],
    y=data_source['y_'+first_event],
    date=data_source['date_'+first_event],
    time=data_source['time_'+first_event]
))
plot.line('x', 'y', source=source)

我在回调函数中更新源数据

callback = CustomJS(args=dict(source=source), code="""
    data = %s;
    f = cb_obj.value;

    if (f == "50 Freestyle") {
        source.data['x'] = data.x_50_free;
        source.data['y'] = data.y_50_free;
        source.data['date'] = data.date_50_free;
        source.data['time'] = data.time_50_free;
    } else if (f == "100 Freestyle") {
        source.data['x'] = data.x_100_free;
        source.data['y'] = data.y_100_free;
        source.data['date'] = data.date_100_free;
        source.data['time'] = data.time_100_free;
    }

    ...

    } else if (f == "400 IM") {
        source.data['x'] = data.x_400_im;
        source.data['y'] = data.y_400_im;
        source.data['date'] = data.date_400_im;
        source.data['time'] = data.time_400_im;
    }

    source.change.emit();
""" % json.dumps(data_source, cls=DatetimeEncoder)) # encoder to handle datetimes for x-axis

据我了解,source.change.emit()用于更新ColumnDataSource。这似乎有效,因为我能够将 source.data[] 记录到控制台并看到它根据 Select 小部件选项进行更新,但绘图本身不会更新它只是一片空白。我如何更新绘图以反射(reflect)源数据的变化?

最佳答案

您的示例既不简单也不完整。一个完整的例子可以立即运行。最低限度的遗漏了与您的问题无关的方面。因此,我不太确定我是否理解了所有内容,但我尝试去适应它。以下是一些可以帮助您入门的代码:

from bokeh.io import show, output_file, output_notebook
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.layouts import column, widgetbox
from bokeh.models import CustomJS, Select

output_file("swim_plot.html")

first_event = "_50_free"
second_event = "_100_free"

data_source = {
    'x': [date(2017,9,3), date(2017,9,4)],
    'y': [0, 0],
    'x_50_free': [date(2017,9,7), date(2017,9,8)],
    'y_50_free': [22.23, 24.34],
    'x_100_free': [date(2017,9,12), date(2017,9,14)],
    'y_100_free': [23.22, 25,12]
}    
source = ColumnDataSource(data=data_source)

callback = CustomJS(args=dict(source=source), code="""
    data = source.data;
    f = cb_obj.value;
    if (f == "_50_free") {
        data['x'] = data.x_50_free;
        data['y'] = data.y_50_free;
    } else if (f == "_100_free") {
        data['x'] = data.x_100_free;
        data['y'] = data.y_100_free;
    }
    source.change.emit();
""")

select = Select(title="Option:", value="default", options=["default",
                first_event, second_event])
select.js_on_change('value', callback)   

plot = figure(plot_width=400, plot_height=400, x_axis_type='datetime')
plot.line('x', 'y', source=source)    
show(column(widgetbox(select),plot))

我在您的代码中发现的主要问题是 ColumnDataSource 的定义。当您将所有数据添加到 data_dict 时,您只将其中的一部分添加到源中。因此,尝试访问 JS 回调中丢失的数据将会失败。

关于javascript - Bokeh 更改 CallbackJS 中的源数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45987419/

相关文章:

javascript - 根据键值从对象数组中提取所有值

python - SQL 零而不是空

python - 为什么我不应该将 django key 存储在 settings.py 中

django - 使用 MySQL <> WebSocket 实时更新 Django 应用程序

javascript - 电子邮件正则表达式不验证句号之后的部分

php - 如何通过 PHP 将 javascript 生成的数据从客户端发送到服务器

javascript - Fancybox 不工作

python - 如何将 for 循环的结果分配给 Python 中的变量

python - Pandas 数据透视表 - 新结果表中不同值的不同前缀?

python - 导入错误 : No module named 'config.settings' ; 'config' is not a package