#!/bin/bash # # arbigraph # # A very simple gnuplot grapher of arbitrary numeric data in a single column. # # FIXME: # Bug: mit sameaxis zusammen mit labels in file: sameaxis wird ignoriert # # Example: # # cat /var/log/syslog | cut -f4 -d" " | cut -d: -f1 | uniq -c | arbigraph # # <-- START OUTPUT --> # # +---------------+---------------+----------------+---------------+---------------+---------------+ # + + + + + + + # 35 ++ ************ ++ # | * * | # | * * ************ | # | * * * * | # 30 ++ * * * * ++ # | ************ * * * * | # | ************ * * * * * * | # 25 ++ * * * * * * * * ++ # | * * ************ * * * * * * | # | * * * * * * * * * * | # 20 ++ * * * * * * * * * * ++ # | * * * * * * * * * * | # | * * * * * * * * * * | # | * * * * * * * * * * ****** # 15 ++ * * * * * * * * * * * +* # 15 ++ * * * * * * * * * * * +* # ****** * * * * * * * * * * * * # * * * * * * * * * * * * * * # 10 *+ * * * * * * * * * * * * +* # * * * * * * * * * * * * * * # * * * * * * * * * * * * * * # * * * * * * * * * * * * * * # 5 *+ * * * * * * * * * * * * +* # * * * * * * * * * * * * * * # * * * + * * + * * + * * + * * + * * * # 0 ******-----************----************----************----************----************-----****** # 0 1 2 3 4 5 6 # # THE GNUPLOT SCRIPT # ------------------ # set terminal dumb 105 30; set boxwidth 0.666666666666667; plot [0:6][0:38.5] "/tmp/fileVdL9wt" using 1:2 # title "" with boxes # # THE DATA # -------- # 0 14 06 # 1 26 07 # 2 24 08 # 3 28 09 # 4 35 10 # 5 33 11 # 6 17 12 # # <-- END OUTPUT --> function usage { echo echo " | `basename $0` [OPTIONS] " echo echo "A script to plot a simple graph" echo echo " -c --columnnames STR Name for columns. Seperate by ';'." echo " -C --custom STR Custom arbitrary gnuplot directives; will be placed right" echo " before the plot directive. Separate commands with semicolon." echo " -d --dots Graph with dots instead of blocks" echo " -e --enablescript Output the gnuplot script below the graph and keep data file" echo " -h --help This text" echo " -H --height STR Graph height in characters" echo " -l --lines Graph with lines instead of blocks" echo " --label Additional text inside the graph. Default positioned top left" echo " -L --logscale Logarithmic scale. Default is normale scale." echo " -m --minx STR Starting value of x-axis. Default is $MINX" echo " --miny STR Minimal value of y-axis. Default is 0 (1 for lograithmic scale)" echo " --maxy STR Maximum value of y-axis. Default is calculated" echo " -o --output STR Write graph into a file (png)" echo " -s --sameaxis Use the same y-axis. Default is seperate axis" echo " -t --title STR Title of graph" echo " -w --width STR Width of graph (terminal actually). Default is terminal width" echo " -x --xaxisticsmodulo N Suppress lables on certain tics on the x axis. xaxisticsmodulo 5" echo " means every Nth tics gets a label. Default is $XAXISMODULO. 1 means" echo " every tics gets a label." echo " -2 Usa an additional, second data column" echo echo "Example: " echo " ls -l /tmp | head -15 | grep -v total | awk '{ print \$5 \" \" \$9 } ' | arbigraph" echo echo "Arbigraph will graph the first column. Subsequent columns are ignored." echo "The X-axis is actually the line number of a value." echo "Command line option \"minx\" therefore defines the" echo "starting point of the line numbering." echo echo "A label inside the graph can be added with the --label option. By default, this is" echo "is put in the top left corner. You can align it to the right by adding \"(right)\"" echo "inside the label text. This will not be printed. You can use \\n to get a CR:" echo "$> arbigraph --label '\n\n\n PEAK--->'" echo echo "The caption (tics) on the x axis are always crowded. Use --xaxisticsmodulo to" echo "suppress some of the labels. A value of 5 means, that only every 5th label is" echo "printed. The other ones are hidden." echo "You can define an offset for the first label to be printed. So that no the 5th" echo "starting from 0 will be printed, but the 5th starting from 2. Define this shift" echo "behind a slash. Negative values are ok." echo "$> arbigraph --xaxisticsmodulo \"24/-2\"" echo "You will have to try out various values for xaxisticsmodulo and a shift to the" echo "right or to the left until you find something that suits the data and the graph." } function set_columnnames { COL1=`echo "$1" | cut -d';' -f1` COL2=`echo "$1" | cut -d';' -f2` } export TRUE=-1 export FALSE=0 NOSCRIPT=$TRUE # Do not print gnuplot directives at the end and do not keep gnuplot data file HEIGHT=30 # graph height in characters STYLE="boxes" # gnuplot style GP=`tempfile -p arbig -s .gp` # gnuplot file DATA=`tempfile -p arbig -s .data` # data file DATACOLUMNS=1 # there is a single data column MINX=1 # the default minimal value X is 1 WIDTH="" # width passed via command line SAMEAXIS=0 # use the same yaxis LOGSCALE=0 # Use logscale on y axis. Default is 0 (= off) COL1="Col 1" # Name of Column 1 COL2="Col 2" # Name of Column 2 TITLE="" # Title of graph CUSTOM_DIRECTIVES="" # Custom arbitrary gnuplot directives to be passed via CLI XAXISMODULO=1 # Suppress some of the x axis tics labels. Modulo 5 means every 5th label is displayed. XAXISMODULOSHIFT=-2 # When using xaxismodulo to suppress certain x axis tics labels, you can use this # to shift the first label to the right or to the left. Negative values OK MINY="" # Minimal value of Y-Axis MAXY="" # Maximum value of X-Axis # param checking loop while [ $# -gt 0 ] do case $1 in -d) export STYLE="dots"; shift 1;; --dots) export STYLE="dots";shift 1;; -c) set_columnnames "$2"; shift 2;; --columnnames) set_columnnames "$2"; shift 2;; -C) export CUSTOM_DIRECTIVES="$2"; shift 2;; --custom) export CUSTOM_DIRECTIVES="$2"; shift 2;; -e) export NOSCRIPT="$FALSE"; shift 1;; --enablescript) export NOSCRIPT="$FALSE";shift 1;; -h) usage; exit;; --help) usage; exit;; -H) export HEIGHT=$2; shift 2;; --height) export HEIGHT=$2; shift 2;; -l) export STYLE="lines"; shift 1;; --lines) export STYLE="lines";shift 1;; --label) export LABEL="$2";shift 2;; -L) export LOGSCALE=1; shift 1;; --logscale) export LOGSCALE=1; shift 1;; -m) export MINX="$2"; shift 1;; --minx) export MINX="$2";shift 1;; --miny) export MINY="$2";shift 1;; --maxy) export MAXY="$2";shift 1;; -s) export SAMEAXIS=1; shift 1;; --sameaxis) export SAMEAXIS=1; shift 1;; -t) export TITLE="$2"; shift 2;; --title) export TITLE="$2"; shift 2;; -o) export OUTPUT="set output \"$2\"; "; OUTPUTFILE="$2"; shift 2;; --output) export OUTPUT="set output \"$2\"; "; OUTPUTFILE="$2"; shift 2;; -w) export WIDTH="$2"; shift 1;; --width) export WIDTH="$2"; shift 1;; -x) export XAXISMODULO_STR="$2"; shift 1;; --xaxisticsmodulo) export XAXISMODULO_STR="$2"; shift 1;; -2) export DATACOLUMNS=2; shift 1;; *) shift 1;; esac done if [ ! -z $XAXISMODULO_STR ]; then XAXISMODULO=$(echo $XAXISMODULO_STR | sed -e "s/\/.*//") XAXISMODULOSHIFT=$(echo $XAXISMODULO_STR | sed -e "s/.*\///") if [ -z $XAXISMODULOSHIFT ]; then XAXISMODULOSHIFT=0 fi fi if [ $DATACOLUMNS -eq 2 -a "$STYLE" = "boxes" ]; then echo "When working with two data columns, you need to set the option --lines (as boxes and dots do not work). This is fatal. Aborting." exit 1 fi # ----------------------------------------------------------------------- # MAIN # ----------------------------------------------------------------------- N="$MINX" # add line numbering while read line; do # read STDIN if [ $N -eq $MINX ]; then echo "$line" | grep -P -q "\t" if [ $? -eq 0 ]; then LABELS_IN_FILE="$TRUE" else LABELS_IN_FILE="$FALSE" fi fi N=$(($N+1)) if [ "$(((($N+$XAXISMODULOSHIFT)) % $XAXISMODULO))" -eq 0 ]; then # we are shifting the modulo a bit. This brings better results with modulo 5 echo -n "$N " >> $DATA if [ "$LABELS_IN_FILE" -eq "$TRUE" ]; then echo -n "$line" | sed -e 's/-/\\n-\\n/' -e "s/\ /_/g" -e "s/\t.*//" >> $DATA echo -n -e "\t" >> $DATA echo "$line" | sed -e "s/.*\t//" >> $DATA else echo "$line" >> $DATA # FIXME: The line below is a previous version. # I do not know what the purpose was #echo "$line" | sed -e 's/-/\\n-\\n/' >> $DATA fi else echo -n "$N " >> $DATA echo "$line" | sed -e 's/.*\t/\\n\t/' >> $DATA fi done if [ -z "$MAXY" ]; then if [ $SAMEAXIS -eq 0 ]; then if [ "$LABELS_IN_FILE" -eq "$TRUE" ]; then MAXY=`cat $DATA | tr "\t" " " | cut -d' ' -f3 | sort -n | tail -1` # maximum y value else MAXY=`cat $DATA | cut -d' ' -f2 | sort -n | tail -1` # maximum y value fi MAXY=`perl -e "print 1.1 * $MAXY;" 2>/dev/null` # maximum y value stretched by 10% if [ $? -ne 0 ]; then echo "There is something wrong with the calculation of the y axes. If you have the x-axis labels in the STDIN, please make sure there is a TAB between label and data. This is fatal. Aborting." exit 1 fi if [ $DATACOLUMNS = 2 ]; then MAXY2=`cat $DATA | cut -d' ' -f3 | sort -n | tail -1` # maximum y value MAXY2=`perl -e "print 1.1 * $MAXY2;"` # maximum y value stretched by 10% fi else MAXY=`(cat $DATA | cut -d' ' -f2; cat $DATA | cut -d' ' -f3;) | sort -n | tail -1` # maximum y value collected from both data columns MAXY=`perl -e "print 1.1 * $MAXY;"` # maximum y value stretched by 10% MAXY2=$MAXY fi fi MAXX=$N # maximum x value BD=1 # boxwith #BD=`perl -e "print 4.0/$MAXX;"` # boxwith. This is a good value for MAXX from 5 to 40 if [ "$WIDTH" == "" ]; then TW=`tput cols` # terminal width else TW=$WIDTH fi if [ ! -z "$LABEL" ]; then POS="$MAXX*0.03,$MAXY*0.95 left" if [ `echo "$LABEL" | grep "(right)" | wc -l` -eq 1 ]; then TMPL=`echo $LABEL | sed -e "s/(right)//"` LABEL="$TMPL" POS="$MAXX*0.97,$MAXY*0.85 right" fi LABEL="set label 2 \"$LABEL\" at $POS; " fi if [ "$LOGSCALE" -eq 1 ]; then DOLOGSCALE="set logscale y; set logscale y2;" if [ -z "$MINY" ]; then MINY="1" fi else DOLOGSCALE=";" if [ -z "$MINY" ]; then MINY="0" fi fi TERMINAL="dumb" if [ ! -z "$OUTPUT" ]; then TERMINAL="png" TERMFONT="enhanced font 'Verdana,14'" else TERMFONT="" fi if [ $STYLE == "boxes" ]; then if [ $DATACOLUMNS = 1 ]; then if [ "$LABELS_IN_FILE" = "$TRUE" ]; then echo "set terminal $TERMINAL $TW $HEIGHT $TERMFONT; $OUTPUT set boxwidth $BD; set format x \"\\n\\n\"; set title \"$TITLE\"; $DOLOGSCALE; $LABEL; $CUSTOM_DIRECTIVES; plot \"$DATA\" using 1:3:xtic(2) title \"$COL1\" with $STYLE" > $GP else echo "set terminal $TERMINAL $TW $HEIGHT $TERMFONT; $OUTPUT set boxwidth $BD; set title \"$TITLE\"; $DOLOGSCALE; $LABEL; $CUSTOM_DIRECTIVES; plot [$MINX:$MAXX][$MINY:$MAXY] \"$DATA\" using 1:2 title \"$COL1\" with $STYLE" > $GP fi else echo "Boxes style does not work with more than one data column. This is fatal. Aborting." exit 1 fi else if [ $DATACOLUMNS = 1 ]; then if [ "$LABELS_IN_FILE" = "$TRUE" ]; then echo "set terminal $TERMINAL $TW $HEIGHT $TERMFONT; $OUTPUT set boxwidth $BD; set format x \"\\n\\n\"; set title \"$TITLE\"; $DOLOGSCALE; $LABEL; $CUSTOM_DIRECTIVES; plot [$MINX:$MAXX][$MINY:$MAXY] \"$DATA\" using 1:3:xtic(2) title \"$COL1\" with $STYLE" > $GP else echo "set terminal $TERMINAL $TW $HEIGHT $TERMFONT; $OUTPUT set boxwidth $BD; set title \"$TITLE\"; $DOLOGSCALE; $LABEL; $CUSTOM_DIRECTIVES; plot [$MINX:$MAXX][$MINY:$MAXY] \"$DATA\" using 1:2 title \"$COL1\" with $STYLE" > $GP fi else if [ "$LABELS_IN_FILE" = "$TRUE" ]; then #echo "Multiple data columns style has not been implemented with labels in file. Please use input file without labels. Aborting." echo "set terminal $TERMINAL $TW $HEIGHT $TERMFONT; $OUTPUT set boxwidth $BD; set format x \"\\n\\n\"; set title \"$TITLE\"; set y2tics; $DOLOGSCALE; $LABEL; $CUSTOM_DIRECTIVES; plot [$MINX:$MAXX][$MINY:$MAXY][$MINX:$MAXX][$MINY:$MAXY2] \"$DATA\" using 1:2:xtic(2) title \"$COL1\" axis x1y1 with $STYLE, \"$DATA\" using 1:3 title \"$COL2\" axis x1y2 with $STYLE;" > $GP else echo "set terminal $TERMINAL $TW $HEIGHT $TERMFONT; $OUTPUT set boxwidth $BD; set title \"$TITLE\"; set y2tics; $DOLOGSCALE; $LABEL; $CUSTOM_DIRECTIVES; plot [$MINX:$MAXX][$MINY:$MAXY][$MINX:$MAXX][$MINY:$MAXY2] \"$DATA\" using 1:2 title \"$COL1\" axis x1y1 with $STYLE, \"$DATA\" using 1:3 title \"$COL2\" axis x1y2 with $STYLE;" > $GP fi fi fi gnuplot $GP | sed -e "1d" if [ "$NOSCRIPT" = "$FALSE" ]; then echo "THE GNUPLOT SCRIPT" echo "------------------" cat $GP echo echo "The transformed datafile $DATA is left for future use. The gnuplot file ist left at $GP." echo echo "Edit with:" echo "$EDITOR $GP" echo echo "Call with:" echo "gnuplot -c $GP" echo else rm $GP $DATA fi if [ ! -z "$OUTPUT" ]; then echo "Plot written to file $OUTPUTFILE." fi