Master interactive dashboard and application development with Panel and Param. Use this skill when building custom web applications with Python, creating reactive component-based UIs, handling file uploads and real-time data streaming, implementing multi-page applications, or developing enterprise dashboards with templates and theming.
/plugin marketplace add uw-ssec/rse-agents/plugin install uw-ssec-holoviz-visualization-community-plugins-holoviz-visualization@uw-ssec/rse-agentsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Master interactive dashboard and application development with Panel and Param. This skill covers building web applications, component systems, and responsive dashboards that scale from simple tools to complex enterprise applications.
Panel provides a comprehensive component library for building rich user interfaces:
import panel as pn
import param
pn.extension('material')
class Dashboard(param.Parameterized):
title = param.String(default="My Dashboard")
refresh_interval = param.Integer(default=5000, bounds=(1000, 60000))
@param.depends('refresh_interval')
def view(self):
return pn.Column(
pn.pane.Markdown(f"## {self.title}"),
pn.param.ObjectSelector.from_param(self.param.refresh_interval),
pn.Row(self._metric_card(), self._chart())
)
def _metric_card(self):
return pn.Card(
"Active Users",
"42,531",
title="Metrics",
styles={"background": "#E8F4F8"}
)
def _chart(self):
return pn.pane.Markdown("## Chart Placeholder")
dashboard = Dashboard()
app = dashboard.view
if __name__ == '__main__':
app.servable()
Panel excels at creating reactive, event-driven applications:
import panel as pn
import param
import numpy as np
class DataAnalyzer(param.Parameterized):
data_source = param.Selector(default='random', objects=['random', 'file'])
num_points = param.Integer(default=100, bounds=(10, 1000))
aggregation = param.Selector(default='mean', objects=['mean', 'sum', 'std'])
@param.depends('data_source', 'num_points', watch=True)
def _refresh_data(self):
if self.data_source == 'random':
self.data = np.random.randn(self.num_points)
@param.depends('data_source', 'num_points', 'aggregation')
def summary(self):
if not hasattr(self, 'data'):
self._refresh_data()
agg_func = getattr(np, self.aggregation)
result = agg_func(self.data)
return f"{self.aggregation.capitalize()}: {result:.2f}"
analyzer = DataAnalyzer()
pn.extension('material')
app = pn.Column(
pn.param.ParamMethod.from_param(analyzer.param),
analyzer.summary
)
Panel supports multiple templates for different application styles:
import panel as pn
import param
pn.extension('material')
class Config(param.Parameterized):
theme = param.Selector(default='dark', objects=['dark', 'light'])
sidebar_width = param.Integer(default=300, bounds=(200, 500))
config = Config()
template = pn.template.MaterialTemplate(
title="Advanced Dashboard",
header_background="#2E3440",
sidebar_width=config.sidebar_width,
main=[pn.pane.Markdown("# Main Content")],
sidebar=[
pn.param.ParamMethod.from_param(config.param)
]
)
template.servable()
Build applications that accept file uploads and process data:
import panel as pn
import pandas as pd
file_input = pn.widgets.FileInput(accept='.csv,.xlsx')
@pn.depends(file_input)
def process_file(file_input):
if file_input is None:
return pn.pane.Markdown("### Upload a file to proceed")
if file_input.filename.endswith('.csv'):
df = pd.read_csv(file_input.value)
else:
df = pd.read_excel(file_input.value)
return pn.Column(
pn.pane.Markdown(f"### {file_input.filename}"),
pn.pane.DataFrame(df.head(10), width=800),
pn.pane.Markdown(f"Shape: {df.shape}")
)
pn.extension('material')
app = pn.Column(
pn.pane.Markdown("# Data Upload"),
file_input,
process_file
)
Create dashboards with live data updates:
import panel as pn
import param
import numpy as np
from datetime import datetime
class LiveMonitor(param.Parameterized):
update_frequency = param.Integer(default=1000, bounds=(100, 5000))
is_running = param.Boolean(default=False)
current_value = param.Number(default=0)
def __init__(self, **params):
super().__init__(**params)
self._data_history = []
def start(self):
self.is_running = True
pn.state.add_periodic_callback(
self._update,
period=self.update_frequency,
start=True
)
def _update(self):
if self.is_running:
self.current_value = np.random.randn() + self.current_value * 0.95
self._data_history.append({
'timestamp': datetime.now(),
'value': self.current_value
})
def get_plot(self):
if not self._data_history:
return pn.pane.Markdown("No data yet...")
import holoviews as hv
df = pd.DataFrame(self._data_history)
return hv.Curve(df, 'timestamp', 'value').opts(responsive=True)
monitor = LiveMonitor()
app = pn.Column(
pn.widgets.Button.from_param(monitor.param.is_running, label="Start/Stop"),
monitor.get_plot
)
responsive=True and sizing_mode optionsclass MultiPageApp(param.Parameterized):
page = param.Selector(default='home', objects=['home', 'analytics', 'settings'])
@param.depends('page')
def current_view(self):
pages = {
'home': self._home_page,
'analytics': self._analytics_page,
'settings': self._settings_page,
}
return pages[self.page]()
class FormValidator(param.Parameterized):
email = param.String(default='')
age = param.Integer(default=0, bounds=(0, 150))
@param.depends('email', 'age')
def validation_message(self):
if not self.email or '@' not in self.email:
return pn.pane.Alert("Invalid email", alert_type='danger')
if self.age < 18:
return pn.pane.Alert("Must be 18+", alert_type='warning')
return pn.pane.Alert("Validation passed!", alert_type='success')
class FilteredDataView(param.Parameterized):
df = param.Parameter(default=None)
column_filter = param.String(default='')
value_filter = param.String(default='')
@param.depends('column_filter', 'value_filter')
def filtered_data(self):
if self.column_filter not in self.df.columns:
return self.df
return self.df[self.df[self.column_filter].astype(str).str.contains(self.value_filter)]
Panel integrates seamlessly with other HoloViz libraries:
@pn.cache decoratorpn.state.add_periodic_callback for background taskspn.state.clear_caches()This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.