R/RCircosZoomPlot.R

Defines functions RCircos.Plot.Zoomed.Area RCircos.Zoom.Paired.Plot.Positions RCircos.Zoom.Single.Plot.Positions RCircos.Clear.Zoom.Area RCircos.Zoom.Area.Outline RCircos.Plot.Zoomed.Polygons RCircos.Plot.Zoomed.Ideogram.Ticks RCircos.Plot.Zoomed.Tiles RCircos.Plot.Zoomed.Scatters RCircos.Plot.Zoomed.Parallel.Lines RCircos.Plot.Zoomed.Continue.Lines RCircos.Plot.Zoomed.Vertical.Lines RCircos.Plot.Zoomed.Gene.Connectors RCircos.Plot.Zoomed.Histogram RCircos.Label.Zoom.Region RCircos.Mark.Zoom.Area RCircos.Set.Zoom.Plot.Positions RCircos.Get.Zoom.Range RCircos.Get.Zoom.Data

Documented in RCircos.Clear.Zoom.Area RCircos.Get.Zoom.Data RCircos.Get.Zoom.Range RCircos.Label.Zoom.Region RCircos.Mark.Zoom.Area RCircos.Plot.Zoomed.Area RCircos.Plot.Zoomed.Continue.Lines RCircos.Plot.Zoomed.Gene.Connectors RCircos.Plot.Zoomed.Histogram RCircos.Plot.Zoomed.Ideogram.Ticks RCircos.Plot.Zoomed.Parallel.Lines RCircos.Plot.Zoomed.Polygons RCircos.Plot.Zoomed.Scatters RCircos.Plot.Zoomed.Tiles RCircos.Plot.Zoomed.Vertical.Lines RCircos.Set.Zoom.Plot.Positions RCircos.Zoom.Area.Outline RCircos.Zoom.Paired.Plot.Positions RCircos.Zoom.Single.Plot.Positions

#
#   Zoom-in plot for heatmap, point, bar/histogram, vLine, cLine .......
#   Note: zoom-in plot is always done at outside of chromosome ideogram.
#
#   There will be two categories of zoom plot:
#
#   1.  Fixed data width: Examples are heatmap, histogram(bar), connector, 
#       scatters, and gene names. They do not needs to deal with genomic 
#       interval length 
#
#   2.  Segment related:  Examples have vertical lines, continue lines,
#       parallel lines, tiles, 
#
#   Functions
#
#   1.  RCircos.Get.Zoom.Data()
#   2.  RCircos.Get.Zoom.Range()
#   3.  RCircos.Set.Zoom.Plot.Positions()
#   4.  RCircos.Mark.Zoom.Area()
#   5.  RCircos.Label.Zoom.Region()
#   6.  RCircos.Plot.Zoomed.Heatmap()
#   7.  RCircos.Plot.Zoomed.Histogram()
#   8.  RCircos.Plot.Zoomed.Gene.Connectors()
#   9.  RCircos.Plot.Zoomed.Vertical.Lines()
#   10. RCircos.Plot.Zoomed.Continue.Lines()
#   11. RCircos.Plot.Zoomed.Parallel.Lines()
#   12. RCircos.Plot.Zoomed.Scatters()
#   13. RCircos.Plot.Zoomed.Tiles()
#   14. RCircos.Plot.Zoomed.Ideogram.Ticks()
#   15. RCircos.Plot.Zoomed.Polygons()
#   16. RCircos.Zoom.Area.Outline()
#   17. RCircos.Clear.Zoom.Area()
#   18. RCircos.Zoom.Single.Plot.Positions()
#   19. RCircos.Zoom.Paired.Plot.Positions()
#   20. RCircos.Plot.Zoomed.Area()
#
#   Procedures:
#
#   zoom.data <- RCircos.Get.Zoom.Data(plot.data, 
#                   name.col=4, target.gene="TP53");
#   zoom.info <- RCircos.Get.Zoom.Range(zoom.data, 
#                   genomic.cols=3)
#   zoom.pos  <- RCircos.Set.Zoom.Plot.Positions(zoom.info)
#   RCircos.Plot.Zoomed.Heatmap(zoom.data, data.col=5, 
#                   zoom.pos, track.num=2, 
#                   min.value=-3, max.value=3)
#   RCircos.Plot.Zoomed.Heatmap(zoom.data, data.col=6, 
#                   zoom.pos, track.num=3, 
#                   min.value=-3, max.value=3)
#   RCircos.Gene.Labels.On.Zoom(zoom.data, name.col=4, 
#                   zoom.pos, track.num=4)
#
#
#   Last modified on January 06, 2016
#   ________________________________________________________________________
#   <RCircos><RCircos><RCircos><RCircos><RCircos><RCircos><RCircos><RCircos>




#   =========================================================================
#
#   1.  RCircos.Get.Zoom.Data()
#
#   Get zoom data (subset of plot data) based on a gene name or row header
#
#   Arguments:
#
#       plot.data:          A data frame containing genomic positions, gene 
#                           names,and plot values. The data should be already  
#                           sorted by chromosome names then start positions.
#       name.col:           Non-negative integer, column for gene names
#       genomic.columns:    Non-negative integer, total number of columns for
#                           genomic position, valid values are 2 or 3.
#       target.gene:        Character vector, name of gene to be focused on
#       neighbor.genes:     Non-negative integer, how many genes will be plot
#                           on each side of target gene, default 5
#
#       Return value:       A data frame (subset of input dataset)
#       Example:            zoom.data <- RCircos.Get.Zoom.Data(plot.data,  
#                                           name.col=4, target.gene="TP53");
#

RCircos.Get.Zoom.Data <- function(plot.data=NULL, name.col=NULL, 
              genomic.columns=3, target.gene=NULL, neighbor.genes=5)
{
    if(is.null(plot.data) || is.null(name.col) || is.null(target.gene) ||
         is.null(genomic.columns) || is.null(neighbor.genes))
        stop("Missing argument(s) in RCircos.Get.Gene.Info().\n")
    if(genomic.columns < 2 || genomic.columns > 3)
        stop("Total columns for position information should be 2 or 3.\n");
    if(name.col <= genomic.columns) 
        stop("Incorrect name column defined.\n");

    gene.row <- which(as.character(plot.data[, name.col]) == target.gene);
    if(length(gene.row) > 1) gene.row <- gene.row[1];

    from <- gene.row - neighbor.genes;
    to   <- gene.row + neighbor.genes;
    target.rows <- from:to;
    zoom.data <- plot.data[target.rows, ]
    
    # in case target gene is on one end of chromosome
    target.chr <- as.character(plot.data[gene.row,  1])
    zoom.rows <- which(as.character(zoom.data[,1]) == target.chr)
    zoom.data <- zoom.data[zoom.rows,]

    return (zoom.data);
}




#   ==========================================================================
#
#   2.  RCircos.Get.Zoom.Range()
#
#   Extract chromosome name, start position, and end position from plot data
#   with a gene name or row header. If using this function to get zoom-in
#   range, there will be no need to call RCircos.Validate.Genomic.Info().
#
#   Argument:
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and plot values
#       genomic.columns:  Non-negative integer, total number of columns for
#                       genomic position, valid values are 2 or 3.
#
#   Return value:       An vector containing chromosome name, start and end
#                       position.
#
#   Example:    zoom.data <- RCircos.Get.Zoom.Data(plot.data, name.col=4, 
#                                       target.gene="TP53");
#               zoom.info <- RCircos.Get.Zoom.Range(zoom.data, 3)
#
#

