#!/usr/bin/env bash
#
# spark
# https://github.com/holman/spark
#
# Generates sparklines for a set of data.
#
# Here's a a good web-based sparkline generator that was a bit of inspiration
# for spark:
#
# https://datacollective.org/sparkblocks
#
# spark takes a comma-separated list of data and then prints a sparkline out of
# it.
#
# Examples:
#
# spark 1,5,22,13,53
# # => ▁▁▃▂▇
#
# spark 0,30,55,80,33,150
# # => ▁▂▃▅▂▇
#
# spark -h
# # => Prints the spark help text.
# Prints the help text for spark.
#
# Returns nothing.
help()
{
cat <<-EOF
USAGE:
spark [comma,separated,value,list]
EXAMPLES:
spark 1,5,22,13,53
▁▁▃▂▇
spark 0,30,55,80,33,150
▁▂▃▅▂▇
EOF
}
# The actual fun characters we are generating in the sparkline.
ticks=(▁ ▂ ▃ ▄ ▅ ▆ ▇ █)
# The numbers the user gave us.
numbers=()
# The sorted array of the numbers.
sorted=()
# This sets up our secondary array so we can actually generate the correct
# tick.
#
# Returns nothing.
setup_array() {
# 3,6,2 => 2,3,6
sorted=$(echo $1 | tr ',' '\n' | sort -k1,1n | paste -s -d',' -)
# convert comma-separated string to array
IFS=,
sorted=($sorted)
numbers=($1)
}
# The maximum value of the sorted array. In other words, the last value.
sort_max()
{
last=${#sorted[@]}
echo $(echo ${sorted[$last - 1]} | awk '{printf "%.0f",$1}')
}
# The minimum value of the sorted array. In other words, the first value.
sort_min()
{
echo ${sorted[0]}
}
# Find the distance between tiers so we know which tick to assign a character.
tier()
{
number_of_ticks=${#ticks[@]}
distance=$(( $(sort_max) / $number_of_ticks ))
if [ $distance -eq 0 ]
then
distance=1
fi
echo $distance
}
# Determines what tick we should print for this number and prints it.
#
# Returns nothing.
print_tick()
{
tier=$(tier)
for (( i = 0 ; i < ${#ticks[@]} ; i++ ))
do
number=$(echo $1 | awk '{printf "%.0f",$1}')
less_than=$(( $i * $tier + sort_min + $tier ))
greater_than=$(( ($i - 1) * $tier + sort_min + $tier ))
result=$(( $number <= $less_than && $number >= $greater_than ))
if [ $result -eq 1 ]
then
printf '%s' "${ticks[$i]}"
return
fi
done
last=${#ticks[@]}
printf '%s' ${ticks[$last-1]}
}
# Iterate over all of our ticks and print them out.
#
# Returns nothing.
print_ticks()
{
for number in ${numbers[@]}
do
print_tick $number
done
echo
}
while getopts ":h" option; do
case "$option" in
h) help && exit ;;
# [?]) echo "$OPTARG";;
esac
done
# Accept input from $1 or from the pipeline.
if test "$*" != ""
then
data="$*"
else
# check to see if stdin's a tty
if [ -t 0 ]; then
help
exit
fi
data="`cat`"
fi
# Trim spaces to allow input like '1, 2, 3'
data=$(echo $data | tr -s '[:space:]' ',')
setup_array $data
print_ticks $data