Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: more-tests
Fetching contributors…

Cannot retrieve contributors at this time

executable file 179 lines (155 sloc) 3.659 kB
#!/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.
set -e
debug='false'
zero_baseline='false'
# 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=(▁ ▂ ▃ ▄ ▅ ▆ ▇)
number_of_tiers=$(( ${#ticks[@]} - 1 ))
# 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)
to_rational ${sorted[0]}
if $zero_baseline ; then
min_n=0
min_d=1
else
min_n=$n
min_d=$d
fi
to_rational ${sorted[${#sorted[@]} - 1]}
max_n=$n
max_d=$d
range_n=$(( max_n * min_d - min_n * max_d ))
range_d=$(( max_d * min_d ))
if [[ $range_n = 0 ]] ; then
range_n=1
range_d=1
fi
numbers=($1)
}
# given an input number which might be a decimal, convert it to
# a rational number; set n and d to its numerator and
# denominator. For example, 3.3 becomes n=33 and d=10;
# 17 becomes n=17 and d=1.
to_rational() {
# Crapulent bash can't handle decimal numbers, so we will convert
# the input number to a rational
if [[ $1 =~ (.*)\.(.*) ]] ; then
i_part=${BASH_REMATCH[1]}
f_part=${BASH_REMATCH[2]}
n="$i_part$f_part";
d=$(( 10 ** ${#f_part} ))
else
n=$1
d=1
fi
}
# Determines what tick we should print for this number and prints it.
#
# Returns nothing.
print_tick()
{
# The following rigamarole calculates
# ($number - $min) / $tier_size
# using rational arithmetic. This is necessary because $((...)) only
# does integer calculations and because shelling out to bc or dc is
# slow and nonportable
to_rational $1
tick_index_d=$(( range_n * d * min_d ))
tick_index_n=$(( ( n * min_d - min_n * d ) * number_of_tiers * range_d ))
# round to nearest integer: first add 1/2
tick_index_an=$(( tick_index_n * 2 + tick_index_d ))
tick_index_ad=$(( tick_index_d * 2 ))
# divide and truncate
tick_index=$(( tick_index_an / tick_index_ad ))
if $debug; then
echo "$number $tick_index_n / $tick_index_d = $tick_index"
else
echo -n ${ticks[$tick_index]};
fi
}
# Iterate over all of our data and print them out.
#
# Returns nothing.
print_ticks()
{
for number in ${numbers[@]}
do
print_tick $number
done
echo
}
while getopts ":hdz" option; do
case "$option" in
h) help && exit ;;
# [?]) echo "$OPTARG";;
d) debug='true'; shift $((OPTIND-1)) ;;
z) zero_baseline='true'; shift $((OPTIND-1)) ;;
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
read data
fi
# Trim spaces to allow input like '1, 2, 3'
data=$(echo $data | tr -s ' ' ',')
setup_array $data
print_ticks $data
Jump to Line
Something went wrong with that request. Please try again.