Selkie--Widget--Heatmap
NAME
Selkie::Widget::Heatmap - Coloured grid for 2D numeric data
SYNOPSIS
use Selkie::Widget::Heatmap;
use Selkie::Sizing;
# A 4Ć4 grid of arbitrary numeric values. Each cell renders as a
# coloured block; colour comes from the viridis ramp by default.
my $h = Selkie::Widget::Heatmap.new(
data => [
[ 0.1, 0.3, 0.5, 0.7 ],
[ 0.2, 0.4, 0.6, 0.8 ],
[ 0.3, 0.5, 0.7, 0.9 ],
[ 0.4, 0.6, 0.8, 1.0 ],
],
sizing => Sizing.fixed(4),
);
# Custom ramp + explicit range (useful for diverging data around 0)
my $diverging = Selkie::Widget::Heatmap.new(
data => @correlation-matrix,
ramp => 'coolwarm',
min => -1.0,
max => 1.0,
sizing => Sizing.flex,
);
# Reactive
my $live = Selkie::Widget::Heatmap.new(
store-path => <metrics utilization-grid>,
sizing => Sizing.flex,
);DESCRIPTION
A heatmap renders a 2D grid of numeric values as a grid of coloured cells. Each cell is filled with ā (full block); the foreground colour comes from a ramp lookup keyed by the cell's value normalised to [0, 1].
Colour ramps
Default ramp is viridis (perceptually uniform, colourblind-safe). Other ramps from Selkie::Plot::Palette:
viridisā purple ā blue ā teal ā green ā yellowmagmaā black ā purple ā magenta ā creamplasmaā deep blue ā magenta ā orangecoolwarmā diverging blue ā white ā red, useful for signed data centred on zerograyscaleā five steps of grey, accessibility fallback
Override per-widget with :ramp<name>.
Range
By default the range [min, max] auto-derives from the data extent. Pass explicit :min / :max to fix it (essential for the diverging coolwarm ramp, where 0 needs to map to the white midpoint regardless of data extent).
NaN values render with the text-dim theme slot so missing data is visually distinct from in-range zero.
Cell aspect ratio
Terminal cells are taller than they are wide (~2:1). Heatmaps don't compensate for this ā each data cell renders as one terminal cell, so a 10Ć10 data grid looks tall and narrow on screen. To get a near-square render, double the columns (repeat each cell horizontally) by pre-processing the data.
EXAMPLES
A 2D function evaluation
my @grid = (^16).map: -> $r {
(^16).map: -> $c {
my $x = ($c - 8) / 8;
my $y = ($r - 8) / 8;
sin(sqrt($x*$x + $y*$y) * 5);
}
};
my $heatmap = Selkie::Widget::Heatmap.new(
data => @grid,
ramp => 'viridis',
sizing => Sizing.fixed(16),
);A correlation matrix with a diverging ramp
Diverging ramps map 0 to white in the middle. Pin the range to keep the centre stable as data updates:
my $heatmap = Selkie::Widget::Heatmap.new(
data => @corr-matrix, # values in [-1, 1]
ramp => 'coolwarm',
min => -1,
max => 1,
sizing => Sizing.fixed(@corr-matrix.elems),
);Custom palette via theme override
The ramp comes from Selkie::Plot::Palette. To use a colour ramp not included in Palette, render a custom heatmap by subclassing this widget ā or open a feature request to add the ramp to Palette upstream.
SEE ALSO
Selkie::Plot::Palette ā the colour ramp definitions
Selkie::Widget::ScatterPlot ā for sparse 2D point data
Selkie::Widget::BarChart ā for 1D categorical data
has Positional @.data
2D array of numeric values. Each row is one row of cells.
has Positional[Str] @.store-path
Reactive store path. Mutually exclusive with data.
has Str $.ramp
Named colour ramp from Selkie::Plot::Palette. Default: viridis.
has Real $.min
Optional explicit lower bound. Auto-derived from data when unset.
has Real $.max
Optional explicit upper bound. Auto-derived from data when unset.
has Str $.empty-message
Message rendered when there is no data. This is the expected startup state for monitoring dashboards. Set to the empty string to suppress.
method set-data
method set-data(
@new
) returns MuReplace the heatmap's grid with a new array-of-rows. Each row is realised into an Array up-front because callers often pass Seqs from .map chains, and a long-lived TUI re-renders every frame ā an exhausted Seq would produce an empty grid on subsequent renders. Throws when constructed in :store-path mode.
method on-store-attached
method on-store-attached(
$store
) returns MuHook called when the widget is attached to a store. Subscribes to :store-path so the heatmap re-renders on state changes. No-op in :data mode.