Hi everyone, I have browsed this website alot and found the answers to many of my issues, but am posting now in hopes that someone can help me or explain where I am going wrong. I am trying to create a dashboard using Holoviews, Panel and Param by way of a parameterized class. The dashboard should contain a few parameters/widgets and a holoviews Layout in a panel Tabs object that is controlled by the widgets. A reproducible example is below.
import holoviews as hv
import param
import panel as pn
import numpy as np
class viewer(param.Parameterized):
tabs_switch = param.Boolean(True, label="Toggle Tabs")
cmap = param.Selector(objects=['rainbow', 'fire', 'bwr'])
layout = param.Parameter()
def __init__(self, **params):
super().__init__(**params)
image = pn.Column(pn.Param(self.param, parameters=['cmap']),
self.create_image)
contours = pn.Column(pn.Param(self.param, parameters=['cmap']),
self.create_contours)
self.col = pn.Column(self.make_layout)
self.tabs = pn.Tabs(self.layout, closable=True)
self.column = pn.Column(pn.Param(self.param, parameters=['tabs_switch', 'cmap']), self.tabs)
@param.depends('cmap')
def create_image(self):
x,y = np.mgrid[-50:51, -50:51] * 0.05
img = hv.Image(np.sin(x**2+y**3)).opts(cmap=self.cmap)
return img
@param.depends('cmap')
def create_contours(self):
img = self.create_image()
contours = hv.operation.contours(img, levels=5).opts(cmap=self.cmap)
return contours
@param.depends('tabs_switch', 'cmap')
def make_layout(self):
image = self.create_image()
contours = self.create_contours()
self.layout = hv.Layout(image + contours).opts(tabs=self.tabs_switch)
v = viewer()
v.column
When I run this, I am able to create an image, create a contours plot, put the images into a layout, and display the layout in a pn.Tabs object (which is closable). There are two parameters: cmap, which changes the colormap of the images, and tabs_switch, which toggles whether the image and contours are side-by-side or put into tabs. The issue is that the widgets are not responsive - nothing happens when changing the cmap or toggling the tabs.
I need the hv.Layout object to be inside the pn.Tabs for a couple reasons: turning tabs off inside the layout so that the plots are side-by-side with the tabs_switch parameter, and being able to close the overall Tabs object with closable=True. The final product will have several of these Tabs/Layout objects in one dashboard, so a user can add additional plots, and use the closable feature to clear them, or take the plots out of the tabs to see side-by-side. I also need the plots within the tabs to be responsive to widgets, and not in a way which completely re-returns the Tabs object, but instead modifies the plots inside. From what I understand this is the best practice and most effective in a Parameterized class. I first noticed this when changing the colormap while viewing the second tab caused the Tabs view to return to the first tab, and found this post: Panel Tabs as item in panel Column switches to first tab on widget interactions . I would really like it to stay on the current tab when using the widgets.
Does anyone know how I can make this work? I am essentially trying to use widgets to update images arranged in a Layout (which can also be made into tabs), then nested in an outer pn.Tabs. As of now, changing the colormap or toggling the tabs produces no response.
This is how I did it initially, which re runs and returns the result upon widget interaction and will reset to the first tab when the colormap changes, and from what I understand is the ineffective way of using a Parameterized class.
import holoviews as hv
import param
import panel as pn
import numpy as np
class viewer(param.Parameterized):
tabs_switch = param.Boolean(True, label="Toggle Tabs")
cmap = param.Selector(objects=['rainbow', 'fire', 'bwr'])
layout = param.Parameter()
def __init__(self, **params):
super().__init__(**params)
image = pn.Column(pn.Param(self.param, parameters=['tabs_switch', 'cmap']),
self.create_image)
contours = pn.Column(pn.Param(self.param, parameters=['tabs_switch', 'cmap']),
self.create_contours)
self.tabs = pn.Tabs(self.make_layout, closable=True)
self.column = pn.Column(pn.Param(self.param, parameters=['tabs_switch', 'cmap']), self.tabs)
@param.depends('cmap')
def create_image(self):
x,y = np.mgrid[-50:51, -50:51] * 0.05
img = hv.Image(np.sin(x**2+y**3)).opts(cmap=self.cmap)
return img
@param.depends('cmap')
def create_contours(self):
img = self.create_image()
contours = hv.operation.contours(img, levels=5).opts(cmap=self.cmap)
return contours
@param.depends('tabs_switch', 'cmap')
def make_layout(self):
image = self.create_image()
contours = self.create_contours()
layout = hv.Layout(image + contours).opts(tabs=self.tabs_switch)
return layout
v = viewer()
v.column