Bokeh XY plot doesn't update correctly if I use string in X axis

I am trying to plot data where I have X axis as string and Y axis as int and have a dropdown to change the string to update Bokeh plot with js callback. It doesn’t seem to work fine if I use X axis with string but if I change to int (like year), it does update correctly. below is an example code. Any help will be
highly appreciated.

import pandas as pd
import bokeh
from bokeh.plotting import figure,output_file,show, save
from bokeh.io import output_notebook
from bokeh.models import NumeralTickFormatter,HoverTool,ColumnDataSource, CategoricalColorMapper,Select
from bokeh.transform import factor_cmap
from bokeh.palettes import Blues8
from bokeh.models.widgets import Tabs,Panel
from bokeh.models import Slider, CustomJS
from bokeh.layouts import row,column
from bokeh.client import push_session

output_file('index.html')

gap = pd.read_csv('C:/Users/ambhuiya/Downloads/gapminder_tidy.csv')
gap1 = gap.loc[:, ['Country', 'Year', 'fertility', 'region']]
gap2 = gap1[gap1['Country'] == 'Iceland']

print(gap1)
print(gap2)

Overall = ColumnDataSource(data=gap1)
Curr = ColumnDataSource(data=gap2)

# plot and the menu is linked with each other by this callback function
callback = CustomJS(args=dict(source=Overall, sc=Curr), code="""
var f = cb_obj.value
sc.data['region']=[]
sc.data['fertility']=[]
for(var i = 0; i <= source.get_length(); i++){
	if (source.data['Country'][i] == f){
		sc.data['region'].push(source.data['region'][i])
		sc.data['fertility'].push(source.data['fertility'][i])
	 }
}

sc.change.emit();
""")
menu = Select(options=list(gap['Country'].unique()), value='Iceland', title='Country')  # drop down menu
p = figure(x_axis_label='region', y_axis_label='fertility')  # creating figure object
p.vbar(x='region', top='fertility',bottom=0, color='green', source=Curr)  # plotting the data using glyph circle
menu.js_on_change('value', callback)  # calling the function on change of selection
layout = column(menu, p)  # creating the layout
show(layout)  # displaying the layout

Have you checked out Handling categorical data — Bokeh 2.4.2 Documentation?

1 Like

Thanks a lot for the suggestion. Looks like I was missing x range setup in figure.

But now as I have have different x axis values, I want the x range to dynamically change depending on the selection of the country. But looks like it blanks out as I change the country if the X axis value is different, works ok if X axis value is the same. I think I am not doing the js callback (very new in js) x range update correctly. Any input on that would be appreciated.

import pandas as pd
import bokeh
from bokeh.plotting import figure,output_file,show, save
from bokeh.io import output_notebook
from bokeh.models import NumeralTickFormatter,HoverTool,ColumnDataSource, CategoricalColorMapper,Select
from bokeh.transform import factor_cmap
from bokeh.palettes import Blues8
from bokeh.models.widgets import Tabs,Panel
from bokeh.models import Slider, CustomJS
from bokeh.layouts import row,column
from bokeh.client import push_session

output_file('index.html')

gap = pd.read_csv('C:/Users/ambhuiya/Downloads/gapminder_tidy1.csv')
gap1 = gap.loc[:, ['Country', 'Year', 'fertility', 'region']]
gap2 = gap1[gap1['Country'] == 'Afghanistan']

print(gap1)
print(gap2)

Overall = ColumnDataSource(data=gap1)
Curr = ColumnDataSource(data=gap2)

reason_code_range_BE = Curr.data['region'].tolist()
# plot and the menu is linked with each other by this callback function
callback = CustomJS(args=dict(source=Overall, sc=Curr, x_range=reason_code_range_BE), code="""
var f = cb_obj.value
sc.data['region']=[]
sc.data['fertility']=[]
for(var i = 0; i <= source.get_length(); i++){
	if (source.data['Country'][i] == f){
		sc.data['region'].push(source.data['region'][i])
		sc.data['fertility'].push(source.data['fertility'][i])
		x_range.factor = sc.data['region'];
	 }
}

sc.change.emit();
""")

print(reason_code_range_BE)
menu = Select(options=list(gap['Country'].unique()), value='Afghanistan', title='Country')  # drop down menu
p = figure(plot_width=1200,x_axis_label='region', y_axis_label='fertility',x_range=reason_code_range_BE
)  # creating figure object
p.vbar(x='region', top='fertility',bottom=0, color='green', source=Curr)  # plotting the data using glyph circle
menu.js_on_change('value', callback)  # calling the function on change of selection
layout = column(menu, p)  # creating the layout
show(layout)  # displaying the layout