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:
scipy
no puede llamarse desde tal callback) 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:
output_notebook()
y las dos últimas líneas sin comentarios). Select
solo manejará los valores de str
, por lo que debe convertir (al crearlo) y fuera (al usar los valores: old
y new
) 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))