R/plotting.helpers.R

Defines functions get.nested.heights.depths get.nested.heights.helper repString get.nested.heights.advanced get.nested.heights.FALLBACK get.nested.heights get.connection.cramp drawHalfLoop drawHalfLoops JS.axis rescale.coords generate.interval.scale drawTranscript drawGene.noSplices JS.arrowChars drawGene drawPlot makeGeneLevelAxis makevstaxis plotTranscriptsOnly

#These functions were (loosely) based on similar functions created for the DEXSeq package.
#
# Note that DEXSeq is licensed under the GPL v3. Therefore this
#   code packaged together is licensed under the GPL v3, as noted in the LICENSE file.
# Some code snippets are "united states government work" and thus cannot be
#   copyrighted. See the LICENSE file for more information.
#
# The current versions of the original functions upon which these were based can be found
#    here: http://github.com/Bioconductor-mirror/DEXSeq
#
# Updated Authorship and license information can be found here:
#   here: http://github.com/Bioconductor-mirror/DEXSeq/blob/master/DESCRIPTION


########################################################
# UTILITY PLOTTING FUNCTIONS:
########################################################

plotTranscriptsOnly <- function(anno.data, geneID, debug.mode = TRUE, par.cex = 1, anno.cex.text = 1, ...)
{  

   draw.legend <- TRUE

   rt.allExon <- which(anno.data$gene_id==geneID & anno.data$featureType == "exonic_part")
   rango <- 1:length(rt.allExon)
   
   main.title <- paste0("Known transcripts for gene ",geneID)
   
   exoncol <- rep("#CCCCCC",length(rt.allExon))
   exonlty <- rep(1,length(exoncol))
   sig.feature <- rep(FALSE,length(exoncol))

   
   ################## DETERMINE THE LAYOUT OF THE PLOT DEPENDING OF THE OPTIONS THE USER PROVIDES ###########
      sub.allExon <- data.frame(start=anno.data$start[rt.allExon], end=anno.data$end[rt.allExon], chr=anno.data$chrom[rt.allExon], strand=anno.data$strand[rt.allExon])
      intervals<-(0:nrow(sub.allExon))/nrow(sub.allExon)


      
      rel.calc.min <- min(sub.allExon$start)
      rel.calc.max <- max(sub.allExon$end)

      rel <- (data.frame(sub.allExon$start, sub.allExon$end)) - rel.calc.min
      rel <- rel/(rel.calc.max - rel.calc.min)

         transcripts <- sapply(sapply(anno.data$transcripts[rt.allExon],toString), function(x){strsplit(x, "+",fixed=TRUE)})
         trans <- Reduce(union, transcripts)
         if(length(trans) > 42){
            warning("This gene contains more than 42 transcripts annotated, only the first 42 will be plotted\n")
            trans <- trans[1:42]
         }
         mat <- 1:(min(length(trans), 42)) ## max support from transcripts is 45, which seems to be the max for the layout supported by graphics
         hei <- c(1, 1.5, rep(1.5, min(length(trans), 42)))

      layout(matrix(mat), heights=hei)
      
      p.values.labels <- rep("",length(rt.allExon))
   
      #########PLOT THE GENE MODEL:
      par(mar=c(0, 4, 0, 2))
      plot.new()
      par(cex = par.cex)
      # lines linking exons / splices to their column.
      segments(apply((rbind(rel[rango,2], rel[rango, 1])), 2, median), 0, apply(rbind(intervals[rango], intervals[rango+1]-((intervals[rango+1]-intervals[rango])*0.2)), 2, median), 1, col=exoncol, lty = exonlty, ...)
      
      par(mar=c(1.5, 4, 0, 2))
      drawGene.noSplices(rel.calc.min, rel.calc.max, tr.allExon=sub.allExon, par.cex = par.cex, anno.cex.text = anno.cex.text,...)
            for(i in 1:min(length(trans), 42)){
               logicexons <- sapply(transcripts, function(x){length(which(x==trans[i]))})
               tr <- data.frame(start = anno.data$start[rt.allExon][logicexons==1], end = anno.data$end[rt.allExon][logicexons==1], featureType = anno.data$featureType[rt.allExon][logicexons==1])
               tr <- tr[tr$featureType == "exonic_part",]
               drawTranscript(rel.calc.min, rel.calc.max, tr=tr, rango=1:(length(anno.data$start[rt.allExon][logicexons==1])), exoncol=NULL, names=c(), trName=trans[i], par.cex = par.cex, anno.cex.text = anno.cex.text,sub.sig = data.frame(start=c(),end=c()))
            }
      
      axis1.main <- make.evenly.spaced.seq(rel.calc.min, rel.calc.max, 10)
      axis1.minor <- make.evenly.spaced.seq.minor(rel.calc.min, rel.calc.max, 10)
      
      axis(1,at=axis1.minor,labels=rep("",length(axis1.minor)),pos=0,lwd.ticks=0.2,padj=-0.7,tcl=-0.25, cex.axis = anno.cex.text, ...)
      axis(1,at=axis1.main,labels=axis1.main,pos=0,lwd.ticks=0.2,padj=-0.7,tcl=-1, cex.axis = anno.cex.text, ...)
}


########################################################
#FUNCTION TO MAKE THE AXIS OF THE VST VALUES
########################################################

makevstaxis <- function(min, ylimn, ecs, use.vst, use.log,plot.type, par.cex = 1, anno.cex.text = 1, draw.axis = 2, pos = 0, yAxisLabels.inExponentialForm = TRUE, ...)
{

   if(use.vst){
   

     range_scaled <- ylimn[2] - ylimn[1]

     decades_unscaled <- c(0,1)
     decades_scaled <- vst(decades_unscaled,ecs)

     while(decades_scaled[length(decades_scaled)] < ylimn[2]){
       decades_unscaled <- c(decades_unscaled, decades_unscaled[length(decades_unscaled)] * 10)
       decades_scaled <- vst(decades_unscaled,ecs)
     }


     if(yAxisLabels.inExponentialForm && length(decades_unscaled) > 2){
       decades_labels <- c(expression(0),expression(1),
         sapply(decades_unscaled[-c(1,2)], function(D){
           exponent <- log10(D)
           substitute(10 ^ X, list(X = exponent))
         })
       )
     } else {
       decades_labels <- c(decades_unscaled)
     }
     
     decades_scaled <- vst(decades_unscaled,ecs)

     ticks_unscaled <- c()
     first.tick.threshold <- (range_scaled * 0.05) + ylimn[1]
     
     for(i in 1:length(decades_unscaled)){
       if(decades_scaled[i] >  first.tick.threshold & decades_unscaled[i] > 0) {
       ticks_unscaled <- c(ticks_unscaled,
                           decades_unscaled[i]*2,
                           decades_unscaled[i]*3,
                           decades_unscaled[i]*4,
                           decades_unscaled[i]*5,
                           decades_unscaled[i]*6,
                           decades_unscaled[i]*7,
                           decades_unscaled[i]*8,
                           decades_unscaled[i]*9
                           )
       }
     }
     ticks_scaled <- vst(ticks_unscaled,ecs)
   
     axis( draw.axis, at=ticks_scaled, labels=FALSE, las=2, pos=pos,tcl=-0.25, cex.axis = anno.cex.text, ...)
     axis( draw.axis, at=decades_scaled, labels=decades_labels, las=2, pos=pos,tcl=-0.5, cex.axis = anno.cex.text, ...)

  } else if(use.log) {
    if(plot.type == "rawCounts"){
        ticks <- rep(c(2,3,4,5,6,7,8,9),ceiling(ylimn[2])) * rep(10^(0:ceiling(ylimn[2]-1)),each=8)
        logticks <- log10(ticks)
        axis(draw.axis,at=c(INTERNAL.NINF.VALUE,0),labels=c(0,""), las=2, tcl=-0.5, pos=pos, cex.axis = anno.cex.text, ...)
        qorts.axis.break(draw.axis,breakpos=(INTERNAL.NINF.VALUE / 2),pos=pos, cex = anno.cex.text, yw = INTERNAL.NINF.VALUE * 0.3,...)

        if(yAxisLabels.inExponentialForm && ceiling(ylimn[2]) > 2){
          decade.labels <- c(expression(1),expression(10),sapply(2:ceiling(ylimn[2]), function(X){
            substitute(10 ^ x, list(x = X))
          }))
        } else {
          decade.labels <- (10^(0:ceiling(ylimn[2])))
        }

        axis(draw.axis,   at=logticks ,labels=FALSE, las=2, pos=pos, tcl=-0.25, cex.axis = anno.cex.text, ...)
        axis(draw.axis,   at=0:ceiling(ylimn[2]),labels=decade.labels, las=2, tcl=-0.5, pos=pos, cex.axis = anno.cex.text, ...)
    } else {
      ticks <- rep(c(2,3,4,5,6,7,8,9),ceiling(ylimn[2])) * rep(10^(0:ceiling(ylimn[2]-1)),each=8)
      logticks <- log10(ticks)
      axis(draw.axis,   at=c(INTERNAL.NINF.VALUE,0),labels=c("0",""),      las=2, tcl=-0.5,  pos=pos, cex.axis = anno.cex.text, ...)
      qorts.axis.break(draw.axis,breakpos=(INTERNAL.NINF.VALUE / 2),pos=pos, cex = anno.cex.text, yw = INTERNAL.NINF.VALUE * 0.3,...)
      
      if(yAxisLabels.inExponentialForm && ceiling(ylimn[2]) > 2){
        decade.labels <- c(expression(1),expression(10),sapply(2:ceiling(ylimn[2]), function(X){
          substitute(10 ^ x, list(x = X))
        }))
      } else {
        decade.labels <- (10^(0:ceiling(ylimn[2])))
      }
      
      axis(draw.axis,   at=logticks ,labels=FALSE, las=2, pos=pos, tcl=-0.25, cex.axis = anno.cex.text, ...)
      axis(draw.axis,   at=0:ceiling(ylimn[2]),labels= decade.labels, las=2, tcl=-0.5, pos=pos, cex.axis = anno.cex.text, ...)
    }
  } else {
    axis(draw.axis, las=2, tcl=0.5, pos=pos, cex.axis = anno.cex.text, ...)
  }
}

