diff CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/mummer-3.23/mummerplot @ 69:33d812a61356

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 17:55:14 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/mummer-3.23/mummerplot	Tue Mar 18 17:55:14 2025 -0400
@@ -0,0 +1,1602 @@
+#!/usr/bin/env perl
+
+################################################################################
+#   Programmer: Adam M Phillippy, The Institute for Genomic Research
+#         File: mummerplot
+#         Date: 01 / 08 / 03
+#               01 / 06 / 05 rewritten (v3.0)
+#  
+#        Usage:
+#    mummerplot  [options]  <match file>
+# 
+#                Try 'mummerplot -h' for more information.
+# 
+#      Purpose: To generate a gnuplot plot for the display of mummer, nucmer,
+#               promer, and show-tiling alignments.
+# 
+################################################################################
+
+use lib "/mnt/c/Users/crash/Documents/BobLiterman/CSP2_Galaxy/CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/mummer-3.23/scripts";
+use Foundation;
+use strict;
+use IO::Socket;
+
+my $BIN_DIR = "/mnt/c/Users/crash/Documents/BobLiterman/CSP2_Galaxy/CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/mummer-3.23";
+my $SCRIPT_DIR = "/mnt/c/Users/crash/Documents/BobLiterman/CSP2_Galaxy/CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/mummer-3.23/scripts";
+
+
+#================================================================= Globals ====#
+#-- terminal types
+my $X11    = "x11";
+my $PS     = "postscript";
+my $PNG    = "png";
+
+#-- terminal sizes
+my $SMALL  = "small";
+my $MEDIUM = "medium";
+my $LARGE  = "large";
+
+my %TERMSIZE =
+    (
+     $X11 => { $SMALL => 500, $MEDIUM => 700,  $LARGE => 900  }, # screen pix
+     $PS  => { $SMALL => 1,   $MEDIUM => 2,    $LARGE => 3    }, # pages
+     $PNG => { $SMALL => 800, $MEDIUM => 1024, $LARGE => 1400 }  # image pix
+     );
+
+#-- terminal format
+my $FFACE    = "Courier";
+my $FSIZE    = "8";
+my $TFORMAT  = "%.0f";
+my $MFORMAT  = "[%.0f, %.0f]";
+
+#-- output suffixes
+my $FILTER  = "filter";
+my $FWDPLOT = "fplot";
+my $REVPLOT = "rplot";
+my $HLTPLOT = "hplot";
+my $GNUPLOT = "gnuplot";
+
+my %SUFFIX =
+    (
+     $FILTER  => ".filter",
+     $FWDPLOT => ".fplot",
+     $REVPLOT => ".rplot",
+     $HLTPLOT => ".hplot",
+     $GNUPLOT => ".gp",
+     $PS      => ".ps",
+     $PNG     => ".png"
+     );
+
+
+#================================================================= Options ====#
+my $OPT_breaklen;                  # -b option
+my $OPT_color;                     # --[no]color option
+my $OPT_coverage;                  # --[no]coverage option
+my $OPT_filter;                    # -f option
+my $OPT_layout;                    # -l option
+my $OPT_prefix    = "out";         # -p option
+my $OPT_rv;                        # --rv option
+my $OPT_terminal  = $X11;          # -t option
+my $OPT_IdR;                       # -r option
+my $OPT_IdQ;                       # -q option
+my $OPT_IDRfile;                   # -R option
+my $OPT_IDQfile;                   # -Q option
+my $OPT_rport;                     # -rport option
+my $OPT_qport;                     # -qport option
+my $OPT_size      = $SMALL;        # -small, -medium, -large
+my $OPT_SNP;                       # -S option
+my $OPT_xrange;                    # -x option
+my $OPT_yrange;                    # -y option
+my $OPT_title;                     # -title option
+
+my $OPT_Mfile;                     # match file
+my $OPT_Dfile;                     # delta filter file
+my $OPT_Ffile;                     # .fplot output
+my $OPT_Rfile;                     # .rplot output
+my $OPT_Hfile;                     # .hplot output
+my $OPT_Gfile;                     # .gp output
+my $OPT_Pfile;                     # .ps .png output
+
+my $OPT_gpstatus;                  # gnuplot status
+
+my $OPT_ONLY_USE_FATTEST;          # Only use fattest alignment for layout
+
+
+#============================================================== Foundation ====#
+my $VERSION = '3.5';
+
+my $USAGE = qq~
+  USAGE: mummerplot  [options]  <match file>
+    ~;
+
+my $HELP = qq~
+  USAGE: mummerplot  [options]  <match file>
+
+  DESCRIPTION:
+    mummerplot generates plots of alignment data produced by mummer, nucmer,
+    promer or show-tiling by using the GNU gnuplot utility. After generating
+    the appropriate scripts and datafiles, mummerplot will attempt to run
+    gnuplot to generate the plot. If this attempt fails, a warning will be
+    output and the resulting .gp and .[frh]plot files will remain so that the
+    user may run gnuplot independently. If the attempt succeeds, either an x11
+    window will be spawned or an additional output file will be generated
+    (.ps or .png depending on the selected terminal). Feel free to edit the
+    resulting gnuplot script (.gp) and rerun gnuplot to change line thinkness,
+    labels, colors, plot size etc.
+
+  MANDATORY:
+    match file      Set the alignment input to 'match file'
+                    Valid inputs are from mummer, nucmer, promer and
+                    show-tiling (.out, .cluster, .delta and .tiling)
+
+  OPTIONS:
+    -b|breaklen     Highlight alignments with breakpoints further than
+                    breaklen nucleotides from the nearest sequence end
+    --[no]color     Color plot lines with a percent similarity gradient or
+                    turn off all plot color (default color by match dir)
+                    If the plot is very sparse, edit the .gp script to plot
+                    with 'linespoints' instead of 'lines'
+    -c
+    --[no]coverage  Generate a reference coverage plot (default for .tiling)
+    --depend        Print the dependency information and exit
+    -f
+    --filter        Only display .delta alignments which represent the "best"
+                    hit to any particular spot on either sequence, i.e. a
+                    one-to-one mapping of reference and query subsequences
+    -h
+    --help          Display help information and exit
+    -l
+    --layout        Layout a .delta multiplot in an intelligible fashion,
+                    this option requires the -R -Q options
+    --fat           Layout sequences using fattest alignment only
+    -p|prefix       Set the prefix of the output files (default '$OPT_prefix')
+    -rv             Reverse video for x11 plots
+    -r|IdR          Plot a particular reference sequence ID on the X-axis
+    -q|IdQ          Plot a particular query sequence ID on the Y-axis
+    -R|Rfile        Plot an ordered set of reference sequences from Rfile
+    -Q|Qfile        Plot an ordered set of query sequences from Qfile
+                    Rfile/Qfile Can either be the original DNA multi-FastA
+                    files or lists of sequence IDs, lens and dirs [ /+/-]
+    -r|rport        Specify the port to send reference ID and position on
+                    mouse double click in X11 plot window
+    -q|qport        Specify the port to send query IDs and position on mouse
+                    double click in X11 plot window
+    -s|size         Set the output size to small, medium or large
+                    --small --medium --large (default '$OPT_size')
+    -S
+    --SNP           Highlight SNP locations in each alignment
+    -t|terminal     Set the output terminal to x11, postscript or png
+                    --x11 --postscript --png (default '$OPT_terminal')
+    -t|title        Specify the gnuplot plot title (default none)
+    -x|xrange       Set the xrange for the plot '[min:max]'
+    -y|yrange       Set the yrange for the plot '[min:max]'
+    -V
+    --version       Display the version information and exit
+    ~;
+
+my @DEPEND =
+    (
+     "$SCRIPT_DIR/Foundation.pm",
+     "$BIN_DIR/delta-filter",
+     "$BIN_DIR/show-coords",
+     "$BIN_DIR/show-snps",
+     "gnuplot"
+     );
+
+my $tigr = new TIGR::Foundation
+    or die "ERROR: TIGR::Foundation could not be initialized\n";
+
+$tigr -> setVersionInfo ($VERSION);
+$tigr -> setUsageInfo ($USAGE);
+$tigr -> setHelpInfo ($HELP);
+$tigr -> addDependInfo (@DEPEND);
+
+
+#=========================================================== Function Decs ====#
+sub GetParseFunc( );
+
+sub ParseIDs($$);
+
+sub ParseDelta($);
+sub ParseCluster($);
+sub ParseMummer($);
+sub ParseTiling($);
+
+sub LayoutIDs($$);
+sub SpanXwY ($$$$$);
+
+sub PlotData($$$);
+sub WriteGP($$);
+sub RunGP( );
+sub ListenGP($$);
+
+sub ParseOptions( );
+
+
+#=========================================================== Function Defs ====#
+MAIN:
+{
+    my @aligns;                # (sR eR sQ eQ sim lenR lenQ idR idQ)
+    my %refs;                  # (id => (off, len, [1/-1]))
+    my %qrys;                  # (id => (off, len, [1/-1]))
+
+    #-- Get the command line options (sets OPT_ global vars)
+    ParseOptions( );
+
+
+    #-- Get the alignment type
+    my $parsefunc = GetParseFunc( );
+
+    if ( $parsefunc != \&ParseDelta &&
+         ($OPT_filter || $OPT_layout || $OPT_SNP) ) {
+        print STDERR "WARNING: -f -l -S only work with delta input\n";
+        undef $OPT_filter;
+        undef $OPT_layout;
+        undef $OPT_SNP;
+    }
+
+    #-- Parse the reference and query IDs
+    if    ( defined $OPT_IdR ) { $refs{$OPT_IdR} = [ 0, 0, 1 ]; }
+    elsif ( defined $OPT_IDRfile ) {
+        ParseIDs ($OPT_IDRfile, \%refs);
+    }
+
+    if    ( defined $OPT_IdQ ) { $qrys{$OPT_IdQ} = [ 0, 0, 1 ]; }
+    elsif ( defined $OPT_IDQfile ) {
+        ParseIDs ($OPT_IDQfile, \%qrys);
+    }
+
+
+    #-- Filter the alignments
+    if ( $OPT_filter || $OPT_layout ) {
+        print STDERR "Writing filtered delta file $OPT_Dfile\n";
+        system ("$BIN_DIR/delta-filter -r -q $OPT_Mfile > $OPT_Dfile")
+            and die "ERROR: Could not run delta-filter, $!\n";
+        if ( $OPT_filter ) { $OPT_Mfile = $OPT_Dfile; }
+    }
+
+
+    #-- Parse the alignment data
+    $parsefunc->(\@aligns);
+
+    
+    #-- Layout the alignment data if requested
+    if ( $OPT_layout ) {
+        if ( scalar (keys %refs) || scalar (keys %qrys) ) {
+            LayoutIDs (\%refs, \%qrys);
+        }
+        else {
+            print STDERR "WARNING: --layout option only works with -R or -Q\n";
+            undef $OPT_layout;
+        }
+    }
+
+
+    #-- Plot the alignment data
+    PlotData (\@aligns, \%refs, \%qrys);
+
+
+    #-- Write the gnuplot script
+    WriteGP (\%refs, \%qrys);
+
+
+    #-- Run gnuplot script and fork a clipboard listener
+    unless ( $OPT_gpstatus == -1 ) {
+
+        my $child = 1;
+        if ( $OPT_gpstatus == 0 && $OPT_terminal eq $X11 ) {
+            print STDERR "Forking mouse listener\n";
+            $child = fork;
+        }
+
+        #-- parent runs gnuplot
+        if ( $child ) {
+            RunGP( );
+            kill 1, $child;
+        }
+        #-- child listens to clipboard
+        elsif ( defined $child ) {
+            ListenGP(\%refs, \%qrys);
+        }
+        else {
+            print STDERR "WARNING: Could not fork mouse listener\n";
+        }
+    }
+
+    exit (0);
+}
+
+
+#------------------------------------------------------------ GetParseFunc ----#
+sub GetParseFunc ( )
+{
+    my $fref;
+
+    open (MFILE, "<$OPT_Mfile")
+        or die "ERROR: Could not open $OPT_Mfile, $!\n";
+
+    $_ = <MFILE>;
+    if ( !defined ) { die "ERROR: Could not read $OPT_Mfile, File is empty\n" }
+
+  SWITCH: {
+      #-- tiling
+      if ( /^>\S+ \d+ bases/ ) {
+          $fref = \&ParseTiling;
+          last SWITCH;
+      }
+
+      #-- mummer
+      if ( /^> \S+/ ) {
+          $fref = \&ParseMummer;
+          last SWITCH;
+      }
+
+      #-- nucmer/promer
+      if ( /^(\S+) (\S+)/ ) {
+          if ( ! defined $OPT_IDRfile ) {
+              $OPT_IDRfile = $1;
+          }
+          if ( ! defined $OPT_IDQfile ) {
+              $OPT_IDQfile = $2;
+          }
+
+          $_ = <MFILE>;
+          if ( (defined)  &&  (/^NUCMER$/  ||  /^PROMER$/) ) {
+              $_ = <MFILE>;   # sequence header
+              $_ = <MFILE>;   # alignment header
+              if ( !defined ) {
+                  $fref = \&ParseDelta;
+                  last SWITCH;
+              }
+              elsif ( /^\d+ \d+ \d+ \d+ \d+ \d+ \d+$/ ) {
+                  $fref = \&ParseDelta;
+                  last SWITCH;
+              }
+              elsif ( /^[ \-][1-3] [ \-][1-3]$/ ) {
+                  $fref = \&ParseCluster;
+                  last SWITCH;
+              }
+          }
+      }
+      
+      #-- default
+      die "ERROR: Could not read $OPT_Mfile, Unrecognized file type\n";
+  }
+
+    close (MFILE)
+        or print STDERR "WARNING: Trouble closing $OPT_Mfile, $!\n";
+
+    return $fref;
+}
+
+
+#---------------------------------------------------------------- ParseIDs ----#
+sub ParseIDs ($$)
+{
+    my $file = shift;
+    my $href = shift;
+
+    open (IDFILE, "<$file")
+        or print STDERR "WARNING: Could not open $file, $!\n";
+
+    my $dir;
+    my $aref;
+    my $isfasta;
+    my $offset = 0;
+    while ( <IDFILE> ) {
+        #-- Ignore blank lines
+        if ( /^\s*$/ ) { next; }
+
+        #-- FastA header
+        if ( /^>(\S+)/ ) {
+            if ( exists $href->{$1} ) {
+                print STDERR "WARNING: Duplicate sequence '$1' ignored\n";
+                undef $aref;
+                next;
+            }
+
+            if ( !$isfasta ) { $isfasta = 1; }
+            if ( defined $aref ) { $offset += $aref->[1] - 1; }
+
+            $aref = [ $offset, 0, 1 ];
+            $href->{$1} = $aref;
+            next;
+        }
+        
+        #-- FastA sequence
+        if ( $isfasta  &&  /^\S+$/ ) {
+            if ( defined $aref ) { $aref->[1] += (length) - 1; }
+            next;
+        }
+
+        #-- ID len dir
+        if ( !$isfasta  &&  /^(\S+)\s+(\d+)\s+([+-]?)$/ ) {
+            if ( exists $href->{$1} ) {
+                print STDERR "WARNING: Duplicate sequence '$1' ignored\n";
+                undef $aref;
+                next;
+            }
+
+            $dir = (defined $3 && $3 eq "-") ? -1 : 1;
+            $aref = [ $offset, $2, $dir ];
+            $offset += $2 - 1;
+            $href->{$1} = $aref;
+            next;
+        }
+
+        #-- default
+        print STDERR "WARNING: Could not parse $file\n$_";
+        undef %$href;
+        last;
+    }
+
+    close (IDFILE)
+        or print STDERR "WARNING: Trouble closing $file, $!\n";
+}
+
+
+#-------------------------------------------------------------- ParseDelta ----#
+sub ParseDelta ($)
+{
+    my $aref = shift;
+
+    print STDERR "Reading delta file $OPT_Mfile\n";
+
+    open (MFILE, "<$OPT_Mfile")
+        or die "ERROR: Could not open $OPT_Mfile, $!\n";
+
+    my @align;
+    my $ispromer;
+    my ($sim, $tot);
+    my ($lenR, $lenQ, $idR, $idQ);
+
+    $_ = <MFILE>;
+    $_ = <MFILE>;
+    $ispromer = /^PROMER/;
+
+    while ( <MFILE> ) {
+        #-- delta int
+        if ( /^([-]?\d+)$/ ) {
+            if ( $1 < 0 ) {
+                $tot ++;
+            }
+            elsif ( $1 == 0 ) {
+                $align[4] = ($tot - $sim) / $tot * 100.0;
+                push @$aref, [ @align ];
+                $tot = 0;
+            }
+            next;
+        }
+
+        #-- alignment header
+        if ( /^(\d+) (\d+) (\d+) (\d+) \d+ (\d+) \d+$/ ) {
+            if ( $tot == 0 ) {
+                @align = ($1, $2, $3, $4, 0, $lenR, $lenQ, $idR, $idQ);
+                $tot = abs($1 - $2) + 1;
+                $sim = $5;
+                if ( $ispromer ) { $tot /= 3.0; }
+                next;
+            }
+            #-- drop to default
+        }
+
+        #-- sequence header
+        if ( /^>(\S+) (\S+) (\d+) (\d+)$/ ) {
+            ($idR, $idQ, $lenR, $lenQ) = ($1, $2, $3, $4);
+            $tot = 0;
+            next;
+        }
+
+        #-- default
+        die "ERROR: Could not parse $OPT_Mfile\n$_";
+    }
+
+    close (MFILE)
+        or print STDERR "WARNING: Trouble closing $OPT_Mfile, $!\n";
+}
+
+
+#------------------------------------------------------------ ParseCluster ----#
+sub ParseCluster ($)
+{
+    my $aref = shift;
+
+    print STDERR "Reading cluster file $OPT_Mfile\n";
+
+    open (MFILE, "<$OPT_Mfile")
+        or die "ERROR: Could not open $OPT_Mfile, $!\n";
+
+    my @align;
+    my ($dR, $dQ, $len);
+    my ($lenR, $lenQ, $idR, $idQ);
+
+    $_ = <MFILE>;
+    $_ = <MFILE>;
+
+    while ( <MFILE> ) {
+        #-- match
+        if ( /^\s+(\d+)\s+(\d+)\s+(\d+)\s+\S+\s+\S+$/ ) {
+            @align = ($1, $1, $2, $2, 100, $lenR, $lenQ, $idR, $idQ);
+            $len = $3 - 1;
+            $align[1] += $dR == 1 ? $len : -$len;
+            $align[3] += $dQ == 1 ? $len : -$len;
+            push @$aref, [ @align ];
+            next;
+        }
+
+        #-- cluster header
+        if ( /^[ \-][1-3] [ \-][1-3]$/ ) {
+            $dR = /^-/ ? -1 : 1;
+            $dQ = /-[1-3]$/ ? -1 : 1;
+            next;
+        }
+
+        #-- sequence header
+        if ( /^>(\S+) (\S+) (\d+) (\d+)$/ ) {
+            ($idR, $idQ, $lenR, $lenQ) = ($1, $2, $3, $4);
+            next;
+        }
+
+        #-- default
+        die "ERROR: Could not parse $OPT_Mfile\n$_";
+    }
+
+    close (MFILE)
+        or print STDERR "WARNING: Trouble closing $OPT_Mfile, $!\n";
+}
+
+
+#------------------------------------------------------------- ParseMummer ----#
+sub ParseMummer ($)
+{
+    my $aref = shift;
+
+    print STDERR "Reading mummer file $OPT_Mfile (use mummer -c)\n";
+
+    open (MFILE, "<$OPT_Mfile")
+        or die "ERROR: Could not open $OPT_Mfile, $!\n";
+
+    my @align;
+    my ($dQ, $len);
+    my ($lenQ, $idQ);
+
+    while ( <MFILE> ) {
+        #-- 3 column match
+        if ( /^\s+(\d+)\s+(\d+)\s+(\d+)$/ ) {
+            @align = ($1, $1, $2, $2, 100, 0, $lenQ, "REF", $idQ);
+            $len = $3 - 1;
+            $align[1] += $len;
+            $align[3] += $dQ == 1 ? $len : -$len;
+            push @$aref, [ @align ];
+            next;
+        }
+
+        #-- 4 column match
+        if ( /^\s+(\S+)\s+(\d+)\s+(\d+)\s+(\d+)$/ ) {
+            @align = ($2, $2, $3, $3, 100, 0, $lenQ, $1, $idQ);
+            $len = $4 - 1;
+            $align[1] += $len;
+            $align[3] += $dQ == 1 ? $len : -$len;
+            push @$aref, [ @align ];
+            next;
+        }
+
+        #-- sequence header
+        if ( /^> (\S+)/ ) {
+            $idQ = $1;
+            $dQ = /^> \S+ Reverse/ ? -1 : 1;
+            $lenQ = /Len = (\d+)/ ? $1 : 0;
+            next;
+        }
+
+        #-- default
+        die "ERROR: Could not parse $OPT_Mfile\n$_";
+    }
+
+    close (MFILE)
+        or print STDERR "WARNING: Trouble closing $OPT_Mfile, $!\n";
+}
+
+
+#------------------------------------------------------------- ParseTiling ----#
+sub ParseTiling ($)
+{
+    my $aref = shift;
+
+    print STDERR "Reading tiling file $OPT_Mfile\n";
+
+    open (MFILE, "<$OPT_Mfile")
+        or die "ERROR: Could not open $OPT_Mfile, $!\n";
+
+    my @align;
+    my ($dR, $dQ, $len);
+    my ($lenR, $lenQ, $idR, $idQ);
+
+    while ( <MFILE> ) {
+        #-- tile
+        if ( /^(\S+)\s+\S+\s+\S+\s+(\d+)\s+\S+\s+(\S+)\s+([+-])\s+(\S+)$/ ) {
+            @align = ($1, $1, 1, 1, $3, $lenR, $2, $idR, $5);
+            $len = $2 - 1;
+            $align[1] += $len;
+            $align[($4 eq "-" ? 2 : 3)] += $len;
+            push @$aref, [ @align ];
+            next;
+        }
+
+        #-- sequence header
+        if ( /^>(\S+) (\d+) bases$/ ) {
+            ($idR, $lenR) = ($1, $2);
+            next;
+        }
+
+        #-- default
+        die "ERROR: Could not parse $OPT_Mfile\n$_";
+    }
+
+    close (MFILE)
+        or print STDERR "WARNING: Trouble closing $OPT_Mfile, $!\n";
+
+    if ( ! defined $OPT_coverage ) { $OPT_coverage = 1; }
+}
+
+
+#--------------------------------------------------------------- LayoutIDs ----#
+# For each reference and query sequence, find the set of alignments that
+# produce the heaviest (both in non-redundant coverage and percent
+# identity) alignment subset of each sequence using a modified version
+# of the longest increasing subset algorithm. Let R be the union of all
+# reference LIS subsets, and Q be the union of all query LIS
+# subsets. Let S be the intersection of R and Q. Using this LIS subset,
+# recursively span reference and query sequences by their smaller
+# counterparts until all spanning sequences have been placed. The goal
+# is to cluster all the "major" alignment information along the main
+# diagonal for easy viewing and interpretation.
+sub LayoutIDs ($$)
+{
+    my $rref = shift;
+    my $qref = shift;
+
+    my %rc;          # chains of qry seqs needed to span each ref
+    my %qc;          # chains of ref seqs needed to span each qry
+    #  {idR} -> [ placed, len, {idQ} -> [ \slope, \loR, \hiR, \loQ, \hiQ ] ]
+    #  {idQ} -> [ placed, len, {idR} -> [ \slope, \loQ, \hiQ, \loR, \hiR ] ]
+
+    my @rl;          # oo of ref seqs
+    my @ql;          # oo of qry seqs
+    #  [ [idR, slope] ]
+    #  [ [idQ, slope] ]
+
+    #-- get the filtered alignments
+    open (BTAB, "$BIN_DIR/show-coords -B $OPT_Dfile |")
+        or die "ERROR: Could not open show-coords pipe, $!\n";
+
+    my @align;
+    my ($sR, $eR, $sQ, $eQ, $lenR, $lenQ, $idR, $idQ);
+    my ($loR, $hiR, $loQ, $hiQ);
+    my ($dR, $dQ, $slope);
+    while ( <BTAB> ) {
+        chomp;
+        @align = split "\t";
+        if ( scalar @align != 21 ) {
+            die "ERROR: Could not read show-coords pipe, invalid btab format\n";
+        }
+
+        $sR   = $align[8];   $eR   = $align[9];
+        $sQ   = $align[6];   $eQ   = $align[7];
+        $lenR = $align[18];  $lenQ = $align[2];
+        $idR  = $align[5];   $idQ  = $align[0];
+
+        #-- skip it if not on include list
+        if ( !exists $rref->{$idR} || !exists $qref->{$idQ} ) { next; }
+
+        #-- get orientation of both alignments and alignment slope
+        $dR = $sR < $eR ? 1 : -1;
+        $dQ = $sQ < $eQ ? 1 : -1;
+        $slope = $dR == $dQ ? 1 : -1;
+
+        #-- get lo's and hi's
+        $loR = $dR == 1 ? $sR : $eR;
+        $hiR = $dR == 1 ? $eR : $sR;
+
+        $loQ = $dQ == 1 ? $sQ : $eQ;
+        $hiQ = $dQ == 1 ? $eQ : $sQ;
+
+        if ($OPT_ONLY_USE_FATTEST)
+        {
+          #-- Check to see if there is another better alignment
+          if (exists $qc{$idQ})
+          {
+            my ($oldR) = keys %{$qc{$idQ}[2]};
+            my $val = $qc{$idQ}[2]{$oldR};
+
+            if (${$val->[4]} - ${$val->[3]} > $hiR - $loR)
+            {
+              #-- Old alignment is better, skip this one
+              next;
+            }
+            else
+            {
+              #-- This alignment is better, prune old alignment
+              delete $rc{$oldR}[2]{$idQ};
+              delete $qc{$idQ};
+            }
+          }
+        }
+
+        #-- initialize
+        if ( !exists $rc{$idR} ) { $rc{$idR} = [ 0, $lenR, { } ]; }
+        if ( !exists $qc{$idQ} ) { $qc{$idQ} = [ 0, $lenQ, { } ]; }
+
+        #-- if no alignments for these two exist OR
+        #-- this alignment is bigger than the current
+        if ( !exists $rc{$idR}[2]{$idQ} || !exists $qc{$idQ}[2]{$idR} ||
+             $hiR - $loR >
+             ${$rc{$idR}[2]{$idQ}[2]} - ${$rc{$idR}[2]{$idQ}[1]} ) {
+
+            #-- rc and qc reference these anonymous values
+            my $aref = [ $slope, $loR, $hiR, $loQ, $hiQ ];
+
+            #-- rc is ordered [ slope, loR, hiR, loQ, hiQ ]
+            #-- qc is ordered [ slope, loQ, hiQ, loR, hiR ]
+            $rc{$idR}[2]{$idQ}[0] = $qc{$idQ}[2]{$idR}[0] = \$aref->[0];
+            $rc{$idR}[2]{$idQ}[1] = $qc{$idQ}[2]{$idR}[3] = \$aref->[1];
+            $rc{$idR}[2]{$idQ}[2] = $qc{$idQ}[2]{$idR}[4] = \$aref->[2];
+            $rc{$idR}[2]{$idQ}[3] = $qc{$idQ}[2]{$idR}[1] = \$aref->[3];
+            $rc{$idR}[2]{$idQ}[4] = $qc{$idQ}[2]{$idR}[2] = \$aref->[4];
+        }
+    }
+
+    close (BTAB)
+        or print STDERR "WARNING: Trouble closing show-coords pipe, $!\n";
+
+    #-- recursively span sequences to generate the layout
+    foreach $idR ( sort { $rc{$b}[1] <=> $rc{$a}[1] } keys %rc ) {
+        SpanXwY ($idR, \%rc, \@rl, \%qc, \@ql);
+    }
+
+    #-- undefine the current offsets
+    foreach $idR ( keys %{$rref} ) { undef $rref->{$idR}[0]; }
+    foreach $idQ ( keys %{$qref} ) { undef $qref->{$idQ}[0]; }
+
+    #-- redefine the offsets according to the new layout
+    my $roff = 0;
+    foreach my $r ( @rl ) {
+        $idR = $r->[0];
+        $rref->{$idR}[0] = $roff;
+        $rref->{$idR}[2] = $r->[1];
+        $roff += $rref->{$idR}[1] - 1;
+    }
+    #-- append the guys left out of the layout
+    foreach $idR ( keys %{$rref} ) {
+        if ( !defined $rref->{$idR}[0] ) {
+            $rref->{$idR}[0] = $roff;
+            $roff += $rref->{$idR}[1] - 1;
+        }
+    }
+
+    #-- redefine the offsets according to the new layout
+    my $qoff = 0;
+    foreach my $q ( @ql ) {
+        $idQ = $q->[0];
+        $qref->{$idQ}[0] = $qoff;
+        $qref->{$idQ}[2] = $q->[1];
+        $qoff += $qref->{$idQ}[1] - 1;
+    }
+    #-- append the guys left out of the layout
+    foreach $idQ ( keys %{$qref} ) {
+        if ( !defined $qref->{$idQ}[0] ) {
+            $qref->{$idQ}[0] = $qoff;
+            $qoff += $qref->{$idQ}[1] - 1;
+        }
+    }
+}
+
+
+#----------------------------------------------------------------- SpanXwY ----#
+sub SpanXwY ($$$$$) {
+    my $x   = shift;   # idX
+    my $xcr = shift;   # xc ref
+    my $xlr = shift;   # xl ref
+    my $ycr = shift;   # yc ref
+    my $ylr = shift;   # yl ref
+
+    my @post;
+    foreach my $y ( sort { ${$xcr->{$x}[2]{$a}[1]} <=> ${$xcr->{$x}[2]{$b}[1]} }
+                    keys %{$xcr->{$x}[2]} ) {
+
+        #-- skip if already placed (RECURSION BASE)
+        if ( $ycr->{$y}[0] ) { next; }
+        else { $ycr->{$y}[0] = 1; }
+
+        #-- get len and slope info for y
+        my $len = $ycr->{$y}[1];
+        my $slope = ${$xcr->{$x}[2]{$y}[0]};
+
+        #-- if we need to flip, reverse complement all y records
+        if ( $slope == -1 ) {
+            foreach my $xx ( keys %{$ycr->{$y}[2]} ) {
+                ${$ycr->{$y}[2]{$xx}[0]} *= -1;
+
+                my $loy = ${$ycr->{$y}[2]{$xx}[1]};
+                my $hiy = ${$ycr->{$y}[2]{$xx}[2]};
+                ${$ycr->{$y}[2]{$xx}[1]} = $len - $hiy + 1;
+                ${$ycr->{$y}[2]{$xx}[2]} = $len - $loy + 1;
+            }
+        }
+
+        #-- place y
+        push @{$ylr}, [ $y, $slope ];
+
+        #-- RECURSE if y > x, else save for later
+        if ( $len > $xcr->{$x}[1] ) { SpanXwY ($y, $ycr, $ylr, $xcr, $xlr); }
+        else { push @post, $y; }
+    }
+
+    #-- RECURSE for all y < x
+    foreach my $y ( @post ) { SpanXwY ($y, $ycr, $ylr, $xcr, $xlr); }
+}
+
+
+#---------------------------------------------------------------- PlotData ----#
+sub PlotData ($$$)
+{
+    my $aref = shift;
+    my $rref = shift;
+    my $qref = shift;
+
+    print STDERR "Writing plot files $OPT_Ffile, $OPT_Rfile",
+    (defined $OPT_Hfile ? ", $OPT_Hfile\n" : "\n");
+
+    open (FFILE, ">$OPT_Ffile")
+        or die "ERROR: Could not open $OPT_Ffile, $!\n";
+    print FFILE "#-- forward hits sorted by %sim\n0 0 0\n0 0 0\n\n\n";
+
+    open (RFILE, ">$OPT_Rfile")
+        or die "ERROR: Could not open $OPT_Rfile, $!\n";
+    print RFILE "#-- reverse hits sorted by %sim\n0 0 0\n0 0 0\n\n\n";
+
+    if ( defined $OPT_Hfile ) {
+        open (HFILE, ">$OPT_Hfile")
+            or die "ERROR: Could not open $OPT_Hfile, $!\n";
+        print HFILE "#-- highlighted hits sorted by %sim\n0 0 0\n0 0 0\n\n\n";
+    }
+
+    my $fh;
+    my $align;
+    my $isplotted;
+    my $ismultiref;
+    my $ismultiqry;
+    my ($plenR, $plenQ, $pidR, $pidQ);
+
+    #-- for each alignment sorted by ascending identity
+    foreach $align ( sort { $a->[4] <=> $b->[4] } @$aref ) {
+
+        my ($sR, $eR, $sQ, $eQ, $sim, $lenR, $lenQ, $idR, $idQ) = @$align;
+
+        if ( ! defined $pidR ) {
+            ($plenR, $plenQ, $pidR, $pidQ) = ($lenR, $lenQ, $idR, $idQ);
+        }
+
+        #-- set the sequence offset, length, direction, etc...
+        my ($refoff, $reflen, $refdir);
+        my ($qryoff, $qrylen, $qrydir);
+
+        if ( (%$rref) ) {
+            #-- skip reference sequence or set atts from hash
+            if ( !exists ($rref->{$idR}) ) { next; }
+            else { ($refoff, $reflen, $refdir) = @{$rref->{$idR}}; }
+        }
+        else {
+            #-- no reference hash, so default atts
+            ($refoff, $reflen, $refdir) = (0, $lenR, 1);
+        }
+
+        if ( (%$qref) ) {
+            #-- skip query sequence or set atts from hash
+            if ( !exists ($qref->{$idQ}) ) { next; }
+            else { ($qryoff, $qrylen, $qrydir) = @{$qref->{$idQ}}; }
+        }
+        else {
+            #-- no query hash, so default atts
+            ($qryoff, $qrylen, $qrydir) = (0, $lenQ, 1);
+        }
+
+        #-- get the orientation right
+        if ( $refdir == -1 ) {
+            $sR = $reflen - $sR + 1;
+            $eR = $reflen - $eR + 1;
+        }
+        if ( $qrydir == -1 ) {
+            $sQ = $qrylen - $sQ + 1;
+            $eQ = $qrylen - $eQ + 1;
+        }
+
+        #-- forward file, reverse file, highlight file
+        my @fha;
+
+        if ( defined $OPT_breaklen &&
+             ( ($sR - 1 > $OPT_breaklen &&
+                $sQ - 1 > $OPT_breaklen &&
+                $reflen - $sR > $OPT_breaklen &&
+                $qrylen - $sQ > $OPT_breaklen)
+               ||
+               ($eR - 1 > $OPT_breaklen &&
+                $eQ - 1 > $OPT_breaklen &&
+                $reflen - $eR > $OPT_breaklen &&
+                $qrylen - $eQ > $OPT_breaklen) ) ) {
+            push @fha, \*HFILE;
+        }
+
+        push @fha, (($sR < $eR) == ($sQ < $eQ) ? \*FFILE : \*RFILE);
+
+        #-- plot it
+        $sR += $refoff; $eR += $refoff;
+        $sQ += $qryoff; $eQ += $qryoff;
+
+        if ( $OPT_coverage ) {
+            foreach $fh ( @fha ) {
+                print $fh
+                    "$sR 10 $sim\n", "$eR 10 $sim\n\n\n",
+                    "$sR $sim 0\n", "$eR $sim 0\n\n\n";
+            }
+        }
+        else {
+            foreach $fh ( @fha ) {
+                print $fh "$sR $sQ $sim\n", "$eR $eQ $sim\n\n\n";
+            }
+        }            
+
+        #-- set some flags
+        if ( !$ismultiref && $idR ne $pidR ) { $ismultiref = 1; }
+        if ( !$ismultiqry && $idQ ne $pidQ ) { $ismultiqry = 1; }
+        if ( !$isplotted ) { $isplotted = 1; }
+    }
+
+
+    #-- highlight the SNPs
+    if ( defined $OPT_SNP ) {
+
+        print STDERR "Determining SNPs from sequence and alignment data\n";
+
+        open (SNPS, "$BIN_DIR/show-snps -H -T -l $OPT_Mfile |")
+            or die "ERROR: Could not open show-snps pipe, $!\n";
+
+        my @snps;
+        my ($pR, $pQ, $lenR, $lenQ, $idR, $idQ);
+        while ( <SNPS> ) {
+            chomp;
+            @snps = split "\t";
+            if ( scalar @snps != 14 ) {
+                die "ERROR: Could not read show-snps pipe, invalid format\n";
+            }
+
+            $pR   = $snps[0];   $pQ   = $snps[3];
+            $lenR = $snps[8];   $lenQ = $snps[9];
+            $idR  = $snps[12];  $idQ  = $snps[13];
+
+            #-- set the sequence offset, length, direction, etc...
+            my ($refoff, $reflen, $refdir);
+            my ($qryoff, $qrylen, $qrydir);
+            
+            if ( (%$rref) ) {
+                #-- skip reference sequence or set atts from hash
+                if ( !exists ($rref->{$idR}) ) { next; }
+                else { ($refoff, $reflen, $refdir) = @{$rref->{$idR}}; }
+            }
+            else {
+                #-- no reference hash, so default atts
+                ($refoff, $reflen, $refdir) = (0, $lenR, 1);
+            }
+            
+            if ( (%$qref) ) {
+                #-- skip query sequence or set atts from hash
+                if ( !exists ($qref->{$idQ}) ) { next; }
+                else { ($qryoff, $qrylen, $qrydir) = @{$qref->{$idQ}}; }
+            }
+            else {
+                #-- no query hash, so default atts
+                ($qryoff, $qrylen, $qrydir) = (0, $lenQ, 1);
+            }
+
+            #-- get the orientation right
+            if ( $refdir == -1 ) { $pR = $reflen - $pR + 1; }
+            if ( $qrydir == -1 ) { $pQ = $qrylen - $pQ + 1; }
+
+            #-- plot it
+            $pR += $refoff;
+            $pQ += $qryoff;
+
+            if ( $OPT_coverage ) {
+                print HFILE "$pR 10 0\n", "$pR 10 0\n\n\n",
+            }
+            else {
+                print HFILE "$pR $pQ 0\n", "$pR $pQ 0\n\n\n";
+            }            
+        }
+
+        close (SNPS)
+            or print STDERR "WARNING: Trouble closing show-snps pipe, $!\n";
+    }
+
+
+    close (FFILE)
+        or print STDERR "WARNING: Trouble closing $OPT_Ffile, $!\n";
+
+    close (RFILE)
+        or print STDERR "WARNING: Trouble closing $OPT_Rfile, $!\n";
+
+    if ( defined $OPT_Hfile ) {
+        close (HFILE)
+            or print STDERR "WARNING: Trouble closing $OPT_Hfile, $!\n";
+    }
+
+
+    if ( !(%$rref) ) {
+        if ( $ismultiref ) {
+            print STDERR
+                "WARNING: Multiple ref sequences overlaid, try -R or -r\n";
+        }
+        elsif ( defined $pidR ) {
+            $rref->{$pidR} = [ 0, $plenR, 1 ];
+        }
+    }
+
+    if ( !(%$qref) ) {
+        if ( $ismultiqry && !$OPT_coverage ) {
+            print STDERR
+                "WARNING: Multiple qry sequences overlaid, try -Q, -q or -c\n";
+        }
+        elsif ( defined $pidQ ) {
+            $qref->{$pidQ} = [ 0, $plenQ, 1 ];
+        }
+    }
+
+    if ( !$isplotted ) {
+        die "ERROR: No alignment data to plot\n";
+    }
+}
+
+
+#----------------------------------------------------------------- WriteGP ----#
+sub WriteGP ($$)
+{
+    my $rref = shift;
+    my $qref = shift;
+
+    print STDERR "Writing gnuplot script $OPT_Gfile\n";
+
+    open (GFILE, ">$OPT_Gfile")
+        or die "ERROR: Could not open $OPT_Gfile, $!\n";
+
+    my ($FWD, $REV, $HLT) = (1, 2, 3);
+    my $SIZE = $TERMSIZE{$OPT_terminal}{$OPT_size};
+
+    #-- terminal specific stuff
+    my ($P_TERM, $P_SIZE, %P_PS, %P_LW);
+    foreach ( $OPT_terminal ) {
+        /^$X11/    and do {
+            $P_TERM = $OPT_gpstatus == 0 ?
+                "$X11 font \"$FFACE,$FSIZE\"" : "$X11";
+
+            %P_PS = ( $FWD => 1.0, $REV => 1.0, $HLT => 1.0 );
+
+            %P_LW = $OPT_coverage || $OPT_color ?
+                ( $FWD => 3.0, $REV => 3.0, $HLT => 3.0 ) :
+                ( $FWD => 2.0, $REV => 2.0, $HLT => 2.0 );
+
+            $P_SIZE = $OPT_coverage ?
+                "set size 1,1" :
+                "set size 1,1";
+
+            last;
+        };
+
+        /^$PS/     and do {
+            $P_TERM = defined $OPT_color && $OPT_color == 0 ?
+                "$PS monochrome" : "$PS color";
+            $P_TERM .= $OPT_gpstatus == 0 ?
+                " solid \"$FFACE\" $FSIZE" : " solid \"$FFACE\" $FSIZE";
+
+            %P_PS = ( $FWD => 0.5, $REV => 0.5, $HLT => 0.5 );
+
+            %P_LW = $OPT_coverage || $OPT_color ?
+                ( $FWD => 4.0, $REV => 4.0, $HLT => 4.0 ) :
+                ( $FWD => 2.0, $REV => 2.0, $HLT => 2.0 );
+
+            $P_SIZE = $OPT_coverage ?
+                "set size ".(1.0 * $SIZE).",".(0.5 * $SIZE) :
+                "set size ".(1.0 * $SIZE).",".(1.0 * $SIZE);
+
+            last;
+        };
+
+        /^$PNG/    and do {
+            $P_TERM = $OPT_gpstatus == 0 ?
+                "$PNG tiny size $SIZE,$SIZE" : "$PNG small";
+            if ( defined $OPT_color && $OPT_color == 0 ) {
+                $P_TERM .= " xffffff x000000 x000000";
+                $P_TERM .= " x000000 x000000 x000000";
+                $P_TERM .= " x000000 x000000 x000000";
+            }
+            
+            %P_PS = ( $FWD => 1.0, $REV => 1.0, $HLT => 1.0 );
+
+            %P_LW = $OPT_coverage || $OPT_color ?
+                ( $FWD => 3.0, $REV => 3.0, $HLT => 3.0 ) :
+                ( $FWD => 3.0, $REV => 3.0, $HLT => 3.0 );
+
+            $P_SIZE = $OPT_coverage ?
+                "set size 1,.375" :
+                "set size 1,1";
+
+            last;
+        };
+
+        die "ERROR: Don't know how to initialize terminal, $OPT_terminal\n";
+    }
+
+    #-- plot commands
+    my ($P_WITH, $P_FORMAT, $P_LS, $P_KEY, %P_PT, %P_LT);
+
+    %P_PT = ( $FWD => 6, $REV => 6, $HLT => 6 );
+    %P_LT = defined $OPT_Hfile ?
+        ( $FWD => 2, $REV => 2, $HLT => 1 ) :
+        ( $FWD => 1, $REV => 3, $HLT => 2 );
+
+    $P_WITH = $OPT_coverage || $OPT_color ? "w l" : "w lp";
+
+    $P_FORMAT = "set format \"$TFORMAT\"";
+    if ( $OPT_gpstatus == 0 ) {
+        $P_LS = "set style line";
+        $P_KEY = "unset key";
+        $P_FORMAT .= "\nset mouse format \"$TFORMAT\"";
+        $P_FORMAT .= "\nset mouse mouseformat \"$MFORMAT\"";
+        $P_FORMAT .= "\nif(GPVAL_VERSION < 5) set mouse clipboardformat \"$MFORMAT\"";
+    }
+    else {
+        $P_LS = "set linestyle";
+        $P_KEY = "set nokey";
+    }
+
+
+    my @refk = keys (%$rref);
+    my @qryk = keys (%$qref);
+    my ($xrange, $yrange);
+    my ($xlabel, $ylabel);
+    my ($tic, $dir);
+    my $border = 0;
+
+    #-- terminal header and output
+    print GFILE "set terminal $P_TERM\n";
+
+    if ( defined $OPT_Pfile ) {
+        print GFILE "set output \"$OPT_Pfile\"\n";
+    }
+
+    if ( defined $OPT_title ) {
+        print GFILE "set title \"$OPT_title\"\n";
+    }
+
+    #-- set tics, determine labels, ranges (ref)
+    if ( scalar (@refk) == 1 ) {
+        $xlabel = $refk[0];
+        $xrange = $rref->{$xlabel}[1];
+    }
+    else {
+        $xrange = 0;
+        print GFILE "set xtics rotate \( \\\n";
+        foreach $xlabel ( sort { $rref->{$a}[0] <=> $rref->{$b}[0] } @refk ) {
+            $xrange += $rref->{$xlabel}[1];
+            $tic = $rref->{$xlabel}[0] + 1;
+            $dir = ($rref->{$xlabel}[2] == 1) ? "" : "*";
+            print GFILE " \"$dir$xlabel\" $tic, \\\n";
+        }
+        print GFILE " \"\" $xrange \\\n\)\n";
+        $xlabel = "REF";
+    }
+    if ( $xrange == 0 ) { $xrange = "*"; }
+
+    #-- set tics, determine labels, ranges (qry)
+    if ( $OPT_coverage ) {
+        $ylabel = "%SIM";
+        $yrange = 110;
+    }
+    elsif ( scalar (@qryk) == 1 ) {
+        $ylabel = $qryk[0];
+        $yrange = $qref->{$ylabel}[1];
+    }
+    else {
+        $yrange = 0;
+        print GFILE "set ytics \( \\\n";
+        foreach $ylabel ( sort { $qref->{$a}[0] <=> $qref->{$b}[0] } @qryk ) {
+            $yrange += $qref->{$ylabel}[1];
+            $tic = $qref->{$ylabel}[0] + 1;
+            $dir = ($qref->{$ylabel}[2] == 1) ? "" : "*";
+            print GFILE " \"$dir$ylabel\" $tic, \\\n";
+        }
+        print GFILE " \"\" $yrange \\\n\)\n";
+        $ylabel = "QRY";
+    }
+    if ( $yrange == 0 ) { $yrange = "*"; }
+
+    #-- determine borders
+    if ( $xrange ne "*" && scalar (@refk) == 1 ) { $border |= 10; }
+    if ( $yrange ne "*" && scalar (@qryk) == 1 ) { $border |= 5; }
+    if ( $OPT_coverage ) { $border |= 5; }
+
+    #-- grid, labels, border
+    print GFILE
+        "$P_SIZE\n",
+        "set grid\n",
+        "$P_KEY\n",
+        "set border $border\n",
+        "set tics scale 0\n",
+        "set xlabel \"$xlabel\"\n",
+        "set ylabel \"$ylabel\"\n",
+        "$P_FORMAT\n";
+
+    #-- ranges
+    if ( defined $OPT_xrange ) { print GFILE "set xrange $OPT_xrange\n"; }
+    else                       { print GFILE "set xrange [1:$xrange]\n"; }
+
+    if ( defined $OPT_yrange ) { print GFILE "set yrange $OPT_yrange\n"; }
+    else                       { print GFILE "set yrange [1:$yrange]\n"; }
+
+    #-- if %sim plot
+    if ( $OPT_color ) {
+        print GFILE
+            "set zrange [0:100]\n",
+            "set colorbox default\n",
+            "set cblabel \"%similarity\"\n",
+            "set cbrange [0:100]\n",
+            "set cbtics 20\n",
+            "set pm3d map\n",
+            "set palette model RGB defined ( \\\n",
+            "  0 \"#000000\", \\\n",
+            "  4 \"#DD00DD\", \\\n",
+            "  6 \"#0000DD\", \\\n",
+            "  7 \"#00DDDD\", \\\n",
+            "  8 \"#00DD00\", \\\n",
+            "  9 \"#DDDD00\", \\\n",
+            " 10 \"#DD0000\"  \\\n)\n";
+    }
+
+    foreach my $s ( ($FWD, $REV, $HLT) ) {
+        my $ss = "$P_LS $s ";
+        $ss .= $OPT_color ? " palette" : " lt $P_LT{$s}";
+        $ss .= " lw $P_LW{$s}";
+        if ( ! $OPT_coverage || $s == $HLT ) {
+            $ss .= " pt $P_PT{$s} ps $P_PS{$s}";
+        }
+        print GFILE "$ss\n";
+    }
+
+    #-- plot it
+    print GFILE
+        ($OPT_color ? "splot \\\n" : "plot \\\n");
+    print GFILE
+        " \"$OPT_Ffile\" title \"FWD\" $P_WITH ls $FWD, \\\n",
+        " \"$OPT_Rfile\" title \"REV\" $P_WITH ls $REV",
+        (! defined $OPT_Hfile ? "\n" :
+         ", \\\n \"$OPT_Hfile\" title \"HLT\" w lp ls $HLT");
+    
+    #-- interactive mode
+    if ( $OPT_terminal eq $X11 ) {
+        print GFILE "\n",
+        "print \"-- INTERACTIVE MODE --\"\n",
+        "print \"consult gnuplot docs for command list\"\n",
+        "print \"mouse 1: coords to clipboard\"\n",
+        "print \"mouse 2: mark on plot\"\n",
+        "print \"mouse 3: zoom box\"\n",
+        "print \"'h' for help in plot window\"\n",
+        "print \"enter to exit\"\n",
+        "pause -1\n";
+    }
+
+    close (GFILE)
+        or print STDERR "WARNING: Trouble closing $OPT_Gfile, $!\n";
+}
+
+
+#------------------------------------------------------------------- RunGP ----#
+sub RunGP ( )
+{
+    if ( defined $OPT_Pfile ) {
+        print STDERR "Rendering plot $OPT_Pfile\n";
+    }
+    else {
+        print STDERR "Rendering plot to screen\n";
+    }
+
+    my $cmd = "gnuplot";
+
+    #-- x11 specifics
+    if ( $OPT_terminal eq $X11 ) {
+        my $size = $TERMSIZE{$OPT_terminal}{$OPT_size};
+        $cmd .= " -geometry ${size}x";
+        if ( $OPT_coverage ) { $size = sprintf ("%.0f", $size * .375); }
+        $cmd .= "${size}+0+0 -title mummerplot";
+
+        if ( defined $OPT_color && $OPT_color == 0 ) {
+            $cmd .= " -mono";
+            $cmd .= " -xrm 'gnuplot*line1Dashes: 0'";
+            $cmd .= " -xrm 'gnuplot*line2Dashes: 0'";
+            $cmd .= " -xrm 'gnuplot*line3Dashes: 0'";
+        }
+
+        if ( $OPT_rv ) {
+            $cmd .= " -rv";
+            $cmd .= " -xrm 'gnuplot*background: black'";
+            $cmd .= " -xrm 'gnuplot*textColor: white'";
+            $cmd .= " -xrm 'gnuplot*borderColor: white'";
+            $cmd .= " -xrm 'gnuplot*axisColor: white'";
+        }
+    }
+
+    $cmd .= " $OPT_Gfile";
+
+    system ($cmd)
+        and print STDERR "WARNING: Unable to run '$cmd', $!\n";
+}
+
+
+#---------------------------------------------------------------- ListenGP ----#
+sub ListenGP($$)
+{
+    my $rref = shift;
+    my $qref = shift;
+
+    my ($refc, $qryc);
+    my ($refid, $qryid);
+    my ($rsock, $qsock);
+    my $oldclip = "";
+
+    #-- get IDs sorted by offset
+    my @refo = sort { $rref->{$a}[0] <=> $rref->{$b}[0] } keys %$rref;
+    my @qryo = sort { $qref->{$a}[0] <=> $qref->{$b}[0] } keys %$qref;
+
+    #-- attempt to connect sockets
+    if ( $OPT_rport ) {
+        $rsock = IO::Socket::INET->new("localhost:$OPT_rport")
+            or print STDERR "WARNING: Could not connect to rport $OPT_rport\n";
+    }
+
+    if ( $OPT_qport ) {
+        $qsock = IO::Socket::INET->new("localhost:$OPT_qport")
+            or print STDERR "WARNING: Could not connect to qport $OPT_qport\n";
+    }
+
+    #-- while parent still exists
+    while ( getppid != 1 ) {
+
+        #-- query the clipboard
+        $_ = `xclip -o -silent -selection primary`;
+        if ( $? >> 8 ) {
+            die "WARNING: Unable to query clipboard with xclip\n";
+        }
+
+        #-- if cliboard has changed and contains a coordinate
+        if ( $_ ne $oldclip && (($refc, $qryc) = /^\[(\d+), (\d+)\]/) ) {
+
+            $oldclip = $_;
+
+            #-- translate the reference position
+            $refid = "NULL";
+            for ( my $i = 0; $i < (scalar @refo); ++ $i ) {
+                my $aref = $rref->{$refo[$i]};
+                if ( $i == $#refo || $aref->[0] + $aref->[1] > $refc ) {
+                    $refid = $refo[$i];
+                    $refc -= $aref->[0];
+                    if ( $aref->[2] == -1 ) {
+                        $refc = $aref->[1] - $refc + 1;
+                    }
+                    last;
+                }
+            }
+
+            #-- translate the query position
+            $qryid = "NULL";
+            for ( my $i = 0; $i < (scalar @qryo); ++ $i ) {
+                my $aref = $qref->{$qryo[$i]};
+                if ( $i == $#qryo || $aref->[0] + $aref->[1] > $qryc ) {
+                    $qryid = $qryo[$i];
+                    $qryc -= $aref->[0];
+                    if ( $aref->[2] == -1 ) {
+                        $qryc = $aref->[1] - $qryc + 1;
+                    }
+                    last;
+                }
+            }
+
+            #-- print the info to stdout and socket
+            print "$refid\t$qryid\t$refc\t$qryc\n";
+
+            if ( $rsock ) {
+                print $rsock "contig I$refid $refc\n";
+                print "sent \"contig I$refid $refc\" to $OPT_rport\n";
+            }
+            if ( $qsock ) {
+                print $qsock "contig I$qryid $qryc\n";
+                print "sent \"contig I$qryid $qryc\" to $OPT_qport\n";
+            }
+        }
+
+        #-- sleep for half second
+        select undef, undef, undef, .5;
+    }
+
+    exit (0);
+}
+
+
+#------------------------------------------------------------ ParseOptions ----#
+sub ParseOptions ( )
+{
+    my ($opt_small, $opt_medium, $opt_large);
+    my ($opt_ps, $opt_x11, $opt_png);
+    my $cnt;
+
+    #-- Get options
+    my $err = $tigr -> TIGR_GetOptions
+        (
+         "b|breaklen:i" => \$OPT_breaklen,
+         "color!"       => \$OPT_color,
+         "c|coverage!"  => \$OPT_coverage,
+         "f|filter!"    => \$OPT_filter,
+         "l|layout!"    => \$OPT_layout,
+         "p|prefix=s"   => \$OPT_prefix,
+         "rv"           => \$OPT_rv,
+         "r|IdR=s"      => \$OPT_IdR,
+         "q|IdQ=s"      => \$OPT_IdQ,
+         "R|Rfile=s"    => \$OPT_IDRfile,
+         "Q|Qfile=s"    => \$OPT_IDQfile,
+         "rport=i"      => \$OPT_rport,
+         "qport=i"      => \$OPT_qport,
+         "s|size=s"     => \$OPT_size,
+         "S|SNP"        => \$OPT_SNP,
+         "t|terminal=s" => \$OPT_terminal,
+         "title=s"      => \$OPT_title,
+         "x|xrange=s"   => \$OPT_xrange,
+         "y|yrange=s"   => \$OPT_yrange,
+         "x11"          => \$opt_x11,
+         "postscript"   => \$opt_ps,
+         "png"          => \$opt_png,
+         "small"        => \$opt_small,
+         "medium"       => \$opt_medium,
+         "large"        => \$opt_large,
+         "fat"          => \$OPT_ONLY_USE_FATTEST,
+         );
+
+    if ( !$err  ||  scalar (@ARGV) != 1 ) {
+        $tigr -> printUsageInfo( );
+        die "Try '$0 -h' for more information.\n";
+    }
+
+    $cnt = 0;
+    if ( $opt_png ) { $OPT_terminal = $PNG; $cnt ++; }
+    if ( $opt_ps  ) { $OPT_terminal = $PS;  $cnt ++; }
+    if ( $opt_x11 ) { $OPT_terminal = $X11; $cnt ++; }
+    if ( $cnt > 1 ) {
+        print STDERR
+            "WARNING: Multiple terminals not allowed, using '$OPT_terminal'\n";
+    }
+
+    $cnt = 0;
+    if ( $opt_large  ) { $OPT_size = $LARGE;  $cnt ++; }
+    if ( $opt_medium ) { $OPT_size = $MEDIUM; $cnt ++; }
+    if ( $opt_small  ) { $OPT_size = $SMALL;  $cnt ++; }
+    if ( $cnt > 1 ) {
+        print STDERR
+            "WARNING: Multiple sizes now allowed, using '$OPT_size'\n";
+    }
+
+    #-- Check that status of gnuplot
+    $OPT_gpstatus = system ("gnuplot --version");
+
+    if ( $OPT_gpstatus == -1 ) {
+        print STDERR
+            "WARNING: Could not find gnuplot, plot will not be rendered\n";
+    }
+    elsif ( $OPT_gpstatus ) {
+        print STDERR
+            "WARNING: Using outdated gnuplot, use v4.0 for best results\n";
+
+        if ( $OPT_color ) {
+            print STDERR
+                "WARNING: Turning of --color option for compatibility\n";
+            undef $OPT_color;
+        }
+
+        if ( $OPT_terminal eq $PNG  &&  $OPT_size ne $SMALL ) { 
+            print STDERR
+                "WARNING: Turning of --size option for compatibility\n";
+            $OPT_size = $SMALL;
+        }
+    }
+
+    #-- Check options
+    if ( !exists $TERMSIZE{$OPT_terminal} ) {
+        die "ERROR: Invalid terminal type, $OPT_terminal\n";
+    }
+
+    if ( !exists $TERMSIZE{$OPT_terminal}{$OPT_size} ) {
+        die "ERROR: Invalid terminal size, $OPT_size\n";
+    }
+
+    if ( $OPT_xrange ) {
+        $OPT_xrange =~ tr/,/:/;
+        $OPT_xrange =~ /^\[\d+:\d+\]$/
+            or die "ERROR: Invalid xrange format, $OPT_xrange\n";
+    }
+
+    if ( $OPT_yrange ) {
+        $OPT_yrange =~ tr/,/:/;
+        $OPT_yrange =~ /^\[\d+:\d+\]$/
+            or die "ERROR: Invalid yrange format, $OPT_yrange\n";
+    }
+
+    #-- Set file names
+    $OPT_Mfile = $ARGV[0];
+    $tigr->isReadableFile ($OPT_Mfile)
+        or die "ERROR: Could not read $OPT_Mfile, $!\n";
+
+    $OPT_Ffile = $OPT_prefix . $SUFFIX{$FWDPLOT};
+    $tigr->isWritableFile ($OPT_Ffile) or $tigr->isCreatableFile ($OPT_Ffile)
+        or die "ERROR: Could not write $OPT_Ffile, $!\n";
+
+    $OPT_Rfile = $OPT_prefix . $SUFFIX{$REVPLOT};
+    $tigr->isWritableFile ($OPT_Rfile) or $tigr->isCreatableFile ($OPT_Rfile)
+        or die "ERROR: Could not write $OPT_Rfile, $!\n";
+
+    if ( defined $OPT_breaklen || defined $OPT_SNP ) {
+        $OPT_Hfile = $OPT_prefix . $SUFFIX{$HLTPLOT};
+        $tigr->isWritableFile($OPT_Hfile) or $tigr->isCreatableFile($OPT_Hfile)
+            or die "ERROR: Could not write $OPT_Hfile, $!\n";
+    }
+
+    if ($OPT_ONLY_USE_FATTEST)
+    {
+      $OPT_layout = 1;
+    }
+
+    if ( $OPT_filter || $OPT_layout ) {
+        $OPT_Dfile = $OPT_prefix . $SUFFIX{$FILTER};
+        $tigr->isWritableFile($OPT_Dfile) or $tigr->isCreatableFile($OPT_Dfile)
+            or die "ERROR: Could not write $OPT_Dfile, $!\n";
+    }
+
+    $OPT_Gfile = $OPT_prefix . $SUFFIX{$GNUPLOT};
+    $tigr->isWritableFile ($OPT_Gfile) or $tigr->isCreatableFile ($OPT_Gfile)
+        or die "ERROR: Could not write $OPT_Gfile, $!\n";
+
+    if ( exists $SUFFIX{$OPT_terminal} ) {
+        $OPT_Pfile = $OPT_prefix . $SUFFIX{$OPT_terminal};
+        $tigr->isWritableFile($OPT_Pfile) or $tigr->isCreatableFile($OPT_Pfile)
+            or die "ERROR: Could not write $OPT_Pfile, $!\n";
+    }
+
+    if ( defined $OPT_IDRfile ) {
+        $tigr->isReadableFile ($OPT_IDRfile)
+            or die "ERROR: Could not read $OPT_IDRfile, $!\n";
+    }
+
+    if ( defined $OPT_IDQfile ) {
+        $tigr->isReadableFile ($OPT_IDQfile)
+            or die "ERROR: Could not read $OPT_IDQfile, $!\n";
+    }
+
+    if ( (defined $OPT_rport || defined $OPT_qport) &&
+         ($OPT_terminal ne $X11 || $OPT_gpstatus ) ) {
+        print STDERR
+            "WARNING: Port options available only for v4.0 X11 plots\n";
+        undef $OPT_rport;
+        undef $OPT_qport;
+    }
+
+
+    if ( defined $OPT_color && defined $OPT_Hfile ) {
+        print STDERR
+            "WARNING: Turning off --color option so highlighting is visible\n";
+        undef $OPT_color;
+    }
+}