Master advanced declarative visualization with HoloViews. Use this skill when creating complex multi-dimensional visualizations, composing overlays and layouts, implementing interactive streams and selection, building network or hierarchical visualizations, or exploring data with dynamic maps and faceted displays.
Creates complex multi-dimensional visualizations using HoloViews composition and interactive streams.
npx claudepluginhub uw-ssec/rse-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
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'
)
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.