makeGeneLevelAxis <- function(ylimn, geneColumn.TOP, use.vst, use.log, plot.type, par.cex = 1, anno.cex.text = 1, draw.axis = 2, pos = 1.04, geneLevel.rescaleFactor, yAxisLabels.inExponentialForm = TRUE, ...){
  if(use.vst){
    stop("Gene-Level data with vst-transformations is not currently supported!")
  } else if(use.log) {
    if(plot.type == "rawCounts"){
      ticks <- rep(c(2,3,4,5,6,7,8,9),ceiling(ylimn[2])) * rep(10^(0:ceiling(ylimn[2]-1)),each=8)
      logticks <- log10(ticks)
      axis(draw.axis,at=c(INTERNAL.NINF.VALUE,0),labels=c(0,""), las=2, tcl=-0.5, pos=pos, cex.axis = anno.cex.text, ...)
      qorts.axis.break(draw.axis,breakpos=(INTERNAL.NINF.VALUE / 2),pos=pos, cex = anno.cex.text, yw = INTERNAL.NINF.VALUE * 0.3,...)
      
      if(yAxisLabels.inExponentialForm && ceiling(ylimn[2]) > 2){
        decade.labels <- c(expression(1),expression(10),sapply(2:ceiling(ylimn[2]), function(X){
          substitute(10 ^ x, list(x = X))
        }))
      } else {
        decade.labels <- (10^(0:ceiling(ylimn[2])))
      }
      
      logticks <- logticks / geneLevel.rescaleFactor
      decades <- 0:ceiling(ylimn[2]) / geneLevel.rescaleFactor
      
      keep.ticks <- logticks <= geneColumn.TOP
      keep.decades <- decades <= geneColumn.TOP
      
      axis(draw.axis,   at = logticks[keep.ticks],labels=FALSE, las=2, pos=pos, tcl=-0.25, cex.axis = anno.cex.text, ...)
      axis(draw.axis,   at = decades[keep.decades], labels=decade.labels[keep.decades], las=2, tcl=-0.5, pos=pos, cex.axis = anno.cex.text, ...)
    } else {
      ticks <- rep(c(2,3,4,5,6,7,8,9),ceiling(ylimn[2])) * rep(10^(0:ceiling(ylimn[2]-1)),each=8)
      logticks <- log10(ticks)
      axis(draw.axis,   at=c(INTERNAL.NINF.VALUE,0),labels=c("0",""),      las=2, tcl=-0.5,  pos=pos, cex.axis = anno.cex.text, ...)
      qorts.axis.break(draw.axis,breakpos=(INTERNAL.NINF.VALUE / 2),pos=pos, cex = anno.cex.text, yw = INTERNAL.NINF.VALUE * 0.3,...)
      
      if(yAxisLabels.inExponentialForm && ceiling(ylimn[2]) > 2){
        decade.labels <- c(expression(1),expression(10),sapply(2:ceiling(ylimn[2]), function(X){
          substitute(10 ^ x, list(x = X))
        }))
      } else {
        decade.labels <- (10^(0:ceiling(ylimn[2])))
      }
      logticks <- logticks / geneLevel.rescaleFactor
      decades <- 0:ceiling(ylimn[2]) / geneLevel.rescaleFactor
      
      keep.ticks <- logticks <= geneColumn.TOP
      keep.decades <- decades <= geneColumn.TOP
      
      axis(draw.axis,   at = logticks[keep.ticks],labels=FALSE, las=2, pos=pos, tcl=-0.25, cex.axis = anno.cex.text, ...)
      axis(draw.axis,   at = decades[keep.decades], labels=decade.labels[keep.decades], las=2, tcl=-0.5, pos=pos, cex.axis = anno.cex.text, ...)
    }
  } else {
    axis(draw.axis, las=2, tcl=0.5, pos=pos, cex.axis = anno.cex.text, ...)
  }
}

