plotGeneTrack <- function(track, xscale, chr, yaxis.gp=gpar(), lollipop_style_switch_limit=10){
if(length(track@dat$featureID)!=length(track@dat)){
return(plotGeneModel(track, xscale, chr, yaxis.gp, lollipop_style_switch_limit))
}
if(length(track@dat2)>0){
feature.height <-
if(is.list(track@dat2$feature.height)) track@dat2$feature.height[[1]] else track@dat2$feature.height[1]
if(length(feature.height)==0) feature.height <- .5
unit <- feature.height/4
y <- feature.height/2
}else{
unit <- 0.25
y <- 0.5
}
pos_vjust <- 1.2
neg_vjust <- -0.5
pos_hjust <- 0.2
neg_hjust <- 0.8
## split transcripts by featureID,
## get the ranges of each transcripts
## assign lines for all transcripts
## plot center line for each featureID
## plot exons by the feature type
## plot direction at TSS
## add gene name at TSS
vp <- viewport(xscale = xscale, y=y, height = unit*2)
pushViewport(vp)
trs <- split(track@dat, track@dat$featureID)
col <- track@style@color
rgs <- unlist(GRangesList(sapply(trs, function(.ele)range(unname(.ele)))))
if(length(trs)!=length(rgs)){
stop("some genes are splited into multiple regions, eg multple strand.")
}
strand <- as.character(strand(rgs))
dj <- disjoin(rgs, with.revmap=TRUE)
lineId <- data.frame(id=seq_along(rgs), line=0)
revmap <- dj$revmap
for(i in seq_along(revmap)){
revm <- sort(revmap[[i]])
if(lineId[revm[1], "line"]==0){
lineId[revm[1], "line"] <- 1
}
for(j in seq_along(revm)[-1]){
lineId[revm[j], "line"] <- lineId[revm[j-1], "line"] + 1
}
}
totalLines <- max(lineId$line)
## check height of plot region
unity <- convertHeight(unit(1, "npc"), unitTo = "lines", valueOnly = TRUE)
doLabels <- unity>=totalLines
eachLineHeight <- 1/totalLines
currLineBottom <- 1
unitx <- convertWidth(unit(1, "npc"), unitTo = "lines", valueOnly = TRUE)
arr_size <- min(.5, unitx/length(trs)) #determine arrow size by width/#events
if(!any(c("fontsize", "cex") %in% names(track@style@ylabgp))){
if(doLabels){
track@style@ylabgp$cex <- optFontSize1(.2*y)
}else{
track@style@ylabgp$cex <- arr_size
}
}
for(i in seq.int(totalLines)){
vp <- viewport(y = currLineBottom - eachLineHeight/2,
height = eachLineHeight, xscale = xscale,
clip = 'on')
pushViewport(vp)
if(doLabels){
gene_y <- .75
gene_h <- .5
}else{
gene_y <- .5
gene_h <- 1
}
if(length(track@dat2)>0){
## add a baseline for lollipop plot
grid.lines(x=xscale,
y=c(gene_y, gene_y),
gp = gpar(col=track@style@color),
default.units = "native")
}
trs.sub <- trs[which(lineId$line==i)]
rgs.sub <- rgs[which(lineId$line==i)]
str.sub <- strand[which(lineId$line==i)]
oid <- order(start(rgs.sub))
trs.sub <- trs.sub[oid]
rgs.sub <- rgs.sub[oid]
str.sub <- str.sub[oid]
stringStopPos <- c(0, 0)
for(j in seq_along(trs.sub)){
curr_trs <- trs.sub[[j]]
curr_rg <- rgs.sub[j]
curr_str <- str.sub[j]
str_neg <- curr_str=="-"
this_color <- if(is.list(curr_trs$color)) curr_trs$color[[1]] else if(length(curr_trs$color)) curr_trs$color else col
this_height <-
if(is.list(curr_trs$height)) curr_trs$height[[1]] else if(length(curr_trs$height)) curr_trs$height else gene_h/ifelse(tolower(curr_trs$feature) %in% c('gene', 'transcripts', "cds", "exon"), 2, 4)
hide_this_label <- FALSE
if(length(curr_trs$hide_label)>0){
hide_this_label <- unlist(curr_trs$hide_label)[1]
if(!is.logical(hide_this_label)){
hide_this_label <- FALSE
}
}
must_have_label <- FALSE
if(length(curr_trs$must_have_label)>0){
must_have_label <- unlist(curr_trs$must_have_label)[1]
if(!is.logical(must_have_label)){
must_have_label <- FALSE
}
}
plot_arrow <- TRUE
curr_width <- unit(width(curr_trs)/(diff(xscale)+1), units = 'npc')
if(length(curr_trs)==1 &&
all(tolower(curr_trs$feature) %in% c('gene', 'transcripts'))){
## one element per gene/transcripts
## no center line
if(convertUnit(curr_width, unitTo = 'points', valueOnly = TRUE)<6){
plot_arrow <- TRUE
}else{
plot_arrow <- FALSE
}
}
## plot center line
grid.lines(x=c(start(curr_rg), end(curr_rg)),
y=c(gene_y, gene_y),
gp = gpar(col=col),
default.units = "native")
if(plot_arrow){
## plot exons by the feature type
grid.rect(x=(start(curr_trs)+end(curr_trs))/2, y=gene_y,
width =width(curr_trs),
height=this_height,
gp=gpar(col=NA, fill=this_color),
default.units = "native")
}else{
## plot exons by the feature type
curr_width <- width(curr_trs)/(diff(xscale)+1)
pt1 <- convertWidth(unit(6, units='points'),
'npc', valueOnly = TRUE)*
(diff(xscale)+1)
curr_x1 <- ifelse(!str_neg, start(curr_trs), end(curr_trs))
curr_x2 <- ifelse(!str_neg, end(curr_trs) - pt1,
start(curr_trs) + pt1)
curr_x3 <- ifelse(!str_neg, end(curr_trs), start(curr_trs))
grid.polygon(x=c(curr_x1, curr_x1,
curr_x2, curr_x3,
curr_x2, curr_x1),
y=c(gene_y-this_height/2, gene_y+this_height/2,
gene_y+this_height/2, gene_y,
gene_y-this_height/2, gene_y-this_height/2),
gp=gpar(col=NA, fill=this_color),
default.units = "native")
}
## plot direction at TSS
stringW <- convertWidth(stringWidth(names(curr_rg)), unitTo = "native", valueOnly = TRUE)
pushViewport(viewport(x=ifelse(!str_neg, start(curr_rg), end(curr_rg)),
y=gene_y,
width = unit(max(min(gene_h/2, 2*width(curr_rg)/abs(diff(xscale)+1)),
convertWidth(unit(8, "lines"),
unitTo = "npc",
valueOnly = TRUE)), "snpc"),
height = unit(gene_h/2, "snpc"),
just = c(ifelse(!str_neg, 0, 1), 1),
default.units = "native",
clip = 'off'))
if(!hide_this_label){
if(!str_neg){## positive strand
if(plot_arrow){
grid.lines(x=unit(c(0, 0, 1), "npc"),
y=unit(c(.5, 0, 0), "npc"),
arrow = arrow(type="closed", angle = 15, length = unit(arr_size, "lines")),
gp=gpar(col=this_color, fill=this_color))
}
## add gene name at TSS
if(doLabels || must_have_label){
if(stringStopPos[1] <= stringStopPos[2]){##lower channel
grid.text(label = names(curr_rg), x = 0, y = 0, hjust = pos_hjust, vjust=pos_vjust,
gp = do.call(gpar, track@style@ylabgp))
stringStopPos[1] <- start(curr_rg)+stringW
}else{##higher channel
grid.text(label = names(curr_rg), x = 0, y = 1, hjust = pos_hjust, vjust=neg_vjust,
gp = do.call(gpar, track@style@ylabgp))
stringStopPos[2] <- start(curr_rg)+stringW
}
}else{#dynamic label
if(i %in% c(1, totalLines)){
if(start(curr_rg) >= stringStopPos[1] &&
end(curr_rg) >= stringStopPos[1] + stringW){
if(i==1){#top
grid.text(label = names(curr_rg), x = 0, y = 1,
hjust = pos_hjust, vjust=neg_vjust,
gp = do.call(gpar, track@style@ylabgp))
}else{
grid.text(label = names(curr_rg), x = 0, y = 0,
hjust = pos_hjust, vjust=pos_vjust,
gp = do.call(gpar, track@style@ylabgp))
}
}
stringStopPos[1] <- end(curr_rg)
}
}
}else{## negative strand
if(plot_arrow){
grid.lines(x=unit(c(1, 1, 0), "npc"),
y=unit(c(.5, 0, 0), "npc"),
arrow = arrow(type="closed", angle = 15, length = unit(arr_size, "lines")),
gp=gpar(col=this_color, fill=this_color))
}
## add gene name at TSS
if(doLabels || must_have_label){
if(stringStopPos[1]<=stringStopPos[2]){##lower channel
grid.text(label = names(curr_rg), x = 1, y = 0, hjust = neg_hjust, vjust=pos_vjust,
gp = do.call(gpar, track@style@ylabgp))
stringStopPos[1] <- end(curr_rg)
}else{##higher channel
grid.text(label = names(curr_rg), x = 1, y = 1, hjust = neg_hjust, vjust=neg_vjust,
gp = do.call(gpar, track@style@ylabgp))
stringStopPos[2] <- end(curr_rg)
}
}else{#dynamic label
if(i %in% c(1, totalLines)){
if(start(curr_rg) >= stringStopPos[1] &&
end(curr_rg) >= stringStopPos[1] + stringW){
if(i==1){#bottom
grid.text(label = names(curr_rg), x = 1, y = 1,
hjust = neg_hjust, vjust=neg_vjust,
gp = do.call(gpar, track@style@ylabgp))
}else{
grid.text(label = names(curr_rg), x = 1, y = 0,
hjust = neg_hjust, vjust=pos_vjust,
gp = do.call(gpar, track@style@ylabgp))
}
}
stringStopPos[1] <- end(curr_rg)
}
}
}
}
popViewport()
}
popViewport()
currLineBottom <- currLineBottom - eachLineHeight
}
popViewport()
if(length(track@dat2)>0){
track@dat2 <- orderedGR(track@dat2)
xscale.gr <- GRanges(seqnames = chr, ranges=IRanges(min(xscale), max(xscale)))
track@dat2 <- subsetByOverlaps(track@dat2, xscale.gr, ignore.strand=TRUE)
if(length(track@dat2)<1) return(invisible())
width(track@dat2) <- 1
TYPES <- c("circle", "pie", "pin", "pie.stack", "flag")
type <- if(is.list(track@dat2$type)) track@dat2$type[[1]] else track@dat2$type[1]
if(length(type)==0) type <- "circle"
if(!type %in% TYPES) type <- "circle"
if(type=="pin"){ ## read the pin shape file
pinpath <- system.file("extdata", "map-pin-red.xml", package="trackViewer")
pin <- readPicture(pinpath)
}else{
pin <- NULL
}
cex <- if(is.list(track@dat2$cex)) track@dat2$cex[[1]] else track@dat2$cex[1]
if(length(cex)==0) cex <- 1
dashline.col <- if(is.list(track@dat2$dashline.col)) track@dat2$dashline.col[[1]] else track@dat2$dashline.col[1]
if(length(dashline.col)==0) dashline.col <- "gray80"
jitter <- if(is.list(track@dat2$jitter)) track@dat2$jitter[[1]] else track@dat2$jitter[1]
if(length(jitter)==0) jitter <- "node"
if(!jitter %in% c("node", "label")) jitter <- "node"
scoreMax0 <- scoreMax <-
if(length(track@dat2$score)>0) ceiling(max(c(track@dat2$score, 1), na.rm=TRUE)) else 1
if(type=="pie.stack") scoreMax <- length(unique(track@dat2$stack.factor))
if(!type %in% c("pie", "pie.stack")){
if(scoreMax>lollipop_style_switch_limit) {
track@dat2$score <- 10*track@dat2$score/scoreMax
scoreMax <- 10*scoreMax0/scoreMax
}else{
scoreMax <- scoreMax0
}
scoreType <-
if(length(track@dat2$score)>0) all(floor(track@dat2$score)==track@dat2$score) else FALSE
}else{
scoreType <- FALSE
}
LINEW <- as.numeric(convertX(unit(1, "line"), "npc"))/2
LINEH <- as.numeric(convertY(unit(1, "line"), "npc"))/2
## GAP the gaps between any elements
GAP <- .2 * LINEH
ratio.yx <- getYXratio()
plotLollipops(track@dat2, feature.height=y+unit, bottomHeight=0, baseline=y,
type=type, ranges=xscale.gr, yaxis=FALSE, yaxis.gp=yaxis.gp,
scoreMax=scoreMax, scoreMax0=scoreMax0, scoreType=scoreType,
LINEW, cex, ratio.yx, GAP, pin, dashline.col,
side="top", jitter=jitter)
}
return(invisible())
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.