How to make param subclass instances independent of each other?

Hi there,

I’m new to param/panel having trouble with the following:

  • I’m aiming to show FooClass parameters in a GUI. FooClass is set up so that the user can choose either SubClass1, SubClass2 or SubClass3 and fill in the relevant parameters. However, when running my code, below, both instances of the child class seem to be interlinked, i.e. changing SubClass1.a in one instance of FooClass also changes it in the other.

  • I think the error is in my definition of options - but in order to use the ObjectSelector, i can’t think of any other way to do this.

NB: toggling per_instance doesn’t seem to make any difference?

Thanks for any help guys!

import param
import panel as pn
pn.extension()

class SubClass1(param.Parameterized):
    a = param.Number(label="a")

    def __init__(self, **params):
        super().__init__(**params)

class SubClass2(param.Parameterized):
    b = param.Number(label="b")

    def __init__(self, **params):
        super().__init__(**params)

class SubClass3(param.Parameterized):
    c = param.Number(label="c")

    def __init__(self, **params):
        super().__init__(**params)


class FooClass(param.Parameterized):
    options = [SubClass1(), SubClass2(), SubClass3()]

    dropdown = param.ObjectSelector(
        label="Fill in sub-options",
        objects=options,
        default=options[0],
        precedence=4,
        allow_refs=True,
        per_instance=True,
    )

    def __init__(self, **params):
        super().__init__(**params)


# generate web GUI layout

Foo1 = FooClass()
Foo2 = FooClass()

show_Foo1 = pn.Param(Foo1.param, expand = True)
show_Foo2 = pn.Param(Foo2.param, expand = True)

main = pn.Row(show_Foo1, show_Foo2)

pn.template.FastListTemplate(
        site="", title="", main=[main],
    ).servable()

The issue is that you only defined a list of instances of SubClass1, SubClass2, … once on the FooClass Class-level, not instance.

It’s pretty easy to tell, because the SubClassxxxxx Names (which param assigns unique numbers to) have the same names across both Foo1 and Foo2.

You’ll need to define SubClassx instances per FooClass Instance with something like this:

import param
import panel as pn
pn.extension()

class SubClass1(param.Parameterized):
    a = param.Number(label="a")

class SubClass2(param.Parameterized):
    b = param.Number(label="b")

class FooClass(param.Parameterized):
    #options = [SubClass1(), SubClass2()]

    dropdown = param.ObjectSelector(
        label="Fill in sub-options",
        #objects=options,
        #default=options[0],
        precedence=4,
        allow_refs=True,
        #per_instance=True,   !! is True by default
    )

    def __init__(self, **params):
        super().__init__(**params)
        options = [SubClass1(), SubClass2()]  #  !!! create subclass instances per FooClass instance
        self.param.dropdown.objects = options

# generate web GUI layout

Foo1 = FooClass()
Foo2 = FooClass()

show_Foo1 = pn.Param(Foo1.param, expand = False)
show_Foo2 = pn.Param(Foo2.param, expand = False)

main = pn.Row(show_Foo1, show_Foo2).servable()
main

I had to change the expand=True to False because for whatever reason pn.Param fails trying to expand with separate .objects. Not sure why.