Actualizaciones eficientes de gráficos de imagen en Bokeh para visualización interactiva

Estoy tratando de crear una visualización interactiva sin problemas de diferentes segmentos de una matriz muldimensional utilizando Bokeh. Los datos en los segmentos cambian según la interacción del usuario y, por lo tanto, deben actualizarse varias veces por segundo. He escrito una aplicación de Bokeh con varios gráficos de imágenes pequeñas (valores de 64×64) para mostrar el contenido de los cortes y una callback para actualizar ColumnDataSources cuando el usuario interactúa con la aplicación. Todo funciona como se esperaba, pero no puedo obtener más de 2 o 3 cuadros por segundo y me gustaría obtener al menos 10 cuadros.

Aquí hay una muestra simplificada de mi código que usa 16 imágenes con una callback periódica cada 100 ms para simular la interacción del usuario. Al usar Bokeh 0.12.3 y Python 2.7 en Mac y Linux, obtengo casi exactamente los mismos tiempos (~ 300 ms por fotogtwig) en ambas máquinas.

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) 

He intentado usar solo una fuente de datos con diferentes campos para cada gráfico, y también actualizar los datos con el método stream () (aunque no tiene sentido porque se está reemplazando la imagen completa) y no he logrado ninguno ganancia de rendimiento. ¿Alguien sabe qué podría hacer para mejorar la interactividad de esta visualización? ¿Estoy haciendo algo mal para actualizar los datos de la imagen?

Mi conjetura es que el cuello de botella es la sobrecarga causada por la encoding / deencoding JSON de los datos de la imagen, que podría mejorar en el futuro, ya que parece que los desarrolladores de Bokeh están conscientes de este problema y están tratando de resolverlo. Lamentablemente, no parece que la solución venga pronto.

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

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

¿Cualquier otra sugerencia?

Como han mencionado otros, se ha implementado un protocolo de matriz binaria eficiente. Así que la respuesta es actualizar a versiones recientes.

Para completar, aquí hay una comparación de resultados.

Con 0.12.3 (la versión de la publicación original – asegúrese de usar tornado <4.5):

—- Tiempo total de actualización (segundos): 0.14389 + Tiempos de actualización de las fonts (segundos): [‘0.00943’, ‘0.00962’, ‘0.01100’, ‘0.00908’, ‘0.00004’, ‘0.00975’, ‘0.00984’, ‘ 0.00997 ‘,’ 0.00946 ‘,’ 0.00926 ‘,’ 0.00912 ‘,’ 0.00898 ‘,’ 0.00900 ‘,’ 0.00908 ‘,’ 0.00999 ‘,’ 0.01014 ‘] ^ C

Con 0.12.13 (la versión más reciente a partir de este tiempo):

—- Tiempo total de actualización (segundos): 0.01999 + Tiempos de actualización de las fonts (segundos): [‘0.00157’, ‘0.00231’, ‘0.00131’, ‘0.00143’, ‘0.00114’, ‘0.00123’, ‘0.00109’, ‘ 0.00118 ‘,’ 0.00116 ‘,’ 0.00102 ‘,’ 0.00113 ‘,’ 0.00118 ‘,’ 0.00099 ‘,’ 0.00099 ‘,’ 0.00104 ‘,’ 0.00104 ‘]

Es probable que haya una mejora marginal aún mayor si todas las imágenes se almacenan en columnas diferentes (longitud 1) de una única ColumnDataSource y se actualizan a la vez, en lugar de iterar sobre varias fonts de datos diferentes.