#!/usr/dt/bin/dtksh # # xplot - plot data to X11. Plots input values on a graph. # This is also a demo of the Desktop Korn Shell's X11 features (dtksh). # # Written for a 24-bit colour display. # # 10-Apr-2004 ver 0.76 (check for newer versions) # # # USAGE: xplot [-h] [-f field] [-d delim] [-hi num] [-inc num] [-x pixels] # [-y pixels] [-tc colour] [-lc colour] [-bg colour] [-t text] # [-T text] # # -h help # -f field number (first is 0) # -d field delimiter # -hi y max scale value # -inc x increment per value # -x width (pixels) # -y height (pixels) # -tc text colour # -lc line colour # -br border colour # -bg background colour # -t text label for graph # -T text title for window # eg, # vmstat 1 | xplot -f 21 -hi 100 -t "idle" # plot idle time # vmstat 1 | xplot -f 3 -T "swap free" # plot swap free # xplot -d : -f 2 -hi 65536 < /etc/passwd # plot UIDs (???) # # Valid colours may include unusual options such as SkyBlue, MidnightBlue, # AntiqueWhite, LightSeaGreen, MediumAquamarine, etc.. # On Solaris the file to read is, /usr/openwin/lib/X11/rgb.txt # # NOTES: options are used as "-f 2" not "-f2". # # # COPYRIGHT: Copyright (c) 2004 Brendan Gregg. # # 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, USA. # # (http://www.gnu.org/copyleft/gpl.html) # # Author: Brendan Gregg [Sydney, Australia] # # ToDo: # * enable this program to work on an 8-bit colour display # * improve plot wrapping # # 01-Apr-2004 Brendan Gregg Created this # 10-Apr-2004 " " Fixed redisplay, resizing # # --- Default Variables --- # max_x=300 # window size x max_y=200 # window size y colour_line=Red # line colour colour_text=DarkBlue # text colour colour_bg=White # background colour colour_border=LightGray # border colour delay1=50 # delay (ms), while reading delay2=750 # delay (ms), waiting high=1 # max y coord. on scale inc=1 # x inc per point field=0 # field to plot text="" # text label title="xplot" # window title ### Nicely exit trap 'delay1=$delay2; sleep 0.4; exit' 2 15 # # --- Parse Options --- # while (( $# != 0 )) do case "$1" in -h|--help) print -u2 " USAGE: $0 [-h] [-f field] [-d delim] [-hi num] [-inc num] [-x pixels] [-y pixels] [-tc colour] [-lc colour] [-bg colour] [-t text] [-T text]\n -h help -f field number (first is 0) -d field delimiter -hi y max scale value -inc x increment per value -x width (pixels) -y height (pixels) -tc text colour -lc line colour -br border colour -bg background colour -t text label for graph -T text title for window\n eg, vmstat 1 | $0 -f 21 -hi 100 -t \"idle\" # plot idle time vmstat 1 | $0 -f 3 -T \"swap free\" # plot swap free $0 -d : -f 2 -hi 65536 < /etc/passwd # plot UIDs (???) " exit 0 ;; -tc|-fg) colour_text=$2 shift ;; -x) max_x=$2 if (( max_x < 100 )); then print -u2 "ERROR: Width $max_x is too small\n" exit 1 fi shift ;; -y) max_y=$2 if (( max_y < 100 )); then print -u2 "ERROR: Height $max_y is too small\n" exit 1 fi shift ;; -f) field=$2 shift ;; -d) IFS=$2 shift ;; -hi) high=$2 shift ;; -inc) inc=$2 shift ;; -t) text=$2 shift ;; -T) title=$2 shift ;; -lc) colour_line=$2 shift ;; -br) colour_border=$2 shift ;; -bg) colour_bg=$2 shift ;; esac shift done # # --- Calculate scalable variables --- # (( draw_y = max_y - 2 )) # draw_y is the drawable size (( margin = draw_y / 4 - 4 )) # margin for text labels # # --- Create X11 window --- # XtInitialize TOP plot Plot $0 XtCreateManagedWidget FORM form XmForm $TOP \ resizePolicy:RESIZE_ANY dialogTitle:"$title" \ height:$max_y width:$max_x x:0 y:0 \ background:$colour_border foreground:$colour_border # # --- Initial panel values --- # y=0 value=0 # # --- Create panel --- # XtCreateManagedWidget DRAW1 draw1 XmDrawingArea $FORM \ topAttachment:ATTACH_FORM bottomAttachment:ATTACH_FORM \ leftAttachment:ATTACH_FORM rightAttachment:ATTACH_FORM \ x:0 y:0 background:$colour_bg marginHeight:0 # # --- Create text label --- # if [[ "$text" != "" ]]; then XtCreateManagedWidget LABEL1 label1 XmLabel $DRAW1 \ x:10 y:$margin background:$colour_bg foreground:$colour_text \ labelString:"$text" fi # # --- Create high label --- # (( high_x = max_x - 70 )) XtCreateManagedWidget HIGH1 high1 XmLabel $DRAW1 \ x:$high_x y:$margin foreground:$colour_text background:$colour_bg \ labelString:"$high" # # --- Fetch widget IDs --- # XtDisplay DISPLAY $FORM XSync $DISPLAY true XtRealizeWidget $TOP XtWindow WINDOW1 $DRAW1 # # --- Initial values --- # time=-1 old_x=0 (( x = -inc )) # # --- Redraw plot - clear --- # # This clears the plot by redrawing it using the background colour. # function redrawplot_clear { points=${#plot[*]} ### White out old plot i=0 while (( i < points )); do ### Calculate coordinates rvalue=${plot[$i]} (( old_rx = i * inc )) (( new_rx = i * inc + inc )) (( new_ry = draw_y - 1 - ((draw_y - 2) * rvalue / high) )) if (( i == 0 )); then old_ry=$new_ry fi ### Draw the line XDrawLine $DISPLAY $WINDOW1 \ -foreground $colour_bg \ -line_width 1 \ -line_style LineSolid \ $old_rx $old_ry $new_rx $new_ry old_ry=$new_ry (( i++ )) done } # # --- Redraw plot - solid --- # # This redraws the plot using the line colour. # function redrawplot_solid { points=${#plot[*]} ### Draw in new plot i=0 while (( i < points )); do ### Calculate coordinates rvalue=${plot[$i]} (( old_rx = i * inc )) (( new_rx = i * inc + inc )) (( new_ry = draw_y - 1 - ((draw_y - 2) * rvalue / high) )) if (( i == 0 )); then old_ry=$new_ry fi ### Draw the line XDrawLine $DISPLAY $WINDOW1 \ -foreground $colour_line \ -line_width 1 \ -line_style LineSolid \ $old_rx $old_ry $new_rx $new_ry old_ry=$new_ry (( i++ )) done XFlush $DISPLAY } # # --- Resize Plot function --- # function resizeplot { ### Clear old plot redrawplot_clear ### Fetch new size XtGetValues $DRAW1 width:max_x height:max_y (( high_x = max_x - 70 )) (( draw_y = max_y - 2 )) (( margin = draw_y / 4 - 4 )) ### Recalculate next starting y loc if (( x >= 0 )); then old_value=${plot[$time]} (( old_y = draw_y - 1 - ((draw_y - 2) * old_value / high) )) fi ### Draw new plot redrawplot_solid XtSetValues $HIGH1 x:$high_x y:$margin if [[ "$text" != "" ]]; then XtSetValues $LABEL1 y:$margin fi } # # --- Update graphs function --- # function update { ### Fetch new value line="" trap ':' 17 # Do nothing on signal 17 (sleep 0.3; kill -17 $$) & # Send 17 if we wait too long read line # This is now a timed read kill -9 $! 2> /dev/null # Zap the watchdog set -A Fields -- $line value=${Fields[$field]} ### Skip if value is not a number if [[ "$value" != [0-9.]* ]]; then ### Trigger next update if [[ "$value" == "" ]]; then # no data, wait a while XtAddTimeOut ID $delay2 update else # bad data, keep reading XtAddTimeOut ID $delay1 update fi return fi ### Increment x (( x += inc )) (( time++ )) if (( x > max_x )); then redrawplot_clear x=0 time=0 unset plot fi ### Save old value old=$value ### Check value if (( value > high )); then redrawplot_clear high=$value XtSetValues $HIGH1 labelString:"$value" XtSetValues $DRAW1 width:$max_x height:$draw_y redrawplot_solid if (( x > 0 )); then (( old_t = time - 1 )) (( old_y = draw_y - 1 - ((draw_y - 2) * plot[$old_t] / high) )) fi fi ### Calculate coordinates (( old_x = x )) (( new_x = x + inc )) (( new_y = draw_y - 1 - ((draw_y - 2) * value / high) )) if (( x == 0 )); then old_y=$new_y fi ### Draw the line XDrawLine $DISPLAY $WINDOW1 \ -foreground $colour_line \ -line_width 1 \ -line_style LineSolid \ $old_x $old_y $new_x $new_y ### save old values old_y=$new_y plot[$time]=$value ### Trigger next update XtAddTimeOut ID $delay1 update } # # --- Main --- # XtAddCallback $DRAW1 inputCallback redrawplot_solid XtAddCallback $DRAW1 exposeCallback redrawplot_solid XtAddCallback $DRAW1 resizeCallback resizeplot XtAddTimeOut ID $delay1 update XtMainLoop