Multiselect widget input not showing options

Hello,
I am creating an app that takes in values provided in textinput widget and displays it as multiselect widget. Also, i would like to obtain that input as a list variable.

Obtain_ticker_list doesnt capture input from text_input_ticker

import pandas as pd
import numpy as np
import requests
import matplotlib.pyplot as plt
import io
import re
import datetime



from bokeh.layouts import grid,column,row
from bokeh.models import TextInput,PasswordInput,MultiSelect
from bokeh.io import curdoc

ticker_list=[]

def obtain_ticker_list(attr,old,new):
    ticker_list=text_input_ticker.value

def activate_ticker_field(attr,old,new):
    text_input_ticker.disabled=False

text_input_key=PasswordInput(placeholder='Please enter API key',prefix='Enter API key',value='')
text_input_ticker=TextInput(placeholder='Please enetr coma separated names of ticker',prefix='Ticker',disabled=True,value='')
text_select_ticker=MultiSelect(options=ticker_list,value=['PFE'],visible=True,height=10,width=100)

text_input_key.on_change('value',activate_ticker_field)
text_input_ticker.on_change('value',obtain_ticker_list)

test_layout=grid(row(text_input_key,text_input_ticker,text_select_ticker))

curdoc().add_root(test_layout)

Thanks

There are some basic Python logic issues. e.g. the following code has no effect:

def obtain_ticker_list(attr,old,new):
    ticker_list = text_input_ticker.value

Assigning to a name in a function creates a local variable inside the function, that gets discarded as soon as the function returns. You need to actually mutate the ticker_list at the module scope. Presumably, based on your description, you want to add these values to the list:

def obtain_ticker_list(attr,old,new):
    ticker_list.append(text_input_ticker.value)

That will update the list in the outer scope.

Next, you never actually update the values for the MultiSelect anywhere. This call:

text_select_ticker = MultiSelect(
    options=ticker_list,
    value=['PFE'],
    visible=True,
    height=10,
    width=100
)

is only executed once, at the start, i.e. when ticker_list is empty. You need to explicitly update text_select_ticker.options somewhere with the new values. For instance, in the other callback:

def obtain_ticker_list(attr,old,new):
    ticker_list.append(text_input_ticker.value)
    text_select_ticker.options = ticker_list

Lastly. when you create the MultiSelect it starts with an empty list of possible values, but then you set the value to ['PFE']. This does not really make sense, since "PFE" is not one of the available options (there are no available options at the start). You should either set the value to the empty list at the start, or else include "PFE" in ticker_list at the start.

Hi Bryan,
Thank you very much for the response. It worked. I was wondering if there is no way where by i can store the input from text widget in a global list and access it from anywhere.

# function definition shpace
def test_callback(attr,old,new):
    global ticker_list
    ticker_list=[i.upper() for i in ticker_list_widget.value.split(',')]

# section to create input space

api_key_input_widget=PasswordInput(placeholder='API KEY',prefix='API_KEY',value='')
ticker_list_widget=TextInput(placeholder='Coma separated ticker list',prefix='TICKER',value='')


# sections to execute events for callback

ticker_list_widget.on_change('value',test_callback)

My over arching goal is to create a url - consisting of API_key from api_key_input_widge and ticker_list_widget to access using request library. Thanks.

The code I gave previously with .append already does that. You can read and mutate the ticker_list value anywhere. I am not sure what else you might be looking for. You can use global and then also be able to assign a new value, but that will overwrite any previous contents of the list. Your problem statement made it sound like you wanted to keep accumulating new values to the same list over time.

1 Like

Hi Bryan,
Thank you very much. You clarified my doubts.