I am still quite new to the holoviz/param library. The documentation has a lot of contents and already proved helpful. I tried to solve a problem and I am not so sure if what I did is good or bad practice.
The problem
I wish to define a complex model with nested objects. In our example, we have one lower-level object Geometry
and one high-level object Figure
with a nested geometry. The goal is to have two Figures
instance with the following constraints:
Figure.resolution
should be independant across all instancesFigure.alpha
should be shared across all instanceGeometry.shape
should be independant across all instancesGeometry.color
should be shared across all instance
The following figure illustrate what should be the result in panel (note: summary is a reflection of the Figure
's instance state)
The current solution
To solve the problem, I relied on the feature allowing parameters to be shared as reference. In the case of the alpha
parameter, I directly referenced the class parameters so it is effectively shared across all instances. For the color
parameter, I had to instanciate the first Figure
, give its parameter to the second Figure
, and then hide the referred parameter from panel.
from enum import Enum, auto
import os
import param as pm
import panel as pn
pn.extension()
class Colors(Enum):
RED = auto()
GREEN = auto()
BLUE = auto()
class Shapes(Enum):
CIRCLE = auto()
SQUARE = auto()
class Geometry(pm.Parameterized):
color = pm.Selector(objects=list(Colors), allow_refs=True, precedence=-1)
shape = pm.Selector(objects=list(Shapes))
class Figure(pm.Parameterized):
geometry = pm.Parameter(Geometry(), precedence=-1)
resolution = pm.Selector(objects=[10, 20, 30])
alpha = pm.Number(default=0, step=0.1, allow_refs=True)
summary = pm.String()
@pm.depends('geometry.color', 'geometry.shape', 'resolution', 'alpha', watch=True)
def update(self):
self.summary = f'{self.geometry.shape.name}_{self.geometry.color.name}_{self.name}_{self.alpha}_{self.resolution}.png'
reference = Geometry()
refered = Geometry(color=reference.param.color)
fig_left = Figure(name='Left Object', geometry=reference, alpha=Figure.param.alpha)
fig_right = Figure(name='Right Object', geometry=refered, alpha=Figure.param.alpha)
pn.Row(
pn.Param(fig_left, expand=True, expand_button=False, parameters=['resolution', 'geometry', 'summary'], expand_layout=pn.Column),
pn.Column(
pn.Param(Figure, parameters=['alpha'], name='Shared alpha'),
pn.Param(reference, parameters=['color'], name='Shared color', display_threshold=-1)),
pn.Param(fig_right, expand=True, expand_button=False, parameters=['resolution', 'geometry', 'summary'], expand_layout=pn.Column)
)
The question
I feel that my approach is quite inefficient and complex for what I am trying to do. I am pretty sure I misunderstood some of the concepts brought by the param library.
Do you see a more efficient way to solve the problem ?