# MultiSelect widget with multiple options for each value

**URL:** <https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118>\
**Category:** Panel\
**Created:** [August 20, 2020, 10:09am UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118 "2020-08-20T10:09:21Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Lara](https://discourse.holoviz.org/letter_avatar_proxy/v4/letter/l/e274bd/32.png) [@Lara](https://discourse.holoviz.org/u/Lara)\
**Post date:** [August 20, 2020, 10:09am UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/1 "2020-08-20T10:09:21Z")

</div>

Hello! I would like to use the MultiSelect panel widget with multiple options for each value, and then use the selected option to render a plot, here is a simple test case of what I’m willing to do:

 ![test](https://discourse.holoviz.org/uploads/default/original/1X/bf40caf76b91af1f608c1878f298efb0840c5ceb.png)

How can I have the same behavior in case of MultiSelect (display only unique values of the keys) and to link the widget to the plot should I use in this case @pn.depends(ticker.param.options) instead of value?  
I’m kinda new to Panel and Python, I will appreciate your help, Thank you

---

<div class="post-metadata">

**Author:** ![AurelienSciarra](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/aureliensciarra/32/857_2.png) [@AurelienSciarra](https://discourse.holoviz.org/u/AurelienSciarra)\
**Post date:** [August 20, 2020, 12:43pm UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/2 "2020-08-20T12:43:04Z")

</div>

Hi, if you want to display only unique triples for your MultiSelect, you can use the drop\_duplicates function when you set the options.

```
multi_select = pn.widgets.MultiSelect(name='Test', 
                          value=test_list,
                          options= test_dtf[test_list].drop_duplicates().values.tolist())

```

For linking the selector with a plot, you can make a param.Parameterized class. In that case you can use a param.ListSelector instead of a pn.widgets.MultiSelect.

Here is an example :

```
import panel as pn
import pandas as pd
import param 
import holoviews as hv
import hvplot.pandas

class AppTest(param.Parameterized):
    test_dict = {"key1" : ['A']*20,
                 "key2" : [1]*20,
                 "key3": [1,2]*10,
                 "value" : [100]*20}

    test_dtf = pd.DataFrame(test_dict)
    test_list = ['key1','key2','key3']
    multi_select = param.ListSelector(objects=test_dtf[test_list].drop_duplicates().values.tolist())

    @param.depends('multi_select')
    def view(self):
        if not self.multi_select:
            return hv.Curve([])
        else:
            df=pd.DataFrame(self.multi_select,columns=['val','x','y'])
            return df.hvplot.scatter('x','y')

pn.extension()
viewer = AppTest()
pn.Row(pn.Param(viewer.param),viewer.view)
```

---

<div class="post-metadata">

**Author:** ![Lara](https://discourse.holoviz.org/letter_avatar_proxy/v4/letter/l/e274bd/32.png) [@Lara](https://discourse.holoviz.org/u/Lara)\
**Post date:** [August 24, 2020, 1:02pm UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/3 "2020-08-24T13:02:48Z")

</div>

@AurelienSciarra Thank you so much! I would like to know what is the difference between param.Parameterized class and the @pn.depends , and if I could use the last one in this cas?

---

<div class="post-metadata">

**Author:** ![AurelienSciarra](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/aureliensciarra/32/857_2.png) [@AurelienSciarra](https://discourse.holoviz.org/u/AurelienSciarra)\
**Post date:** [August 24, 2020, 1:35pm UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/4 "2020-08-24T13:35:57Z")

</div>

@param.depends is used for linking param objects and functions , but param widgets only works in a param.Parameterized class.

@pn.depends links panel.widgets and function. You can use it inside or outside a param.Parameterized class. In this case you can replace the @param.depends(‘multi\_select’) by @param.depends(‘multi\_select.value’) and replace the param multi\_select by a panel.widgets.

Like that :

```
import panel as pn
import pandas as pd
import param 
import holoviews as hv
import hvplot.pandas

class AppTest(param.Parameterized):
    test_dict = {"key1" : ['A']*20,
                 "key2" : [1]*20,
                 "key3": [1,2]*10,
                 "value" : [100]*20}

    test_dtf = pd.DataFrame(test_dict)
    test_list = ['key1','key2','key3']
    default_value=test_dtf[test_list].drop_duplicates().values.tolist()[0]
    multi_select = pn.widgets.MultiSelect(name='Test', value=[default_value] ,options= test_dtf[test_list].drop_duplicates().values.tolist())
    
    
    @pn.depends('multi_select.value')
    def view(self):
        if len(self.multi_select.value) ==0:
            return hv.Curve([])
        else:
            df=pd.DataFrame(self.multi_select.value,columns=['val','x','y'])
            return df.hvplot.scatter('x','y')

pn.extension()
viewer = AppTest()
pn.Row(viewer.multi_select,viewer.view) 

```

If you want to know if you can do it with pn.depends() and without a param.Parameterized class. I’ll need more detail on what you want to do (what type of function do you want to link). Since I always make a class when I want to create a small app, I don’t really know how to do it this way. Plus in my opinion It’s easier to manage the interaction with param than using panel widgets.

---

<div class="post-metadata">

**Author:** ![Lara](https://discourse.holoviz.org/letter_avatar_proxy/v4/letter/l/e274bd/32.png) [@Lara](https://discourse.holoviz.org/u/Lara)\
**Post date:** [August 24, 2020, 3:46pm UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/5 "2020-08-24T15:46:27Z")

</div>

Thank you so much , you are so helful! In fact I discovered Panel, reading this Medium article ([https://towardsdatascience.com/how-to-build-a-time-series-dashboard-in-python-with-panel-altair-and-a-jupyter-notebook-c0ed40f02289](https://towardsdatascience.com/how-to-build-a-time-series-dashboard-in-python-with-panel-altair-and-a-jupyter-notebook-c0ed40f02289)) , so I would like to use the same example, but instead of 1 key (here company), I’m using a list of keys, and for each key a list of values, here is the notebook:  
[https://github.com/bendoesdata/panel-altair-dashboard/blob/master/panel-altair-demo.ipynb](https://github.com/bendoesdata/panel-altair-dashboard/blob/master/panel-altair-demo.ipynb)

---

<div class="post-metadata">

**Author:** ![AurelienSciarra](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/aureliensciarra/32/857_2.png) [@AurelienSciarra](https://discourse.holoviz.org/u/AurelienSciarra)\
**Post date:** [August 25, 2020, 7:40am UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/6 "2020-08-25T07:40:25Z")

</div>

I didn’t understand clearly what you want to do, you said that you consider Company as a key and you want to use multiple key with for each key multiple values. So I was wondering if multi\_select is really what you need.

If you have a small number of keys you can use a selector for each key, you will have all the combinations.  
In that case you just need to add those new selector to pn.depends and to the signature of the get\_plot function.

Another case : If you only need to chose a couple (key, value) you can check this [topic](https://discourse.holoviz.org/t/updating-options-in-a-widget-by-a-previous-widget-value/1134)

But if you’re good with your MultiSelect, replacing ticker.param.value by multi\_select.param.value would do the work. You will need to check if multi\_select is empty , if you have selected only 1 value and the case where you have selected several values. Also I have made a mistake with the instantiation of the MultiSelect widget :

```auto
multi_select = pn.widgets.MultiSelect(name='Test', 
                          value = test_dtf[test_list].drop_duplicates().values.tolist()[0],
                          options = test_dtf[test_list].drop_duplicates().values.tolist())

```

---

<div class="post-metadata">

**Author:** ![Lara](https://discourse.holoviz.org/letter_avatar_proxy/v4/letter/l/e274bd/32.png) [@Lara](https://discourse.holoviz.org/u/Lara)\
**Post date:** [August 25, 2020, 9:44am UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/7 "2020-08-25T09:44:00Z")

</div>

First of all, I do appreciate your insightful comments, I don’t have a fixed number of keys nor values for each key, so I can’t create a selector for each one.  
I would like to do this dynamically using MultiSelect but it doesn’t seem to work for this example when I use " multi\_select.param.value", the plot does not show in the output, when I checked I found that the selection was empty! here is an example of my code:  
[https://colab.research.google.com/drive/1I9\_bcJTwcOqK1teEJvfslZb-Xv8Zn3M9?usp=sharing](https://colab.research.google.com/drive/1I9_bcJTwcOqK1teEJvfslZb-Xv8Zn3M9?usp=sharing)  
I’m working on this issue to understand the reason why it doesn’t work and I will try the couple ( key, value ) as well, if you have any other suggestions please let me know, and Thank you again.

---

<div class="post-metadata">

**Author:** ![AurelienSciarra](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/aureliensciarra/32/857_2.png) [@AurelienSciarra](https://discourse.holoviz.org/u/AurelienSciarra)\
**Post date:** [August 25, 2020, 12:36pm UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/8 "2020-08-25T12:36:14Z")

</div>

I can’t use altair on my computer because of javascript error, so I haven’t tested your code yet, but I think you can’t use nested list in transform\_filter(). A solution would be to apply your filters on the dataframe instead of applying them on the Chart. Here is an example with hvplot :

```
import panel as pn
import pandas as pd
import datetime as dt
from vega_datasets import data
import numpy as np
import hvplot.pandas

dtf = data.stocks()
dtf=pd.DataFrame(dtf)
dtf['key2']=[1]*560
dtf['key3']=[2]*560
title='title'
subtitle='subtitle'

test_list = ['symbol','key2','key3']
multi_select = pn.widgets.MultiSelect(name='Test',value = dtf[test_list].drop_duplicates().values.tolist()[0],
                                     options = dtf[test_list].drop_duplicates().values.tolist())

date_range_slider = pn.widgets.DateRangeSlider(name='Date Range slider',start=dt.datetime(2001,1,1), end=dt.datetime(2010,1,1),
                                                value=(dt.datetime(2001,1,1),dt.datetime(2010,1,1)))

@pn.depends(multi_select.param.value,date_range_slider.param.value)
def get_plot(multi_select,date_range):
    df = dtf
    df['date'] = pd.to_datetime(df['date'])
    
    start_date = date_range_slider.value[0]
    end_date = date_range_slider.value[1]
    mask = (df['date'] > start_date) & (df['date'] <= end_date)
    df = df.loc[mask]
    
    if len(multi_select)==0:
        _multi_select=[]
    elif isinstance(multi_select[0],str):
        _multi_select=[multi_select]
    else:
        _multi_select=multi_select
    
    ms=list(map(lambda x : ','.join(np.array(x).astype(str)),_multi_select))
    df=df[df[test_list].apply(lambda x : ",".join(x.astype(str).values) in ms,axis=1)]
    return df.hvplot.area('date','price').opts(color='#0c1944',alpha=0.8)

dashboard = pn.Row(pn.Column(title,subtitle,multi_select,date_range_slider),get_plot)

dashboard
```

---

<div class="post-metadata">

**Author:** ![Lara](https://discourse.holoviz.org/letter_avatar_proxy/v4/letter/l/e274bd/32.png) [@Lara](https://discourse.holoviz.org/u/Lara)\
**Post date:** [August 26, 2020, 9:49am UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/9 "2020-08-26T09:49:19Z")

</div>

Thank you @AurelienSciarra, I discovered with you another amazing library hvplot!  
You’re right transform\_filter can’t be used for nested list, I tested the example you gave me, and it works fine with multiple keys, however it doesn’t when working with one or multiple keys (!= str), so I changed the condition to include this use case as well but the output hvplot is empty:

```
import panel as on
import pandas as pd
import datetime as dt
from vega_datasets import data
import numpy as np
import hvplot.pandas

dtf = data.stocks()
dtf=pd.DataFrame(dtf)
dtf['key2']=[1]*560
#dtf['key3']=[2]*560
title='title'
subtitle='subtitle'

#test_list = ['symbol','key2','key3']
test_list = ['key2']
multi_select = pn.widgets.MultiSelect(name='Test',value = 
dtf[test_list].drop_duplicates().values.tolist()[0],
                                 options = dtf[test_list].drop_duplicates().values.tolist())

date_range_slider = pn.widgets.DateRangeSlider(name='Date Range 
slider',start=dt.datetime(2001,1,1), end=dt.datetime(2010,1,1),
                                            value=(dt.datetime(2001,1,1),dt.datetime(2010,1,1)))

@pn.depends(multi_select.param.value,date_range_slider.param.value)
def get_plot(multi_select,date_range):
print(len(multi_select))
df = dtf
df['date'] = pd.to_datetime(df['date'])

start_date = date_range_slider.value[0]
end_date = date_range_slider.value[1]
mask = (df['date'] > start_date) & (df['date'] <= end_date)
df = df.loc[mask]

if len(multi_select)==0:
    _multi_select=[]
elif len(multi_select)==1:
    _multi_select=[multi_select]
else:
    _multi_select= multi_select

ms=list(map(lambda x : ','.join(np.array(x).astype(str)),_multi_select))
df=df[df[test_list].apply(lambda x : ",".join(x.astype(str).values) in ms,axis=1)]
return df.hvplot.area('date','price').opts(color='#0c1944',alpha=0.8)

dashboard = pn.Row(pn.Column(title,subtitle,multi_select,date_range_slider),get_plot)

dashboard
```

---

<div class="post-metadata">

**Author:** ![AurelienSciarra](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/aureliensciarra/32/857_2.png) [@AurelienSciarra](https://discourse.holoviz.org/u/AurelienSciarra)\
**Post date:** [August 26, 2020, 11:52am UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/10 "2020-08-26T11:52:17Z")

</div>

In your example multi\_select = [[1]] which verify len(multi\_select)==1 but that means \_multi\_select = [[[1]]].  
That will cause an error when we compute ms.

You need to change the condition by :

```
if len(multi_select)==0:
        _multi_select=[]
elif len(np.shape(multi_select))<=1:
        _multi_select=[multi_select]
else:
        _multi_select=multi_select 

```

And sort values by date

```
return df.sort_values('date').hvplot.area('date','price').opts(color='#0c1944',alpha=0.8)

```

with those changes it would works with one or multiple keys

---

<div class="post-metadata">

**Author:** ![Lara](https://discourse.holoviz.org/letter_avatar_proxy/v4/letter/l/e274bd/32.png) [@Lara](https://discourse.holoviz.org/u/Lara)\
**Post date:** [August 26, 2020, 2:34pm UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/11 "2020-08-26T14:34:08Z")

</div>

I’m so grateful for your help 🙏

---

<div class="post-metadata">

**Author:** ![khannaum](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/khannaum/32/495_2.png) [@khannaum](https://discourse.holoviz.org/u/khannaum)\
**Post date:** [February 21, 2022, 11:06am UTC](https://discourse.holoviz.org/t/multiselect-widget-with-multiple-options-for-each-value/1118/12 "2022-02-21T11:06:02Z")

</div>

I’m so grateful for your help
