Selkie--Plot--Palette

NAME

Selkie::Plot::Palette - Colorblind-friendly series palettes and color ramps for chart widgets

SYNOPSIS

use Selkie::Plot::Palette;

# Series palettes β€” discrete colors for multi-series charts
my @colors = Selkie::Plot::Palette.series('okabe-ito');
# (0xE69F00, 0x56B4E9, 0x009E73, 0xF0E442, 0x0072B2,
#  0xD55E00, 0xCC79A7, 0x999999)

# Color ramps β€” continuous gradients for heatmaps
my @stops = Selkie::Plot::Palette.ramp('viridis');
# (0.0 => 0x440154, 0.25 => 0x3B528B, 0.5 => 0x21908C, ...)

# Sample a ramp at any position in [0, 1]
my $color = Selkie::Plot::Palette.sample('viridis', 0.42);
# β†’ 0x2E6A8E (interpolated between 0.25 and 0.5 stops)

DESCRIPTION

Two abstractions for chart colors:

  • Series palettes β€” discrete lists of distinct colors for multi-series charts (BarChart with N categories, LineChart with N series). Defaults to Okabe-Ito, designed to be distinguishable for the most common forms of colorblindness.

  • Color ramps β€” continuous gradients sampled by a normalised position in [0, 1], for heatmaps and other value-encoded color use. Defaults to viridis, the perceptually uniform colormap that's been the matplotlib default since 2.0.

Both are separate from Selkie::Theme. Theme slots cover named chart elements (axis, gridlines, legend background); palettes cover data colors. Different access patterns, different homes.

Series palettes

  • okabe-ito (default, 8 colors) β€” Okabe & Ito's palette, optimised for deuteranopia / protanopia / tritanopia. The original palette starts with pure black, which is invisible on dark backgrounds; this implementation substitutes 0x999999 as the first color so the palette works on either light or dark themes.

  • tol-bright (7 colors) β€” Paul Tol's "bright" qualitative palette (personal.sron.nl/~pault). Higher saturation, also colorblind-safe.

  • tableau-10 (10 colors) β€” Tableau's category10 palette. Vivid and well-tested in business dashboards. Less colorblind-friendly than Okabe-Ito but maximises distinct hues for many series.

If a chart needs more series than its palette provides, the colors cycle. For more than ~8 series consider redesigning the chart (faceting, stacked layout, on-hover series isolation) β€” at a glance, the human eye can't reliably distinguish more than ~7 chart series by color alone.

Color ramps

All ramps are 5-stop. Sampling between stops uses straight linear interpolation in RGB space β€” perceptually correct interpolation would need OkLab or Lab conversion, which is overkill for terminal cells where adjacent values blur visually anyway.

  • viridis (default for heatmaps) β€” perceptually uniform, colorblind-safe, prints reasonably in greyscale. The matplotlib default since 2.0.

  • magma β€” like viridis but warmer (purple β†’ red β†’ cream).

  • plasma β€” high-saturation gradient (deep blue β†’ pink β†’ orange).

  • coolwarm β€” diverging blueβ†’whiteβ†’red, useful for signed data where 0 is special (correlations, deltas).

  • grayscale β€” five steps of gray. Mostly for accessibility fallback or print contexts.

EXAMPLES

Coloring a multi-series LineChart

my @palette = Selkie::Plot::Palette.series('okabe-ito');
my @series = (
    { label => 'cpu',     values => @cpu,    color => @palette[0] },
    { label => 'memory',  values => @mem,    color => @palette[1] },
    { label => 'iowait',  values => @iowait, color => @palette[2] },
);

my $chart = Selkie::Widget::LineChart.new(:@series, :show-legend);

Driving a Heatmap with a custom ramp stop

my $heatmap = Selkie::Widget::Heatmap.new(
    data => @grid,
    ramp => 'coolwarm',
);

# Or, for one-off color lookups in custom widget code:
my $color = Selkie::Plot::Palette.sample('viridis', $normalised-value);

Cycling a palette beyond its length

my @palette = Selkie::Plot::Palette.series('tol-bright');   # 7 colors
my $color-for = sub ($i) { @palette[$i mod @palette.elems] };