#######################
#FUNCTION TO DRAW THE EXPRESSION PLOTS:
#######################
drawPlot <- function(matr, ylimn,ecs, intervals, rango, fitExpToVar, numexons, textAxis, geneLevelAxisTitle = NULL, rt, color.count, 
                     colorlines,countbinIDs,use.vst, use.log,plot.type,main.title,draw.legend,color.key,
                     condition.names,p.values=NULL,draw.p.values=FALSE,plot.lwd = 1,axes.lwd = 1, 
                     anno.lwd =1, par.cex = 1, anno.cex.text = 1, anno.cex.axis = anno.cex.text, anno.cex.main = anno.cex.text * 1.2,
                     fit.countbin.names = TRUE, fit.pvals = TRUE, stagger.pvals = 2,debug.mode = FALSE,
                     plot.gene.level.expression = FALSE, geneCount = NULL, color.geneCount = NULL, 
                     yAxisLabels.inExponentialForm = TRUE,
                     autofit.legend = TRUE, italicize.label = NULL, condition.legend.text = condition.legend.text,
                     annolink.col = NULL, exonlty = NULL,
                     graph.margins = c(2,3,3,2),
                     plotWindowXmax = 1.04,
                     fit.labels = TRUE,
                     above.pvals = FALSE,
                     ...)
{
   plot.junction.ids.vertically <- NULL
   plot.junction.ids.vertically.threshold <- Inf
   
   if(debug.mode) message("> Step 6.1")
   
   par(mar=graph.margins, cex = par.cex)
   plot.new()
   par(cex = par.cex)
   
     spare.yaxs.margin <- (abs(ylimn[2] - ylimn[1])) * 0.08
     spare.yaxs.margin <- (abs(ylimn[2] - ylimn[1]))*0.04
   
   plot.window(xlim=c(0, plotWindowXmax), ylim=c(ylimn[1], ylimn[2] + spare.yaxs.margin), xaxs = "i", yaxs="i")
   
   if(debug.mode) message("> Step 6.2")
   makevstaxis(1/ncol(matr), ylimn, ecs,use.vst=use.vst, use.log=use.log,plot.type=plot.type, lwd = axes.lwd, par.cex = par.cex, anno.cex.text = anno.cex.text, ...)
   title(main=main.title, cex.main = anno.cex.main, ...)
   if(debug.mode) message("> Step 6.3")
   
   if(plot.type == "logRawCounts")  segments(0,INTERNAL.NINF.VALUE,par("usr")[2]+1,INTERNAL.NINF.VALUE,lty="dotted",col="black", lwd = plot.lwd,...); 
   if((! use.vst) && use.log ) segments(0,INTERNAL.NINF.VALUE,par("usr")[2]+1,INTERNAL.NINF.VALUE,lty="dotted",col="black", lwd = plot.lwd,...); 
   segments(0,0,par("usr")[2]+1,0,lty="dotted",col="black", lwd = plot.lwd,...)
   junctionColumns.RIGHT <- (intervals[rango+1]-((intervals[rango+1]-intervals[rango])*0.2))[length(rango)]
   if(debug.mode) message("> Step 6.4")

     geneColumn.RIGHT <- par("usr")[2]
     
     if(autofit.legend && draw.legend){
       legend.rect <- legend(geneColumn.RIGHT,  par("usr")[4],fill=color.key[names(condition.legend.text)],legend=condition.legend.text[condition.names], cex = anno.cex.text, bg = "white", box.lwd = axes.lwd, xjust = 1, yjust = 1, xpd = NA, plot=FALSE,...)$rect
       #note: rect$w = width, rect$h = height, rect$left = left coord, rect$top = top coord.
       devlimits <- device.limits()
       junctionColumns.RIGHT.RESCALED <- devlimits[2] - legend.rect$w
       if(junctionColumns.RIGHT.RESCALED < junctionColumns.RIGHT){
         if(debug.mode) message("Shifting plots to autofit the legend box.")
         intervals <- intervals * (junctionColumns.RIGHT.RESCALED / junctionColumns.RIGHT)
         junctionColumns.RIGHT <- junctionColumns.RIGHT.RESCALED
       }
       geneColumn.TOP.PCT <- 0.98
       geneColumn.TOP <- (legend.rect$top - legend.rect$h) * geneColumn.TOP.PCT
     } else {
       geneColumn.TOP.PCT <- 0.9
       geneColumn.TOP   <- par("usr")[4] * geneColumn.TOP.PCT
     }
     geneColumn.LEFT  <- ((geneColumn.RIGHT - junctionColumns.RIGHT) * 0.25) + junctionColumns.RIGHT
     geneColumn.MID   <- ((geneColumn.RIGHT - geneColumn.LEFT) *0.5 + geneColumn.LEFT)
     geneColumn.YMAX <- geneColumn.TOP * 0.96
     
     
     
     
   if(plot.gene.level.expression){
     rect(junctionColumns.RIGHT,    par("usr")[3], geneColumn.LEFT,    par("usr")[4], xpd=NA, lwd = axes.lwd,xpd=NA, border="white",col="white",...)
     rect(0,    par("usr")[3], junctionColumns.RIGHT,    par("usr")[4], xpd=NA, lwd = axes.lwd,xpd=NA,...)
     rect(geneColumn.LEFT, par("usr")[3], geneColumn.RIGHT, geneColumn.TOP, xpd=NA, lwd = axes.lwd,xpd=NA,...)
   } else {
     rect(junctionColumns.RIGHT,    par("usr")[3], par("usr")[2],    par("usr")[4], xpd=NA, lwd = axes.lwd,xpd=NA, border="white",col="white",...)
     rect(0,    par("usr")[3], junctionColumns.RIGHT,    par("usr")[4], xpd=NA, lwd = axes.lwd,xpd=NA,...)
   }
     if(draw.legend){
         if(autofit.legend){
           legend(junctionColumns.RIGHT,  par("usr")[4],fill=color.key[names(condition.legend.text)],legend=condition.legend.text[condition.names], cex = anno.cex.text, box.lwd = axes.lwd, xjust = 0, yjust = 1, xpd = NA, box.col = "transparent", bg = "transparent",...)
         } else {
           legend(geneColumn.RIGHT,  par("usr")[4],fill=color.key[names(condition.legend.text)],legend=condition.legend.text[condition.names], cex = anno.cex.text, bg = "white", box.lwd = axes.lwd, xjust = 1, yjust = 1, xpd = NA, ...)
         }
     }
   

   
   if(debug.mode) message("> Step 6.5")
   
   middle <- apply(cbind(intervals[rango], (intervals[rango+1]-((intervals[rango+1])-intervals[rango])*0.2)), 1, median)
   matr <- rbind(matr, NA)
   j <- 1:ncol(matr)
   
   segments(intervals[rango],matr[rango,j], intervals[rango+1]-((intervals[rango+1]-intervals[rango])*0.2), matr[rango,j], col=color.count, lwd = plot.lwd,...)  #### line with the y level
   segments(intervals[rango+1]-((intervals[rango+1]-intervals[rango])*0.2), matr[rango,j], intervals[rango+1], matr[rango+1,j], col=color.count, lty="dotted", lwd =plot.lwd,...)  #### line joining the y levels
   abline(v=middle[rango], lty="dotted", col=colorlines, lwd = plot.lwd)
   
   cex.mainPlotAxis <- anno.cex.text
   if(fit.labels){
     cex.mainPlotAxis <- shrink.character.vector.VERT(textAxis, cex.mainPlotAxis, abs(ylimn[2] - ylimn[1]) * 0.95)
   }
   text(device.limits()[1], ylimn[1] + abs(ylimn[2] - ylimn[1])*0.5, textAxis,           cex = cex.mainPlotAxis, xpd = NA, adj = c(0.5,1.1), srt = 90 , ...)
   if(plot.gene.level.expression){
     cex.geneLevelAxis <- anno.cex.text
     if(fit.labels){
       cex.geneLevelAxis <- shrink.character.vector.VERT(geneLevelAxisTitle, cex.geneLevelAxis, abs(geneColumn.TOP - ylimn[1]) *0.95)
     }
     text(device.limits()[2], abs(geneColumn.TOP - ylimn[1]) *0.5 + ylimn[1], geneLevelAxisTitle, cex = cex.geneLevelAxis, xpd = NA, adj = c(0.5,1.1), srt = 270 , ...)
   }
   
   if(debug.mode) message("> Step 6.6")
   
   cex.countbinIDs <- anno.cex.axis
   srt.countbinIDs <- 0

   if(is.null(plot.junction.ids.vertically)){
     if(length(rt) > plot.junction.ids.vertically.threshold){
       plot.junction.ids.vertically <- TRUE
     } else {
       plot.junction.ids.vertically <- FALSE
     }
   }
   if(debug.mode) message("> Step 6.7")
   srt.countbinIDs <- 0
   cex.countbinIDs <- anno.cex.axis
   adj.countbinIDs <- c(0.5,0.5)
   tcl.countbinIDs <- -0.4
   if(fit.countbin.names){
     bin.width <- abs(intervals[1] - intervals[2])
     cex.countbinIDs <- fit.character.vector(countbinIDs, min.width = 0.6 * bin.width, max.width = 0.9 * bin.width, max.width.per.char = 0.4 * bin.width)
     cex.countbinIDs <- min(cex.countbinIDs, anno.cex.axis)
     if(cex.countbinIDs < anno.cex.axis / 4){
       srt.countbinIDs <- 90
       cex.countbinIDs <- cex.countbinIDs * 3
       tcl.countbinIDs <- -0.1
     } else if(cex.countbinIDs < anno.cex.axis / 2){
       srt.countbinIDs <- 45
       cex.countbinIDs <- cex.countbinIDs * 2
       tcl.countbinIDs <- -0.25
     }
   }
   if(is.null(italicize.label)){
     axis.font <- NULL
   } else {
     axis.font <- ifelse(italicize.label,3,2)
   }
   axis.label.floor <- JS.axis(1, at=middle[1:length(rt)], labels=countbinIDs, tcl = tcl.countbinIDs,  lwd = axes.lwd, lwd.ticks = axes.lwd, cex.axis = cex.countbinIDs, srt = srt.countbinIDs, font = axis.font, adj = adj.countbinIDs,...)# ,

   if(debug.mode) message("> Step 6.8")
   
   
   if(debug.mode) message("> Step 6.9")
   p.values[is.na(p.values)] <- ""
   if(any(p.values != "")){
     if(draw.p.values){
        bin.width <- abs(intervals[1] - intervals[2])
         
         if(fit.pvals){  
           cex.pvalues <- fit.character.vector(p.values, min.width = 1 * bin.width, max.width = 1.5 * bin.width, max.width.per.char = 0.5 * bin.width)
           cex.pvalues <- min(cex.pvalues, anno.cex.text)
         } else {
           cex.pvalues <- anno.cex.text
         }
         pval.height <- max(strheight(p.values, cex = cex.pvalues))
         
         if(above.pvals){
           pval.ceiling <- par("usr")[4] + pval.height * stagger.pvals
           pval.yadj <- 0
         } else {
           pval.ceiling <- par("usr")[4] - pval.height*0.1
           pval.yadj <- 1
         }
         
        pval.y <- rep(pval.ceiling,length(rango))
        if(stagger.pvals > 1){
          tryCatch({
            if(debug.mode) message("> Step 6.9b")
            
            #CURRENTLY ONLY IMPLEMENTING 2-layer stagger! 3-layer stagger is DEPRECIATED.
            
            pval.drop <- rep(-pval.height,length(p.values))
              
              pw <- which(p.values != "")
              pwo <- pw
              while(length(pw) > 0){
                if(any( c(pw[1] - 1, pw[1] + 1) %in% pwo ) && pw %% 2 == 0){
                  pval.drop[pw[1]] <- pval.drop[pw[1]] + pval.height
                } else{
                  #do nothing.
                }
                pw <- pw[-1]
              }
            pval.y <- pval.ceiling + pval.drop
          }, error = function(e){
            message("WARNING: staggering p-values failed. Falling back to simpler method. This warning should never appear. If you see this, reporting this to the developer would be appreciated.")
          })
        }
        
        if(strwidth(p.values[1], cex = cex.pvalues) > bin.width  * 0.9){
          text(intervals[1], pval.y[1], labels = p.values[1], col = colorlines[1], cex = cex.pvalues, adj = c(0,pval.yadj), ...)
        } else {
          text(middle[1], pval.y[1], labels = p.values[1], col = colorlines[1], cex = cex.pvalues, adj = c(0.5,pval.yadj),  ...)
        }
        if(strwidth(p.values[length(p.values)], cex = cex.pvalues) > bin.width * 0.9){
          text(junctionColumns.RIGHT, pval.y[length(middle)], labels = p.values[length(middle)], col = colorlines[length(middle)], cex = cex.pvalues, adj = c(1,pval.yadj), xpd = NA, ...)
        } else {
          text(middle[length(middle)], pval.y[length(middle)], labels = p.values[length(middle)], col = colorlines[length(middle)], cex = cex.pvalues, adj = c(0.5,pval.yadj), xpd = NA, ...)
        }
        text(middle[2:(length(middle)-1)],pval.y[2:(length(middle)-1)],labels=p.values[2:(length(middle)-1)],col=colorlines[2:(length(middle)-1)], cex = cex.pvalues, adj = c(0.5,pval.yadj), xpd = NA,...)
     }
   }
   if(debug.mode) message("> Step 6.10 (anno.cex.text = ",anno.cex.text,")")
   
   if(plot.gene.level.expression){
     geneLevel.max <- max(geneCount, na.rm=TRUE)
     
     geneLevel.rescaleFactor <- (geneLevel.max) / (geneColumn.YMAX)
     
     geneLevelRescaled <- ifelse(geneCount < 0, geneCount, geneCount / geneLevel.rescaleFactor)
     points(rep(geneColumn.MID,length(geneLevelRescaled)), geneLevelRescaled, col = color.geneCount, pch = 4, ...)
     
     segments(geneColumn.LEFT, geneLevelRescaled, geneColumn.RIGHT, geneLevelRescaled, col = color.geneCount, lwd = plot.lwd, ... )
     segments(junctionColumns.RIGHT,matr[rango[length(rango)],j],geneColumn.LEFT, geneLevelRescaled,col = color.geneCount,lwd = plot.lwd, lty = "dotted",...)
     
     makeGeneLevelAxis( c(0,geneColumn.TOP * geneLevel.rescaleFactor), geneColumn.TOP, use.vst=use.vst, use.log=use.log, plot.type=plot.type, lwd = axes.lwd, par.cex = par.cex, anno.cex.text = anno.cex.text, draw.axis=4, pos = geneColumn.RIGHT, geneLevel.rescaleFactor = geneLevel.rescaleFactor, mgp = c(3,0.5,0), ...)

     cex.gene.tick <- min(anno.cex.axis, cex.countbinIDs * 1.5)
     srt.gene.tick <- 0
     if(strwidth("GENE",cex = cex.gene.tick)/2 > abs(geneColumn.MID - junctionColumns.RIGHT) * 0.9 ){
       cex.gene.tick <- cex.countbinIDs
       srt.gene.tick <- srt.countbinIDs
     }
     JS.axis(1, at=geneColumn.MID, labels="GENE", tcl =  tcl.countbinIDs,  lwd = axes.lwd, lwd.ticks = axes.lwd, cex.axis = cex.gene.tick, srt = srt.gene.tick, font = 2, adj = adj.countbinIDs,...)# ,
   } else {
   }

   if(debug.mode) message("> Step 6.11")
   return(intervals)
}


