Histogtwig con filtro deslizante.

Me gustaría crear un histogtwig con un gráfico de densidad combinado en bokeh con un filtro deslizante. Atm, tengo los bloques para crear un histogtwig de bokeh con un gráfico de densidad de otro hilo. No sé cómo crear la función de callback para actualizar los datos y redirigir el gráfico.

from bokeh.io import output_file, show from bokeh.plotting import figure from bokeh.sampledata.autompg import autompg as df from numpy import histogram, linspace from scipy.stats.kde import gaussian_kde pdf = gaussian_kde(df.hp) x = linspace(0,250,50) p = figure(plot_height=300) p.line(x, pdf(x)) # plot actual hist for comparison hist, edges = histogram(df.hp, density=True, bins=20) p.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:], alpha=0.4) show(p) 

Hay dos formas de implementar devoluciones de llamada en Bokeh:

  • con código JS . En ese caso, la gráfica sigue siendo un objeto independiente, la restricción es que debe realizar cualquier manipulación de datos dentro de Javascript (hay una pequeña advertencia en esa statement, pero no es relevante aquí: scipy no puede llamarse desde tal callback)
  • al tener la callback ejecutada en el servidor Bokeh , en cuyo caso tiene todo el arsenal de python disponible para usted. El costo es que hay un poco más para trazar y distribuir el gráfico que en el primer caso (pero no es difícil, vea el ejemplo).

Teniendo en cuenta que debe volver a montar el kde cada vez que cambie la condición del filtro, la segunda forma es la única opción (a menos que desee hacerlo en javascript …).

Así es como lo harías (ejemplo con un filtro en cyl ):

 from bokeh.application import Application from bokeh.application.handlers import FunctionHandler from bokeh.io import output_notebook, show from bokeh.layouts import column from bokeh.plotting import figure from bokeh.models import ColumnDataSource, Select from bokeh.sampledata.autompg import autompg as df from numpy import histogram, linspace from scipy.stats.kde import gaussian_kde output_notebook() def modify_doc(doc): x = linspace(0,250,50) source_hist = ColumnDataSource({'top': [], 'left': [], 'right': []}) source_kde = ColumnDataSource({'x': [], 'y': []}) p = figure(plot_height=300) p.line(x='x', y='y', source=source_kde) p.quad(top='top', bottom=0, left='left', right='right', alpha=0.4, source=source_hist) def update(attr, old, new): if new == 'All': filtered_df = df else: condition = df.cyl == int(new) filtered_df = df[condition] hist, edges = histogram(filtered_df.hp, density=True, bins=20) pdf = gaussian_kde(filtered_df.hp) source_hist.data = {'top': hist, 'left': edges[:-1], 'right': edges[1:]} source_kde.data = {'x': x, 'y': pdf(x)} update(None, None, 'All') select = Select(title='# cyl', value='All', options=['All'] + [str(i) for i in df.cyl.unique()]) select.on_change('value', update) doc.add_root(column(select, p)) # To run it in the notebook: plot = Application(FunctionHandler(modify_doc)) show(plot) # Or to run it stand-alone with `bokeh serve --show myapp.py` # in which case you need to remove the `output_notebook()` call # from bokeh.io import curdoc # modify_doc(curdoc()) 

Algunas notas:

  • esto está hecho para ejecutarse en una notebook jupyter (vea output_notebook() y las dos últimas líneas sin comentarios).
  • para ejecutarlo afuera, comente las líneas del cuaderno (ver arriba) y elimine el comentario de las dos últimas líneas. Luego puedes ejecutarlo desde la línea de comandos.
  • Select solo manejará los valores de str , por lo que debe convertir (al crearlo) y fuera (al usar los valores: old y new )
  • para varios filtros, debe acceder al estado de cada Select al mismo tiempo. Para ello, cree una instancia de Select s antes de definir la función de update (¡pero sin ninguna callback, aún!) Y mantenga una referencia a ellos, acceda a su valor con your_ref.value valor y construya su condición con eso. Después de la definición de update , puede adjuntar la callback en cada Select .

Finalmente, un ejemplo con múltiples selecciones:

 def modify_doc(doc): x = linspace(0,250,50) source_hist = ColumnDataSource({'top': [], 'left': [], 'right': []}) source_kde = ColumnDataSource({'x': [], 'y': []}) p = figure(plot_height=300) p.line(x='x', y='y', source=source_kde) p.quad(top='top', bottom=0, left='left', right='right', alpha=0.4, source=source_hist) select_cyl = Select(title='# cyl', value='All', options=['All'] + [str(i) for i in df.cyl.unique()]) select_ori = Select(title='origin', value='All', options=['All'] + [str(i) for i in df.origin.unique()]) def update(attr, old, new): all = pd.Series(True, index=df.index) if select_cyl.value == 'All': cond_cyl = all else: cond_cyl = df.cyl == int(select_cyl.value) if select_ori.value == 'All': cond_ori = all else: cond_ori = df.origin == int(select_ori.value) filtered_df = df[cond_cyl & cond_ori] hist, edges = histogram(filtered_df.hp, density=True, bins=20) pdf = gaussian_kde(filtered_df.hp) source_hist.data = {'top': hist, 'left': edges[:-1], 'right': edges[1:]} source_kde.data = {'x': x, 'y': pdf(x)} update(None, None, 'All') select_ori.on_change('value', update) select_cyl.on_change('value', update) doc.add_root(column(select_ori, select_cyl, p))