Search code examples
pythonholoviewspyvizholovizpanel-pyviz

How do i automatically update a dropdown selection widget when another selection widget is changed? (Python panel pyviz)


I have a Select widget that should give a different list of options whenever another Select widget is changed, so it updates whenever this other Select widget changes. How do I this in the example code below?

Select Dropdown dependent on changes of another dropdown

 _countries = {
    'Africa': ['Ghana', 'Togo', 'South Africa'],
    'Asia'  : ['China', 'Thailand', 'Japan'],
    'Europe': ['Austria', 'Bulgaria', 'Greece']
}

continent = pn.widgets.Select(
    value='Asia', 
    options=['Africa', 'Asia', 'Europe']
)

country = pn.widgets.Select(
    value=_countries[continent.value][0], 
    options=_countries[continent.value]
)

@pn.depends(continent.param.value)
def _update_countries(continent):
    countries = _countries[continent]
    country.options = countries
    country.value = countries[0]

pn.Row(continent, country)

Solution

  • So, it took me forever to find this out, but in your @pn.depends() you have to add argument watch=True, so it constantly listens if changes are happening and updates to your other list should be done.
    In this case:

    @pn.depends(continent.param.value, watch=True)
    

    Whole example:

    _countries = {
        'Africa': ['Ghana', 'Togo', 'South Africa'],
        'Asia'  : ['China', 'Thailand', 'Japan'],
        'Europe': ['Austria', 'Bulgaria', 'Greece']
    }
    
    continent = pn.widgets.Select(
        value='Asia', 
        options=['Africa', 'Asia', 'Europe']
    )
    
    country = pn.widgets.Select(
        value=_countries[continent.value][0], 
        options=_countries[continent.value]
    )
    
    @pn.depends(continent.param.value, watch=True)
    def _update_countries(selected_continent):
        countries = _countries[selected_continent]
        country.options = countries
        country.value = countries[0]
    
    pn.Row(continent, country)
    

    The example of the GoogleMapViewer on this page pointed me in the right direction:
    Selector updates after another selector is changed

    The same answer but then in the form of a Class:

    class GoogleMapViewer(param.Parameterized):
        
        continent = param.Selector(default='Asia', objects=['Africa', 'Asia', 'Europe'])
        
        country = param.Selector(default='China', objects=['China', 'Thailand', 'Japan'])
        
        _countries = {'Africa': ['Ghana', 'Togo', 'South Africa'],
                      'Asia'  : ['China', 'Thailand', 'Japan'],
                      'Europe': ['Austria', 'Bulgaria', 'Greece']}
        
        @param.depends('continent', watch=True)
        def _update_countries(self):
            countries = self._countries[self.continent]
            self.param['country'].objects = countries
            self.country = countries[0]
            
    viewer = GoogleMapViewer(name='Google Map Viewer')
    pn.Row(viewer.param)