ANSI-Heatmap
view release on metacpan or search on metacpan
lib/ANSI/Heatmap.pm view on Meta::CPAN
}
for my $y (0..$mm{height}-1) {
for my $x (0..$mm{width}-1) {
my $sx = ($x / $xscale) + $mm{min_x};
my $sy = ($y / $yscale) + $mm{min_y};
my $z = $sample->($sx, $sy);
# Normalise intensity
$z = $mm{max_z} if $z > $mm{max_z};
$z -= $mm{min_z};
$z *= $inv_max_z;
$out[$y][$x] = $z;
}
}
return \@out;
}
sub render {
my ($self, $matrix) = @_;
my $half = $self->half;
my @s;
for my $y (0..$#{$matrix}) {
next if $half && $y % 2 == 1;
for my $x (0..$#{$matrix->[$y]}) {
my $top = $matrix->[$y][$x] || 0;
my $bottom = $half ? ($y == $#{$matrix} ? undef : $matrix->[$y+1][$x] || 0)
: $top;
my ($top_color, $bottom_color) = map {
$self->_swatch_lookup($_)
} grep { defined } ($top, $bottom);
my $fg = sprintf "\e[38;5;%d%s", $top_color, 'm';
my $bg = defined $bottom ? sprintf "\e[48;5;%d%s", $bottom_color, 'm'
: '';
my $char = $half ? $fg . $bg . $TOPBLOCK : $bg . ' ';
push @s, $char . "\e[0m";
}
push @s, "\n";
}
return join '', @s;
}
# Return hash of min/max values for each axis.
sub _figure_out_min_and_max {
my $self = shift;
my %calc = (
(map { $_ => 0 } @_minmax_fields),
%{$self->{minmax}},
($self->{minmax}{min_z}||0) >= 0 ? (min_z => 0) : (),
);
# Override with user-specified values, if supplied.
for my $k (keys %calc) {
$calc{$k} = $self->{$k} if defined $self->{$k};
}
# If user did not specify width/height, assume 1x scale.
$calc{width} = $self->{width} || ($calc{max_x} - $calc{min_x} + 1);
$calc{height} = $self->{height} || ($calc{max_y} - $calc{min_y} + 1);
$calc{zrange} = $calc{max_z} - $calc{min_z};
return %calc;
}
sub _binterp {
my $get = shift;
return sub {
my ($x, $y) = @_;
my ($fx, $bx) = modf($x);
my ($fy, $by) = modf($y);
my @p = map { $get->($bx + $_->[0], $by + $_->[1]) } ([0,0],[0,1],[1,0],[1,1]);
my $y1 = $p[0] + ($p[1] - $p[0]) * $fy;
my $y2 = $p[2] + ($p[3] - $p[2]) * $fy;
my $z = $y1 + ($y2 - $y1) * $fx;
return $z;
};
}
sub _set_minmax {
my ($self, %vals) = @_;
my $mm = $self->{minmax};
while (my ($k, $v) = each %vals) {
if (!defined $mm->{"min_$k"}) {
$mm->{"min_$k"} = $mm->{"max_$k"} = $v;
}
else {
$mm->{"min_$k"} = min($mm->{"min_$k"}, $v);
$mm->{"max_$k"} = max($mm->{"max_$k"}, $v);
}
}
}
# Maps a number from [0,1] to a swatch colour.
sub _swatch_lookup {
my ($self, $index) = @_;
return $self->{swatch}->[$index * $#{$self->{swatch}} + .5];
}
1;
=head1 NAME
ANSI::Heatmap - render heatmaps to your terminal
=head1 SYNOPSIS
my $map = ANSI::Heatmap->new(
half => 1,
min_x => 0, max_x => 49,
min_y => 0, max_y => 49,
swatch => 'blue-red',
( run in 1.515 second using v1.01-cache-2.11-cpan-39bf76dae61 )