Peter’s blog ✴ Week 179 ✴ 22 August 2022

THE WEEKLY CHALLENGE
Ordinal sparkles

The Perl Camel

Task 2

Unicode sparkline

You are given a list of positive numbers, @n. Write a script to print a sparkline in Unicode for the given list of numbers.

Analysis

A sparkline is a small graph, shown without axes, demonstrating visually the variation in some quantity. We are to use the Unicode characters 0x2581 to 0x2588 - ▁ ▂ ▃ ▄ ▅ ▆ ▇ █.

It isn't stated explicitly, but I have assumed we are to divide the presented numbers amongst some number - I've assumed 10 - equally sized buckets such that the smallest member of @n is in the first bucket and the greatest is in the last.

So the process is:

  • Find the least and greatest of the elements of $n
  • Divide the difference between those by 10: this is the 'width' of each bucket
  • Count the number of elements of $n which fall into each bucket
  • Scale these counts such that the smallest is 1 and the largest
    is 8
  • Use these counts to create a sparkline with the 8 Unicode characters

Note: The representation of the Unicode characters varies a lot from font to font so I have supplied the numeric values representing the heights of the 8 characters in the sparkline.

I am sorry that the 'Try it' feature is currently working very slowly or not at all owing to some issue with my web hosting provider.

Try it 

Try running the script with any input. Rather than asking you to input a lot of numbers, enter a number between 10 and 500 and that number of randomised numbers will be generated for you.



example: 100

Script


#!/usr/bin/perl

# Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use v5.26;    # The Weekly Challenge - 2022-08-22
use utf8;     # Week 179 - task 2 - Unicode sparkline
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';

my @values;
push @values, int(rand(50) + 10) for 0 .. 50;
unicode_sparkline(@values);

sub unicode_sparkline {
    
    my (@input, @symbols, $range, $group, $value, $n, @buckets, $sparkline, $max_bucket, $min_bucket, $m,
        $digitline, @digits);
    
    @input = sort {$a <=> $b} @_;
    @symbols = qw(▁ ▂ ▃ ▄ ▅ ▆ ▇ █);
    @digits = qw(1 2 3 4 5 6 7 8);
    @buckets = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    
    # divide input values into 10 buckets of equal width
    $range = ($input[-1] - $input[0]) * 1.001;
    $group = $range / 10;

    $max_bucket = 0;
    for $value (@input) {
        $n = int(($value - $input[0]) / $group);
        $buckets[$n] ++;
        $max_bucket = $buckets[$n] if $buckets[$n] > $max_bucket;
    }
    $min_bucket = $max_bucket;
    for $n (0 .. 9) {
        $min_bucket = $buckets[$n] if $buckets[$n] < $min_bucket;
    }

    # scale vertical 1 to 8
    for $n (0 .. 9) {
        $m = int(($buckets[$n] - $min_bucket) / ($max_bucket - $min_bucket) * 7.999);
        $sparkline .= qq[$symbols[$m]];
        $digitline .= qq[$digits[$m]];
    }
        
    say qq[\nInput:  \@n = (] . join(', ', @_) . ')';
    say qq[Output: $sparkline (values are $digitline)];
}

23 lines of code
Completed after the closing date and not submitted to GitHub

Output from script


Input:  @n = (41, 58, 54, 27, 55, 13, 17, 41, 18, 20, 16,
43, 45, 58, 44, 34, 30, 27, 27, 55, 57, 32, 52, 44, 35,
49, 19, 40, 58, 10, 52, 34, 53, 22, 57, 54, 26, 28, 13,
56, 41, 50, 44, 27, 13, 10, 55, 59, 25, 51, 50)
Output: ▄▃▁▆▃▁▇▁▇█ (values are 4316317178)

 

Any content of this website which has been created by Peter Campbell Smith is in the public domain