#########################
#FUNCTION TO DRAW THE GENE MODELS AND TRANSCRIPTS:
#########################



drawGene <- function(minx, maxx, tr, tr.allExon, tr.allJunction, rango, rescale.iv = NULL, exoncol=NULL,allExon.exonCol=NULL, names, 
                     trName, exonlty, plot.lwd = 1, anno.lwd = 1, show.strand.arrows = 0, geneStrand = ".", par.cex = 1, anno.cex.text = 1, 
                     draw.untestable.annotation = TRUE,
                     draw.start.end.sites = TRUE, startSites = NULL, endSites = NULL,
                     cex.arrows, chrom.label = "", label.chromosome = TRUE,
                     draw.curved.SJ = TRUE, draw.nested.SJ = TRUE,
                     draw.exon.lines = TRUE,
                     splice.junction.drawing.style = "hyperbola",
                     merge.exon.parts = TRUE,
                     plot.untestable.results = FALSE,
                     exon.height = 0.75,
                     INTERNAL.VARS = list(),
                     flip.splicing = FALSE, gapped.flip = FALSE,
                     ylim = c(0,1),
                     ...)
{
   xpd <- NA
   plot.new()
   plot.window(xlim=c(minx, maxx), ylim=ylim, xaxs = "i")
   ymax <- par("usr")[4]
   ymin <- par("usr")[3]
   startSiteMarks.lwd <- plot.lwd
   arrows.lwd <- plot.lwd
   centerLine.lwd <- plot.lwd
   geneRect.lwd <- plot.lwd
   
   start.end.sites.height <- 0.2

   if(! flip.splicing){
     rect.floor <- 0.1 * (exon.height)
     rect.ceil  <- exon.height
     splice.ceil <- (0.975 * (1-exon.height)) + exon.height
     splice.floor <- rect.ceil
     
     startSite.marker.width <- strwidth("M",cex = anno.cex.text)
     startSite.angle.width <- startSite.marker.width * 1/3
     if(draw.start.end.sites){
       rect.floor <- start.end.sites.height * (exon.height)
       startSites.floor <- 0.05 * exon.height
       endSites.floor <- (rect.floor - startSites.floor) * (1/3) + startSites.floor
     }
     rect.mid   <- ((rect.ceil - rect.floor)/2) + rect.floor
   } else {
     rect.floor <- (1-exon.height)
     rect.ceil  <- (0.975 * exon.height) + rect.floor
     
     splice.ceil <- rect.floor
     splice.floor <- 0.05 * (1-exon.height)
     
     startSite.angle.width <-  strwidth("M",cex = anno.cex.text)  * 1/3
     startSite.marker.width <- strwidth("M",cex = anno.cex.text)  * 1/3
     
     if(draw.start.end.sites){
       startSites.floor <- rect.floor - (0.1 * exon.height)
       endSites.floor <- startSites.floor
       
       if(gapped.flip){
       #proposed alt:
         rect.floor <- (1-exon.height) + start.end.sites.height * exon.height
         startSites.floor <- 0.05 * exon.height + (1-exon.height)
         endSites.floor <- startSites.floor
       }
     }
   }
   rect.mid   <- ((rect.ceil - rect.floor)/2) + rect.floor
   
   if(! is.null(rescale.iv)){
     tr.allExon$start <- (rescale.coords(tr.allExon$start,rescale.iv) * (maxx-minx)) + minx
     tr.allExon$end   <- (rescale.coords(tr.allExon$end,rescale.iv) * (maxx-minx)) + minx
     tr$start <- (rescale.coords(tr$start,rescale.iv) * (maxx-minx)) + minx
     tr$end   <- (rescale.coords(tr$end,rescale.iv) * (maxx-minx)) + minx
     
     
     if(nrow(tr.allJunction) > 0){
       tr.allJunction$start <- (rescale.coords(tr.allJunction$start,rescale.iv) * (maxx-minx)) + minx
       tr.allJunction$end   <- (rescale.coords(tr.allJunction$end,rescale.iv) * (maxx-minx)) + minx
     }
     
     if(draw.start.end.sites){
       startSites <- (rescale.coords(startSites,rescale.iv) * (maxx-minx)) + minx
       endSites <- (rescale.coords(endSites,rescale.iv) * (maxx-minx)) + minx
     }
   }
   
   lines(c(minx,maxx),c(rect.mid,rect.mid),lty= 1, lwd = centerLine.lwd, xpd = xpd, ...)
   if(merge.exon.parts & nrow(tr.allExon) > 1 && any(tr.allExon$start %in% tr.allExon$end) ){
     #merge adjacent exonic parts:
     tr.mergedExon <- data.frame(start = tr.allExon$start[1], end = tr.allExon$end[1])
     tr.breakLine <- c()
     
     for(i in 2:nrow(tr.allExon)){
       j <- nrow(tr.mergedExon)
       if(tr.mergedExon$end[j] == tr.allExon$start[i]){
         tr.mergedExon$end[j] <- tr.allExon$end[i]
         tr.breakLine <- c(tr.breakLine, tr.allExon$start[i])
       } else {
         tr.mergedExon[j+1,] <- c(tr.allExon$start[i], tr.allExon$end[i])
       }
     }
     rect(tr.allExon$start, rect.floor, tr.allExon$end, rect.ceil, lty = 1, lwd = geneRect.lwd ,col=tr.allExon$fillColor, border= "transparent", xpd = xpd,...)
     rect(tr.mergedExon$start, rect.floor, tr.mergedExon$end, rect.ceil, lty = 1, lwd = geneRect.lwd, col = "transparent", border = "black", xpd = xpd, ...)
     segments(tr.breakLine, rect.floor, tr.breakLine, rect.ceil, lty = 3, lwd = geneRect.lwd, col = "gray33", ...)
   } else {
     rect(tr.allExon$start, rect.floor, tr.allExon$end, rect.ceil, lty = 1, lwd = geneRect.lwd ,col=tr.allExon$fillColor, xpd = xpd,...)
   }
   
   if(draw.start.end.sites){
     segments(startSites + startSite.angle.width, startSites.floor,startSites,rect.floor, lwd = startSiteMarks.lwd,xpd=NA,...)
     segments(endSites   - startSite.angle.width,   endSites.floor,  endSites,  rect.floor, lwd = startSiteMarks.lwd,xpd=NA,...)
     
     segments(startSites + startSite.angle.width, startSites.floor,  startSites + startSite.marker.width, startSites.floor, lwd = startSiteMarks.lwd,xpd=xpd,...)
     segments(endSites   - startSite.angle.width,   endSites.floor,  endSites   - startSite.marker.width,   endSites.floor, lwd = startSiteMarks.lwd,xpd=xpd,...)
   }
   
   if(show.strand.arrows > 0){
         strand <- tr.allExon$strand[1]
         
         if(cex.arrows == "auto"){
             arrow.height <- strheight(">", cex = 1)
             if(arrow.height > abs(rect.ceil - rect.floor) * 0.75 ){
               cex.arrows <- (abs(rect.ceil - rect.floor) * 0.75) / arrow.height
             } else {
               cex.arrows <- 1
             }
         }
         if(show.strand.arrows == 1){
           if(strand == "+" || geneStrand == "+"){
             arrow.X <- par("usr")[2] + par("cxy")[1]*1.5
             lines(c(par("usr")[2],arrow.X),c(rect.mid, rect.mid), lwd = arrows.lwd, xpd = NA, ...)
             JS.arrowChars( arrow.X , rect.mid, "right", arrow.cex = cex.arrows, lwd = arrows.lwd, xpd = NA, ...)
           } else if(strand == "-" || geneStrand == "-"){
             arrow.X <- par("usr")[1] - par("cxy")[1]*1.5
             lines(c(par("usr")[1],arrow.X),c(rect.mid, rect.mid), lwd = arrows.lwd, xpd = NA, ...)
             JS.arrowChars( arrow.X , rect.mid, "left", arrow.cex = cex.arrows, lwd = arrows.lwd, xpd = NA, ...)
           }
         } else {
           arrow.X <-((1:(show.strand.arrows - 1)) / (show.strand.arrows)) * (maxx - minx) + minx
           if(strand == "+" || geneStrand == "+"){
              JS.arrowChars( arrow.X ,rep(rect.mid,length(arrow.X)), "right", arrow.cex = cex.arrows, lwd = arrows.lwd, ...)
           } else if(strand == "-" || geneStrand == "-"){
              JS.arrowChars( arrow.X ,rep(rect.mid,length(arrow.X) - 1), "left", arrow.cex = cex.arrows, lwd = arrows.lwd, ...)
           }
         }
   }
   if(nrow(tr.allJunction) > 0){
      tr.splice <- tr.allJunction
      start.splice <- tr.splice$start
      end.splice <- tr.splice$end
      middle.splice <- apply(rbind(start.splice, end.splice), 2, median)
      if(draw.nested.SJ){
        if(is.null(INTERNAL.VARS[["SJ.ceiling"]])){
          tr.splice$span <- tr.splice$end - tr.splice$start
          nh <- get.nested.heights(as.data.frame(tr.splice), splice.floor, splice.ceil)
          SJ.ceiling <- nh[["SJ.ceiling"]]
        } else {
          SJ.ceiling <- INTERNAL.VARS[["SJ.ceiling"]]
          SJ.ceiling <- SJ.ceiling * abs(splice.ceil - splice.floor) + splice.floor
          SJ.ceiling <- SJ.ceiling[match(names(SJ.ceiling), tr.splice$featureID)]
        }
      } else {
        SJ.ceiling <- splice.ceil
      }
      if(any(tr.splice$is.plotted)){
        segments(middle.splice[tr.splice$is.plotted], SJ.ceiling[tr.splice$is.plotted], middle.splice[tr.splice$is.plotted], ymax, col=tr.splice$lineColor[tr.splice$is.plotted], lty = tr.splice$lty[tr.splice$is.plotted], lwd = plot.lwd, xpd=xpd,...)
      }
      
      if(draw.curved.SJ){
        if(flip.splicing){
           drawHalfLoops("up",start.splice, end.splice, splice.ceil - SJ.ceiling + splice.floor, splice.ceil, col = tr.splice$lineColor, lwd = plot.lwd, xpd = xpd, lty = tr.splice$lty, style = splice.junction.drawing.style, ...)
        } else {
           drawHalfLoops("down",start.splice, end.splice, splice.floor,SJ.ceiling, col = tr.splice$lineColor, lwd = plot.lwd, xpd = xpd, lty = tr.splice$lty, style = splice.junction.drawing.style, ...)
        }
      } else {
        if(flip.splicing){
          segments(start.splice, splice.ceil - SJ.ceiling + splice.floor, middle.splice, splice.ceil, col=tr.splice$lineColor, lty = tr.splice$lty, lwd = plot.lwd, xpd=xpd,...)
          segments(middle.splice, splice.ceil, end.splice, splice.ceil - SJ.ceiling + splice.floor, col=tr.splice$lineColor,   lty = tr.splice$lty, lwd = plot.lwd, xpd=xpd,...)
        } else {
          segments(start.splice, splice.floor, middle.splice, SJ.ceiling, col=tr.splice$lineColor, lty = tr.splice$lty, lwd = plot.lwd, xpd=xpd,...)
          segments(middle.splice, SJ.ceiling, end.splice, splice.floor, col=tr.splice$lineColor,   lty = tr.splice$lty, lwd = plot.lwd, xpd=xpd,...)
        }

      }
    }

   if( any(tr$is.exon) && draw.exon.lines){
      tr.ex <- tr[tr$is.exon, , drop = FALSE]
      middle.ex <- apply(rbind(tr.ex$start,tr.ex$end),2,median)
      colors.ex <- exoncol[tr$is.exon]
      segments(middle.ex, rect.ceil, middle.ex, ymax, col=colors.ex, lty = exonlty[tr$is.exon], lwd = plot.lwd, xpd = xpd,...)
   }
   

}


