Drawing decision boundaries with selectable variables

I am trying to draw a decision boundary mesh on a Bokeh plot, like in this example: https://miro.medium.com/v2/resize:fit:1400/1*FP3Mm4VEtUZwq3YsZySenQ.png . I would like the decision boundary to change depending on which variables are selected. However, I am unable to get the boundary mesh to even show on the plot whatsoever.

This is the code I have currently written (presented on simplified fake data):

select_x = Select(title="Choose the variable for the x-axis:", value=starting_x, options=["Var1", "Var2", "Var3"])
select_y = Select(title="Choose the variable for the y-axis:", value=starting_y, options=["Var1", "Var2", "Var3"])
callback_select = CustomJS(args=dict(source=cds_data, plot=plot, renderer=scatterpoints, 
                                     x_select=select_x, y_select=select_y, 
                                     meshes_json=meshes_json,
                                     xaxis=plot.xaxis[0], yaxis=plot.yaxis[0]),             
    code="""
    renderer.glyph.x = {field: x_select.value};
    renderer.glyph.y = {field: y_select.value};
    
    xaxis.axis_label = x_select.value;
    yaxis.axis_label = y_select.value;
    
    var all_meshes = JSON.parse(meshes_json);
    current_key = x_select.value + ", " + y_select.value
    var current_mesh = all_meshes[current_key];

    var mesh_source = new Bokeh.ColumnDataSource({
        data: {
            x: current_mesh.xx,
            y: current_mesh.yy,
            fill_color: current_mesh.colors,
        }
    });
    
    var meshpoints = new Bokeh.Square({
        x: {field: "x"},
        y: {field: "y"},
        fill_color: {field: "fill_color"},
        size: 12, line_alpha: 0, fill_alpha: 0.9,
    });
    
    var mesh_renderer = new Bokeh.GlyphRenderer({
        data_source: mesh_source,
        glyph: meshpoints,
        name: 'Mesh'
    });
    
    plot.add_renderers(mesh_renderer);
""")

I’m afraid I really have no idea what I am doing wrt writing the CustomJS, so if anyone could give any advice at all, I would be incredibly grateful.

I managed to find the fix myself: Create the mesh as a grid of squares, and then simply update it within the CustomJS in the same way that I was updating the scatterpoints.

cds_data = ColumnDataSource(data)
cds_mesh = ColumnDataSource(all_meshes)

starting_x = "Var1"
starting_y = "Var2"

# create the initial figure
plot = figure(plot_width=600, plot_height=600, x_axis_label=starting_x, y_axis_label=starting_y)

# plot the data points
mesh = plot.square(source=cds_mesh, x=f"{starting_x}_{starting_y}_xx", y=f"{starting_x}_{starting_y}_yy", 
                   fill_color=f"{starting_x}_{starting_y}_colours", size=6, line_alpha=0, fill_alpha=0.4, name="Mesh")
mesh.nonselection_glyph = None

scatterpoints = plot.scatter(source=cds_data, x=starting_x, y=starting_y, 
             size=12, line_width=0.5, line_color="#686768", legend_field="Source",
             color=factor_cmap(field_name="Source", palette=["red", "green", "blue"], factors=["cat1a", "cat1b", "cat2"]))

# select the x and y variables
select_x = Select(title="Choose the variable for the x-axis:", value=starting_x, options=["Var1", "Var2", "Var3"])
select_y = Select(title="Choose the variable for the y-axis:", value=starting_y, options=["Var1", "Var2", "Var3"])
callback_select = CustomJS(args=dict(source=cds_data, plot=plot, scatterpoints_renderer=scatterpoints, 
                                     x_select=select_x, y_select=select_y, 
                                     mesh_data=cds_mesh, mesh_renderer=mesh,
                                     xaxis=plot.xaxis[0], yaxis=plot.yaxis[0]),             
    code="""
    scatterpoints_renderer.glyph.x = {field: x_select.value};
    scatterpoints_renderer.glyph.y = {field: y_select.value};
    
    xaxis.axis_label = x_select.value;
    yaxis.axis_label = y_select.value;
    
    var current_vars = x_select.value + "_" + y_select.value;
    var current_xx = current_vars + "_xx";
    var current_yy = current_vars + "_yy";
    var current_colour = current_vars + "_colours";
    mesh_renderer.glyph.x = {field: current_xx};
    mesh_renderer.glyph.y = {field: current_yy};
    mesh_renderer.glyph.fill_color = {field: current_colour};
    
""")

select_x.js_on_change('value', callback_select)
select_y.js_on_change('value', callback_select)

# layout of the whole plot
layout = column(select_x, select_y, plot)
show(layout)

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.