Gráficas dinámicas con Bokeh

Estándar

En esta última entrada sobre librerías de visualización gráfica en Python, revisaremos Bokeh, una librería orientada a la creación de gráficas interactivas basadas en HTML/JS. Estas gráficas pueden usarse en una aplicación o página web para mostrar resultados.

Bokeh está incluido en algunas distribuciones, y también puede instalarse usando pip. A diferencia de las librerías que hemos visto con anterioridad, Bokeh no está indicado para su uso en la fase de estudio de los datos, sino para la diseminación final de los resultados, o como parte de aplicaciones basadas en datos (paneles de control, visores de bases de datos, etc).

En esta entrada, crearemos una gráfica interactiva muy simple, recurriendo nuevamente al ejemplo de la función seno utilizada en la entrada de Matplotlib. A continuación, utilizaremos el servidor incluido en Bokeh para crear una gráfica dinámica.

In [1]:
import bokeh.plotting as bp
from bokeh.models import CustomJS, Slider
from bokeh.io import output_notebook, vplot
import numpy as np


x = np.arange(0,2*np.pi,0.01)
y = np.sin(x)

Creamos una figura con un título y etiquetas para los ejes:

In [2]:
fig = bp.figure(title='sin(x) function', x_axis_label='x', y_axis_label='sin(x)')

El siguiente paso es crear la gráfica de línea en la figura:

In [3]:
figline = fig.line(x, y, line_width=2)

Finalmente, guardamos el resultado en un archivo HTML. Con esto ya tenemos una gráfica interactiva.

In [4]:
bp.curdoc().add_root(vplot(fig))
bp.save(fig,'out.html')

Podemos previsualizar el resultado en IPython Notebook:

In [5]:
output_notebook()
bp.show(fig)


BokehJS successfully loaded.

Out[5]:
<bokeh.io._CommsHandle at 0x220e98d86a0>

Se puede interactuar con esta gráfica en esta misma entrada de blog. La interacción es algo limitada, y puede ser insuficiente en algunos casos. Supongamos que queremos cambiar la frecuencia de la función seno. Podemos hacer esto añadiendo un componente Slider:

In [6]:
callback = CustomJS(args=dict(source=figline.data_source), code="""
        var data = source.get('data');
        var f = cb_obj.get('value')
        x = data['x']
        y = data['y']
        for (i = 0; i < x.length; i++) {
            y[i] = Math.sin(f*x[i])
        }
        source.trigger('change');
    """)

slider = Slider(start=0.1, end=4, value=1, step=.1, title="Frequency", callback=callback)

layout = vplot(slider, fig)

bp.show(layout)

Out[6]:
<bokeh.io._CommsHandle at 0x220e98f52e8>

Supongamos que tenemos un origen de datos que cambia con el tiempo, o que depende de un procesado pesado a partir de los datos insertados por el usuario. Hay formas de hacer esto usando el callback JS (o Python usando la función CustomJS.from_py_func()) para actualizar el gráfico. Pero Bokeh además ofrece funciones tanto del lado de servidor como del cliente para este tipo de casos. Debemos crear para ello un script en Python que cree una vista (la figura y el componente de entrada) y una función callback que actualice la vista. Este script se utiliza como entrada del servidor de Bokeh, que debe estar en ejecución mientras se quiera acceder al gráfico. Crearemos la misma gráfica de la función seno que muestra los cambios al variar la frecuencia. Debemos crear un archivo con los siguientes contenidos:

# sineserver.py

# Importaciones
import bokeh.plotting as bp
from bokeh.models import Slider
from bokeh.io import vplot
import numpy as np

# Datos originales
x = np.arange(0,2*np.pi,0.01)
y = np.sin(x)

# Creamos la figura
fig = bp.figure(title='sin(x) function', x_axis_label='x', y_axis_label='sin(x)')
figline = fig.line(x, y, line_width=2)

# Funcion callback
def update_sin(attr, old, new):
    f = int(new)
    x = np.arange(0,2*np.pi,0.01)
    y = np.sin(f*x)
    figline.data_source.data["y"] = y

# Añadimos el control     
slider = Slider(start=1, end=10, title='Freq')
slider.on_change('value', update_sin)

# Creamos la vista
bp.curdoc().add_root(vplot(slider, fig))

Para ejecutar este código, debemos abrir una terminal y ejecutar bokeh serve --show sineserver.py. A continuación, abrimos un navegador y vamos a http://localhost:5008/sineserver.

Bokeh es una gran plataforma para mostrar gráficos en una página o aplicación web; especialmente para aplicaciones dinámicas basadas en datos. Como librería, no tiene el mismo grado de desarrollo que Matplotlib y no hay tanta documentación. Está bajo desarrollo, por lo que ocasionalmente puede dar fallos. Su uso frecuente no es muy práctico, pero para la creación de gráficos interactivos es con diferencia la mejor opción.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *