Search code examples
pythonbokeh

Bokeh - how to make multiselect dependent on select widget 'and retrieve multiselect values'?


I am able to create one Select (portfolio) widget and one dependent Multiselect (keywords) widget (keywords change based on portfolio selected). However, i am struggling to retrieve the values of Multiselect. I am not sure how to pass the populated 'keywords' widget from get_folio_terms() to the main section so that it reflects in the multiselect. Any help on this is appreciated.

PS: The code correctly displays the multiselect with the right values populated from get_folio_terms().

Here is the code:

keywords = MultiSelect(title="Keywords", options=[])

def get_folio_terms(attrname, old, new):
    connection = pymysql.connect(host='localhost',
                                 user='root',
                                 password='root',
                                 db='qa_env',
                                 charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)

    with connection.cursor() as cursor:
        sqlstmt1 = "SELECT * from portfolioterms where portfolio_name = "
        sql = sqlstmt1 + "'" + portfolio.value + "';" # handle Keyerror later
        print(sql)
        cursor.execute(sql)
        result = cursor.fetchall()
        if cursor.rowcount > 0:
            dfinput = pd.DataFrame.from_dict(result)
            print(dfinput)

            keywords = MultiSelect(title="Keywords", options=list(dfinput['businessterm']))
            layout.children[1] = keywords
        else:
            keywords = MultiSelect(title="Keywords", options=[]) # reset to empty
            layout.children[1] = keywords

def update_portfolio():

    print(portfolio.value, keywords.value)


def update(attrname, old, new):
    print(keywords.value)

# set up select widget
portfolio = Select(title="portfolio", options=['ERT','Trading', 'Wealth'])
portfolio.on_change('value', get_folio_terms)

keywords.on_change('value', update)

kwbutton = Button(label='Select Keywords',width=150,button_type="success")
kwbutton.on_click(update_portfolio)
layout = column(portfolio,keywords,kwbutton)
curdoc().add_root(layout)

Solution

  • You are overwriting your initial keywords widget in your function, which you then pass to the children. That works, but the global keywords is not overwritten, but remains the old one. Refer to the new one by referring directly to the child:

    print(portfolio.value, layout.children[1].value)
    

    A cleaner way of doing this is not to replace the widget with a new one, but only replacing the options:

    keywords.options=list(dfinput['businessterm'])
    

    And remove the overwrite of the children as it is not necessary anymore.

    layout.children[1] = keywords
    

    When doing it in this way, you can use you old print statements again.

    print(portfolio.value, keywords.value)