#!/bin/sh # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # or email the author of this code for a copy. # # Based on the barchart script by Graham J Williams of Togaware, but # largely rewritten. # # Copyright (c) 2006 Peter Chubb # Defaults # typeout=x11 ymin=0 heading=1 noxlabel=0 noylabel=0 # This section converted to /bin/sh, but otherwise verbatim from Graham's # version: shortmsg () { echo >&2 "Try \`$0 --help' for more information.\n" } usage () { echo >&2 "Usage: $0 [options] datafile [datafile] > plot.pdf -h, --help Usage plus extra help -t, --trend Draw bezier trend line -s, --font-size=N Font size (points) *not all output types* -T, --type=[pdf,eps,fig,png] Output type to generate -v, --values Include y values with corresponding bar -m, --maxy=value The y axis maximum value --auto-miny Choose min y value from data (0 otherwise) -n, --no-heading Do not include a heading -r, --rotate Rotate the x axis labels -l, --line-at=N Draw a line parallel to x axis at N -g, --log=A Use log scale on axis A (x or y or xy) --noxlabel,--noylabel No labels on the x or y axis " } help () { cat >&2 <<\EOF Generates a bar chart of the supplied data. The first line of the (first) data file is the plot title. The second line contains column titles (with _ converted to space). The remaining lines contain the x axis label and the y value on each line, space separated. Output is written to standard out. If labels or any other entity is poorly placed then generate FIG using \`-T fig' and modify with xfig then export to PDF. Sample input file: DC 23: Eye and Ear Diseases Aggregate Financial_Year Total_Cost 94/95 12340 95/96 52.35 96/97 311361.8 97/98 450102.8 EOF } # # Handle command line: getopt reads the command line, checks for errors # then generates a reformatted, reordered and well formed command line. # Thus the user can make the command line as ugly as they like :-) # command_line=`getopt --options S:s:fg:hl:m:nrtT:v \ --longoptions scale:,font-size:,force,log:,help,line-at:,maxy:,auto-miny,no-heading,rotate,trend,type,values:,noxlabel,noylabel,noxticlabels,noyticlables \ --alternative --name "$0" -- "$@"` if [ $? -gt 0 ] ; then usage exit 1 fi # # Replace old command line with newly parsed command line # eval set -- "$command_line" # # Now process all arguments # Note: not all implemented yet. # while true ; do case "$1" in -s|--font-size) font_points="$2" ; shift 2;; -S|--scale) scale="$2"; shift 2;; # -d|--decimals) decimals="$2" ; shift 2 ;; -h|--help) usage ; help ; exit 0 ;; -f|--force) force=1 ; shift ;; -g|--log) logscale="$2" ; shift 2 ;; -l|--line-at) lineat="f(x)=$2,f(x) notitle," ; shift 2 ;; -m|--maxy) ymax="$2" ; shift 2 ;; --auto-miny) ymin="" ; shift ;; -n|--no-heading) heading=0 ; shift ;; --noxlabel) noxlabel=1 ; shift ;; --noylabel) noylabel=1 ; shift ;; -r|--rotate) xticsopts="rotate" ; xlabelshift="0,-2" ; shift ;; -t|--trend) trend_line=1 ; shift ;; -T|--type) typeout="$2" ; shift 2 ;; -v|--values) display_values=1 ; shift ;; --) shift ; break ;; *) echo "$0: Internal error 1!" ; exit 1 ;; esac done # From here down is new. # # Check supplied arguments # case "$typeout" in x11) terminal="x11" [ "$font_points" ] && terminal="$terminal font \"Helvetica,$font_points\"" extra="-persist" ;; eps) terminal="postscript enhanced color" [ "$font_points" ] && terminal="$terminal \"Helvetica\" $font_points" ;; fig) terminal="fig color" [ "$font_points" ] && terminal="$terminal fontsize $font_points" ;; pdf) terminal="pdf enhanced" [ "$font_points" ] && terminal="$terminal fsize $font_points" ;; png) terminal="png" [ "$font_points" ] && terminal="$terminal font helvetica $font_points" ;; *) echo >&2 "$0: allowed types are [x11,pdf,eps,fig,png], not: ${typeout}\n" shortmsg exit 1 ;; esac awk -v ymax="$ymax" -v ymin="$ymin" \ -v add_heading=$heading \ -v noxlabel=$noxlabel -v noylabel=$noylabel \ -v trend=$trend_line -v add_values=${display_values:0} \ -v "line=$lineat" -v scale="$scale" \ -v "terminal=$terminal" -v lineat="$lineat" \ -v logscale=$logscale ' # # Given nf data files, # What is the offset of the x values for the nth one? # Shift by from x-0.25 to x+0.25 # function calc_offset(n, nf) { if (nf == 1) return 0; return (n-1)/(2*(nf-1)) - 0.25; } BEGIN {count = 1 # guard against non-numeric scale if (scale+0 == 0) { print "Bad scale " scale ", resetting to 1" >/dev/stderr scale=1 } } FILENAME != oldfilename { oldfilename = FILENAME; nf++; filenames[nf] = FILENAME; } FNR==1 { split($0, a); # Merge titles from each file if (title[1] == "") split($0, title); else { for (i = 1; title[i] != ""; i++) { if (a[i] != title[i]) break; } for (j = i+1; title[j] != ""; j++) ; for (k=1 ; a[i] != ""; i++) { title[j++] = a[i]; name[nf] = name[nf] " " a[i] } } } FNR==2 && $1 != "" && $2 != "" { xlabel[nf]=$1; ylabel[nf]=$2; } FNR > 2 { # At last.. a data point. if (!($1 in idx)) { labels[count] = $1; idx[$1] = count++; } $2 *= scale; values[idx[$1], nf] = $2; if ($2 > max) max = $2; } END { boxwidth = nf > 1 ? 0.25 : 0.5; if (add_heading) { printf "set title \"" for (i = 1; i <= length(title); i++) printf "%s ", title[i]; printf "\"\n" } print "set terminal " terminal if (logscale != "") { ymin="" print "set logscale y" } print "set xrange [0:" count+1 "]" if (ymax == "") ymax = max; print "set yrange [" ymin ":" ymax "]" print "set grid noxtics ytics" print "set style fill solid" print "set boxwidth " boxwidth " relative" if (!force_labels) for (i = 2; i <= nf; i++) { if (xlabel[i] != xlabel[1]) { print "Xlabels don'"'"'t match in files " i" and 1" > "/dev/stderr" exit(1); } if (ylabel[i] != ylabel[1]) { print "Ylabels don'"'"'t match in files " i" and 1" > "/dev/stderr" exit(1); } } if (!noxlabel) print "set xlabel \"" xlabel[1] "\"" if (!noylabel) print "set ylabel \"" ylabel[1] "\"" # # Set up the X-axis labels # printf "set xtics (" between="" for (i = 1; i < count; i++) { printf "%s \"%s\" %d", between, labels[i], i; between = "," } print ")" # # Add the values at the top of each bar. # if (add_values) for (i = 1; i <= nf; i++) { offset=calc_offset(i, nf); for (j=1; j < count; j++) printf "set label \"%g\" at %g,%g center\n", values[j, i], j+offset, values[j,i]; } # # And finally the plot commands themselves. # printf "plot " lineat for (i = 1; i <= nf; i++) { if (name[i] == "") name[i] = filenames[i]; printf " \"-\" title \"" name[i] "\" with boxes"; if (i < nf || trend) printf ", " } if (trend) for (i = 1; i <= nf; i++) { printf " \"-\" smooth bezier notitle"; if (i < nf) printf ", " } printf "\n" # And the data. # Order is the same as that in the first data file. # for (i=1; i <= nf; i++) { offset=calc_offset(i, nf) for (j = 1; j < count; j++) print j + offset, values[j, i]; print "e" } if (trend) for (i=1; i <= nf; i++) { offset=calc_offset(i, nf) for (j = 1; j < count; j++) print j + offset, values[j, i]; print "e" } }' "$@" | gnuplot $extra