Эффективное обновление графических изображений в Bokeh для интерактивной визуализации

Я пытаюсь создать гладкую интерактивную визуализацию различных фрагментов многомерного массива с помощью Bokeh. Данные в срезах изменяются в соответствии с взаимодействием пользователя и, следовательно, должны обновляться несколько раз в секунду. Я написал приложение Bokeh с несколькими небольшими графическими изображениями (значения 64×64), чтобы показать содержимое фрагментов, и обратный вызов для обновления ColumnDataSources, когда пользователь взаимодействует с приложением. Все работает так, как ожидалось, но я не могу получить более 2 или 3 кадров в секунду, и я хотел бы получить как минимум 10 кадров.

Вот упрощенный образец моего кода, использующий 16 изображений с периодическим обратным вызовом каждые 100 мс для имитации взаимодействия с пользователем. Используя Bokeh 0.12.3 и Python 2.7 на Mac и Linux, я получаю практически одинаковые тайминги (~ 300 мс на фрейм) на обеих машинах.

from __future__ import print_function, division from random import randint from timeit import default_timer as timer import numpy as np from bokeh.io import curdoc from bokeh.layouts import gridplot from bokeh.models import ColumnDataSource from bokeh.plotting import figure # Set up app and fake data grid_size = 4 data_size = 64 names = ['d{}'.format(i) for i in range(grid_size)] plots = [[None for _ in range(grid_size)] for _ in range(grid_size)] sources = dict() num_images = 16 image_data = [[np.random.rand(data_size, data_size)] for i in range(num_images)] # Create plots and datasources plot_size = 256 for row, row_name in enumerate(names): for col, c_name in enumerate(names): d_name = row_name + "_" + c_name sources[d_name] = ColumnDataSource( {'value': image_data[randint(0, num_images - 1)]}) plots[row][col] = figure(plot_width=plot_size, plot_height=plot_size, x_range=(0, data_size), y_range=(0, data_size)) plots[row][col].image('value', source=sources[d_name], x=0, y=0, dw=data_size, dh=data_size, palette="Viridis256") # Updates def update(): global sources start_update, end_update = [], [] start_time = timer() for row, row_name in enumerate(names): for col, c_name in enumerate(names): d_name = row_name + "_" + c_name new_data = dict() new_data['value'] = image_data[randint(0, num_images - 1)] start_update.append(timer()) # ----- TIMER ON sources[d_name].data = new_data end_update.append(timer()) # ----- TIMER OFF print("\n---- \tTotal update time (secs): {:07.5f}".format(timer() - start_time)) print("+ \tSources update times (secs): {}".format( ["{:07.5f}".format(end_update[i] - s) for i,s in enumerate(start_update)])) # Document grid = gridplot(plots) curdoc().add_root(grid) curdoc().add_periodic_callback(update, 100) 

Я попытался использовать только один источник данных с разными полями для каждого графика, а также обновить данные с помощью метода stream () (хотя это не имеет смысла, поскольку все изображение заменяется), и я не достиг прирост производительности. Кто-нибудь знает, что я могу сделать, чтобы улучшить интерактивность этой визуализации? Я делаю что-то неправильно, чтобы обновлять данные изображения?

Я предполагаю, что узким местом является накладные расходы, вызванные кодированием / декодированием JSON данных изображения, которые могут улучшиться в будущем, поскольку кажется, что разработчики Bokeh знают об этой проблеме и пытаются ее решить. К сожалению, похоже, что исправление не скоро появится.

https://github.com/bokeh/bokeh/issues/2204

https://github.com/bokeh/bokeh/pull/5429

Любые другие предложения?