JS.arrowChars <- function(xcenter, ycenter, direction, arrow.cex, lwd, ...){
  arrow.width = strwidth(">", cex= arrow.cex)
  arrow.height = strheight(">", cex = arrow.cex)
  if(direction == "left"){
    segments(xcenter,ycenter,xcenter + arrow.width,ycenter + arrow.height / 2, lwd = lwd, lend = 0, ...)
    segments(xcenter,ycenter,xcenter + arrow.width,ycenter - arrow.height / 2, lwd = lwd, lend = 0, ...)
  } else if(direction == "right"){
    segments(xcenter - arrow.width,ycenter + arrow.height / 2, xcenter, ycenter, lwd = lwd, lend = 0, ...)
    segments(xcenter - arrow.width,ycenter - arrow.height / 2, xcenter, ycenter, lwd = lwd, lend = 0, ...)
  }
}

drawGene.noSplices <- function(minx, maxx, tr.allExon, exon.names=NULL, anno.lwd = 1, par.cex = 1, anno.cex.text = 1, ...)
{
   plot.new()
   par(cex = par.cex)
   plot.window(xlim=c(minx, maxx), ylim=c(0, 1))

   rect(tr.allExon[,1], 0, tr.allExon[,2], 0.75, col="lightgrey", lty = 1, lwd=anno.lwd,...)
   
   if(! is.null(exon.names)){
     text(apply(tr.allExon,1,mean),0.5,labels=exon.names,srt=90, cex = anno.cex.text)
   }
}


drawTranscript <- function(minx, maxx, ymin, tr, tr.allJunction, rango, rescale.iv = NULL, names, trName, trStrand = ".", sub.sig, 
                           anno.lwd = 1, par.cex = 1, anno.cex.text = 1, anno.cex.TX.ID = anno.cex.text * 0.5, 
                           cex.arrows = 1, draw.strand = FALSE, labelPosition = c("above","left"),
                           ...)
{
   if(cex.arrows == "auto") cex.arrows <- 1
   labelPosition <- match.arg(labelPosition)
   
   exon.height = 0.8
   if(! is.null(trName)){
     if(labelPosition == "above"){
       id.ht <- strheight(trName, cex = anno.cex.TX.ID)
       if(id.ht < 0.75){
         exon.height <- 0.75 - id.ht
       } else {
         exon.height <- 0.25
       }
     } 
   }
   splice.top <- exon.height * 0.9
   splice.mid <- splice.top / 2
   #Change? Splice junctions are now plotted at straight lines in TX annotation?
   #        Note to dev: No, leave it as-is. It looks better this way.
   tr.raw <- tr
   
   is.adjacent <- tr$start[-1] == tr$end[-length(tr$end)]
   tr.mergedExons <- data.frame(start = tr.raw$start[1], end = tr.raw$end[1])
   exon.breaks <- c()
   if(nrow(tr.raw) > 1){
     for(i in 2:nrow(tr.raw)){
       if( tr.raw$start[i] == tr.mergedExons$end[nrow(tr.mergedExons)] ){
         tr.mergedExons$end[nrow(tr.mergedExons)] <- tr.raw$end[i]
         exon.breaks <- c(exon.breaks, tr.raw$start[i])
       } else {
         tr.mergedExons <- rbind(tr.mergedExons, c(tr.raw$start[i], tr.raw$end[i] ))
       }
     }
   } else {
     tr.mergedExons <- tr.raw
   }
   
   if(nrow(tr.mergedExons) > 1){
     tr.splices <- data.frame(start = tr.mergedExons$end[-nrow(tr.mergedExons)], end = tr.mergedExons$start[-1])
     tr.splices$lineColor <- rep("#DDDDDD",nrow(tr.splices))
     for(i in 1:nrow(tr.splices)){
        matched.jct <- which(tr.allJunction$start == tr.splices$start[i] & tr.allJunction$end == tr.splices$end[i] )
        if(length(matched.jct) != 1){
          warning("WARNING: unmatched junction (len=",length(matched.jct),") (Jct #",i,")!\n","[",tr.splices$start[i],",",tr.splices$end[i],"]")
          print("####tr.splices:")
          print(tr.splices)
          print("####tr.allJunctions:")
          print(tr.allJunction)
          print("####tr.mergedExons:")
          print(tr.mergedExons)
          print("####tr.raw:")
          print(tr.raw)
          print("####exon.breaks:")
          print(exon.breaks)
        } else {
          tr.splices$lineColor[i] <- tr.allJunction$lineColor[matched.jct]
        }
     }
   }
   
   if(! is.null(rescale.iv)){
     tr.mergedExons$start <- (rescale.coords(tr.mergedExons$start,rescale.iv) * (maxx-minx)) + minx
     tr.mergedExons$end   <- (rescale.coords(tr.mergedExons$end,  rescale.iv) * (maxx-minx)) + minx
     tr.raw$start <- (rescale.coords(tr.raw$start,rescale.iv) * (maxx-minx)) + minx
     tr.raw$end   <- (rescale.coords(tr.raw$end,  rescale.iv) * (maxx-minx)) + minx;     
     if(nrow(sub.sig) > 0){
       sub.sig$start <- (rescale.coords(sub.sig$start,rescale.iv) * (maxx-minx)) + minx
       sub.sig$end   <- (rescale.coords(sub.sig$end,  rescale.iv) * (maxx-minx)) + minx
     }
     if(nrow(tr.mergedExons) > 1){
       tr.splices$start <- (rescale.coords(tr.splices$start,rescale.iv) * (maxx-minx)) + minx
       tr.splices$end   <- (rescale.coords(tr.splices$end,rescale.iv) * (maxx-minx)) + minx
     }
     if(length(exon.breaks) > 0){
       exon.breaks <- (rescale.coords(exon.breaks,rescale.iv) * (maxx-minx)) + minx
     }
   }
   
   if(nrow(tr.mergedExons) > 1){
     zr <- apply(rbind(tr.splices$start, tr.splices$end), 2, median)
     segments(tr.splices$start, ymin+splice.mid, zr, ymin+splice.top,col=tr.splices$lineColor, lwd = anno.lwd, xpd = NA,...)
     segments(zr, ymin+splice.top,tr.splices$end, ymin+splice.mid,col=tr.splices$lineColor, lwd = anno.lwd, xpd = NA,...)
   }
   
   TX.EXON.BORDER.COLOR <- "black"
   rect(tr.raw$start, ymin, tr.raw$end, ymin+exon.height, col=tr$fillColor, border = "transparent", lwd = anno.lwd / 2, xpd = NA, ...)
   rect(tr.mergedExons$start, ymin, tr.mergedExons$end, ymin+exon.height, col="transparent", border = TX.EXON.BORDER.COLOR, lwd = anno.lwd / 2, xpd = NA, ...)
   

   
   if(length(exon.breaks) > 0){
     segments(exon.breaks,ymin,exon.breaks,ymin+exon.height, col = "black", lwd = anno.lwd / 2, lty = 3, ...)
   }
   

   if(labelPosition == "above"){
     id.wd <- strwidth(trName, cex = anno.cex.TX.ID)
     id.leftX <- tr.raw$start[1]
     if(id.leftX + id.wd > maxx){
       id.leftX <- maxx - id.wd
     }
     text(id.leftX,ymin + 0.8,labels=trName,srt=0,xpd=NA,cex= anno.cex.TX.ID, adj=c(0,1),...)
   } else if(labelPosition == "left"){
     id.wd <- strwidth(trName, cex = anno.cex.TX.ID)
     id.leftX <- tr.raw$start[1]
     text(id.leftX,ymin + 0.5,labels=trName,srt=0,xpd=NA,cex= anno.cex.TX.ID, adj=c(1.1,0.5),...)
   }
   
   
   
   if(draw.strand){
     arrow.height <- strheight(">", cex = anno.cex.TX.ID)
     arrow.width <- convertHeightToWidth(exon.height) / 2
     arrow.len <- par("cxy")[1]*1.75*anno.cex.TX.ID
     
     if(is.null(trStrand)){
       #Do Nothing
     } else if(trStrand == "+"){
       lastEnd <- tr.raw$end[length(tr.raw$end)]
       
       arrow.X <- lastEnd + arrow.len
       arrow.mid <- exon.height/2 + ymin
       
       lines(c(lastEnd,arrow.X),c(arrow.mid, arrow.mid), lwd = anno.lwd / 2, xpd = NA, ...)
       JS.arrowChars( arrow.X , arrow.mid, "right", arrow.cex = anno.cex.TX.ID, lwd = anno.lwd / 2, xpd = NA, ...)
       
     } else if (trStrand == "-"){
       firstStart <- tr.raw$start[1]
       
       arrow.X <- firstStart - arrow.len
       arrow.mid <- exon.height/2 + ymin
       
       lines(c(arrow.X, firstStart),c(arrow.mid, arrow.mid), lwd = anno.lwd / 2, xpd = NA, ...)
       JS.arrowChars( arrow.X , arrow.mid, "left", arrow.cex = anno.cex.TX.ID, lwd = anno.lwd / 2, xpd = NA, ...)
       
     }
   }
}
#############################################


