Holoviz Panel: how to extract the button name in a callback method?

85 views Asked by At

I need the button name for my Holoviz Panel callback method because the name serves also as a key to a dictionary containing sql commands to be executed on click. I’ve tried to search if the event passed to the callback could have some properties including the name but I have found nothing. There must(?) be a way of identifying the button which has been clicked. Could someone help me out with this? The format below works in Jupyter Lab except for the name extraction.

class Query:
    
    def __init__(self):
        self.buttons = [btn_0, btn_1, btn_2]
        self.data = dict

    def callback(self, event):
        
        value = self.dict[button_name]
        # Run an SQL query using the value
        return (the query result)

    def bind_buttons(self):
        
        for button in self.buttons:
            pn.bind(callback, self.button, watch=True)

query = Query()
query.bind_buttons()
query_buttons = pn.Column(
    '# Queries', 
    query.buttons[0],
    query.buttons[1],
    query.buttons[2],
)
2

There are 2 answers

1
Yuri R On BEST ANSWER

In Panel, when you bind a callback to a button, the function you bind to the button does not receive any arguments by default. However, you can use a functools.partial function to pass additional arguments to the callback.

import panel as pn
from functools import partial

class Query:
    
    def __init__(self):
        self.buttons = [pn.widgets.Button(name='btn_0'), 
                        pn.widgets.Button(name='btn_1'), 
                        pn.widgets.Button(name='btn_2')]
        self.data = {'btn_0': 'query_0', 'btn_1': 'query_1', 'btn_2': 'query_2'}

    def callback(self, event, button_name):
        value = self.data[button_name]
        print(f'Button {button_name} was clicked! Running query: {value}')
        # Run an SQL query using the value
        # return (the query result)

    def bind_buttons(self):
        for button in self.buttons:
            button.on_click(partial(self.callback, button_name=button.name))

query = Query()
query.bind_buttons()

query_buttons = pn.Column(
    '# Queries', 
    *query.buttons,
)

query_buttons.servable()
0
jvkloc On

This problem can be circumvented by using on_click instead of bind. The on_click-method allows extracting the name from event.obj.name. The following pattern works.

class Query:
    
    def __init__(self):
        self.buttons = [btn_0, btn_1, btn_2]
        self.data = dict

    def callback(self, event):
        
        value = self.dict[event.obj.name]
        # Run an SQL query using the value
        return (the query result)

    def bind_buttons(self):
        
        for button in self.buttons:
            button.on_click(callback)

query = Query()
query.bind_buttons()
query_buttons = pn.Column(
    '# Queries', 
    query.buttons[0],
    query.buttons[1],
    query.buttons[2],
)