RCircos.Get.Zoom.Range <- function(zoom.data=NULL,  genomic.columns=3)
{
    if(is.null(zoom.data) || is.null(genomic.columns))
        stop("Missing argument(s) in RCircos.Get.Gene.Info().\n")
    if(genomic.columns < 2 || genomic.columns > 3)
        stop("Total columns for genomic position should be 2 or 3.\n");

    zoom.chr <- unique(as.character(zoom.data[, 1]))
    if(length(zoom.chr) > 1) 
        stop("Only data on same chromosome could be zoomed-in.\n");

    zoom.start <- min(as.numeric(zoom.data[, 2]));
    zoom.end <- max(as.numeric(zoom.data[, genomic.columns]));
    zoom.range <- c(zoom.chr, zoom.start, zoom.end);    

    RCircos.Validate.Genomic.Info(zoom.range);

    return (zoom.range);
}




#    =========================================================================
#
#   3.  RCircos.Set.Zoom.Plot.Positions()
#
#   Set plot position for zooming-in pot area by selecting index of default
#   plot positions. The zoomed plot will be aligned with the original plot 
#   position such as gene position or a cytoband. The zoom area was defined 
#   as fraction of circle circumference, default is 1/4.
#
#    Arguments: 
#
#       zoom.info:      A vector contains chromosome name, start and optional
#                       end position to be zoomed in
#       total.genes:    integer of 1 ~ maximum number of genes to be plotted.
#                       The maximum number of genes is calculated based on
#                       track height and will be adjusted inside the function
#       area.length:    Non-negative numeric, for better layout, it must be 
#                       smaller than or equal to 1/4
#       gene.width:     Non-negative integer, number of units for gene width
#
#    Return value:      Numeric vector for index of RCircos.Base.Position
#    Example:           RCircos.Set.Zoom.Plot.Positions(area.length=4)
#

RCircos.Set.Zoom.Plot.Positions <- function(zoom.info=NULL, total.genes=11, 
                    area.length=0.25, fixed.width=FALSE, gene.width=NULL)
{
    if(is.null(zoom.info)) 
        stop("Missing zoom info in RCircos.Get.Zoom.Plot.Positions().\n");
    if(total.genes < 1 ) stop("Total genes to zoom must be 1 or more.\n")
 
    RCircos.Pos  <- RCircos.Get.Plot.Positions();
    RCircos.Par  <- RCircos.Get.Plot.Parameters();

    #   Get number of points for polygon width (same as rectangle with
    #   length of track height)
    #   ===================================================================
    #
    if(fixed.width == FALSE) 
    {
        area.points <- nrow(RCircos.Pos)*area.length;
        
    } else {
        if(is.null(gene.width)) {
            gene.width <- ceiling(nrow(RCircos.Pos) * 
                (RCircos.Par$track.height/(2*pi*RCircos.Par$track.out.start)));
        } else {
            if(gene.width<0) 
                stop("Area for a zoomed gene cannot be negative.\n");
        }
        max.genes <- floor(nrow(RCircos.Pos) * area.length / gene.width);
   
        if(total.genes > max.genes)
        {
            stop(paste0("Set area.length=", area.length, 
                " can only plot ", max.genes, "genes.\n"));
        }
        area.points <- ceiling(gene.width*total.genes);
    }  

    #    Default index of RCircos.Pos
    #    ===========================================================
    #
    point.index <- 1:area.points;
    area.center <- floor(area.points/2);

    #    Rotate the index clockwise so that its mid point is the 
    #    center of segment to be zoomed
    #    =========================================================
    #
    target.index <- RCircos.Data.Point(as.character(zoom.info[1]),
        mean(as.numeric(zoom.info[2]), as.numeric(zoom.info[2])));
    distance <- abs(target.index - area.center);
    point.index <- point.index + distance;    
    
    #   In case of rotate the index counter-clockwise 
    #   ============================================================
    #
    zeros <- which(point.index <= 0)
    if(length(zeros)>0) 
        point.index[zeros] <- point.index[zeros] + nrow(RCircos.Pos);

    return (point.index);
}



#   =========================================================================
#
#   4.  RCircos.Mark.Zoom.Area()
#
#   Plot colored area between chromosome highlight and the start location of
#   zoom plot area to mark the original location of zoom-in data on chromosome.
#
#   Arguments:
#
#       zoom.pos:       Non-negative numeric vector, the index of RCircos p
#                       lot position
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and plot values for zoom-in genes/rows       
#       track.num:      Non-negative integer, which track will be plotted
#       color:          Character vector for a color name or a R color
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#
#   Return value:   None
#   Example:        RCircos.Mark.Zoom.Area(zoom.pos, 2)
#

RCircos.Mark.Zoom.Area <- function(zoom.range=NULL, track.num=1, zoom.pos=NULL, 
        fill.color="yellow", inside.pos=NULL, outside.pos=NULL)
{
    if(is.null(zoom.pos) || is.null(zoom.range)) 
        stop("Zoom in position and zoom in data must be defined.\n")

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                        inside.pos, outside.pos);
    out.pos <- boundary[1];
    in.pos  <- boundary[2];

    zoom.start <- zoom.pos[1];
    zoom.end   <- zoom.pos[length(zoom.pos)];
    
    chr.start <- RCircos.Data.Point(as.character(zoom.range[1]),
                        as.numeric(zoom.range[2]));
    chr.end   <- RCircos.Data.Point(as.character(zoom.range[1]),
                        as.numeric(zoom.range[3]));

    rgb.color <- col2rgb(fill.color, alpha=FALSE);
    mark.color <- rgb(rgb.color[1,1]/255, rgb.color[2,1]/255, 
                        rgb.color[3,1]/255, 0.1);

    RCircos.Pos <- RCircos.Get.Plot.Positions();
    RCircos.Par <- RCircos.Get.Plot.Parameters();
    highlight.pos <- RCircos.Par$highlight.pos;

    polygonX <- c(RCircos.Pos[zoom.start:zoom.end, 1]*in.pos, 
                RCircos.Pos[chr.end:chr.start, 1]*highlight.pos);
    polygonY <- c(RCircos.Pos[zoom.start:zoom.end, 2]*in.pos, 
                RCircos.Pos[chr.end:chr.start, 2]*highlight.pos);
    polygon(polygonX, polygonY, col=mark.color);
}




#   =========================================================================
#
#   5.  RCircos.Label.Zoom.Region()
#
#   Plot gene names for zoom-in track(s).
#
#   Arguments:
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and plot values for zoom-in genes/rows
#       name.col:       Non-negative integer, which column is labels
#       track.num:      Non-negative integer, which track will be plotted
#       zoom.pos:       Non-negative numeric vector, the index of RCircos p
#                       lot position
#       text.size:      Size of text for labels
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#
#   Return value:       None
#   Example:            RCircos.Gene.Labels.On.Zoom(zoom.data, 5, zoom.pos, 6)
#

RCircos.Label.Zoom.Region <- function(zoom.data=NULL, name.col=NULL, 
            track.num=NULL, zoom.pos=NULL, text.size=0.75, 
            inside.pos=NULL, outside.pos=NULL)
{    
    if(is.null(zoom.data) || is.null(name.col) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Heatmap().\n");

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                        inside.pos, outside.pos);
    out.pos <- boundary[1];
    in.pos  <- boundary[2];

    RCircos.Pos <- RCircos.Get.Plot.Positions();
    RCircos.Par <- RCircos.Get.Plot.Parameters(); 

    total.gene <- nrow(zoom.data);
    gene.width <- floor(length(zoom.pos) / total.gene);
    label.pos <- (1:nrow(zoom.data))*gene.width - floor(gene.width/2);
    label.pos <- label.pos + zoom.pos[1];

    #   Label all gene names
    #   ==================================================================

    gene.names <- as.character(zoom.data[, name.col]);
    text.start   <- in.pos;
    text.loc <- rep(4, length(label.pos));
    text.loc[which(label.pos > (nrow(RCircos.Pos)/2))] <- 2;

    for(a.gene in seq_len(total.gene))
    {
        index <- label.pos[a.gene]
        text(RCircos.Pos[index, 1]*text.start, 
                RCircos.Pos[index, 2]*text.start, offset=0,
                cex=text.size, srt=RCircos.Pos[index, 3], 
                gene.names[a.gene], pos=text.loc[a.gene]);
    }
}




