Selkie--Widget--Sparkline

NAME

Selkie::Widget::Sparkline - Inline single-row chart using Unicode block glyphs

SYNOPSIS

use Selkie::Widget::Sparkline;
use Selkie::Sizing;

# Static data β€” fixed series
my $sl = Selkie::Widget::Sparkline.new(
    data   => [1, 4, 2, 8, 5, 9, 3, 7],
    sizing => Sizing.fixed(1),
);

# Streaming β€” push samples as they arrive
my $stream = Selkie::Widget::Sparkline.new(sizing => Sizing.fixed(1));
$cpu-supply.tap: -> $sample { $stream.push-sample($sample) };

# Reactive β€” read from a store path that holds the array
my $bound = Selkie::Widget::Sparkline.new(
    store-path => <metrics latency-history>,
    sizing     => Sizing.fixed(1),
);

DESCRIPTION

A single-row inline chart that maps numeric values to the Unicode "lower one-eighth block" series:

▁ β–‚ β–ƒ β–„ β–… β–† β–‡ β–ˆ

Each cell shows one sample. The widget's width determines how many samples are visible β€” when the buffer overflows, the oldest sample is discarded (FIFO ring buffer).

Sparklines are designed to live inline with text or in table cells, not as standalone visualisations. For a full-fledged line chart with axes and legends, use Selkie::Widget::LineChart (static data) or Selkie::Widget::Plot (streaming).

Construction modes

  • Static β€” pass :data(@arr) for a fixed sample series. The widget renders the same data every frame.

  • Streaming β€” construct without :data, then call .push-sample($v) as new samples arrive. Internal ring buffer caps at the widget's column count.

  • Reactive β€” pass :store-path<a b c> to read the sample array from a store path on each render. Subscription marks the widget dirty when the value changes.

The three modes are mutually exclusive: pass exactly one of :data or :store-path, or neither (streaming). Mixing throws at TWEAK.

Value mapping

Values are mapped linearly from [min, max] (auto-derived from the buffer) onto the eight glyph levels. By default min is the minimum sample seen and max the maximum; pass explicit :min / :max to fix the range across renders (useful when streaming so the heights don't jitter as new samples shift the auto-range).

NaN samples render as a space (the cell is skipped). Negative or positive infinities clamp to the corresponding edge glyph.

EXAMPLES

Inline in a status bar

use Selkie::Layout::HBox;
use Selkie::Widget::Text;
use Selkie::Widget::Sparkline;
use Selkie::Sizing;

my $status = Selkie::Layout::HBox.new(sizing => Sizing.fixed(1));
$status.add: Selkie::Widget::Text.new(text => 'CPU: ', sizing => Sizing.fixed(5));
$status.add: $cpu-sparkline,                         sizing => Sizing.fixed(20);
$status.add: Selkie::Widget::Text.new(text => '', sizing => Sizing.flex);

In a Table cell

Embed sparklines in a table column to show per-row history. The hand-rolled implementation has no native handle, so it's cheap to instantiate one per row:

use Selkie::Widget::Table;

my $table = Selkie::Widget::Table.new(...);
$table.add-column(
    name     => 'history',
    width    => 20,
    renderer => -> %row {
        Selkie::Widget::Sparkline.new(
            data   => %row<latency-samples>,
            sizing => Sizing.fixed(1),
        );
    },
);

Streaming with a fixed range

Auto-range jitter is annoying when you want to see absolute trends. Pin the range to your domain knowledge:

my $cpu-spark = Selkie::Widget::Sparkline.new(
    min    => 0,           # CPU is 0..100%
    max    => 100,
    sizing => Sizing.fixed(1),
);
$cpu-supply.tap: -> $sample { $cpu-spark.push-sample($sample) };

SEE ALSO

has Positional[Real] @.data

Static sample list. Mutually exclusive with store-path.

has Positional[Str] @.store-path

Reactive store path β€” list-of-strings forming the lookup. Mutually exclusive with data.

has Real $.min

Optional fixed range lower bound. When unset, the minimum across the current buffer is used (auto-range).

has Real $.max

Optional fixed range upper bound. See min.

has Str $.empty-message

Message rendered when there are no samples yet. This is the expected startup state for monitoring dashboards, so defaults to a calm placeholder rather than nothing. Disable by setting to the empty string.

method on-store-attached

method on-store-attached(
    $store
) returns Mu

Hook called when the widget is attached to a store. Subscribes against :store-path so the sparkline re-renders when the underlying samples change. No-op in :data or push-sample-driven mode.

method push-sample

method push-sample(
    Real $v
) returns Mu

Append a single sample to the streaming ring buffer. When the buffer reaches the widget's column count, the oldest sample is discarded. No-op in :data or :store-path mode (the buffer is owned by the data source, not the widget).

method set-data

method set-data(
    @new
) returns Mu

Replace the static data array. Only valid in :data mode.

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.