# Series 0..6 get distinct colors; 7 wraps to series 0's color.

SEE ALSO

method series

method series(
    Str:D $name = "okabe-ito"
) returns List

Return the named series palette as a list of 24-bit RGB integers. Defaults to okabe-ito. Throws on unknown names.

method ramp

method ramp(
    Str:D $name = "viridis"
) returns List

Return the named color ramp as a list of Real = UInt> Pairs, each pair being a position in [0, 1] mapped to a 24-bit RGB. Defaults to viridis. Throws on unknown names.

method sample

method sample(
    Str:D $name,
    Real $t
) returns UInt

Sample a ramp at $t ∈ [0, 1], returning the interpolated 24-bit RGB color. Out-of-range $t is clamped. Interpolation is linear in RGB space (not OkLab) β€” adequate for terminal cells.

Selkie v0.10.0

High-level TUI framework built on Notcurses

Authors

  • Matt Doughty

License

Artistic-2.0

Dependencies

Notcurses::Native:ver<0.4.0+>:auth<zef:apogee>

Test Dependencies

Provides

  • Selkie
  • Selkie::App
  • Selkie::App::Internal::Dispatch
  • Selkie::App::Internal::ErrorLog
  • Selkie::App::Internal::FocusTree
  • Selkie::App::Internal::HitTest
  • Selkie::App::Internal::IdleBudget
  • Selkie::App::Internal::OverlayTree
  • Selkie::App::Internal::RenderLoop
  • Selkie::App::Internal::ScreenModalLifecycle
  • Selkie::App::Internal::Terminal
  • Selkie::App::Internal::TerminalSequences
  • Selkie::Container
  • Selkie::EffectiveBounds
  • Selkie::Event
  • Selkie::Layout::Allocate
  • Selkie::Layout::HBox
  • Selkie::Layout::Split
  • Selkie::Layout::VBox
  • Selkie::Plot::Palette
  • Selkie::Plot::Scaler
  • Selkie::Plot::Ticks
  • Selkie::ScreenManager
  • Selkie::Sizing
  • Selkie::Store
  • Selkie::Style
  • Selkie::Test::Focus
  • Selkie::Test::Keys
  • Selkie::Test::Snapshot
  • Selkie::Test::Snapshot::Harness
  • Selkie::Test::Store
  • Selkie::Test::Supply
  • Selkie::Test::Tree
  • Selkie::Theme
  • Selkie::Trace
  • Selkie::Tree
  • Selkie::Widget
  • Selkie::Widget::Axis
  • Selkie::Widget::BarChart
  • Selkie::Widget::Border
  • Selkie::Widget::Button
  • Selkie::Widget::CardList
  • Selkie::Widget::Checkbox
  • Selkie::Widget::CommandPalette
  • Selkie::Widget::ConfirmModal
  • Selkie::Widget::FileBrowser
  • Selkie::Widget::FocusableByDefault
  • Selkie::Widget::Heatmap
  • Selkie::Widget::HelpOverlay
  • Selkie::Widget::Histogram
  • Selkie::Widget::Image
  • Selkie::Widget::Legend
  • Selkie::Widget::LineChart
  • Selkie::Widget::ListView
  • Selkie::Widget::Modal
  • Selkie::Widget::MultiLineInput
  • Selkie::Widget::PasswordStrength
  • Selkie::Widget::Plot
  • Selkie::Widget::ProgressBar
  • Selkie::Widget::RadioGroup
  • Selkie::Widget::RichText
  • Selkie::Widget::RichText::Span
  • Selkie::Widget::ScatterPlot
  • Selkie::Widget::ScrollView
  • Selkie::Widget::Select
  • Selkie::Widget::Sparkline
  • Selkie::Widget::Spinner
  • Selkie::Widget::TabBar
  • Selkie::Widget::Table
  • Selkie::Widget::Text
  • Selkie::Widget::TextInput
  • Selkie::Widget::TextInput::HighlightSpan
  • Selkie::Widget::TextStream
  • Selkie::Widget::Toast
  • Selkie::Widget::ViewportedCardList

Documentation

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.