#    =========================================================================
#
#   6.  RCircos.Plot.Zoomed.Heatmap()
#
#   Plot zoom-in heatmap for a small area with fixed width for each gene. 
#
#   Arguments:
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and plot values for zoom-in genes/rows
#       data.col:       Non-negative integer, which column of plot data
#       track.num:      Non-negative integer, which track will be plotted
#       zoom.pos:       Non-negative numeric vector, the index of RCircos  
#                       plot position
#       min.value:      Numeric, the minimum value of heatmap 
#       max.value:      Numeric, the maximum value for heatmap
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#
#   Return value:   None
#   Example:        RCircos.Plot.Zoomed.Heatmap(zoom.data, 5, zoom.pos, 4)
#

RCircos.Plot.Zoomed.Heatmap <- function (zoom.data=NULL, data.col=NULL, 
            track.num=NULL, zoom.pos=NULL, min.value=NULL, max.value=NULL,
            inside.pos=NULL, outside.pos=NULL)
{
    if(is.null(zoom.data) || is.null(data.col) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Heatmap().\n");

    if(is.null(min.value) || is.null(max.value))
        stop("Min and max heatmap value must be defiend.\n");

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                            inside.pos, outside.pos);                           
    out.pos <- boundary[1];
    in.pos  <- boundary[2];
    
    #   heatmap plot for a sample in zoom-in area
    #   ============================================================
    #
    heatmap.values <- as.numeric(zoom.data[, data.col]);
    heatmap.colors <- RCircos.Get.Heatmap.Data.Colors(heatmap.values, 
                        min.value, max.value);
    gene.width <- floor(length(zoom.pos) / nrow(zoom.data));

    RCircos.Pos <- RCircos.Get.Plot.Positions();                
    for(a.gene in seq_len(length(heatmap.values)))
    {
            first <- zoom.pos[1] + (a.gene-1)*gene.width;
            last  <- first + gene.width;

            polygon(c(RCircos.Pos[first:last, 1]*in.pos, 
                RCircos.Pos[last:first, 1]*out.pos),
                c(RCircos.Pos[first:last , 2]*in.pos, 
                RCircos.Pos[last:first, 2]*out.pos),
                col=heatmap.colors[a.gene], border=NA);
    }
}




#   =========================================================================
#
#   7.  RCircos.Plot.Zoomed.Histogram()
#
#   Plot zoom-in histogram on zoom-in area with fixed width for each gene.
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and plot values for zoom-in genes/rows
#       data.col:       Non-negative integer, which column is labels
#       zoom.pos:       Non-negative numeric vector, the index of RCircos
#                       plot position
#       track.num:      Non-negative integer, which track will be plotted
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#
#   Return value:       None
#   Example:    RCircos.Plot.Zoomed.Histogram(zoom.data, 5, zoom.pos, 1);
#               RCircos.Plot.Zoomed.Histogram(zoom.data, 5, zoom.pos, 
#                                   outside.pos=5.4, inside.pos=5);
#

RCircos.Plot.Zoomed.Histogram <- function(zoom.data=NULL, data.col=NULL, 
            track.num=NULL, zoom.pos=NULL, min.value=NULL, max.value=NULL, 
            inside.pos=NULL, outside.pos=NULL, outline=TRUE) 
{
    if(is.null(zoom.pos) || is.null(zoom.data)) 
        stop("Zoom in position and zoom in data must be defined.\n")

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", inside.pos, 
                                               outside.pos);
    out.pos <- boundary[1];
    in.pos  <- boundary[2];
    gene.width <- floor(length(zoom.pos) / nrow(zoom.data));

    RCircos.Par <- RCircos.Get.Plot.Parameters();
    hist.color  <- RCircos.Get.Plot.Colors(zoom.data, RCircos.Par$hist.color);
    
    if(outline==TRUE)
    {
        layers <- RCircos.Par$sub.tracks;
        RCircos.Zoom.Area.Outline(zoom.pos, in.pos, out.pos, layers);
    }
    
    histValues <- as.numeric(zoom.data[, data.col]);
    if(is.null(max.value) || is.null(min.value)) {
        max.value <- max(histValues);
        min.value <- min(histValues);
    } else {
        if(min.value > max.value) stop("min.value > max.value.")
    }
    hist.height <- RCircos.Get.Data.Point.Height(histValues, min.value, 
                    max.value, plot.type="points", out.pos-in.pos);
    hist.height <- hist.height + in.pos;

    RCircos.Pos <- RCircos.Get.Plot.Positions();
    for(a.gene in seq_len(length(hist.height)))
    {
            first <- zoom.pos[1] + (a.gene-1)*gene.width;
            last  <- first + gene.width;

            polygon(c(RCircos.Pos[first:last, 1]*in.pos, 
                RCircos.Pos[last:first, 1]*hist.height[a.gene]),
                c(RCircos.Pos[first:last, 2]*in.pos, 
                RCircos.Pos[last:first, 2]*hist.height[a.gene]),
                col=hist.color[a.gene]);
    }
}




#   ==========================================================================
#
#   8. RCircos.Plot.Zoomed.Gene.Connectors()
#
#   Plot gene connectors to mark the original location of gene names plotted
#   on the zoom-in area so that more gene labels could be done for a small
#   genomic interval. Gene names should be plotted with fixed area size. 
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and must be sorted by start positions
#       zoom.pos:       Non-negative numeric vector, the index of RCircos p
#                       lot position
#       track.num:      Non-negative integer, the number of a track where
#                       connecter will be started. Default is NULL and if 
#                       inside.pos or outside.pos is not defined, total of 3
#                       tracks will be used to draw connectors.
#       genomic.cols:   Non-negative integer, total number of columns for
#                       genomic positions. Valid values are 2 or 3.
#       line.size:      Non-negative numeric, lwd parameter for line plot.
#       inside.pos:     Non-negative numeric, the close location relative  
#                       to center of plot area
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#
#   Return value:   None
#   Example:        RCircos.Plot.Zoomed.Gene.Connectors(zoom.data, zoom.pos, 
#                           track.num=1, genomic.cols=3, line.size=1);
#                   RCircos.Plot.Zoomed.Gene.Connectors(zoom.data, zoom.pos, 
#                               genomic.cols=3, line.size=1, outside.pos=2.0, 
#                               inside.pos=1.5);
#