generate.interval.scale <- function(gene.features, exon.fraction, rescaleFunction = c("sqrt","log","linear","34root"), debug.mode = FALSE){
  rescaleFunction <- match.arg(rescaleFunction)
  if(rescaleFunction == "34root"){
    resFunc <- function(x){ x ^ 0.75 }
  } else if(rescaleFunction == "log"){
    resFunc <- function(x){ ifelse(x == 0, 0, log(x)) }
  } else if(rescaleFunction == "sqrt"){
    resFunc <- function(x){ sqrt(x) }
  } else {
    resFunc <- function(x){x}
  }
  
  MAX <- max(c(gene.features$start, gene.features$end))
  MIN <- min(c(gene.features$start, gene.features$end))
  SPAN <- MAX - MIN
  
  if(is.na(exon.fraction) || exon.fraction <= 0 || exon.fraction >= 1){ #if rescaling is off, do not rescale!
    iv <- data.frame(start = MIN, end = MAX, span = SPAN,
                       rescale.start = 0, rescale.end = 1, normSpan = 1)
    return(iv)
  }
  
  exon.iv <- data.frame(start = gene.features$start[gene.features$is.exon], 
                            end = gene.features$end[gene.features$is.exon])
  exon.iv$span <- exon.iv$end - exon.iv$start
  intr.iv <- data.frame(start = exon.iv$end[-nrow(exon.iv)], end = exon.iv$start[-1])
  if(max(exon.iv$end) < MAX){
    intr.iv <- rbind.data.frame(intr.iv,data.frame(start = max(exon.iv$end), end = MAX))
  }
  if(min(exon.iv$start) > MIN){
    intr.iv <- rbind.data.frame(data.frame(start = MIN, end = min(exon.iv$start)),intr.iv)
  }
  exon.iv$span <- exon.iv$end - exon.iv$start
  intr.iv$span <- intr.iv$end - intr.iv$start
  
  
  if((nrow(intr.iv) > 0) && sum(intr.iv$span) > 0 ){
    exon.iv$type <- "E"
    intr.iv$type <- "I"
    exon.iv$normSpan <- exon.fraction * resFunc(exon.iv$span) / sum(resFunc(exon.iv$span))
    intr.iv$normSpan <- (1 - exon.fraction) * resFunc(intr.iv$span) / sum(resFunc(intr.iv$span))
    
    #alternate intron and exon:
    
    iv <- rbind(exon.iv, intr.iv)
    iv <- iv[order(iv$start, iv$end),,drop=FALSE]
    cumulativeSum <- cumsum(iv$normSpan)
    
    iv$rescale.start <- c(0,cumulativeSum[-length(cumulativeSum)])
    iv$rescale.end <- cumulativeSum
    iv$normSpan <- iv$rescale.end - iv$rescale.start
    iv$simple.normSpan <- iv$span / sum(iv$span)
    iv$simple.rescale.start <- (iv$start - MIN) / SPAN
    iv$simple.rescale.end   <- (iv$end - MIN) / SPAN
    return(iv)
  } else { #Catch special case: the entire gene is exonic:
    exon.iv$type <- "E"
    exon.iv$normSpan <- 1 * resFunc(exon.iv$span) / sum(resFunc(exon.iv$span))
    
    iv <- exon.iv
    cumulativeSum <- cumsum(iv$normSpan)
    iv$rescale.start <- c(0,cumulativeSum[-length(cumulativeSum)])
    iv$rescale.end <- cumulativeSum
    iv$normSpan <- iv$rescale.end - iv$rescale.start
    iv$simple.normSpan <- iv$span / sum(iv$span)
    iv$simple.rescale.start <- (iv$start - MIN) / SPAN
    iv$simple.rescale.end   <- (iv$end - MIN) / SPAN
    return(iv)
  }
}

rescale.coords <- function(x, rescale.iv){
  sapply(x, FUN=function(y){
    idy <- which(y >= rescale.iv$start & y <= rescale.iv$end)[1]
    pct <- (y - rescale.iv$start[idy]) / rescale.iv$span[idy]
    rescale.iv$rescale.start[idy] + rescale.iv$normSpan[idy] * pct
  })
}

#############################################
#Expansion of axis.break from the plotrix package
# adds the ability to modify additional graphical parameters, and fixes a bug where
# this function globally overrides certain graphical parameters via par().

qorts.axis.break <- function (axis = 1, breakpos = NULL, pos = NA, bgcol = "white", 
    breakcol = "black", style = "slash", cex = 1, xw = NULL, yw = NULL,...) 
{
    brw <- strwidth("W",cex = cex, units="figure")
    brh <- strheight("W",cex = cex, units="figure")
    figxy <- par("usr")
    xaxl <- par("xlog")
    yaxl <- par("ylog")
    if(is.null(xw)) xw <- (figxy[2] - figxy[1]) * brw
    if(is.null(yw)) yw <- (figxy[4] - figxy[3]) * brh
    if (!is.na(pos)) 
        figxy <- rep(pos, 4)
    if (is.null(breakpos)) 
        breakpos <- ifelse(axis%%2, figxy[1] + xw * 2, figxy[3] + 
            yw * 2)
    if (xaxl && (axis == 1 || axis == 3)) 
        breakpos <- log10(breakpos)
    if (yaxl && (axis == 2 || axis == 4)) 
        breakpos <- log10(breakpos)
    switch(axis, 
        br <- c(breakpos - xw/2, figxy[3] - yw/2, breakpos + xw/2, figxy[3] + yw/2), 
        br <- c(figxy[1] - xw/2, breakpos - yw/2, figxy[1] + xw/2, breakpos + yw/2), 
        br <- c(breakpos - xw/2, figxy[4] - yw/2, breakpos + xw/2, figxy[4] + yw/2), 
        br <- c(figxy[2] - xw/2, breakpos - yw/2, figxy[2] + xw/2, breakpos + yw/2), 
        stop("Improper axis specification."))
    if (xaxl) 
        br[c(1, 3)] <- 10^br[c(1, 3)]
    if (yaxl) 
        br[c(2, 4)] <- 10^br[c(2, 4)]
    if (style == "gap") {
        if (xaxl) {
            figxy[1] <- 10^figxy[1]
            figxy[2] <- 10^figxy[2]
        }
        if (yaxl) {
            figxy[3] <- 10^figxy[3]
            figxy[4] <- 10^figxy[4]
        }
        if (axis == 1 || axis == 3) {
            rect(breakpos, figxy[3], breakpos + xw, figxy[4], 
                col = bgcol, border = bgcol)
            xbegin <- c(breakpos, breakpos + xw)
            ybegin <- c(figxy[3], figxy[3])
            xend <- c(breakpos, breakpos + xw)
            yend <- c(figxy[4], figxy[4])
            if (xaxl) {
                xbegin <- 10^xbegin
                xend <- 10^xend
            }
        }
        else {
            rect(figxy[1], breakpos, figxy[2], breakpos + yw, 
                col = bgcol, border = bgcol)
            xbegin <- c(figxy[1], figxy[1])
            ybegin <- c(breakpos, breakpos + yw)
            xend <- c(figxy[2], figxy[2])
            yend <- c(breakpos, breakpos + yw)
            if (xaxl) {
                xbegin <- 10^xbegin
                xend <- 10^xend
            }
        }
    }
    else {
        if (style == "slash") {
            if (axis == 1 || axis == 3) {
                xbegin <- c(breakpos - xw, breakpos)
                xend <- c(breakpos, breakpos + xw)
                ybegin <- c(br[2], br[2])
                yend <- c(br[4], br[4])
                if (xaxl) {
                  xbegin <- 10^xbegin
                  xend <- 10^xend
                }
            }
            else {
                xbegin <- c(br[1], br[1])
                xend <- c(br[3], br[3])
                ybegin <- c(breakpos - yw, breakpos)
                yend <- c(breakpos, breakpos + yw)
                if (yaxl) {
                  ybegin <- 10^ybegin
                  yend <- 10^yend
                }
            }
        }
        else {
            if (axis == 1 || axis == 3) {
                xbegin <- c(breakpos - xw/2, breakpos - xw/4, 
                  breakpos + xw/4)
                xend <- c(breakpos - xw/4, breakpos + xw/4, breakpos + 
                  xw/2)
                ybegin <- c(ifelse(yaxl, 10^figxy[3 + (axis == 
                  3)], figxy[3 + (axis == 3)]), br[4], br[2])
                yend <- c(br[4], br[2], ifelse(yaxl, 10^figxy[3 + 
                  (axis == 3)], figxy[3 + (axis == 3)]))
                if (xaxl) {
                  xbegin <- 10^xbegin
                  xend <- 10^xend
                }
            }
            else {
                xbegin <- c(ifelse(xaxl, 10^figxy[1 + (axis == 
                  4)], figxy[1 + (axis == 4)]), br[1], br[3])
                xend <- c(br[1], br[3], ifelse(xaxl, 10^figxy[1 + 
                  (axis == 4)], figxy[1 + (axis == 4)]))
                ybegin <- c(breakpos - yw/2, breakpos - yw/4, 
                  breakpos + yw/4)
                yend <- c(breakpos - yw/4, breakpos + yw/4, breakpos + 
                  yw/2)
                if (yaxl) {
                  ybegin <- 10^ybegin
                  yend <- 10^yend
                }
            }
        }
    }
    segments(xbegin, ybegin, xend, yend, col = breakcol, lty = 1, xpd = NA, ...)
    
}

