Я использую Bokeh Server с Django, чтобы анимировать некоторые диаграммы, которые показывают, что несколько серий меняются со временем. В настоящее время я пытаюсь автоматизировать слайдер для продвижения временных рядов.
К сожалению, у меня возникли две проблемы (которые, вероятно, связаны). Во-первых, несмотря на то, что анимация начинается (ползунок перемещается, а кнопка «play» меняется на «pause» на кнопке), диаграмма не обновляется. Во-вторых, любая попытка остановить слайдер (нажав на кнопку «пауза») вызывает ошибку:
ValueError: callback already ran or was already removed, cannot be removed again
Ползунок продолжает двигаться.
Django делает запрос к серверу для server_document, передавая 'pk' в качестве аргумента:
views.py
from django.shortcuts import render
from django.http import HttpResponse
from bokeh.embed import server_document
def getchart(request, pk):
key = pk
script = server_document(url="http://localhost:5006/bokeh_server",
arguments={"pk": pk,
},
)
return render(request, 'testserver.html', {'script':script})
Сервер Bokeh получает запрос находит данные, связанные с 'pk', затем строит диаграмму с анимацией.
main.py
from bokeh.io import curdoc
from copy import deepcopy
from bokeh.plotting import figure
from bokeh.embed import components
from bokeh.models import ColumnDataSource, Slider, Button
from bokeh.models.widgets import TableColumn
from bokeh.layouts import column, row
"""
Get arguments from request
"""
args = curdoc().session_context.request.arguments
pk = int(args.get('pk')[0])
"""
get data for graph from file and initialise variables
...
Replaced with example data in data_dict
"""
data_dict={'xdata':[[0, 1, 2, 4, 5, 6, 10, 11, 12], [4, 8, 16, 0, 13, 21, -3, 9, 21]],
'ydata':[[4, 8, 16, 0, 13, 21, -3, 9, 21], [0, 1, 2, 4, 5, 6, 10, 11, 12]]}
no_of_series = len(data_dict.get('xdata'))
length_of_series = len(data_dict.get('xdata')[0])
"""
Initialise ColumnDataSources
"""
graph_source = ColumnDataSource(data=deepcopy(data_dict)) #current data that will be displayed
"""
set graph_source to empty at start
"""
def initialise_graph_data(source):
fullxdata = source.data['xdata']
fullydata = source.data['ydata']
i = 0
while i < len(full_xdata):
source.data['xdata'][i] = fullxdata[i][0:1]
source.data['ydata'][i] = fullydata[i][0:1]
i += 1
initialise_graph_data(graph_source)
"""
format graph
"""
tools="pan, wheel_zoom, reset"
p = figure(tools=tools)
p.multi_line(xs='xdata', ys='ydata', source=graph_source,)
"""
Interactive slider
"""
def animate_update():
tick = slider.value + 1
slider.value = tick
def slider_update(attr, old, new):
tick = slider.value
"""
create display data for each series, starting at 0 and ending at the current tick value
"""
i=0
while i < no_of_series:
graph_source.data['xdata'][i] = data_dict['xdata'][i][0:tick]
graph_source.data['ydata'][i] = data_dict['ydata'][i][0:tick]
i += 1
slider = Slider(start=0, end=length_of_series, value=0, step=1)
slider.on_change('value', slider_update)
def animate():
if button.label == "► Play":
button.label = "❚❚ Pause"
curdoc().add_periodic_callback(animate_update, 200)
else:
button.label = "► Play"
curdoc().remove_periodic_callback(animate_update)
button = Button(label="► Play", width=60)
button.on_click(animate)
layout = row(column(p), button, slider)
curdoc().add_root(layout)
с print(graph_source.data['xdata'][i])
в конце slider_update()
ясно, что исходные данные обновляются, как и ожидалось, но диаграмма не ссылается sh.
Я ожидаю, что проблема вызвана многократным использованием curdoc()
в main .py , или я неправильно использую server_document()
в views.py