RCircos.Plot.Zoomed.Gene.Connectors <- function(zoom.data=NULL, track.num=NULL,  
                zoom.pos=NULL, line.width=1, inside.pos=NULL, outside.pos=NULL) 
{
    if(is.null(zoom.data) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Lines().\n");
    if(is.null(line.width) || line.width < 1) line.size <- 1;
   
    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", inside.pos, 
                                              outside.pos);
    out.pos <- boundary[1]; 
    in.pos  <- boundary[2];

    track.height <- out.pos - in.pos;
    if(is.null(track.num) == FALSE) {
        out.pos <- in.pos + track.height*3;
        low.end   <- in.pos + track.height;
        top.start <- low.end + track.height;
    } else {
        low.end   <- in.pos + track.height * 0.25;
        top.start <- in.pos + track.height * 0.75;
    }

    gene.width <- floor(length(zoom.pos) / nrow(zoom.data));
    label.pos  <- (1:nrow(zoom.data))*gene.width - floor(gene.width/2);
    label.pos <- label.pos + zoom.pos[1];
    gene.pos  <- RCircos.Get.Single.Point.Positions(zoom.data, 
                            genomic.columns=2);
    gene.Pos <- as.numeric(gene.pos$Location)
   
    RCircos.Par <- RCircos.Get.Plot.Parameters();
    line.colors <- RCircos.Get.Plot.Colors(zoom.data, RCircos.Par$line.color);
    
    RCircos.Pos <- RCircos.Get.Plot.Positions();
    for(a.gene in seq_len(length(label.pos)))
    {
        line.x <- c(RCircos.Pos[gene.Pos[a.gene], 1]*in.pos,
                    RCircos.Pos[gene.Pos[a.gene], 1]*low.end,
                    RCircos.Pos[label.pos[a.gene], 1]*top.start,
                    RCircos.Pos[label.pos[a.gene], 1]*out.pos);

        line.y <- c(RCircos.Pos[gene.Pos[a.gene], 2]*in.pos,
                    RCircos.Pos[gene.Pos[a.gene], 2]*low.end,
                    RCircos.Pos[label.pos[a.gene], 2]*top.start,
                    RCircos.Pos[label.pos[a.gene], 2]*out.pos);

        lines(line.x, line.y, lwd=line.width);
    }
}




#   ==========================================================================
#
#   9.  RCircos.Plot.Zoomed.Vertical.Lines()
#
#   Plot zoom-in vertical lines on zoom-in area.
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and plot values for zoom-in genes/rows
#       track.num:      Non-negative integer, which track will be plotted
#       zoom.pos:       Non-negative numeric vector, the index of RCircos
#                       plot position
#       line.width:     Non-negative integet, line width parameter
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#
#   Return value:   None
#   Example:        RCircos.Plot.Zoomed.Vertical.Lines(zoom.data, 
#                               zoom.pos, line.width=4, track.num=5)
#                    RCircos.Plot.Zoomed.Vertical.Lines(zoom.data,  
#                               zoom.pos, line.width=4, outside.pos=5.5, 
#                               inside.pos=4.5)
#

RCircos.Plot.Zoomed.Vertical.Lines <- function(zoom.data=NULL,  
                track.num=NULL, zoom.pos=NULL, line.width=1, 
                inside.pos=NULL, outside.pos=NULL, outline=FALSE) 
{
    if(is.null(zoom.data) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Lines().\n");
    if(line.width < 1) stop("Line width cannot be 0 or less.\n");

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", inside.pos, 
                                               outside.pos);
    out.pos <- boundary[1]; 
    in.pos  <- boundary[2];

    line.pos <- RCircos.Zoom.Single.Plot.Positions(zoom.data, zoom.pos);
    
    RCircos.Par <- RCircos.Get.Plot.Parameters();
    RCircos.Pos <- RCircos.Get.Plot.Positions();
    line.color  <- RCircos.Get.Plot.Colors(zoom.data, RCircos.Par$line.color);
    
    if(outline==TRUE)
    {
        layers <- RCircos.Par$sub.tracks;
        RCircos.Zoom.Area.Outline(zoom.pos, in.pos, out.pos, layers);
    }

    for(a.line in seq_len(length(line.pos)))
    {
        lines(c(RCircos.Pos[line.pos[a.line], 1]*in.pos, 
                RCircos.Pos[line.pos[a.line], 1]*out.pos),
              c(RCircos.Pos[line.pos[a.line], 2]*in.pos, 
                RCircos.Pos[line.pos[a.line], 2]*out.pos),
                col=line.color[a.line], lwd=line.width);
    }
}




#   ==========================================================================
#
#   10.  RCircos.Plot.Zoomed.Continue.Lines()
#
#   Plot continuous lines from one point to next point on zoom in area
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and plot values for zoom-in genes/rows
#       data.col:       Non-negative integer, which column is labels
#       zoom.pos:       Non-negative numeric vector, the index of RCircos 
#                       plot position
#       line.width:     Non-negative integet, line width parameter
#       min.value:      Numeric, minimum value ifor point height
#       max.value:      Numeric, maximum value ifor point height
#       track.num:      Non-negative integer, which track will be plotted
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#
#   Return value:   None
#   Example:        RCircos.Plot.Zoomed.Cotinuous.Lines(zoom.data, 5, zoom.pos,
#                                           4, -5, 5, 1);
#                   RCircos.Plot.Zoomed.Cotinuous.Lines(zoom.data, data.col=5, 
#                           zoom.pos, line.width=4, min.value=-5, max.value=5, 
#                           outside.pos=5, inside.pos=4.5);
#

RCircos.Plot.Zoomed.Continue.Lines <- function(zoom.data=NULL,   
        data.col=NULL, track.num=NULL, zoom.pos=NULL, line.width=1, 
        min.value=NULL, max.value=NULL, inside.pos=NULL, 
        outside.pos=NULL, outline=TRUE) 
{
    if(is.null(zoom.data) || is.null(data.col) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Lines().\n");
    if(line.width < 1) stop("Line width cannot be 0 or less.\n");
    
    if(is.null(min.value) || is.null(max.value))
        stop("min.value and max.value must be defined.\n");

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                          inside.pos, outside.pos);
    out.pos <- boundary[1]; in.pos  <- boundary[2];
    track.height <- out.pos - in.pos;

    #   Points (line start and end) locations
    #   =============================================================
    #
    gene.width <- floor(length(zoom.pos) / nrow(zoom.data));
    point.pos <- (1:nrow(zoom.data))*gene.width - floor(gene.width/2);
    point.pos <- RCircos.Zoom.Single.Plot.Positions(zoom.data, zoom.pos);

    #   Point height
    #   =============================================================
    #
    point.value <- as.numeric(zoom.data[, data.col]);
    point.height <- RCircos.Get.Data.Point.Height(point.value, 
                min.value, max.value, "points", track.height);
    point.height <- point.height + in.pos;

    #   line colors
    #   ===================================================
    #
    RCircos.Par <- RCircos.Get.Plot.Parameters();
    line.colors <- RCircos.Get.Plot.Colors(zoom.data, RCircos.Par$line.color); 

    #   Outline at zoom area
    #   =============================================================
    #
    RCircos.Pos <- RCircos.Get.Plot.Positions();
    if(outline == TRUE)
    {
        layers <- RCircos.Par$sub.tracks;
        RCircos.Zoom.Area.Outline(zoom.pos, in.pos, out.pos, layers);
    }

    for(a.point in seq_len((length(point.pos)-1)))
    {
        point.one <- point.pos[a.point];
        point.two <- point.pos[a.point+1];
        
        lines(c(RCircos.Pos[point.one, 1]*point.height[a.point], 
                RCircos.Pos[point.two, 1]*point.height[a.point+1]),
              c(RCircos.Pos[point.one, 2]*point.height[a.point], 
                RCircos.Pos[point.two, 2]*point.height[a.point+1]),
               col=line.colors[a.point]);
    }
}




