How can I enforce param.ListSelector to have at least one selection active?

Hello All!

I would like that my ListSelector / pn.widgets.MultiChoice wouldn’t allow the user to remove all options from the list.

class Labels(param.Parameterized):
    labels = param.ListSelector(default=list('abc'), objects=list('abc'))
    def show_labels(self):
        return pn.Column(
                    pn.Param(self.param['labels'], widgets={"labels": pn.widgets.MultiChoice})
                )

Labels().show_labels().show()

What can I change my code to achieve this?

Thank you!

1 Like

It depends on how you would like to handle this.

One way could be to depend on labels and then issue a notification to the user about the error. And not update or allow the user to update what ever you want to show.

Another way could be to create a custom version of ListSelector via inheritance. You can inspect which (private) methods are available. Inside one of those you could check the value and set some default value if the value is the empty list. I would really like the best practice for doing this as developer defined cleaning/ validation is something basic that should be supported.

All I want is that when the user removes labels, and gets to the last one, to not be able to remove that last one.
I hope there is no need for something too fancy. :slight_smile:

@Marc , I tried your first suggestion. It sort of worked, but it wasn’t actually updating the widget. I decided to try to make the catch more superficial. This seemed to work fine:

class Labels(param.Parameterized):
    labels = param.ListSelector(default=list('abc'), objects=list('abc'))

    @param.depends('labels')
    def show_labels(self):
        global out
        out =  pn.Param(self.param['labels'], widgets={"labels": pn.widgets.MultiChoice})
        
        @pn.depends(out[0], watch = True)
        def check(ev):
            if len(out[0].value) == 0:
                out[0].value = ['a']
    
        return pn.Column(out)

q = Labels()
q.show_labels()
1 Like

Thank you, @riziles and @Marc for the suggestions!
I went with your answer as the solution, @riziles!

I even added also a notification for the user, to know why it happened.

class Labels(param.Parameterized):
    labels = param.ListSelector(default=list('abc'), objects=list('abc'))

    @param.depends('labels')
    def show_labels(self):
        global out
        out =  pn.Param(self.param['labels'], widgets={"labels": pn.widgets.MultiChoice})
        
        @pn.depends(out[0], watch = True)
        def check(ev):
            if len(out[0].value) == 0:
                pn.state.notifications.position = 'top-right'
                pn.state.notifications.warning('Labels can not be empty! \nSetting the first value.', duration=5000)
                out[0].value = ['a']
    
        return pn.Column(out)

q = Labels()
q.show_labels().show()

I am wondering…could small use cases/examples like this one be added to the Panel documentation? :slight_smile:

1 Like

I definitely feel like pn.depends doesn’t get enough love in the docs. It’s very useful.

Hi @sorin

We would love contributions to the docs. The Panel docs are going through a major overhaul and we will have a category of docs called how to where this could fit.

@droumis might be able to add more info to that.


image

1 Like

I need to have enough courage to contribute once, then maybe in time it will be easier.

1 Like

You should try to do it. You can start with a tiny contribution. Just a misspelling or improving a few lines of text. Then you will get a feel for the support you will get and how it works.

Contributing to an open source project is an alternative or supplement to traditional education. You might learn a lot :+1:

2 Likes

@sorin. great! We are making pretty big changes to the docs in preparation for Panel 1.0 that include a restructuring of long User Guides into short How-to’s. We’ll also add a Background section for more discussion content. Also, we’re discussing how to make the Reference more useful with short examples, although this might happen after 1.0. My suggestion would be to check out the new organization when Panel 1.0 is released to see where the remaining gaps are (there will be a lot) and where use cases/examples like this one could fit in.

2 Likes