0

I've got a dataframe with categorical data.

A1 = ["cat",'apple','red',1,2]
A2 = ['dog','grape','blue',3,4]
A3 = ['rat','grape','gray',5,6]
A4 = ['toad','kiwi','yellow',7,8]

df_MD = pd.DataFrame([A1,A2,A3,A4],columns= ["animal","fruit","color","length","weight"])


  animal  fruit   color  length  weight
0    cat  apple     red       1       2
1    dog  grape    blue       3       4
2    rat  grape    gray       5       6
3   toad   kiwi  yellow       7       8

I want to use bokeh serve to eventually create interactive plots. I implemented this suggestion on how to add listeners:

tgtCol1 = 'animal'
catList = list(np.unique(df_MD[tgtCol1]))


def updatexy(tgtCol1,catList,df_MD):
    '''creates x and y values based on whether the entry is found in catlist'''
    mybool = df_MD[tgtCol1]==catList[0]
    for cc in catList: 
        mybool = (mybool) | ( df_MD[tgtCol1]== cc)
    df_MD_mybool = df_MD[mybool].copy()
    x = df_MD_mybool['length'].copy()
    y = df_MD_mybool['weight'].copy()
    return(x,y)

x,y = updatexy(tgtCol1,catList,df_MD)


#create dropdown menu for column selection
menu = [x for x in zip(df_MD.columns,df_MD.columns)]
dropdown = Dropdown(label="select column", button_type="success", menu=menu)
def function_to_call(attr, old, new):
    print(dropdown.value)
dropdown.on_change('value', function_to_call)
dropdown.on_click(function_to_call)


#create buttons for category selection
catList = np.unique(df_MD[tgtCol1].dropna())
checkbox = CheckboxGroup(labels=catList)
def function_to_call2(attr, old, new):
    print(checkbox.value)
checkbox.on_change('value', function_to_call2)
checkbox.on_click(function_to_call2)



#slap everything together
layout = column(dropdown,checkbox)
#add it to the layout
curdoc().add_root(layout)
curdoc().title = "Selection Histogram"

This works ok to create the initial set of menus. But when I try to change the column or select different categories I get an error:

TypeError("function_to_call() missing 2 required positional arguments: 'old' and 'new'",)

so I can't even call the "listener" functions.

Once I call the listener functions, how do I update my list of checkbox values, as well as x and y?

I can update them within the scope of function_to_call1 and function_to_call2, but the global values for x ,y ,tgtCol1, and catList are unchanged!

Mohammad Athar
  • 1,953
  • 1
  • 15
  • 31

1 Answers1

0

I couldn't really find any guide or documentation on how listeners work, but after some experimentation I found that the structure for the listener is wrong. It should be as follows

myWdiget = <some widget>(<arguments>)
def function_to_call(d):
    <actions, where d is a string or object corresponding to the widget state>
myWdiget.on_click(function_to_call) #add a event listener to myWdiget

So, my code turns out to be

dropdown = Dropdown(label="select column", button_type="success", menu=menu)
def function_to_call(d): #only one argument, the selection from the dropdown
    catList =  list(np.unique(df_MD[d].dropna()))
    checkbox.labels=catList
    checkbox.active = [] #makes it so nothing is checked
dropdown.on_click(function_to_call)

#create buttons for category selection
checkbox = CheckboxGroup(labels=catList)
def function_to_call2(cb):
    tempindex = [x for x in cb]  #cb is some bokeh object, we convert it to a list
    #tgtCol1 is a global variable referring to the currently active column
    #not an ideal solution
    catList  =  np.unique(df_MD[tgtCol1].dropna())
    if len(tempindex) != 0:  catList = list(catList[tempindex])
    x,y = updatexy(tgtCol1,catList,df_MD) #gets new data based on desired column, category set, and dataframe
    s.data = dict(x = x,y = y) #'source' object to update a plot I made, unrelated to this answer, so I'm not showing it
checkbox.on_click(function_to_call2)
Mohammad Athar
  • 1,953
  • 1
  • 15
  • 31