0

I heave some issues plotting with Bokeh. There is a filter on 'category', thus plot should update on change. Also, the plot has an interactive legend.

There must be something wring with the code. I get an error "BAD-COLUMN_NAME" in jupyter notebook, but probably there are there issues too, and the html file is empty. Please, I need some help here. Thank you!

# Perform necessary imports
import pandas as pd
from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.models import CustomJS, HoverTool, ColumnDataSource, Select
from bokeh.palettes import Category20_20
from bokeh.layouts import layout, widgetbox, gridplot

#Dataframe
df = pd.DataFrame({'Reg': ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],
        'Category': ['Cat1', 'Cat1', 'Cat1', 'Cat2', 'Cat2', 'Cat2', 'Cat3', 'Cat3', 'Cat3', 'Cat3'],
        'X': ['751', '673', '542', '762', '624', '536', '845', '626', '876', '233'],
        'Y': ['458', '316', '287', '303', '297', '564', '278', '834', '234', '623'],
        'Size': ['5', '9', '5', '8', '10', '22', '23', '12', '9', '20'],           
        'User': ['u1', 'u2', 'u3', 'u1', 'u2', 'u3', 'u1', 'u2', 'u3', 'u3']           
        })

# Make the ColumnDataSource
source = ColumnDataSource(data=dict(Reg=df['Reg'], Category=df['Category'], x=df['X'], y=df['Y'], Size=df['Size'], User=df['User']))
filteredSource = ColumnDataSource(data=dict(Reg=[], Category=[], x=[], y=[], Size=[], User=[]))

#Create widget
category = list(set(df['Category']))
category.sort()
category_select = Select(title="Category:", value=category[0], options=category)

#Callback
callback = CustomJS(args=dict(source=source, filteredSource=filteredSource, 
                              category_select=category_select), code="""
    const data = source.data;
    var f = cb_obj.value;
    const df2 = filteredSource.data;
    df2['category']=[]

    for(i = 0; i < data['category'].length;i++){

    if(data['category'][i]==f){
        df2['category'].push(data['category'][i])
    }
    }

    filteredSource.change.emit()

""")

category_select.js_on_change('value', callback)

# Create the figure: p1
p1 = figure(x_axis_label='x)', y_axis_label='y', 
            plot_width=450, plot_height=450, tools=['box_select', HoverTool(tooltips='Size: @size')])
# Add a circle glyph to p1

users=list(set(df['User']))
for name, color in zip(users, Category20_20):
    user_df = df[df['User'] == name]
    p1.circle(x='X', y='Y', size='Size',
             color=color, alpha=0.8, source=filteredSource, legend=name)

p1.legend.location = "top_right"
p1.legend.click_policy="hide"

#layout
layout = gridplot([widgetbox(category_select), p1], ncols=2, sizing_mode='scale_both')
show(layout)

1 Answer 1

1

You have inconsistent character cases in column names. You use e.g. x and X. You have to stick to one variant and use it everywhere - in data sources, in column specifications when creating glyph renderers, in CustomJS code, etc.

Also, your CustomJS code is wrong. i = 0 will result in an error - you should use let i = 0 instead. And you also update just the Category column whereas you have to update all of the columns to make sure that they're of the same length.

As a side note, judging by this and the other question, you may find this documentation section rather useful: https://docs.bokeh.org/en/latest/docs/user_guide/data.html#filtering-data. The approach described there helps prevent writing JS code and unneded data churning. There are multiple examples here and on Bokeh's Discourse.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your feedback, Eugene!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.