Bokeh - Adicionando Widgets
O módulo bokeh.models.widgets contém definições de objetos GUI semelhantes a elementos de formulário HTML, como botão, controle deslizante, caixa de seleção, botão de rádio, etc. Esses controles fornecem interface interativa para um gráfico. A chamada de processamento, como modificação de dados de plotagem, alteração de parâmetros de plotagem, etc., pode ser realizada por funções JavaScript personalizadas executadas em eventos correspondentes.
Bokeh permite que a funcionalidade de retorno de chamada seja definida com dois métodos -
Use o CustomJS callback para que a interatividade funcione em documentos HTML autônomos.
Usar Bokeh server e configurar manipuladores de eventos.
Nesta seção, veremos como adicionar widgets Bokeh e atribuir retornos de chamada JavaScript.
Botão
Este widget é um botão clicável geralmente usado para invocar um manipulador de retorno de chamada definido pelo usuário. O construtor leva os seguintes parâmetros -
Button(label, icon, callback)
O parâmetro label é uma string usada como legenda do botão e callback é a função JavaScript personalizada a ser chamada quando clicada.
No exemplo a seguir, um gráfico e um widget de botão são exibidos no layout Coluna. O próprio gráfico renderiza um glifo de linha entre as séries de dados xey.
Uma função JavaScript personalizada chamada 'callback' foi definida usando CutomJS() function. Ele recebe referência ao objeto que disparou o callback (neste caso o botão) na variável de formulário cb_obj.
Esta função altera os dados de origem ColumnDataSource e finalmente emite essa atualização nos dados de origem.
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)
Saída (inicial)
Clique no botão na parte superior do gráfico e veja a figura do gráfico atualizado que se parece com o seguinte -
Saída (após clique)
Slider
Com a ajuda de um controle deslizante, é possível selecionar um número entre as propriedades iniciais e finais atribuídas a ele.
Slider(start, end, step, value)
No exemplo a seguir, registramos uma função de retorno de chamada no evento on_change do controle deslizante. O valor numérico instantâneo do Slider está disponível para o manipulador na forma de cb_obj.value que é usado para modificar os dados ColumnDatasource. A figura do gráfico é atualizada continuamente conforme você desliza a posição.
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)
Resultado
RadioGroup
Este widget apresenta uma coleção de botões de alternância mutuamente exclusivos, mostrando botões circulares à esquerda da legenda.
RadioGroup(labels, active)
Onde, rótulos é uma lista de legendas e ativo é o índice da opção selecionada.
Selecione
Este widget é uma lista suspensa simples de itens de string, um dos quais pode ser selecionado. A string selecionada aparece na janela superior e é o parâmetro de valor.
Select(options, value)
A lista de elementos de string na lista suspensa é fornecida na forma de um objeto de lista de opções.
A seguir está um exemplo combinado de botão de opção e widgets de seleção, ambos fornecendo três relacionamentos diferentes entre as séries de dados xey. oRadioGroup e Select widgets são registrados com os respectivos manipuladores por meio do 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)
Resultado
Widget de guia
Assim como em um navegador, cada guia pode mostrar uma página da web diferente, o widget Guia é o modelo Bokeh que fornece uma visualização diferente para cada figura. No exemplo a seguir, duas figuras de gráfico de curvas de seno e cosseno são renderizadas em duas guias 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)