####################################################################
## Author: Gro Nilsen, Knut Liestøl and Ole Christian Lingjærde.
## Maintainer: Gro Nilsen <gronilse@ifi.uio.no>
## License: Artistic 2.0
## Part of the copynumber package
## Reference: Nilsen and Liestøl et al. (2012), BMC Genomics
####################################################################
# Function that plots the frequency of deletions and amplifications given a threshold on the genome represented by a circle. Can also add arc to represent connections between different
# part of the genome
## Input:
### segments: segmentations results from pcf or multipcf
### thres.gain,thres.loss: a vector with threshold(s) to be applied for abberration calling
### pos.unit: unit used for positions (bp,kbp,mbp)
### freq.colors: colors used to plot gain and loss frequencies
### alpha: a scalar between 0 and 1 that sets the amount of scaling of frequencies in order to fit in circle
### arcs: a data frame with 5 columns. The first four columns gives chromosome numbers and local positions for start point and end point of arc, respectively, while the last column should contain a vector of numbers 1,2,... indication that the arcs belong to different classes. Each class of arcs will then be plotted in a different color
### arc.colors: colors used to plot the lines representing the different classes in arcs. Must be longer or equal to the number of classes found in arcs.
### d: a scalar > 0 representing the distance from the genome circle to the starting points of the arcs. Set d=0 to make arcs start at the genome circle
### assembly: which assembly to use, must be one of hg19, hg18, hg17 or hg16
## Required by: none
### Requires:
## getGlobPos
## numericChrom
## circ
## c.lines
## pullOutContent
## getFreqData
plotCircle <- function(segments, thres.gain, thres.loss = -thres.gain, pos.unit = "bp", freq.colors = c("red", "limegreen"), alpha = 1 / 7, arcs = NULL, arc.colors = c("goldenrod1", "dodgerblue"), d = 0.3, assembly = "hg19") {
delta <- 20000000 # defines the amount of space to be plotted between each chromosome
# Empty plot
par(mar = c(0, 0, 0, 0))
plot(0, 0, xlim = c(-1.2, 1.2), ylim = c(-1.2, 1.2), axes = F, xlab = "", ylab = "", asp = 1, type = "n")
outer.circ <- 0 # location of outer circle
inner.circ <- 0.1 # location of inner circle
# Plot cytoband
cytoband <- get(assembly)
cyto.chr <- substring(cytoband[, 1], 4)
cyto.chr[grep("X", cyto.chr)] <- 23
cyto.chr[grep("Y", cyto.chr)] <- 24
cyto.chr <- as.numeric(cyto.chr)
o <- order(cyto.chr)
cyto.chr <- cyto.chr[o]
cytoband <- cytoband[o, ]
chr.end <- diff(cyto.chr) > 0
cyto.start <- getGlobPos(cyto.chr, cytoband[, 2], pos.unit, cytoband, delta = delta)
cyto.end <- getGlobPos(cyto.chr, cytoband[, 3], pos.unit, cytoband, delta = delta)
cyto.end[chr.end[1]:length(cyto.end)] <- cyto.end[chr.end[1]:length(cyto.end)] + delta # need to add delta between first and second chromosome
cyto.stain <- cytoband[, 5]
xmin <- cyto.start[1]
xmax <- cyto.end[length(cyto.end)]
ngrid <- 5000
gridpts <- seq(xmin, xmax, length = ngrid)
x0 <- gridpts
x1 <- x0
y0 <- rep(0, ngrid)
y1 <- rep(inner.circ, ngrid)
tmp0 <- circ(x0, y0, xmax)
tmp1 <- circ(x1, y1, xmax)
# Get colors for the cytoband
c0 <- rep(0, ngrid)
chr.stop.pos <- c(cyto.end[chr.end], cyto.end[length(cyto.end)])
delta.gridpts <- c()
for (i in 1:ngrid) {
grid.chr <- which(chr.stop.pos >= gridpts[i])[1]
# Check if we are within chromosome or in the delta-region added at the end of each chrom
if (gridpts[i] <= (chr.stop.pos[grid.chr] - delta)) {
band <- which(cyto.end >= gridpts[i])[1]
c0[i] <- switch(cyto.stain[band],
"gneg" = "white",
"gpos100" = "black",
"gpos75" = "gray25",
"gpos50" = "gray50",
"gpos25" = "gray75",
"stalk" = "gray90",
"gvar" = "grey",
"acen" = "yellow"
)
} else {
delta.gridpts <- c(delta.gridpts, i)
# Between chromosomes the color should be white
c0[i] <- "white"
}
}
# Plot cytobands:
segments(tmp0$x[-delta.gridpts], tmp0$y[-delta.gridpts], tmp1$x[-delta.gridpts], tmp1$y[-delta.gridpts], col = c0[-delta.gridpts], lwd = 2)
# Plot outer circle
x <- seq(0, 1, len = 2000)
y <- rep(outer.circ, 2000)
c.lines(x, y, xmax = 1)
# Plot inner circle
x <- seq(0, 1, len = 2000)
y <- rep(inner.circ, 2000)
c.lines(x, y, xmax = 1)
# Plot the white area between each chromosome:
segments(tmp0$x[delta.gridpts], tmp0$y[delta.gridpts], tmp1$x[delta.gridpts], tmp1$y[delta.gridpts], col = c0[delta.gridpts], lwd = 2)
# Plot chromosome borders
borders <- c(chr.stop.pos, chr.stop.pos - delta)
x0 <- borders
x1 <- x0
y0 <- rep(outer.circ - 0.04, length(borders)) # How much lines separating chromosomes will point out of the outer circle
y1 <- rep(inner.circ, length(borders))
tmp0 <- circ(x0, y0, xmax)
tmp1 <- circ(x1, y1, xmax)
segments(tmp0$x, tmp0$y, tmp1$x, tmp1$y, lwd = 3)
# Plot chromosome numbers
chrmiddle <- (chr.stop.pos[1:23] + (chr.stop.pos - delta)[2:24]) / 2
chrmiddle <- c((chr.stop.pos[1] - delta) / 2, chrmiddle) # add middle of chrom 1
x0 <- chrmiddle
y0 <- rep(outer.circ - 0.1, length(chrmiddle))
tmp <- circ(x0, y0, xmax)
text(tmp$x, tmp$y, c(1:22, "X", "Y"))
# Plot frequency of aberration
# Check data input:
# Make sure data input is a data frame (could be a list if it comes from segmentation algorithm or winsorize). Could also be a segments data frame or a data frame with original data.
# data <- pullOutContent(res=data,what="estimates")
data <- segments
if (is.data.frame(data)) {
# Check if segments or data:
data <- getFreqData(data)
} else {
data <- pullOutContent(res = data, what = "estimates")
}
stopifnot(ncol(data) >= 3) # something is missing in input data
# Make sure that chromosomes in data are numeric:
chr <- numericChrom(data[, 1])
pos <- data[, 2]
yhat <- data[, -c(1:2)]
freq.circ <- 1 / 7 + inner.circ # placement of frequencies-circle
m <- freq.circ + (freq.circ - inner.circ) # max space for amp frequencies
AmpFreq <- apply(yhat > thres.gain, 1, mean)
glob.pos <- getGlobPos(chr, pos, pos.unit, cytoband, delta = delta)
x0 <- glob.pos
y0 <- rep(freq.circ, length(x0))
x1 <- x0
y1 <- freq.circ + 0.01 + AmpFreq * alpha # Add 0.01 to avoid overlapping colors
y1[y1 > m] <- m # make sure that frequencies don't exceed the maximum space; truncate large values to this max
tmp0 <- circ(x0, y0, xmax)
tmp1 <- circ(x1, y1, xmax)
segments(tmp0$x, tmp0$y, tmp1$x, tmp1$y, col = freq.colors[1], lwd = 2)
m <- freq.circ - (freq.circ - inner.circ) # max space for del frequencies
DelFreq <- apply(yhat < thres.loss, 1, mean)
x0 <- glob.pos
y0 <- rep(freq.circ, length(x0))
x1 <- x0
y1 <- freq.circ - 0.01 - DelFreq * alpha # Subtract 0.01 to avoid overlapping colors
y1[y1 < m] <- m # make sure that frequencies don't exceed the maximum space; truncate large values to this max
tmp0 <- circ(x0, y0, xmax)
tmp1 <- circ(x1, y1, xmax)
segments(tmp0$x, tmp0$y, tmp1$x, tmp1$y, col = freq.colors[2], lwd = 2)
# Plot x-axis (x-circle)
x <- seq(0, 1, len = 2000)
y <- rep(freq.circ, 2000)
c.lines(x, y, xmax = 1)
# Plot arcs if specified
if (!is.null(arcs)) {
cl <- arcs[, 5]
u.cl <- sort(unique(cl))
if (length(arc.colors) < length(u.cl)) {
arc.colors <- rep(arc.colors, length(u.cl))
warning("Number of colors in 'arc.colors' is fewer than number of unique classes in 'arcs'. Colors are reused.", call.s = FALSE)
}
chr0 <- arcs[, 1]
chr1 <- arcs[, 3]
pos0 <- arcs[, 2]
pos1 <- arcs[, 4]
x0 <- getGlobPos(chr0, pos0, pos.unit, cytoband, delta = delta)
x1 <- getGlobPos(chr1, pos1, pos.unit, cytoband, delta = delta)
m <- d + inner.circ # determine where arcs should start
for (i in 1:length(x0)) {
tmp <- circ(c(x0[i], 0, x1[i]), c(0.1, 1.0, 0.1), xmax)
tmp <- circ(c(x0[i], 0, x1[i]), c(m, 1.0, m), xmax)
a0 <- xspline(tmp$x, tmp$y, shape = c(0, 1, 0), draw = F)
lines(a0$x, a0$y, col = arc.colors[which(u.cl == cl[i])])
}
} # endif
}
# Circos transformation
circ <- function(x, y, xmax) {
x <- x * 2 * pi / xmax
xnew <- (1 - y) * cos(-x + pi / 2)
ynew <- (1 - y) * sin(-x + pi / 2)
list(x = xnew, y = ynew)
}
c.lines <- function(x, y, xmax, ...) {
tmp <- circ(x, y, xmax)
lines(tmp$x, tmp$y, ...)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.