Bokeh: agregar widgets

El módulo bokeh.models.widgets contiene definiciones de objetos GUI similares a elementos de formulario HTML, como botón, control deslizante, casilla de verificación, botón de radio, etc. Estos controles proporcionan una interfaz interactiva para un gráfico. El procesamiento de invocación, como la modificación de los datos de la trama, el cambio de los parámetros de la trama, etc., se puede realizar mediante funciones personalizadas de JavaScript ejecutadas en los eventos correspondientes.

Bokeh permite definir la funcionalidad de devolución de llamada con dos métodos:

  • Utilizar el CustomJS callback para que la interactividad funcione en documentos HTML independientes.

  • Utilizar Bokeh server y configurar controladores de eventos.

En esta sección, veremos cómo agregar widgets Bokeh y asignar devoluciones de llamada de JavaScript.

Botón

Este widget es un botón en el que se puede hacer clic, generalmente utilizado para invocar un controlador de devolución de llamada definido por el usuario. El constructor toma los siguientes parámetros:

Button(label, icon, callback)

El parámetro de etiqueta es una cadena que se utiliza como título del botón y la devolución de llamada es la función de JavaScript personalizada que se llama cuando se hace clic.

En el siguiente ejemplo, un gráfico y un widget de botón se muestran en el diseño de columna. La gráfica en sí muestra un glifo de línea entre las series de datos xey.

Se ha definido una función de JavaScript personalizada llamada 'devolución de llamada' utilizando CutomJS() function. Recibe una referencia al objeto que desencadenó la devolución de llamada (en este caso el botón) en la variable de formulario cb_obj.

Esta función altera los datos de origen de ColumnDataSource y finalmente emite esta actualización en los datos de origen.

from bokeh.layouts import column
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.plotting import Figure, output_file, show
from bokeh.models.widgets import Button

x = [x*0.05 for x in range(0, 200)]
y = x

source = ColumnDataSource(data=dict(x=x, y=y))
plot = Figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)

callback = CustomJS(args=dict(source=source), code="""
   var data = source.data;
   x = data['x']
   y = data['y']
   for (i = 0; i < x.length; i++) {
      y[i] = Math.pow(x[i], 4)
   }
   source.change.emit();
""")

btn = Button(label="click here", callback=callback, name="1")

layout = column(btn , plot)
show(layout)

Salida (inicial)

Haga clic en el botón en la parte superior de la gráfica y vea la figura de la gráfica actualizada que se ve de la siguiente manera:

Salida (después de hacer clic)

Deslizador

Con la ayuda de un control deslizante, es posible seleccionar un número entre las propiedades iniciales y finales asignadas.

Slider(start, end, step, value)

En el siguiente ejemplo, registramos una función de devolución de llamada en el evento on_change del control deslizante. El valor numérico instantáneo de Slider está disponible para el controlador en forma de cb_obj.value, que se utiliza para modificar los datos de ColumnDatasource. La figura de la trama se actualiza continuamente a medida que desliza la posición.

from bokeh.layouts import column
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.plotting import Figure, output_file, show
from bokeh.models.widgets import Slider

x = [x*0.05 for x in range(0, 200)]
y = x

source = ColumnDataSource(data=dict(x=x, y=y))
plot = Figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)

handler = CustomJS(args=dict(source=source), code="""
   var data = source.data;
   var f = cb_obj.value
   var x = data['x']
   var y = data['y']
   for (var i = 0; i < x.length; i++) {
      y[i] = Math.pow(x[i], f)
   }
   source.change.emit();
""")

slider = Slider(start=0.0, end=5, value=1, step=.25, title="Slider Value")

slider.js_on_change('value', handler)
layout = column(slider, plot)
show(layout)

Salida

RadioGroup

Este widget presenta una colección de botones de alternancia mutuamente excluyentes que muestran botones circulares a la izquierda del título.

RadioGroup(labels, active)

Donde, etiquetas es una lista de títulos y activo es el índice de la opción seleccionada.

Seleccione

Este widget es una lista desplegable simple de elementos de cadena, uno de los cuales se puede seleccionar. La cadena seleccionada aparece en la ventana superior y es el parámetro de valor.

Select(options, value)

La lista de elementos de cadena en el menú desplegable se proporciona en forma de objeto de lista de opciones.

A continuación se muestra un ejemplo combinado de botón de opción y widgets de selección, que proporcionan tres relaciones diferentes entre las series de datos xey. losRadioGroup y Select widgets están registrados con los respectivos controladores a través del método on_change ().

from bokeh.layouts import column
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.plotting import Figure, output_file, show
from bokeh.models.widgets import RadioGroup, Select

x = [x*0.05 for x in range(0, 200)]
y = x

source = ColumnDataSource(data=dict(x=x, y=y))

plot = Figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)

radiohandler = CustomJS(args=dict(source=source), code="""
   var data = source.data;
   console.log('Tap event occurred at x-position: ' + cb_obj.active);
   //plot.title.text=cb_obj.value;
   x = data['x']
   y = data['y']
   if (cb_obj.active==0){
      for (i = 0; i < x.length; i++) {
         y[i] = x[i];
      }
   }
   if (cb_obj.active==1){
      for (i = 0; i < x.length; i++) {
         y[i] = Math.pow(x[i], 2)
      }
   }
   if (cb_obj.active==2){
      for (i = 0; i < x.length; i++) {
         y[i] = Math.pow(x[i], 4)
      }
   }
   source.change.emit();
""")

selecthandler = CustomJS(args=dict(source=source), code="""
   var data = source.data;
   console.log('Tap event occurred at x-position: ' + cb_obj.value);
   //plot.title.text=cb_obj.value;
   x = data['x']
   y = data['y']
   if (cb_obj.value=="line"){
      for (i = 0; i < x.length; i++) {
         y[i] = x[i];
      }
   }
   if (cb_obj.value=="SquareCurve"){
      for (i = 0; i < x.length; i++) {
         y[i] = Math.pow(x[i], 2)
      }
   }
   if (cb_obj.value=="CubeCurve"){
      for (i = 0; i < x.length; i++) {
         y[i] = Math.pow(x[i], 4)
      }
   }
   source.change.emit();
""")

radio = RadioGroup(
   labels=["line", "SqureCurve", "CubeCurve"], active=0)
radio.js_on_change('active', radiohandler)
select = Select(title="Select:", value='line', options=["line", "SquareCurve", "CubeCurve"])
select.js_on_change('value', selecthandler)

layout = column(radio, select, plot)
show(layout)

Salida

Widget de pestaña

Al igual que en un navegador, cada pestaña puede mostrar una página web diferente, el widget de pestaña es un modelo Bokeh que proporciona una vista diferente a cada figura. En el siguiente ejemplo, dos figuras de trazado de curvas de seno y coseno se representan en dos pestañas diferentes:

from bokeh.plotting import figure, output_file, show
from bokeh.models import Panel, Tabs
import numpy as np
import math
x=np.arange(0, math.pi*2, 0.05)
fig1=figure(plot_width=300, plot_height=300)

fig1.line(x, np.sin(x),line_width=2, line_color='navy')

tab1 = Panel(child=fig1, title="sine")
fig2=figure(plot_width=300, plot_height=300)
fig2.line(x,np.cos(x), line_width=2, line_color='orange')
tab2 = Panel(child=fig2, title="cos")

tabs = Tabs(tabs=[ tab1, tab2 ])

show(tabs)

Salida