JS.axis <- function(side, at, labels = at, tcl = -0.5, lwd = 1, lwd.ticks = 1, cex.axis = 1, srt = 0, line = NA, pos = NA, adj = c(0.5,1.1), font = 1, ...){
  
  if(side == 1){
    axis.height <- par("usr")[3]
    axis.tick.floor <- axis.height + (tcl * (2 * par("cxy")[2]))
    segments(at, axis.tick.floor,at, axis.height, lwd = lwd.ticks, cex = cex.axis, xpd = NA, ...)
    devlim <- device.limits()

    axis.label.height <- abs((axis.tick.floor - devlim[3])/2) + devlim[3]
    
    text(x = at, y = axis.label.height, labels = labels, cex = cex.axis, adj = adj, srt = srt, xpd = NA, font = font,...)
    axis.floor <- axis.label.height - max(strheight(labels, cex = cex.axis))
    
    
    return(axis.floor)
  }
}

drawHalfLoops <- function(dir = c("down","up","left","right"), x0,x1,y0,y1,sampleCt = 100, col = "black", lwd = 1, lty = 1, style = c("hyperbola","ellipse","triangular","line"), ...){
  dir <- match.arg(dir)
  style <- match.arg(style)
  
  len <- max(sapply(list(x0,x1,y0,y1),length))
  if(length(x0) == 1) x0 <- rep(x0,len)
  if(length(x1) == 1) x1 <- rep(x1,len)
  if(length(y0) == 1) y0 <- rep(y0,len)
  if(length(y1) == 1) y1 <- rep(y1,len)
  if(length(col) == 1) col <- rep(col, len)
  if(length(lwd) == 1) lwd <- rep(lwd,len)
  if(length(lty) == 1) lwd <- rep(lty,len)
  for(i in 1:len){
    drawHalfLoop(dir = dir, x0 = x0[i], x1 = x1[i], y0 = y0[i], y1 = y1[i], sampleCt = sampleCt, col = col[i], lwd = lwd[i], lty = lty[i], style = style, ...)
  }
}

#This handy little function draws a bracket or "half-loop" in a number of different styles. 
# \item{dir}{ The "open" direction of the half-loop. Not all directions are currently implemented for all styles. }
# \item{x0,x1,y0,y1}{ The x and y limits of the loop.}
# \item{sampleCt}{ The number of points to draw to form the shape. Higher sampleCt values will produce smoother curves. Not applicable to all styles.  }
# \item{style}{ the half-loop style. hyperbola produces a pair of mirrored hyperbolas with the ends straightened out.
#               ellipse produces an ellipse over the region.
#               triangular produces a isosceles triangle over the region.
#               line produces a simple line segment along the "open" edge.
#               Some styles will be affected by the styleFactor parameter.}
# \item{styleFactor}{
#                Currently only implemented for the hyperbola style. The default is c(8,8,0.5). The first number is the maximum X value, the second value is the maximum Y value.
#                The third value determines the proportion of the vertical space that is straightened out.
#                This function then calculates a curve for Y = 1 / X over the range c(1 / styleFactor[2], styleFactor[1]). The curve is then mirrored and refitted alongside straight
#                lines to fit in the assigned region.
#}
# \item{...}{ graphical parameters to be passed to the lines function, such as lty, lwd, and col.}
# Note this function is a bit quick-and-dirty, and is definitely NOT optimized for performance.
#
# Future functionality (WIP): "bracket" style.
# 
DRAWHALFLOOP.DEFAULT.HYPERBOLA.STYLEFACTOR <- c(8,8, 0.7)
DRAWHALFLOOP.DEFAULT.HYPERBOLA.SAMPLECT <- 100

DRAWHALFLOOP.DEFAULT.HYPERBOLA.X  <- {
      maxRawX <- DRAWHALFLOOP.DEFAULT.HYPERBOLA.STYLEFACTOR[1]
      maxRawY <- DRAWHALFLOOP.DEFAULT.HYPERBOLA.STYLEFACTOR[2]
      curvePct <- DRAWHALFLOOP.DEFAULT.HYPERBOLA.STYLEFACTOR[3]
      minRawX <- 1 / maxRawY
      sampleCt <- DRAWHALFLOOP.DEFAULT.HYPERBOLA.SAMPLECT
      minRawX <- 1 / maxRawY
      X.raw <- ((1:sampleCt) / sampleCt) * (maxRawX - minRawX) + minRawX
      X <- c(X.raw, X.raw + max(X.raw) - min(X.raw))
      X <- c(min(X), X, max(X))
      X <- X / abs(min(X) - max(X))
      X <- X - min(X)
      X[2] <- X[1]
      X[length(X)-1] <- X[length(X)];  
      X
}
DRAWHALFLOOP.DEFAULT.HYPERBOLA.Y  <- {
      maxRawX <- DRAWHALFLOOP.DEFAULT.HYPERBOLA.STYLEFACTOR[1]
      maxRawY <- DRAWHALFLOOP.DEFAULT.HYPERBOLA.STYLEFACTOR[2]
      curvePct <- DRAWHALFLOOP.DEFAULT.HYPERBOLA.STYLEFACTOR[3]
      sampleCt <- DRAWHALFLOOP.DEFAULT.HYPERBOLA.SAMPLECT
      minRawX <- 1 / maxRawY
      X.raw <- ((1:sampleCt) / sampleCt) * (maxRawX - minRawX) + minRawX
      Y.raw <- 1 / X.raw
      Y.raw <- c(max(Y.raw) * (1 / curvePct), Y.raw)
      Y.raw <- max(Y.raw) - Y.raw
      Y <- c(Y.raw, rev(Y.raw))
      Y <- Y / abs(min(Y) - max(Y))
      Y <- Y - min(Y)
      Y
}

drawHalfLoop <- function(dir = c("down","up","left","right"), x0,x1,y0,y1, sampleCt = NULL, style = c("hyperbola","ellipse","triangular","line"), styleFactor = NULL, ...){
  dir <- match.arg(dir)
  style <- match.arg(style)
  
  if(style == "ellipse"){
    if(is.null(sampleCt)){
      sampleCt <- 100
    }
    if(dir == "down"){
      theta <- (0:sampleCt / sampleCt) * pi
      A <- abs(x1-x0)/2
      B <- abs(y1-y0)
      X <- A * cos(theta) + abs(x1-x0)/2 + x0
      Y <- B * sin(theta) + y0
      lines(X,Y, ...)
    } else if(dir == "up"){
      theta <- ((0:sampleCt) / sampleCt) * pi + pi
      A <- abs(x1-x0)/2
      B <- abs(y1-y0)
      X <- A * cos(theta) + abs(x1-x0)/2 + x0
      Y <- B * sin(theta) + y1
      lines(X,Y, ...)
    } else {
      stop(paste0("Half-loop direction: \"",dir,"\" not supported for style \"",style,"\"."))
    }
  } else if(style == "hyperbola"){
    if(missing(styleFactor) && missing(sampleCt)){
      X <- DRAWHALFLOOP.DEFAULT.HYPERBOLA.X
      Y <- DRAWHALFLOOP.DEFAULT.HYPERBOLA.Y
    } else {
      if(is.null(styleFactor)){
        styleFactor <- c(8,8, 0.7)
      }
      if(is.null(sampleCt)){
        sampleCt <- 100
      }
      maxRawX <- styleFactor[1]
      maxRawY <- styleFactor[2]
      curvePct <- styleFactor[3]
      minRawX <- 1 / maxRawY
      X.raw <- ((1:sampleCt) / sampleCt) * (maxRawX - minRawX) + minRawX
      Y.raw <- 1 / X.raw
      Y.raw <- c(max(Y.raw) * (1 / curvePct), Y.raw)
      Y.raw <- max(Y.raw) - Y.raw
      X <- c(X.raw, X.raw + max(X.raw) - min(X.raw))
      X <- c(min(X), X, max(X))
      X <- X / abs(min(X) - max(X))
      X <- X - min(X)
      Y <- c(Y.raw, rev(Y.raw))
      Y <- Y / abs(min(Y) - max(Y))
      Y <- Y - min(Y)
      X[2] <- X[1]
      X[length(X)-1] <- X[length(X)];      
    }

    if(dir == "down"){
      X <- X * abs(x1-x0) + x0
      Y <- Y * abs(y1-y0) + y0
      lines(X,Y, ...)
    } else if(dir == "up"){
      X <- X * abs(x1-x0) + x0
      Y <- Y * abs(y1-y0) + y0
      Y <- y1 - Y + y0
      lines(X,Y, ...)
    } else{
      stop(paste0("Half-loop direction: \"",dir,"\" not supported for style \"",style,"\"."))
    }
  } else if(style == "triangular"){
    if(dir == "down"){
      xM <- abs(x1-x0)/2 + x0
      lines(c(x0,xM,x1), c(y0,y1,y0), ...)
    } else if(dir == "up"){
      xM <- abs(x1-x0)/2 + x0
      lines(c(x0,xM,x1), c(y1,y0,y1), ...)
    } else if(dir == "left"){
      yM <- abs(y1-y0)/2 + y0
      lines(c(x0,x1,x0), c(y0,yM,y1), ...)
    } else if(dir == "right"){
      yM <- abs(y1-y0)/2 + y0
      lines(c(x1,x0,x1), c(y0,yM,y1), ...)
    } else {
      stop(paste0("Half-loop direction: \"",dir,"\" not supported for style \"",style,"\"."))
    }
  } else if(style == "line"){
    if(dir == "down"){
      lines(c(x0,x1),c(y0,y0),...)
    } else if(dir == "up"){
      lines(c(x0,x1),c(y1,y1),...)
    } else if(dir == "left"){
      lines(c(x0,x0),c(y0,y1),...)
    } else if(dir == "right"){
      lines(c(x1,x1),c(y0,y1),...)
    } else {
      stop(paste0("Half-loop direction: \"",dir,"\" not supported for style \"",style,"\"."))
    }
  } else {
    stop(paste0("Half-loop style: \"",style,"\" not supported."))
  }
}