#   ==========================================================================
#
#   11. RCircos.Plot.Zoomed.Parallel.Line()
#
#   Plot parallel links between two genomic positions on zoom in area.
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and layer values for zoom-in genes/rows
#       zoom.pos:       Non-negative numeric vector, the index of RCircos 
#                       plot position
#       genomic.cols:   Non-negative integer, total number of columns for
#                       genomic positions. Valid values are 2 or 3.
#       track.num:      Non-negative integer, which track will be plotted
#       line.width:     Non-negative integet, line width parameter
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#
#   Return value:   None
#   Example:    RCircos.Plot.Zoomed.Scatters(zoom.data, 5, zoom.pos, 
#                       min.value=-10, max.value=10, track.num=1)
#               RCircos.Plot.Zoomed.Scatters(zoom.data, 5, zoom.pos,
#                       min.value=-10, max.value=10, 
#                       outside.pos=2.5, inside.pos=2);
#
RCircos.Plot.Zoomed.Parallel.Lines <- function(zoom.data=NULL, track.num=NULL, 
            zoom.pos=NULL, genomic.cols=3, line.width=NULL, 
            inside.pos=NULL, outside.pos=NULL, outline=FALSE) 
{
    if(is.null(zoom.data) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Lines().\n");
    if(line.width < 1) stop("Line width cannot be 0 or less.\n");

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                                inside.pos, outside.pos);
    out.pos <- boundary[1]; 
    in.pos  <- boundary[2];
    track.height <- out.pos - in.pos;

    #   Data points to link each other
    #   ================================================
    #
    line.data <- RCircos.Get.Paired.Points.Positions(zoom.data, 
                       genomic.cols, "tile");
    layers <- RCircos.Get.Plot.Layers(line.data, genomic.cols);
     if(max(layers)==1) {
        line.height <- in.pos + track.height/2;
    } else {
        line.height <- layers*(track.height/max(layers)) + in.pos;
    }
     
    line.location <- RCircos.Zoom.Paired.Plot.Positions(zoom.data, zoom.pos);
    line.start <- line.location[,1];
    line.end   <- line.location[,2];
    
    #   Get link line colors for each pair of locations
    #   ================================================
    #
    RCircos.Par <- RCircos.Get.Plot.Parameters();
    RCircos.Pos <- RCircos.Get.Plot.Positions();
    line.colors <- RCircos.Get.Plot.Colors(line.data, RCircos.Par$line.color);

    #   Draw link lines for each pair of genomic positions
    #   ==========================================
    #
    if(outline == TRUE)
    { RCircos.Zoom.Area.Outline(zoom.pos, in.pos, out.pos, max(layers));}
    for(a.line in seq_len(nrow(line.data)))
    {
        a.start <- line.start[a.line];
        a.end   <- line.end[a.line];
        
        lines(RCircos.Pos[a.start:a.end, 1]*line.height[a.line], 
              RCircos.Pos[a.start:a.end, 2]*line.height[a.line], 
               col=line.colors[a.line], lwd=line.width);
    }
}




#   ==========================================================================
#
#   12. RCircos.Plot.Zoomed.Scatters()
#
#   Plot scatters on zoom in area.
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and plot values for zoom-in genes/rows
#       data.col:       Non-negative integer, which column is labels
#       zoom.pos:       Non-negative numeric vector, the index of RCircos 
#                       plot position
#       line.width:     Non-negative integet, line width parameter
#       min.value:      Numeric, minimum value ifor point height
#       max.value:      Numeric, maximum value ifor point height
#       track.num:      Non-negative integer, which track will be plotted
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#
#   Return value:   None
#   Example:    RCircos.Plot.Zoomed.Scatters(zoom.data, 5, zoom.pos, 
#                       min.value=-10, max.value=10, track.num=1)
#               RCircos.Plot.Zoomed.Scatters(zoom.data, 5, zoom.pos,
#                       min.value=-10, max.value=10, 
#                       outside.pos=2.5, inside.pos=2);
#

RCircos.Plot.Zoomed.Scatters <- function(zoom.data=NULL, data.col=NULL,  
            track.num=NULL, zoom.pos=NULL, min.value=NULL, max.value=NULL,  
            point.type=16, by.fold=0, with.size=TRUE, with.height=FALSE, 
            point.scale=1, inside.pos=NULL, outside.pos=NULL, outline=TRUE) 
{
   if(is.null(zoom.data) || is.null(data.col) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Lines().\n");
    if(is.null(point.scale) || point.scale < 1) point.scale <- 1;
    if(is.null(min.value) || is.null(max.value))
        stop("min.value and max.value must be defined.\n")

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                        inside.pos, outside.pos);
    out.pos <- boundary[1]; 
    in.pos  <- boundary[2];

    #   plot height inside of plot area
    #   =============================================================
    RCircos.Par <- RCircos.Get.Plot.Parameters();
    scatter.values <- as.numeric(zoom.data[, data.col]);   
    if(with.height == TRUE) {
        plot.values <- RCircos.Adjust.Scatter.Values(scatter.values, 
                    max.value, min.value, out.pos-in.pos, 
                    RCircos.Par$sub.track );
    } else { 
        plot.values <- rep((out.pos-in.pos)/2, nrow(zoom.data)); 
    }
    point.height <- in.pos + plot.values;

    #   plot size
    #   ===========================================================
    if(with.size == TRUE)
    {
        point.size <- scatter.values/(max.value-min.value)*10;
    } else {point.size <- rep(point.scale, nrow(zoom.data)); }


    #   plot colors
    #   ===========================================================
    if(by.fold>0) {
        point.colors <- rep("black", nrow(zoom.data));
        red.rows <- which(scatter.values>by.fold);
        if(length(red.rows)>0) point.colors[red.rows] <- "red"; 
        
        blue.rows <- which(scatter.values <= -by.fold);
        if(length(blue.rows)>0) point.colors[blue.rows] <- "blue"; 
    } else {    
        point.colors <- RCircos.Get.Plot.Colors(zoom.data, 
                            RCircos.Par$scatter.color);
    }
                            
    #   Points locations
    #   =============================================================
    #
    point.pos <- RCircos.Zoom.Single.Plot.Positions(zoom.data, zoom.pos)
   
    #   Outline scatter plot at zoom area
    #   =============================================================
    #
    if(outline==TRUE) 
    {
        layers <- RCircos.Par$sub.tracks;
        RCircos.Zoom.Area.Outline(zoom.pos, in.pos, out.pos, layers);
    }
    
    RCircos.Pos <- RCircos.Get.Plot.Positions();
    for(a.point in seq_len(length(point.pos)))
    {
        points(RCircos.Pos[point.pos[a.point], 1]*point.height[a.point],
                RCircos.Pos[point.pos[a.point], 2]*point.height[a.point],
                pch=point.type, cex=point.size[a.point], 
                col=point.colors[a.point]);
    }
}





#   ==========================================================================
#
#   13. RCircos.Plot.Zoomed.Tiles()
#
#   Plot zoomed in tiles on zoom in area. Most of this function is same as
#   parallel link plot except replacing lines() by polygons
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and layer values for zoom-in genes/rows
#       zoom.pos:       Non-negative numeric vector, the index of RCircos 
#                       plot position
#       genomic.cols:   Non-negative integer, total number of columns for
#                       genomic positions. Valid values are 2 or 3.
#       track.num:      Non-negative integer, which track will be plotted
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#
#   Return value:   None
#   Example:    RCircos.Plot.Zoomed.Scatters(zoom.data, 5, zoom.pos, 
#                       min.value=-10, max.value=10, track.num=1)
#               RCircos.Plot.Zoomed.Scatters(zoom.data, 5, zoom.pos,
#                       min.value=-10, max.value=10, 
#                       outside.pos=2.5, inside.pos=2);
#
RCircos.Plot.Zoomed.Tiles <- function(zoom.data=NULL, track.num=NULL, 
                zoom.pos=NULL, genomic.cols=3, layers=5, border.col=NULL, 
                inside.pos=NULL, outside.pos=NULL, outline=TRUE)
{
    if(is.null(zoom.data) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Lines().\n");
    if(genomic.cols != 3) 
        stop("Tile data must have three columns of genomic position.\n");

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                                inside.pos, outside.pos);
    out.pos <- boundary[1]; in.pos  <- boundary[2];
    track.height <- out.pos - in.pos;

    #   Get color, start and end position for each tile 
    #   ================================================
    #
    RCircos.Par <- RCircos.Get.Plot.Parameters();
    tile.colors <- RCircos.Get.Plot.Colors(zoom.data, RCircos.Par$tile.color); 
    tile.location <- RCircos.Zoom.Paired.Plot.Positions(zoom.data, zoom.pos);

    #   Top and bottome locations of each tile
    #   =======================================================
    #
    layer.height <- track.height/layers;
    zoomed.layers <- RCircos.Get.Plot.Layers(zoom.data, genomic.columns=3);
    polygon.bot <- (zoomed.layers-1)*layer.height + in.pos;
    polygon.top <- zoomed.layers*layer.height + in.pos;
    
    RCircos.Pos <- RCircos.Get.Plot.Positions();
    if(outline == TRUE)
    { RCircos.Zoom.Area.Outline(zoom.pos, in.pos, out.pos, layers); }

    for(a.tile in seq_len(nrow(zoom.data)))
    {
        first <- tile.location[a.tile, 1];
        last  <- tile.location[a.tile, 2];
        
        polygon.x <- c(RCircos.Pos[first:last, 1]*polygon.bot[a.tile], 
                       RCircos.Pos[last:first, 1]*polygon.top[a.tile]);
        polygon.y <- c(RCircos.Pos[first:last, 2]*polygon.bot[a.tile], 
                       RCircos.Pos[last:first, 2]*polygon.top[a.tile]);
        polygon(polygon.x, polygon.y, col=tile.colors[a.tile]); 
    }

}



