It is currently Sun May 20, 2018 3:20 pm

ASCII graphing

All times are UTC - 6 hours

Post new topic Reply to topic  [ 3 posts ] 
Author Message
 PostPosted: Fri Jul 09, 2010 1:43 pm   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
Here's a little something I wrote a while ago to graph some data on a text-only terminal.
Save it as graph.fnc and source it in the script you want to use it in.
Then just call the graph function as in the 'Usage' comment :)

## graph.fnc -- by Patsie
# Shell function that draws a graph with average line in ASCII
# The graph will have a width equal to the number of data points
# and a height equal to the first argument
# Usage: graph <height> <val1> [<val2> [<...>]]

function graph {
  height=$1; shift;

  echo "[email protected]" | awk -v height=$height 'BEGIN { }
    ## convert big numbers to short kilo/mega/giga etc numbers
    function pow1k(bignum) {

      # devide by 1000 until we have got a small enough number
      while (num>=1000) { metric++; num/=1000; }

      # get SI prefix (kilo, mega, giga, tera, peta, exa, zotta, yotta)
      si=substr(" KMGTPEZY", metric, 1);

      # get a division remainder to total our number of characters to a maximum of 4
      division=substr(bignum, length(num)+1, 3-length(num));

      # right align the output
      str=sprintf("%s%c%s", num, si, division);
      return(sprintf("% 4s", str));
    # get smallest, largest and total of all numbers
    for (x=2; x<=NF; x++) { tot+=$x; if ($x>max) max=$x; if ($x<min) min=$x; }

    # the difference between largest and smallest number is out working area
    if (diff==0) diff=1;                                # all numbers are the same?!
    # some fancy math to get the average of all numbers
    avgfull=int(((avg-min)*height/diff));               # average full
    avghalf=int(((avg-min)*height/diff)%1+0.5);         # average half

    # fill arrays bars
    for (x=1; x<=NF; x++) {
      v=$x-min;                                         # our value
      i=0;array[x]="";                                  # blank the array
      full=int((v*height/diff));                        # how many full?
      ttrd=int((v*height/diff)%1+0.333);                # 2/3rd full?
      otrd=int((v*height/diff)%1+0.666);                # 1/3rd full?
      while (i<full)   { array[x]=array[x]"O"; i++; }   # fill all fulls
      if    (ttrd>0)   { array[x]=array[x]"o"; i++; }   # fill 2/3rd
      else if (otrd>0) { array[x]=array[x]"."; i++; }   # or 1/3rd

      # average line or blank
      while (i<height) {                                # fill to the top
         if (i==avgfull)                                # with average line
           if (avghalf>0) array[x]=array[x]"-";
           else array[x]=array[x]"_";
         else array[x]=array[x]" ";                     # or mostly blanks

    # display output
    for (y=height; y>0; y--) {
      line=""; num="    ";                              # blank line and number
      if (y==avgfull+1) { num=pow1k(int(avg)); }        # show average number
      if (y==height)    { num=pow1k(max); }             # show maximum number
      if (y==1)         { num=pow1k(min); }             # show minimum number

      for (x=1; x<=NF; x++)                             # do for all data values
        line=line""substr(array[x],y,1);                # create line from arrays
      printf(" %s | %s | %s\n", num, line, num);        # display 1 line

And here's an example how to use it. It will plot a graph with random data and simulate 100 times getting a new data point.
Be sure that graph.fnc is in your current directory.

## -- by Patsie
# Draw a graph using an ASCII graph function
# The graph will have a width equal to the number of data points
# and a height equal to the first argument
# Usage:

## Should the graph move from right to left or vice versa

## include graphing function
. ./graph.fnc

## starting value, fill graph data
data=`for i in $(seq 60); do echo $((val+=RANDOM%1000-500)); done`


## repeat 100 times
while [ $((i++)) -lt 100 ]; do
  ## Go to top left corner and print date
  echo -e "\e[H`date`\n"

  ## Add new datapoint to graph
  if [ $right_to_left -eq 1 ]; then
    val=$(echo $data | awk '{print $NF}')
    data=$(echo $data $((val+=RANDOM%1000-500)) | cut -d' ' -f2-60)
    val=$(echo $data | awk '{print $1}')
    data=$(echo $((val+=RANDOM%1000-500)) $data | cut -d' ' -f1-59)

  ## Draw graph and wait
  graph 9 $data
  sleep 1

Removing the final 'sleep' makes it more interresting :)
Oh and ofcourse some sample output of the test script:
Fri Jul  9 21:45:06 CEST 2010

101K |                                                           O | 101K
     |                                                          OO |     
     |                                             o          OOOO |     
     | . .                                 o oo.  oOo..o.   oOOOOO |     
99K8 | O-OOo.----------.-------O.--------.OOoOOOOOOOOOOOO.OoOOOOOO | 99K8

 PostPosted: Sat Jul 17, 2010 8:50 am   
Site Admin
User avatar

Joined: Sun May 15, 2005 9:36 pm
Posts: 693
Location: Des Moines, Iowa
Thats pretty cool :)

 Profile WWW  
 PostPosted: Sat Jul 17, 2010 1:07 pm   
User avatar

Joined: Sun Jun 27, 2010 12:57 am
Posts: 192
Thank you. I hope you also like my Game of Life in the Sed & Awk forum. I'll try to post a couple of more scripts here that I'm fond of, so keep your eyes opened :)

Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 6 hours

Who is online

Users browsing this forum: No registered users and 5 guests

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  

BashScripts | Promote Your Page Too
Powered by phpBB © 2011 phpBB Group