Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

220
Visualizações
Bokeh models to plot interactive addition of columns using CustomJS and CheckboxGroup

I want a CheckboxGroup to represent different columns of a dataframe. The idea is for the user to be able to add multiple column values if they select multiple columns and interactively display the sum as a plot.

I have the following plot from a previous help I got:

from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.layouts import layout, widgetbox
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import CheckboxGroup
import pandas as pd

output_file('additive_checkbox.html')
names = ['Number', 'A', 'B', 'C']
rows = [(340, 77, 70, 15),
        (341, 80, 73, 15),
        (342, 83, 76, 16),
        (343, 86, 78, 17)]
data = pd.DataFrame(rows, columns=names)
data['combined'] = None
source = ColumnDataSource(data)
callback = CustomJS(args=dict(source=source), code="""
    const labels = cb_obj.labels;
    const active = cb_obj.active;
    const data = source.data;
    const sourceLen = data.combined.length;
    const combined=Array(sourceLen).fill(undefined);
    var combined_label = ''

if (active.length > 0) {
    const selectedColumns = labels.filter((val, ind) => active.includes(ind));
    for(let i = 0; i < sourceLen; i++) {
        let sum = 0;
        for(col of selectedColumns){
            sum += data[col][i];
        }
        combined[i] = sum;
    }
// get index positions of active buttons; use that to retrieve labels to build "combined" label string
    for (let j=0; j < active.length; j++) {
        combined_label += labels[active[j]]+'+';
    } 
    combined_label = '('+combined_label.substring(0, combined_label.length - 1)+')';
}
else {  // if there are no active buttons, label as 'none'
  combined_label = '(none)';
}

legend_item.label.value = 'combined '+combined_label;
data.combined=combined;
source.change.emit();
""")
checkbox_group = CheckboxButtonGroup(labels=names[1:], active=[], width=400)
checkbox_group.js_on_change("active", callback)

final_col = column(p, checkbox_group)
show(final_col)

And it is giving me the following error: ValueError: failed to validate CheckboxButtonGroup(id='1223', ...).js_event_callbacks: expected an element of Dict(String, List(Instance(CustomJS))), got CustomJS(id='1222', ...)

I am not good with JS and have no idea what it means!

Update: Now, after frustrating syntax changes that I am not sure if they are accurate, the above error went away but it doesn't plot combined or any columns from the source!

about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

Here is a solution for your problem using lines to plot the data.

The idea in the JS part is, to initialize for every click your values for combined with 0 and then loop over all selected labels given through the values in active and add them to combined.

This is done in two cascaded for loops.

import pandas as pd
from bokeh.plotting import figure, output_notebook, show
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import CheckboxButtonGroup
output_notebook()

# data
names = ['Number', 'A', 'B', 'C']
rows = [(340, 77, 70, 15),
        (341, 80, 73, 15),
        (342, 83, 76, 16),
        (343, 86, 78, 17)]
data = pd.DataFrame(rows, columns=names)
data['combined'] = 0
source = ColumnDataSource(data)

# figure
p = figure(width=300, height=300, y_range=(-10, 200))
p.line(x='Number', y='A', color='red', source=source)
p.line(x='Number', y='B', color='green', source=source)
p.line(x='Number', y='C', color='blue', source=source)
p.line(x='Number', y='combined', color='black', line_width=2, source=source)

# JS
callback = CustomJS(args=dict(source=source), code="""
    const labels = cb_obj.labels;
    const active = cb_obj.active;
    const data = source.data;

    // initialize with 0
    for(let i=0; i<data['Number'].length; i++)
        data['combined'][i] = 0
    // add new value for every selected label
    for(let a of active){
        let active_label = labels[a]
        for(let i=0; i<data['Number'].length; i++)
            data['combined'][i] += data[active_label][i]
    }
        
    source.change.emit();
""")
checkbox_group = CheckboxButtonGroup(labels=names[1:], active=[], width=400)
checkbox_group.js_on_change("active", callback)

# output
final_col = column(p, checkbox_group)
show(final_col)

Output

sum

Comment

To add a legend label for each line renderer a legend_label="value" to p.line().

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda