Slider and dropdown not updating my plot

I am a newbie on bokeh, trying to create my first application using the World Bank indicator database. So far I have managed to create a plot that gets updated as I change the value of the slider. However, when I try to add a couple dropdown lists (for my x and y axes) the application is not responding anymore.Both the slider or the dropdown lists fail to update the plot. I have looked at many resources online including tutorials or the documentation but I can’t seem to figure out what I a doing wrong. Any help with be more than greatly appreciated…Also attached the current status of my application.


import pandas as pd
from bokeh.io import output_file,output_notebook,show
from bokeh.models import ColumnDataSource, Slider, Select
from bokeh.plotting import figure
from bokeh.models import HoverTool
from bokeh.models import CategoricalColorMapper
from bokeh.io import curdoc
from numpy.random import random, normal, lognormal
from bokeh.layouts import column, row
from bokeh.layouts import widgetbox

#slice data to year 2000-2020 

wdi= wdi_o[67680:380159]

#melting the  data

wdi_m= wdi.melt(id_vars=["Country Name","Indicator Name","Country Code","Indicator Code"],var_name="Year")

#cleanup and formatting the wdi_m dataset

wdi_m.convert_dtypes().dtypes
wdi_m=wdi_m.fillna(0).replace("Unnamed: 65",0)
wdi_m.Year=wdi_m.Year.astype("int")
wdi_m= wdi_m.set_index(["Indicator Name","Year"])

#create ColumnDataSource

source= ColumnDataSource(data={
    'x'       : wdi_m.loc[["Access to electricity (% of population)","Year"]].value,
    'y'       : (wdi_m.loc[["GDP (current US$)","Year"]].value)/(10**9),
    "c"       : wdi_m.loc[["Access to electricity (% of population)","Year"],"Country Name"]
})


#create a hovertool

hover= HoverTool(tooltips=[
    ("GDP ($ billion)", "@y"),
    ("Access to electricity (%)", "@x"),
    ("Country Name", "@c")
])


# Create the figure: plot
plot = figure( plot_height=400, plot_width=700, tools= [hover, "pan", "wheel_zoom"])


# Add circle glyphs to the plot
plot.circle(x="x", y="y", fill_alpha=0.8, source=source)


liste= list(wdi["Indicator Name"])

# Define the callback: update_plot
def update_plot(attr, old, new):
    yr= slider.value
    x= x_select.value
    y= y_select.value
    plot.xaxis.axis_label = x
    plot.yaxis.axis_label = y
    new_data= {
        'x': data.loc[x,yr].value,
        'y': data.loc[y,yr].value,
        'c': data.loc[[y,yr],"Country Name"]
    }
    
    source.data = new_data
    plot.title.text= 'World Bank Indicator for %d' % yr  

#Create the Slider dropdown
slider= Slider(start=2000, end=2020, value=2012, step=1, title = " Year")

# Attach the callback to the 'value' property of slider
slider.on_change('value', update_plot)

# Create a dropdown Select widget for the x data: x_select
x_select = Select(
    options=liste[0:2],
    value='Access to electricity (% of population)',
    title='x-axis data'
)
    
x_select.on_change('value', update_plot)

# Create a dropdown Select widget for the y data: y_select
y_select = Select(
    options= ["GDP (current US$)", "Adjusted net national income (current US$"],
    value="GDP (current US$)",
    title='y-axis data'
)

y_select.on_change("value",update_plot)


# Create layout and add to current document
layout = row(column(slider, x_select, y_select), plot)
curdoc().title = 'BankData'
curdoc().add_root(layout)

Hi @theotankou please edit your post to use code formatting so that the code is intelligible (either with the </> icon on the editing toolbar, or triple backtick ``` fences around the code blocks)

Hello Bryan,

just edited the post, please let me know if anything.

Best regards,
Alex

@theotankou Where does wdi come from? I intended to actually run the code to investigate, as it is usually orders of magnitude faster for me to diagnose a problem I can actually run real code. Please provide a Minimal Reproducible Example including data necessary to run the example. If you can’t share the real data please update to use some fake/synthetic data.

@Bryan I have reduced the code to strict minimum for reproducibility. World bank database can be downloaded here (the file is called “WDIData.csv”): http://databank.worldbank.org/data/download/WDI_csv.zip

# libraries import
import pandas as pd
from bokeh.io import output_file,output_notebook,show
from bokeh.models import ColumnDataSource, Slider, Select
from bokeh.plotting import figure
from bokeh.models import HoverTool
from bokeh.models import CategoricalColorMapper
from bokeh.io import curdoc
from numpy.random import random, normal, lognormal
from bokeh.layouts import column, row
from bokeh.layouts import widgetbox

# World Bank data import: wdi_original
wdi_original=pd.read_csv("/Users/alexandertankou/Desktop/python/WDI_csv/WDIData.csv")

# Slice wdi_original to year 2000-2020: wdi
wdi= wdi_original[67680:380159]

# Melting wdi: wdi_melt
wdi_melt= wdi(id_vars=["Country Name","Indicator Name","Country Code","Indicator Code"],var_name="Year")

# Cleanup and formatting the wdi_melt dataset
wdi_m.convert_dtypes().dtypes
wdi_m=wdi_m.fillna(0).replace("Unnamed: 65",0)
wdi_m.Year=wdi_m.Year.astype("int")
wdi_m= wdi_m.set_index(["Indicator Name","Year"])

# Create ColumnDataSource: source
source= ColumnDataSource(data={
    'x'       : wdi_m.loc[["Access to electricity (% of population)","Year"]].value,
    'y'       : (wdi_m.loc[["GDP (current US$)","Year"]].value)/(10**9),
    "c"       : wdi_m.loc[["Access to electricity (% of population)","Year"],"Country Name"]
})

# Create the figure: plot
plot = figure( plot_height=400, plot_width=700, tools= [hover, "pan", "wheel_zoom"])

# Add circle glyphs to the plot
plot.circle(x="x", y="y", fill_alpha=0.8, source=source)

# Define the callback: update_plot
def update_plot(attr, old, new):
    yr= slider.value
    x= x_select.value
    y= y_select.value
    plot.xaxis.axis_label = x
    plot.yaxis.axis_label = y
    new_data= {
        'x': data.loc[x,yr].value,
        'y': data.loc[y,yr].value,
        'c': data.loc[[y,yr],"Country Name"]
    }
    
    source.data = new_data
    plot.title.text= 'World Bank Indicator for %d' % yr  

# Create the Slider dropdown: slider
slider= Slider(start=2000, end=2020, value=2012, step=1, title = " Year")

# Attach the callback to the 'value' property of slider
slider.on_change('value', update_plot)

# Create a dropdown Select widget for the x data: x_select
x_select = Select(
    options=['Access to electricity (% of population)', 'Access to clean fuels and technologies for cooking (% of population)'],
    value='Access to electricity (% of population)',
    title='x-axis data'
)
    x_select.on_change('value', update_plot)

# Create a dropdown Select widget for the y data: y_select
y_select = Select(
    options= ["GDP (current US$)", "Adjusted net national income (current US$"],
    value="GDP (current US$)",
    title='y-axis data'
)
y_select.on_change("value",update_plot)

# Create layout and add to current document
layout = row(column(slider, x_select, y_select), plot)
curdoc().title = 'BankData'
curdoc().add_root(layout) 

@theotankou When I try to run your code there is an error on line 20 where it tries to call a DataFrame as a function:

2021-03-10 09:01:33,460 Error running application handler <bokeh.application.handlers.script.ScriptHandler object at 0x7f82803bf490>: 'DataFrame' object is not callable
File "foo.py", line 20, in <module>:
wdi_melt= wdi(id_vars=["Country Name","Indicator Name","Country Code","Indicator Code"],var_name="Year") Traceback (most recent call last):
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/bokeh/application/handlers/code_runner.py", line 197, in run
    exec(self._code, module.__dict__)
  File "/Users/bryan/tmp/foo.py", line 20, in <module>
    wdi_melt= wdi(id_vars=["Country Name","Indicator Name","Country Code","Indicator Code"],var_name="Year")
TypeError: 'DataFrame' object is not callable

I tried changing the bad wdi(...) call to wdi.melt(...) (just on purely a guess). But then there was an undefined name wdi_m. On another guess I changed wdi_melt to wdi_m. But now there this a key error:

raise KeyError(f"{keyarr[mask]} not in index") Traceback (most recent call last):
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/bokeh/application/handlers/code_runner.py", line 197, in run
    exec(self._code, module.__dict__)
  File "/Users/bryan/tmp/foo.py", line 30, in <module>
    'x'       : wdi_m.loc[["Access to electricity (% of population)","Year"]].value,
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/pandas/core/indexing.py", line 895, in __getitem__
    return self._getitem_axis(maybe_callable, axis=axis)
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/pandas/core/indexing.py", line 1113, in _getitem_axis
    return self._getitem_iterable(key, axis=axis)
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/pandas/core/indexing.py", line 1053, in _getitem_iterable
    keyarr, indexer = self._get_listlike_indexer(key, axis, raise_missing=False)
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/pandas/core/indexing.py", line 1254, in _get_listlike_indexer
    indexer, keyarr = ax._convert_listlike_indexer(key)
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/pandas/core/indexes/multi.py", line 2568, in _convert_listlike_indexer
    raise KeyError(f"{keyarr[mask]} not in index")
KeyError: "['Year'] not in index"

I am afraid I have reached my limit in trying to diagnose and debug non-Bokeh releated problems in this code. Please update it to be in runnable state and I will take a look.

@Bryan I fixed it (I had some typos on the variables naming). You should now see that the plot that is generated remains static (dropdown and slider do not update the data)


# libraries import
import pandas as pd
from bokeh.io import output_file,output_notebook,show
from bokeh.models import ColumnDataSource, Slider, Select
from bokeh.plotting import figure
from bokeh.models import HoverTool
from bokeh.models import CategoricalColorMapper
from bokeh.io import curdoc
from numpy.random import random, normal, lognormal
from bokeh.layouts import column, row
from bokeh.layouts import widgetbox

# World Bank data import: wdi_original
wdi_original=pd.read_csv("/Users/alexandertankou/Desktop/python/WDI_csv/WDIData.csv")

# Slice wdi_original to year 2000-2020: wdi
wdi= wdi_original[67680:380159]

# Melting wdi: wdi_melt
wdi_melt= wdi.melt(id_vars=["Country Name","Indicator Name","Country Code","Indicator Code"],var_name="Year")

# Cleanup and formatting the wdi_melt dataset
wdi_melt.convert_dtypes().dtypes
wdi_melt=wdi_melt.fillna(0).replace("Unnamed: 65",0)
wdi_melt.Year=wdi_melt.Year.astype("int")
wdi_melt= wdi_melt.set_index(["Indicator Name","Year"])

# Create ColumnDataSource: source
source= ColumnDataSource(data={
   'x'       : wdi_melt.loc[["Access to electricity (% of population)","Year"]].value,
   'y'       : (wdi_melt.loc[["GDP (current US$)","Year"]].value)/(10**9),
   "c"       : wdi_melt.loc[["Access to electricity (% of population)","Year"],"Country Name"]
})

# Create the figure: plot
plot = figure( plot_height=400, plot_width=700)

# Add circle glyphs to the plot
plot.circle(x="x", y="y", fill_alpha=0.8, source=source)

# Define the callback: update_plot
def update_plot(attr, old, new):
   yr= slider.value
   x= x_select.value
   y= y_select.value
   plot.xaxis.axis_label = x
   plot.yaxis.axis_label = y
   new_data= {
       'x': data.loc[x,yr].value,
       'y': data.loc[y,yr].value,
       'c': data.loc[[y,yr],"Country Name"]
   }
   
   source.data = new_data
   plot.title.text= 'World Bank Indicator for %d' % yr  

# Create the Slider dropdown: slider
slider= Slider(start=2000, end=2020, value=2012, step=1, title = " Year")

# Attach the callback to the 'value' property of slider
slider.on_change('value', update_plot)

# Create a dropdown Select widget for the x data: x_select
x_select = Select(
   options=['Access to electricity (% of population)', 'Access to clean fuels and technologies for cooking (% of population)'],
   value='Access to electricity (% of population)',
   title='x-axis data'
)
x_select.on_change('value', update_plot)

# Create a dropdown Select widget for the y data: y_select
y_select = Select(
   options= ["GDP (current US$)", "Adjusted net national income (current US$"],
   value="GDP (current US$)",
   title='y-axis data'
)
y_select.on_change("value",update_plot)

# Create layout and add to current document
layout = row(column(slider, x_select, y_select), plot)
curdoc().title = 'BankData'
curdoc().add_root(layout)

I still get a key error when trying to even open a session (I never see anything in the browser):

2021-03-10 21:33:50,604 Starting Bokeh server with process id: 5759
2021-03-10 21:34:13,576 Error running application handler <bokeh.application.handlers.script.ScriptHandler object at 0x7fbd407c7490>: "['Year'] not in index"
File "multi.py", line 2568, in _convert_listlike_indexer:
raise KeyError(f"{keyarr[mask]} not in index") Traceback (most recent call last):
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/bokeh/application/handlers/code_runner.py", line 197, in run
    exec(self._code, module.__dict__)
  File "/Users/bryan/tmp/foo.py", line 31, in <module>
    'x'       : wdi_melt.loc[["Access to electricity (% of population)","Year"]].value,
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/pandas/core/indexing.py", line 895, in __getitem__
    return self._getitem_axis(maybe_callable, axis=axis)
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/pandas/core/indexing.py", line 1113, in _getitem_axis
    return self._getitem_iterable(key, axis=axis)
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/pandas/core/indexing.py", line 1053, in _getitem_iterable
    keyarr, indexer = self._get_listlike_indexer(key, axis, raise_missing=False)
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/pandas/core/indexing.py", line 1254, in _get_listlike_indexer
    indexer, keyarr = ax._convert_listlike_indexer(key)
  File "/Users/bryan/anaconda/envs/2339/lib/python3.9/site-packages/pandas/core/indexes/multi.py", line 2568, in _convert_listlike_indexer
    raise KeyError(f"{keyarr[mask]} not in index")
KeyError: "['Year'] not in index"

The only change I made was to update the path to my local download of the data file, which, for reference, looks like this:

(dev) ❯ head ~/tmp/WDIData.csv
"Country Name","Country Code","Indicator Name","Indicator Code","1960","1961","1962","1963","1964","1965","1966","1967","1968","1969","1970","1971","1972","19,
"Arab World","ARB","Access to clean fuels and technologies for cooking (% of population)","EG.CFT.ACCS.ZS","","","","","","","","","","","","","","","","","",,
"Arab World","ARB","Access to electricity (% of population)","EG.ELC.ACCS.ZS","","","","","","","","","","","","","","","","","","","","","","","","","","","",
"Arab World","ARB","Access to electricity, rural (% of rural population)","EG.ELC.ACCS.RU.ZS","","","","","","","","","","","","","","","","","","","","","",",
"Arab World","ARB","Access to electricity, urban (% of urban population)","EG.ELC.ACCS.UR.ZS","","","","","","","","","","","","","","","","","","","","","",",
"Arab World","ARB","Account ownership at a financial institution or with a mobile-money-service provider (% of population ages 15+)","FX.OWN.TOTL.ZS","","","",
"Arab World","ARB","Account ownership at a financial institution or with a mobile-money-service provider, female (% of population ages 15+)","FX.OWN.TOTL.FE.Z,
"Arab World","ARB","Account ownership at a financial institution or with a mobile-money-service provider, male (% of population ages 15+)","FX.OWN.TOTL.MA.ZS",
"Arab World","ARB","Account ownership at a financial institution or with a mobile-money-service provider, older adults (% of population ages 25+)","FX.OWN.TOT,
"Arab World","ARB","Account ownership at a financial institution or with a mobile-money-service provider, poorest 40% (% of population ages 15+)","FX.OWN.TOTL,

I am not sure if there is simply some platform or environment difference (e.g. I have pandas 1.2.2), but I am afraid this point all I can really do is offer some general debugging tips:

  • Check the browser’s JavaScript console for errors. How to access the console differs by browser, you will have to google how to access your specific browser’s dev tools
  • The console log for the bokeh server is also often useful. That’s where the exception above showed up for instance.
  • Putting in print statements into the callbacks and app code is an effective simple way to verify that program state matches your expectations (output will print with the bokeh serve console log)
  • There are also some environment vars you can set to raise the JS or Python debug levels, see bokeh.settings — Bokeh 2.4.2 Documentation

Hello Bryan,

not sure why you are getting the error ether, it runs fine from my Jupiter notebook 6. 0. 3. I will follow your general guidance and hopefully it will help me debug the visual.

Best regards,
Alex