1

I am new in Bokeh and I am trying to change the colors of the points of a scatterplot depending on the option selected in a checkbox. If the user selects ‘all’ then all the points should be black, else if the user selects ‘group’ then the points should be colored by group (group A = green, group B = blue). I have attached a tentative script below. So far nothing happens when the checkbox is triggered because Im having trouble with the customjs callback.

Any help appreciated,


# Data handling
import pandas as pd

# Bokeh libraries
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, Callback, CustomJS
from bokeh.models.widgets import DataTable, NumberFormatter, TableColumn, HTMLTemplateFormatter
from bokeh.io import curdoc
from bokeh.layouts import row, column
from bokeh.models.widgets import CheckboxGroup


# data
data = dict(group = ['A','A','A','A','A','A','A','B','B','B','B','B','B'],
length = [10, 20, 10, 20, 30, 20, 20, 30, 20, 30, 30, 20, 30],
weight = [100, 200, 100, 300, 100, 400, 100, 300, 100, 400, 500, 600, 450])

data = pd.DataFrame(data)

source = ColumnDataSource(data)

plot = figure()
plot.circle(x = 'length', y = 'weight', source = source)

color_checkbox = CheckboxGroup(labels=["all", "group"], active=[0])

color_checkbox.callback = CustomJS(args=dict(source = source), code='''
var source = source
var data = data;
var group = data['group'];
var selected_option = cb_obj.value;

var i, n = group.length;
    for (i = 0; i < n; ++i) {

      if (selected_option = 0);{
        plot.circle.color = 'black'
      }

      else {
        if (group[i] = 'A') {
          plot.circle.color = 'green'
        else
          plot.circle.color = 'blue'
        }
      }
    }
source.change.emit();
''')

widgets = column(color_checkbox)

layout = row(widgets, plot)

show(layout)


  • have you checked out the [online docs](https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.html#userguide-interaction-jscallbacks-customjs-interactions) regarding plots with js? Also check out this other [stackoverflow question](https://stackoverflow.com/questions/39522642/bokeh-check-checkboxes-with-a-button-checkbox-callback). – Rachel Gallen May 21 '19 at 20:29

1 Answers1

1

There were some mistakes in your Javascript code. First of all you should not edit plot.circle.color. Instead you should add a color column to your ColumnDataSource and edit the colors in there. You also forgot to add some brackets. Such bugs can be detected by pressing F12 while in your browser and looking in the console. Another issue in your code is that you are using a normal checkbox, this allows the user to select nothing or both checkboxes which shouldn't be possible in your case. I replaced this with a radiogroup.

Working code:

# Data handling
import pandas as pd

# Bokeh libraries
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, Callback, CustomJS
from bokeh.models.widgets import DataTable, NumberFormatter, TableColumn, HTMLTemplateFormatter
from bokeh.io import curdoc
from bokeh.layouts import row, column
from bokeh.models.widgets import RadioGroup


# data
data = dict(group = ['A','A','A','A','A','A','A','B','B','B','B','B','B'],
length = [10, 20, 10, 20, 30, 20, 20, 30, 20, 30, 30, 20, 30],
weight = [100, 200, 100, 300, 100, 400, 100, 300, 100, 400, 500, 600, 450],
color = ['black', 'black', 'black', 'black', 'black', 'black', 'black', 'black', 'black', 'black', 'black', 'black', 'black'])

data = pd.DataFrame(data)

source = ColumnDataSource(data)

plot = figure()
plot.circle(x = 'length', y = 'weight', color = 'color', source = source)

color_radiogroup = RadioGroup(labels=["All", "Group"], active=0)

color_radiogroup.callback = CustomJS(args=dict(source = source), code='''
    var data = source.data
    var selected_option = cb_obj.active

    if (cb_obj.active == 0) {
        for (var i = 0; i < data['group'].length; i++) {
            data['color'][i] = 'black'
        }
    } else if (cb_obj.active == 1) {
        for (var i = 0; i < data['group'].length; i++) {
            if (data['group'][i] == 'A') {
                data['color'][i] = 'green'
            } else if (data['group'][i] == 'B') {
                data['color'][i] = 'blue'
            }
        }
    }
    source.change.emit()

''')

widgets = column(color_radiogroup)

layout = row(widgets, plot)

show(layout)
Jasper
  • 1,795
  • 1
  • 12
  • 17
  • Thanks for this solution! I need sth. similar now. For the version of bokeh i'm currently using (2.2.3), I cannot set the callback with `color_radiogroup.callback = ` any more, but `color_radiogroup.js_on_click(CustomJS(...))` works. – mcrot Mar 30 '21 at 09:04