#   ==========================================================================
#
#   14. RCircos.Plot.Zoomed.Ideogram.Ticks()
#
#       Draw chromosome ticks and lables along outside of zoom area. Short 
#       ticks will use one track height and labels will start from one track
#       outside of zoom area unless the inside.pos and outside.pos are used
#       instead of track number.
#       
#       Arguments:
#
#       zoom.info:      A vector contains chromosome name, start and optional
#                       end position to be zoomed in.
#       zoom.pos:       Non-negative numeric vector, the index of RCircos 
#                       plot position
#       tick.interval:  Non-negative numeric, length in million base pairs 
#                       between two chromosome ticks.
#       track.num:      Non-negative integer, which track will be plotted
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#
#       Returned value: None
#       Example:        zoom.pos <- c(1:125000)
#                       RCircos.Plot.Zoomed.Ideogram.Ticks(zoom.pos, )
#
#   

RCircos.Plot.Zoomed.Ideogram.Ticks <- function(zoom.info=NULL, track.num=NULL,
    zoom.pos=NULL, tick.interval=5, inside.pos=NULL, outside.pos=NULL)
{
    if(is.null(zoom.info) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Lines().\n");
    if(tick.interval <= 0) stop("Tick interval must be > 0")

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                                inside.pos, outside.pos);
    out.pos <- boundary[1]; 
    in.pos  <- boundary[2];

    RCircos.Pos <- RCircos.Get.Plot.Positions();
    RCircos.Par <- RCircos.Get.Plot.Parameters();

    #   Tick locations from interval data width 
    #   ========================================================
    interval <- tick.interval*1000000;
    chr.start <- as.numeric(zoom.info[2]);
    chr.end   <- as.numeric(zoom.info[3]);

    #   Move start position to next whole interval
    to.pass <- interval - (chr.start %% interval)
    chr.start <- chr.start + to.pass;
    first.name <- chr.start/interval;

    tick.starts <- seq(chr.start, chr.end, by=interval)
    total.ticks <- length(tick.starts);

    zoom.data <- data.frame(rep(zoom.info[1], total.ticks), tick.starts)
    tick.pos  <- RCircos.Zoom.Single.Plot.Positions(zoom.data, zoom.pos)
    mid.tick.pos <- round((tick.pos[2]-tick.pos[1])/2, digits=0);
    mid.tick.len <- in.pos + (out.pos-in.pos)/2;

    #   line where all ticks start
    line.x <- RCircos.Pos[zoom.pos, 1]*in.pos;
    line.y <- RCircos.Pos[zoom.pos, 2]*in.pos;
    lines(line.x, line.y, col="black");

    text.loc <- rep(4, total.ticks);
    text.loc[which(tick.pos > (nrow(RCircos.Pos)/2))] <- 2;

    for(a.tick in seq_len(total.ticks))
    {
        #   long tick
        lines(c(RCircos.Pos[tick.pos[a.tick],1]*in.pos, 
                RCircos.Pos[tick.pos[a.tick],1]*out.pos),
              c(RCircos.Pos[tick.pos[a.tick],2]*in.pos, 
                RCircos.Pos[tick.pos[a.tick],2]*out.pos),
                col="black");

        #   tick label
        tick.label <- paste0((first.name+a.tick-1)*tick.interval, "MB");
        text(RCircos.Pos[tick.pos[a.tick],1]*out.pos, 
             RCircos.Pos[tick.pos[a.tick],2]*out.pos, 
             tick.label, srt=RCircos.Pos[tick.pos[a.tick], 3],
             offset=0.25, pos=text.loc[a.tick], cex=RCircos.Par$text.size);

        #   short tick
        if(a.tick == total.ticks) next;
        short.tick.pos <- tick.pos[a.tick] + mid.tick.pos;
        lines(c(RCircos.Pos[short.tick.pos,1]*in.pos, 
                RCircos.Pos[short.tick.pos,1]*mid.tick.len),
              c(RCircos.Pos[short.tick.pos,2]*in.pos, 
                RCircos.Pos[short.tick.pos,2]*mid.tick.len),
                col="black");
        
    }
}



#
#   ==========================================================================
#
#   15. RCircos.Plot.Zoomed.Polygons()
#
#       Plot zoomed polygons inside of zoom area. Polygons can be drawn as:
#       1). from top to bottom, 2). from bottom to top, or 3). from middle 
#       to both top and bottom. The difference between zoomed histogram plot 
#       and the second polygon plot is the polygon width. 
#       is 
#       
#       Arguments:
#
#       zoom.data:      A data frame containing genomic positions and
#                       plot values for polygons
#       data.col:       Non-negative integer, which column is labels
#       zoom.pos:       Non-negative numeric vector, the index of RCircos 
#                       plot position
#       tick.interval:  Non-negative numeric, length in million base pairs 
#                       between two chromosome ticks.
#       track.num:      Non-negative integer, which track will be plotted
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#
#       Returned value: None
#       Example:        zoom.pos <- c(1:125000)
#                       RCircos.Plot.Zoomed.Ideogram.Ticks(zoom.pos, )
#
RCircos.Plot.Zoomed.Polygons <- function(zoom.data=NULL, data.col=4, 
                track.num=NULL, zoom.pos=NULL, genomic.cols=3, 
                min.value=NULL, max.value=NULL, border.col=NULL, 
                inside.pos=NULL, outside.pos=NULL, outline=TRUE)
{
    if(is.null(zoom.data) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Lines().\n");
    if(genomic.cols != 3) 
        stop("Polygon data must have three columns of genomic position.\n");
    if(data.col < 4) 
        stop("Data for polygon height must be after genomic positions.\n");
        
    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                                inside.pos, outside.pos);
    out.pos <- boundary[1]; in.pos  <- boundary[2];
    track.height <- out.pos - in.pos;

    #   Get color, start and end position for each tile 
    #   ================================================
    #
    RCircos.Par <- RCircos.Get.Plot.Parameters();
    polygon.colors <- RCircos.Get.Plot.Colors(zoom.data, RCircos.Par$tile.color); 
    polygon.location <- RCircos.Zoom.Paired.Plot.Positions(zoom.data, zoom.pos);

    #   Top and bottom locations of each tile
    #   =======================================================
    #
    data.heights <- as.numeric(zoom.data[,data.col])
    if(is.null(min.value) || is.null(max.value)) {
        min.value <- min(data.heights);
        max.value <- max(data.heights);
    }
    
    polygon.loc <- RCircos.Get.Polygon.Height(zoom.data[, data.col],
        min.value, max.value, inside.pos=in.pos, outside.pos=out.pos);
    bottom <- polygon.loc[,1];
    top    <- polygon.loc[,2];

    if(is.null(border.col)) 
        border.col <- rep(NA, nrow(zoom.data))
    else border.col <- rep(border.col, nrow(zoom.data))
    
    RCircos.Pos <- RCircos.Get.Plot.Positions();

    if(outline == TRUE)
    { 
        if(min.value >= 0 || max.value <= 0) {
            layers <- RCircos.Par$sub.tracks;
        } else { layers <- 10; }   
        RCircos.Zoom.Area.Outline(zoom.pos, in.pos, out.pos, num.layers=layers); 
    }

    for(a.row in seq_len(nrow(zoom.data)))
    {
        a.start <- polygon.location[a.row, 1];
        a.end   <- polygon.location[a.row, 2];
        
        polygon.x <- c(RCircos.Pos[a.start:a.end, 1]*top[a.row], 
                        RCircos.Pos[a.end:a.start, 1]*bottom[a.row]);
        polygon.y <- c(RCircos.Pos[a.start:a.end, 2]*top[a.row], 
                        RCircos.Pos[a.end:a.start, 2]*bottom[a.row]);

        polygon(polygon.x, polygon.y, col=polygon.colors[a.row], 
                        border=border.col);
    }

}