get.connection.cramp <- function(connection.lines.bottom, connection.lines.top, intron.break.threshold){
   if(is.na(intron.break.threshold)){
     FALSE
   } else {
     #This only applies when there's lots of features:
     if(length(connection.lines.bottom) < 30){
       FALSE
     } else {
       return(any(abs(connection.lines.top - connection.lines.bottom) > intron.break.threshold))
     }
   }
}

#Nests splices inside one another:
# Modified Version: calculates nesting when junctions overlap.
get.nested.heights <- function(tr.splice, ymin, ymax, verbose = TRUE, debug.mode = FALSE){
  tryCatch({
    if(verbose) message("Starting nested heights...")
    get.nested.heights.advanced(tr.splice,ymin,ymax,verbose,debug.mode)
  }, error = function(e){
    message("Construction of nested splices failed. Falling back to simpler nesting method...")
    message("---")
    print(e)
    message("---")
    tryCatch({
      get.nested.heights.FALLBACK(tr.splice,ymin,ymax,verbose,debug.mode)
    }, error = function(e){
      message("Fallback nested splices failed. Falling back to un-nested splices.")
      SJ.ceiling = rep(ymax,nrow(tr.splice))
      names(SJ.ceiling) <- tr.splice$featureID
      return( list( SJ.ceiling = SJ.ceiling, maxDepth = 0 ))
    })
  })
}

#Nests splices inside one another:
# Any splice site is guaranteed to have a lower ceiling than any splice site that contains it.
# The height of a splice site's ceiling depends on the number of splice sites above and below it.
# Splice sites that mutually overlap but are not subsets of one another do not affect one another's height.

get.nested.heights.FALLBACK <- function(tr.splice, ymin, ymax, verbose = TRUE, debug.mode = FALSE){
        num.over <- sapply(1:nrow(tr.splice), function(i){
          sum(tr.splice$start[i] >= tr.splice$start & tr.splice$end[i] <= tr.splice$end ) - 1
        })
        num.under <- sapply(1:nrow(tr.splice), function(i){
          sum(tr.splice$start[i] <= tr.splice$start & tr.splice$end[i] >= tr.splice$end ) - 1
        })
        SJ.ceiling <- (num.under + 1) / (num.over + num.under + 1)
        SJ.ceiling <- SJ.ceiling * abs(ymax-ymin) + ymin
        names(SJ.ceiling) <- tr.splice$featureID
        return(list(  SJ.ceiling = SJ.ceiling, maxDepth = max(num.over)  ))
}



get.nested.heights.advanced <- function(tr.splice, ymin, ymax, verbose = TRUE, debug.mode = FALSE){
  tr <- data.frame(ID = 1:nrow(tr.splice), start = tr.splice$start, end = tr.splice$end, span = tr.splice$end - tr.splice$start)
  
  if(debug.mode) print(tr)
  
  nhh <- get.nested.heights.helper(tr, currDepth = 1, debug.mode = debug.mode)
  if(debug.mode) print(nhh)
  
  tr <- get.nested.heights.depths(nhh, tr)
  
  num.under <- tr$depthBelow - tr$depth
  num.over <- tr$depth
  
  SJ.ceiling <- (num.under + 1) / (num.over + num.under + 1)
  SJ.ceiling <- SJ.ceiling * abs(ymax-ymin) + ymin
  names(SJ.ceiling) <- tr.splice$featureID
  return(list(  SJ.ceiling = SJ.ceiling, maxDepth = max(num.over)  ))
}

repString <- function(s,n){
  paste0(rep(s,n),collapse="")
}

get.nested.heights.helper <- function(tr, currDepth = 1, debug.mode = FALSE){
  if(debug.mode) message(repString("|",currDepth),"^^^^")
  if(debug.mode) message(repString("|",currDepth),"[", paste0(tr$ID,collapse=","),"]")
  intersections <- lapply(1:nrow(tr), function(i){
    tr$start[i] <= tr$end & tr$end[i] >= tr$start
  })
  ixMatrix <- as.matrix(do.call(rbind, intersections))
  notDiag <- as.matrix(do.call(rbind, lapply(1:nrow(tr), function(i){
    out <- rep(TRUE, nrow(tr))
    out[i] <- FALSE
    out
  })))
  ixMatrix <- ixMatrix & notDiag
  numIX <- rowSums( ixMatrix )
  
  if(debug.mode) message(repString("|",currDepth),"numIX=",paste0(numIX,collapse=","))
  
  is.ungrouped <- rep(TRUE,nrow(tr))
  is.alone <- sapply(intersections, function(I){ sum(I) == 1 })
  intersection.groups <- as.list((tr$ID)[is.alone])
  is.in.group <- lapply(intersection.groups, function(ig){ tr$ID %in% ig })
  
  is.ungrouped[is.alone] <- FALSE
  
  if(all(is.alone)){ 
    if(debug.mode) message(repString("|",currDepth),"vvvv")
    return(tr$ID)
  }

  for(i in 1:nrow(tr)){
    if(is.ungrouped[i]){
      g <- length(is.in.group) + 1
      ix <- intersections[[i]]
      is.in.group[[g]] <- ix
      unchecked <- rep(TRUE, nrow(tr))
      unchecked[i] <- FALSE
      while( any(unchecked & is.in.group[[g]]) ){
        j <- min(which(unchecked & is.in.group[[g]]))
        is.in.group[[g]] <- is.in.group[[g]] | intersections[[j]]
        unchecked[j] <- FALSE
      }
      is.ungrouped[is.in.group[[g]]] <- FALSE
      intersection.groups[[length(intersection.groups)+1]] <- tr$ID[is.in.group[[g]]]
    }
  }
  
  if(debug.mode) message(repString("|",currDepth),"GRP: [",paste0(lapply(is.in.group, function(ig){ paste0(tr$ID[ig], collapse=",")}), collapse = "] [" ) ,"]")
  
  out <- lapply(is.in.group, function(ig){
    if(sum(ig) == 1){
      tr$ID[ig]
    } else {
      #order by # intersections, then span:
      if(debug.mode) message(repString("|",currDepth)," For GRP: [",paste0(tr$ID[ig],collapse=","),"]")
      maxIX <- max(numIX[ig])
      if( sum(numIX == maxIX & ig) == 1){
        ex <- which(numIX == maxIX  & ig)
      } else {
        ex <- which( numIX == maxIX  & ig )
        ex <- ex[which.max(tr$span[ex])]
      }
      ig[ex] <- FALSE
      if(debug.mode) message(repString("|",currDepth)," extract: ",tr$ID[ex])
      if(sum(ig) == 1){
        list(parent = tr$ID[ex], children = tr$ID[ig])
      } else {
        list(parent = tr$ID[ex], children = get.nested.heights.helper(tr[ig,,drop=FALSE], currDepth + 1, debug.mode))
      }
    }
  })
  if(debug.mode) message(repString("|",currDepth),"vvvv")
  if(length(out) == 1){
    out[[1]]
  } else {
    out
  }
}

get.nested.heights.depths <- function(nhh, tr){
  depth <- rep(-1, nrow(tr))
  depthBelow <- rep(-1, nrow(tr))
  parents <- list()

  for(i in 1:nrow(tr)){
    currDepth <- 0
    currList <- nhh
    currParents <- list()
    
    while(is.list(currList)){
      if((! is.null(names(currList))) && names(currList)[1] == "parent"){
        if(i == currList$parent){
          currList <- NULL
          depth[i] <- currDepth
        } else {
          currParents <- c(currParents, currList$parent)
          currDepth <- currDepth + 1
          currList <- currList$children
        }
      } else {
        contains.i <- which(sapply(currList, function(L){ any(unlist(L) == tr$ID[i]) }))
        currList <- currList[[contains.i]]
      }
    }
    depth[i] <- currDepth
    parents[[i]] <- currParents
  }
  parentCt <- sapply(parents, function(p){length(p)})
  for(i in 1:nrow(tr)){
    containsi <- sapply(parents,function(p){ any(p == i) })
    if(any(containsi)){
      depthBelow[i] <- max(c(parentCt[containsi],depth[i]))
    } else {
      depthBelow[i] <- max(0,depth[i])
    }
  }
  tr$depth <- depth
  tr$depthBelow <- depthBelow
  tr$parentCt <- parentCt
  tr$lvl <- ifelse(depth == 0 & depthBelow == 0, 1, depth / depthBelow)
  tr$parents <- sapply(parents,function(p){ paste0(p,collapse=",")})
  return(tr)
}

Try the JunctionSeq package in your browser

Any scripts or data that you put into this service are public.

JunctionSeq documentation built on April 28, 2020, 7:57 p.m.