#! /usr/bin/perl
# plot file ... - a command line interface for gnuplot
# (c) R.G. Della Valle 1996-2010

if( $#ARGV<0 ){
  print "plot      a command line interface for gnuplot\n\n";
  print "Usage:    plot [Options] Items\n\n";
  print "Options:  -o[file]      save plot to file\n";
  print "          -P[printer]   send plot to the printer\n";
  print "          -d[device]    set type of output device\n";
  print "          -t[Time]      set the visualization time\n";
  print "          -l[label,...] set labels for column 1,2...\n";
  print "Items:    'X,Y,plot'    set title for X, Y, plot\n";
  print "          min:max       set range for X, then Y\n";
  print "          File          read X,Y data from File\n";
  print "          y             plot column y vs column 1\n";
  print "          x,y           plot column y vs column x\n";
  print "          x,y1,y2,...   plot y1 vs x, y2 vs x, ...\n\n";
  print "Ranges of contiguous columns are represented as i-j.\n";
  print "Column 0 stays for the number 0,1,2... of the data.\n";
  print "Points are used for all columns by default. Lines or\n";
  print "lines+points are specified by - or + signs in front\n";
  print "of x (for all columns) or y (for that column only).\n";
  print "Options, titles, X range and Y ranges must appear in\n";
  print "the given order. Files and columns may be repeated.\n";
  print "Files to be plotted accumulate and remain in effect\n";
  print "for all sets of columns immediately following them.\n";
  print "Unless redirected, plot's output is piped to gnuplot.\n";
  exit;
}

#  Variables:
# $file      output file name (blank for no file)
# $printer   printer name (blank for default)
# $term      gnuplot's terminal for printing (default "postscript")
# @labels    array containing the list of column labels (if any)
# $time      visualization time in seconds (defaults 30 or 120)
# @f, $f     list of files to be plotted, current file
# @c, $c     list of column to be plotted, current column
# $DefStyle  default style (for all columns)
# $ColStyle  style for the current column only
# $comma     used to format the output, $comma is either "" or ","
# @l         array used to split the list of columns
# $t         temporary string used to build titles

# Argument starts with -o, get file name (blanck for "x.plot$$.ps" default)
# Argument starts with -P, get printer name (blanck for default printer)
# Argument starts with -d, get printer name (default PostScript, 18pt font)
# Argument starts with -t, set visualization time (default 120 seconds)
# Argument starts with -l, set column labels (default file and column)
$term = "postscript color";
while( $ARGV[0] =~ /^[+-]([oPdtl])(.*)/ ){
  shift;
  if( $1 eq 'o' ){ $file    = ( $2 ? $2 : "x.plot$$.ps" ) }
  if( $1 eq 'P' ){ $printer = ( $2 ? "-P$2" : " " ) }
  if( $1 eq 'd' ){ $term    = ( $2 ? $2 : $term ) }
  if( $1 eq 't' ){ $time    = ( $2 ? $2 : 120 ) }
  if( $1 eq 'l' ){ @labels  = split(',',$2) }
}

# Output to a tty and no -t given: pipe all output through gnuplot
if( $time || -t STDOUT ){ open( STDOUT, "| gnuplot" ) }

# Make gnuplot script, with the standard path
print "#! /usr/bin/gnuplot\n";

# If the first argument cannot be anything else, assume it is for titles
if( $ARGV[0] =~ /[,:;\`\'\"?!\#&%* (){}<>|^]/ &&
    $ARGV[0] =~ /[^,:0-9.e+-]/i               &&
    $ARGV[0] =~ /^([^,]*),?([^,]*),?(.*)$/    ){
  shift;
  print "set xlabel '$1'\n";
  print "set ylabel '$2'\n";
  print "set title  '$3'\n";
}

# This is the main "plot" statement for gnuplot
print "plot ";

# The next two arguments might be x and y ranges
if( $ARGV[0] =~ /^[0-9.e+-]*:[0-9.e+-]*$/i ){ print "[", shift, "] " }
if( $ARGV[0] =~ /^[0-9.e+-]*:[0-9.e+-]*$/i ){ print "[", shift, "] " }

# Main loop: all other arguments specify either columns or files
while ( $_ = shift ) {
  if( /^[+-]?[0-9][0-9,+-]*$/ ){ &cols() }
  else                         { &file() }
}
&flush();

# Make file, or hardcopy, or just pause (default 30 seconds)
if( $printer || $file ){
  $file = $file || "x.plot$$.ps";
  print "\nset term $term\n";
  print "set out '$file'\n";
  print "replot\n";
  if( $printer ){ print "! print $printer $file\n" }
} else {
  printf "\n  pause %d\n", ( $time ? $time : 30 );
}

#----------------------------------------------------------------------------
# style(default) - return "lines" or "linespoints" if $_ starts in "-" or "+"
sub style {
  if( s/^\-//    ){ return "lines" }
  elsif( s/^\+// ){ return "linespoints" }
  else            { return shift( @_ ) }
}

#----------------------------------------------------------------------------
# cols() - add all column pairs and styles in $_ to @c column list
sub cols {
  $DefStyle = &style("points");			 # Get default style
  s/^([1-9][0-9]*)$/1,$1/;                       # Turn y into 1,y

  # Expand i-j ranges, and propagate any "+" or "-" style of the first item
  while( s/([+-]?)(\d+)-(\d+)/$1 . join(",$1",($2..$3))/e ){};

  @l = split(',+',$_);                           # Split at commas
  foreach $_ ( @l[1..$#l] ){                     # Loop on columns
    $ColStyle = &style($DefStyle);               # Get column style
    push( @c, "$l[0]:$_ with $ColStyle" );       # Add x,y to @c
  }
}

#----------------------------------------------------------------------------
# file() - add file $_ to @f file list, flush @c and @l lists if both exist
sub file {
  if( @f && @c ){ &flush() }
  push( @f, $_ );
}

#----------------------------------------------------------------------------
# flush() - plot all accumulated column pairs and files, and flush both lists
sub flush {
  if( ! @c ){ push( @c, "1:2 with points" ) }	# Default column pair
  foreach $f ( @f ){				# For all files
    foreach $c ( @c ){				# For all column pairs
      $plot++;					# Count number of plots

      $c =~ /^([0-9]+:)([0-9]+)(.*)/; 		# Title is 'file i:j' for
      if( "$f $1" ne $l ){ $x = $l = "$f $1" }	# new file or new i ...
      else               { $x =      ""      }	# 'j' only otherwise

      if( @labels )				# Set column titles if any
           { $t = ( $plot-1<=$#labels ? "title '$labels[$plot-1]'": 'notitle' ) }
      else { $t = ( "title '$x$2'" ) }

      $t = "using $1$2 $t $3";		 	# columns title style

      if( $f =~ /\.(z|Z|gz)$/ )			# Compressed input file
        { $f = "< zcat $f" }			# ... uncompress with zcat

      print "$comma \\\n '$f' $t";	 	# file columns title style
      $comma = ",";				# Use "," after first plot

      $f = "";					# '' filename (reuse last)
    }
  }
  undef @f;					# Flush file and column lists
  undef @c;
}