#   ==========================================================================
#
#   16. RCircos.Zoom.Area.Outline()
#
#   Draw outline for zoom area with lines of sub-tracks. This function is
#   mainly for internal use.
#
#   Arguments:
#   
#       outside.pos:    Non-negative numeric, outside position of plot area
#       inside.pos:     Non-negative numeric, inside position of plot area
#       num.layers:     Non-negative integer, total number of sub tracks
#       zoom.positions: Non-negative numeric vector, the index of RCircos 
#                       plot position
#       fill.col:       Character vector of color names
#
#   Returned value:     None
#   Example:            RCircos.Zoom.Area.Outline(zoom.pos=NULL, 
#                           inside.pos=2.5, outside.pos=3, 
#                           num.layers=5, fill.col="yellow")                
#
RCircos.Zoom.Area.Outline <- function(zoom.pos=NULL, inside.pos=NULL, 
        outside.pos=NULL, num.layers=5, fill.col="white")
{
    if(is.null(outside.pos) || is.null(inside.pos) || is.null(zoom.pos))
        stop("Missing arguments for RCircos.Zoom.Area.Outline() ")

    RCircos.Pos <- RCircos.Get.Plot.Positions();
    RCircos.Par <- RCircos.Get.Plot.Parameters();
    
    start.pos <- zoom.pos[1];
    end.pos <- zoom.pos[length(zoom.pos)];
    
    polygonX <- c(RCircos.Pos[start.pos:end.pos,1]*outside.pos,
                  RCircos.Pos[end.pos:start.pos,1]*inside.pos);
    polygonY <- c(RCircos.Pos[start.pos:end.pos,2]*outside.pos,
                  RCircos.Pos[end.pos:start.pos,2]*inside.pos);
    polygon(polygonX, polygonY, col=fill.col);
    
    if(num.layers > 1) {
        if(fill.col=="white") { 
            grid.col <- RCircos.Par$grid.line.color;
        } else { grid.col <- fill.col; }
    
        sub.height <- (outside.pos - inside.pos)/ num.layers;
        for(a.line in seq_len(num.layers)[-num.layers])
        {
            line.height <- inside.pos + sub.height*a.line;
            lines(RCircos.Pos[start.pos:end.pos, 1] * line.height, 
                  RCircos.Pos[start.pos:end.pos, 2] * line.height,
                  col=grid.col);  
        }
    }
}



#   =========================================================================
#
#   17. RCircos.Clear.Zoom.Area
#
#   Erase everything plotted on zoomed area for a data track. Note: marking
#   area cannot be erased since it spans from chromosome highlight to zoom 
#   area and erase this area may remove part or all of a chromosome name.
#
#   Arguments:
# 
#       zoom.pos:       Non-negative numeric vector, the index of RCircos 
#                       plot position
#       inside.pos:     Non-negative numeric, inside position of plot area
#       outside.pos:    Non-negative numeric, outside position of plot area
#
#   Returned value:     None
#   Example:            zoom.position <- c(10000:20000)
#                       RCircos.Clear.Zoom.Area(zoom.pos=zoom.position, 
#                                   inside.pos=2.5, outside.pos=3)
#

RCircos.Clear.Zoom.Area <- function(zoom.pos=NULL, track.num=NULL, 
                            inside.pos=NULL, outside.pos=NULL)
{
    if(is.null(zoom.pos))
        stop("Zoom in position must be defined.\n")

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                        inside.pos, outside.pos);
    out.pos <- boundary[1];
    in.pos  <- boundary[2];

    RCircos.Pos <- RCircos.Get.Plot.Positions();
    RCircos.Par <- RCircos.Get.Plot.Parameters();

    start.pos <- zoom.pos[1]-10;
    end.pos <- zoom.pos[length(zoom.pos)]+10;

    polygonX <- c(RCircos.Pos[start.pos:end.pos ,1]*out.pos,
                    RCircos.Pos[end.pos:start.pos ,1]*in.pos);
    polygonY <- c(RCircos.Pos[start.pos:end.pos ,2]*out.pos,
                    RCircos.Pos[end.pos:start.pos ,2]*in.pos);
    polygon(polygonX, polygonY, col="white", border="white");
}




#   =========================================================================
#
#   18. RCircos.Zoom.Single.Plot.Positions()
#
#   Scale the original plot locations to plot the data on zoom area. This is
#   used to zoom the plot position of data that require only single genomic 
#   positions such as the heatmap, histogram, points and is not suitable for 
#   data with two genomic positions such as tiles, polygons, parallele lines. 
#
#   Arguments:
#
#       zoom.data:  data frame, data to be plotted onto zoom area
#       zoom.pos:   Non-negative numeric vector, index of RCircos base plot
#                   positions
#
#   Returned value: Non-negative numeric vector, index of RCircos base plot
#                   positions
#
#   Example:    data(RCircos.Scatter.Data.RData)
#               data.rows <- which(RCircos.Scatter.Data$Chromosome=="chr11")
#               zoom.data <- RCircos.Scatter.Data[data.rows[11:21], ];
#               zoom.range <- RCircos.Get.Zoom.Range(zoom.data, 3)
#               zoom.pos <- RCircos.Set.Zoom.Plot.Positions(zoom.range, 
#                               total.genes=11)
#               plot.location <- RCircos.Zoom.Original.Plot.Positions(zoom.data,
#                                        zoom.pos)
#

RCircos.Zoom.Single.Plot.Positions <- function(zoom.data=NULL, zoom.pos=NULL)
{
    if(is.null(zoom.data) || is.null(zoom.pos))
        stop("Missing argument in RCircos.Zoom.Original.Plot.Positions()")

    #   Orignal plot locations
    original.loc <- RCircos.Get.Single.Point.Positions(zoom.data, 
                            genomic.columns=2);
    original.loc <- as.numeric(original.loc$Location);
    original.len <- max(original.loc) - min(original.loc);
    
    zoom.factor <- length(zoom.pos)/original.len;
    if(zoom.factor < 1) 
        stop("Length of orignal plot location is greater than zoom position");
   
    zoomed.loc <- original.loc - min(original.loc);
    zoomed.loc <- zoomed.loc * zoom.factor + zoom.pos[1];
    zoomed.loc <- round(zoomed.loc, digits=0);

    return (zoomed.loc);
}




