#' plot ideogram with data
#' @description plot ideogram with data for multiple chromosomes
#' @param ideo output of \link{loadIdeogram}.
#' @param dataList a \link[GenomicRanges:GRangesList-class]{GRangesList} of data to plot.
#' @param layout The layout of chromosomes. Could be a list with chromosome names
#' as its elements.
#' @param horiz a logical value. If FALSE, the ideograms are drawn vertically
#' to the left. If TRUE, the ideograms are drawn horizontally at the bottom.
#' @param parameterList a list of parameters for each dataset in the dataList.
#' The elements of the parameters could be xlabs, ylabs, etc. type could be
#' barplot, line, point, heatmap.
#' @param colorSheme A character vector of giemsa stain colors.
#' @param gp parameters used for \link[grid]{grid.roundrect}.
#' @param ... parameters not used.
#' @import grid
#' @importFrom GenomeInfoDb seqlevels seqlengths
#' @import S4Vectors
#' @export
#' @examples
#' \dontrun{
#' ideo <- loadIdeogram("hg38")
#' library(rtracklayer)
#' library(grid)
#' dataList <- ideo
#' dataList$score <- as.numeric(dataList$gieStain)
#' dataList <- dataList[dataList$gieStain!="gneg"]
#' dataList <- GRangesList(dataList)
#' grid.newpage()
#' ideogramPlot(ideo, dataList,
#' layout=list("chr1", "chr2", c("chr3", "chr22"),
#' c("chr4", "chr21"), c("chr5", "chr20"),
#' c("chr6", "chr19"), c("chr7", "chr18"),
#' c("chr8", "chr17"), c("chr9", "chr16"),
#' c("chr10", "chr15"), c("chr11", "chr14"),
#' c("chr12", "chr13"), c("chrX", "chrY")),
#' parameterList = list(types="heatmap", colorKeyTitle="sample1"))
#' }
#'
#'
ideogramPlot <- function(ideo, dataList, layout=NULL,
horiz=TRUE,
parameterList=
list(vp=plotViewport(margins=c(.1, 4.1, .3, .1)),
ideoHeight=unit(1/(1+length(dataList)), "npc"),
vgap=unit(.3, "lines"),
ylabs="auto",
ylabsRot=ifelse(horiz, 0, 90),
ylabsPos=unit(2.5, "lines"),
xaxis=FALSE, yaxis=FALSE,
xlab="",
types="barplot", heights=NULL,
dataColumn="score",
gps=gpar(col="black", fill="gray")),
colorSheme=gieStain(),
gp=gpar(fill=NA, lwd=2), ...){
## get the seqlengths
seql <- seqlengths(ideo)
seql <- seql[names(seql) %in% unique(seqnames(ideo))]
stopifnot(is.list(parameterList))
parameterList.default=list(vp=plotViewport(margins=c(.1, 4.1, .3, .1)),
ideoHeight=unit(1/(1+length(dataList)), "npc"),
vgap=unit(.3, "lines"),
ylabs="auto",
ylabsRot=ifelse(horiz, 0, 90),
ylabsPos=unit(2.5, "lines"),
xaxis=FALSE, yaxis=FALSE,
xlab="",
types="barplot", heights=NULL,
dataColumn="score",
gps=gpar(col="black", fill="gray"))
for(n in names(parameterList)){
parameterList.default[[n]] <- parameterList[[n]]
}
if(parameterList.default$ylabs[1]!="auto"){
if(!is.list(parameterList.default$ylabs)){
stop("parameterList$ylabs must be a list with names of seqnames of ideo")
}
if(any(!seqlevels(ideo) %in% names(parameterList.default$ylabs))){
stop("parameterList$ylabs must be a list with names of seqnames of ideo")
}
}
if(all(parameterList.default$types=="heatmap")){
gps <- parameterList.default$gps
if(is(gps, "gpar")){
cols <- list(gps$col)
if(length(cols)==0){
cols <- rep(list(c("green", "black", "red")), length(dataList))
}
if(length(cols)!=length(dataList)){
cols <- rep(cols, length(dataList))
}
}else{
if(length(gps)!=length(dataList)){
stopifnot(all(sapply(gps, is.list)))
gps <- rep(gps, length(dataList))[seq_along(dataList)]
}
cols <- lapply(gps, function(.ele) .ele$col)
}
## get range of data points
rg <- mapply(function(.ele, .cn)
range(as.numeric(as.matrix(mcols(.ele)[, .cn])), na.rm = TRUE),
dataList, parameterList.default$dataColumn, SIMPLIFY = FALSE)
## break value of each color range
v <- lapply(rg, function(.ele){
if(diff(.ele)==0){
c(.ele[1]-.ele[1]/10, .ele[2], .ele[2]+.ele[2]/10)
}else{
seq(.ele[1]-diff(.ele)/10, .ele[2]+diff(.ele)/10, length.out = 101)
}
})
cols <- mapply(function(col, .ele){
if(length(col)==0){
col <- colorRampPalette(c("green", "black", "red"))(100)
}else{
if(length(col)==1){
col <- if(col=="white")
colorRampPalette(c("black", col))(100) else
colorRampPalette(c("white", col))(100)
}else{
col <- colorRampPalette(col)(100)
}
}
if(diff(.ele)==0){
col[c(1, 100)]
}else{
col
}
}, cols, rg, SIMPLIFY = FALSE)
parameterList.default$gps <- mapply(function(col, breaks)
list(col=col, breaks=breaks), cols, v, SIMPLIFY = FALSE)
labels <- parameterList.default$colorKeyTitle
if(length(labels)==0){
labels <- paste0("colorKey", 1:length(dataList))
}
labels.width <- convertX(stringWidth("W"), "inches", valueOnly = TRUE)*nchar(labels)
colorKey.width <- 1
oneChar.width <- convertX(unit(1, "lines"), "inches", valueOnly = TRUE)
pushViewport(viewport(y=unit(1.75, "lines"), height=unit(3.5, "lines"),
width=unit(sum(labels.width) +
length(labels) +
length(labels)*2*oneChar.width,
"inches")))
labels.x.width <- colorKey.width + 2*oneChar.width + labels.width
this.labels.width <- 0
for(i in 1:length(labels)){
pushViewport(viewport(x=unit(labels.x.width[i]/2 + this.labels.width,
'inches'),
width=unit(labels.x.width[i], "inches")))
this.labels.width <- this.labels.width + labels.x.width[i]
this.xscale <- range(v[[i]])
vp <- viewport(x=unit(.5, "inches"), width=unit(1, "inches"),
y=unit(3, "lines"), height=unit(.5, "lines"),
xscale=this.xscale)
pushViewport(vp)
grid.raster(as.raster(matrix(cols[[i]], nrow=1)),
width = 1, height = 1, interpolate=FALSE)
grid.xaxis()
upViewport()
grid.text(label=labels[i],
vp = viewport(x=unit(colorKey.width+oneChar.width+
labels.width[i]/2, "inches"),
width=unit(labels.width[i], "inches"),
y=unit(3, "lines"), height=unit(1, "lines")))
upViewport()
}
upViewport()
pushViewport(plotViewport(margins = c(4.1, 0, 0, 0)))
on.exit(upViewport())
}
parameterList.cp <- parameterList <- parameterList.default
if(any(is.na(seql))){
stop("seqlengths contain NAs")
}
if(length(layout)==0){
if(length(seql)==0){
return()
}
if(length(seql)==1){
plotOneIdeo(ideo, dataList, parameterList, chrom=names(seql),
colorSheme=colorSheme, gp=gp, ...)
return()
}
## 1 column
layout <- as.list(names(seql))
}
stopifnot(is.list(layout))
if(!horiz){
canvas.w <- convertX(unit(1, "npc"), "inch", valueOnly = TRUE)
canvas.h <- convertY(unit(1, "npc"), "inch", valueOnly = TRUE)
tmp <- canvas.h
canvas.h <- convertY(unit(canvas.w, "inch"), "npc")
canvas.w <- convertX(unit(tmp, "inch"), "npc")
pushViewport(viewport(width=canvas.w,
height=canvas.h,
angle=-90))
on.exit(upViewport())
}
layout.df <- data.frame(seq=unlist(layout),
group=rep(1:length(layout), sapply(layout, length)),
stringsAsFactors = FALSE)
layout.df$seqlength <- seql[layout.df$seq]
xscale <- max(sapply(split(layout.df$seqlength, layout.df$group), sum)) * 1.05
vpH <- 1/length(layout)
for(i in sort(unique(layout.df$group))){
this.layout <- layout.df[layout.df$group==i, , drop=FALSE]
vp <- viewport(y=1-vpH*(i-.5), height = vpH, name=paste0("layout", i))
pushViewport(vp)
vpW <- this.layout$seqlength/xscale
if(length(vpW)==1){
vpWgap <- 0
}else{
vpWgap <- (1/1.05-sum(vpW))/(length(vpW)-1)
}
for(j in seq_along(vpW)){
vp <- viewport(x=sum(vpW[-(j:length(vpW))])+.5*vpW[j]+vpWgap*(j-1),
width=vpW[j], name=paste0("layout", i, "_", j))
pushViewport(vp)
parameterList <- parameterList.cp
if(parameterList$ylabs[1]=="auto"){
parameterList$ylabs <- this.layout$seq[j]
}else{
parameterList$ylabs <- parameterList$ylabs[[this.layout$seq[j]]]
}
if(j==length(vpW) && length(vpW)>1){
parameterList$vp$x <-
unit(convertX(unit(1, "npc") - parameterList$vp$x - parameterList$vp$width,
"lines", valueOnly = TRUE), "lines")
parameterList$ylabsPos <- unit(1, "npc") - parameterList$ylabsPos
}
plotOneIdeo(ideo, dataList, parameterList,
chrom=this.layout$seq[j], colorSheme=colorSheme,
gp=gp, ...)
upViewport()
}
upViewport()
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.