Updated 2017-11-16 16:26:47 by dbohdan

Sparkline is a term Edward Tufte invented with for "small, high resolution graphics embedded in a context of words, numbers, images". On the Internet, however, the term has come to mean rough text charts made with block characters, like this: ▁▂▃▅▂▇.

dbohdan 2014-12-29: This particular implementation was inspired by using one for Bash (sadly, incompatible with the POSIX sh). It works in both Tcl 8.4+ and recent versions of Jim Tcl.

Download with wiki-reaper: wiki-reaper -x 40990 0 > spark.tcl
namespace eval sparklines {
        namespace export create
        variable version 0.0.5
        variable ticks [list ▁ ▂ ▃ ▄ ▅ ▆ ▇ █]
        variable tickMax [expr {[llength $ticks] - 1}]
        proc create data {
                variable ticks
                variable tickMax
                set sorted [lsort -real $data]
                set min [lindex $sorted 0]
                set max [lindex $sorted end]
                if {$min == $max} {
                    # All data points are the same.
                    return [string repeat \
                            [lindex $ticks [expr {int($tickMax / 2)}]] \
                            [llength $data]]
                } else {
                    set result {}
                    foreach x $data {
                            set xNormalized [expr {
                                int($tickMax * ($x - $min) / ($max - $min))
                            }]
                            append result [lindex $ticks $xNormalized]
                    }
                    return $result
                }
        }
}

# The following code allows you to use this script from the command line much
# like the Bash version mentioned above.
proc main-script? {} {
    # From https://wiki.tcl.tk/40097.
    global argv0
    if {[info exists argv0]
     && [file exists [info script]] && [file exists $argv0]} {
        file stat $argv0        argv0Info
        file stat [info script] scriptInfo
        expr {$argv0Info(dev) == $scriptInfo(dev)
           && $argv0Info(ino) == $scriptInfo(ino)}
    } else {
        return 0
    }
}

if {[main-script?]} {
    if {$argv eq ""} {
        puts "usage: $argv0 value ?value...?"
        puts "       $argv0 \"value ?value...?\""
    } elseif {$argv eq "test"} {
        proc assert {v1 v2} {
            if {$v1 eq $v2} {
                puts $v1
            } else {
                error "assertion failed: \"$v1\" ne \"$v2\""
            }
        }
        assert [sparklines::create {1 5 22 13 53}] {▁▁▃▂█}
        assert [sparklines::create {0 30 55 80 33 150}] {▁▂▃▄▂█}
        assert [sparklines::create {9 13 5 17 1}] {▄▆▂█▁}
        assert [sparklines::create {1 1 1 1}] {▄▄▄▄}
        puts ok
    } else {
        if {[llength $argv] == 1} {
            set argv [lindex $argv 0]
        }
        puts [sparklines::create $argv]
    }
}

See also edit