Creates advanced HoloViews visualizations: multi-dimensional plots, overlays, layouts, interactive streams, networks, dynamic maps, and faceted displays.
npx claudepluginhub uw-ssec/rse-plugins --plugin holoviz-visualizationThis skill uses the workspace's default tool permissions.
Master advanced declarative visualization with HoloViews and composition patterns. This skill covers sophisticated visualization techniques for complex data exploration and presentation.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Master advanced declarative visualization with HoloViews and composition patterns. This skill covers sophisticated visualization techniques for complex data exploration and presentation.
HoloViews allows sophisticated composition of visualization elements:
import holoviews as hv
from holoviews import opts
import pandas as pd
import numpy as np
# Create overlaid elements
curve = hv.Curve(df, 'x', 'y', label='Measured')
scatter = hv.Scatter(df_with_noise, 'x', 'y', label='Noisy')
overlay = curve * scatter # Multiplication overlays
# Create layouts
col_layout = hv.Column(plot1, plot2, plot3)
row_layout = hv.Row(plot1, plot2, plot3)
grid_layout = hv.GridMatrix(data_dict)
# Faceted displays
faceted = hv.Curve(df, 'date', 'value').facet('category')
# Nested layouts
complex_layout = hv.Column(
hv.Row(plot1, plot2),
hv.Row(plot3, plot4),
hv.Row(plot5, plot6)
)
Create responsive visualizations with interactive selection:
from holoviews import streams
# Selection stream
range_stream = streams.RangeXY()
scatter = hv.Scatter(df, 'x', 'y').opts(tools=['box_select'])
@hv.transform
def selected_data(data):
if range_stream.selection:
x0, x1 = range_stream.selection[0], range_stream.selection[1]
y0, y1 = range_stream.selection[2], range_stream.selection[3]
mask = (data['x'] >= x0) & (data['x'] <= x1) & \
(data['y'] >= y0) & (data['y'] <= y1)
return data[mask]
return data
histogram = selected_data.to(hv.Histogram)
scatter_with_hist = scatter + histogram
# Dynamic updating based on parameters
from holoviews import DynamicMap, streams
def plot_by_category(category):
data = df[df['category'] == category]
return hv.Scatter(data, 'x', 'y', title=f'Category: {category}')
category_stream = streams.Stream.define('category', category='A')
dmap = DynamicMap(plot_by_category, streams=[category_stream])
# Parameterized dynamic map
def plot_with_params(threshold=0.5):
filtered = df[df['value'] > threshold]
return hv.Scatter(filtered, 'x', 'y')
dmap_param = DynamicMap(
plot_with_params,
streams=[streams.Stream.define('threshold', threshold=0.5)]
)
import networkx as nx
# Network graph
G = nx.karate_club_graph()
pos = nx.spring_layout(G)
edges = [(u, v) for u, v in G.edges()]
nodes = list(G.nodes())
# Create nodes and edges visualization
edge_plot = hv.Segments(edges, kdims=['source', 'target'])
node_plot = hv.Scatter(
[(pos[n][0], pos[n][1], n) for n in nodes],
kdims=['x', 'y', 'node']
)
network = (edge_plot * node_plot).opts(
opts.Scatter(size=100, color='red'),
opts.Segments(color='gray')
)
# Treemap for hierarchical data
treemap = hv.TreeMap(
hierarchical_data,
label='Organization'
).opts(tools=['hover'])
# Aggregate with Rasterize
from holoviews.operation import datashader as dshade
# Box plot for comparison
box_plot = hv.BoxWhisker(df, kdims=['category'], vdims=['value'])
# Violin plot
violin = hv.Violin(df, kdims=['category'], vdims=['value'])
# Distribution comparison
dist_layout = hv.Column(*[
df[df['category'] == cat]['value'].hvplot.hist()
for cat in df['category'].unique()
])
# HoloMap for multi-dimensional data
def plot_by_params(category, metric):
data = df[(df['category'] == category) & (df['metric'] == metric)]
return hv.Scatter(data, 'x', 'y', title=f'{category} - {metric}')
hmap = hv.HoloMap(
{(cat, met): plot_by_params(cat, met)
for cat in categories for met in metrics},
kdims=['Category', 'Metric']
)
# NdLayout for structured multi-dimensional display
ndlayout = hv.NdLayout({
(cat, met): plot_by_params(cat, met)
for cat in categories for met in metrics
}, kdims=['Category', 'Metric'])
# Set global defaults
opts.defaults(
opts.Curve(width=700, height=400, responsive=True),
opts.Scatter(size=100, alpha=0.5),
opts.Image(cmap='viridis')
)
# Apply to multiple elements
styled_plots = [
plot.opts(
title='Styled Plot',
xlabel='X Axis',
ylabel='Y Axis',
toolbar='right',
active_tools=['pan', 'wheel_zoom']
)
for plot in plots
]
# Element-specific styling
plot = hv.Scatter(df, 'x', 'y').opts(
color=hv.dim('category').categorize({
'A': '#FF6B6B',
'B': '#4ECDC4',
'C': '#45B7D1'
}),
size=hv.dim('value').norm(min=10, max=100),
selection_color='red',
nonselection_alpha=0.1
)
# Conditional formatting
plot.opts(
color=hv.dim('status').categorize({
'good': 'green',
'warning': 'orange',
'error': 'red'
})
)
# Annotations
annotated_plot = hv.Curve(df, 'x', 'y')
annotations = [
hv.Text(x, y, text, fontsize=10)
for x, y, text in annotations_data
]
plot_with_annotations = annotated_plot * hv.Overlay(annotations)
# Custom legend
plot = hv.Overlay([
hv.Curve(df1, label='Series 1'),
hv.Curve(df2, label='Series 2'),
hv.Curve(df3, label='Series 3')
]).opts(
legend_position='top_left',
legend_muted_alpha=0.2
)
# Use rasterize for dense plots
from holoviews.operation import rasterize
large_scatter = hv.Scatter(large_df, 'x', 'y')
rasterized = rasterize(large_scatter, pixel_ratio=2)
# Use aggregation
aggregated = df.groupby('category')['value'].mean().hvplot.bar()
# Use datashader for massive datasets (>100M points)
from holoviews.operation.datashader import datashade
dshaded = datashade(large_scatter)
# Responsive sizing
plot = hv.Scatter(df, 'x', 'y').opts(
responsive=True,
sizing_mode='stretch_width'
)
# Accessible color palettes
plot = hv.Scatter(df, 'x', 'y').opts(
color=hv.dim('value').norm(),
cmap='cet_gray_r' # Perceptually uniform
)
# Clear labels
plot.opts(
title='Clear Title',
xlabel='Independent Variable (units)',
ylabel='Dependent Variable (units)',
fontsize=14
)
# Avoid deep nesting
# Bad: ((a + (b + (c + d)))
# Good: a + b + c + d
# Create helper functions
def create_comparison_layout(data_dict):
plots = [hv.Scatter(v, label=k) for k, v in data_dict.items()]
return hv.Column(*plots)
# Modular composition
sidebar = hv.Column(title_text, filter_widget)
main = hv.Row(plot1, plot2)
app = hv.Column(sidebar, main)
def create_linked_views(df):
scatter = hv.Scatter(df, 'x', 'y').opts(tools=['box_select'])
def get_histogram(selection):
if selection:
selected_df = df.iloc[selection.event.inds]
else:
selected_df = df
return hv.Histogram(selected_df['x'], bins=20)
return scatter + DynamicMap(get_histogram, streams=[streams.Selection1D()])
def create_zoomable_view(df):
scatter = hv.Scatter(df, 'x', 'y')
zoomed = scatter.opts(
xlim=(0, 10),
ylim=(0, 10)
)
return hv.Column(scatter, zoomed)
def create_faceted_analysis(df, facet_col):
return df.hvplot.scatter(
x='x',
y='y',
by=facet_col,
subplots=True,
layout='vertical'
)