Selectable axes data combined with grouped filtering capabilities on the same plot in Bokeh

Hi,

I am trying to create a Bokeh plot where I can change the data plotted on each axis using a select box, whilst also allowing me to filter data points using check box group.

The data that I have is a mixture of categorical and numeric. An example of the .csv can be found here.

I am able to change the data the axes plot using this solution (not using CDS or CustomJS). I am aware of Bokeh issue #8421, which is the reason for choosing this solution to have the ability to choose the categoric and numeric data plotted on the axes.

I can implement grouped filtering using the solution from the Community Support entry 8747/8 (using CDS and CustomJSFilter).

However, I am having trouble combining both capabilities in the same plot. Is there a way to do this, please?

My current code trying to combine both capabilities is below. I cannot get the filtering component to work.

import pandas as pd
from bokeh.layouts import column, row
from bokeh.models import ColumnDataSource, Scatter, Select, CheckboxGroup, Paragraph
from bokeh.palettes import Spectral5
from bokeh.plotting import curdoc, figure, show
from bokeh.server.server import Server

df = pd.read_csv("Data.csv", header=0)

SIZES = list(range(6, 22, 3))
COLORS = Spectral5
N_SIZES = len(SIZES)
N_COLORS = len(COLORS)

columns = sorted(df.columns)
discrete = [x for x in columns if df[x].dtype == object]
continuous = [x for x in columns if x not in discrete]

def bkapp(doc):

    def create_figure():
        xs = df[x.value].values
        ys = df[y.value].values

        x_title = x.value.title()
        y_title = y.value.title()

        kw = dict()
        if x.value in discrete:
            kw['x_range'] = sorted(set(xs))
        if y.value in discrete:
            kw['y_range'] = sorted(set(ys))

        kw['title'] = "%s vs %s" % (x_title, y_title)

        p = figure(height=600, width=800, tools='pan,box_zoom,hover,reset', **kw)
        p.xaxis.axis_label = x_title
        p.yaxis.axis_label = y_title

        if x.value in discrete:
            p.xaxis.major_label_orientation = pd.np.pi / 4

        sz = 9
        if size.value != 'None':
            if len(set(df[size.value])) > N_SIZES:
                groups = pd.qcut(df[size.value].values, N_SIZES, duplicates='drop')
            else:
                groups = pd.Categorical(df[size.value])
            sz = [SIZES[xx] for xx in groups.codes]

        c = "#31AADE"
        if color.value != 'None':
            if len(set(df[color.value])) > N_COLORS:
                groups = pd.qcut(df[color.value].values, N_COLORS, duplicates='drop')
            else:
                groups = pd.Categorical(df[color.value])
            c = [COLORS[xx] for xx in groups.codes]

        p.scatter(x=xs, y=ys, color=c, size=sz, line_color="white", alpha=0.6, hover_color='white', hover_alpha=0.5)

        return p

    def update(attr, old, new):
        layout.children[1] = create_figure()

    Parameter_2 = list(df["Parameter #2"].unique())
    Parameter_2_cbg = CheckboxGroup(labels=Parameter_2, active=list(range(len(Parameter_2))))
    Parameter_2_cbg_active = list(Parameter_2_cbg.active)
    df[df['Parameter #2'].isin(Parameter_2_cbg_active)]
    Parameter_2_cbg.on_change('active', update)
    
    Parameter_3 = list(df["Parameter #3"].unique())
    Parameter_3_cbg = CheckboxGroup(labels=Parameter_3, active=list(range(len(Parameter_3))))
    Parameter_3_cbg_active = list(Parameter_3_cbg.active)
    df[df['Parameter #3'].isin(Parameter_3_cbg_active)]
    Parameter_3_cbg.on_change('active', update)

    Parameter_4 = list(df["Parameter #4"].unique())
    Parameter_4_cbg = CheckboxGroup(labels=Parameter_4, active=list(range(len(Parameter_4))))
    Parameter_4_cbg_active = list(Parameter_4_cbg.active)
    df[df['Parameter #4'].isin(Parameter_4_cbg_active)]
    Parameter_4_cbg.on_change('active', update)

    x = Select(title='X-Axis', value='Parameter #1', options=columns)
    x.on_change('value', update)

    y = Select(title='Y-Axis', value='Items', options=columns)
    y.on_change('value', update)

    size = Select(title='Size', value='None', options=['None'] + continuous)
    size.on_change('value', update)

    color = Select(title='Color', value='None', options=['None'] + continuous)
    color.on_change('value', update)

    Title1 = Paragraph(text = """Parameter #2""")
    Title2 = Paragraph(text = """Parameter #3""")
    Title3 = Paragraph(text = """Parameter #4""")

    controls = column(x, y, color, size, width=200)
    layout = row(controls, create_figure(), row(column(Title1, Parameter_2_cbg), column(Title2, Parameter_3_cbg), column(Title3, Parameter_4_cbg)))

    doc.add_root(layout)

server = Server({'/': bkapp}, num_procs=1)
server.start()

if __name__ == '__main__':
    print('Opening Bokeh application on http://localhost:5006/')

    server.io_loop.add_callback(server.show, "/")
    server.io_loop.start()

Any help would be much appreciated.

Kind regards,
James

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