#   =========================================================================
#
#   19. RCircos.Zoom.Paired.Plot.Positions()
#
#   Scale the original paired locations to plot the data on zoom area. This
#   function is used to zoom the plot position of data that require two 
#   genomic positions such as tiles, polygons, and parallele lines. 
#
#   Arguments:
#
#       zoom.data:  data frame, data to be plotted onto zoom area. Must
#                   have three columns for genomic positions
#       zoom.pos:   Non-negative numeric vector, index of RCircos base plot
#                   positions
#
#   Returned value: Non-negative numeric matrix with two columns represents
#                   index of RCircos base plot positions
#
#   Example:    data(RCircos.Tile.Data.RData)
#           data.rows <- which(RCircos.Scatter.Data$Chromosome=="chr11")
#           zoom.data <- RCircos.Scatter.Data[data.rows[11:21], ];
#           zoom.range <- RCircos.Get.Zoom.Range(zoom.data, 3)
#           zoom.pos <- RCircos.Set.Zoom.Plot.Positions(zoom.range, 
#                               total.genes=11)
#           plot.location <- RCircos.Zoom.Paired.Plot.Positions(zoom.data,
#                                        zoom.pos)
#

RCircos.Zoom.Paired.Plot.Positions <- function(zoom.data=NULL, zoom.pos=NULL)
{
    if(is.null(zoom.data) || is.null(zoom.pos))
        stop("Missing argument in RCircos.Zoom.Original.Plot.Positions()")

    RCircos.Validate.Genomic.Data(genomic.data=zoom.data, 
            plot.type="plot", genomic.columns=3)

    #   Convert genomic positions from three columns to two columns 
    #   Note: genomic positions of different data points may overlap
    #
    genome.loc <- c(zoom.data[,2], zoom.data[,3]);
    loc.order <- order(genome.loc);
    chromosomes <- rep(zoom.data[1,1], length(genome.loc));

    plot.data <- data.frame(chromosomes, genome.loc);
    
    #   Get zoomed position for two columns genomic position
    #
    plot.loc <- RCircos.Get.Single.Point.Positions(plot.data, 
                            genomic.columns=2);
    original.loc <- as.numeric(plot.loc$Location);
    original.len <- max(original.loc) - min(original.loc);
    
    zoom.factor <- length(zoom.pos)/original.len;
    if(zoom.factor < 1) 
        stop("Length of orignal plot location is greater than zoom position");
   
    zoom.loc <- original.loc - min(original.loc);
    zoom.loc <- floor(zoom.loc * zoom.factor) + zoom.pos[1];
    zoom.loc <- zoom.loc[order(loc.order)];
    zoom.loc <- round(zoom.loc, digits=0);
    
    #   Covert the vector to two column matrix
    start.loc <- c(1:nrow(zoom.data))
    end.loc   <- start.loc + nrow(zoom.data)
    zoomed.location <- cbind(zoom.loc[start.loc], zoom.loc[end.loc])
    return (zoomed.location);
}




#   =========================================================================
#
#   20. RCircos.Plot.Zoomed.Area()
#   Plot continuous lines from one point to next point on zoom in area
#
#       zoom.data:      A data frame containing genomic positions, gene 
#                       names, and plot values for zoom-in genes/rows
#       data.col:       Non-negative integer, which column is labels
#       zoom.pos:       Non-negative numeric vector, the index of RCircos 
#                       plot position
#       line.width:     Non-negative integet, line width parameter
#       min.value:      Numeric, minimum value ifor point height
#       max.value:      Numeric, maximum value ifor point height
#       track.num:      Non-negative integer, which track will be plotted
#       outside.pos:    Non-negative numeric, the far location relative
#                       to center of plot area
#       inside.pos:     Non-negative numeric, the cloase location relative  
#                       to center of plot area
#
#   Return value:   None
#   Example:        RCircos.Plot.Zoomed.Cotinuous.Lines(zoom.data, 5, zoom.pos,
#                                           4, -5, 5, 1);
#                   RCircos.Plot.Zoomed.Cotinuous.Lines(zoom.data, data.col=5, 
#                           zoom.pos, line.width=4, min.value=-5, max.value=5, 
#                           outside.pos=5, inside.pos=4.5);
#

RCircos.Plot.Zoomed.Area <- function(zoom.data=NULL, plot.type="mountain",
        data.col=NULL, track.num=NULL, zoom.pos=NULL, min.value=NULL, 
        max.value=NULL, area.color="gray", border.col="black",
        inside.pos=NULL, outside.pos=NULL, outline=TRUE) 
{
    if(is.null(zoom.data) || is.null(data.col) || is.null(zoom.pos)) 
        stop("Missing argument in RCircos.Plot.Zoomed.Lines().\n");
    if(! plot.type %in% c("mountain","curtain", "band")) 
        stop("Plot type must be either 'mountain', 'curtain', or 'band'.\n");
    
    if(is.null(min.value) || is.null(max.value))
        stop("min.value and max.value must be defined.\n");

    boundary <- RCircos.Get.Plot.Boundary(track.num, side="out", 
                          inside.pos, outside.pos);
    out.pos <- boundary[1]; in.pos  <- boundary[2];
    track.height <- out.pos - in.pos;

    #   Location of each data point
    #   =============================================================
    #
    point.pos <- RCircos.Zoom.Single.Plot.Positions(zoom.data, zoom.pos)
    area.color <- RCircos.Get.Plot.Colors(zoom.data, area.color);

    #   area height
    #   =============================================================
    #
    if(plot.type != "band")
    {
        area.values <- as.numeric(zoom.data[, data.col]);
        point.height <- RCircos.Get.Data.Point.Height(area.values, min.value, 
            max.value, plot.type="points", track.height=track.height);
        if(plot.type == "mountain")
        {
            area.bot <- rep(in.pos, length(point.height));
            area.top <- in.pos + point.height;
        } else {
            area.top <- rep(out.pos, length(point.height));
            area.bot <- out.pos - point.height;
        }
    } else {
        area.values <- as.matrix(zoom.data[, data.col]);
        differ <- sum(area.values[,1] > area.values[, 2])
        if(differ == 0) {
            bottom <- 1; top <- 2; 
        } else if(differ == nrow(area.values)) {
            top <- 1; bottom <- 2;
        } else { stop("Band top cross area bottom.\n")}

        band.top <- as.numeric(area.values[, top]);
        area.top <- RCircos.Get.Data.Point.Height(band.top, min.value, 
            max.value, plot.type="points", track.height=track.height);
        area.top <- area.top + in.pos;
        
        band.bot <- as.numeric(area.values[, bottom]);
        area.bot <- RCircos.Get.Data.Point.Height(band.bot, min.value, 
            max.value, plot.type="points", track.height=track.height);
        area.bot <- area.bot + in.pos;
    }

    #   Outline at zoom area
    #   =============================================================
    #
    RCircos.Pos <- RCircos.Get.Plot.Positions();
    if(outline == TRUE)
    {
        RCircos.Par <- RCircos.Get.Plot.Parameters();
        layers <- RCircos.Par$sub.tracks;
        RCircos.Zoom.Area.Outline(zoom.pos, in.pos, out.pos, layers);
    }

    polygon.x <- c(RCircos.Pos[point.pos, 1]*area.top, 
                    RCircos.Pos[rev(point.pos), 1]*rev(area.bot));
    polygon.y <- c(RCircos.Pos[point.pos, 2]*area.top, 
                    RCircos.Pos[rev(point.pos), 2]*rev(area.bot));

    polygon(polygon.x, polygon.y, col=area.color, border=border.col);
}


#   End of RCircosZoomPlot.R
#   ________________________________________________________________________
#   <RCircos><RCircos><RCircos><RCircos><RCircos><RCircos><RCircos><RCircos>

Try the RCircos package in your browser

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

RCircos documentation built on March 18, 2022, 7:59 p.m.