Skip to content

Commit

Permalink
add circos.arrow()
Browse files Browse the repository at this point in the history
  • Loading branch information
jokergoo committed Jun 19, 2017
1 parent 45f5b14 commit d0ce2fc
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 1 deletion.
3 changes: 2 additions & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export('$.CELL_META')
export('circos.arrow')
export('circos.axis')
export('circos.clear')
export('circos.dendrogram')
Expand All @@ -25,7 +26,6 @@ export('circos.nested')
export('circos.par')
export('circos.points')
export('circos.polygon')
export('circos.raster')
export('circos.rect')
export('circos.segments')
export('circos.text')
Expand All @@ -49,6 +49,7 @@ export('get.current.sector.index')
export('get.current.track.index')
export('highlight.chromosome')
export('highlight.sector')
export('panel.fun')
export('posTransform.default')
export('posTransform.text')
export('print.CELL_META')
Expand Down
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Changes in version 0.4.1
---------------------------------------------------------------------------

* add `circos.raster()`
* add `circos.arrow()`


Changes in version 0.4.0
Expand Down
118 changes: 118 additions & 0 deletions R/circos.arrow.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@

# == title
# Draw arrow which is paralle to the circle
#
# == param
# -x1 start position of the arrow on the x-axis.
# -x2 end position of the arrow on the x-axis.
# -y position of the arrow on the y-axis. Note this is the center of the arrow on y-axis.
# -width width of the arrow body.
# -sector.index index of the sector.
# -track.index index of the track.
# -arrow.head.length length of the arrow head. Note the value should be smaller than the length of the arrow itself (which is ``x2 - x1``).
# -arrow.head.width width of the arrow head.
# -arrow.position where is the arrow head on the arrow.
# -tail the shape of the arrow tail (the opposite side of arrow head).
# -border border color of the arrow.
# -col filled color of the arrow.
# -lty line style of the arrow.
# -.. pass to `graphics::polygon`.
#
# == details
# Note all position values are measured in the data coordinate (the coordinate in each cell).
#
# If you see points overflow warnings, you can set ``circos.par(points.overflow.warning = FALSE)`` to turn it off.
#
# == author
# Zuguang Gu <[email protected]>
#
# == example
# circos.initialize(letters[1:4], xlim = c(0, 1))
# circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
# circos.arrow(0, 1, y = 0.5, width = 0.4, arrow.head.length = ux(1, "cm"),
# col = "red", tail = ifelse(CELL_META$sector.index %in% c("a", "c"),
# "point", "normal"))
# }, bg.border = NA, track.height = 0.4)
#
# ########## cell cycle ###########
# cell_cycle = data.frame(phase = c("M", "G1", "S", "G2"),
# time = c(1, 11, 8, 4))
#
# color = c("#66C2A5", "#FC8D62", "#8DA0CB", "#E78AC3")
# circos.par(start.degree = 90)
# circos.initialize(cell_cycle$phase, xlim = cbind(rep(0, 4), cell_cycle$time))
# circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
# circos.arrow(CELL_META$xlim[1], CELL_META$xlim[2],
# arrow.head.width = CELL_META$yrange*0.8, arrow.head.length = ux(1, "cm"),
# col = color[CELL_META$sector.numeric.index])
# circos.text(CELL_META$xcenter, CELL_META$ycenter, CELL_META$sector.index,
# facing = "downward")
# }, bg.border = NA, track.height = 0.3)
# circos.clear()
#
circos.arrow = function(x1, x2, y = get.cell.meta.data("ycenter", sector.index, track.index),
width = get.cell.meta.data("yrange", sector.index, track.index)/2,
sector.index = get.current.sector.index(), track.index = get.current.track.index(),
arrow.head.length = convert_x(5, "mm", sector.index, track.index),
arrow.head.width = width*2, arrow.position = c("end", "start"),
tail = c("normal", "point"), border = "black", col = "white", lty = par("lty"), ...) {

arrow.position = match.arg(arrow.position)[1]
tail = match.arg(tail)[1]

sector.index = sector.index
track.index = track.index

if(x2 <= x1) {
stop("`x2` should be larger than `x1`.")
}

if(abs(x2 - x1 - arrow.head.length) < 1e-6) {
stop("Arrow head is too long that it is even longer than the arrow itself.")
}

if(arrow.position == "end") {
arrow.head.coor = rbind(c(x2 - arrow.head.length, y + arrow.head.width/2),
c(x2, y),
c(x2 - arrow.head.length, y - arrow.head.width/2))
if(tail == "normal") {
arrow.body.coor = rbind(c(x2 - arrow.head.length, y - width/2),
c(x1, y - width/2),
c(x1, y + width/2),
c(x2 - arrow.head.length, y + width/2))
arrow.body.coor2 = rbind(lines.expand(arrow.body.coor[1:2, 1], arrow.body.coor[1:2, 2], sector.index, track.index),
lines.expand(arrow.body.coor[3:4, 1], arrow.body.coor[3:4, 2], sector.index, track.index))
} else {
arrow.body.coor = rbind(c(x2 - arrow.head.length, y - width/2),
c(x1, y),
c(x2 - arrow.head.length, y + width/2))
arrow.body.coor2 = rbind(lines.expand(arrow.body.coor[1:2, 1], arrow.body.coor[1:2, 2], sector.index, track.index),
lines.expand(arrow.body.coor[2:3, 1], arrow.body.coor[2:3, 2], sector.index, track.index))
}

coor = rbind(arrow.body.coor2, arrow.head.coor)
} else {

arrow.head.coor = rbind(c(x1 + arrow.head.length, y + arrow.head.width/2),
c(x1, y),
c(x1 + arrow.head.length, y - arrow.head.width/2))
if(tail == "normal") {
arrow.body.coor = rbind(c(x1 + arrow.head.length, y - width/2),
c(x2, y - width/2),
c(x2, y + width/2),
c(x1 + arrow.head.length, y + width/2))
arrow.body.coor2 = rbind(lines.expand(arrow.body.coor[1:2, 1], arrow.body.coor[1:2, 2], sector.index, track.index),
lines.expand(arrow.body.coor[3:4, 1], arrow.body.coor[3:4, 2], sector.index, track.index))
} else {
arrow.body.coor = rbind(c(x1 + arrow.head.length, y - width/2),
c(x2, y),
c(x1 + arrow.head.length, y + width/2))
arrow.body.coor2 = rbind(lines.expand(arrow.body.coor[1:2, 1], arrow.body.coor[1:2, 2], sector.index, track.index),
lines.expand(arrow.body.coor[2:3, 1], arrow.body.coor[2:3, 2], sector.index, track.index))
}
coor = rbind(arrow.body.coor2, arrow.head.coor)
}

d2 = circlize(coor[, 1], coor[, 2], sector.index, track.index)
polygon(polar2Cartesian(d2), border = border, col = col, lty = lty, ...)
}
66 changes: 66 additions & 0 deletions man/circos.arrow.rd
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
\name{circos.arrow}
\alias{circos.arrow}
\title{
Draw arrow which is paralle to the circle
}
\description{
Draw arrow which is paralle to the circle
}
\usage{
circos.arrow(x1, x2, y = get.cell.meta.data("ycenter", sector.index, track.index),
width = get.cell.meta.data("yrange", sector.index, track.index)/2,
sector.index = get.current.sector.index(), track.index = get.current.track.index(),
arrow.head.length = convert_x(5, "mm", sector.index, track.index),
arrow.head.width = width*2, arrow.position = c("end", "start"),
tail = c("normal", "point"), border = "black", col = "white", lty = par("lty"), ...)
}
\arguments{

\item{x1}{start position of the arrow on the x-axis.}
\item{x2}{end position of the arrow on the x-axis.}
\item{y}{position of the arrow on the y-axis. Note this is the center of the arrow on y-axis.}
\item{width}{width of the arrow body.}
\item{sector.index}{index of the sector.}
\item{track.index}{index of the track.}
\item{arrow.head.length}{length of the arrow head. Note the value should be smaller than the length of the arrow itself (which is \code{x2 - x1}).}
\item{arrow.head.width}{width of the arrow head.}
\item{arrow.position}{where is the arrow head on the arrow.}
\item{tail}{the shape of the arrow tail (the opposite side of arrow head).}
\item{border}{border color of the arrow.}
\item{col}{filled color of the arrow.}
\item{lty}{line style of the arrow.}
\item{..}{pass to \code{\link[graphics]{polygon}}.}

}
\details{
Note all position values are measured in the data coordinate (the coordinate in each cell).

If you see points overflow warnings, you can set \code{circos.par(points.overflow.warning = FALSE)} to turn it off.
}
\author{
Zuguang Gu <z.gu@dkfz.de>
}
\examples{
circos.initialize(letters[1:4], xlim = c(0, 1))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
circos.arrow(0, 1, y = 0.5, width = 0.4, arrow.head.length = ux(1, "cm"),
col = "red", tail = ifelse(CELL_META$sector.index %in% c("a", "c"),
"point", "normal"))
}, bg.border = NA, track.height = 0.4)

########## cell cycle ###########
cell_cycle = data.frame(phase = c("M", "G1", "S", "G2"),
time = c(1, 11, 8, 4))

color = c("#66C2A5", "#FC8D62", "#8DA0CB", "#E78AC3")
circos.par(start.degree = 90)
circos.initialize(cell_cycle$phase, xlim = cbind(rep(0, 4), cell_cycle$time))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
circos.arrow(CELL_META$xlim[1], CELL_META$xlim[2],
arrow.head.width = CELL_META$yrange*0.8, arrow.head.length = ux(1, "cm"),
col = color[CELL_META$sector.numeric.index])
circos.text(CELL_META$xcenter, CELL_META$ycenter, CELL_META$sector.index,
facing = "downward")
}, bg.border = NA, track.height = 0.3)
circos.clear()
}
39 changes: 39 additions & 0 deletions man/panel.fun.rd
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
\name{panel.fun}
\alias{panel.fun}
\title{
Add raster images
}
\description{
Add raster images
}
\usage{
panel.fun(x, y)
}
\arguments{

\item{image}{a \code{raster} object, or an object that can be converted by \code{\link[grDevices]{as.raster}}}
\item{x}{position of the center of the raster image, measued in the data coordinate in the cell}
\item{y}{position of the center of the raster image, measued in the data coordinate in the cell}
\item{width}{width of the raster image. When \code{facing} is one of "inside", "outside", "clockwise" and "reverse.clockwise", the image should have absolute size where the value of \code{width} should be specified like \code{20mm}, \code{1cm} or \code{0.5inche}. When \code{facing} is one of \code{bending.inside} and \code{bending.outside}, the value of \code{width} is measured in the data coordinate in the cell.}
\item{height}{height of the raster image. Same format as \code{width}. If the value of \code{height} is omit, default height is calculated by taking the aspect ratio of the original image. But when \code{facing} is one of \code{bending.inside} and \code{bending.outside}, \code{height} is mandatory to set.}
\item{facing}{facing of the raster image}
\item{niceFacing}{facing of text. Please refer to vignette for different settings}
\item{sector.index}{index for the sector}
\item{track.index}{index for the track}
\item{scaling}{scaling factor to resize the raster image.}

}
\author{
Zuguang Gu <z.gu@dkfz.de>
}
\examples{
require(png)
image = system.file("extdata", "Rlogo.png", package = "circlize")
image = as.raster(readPNG(image))
circos.initialize(letters[1:8], xlim = c(0, 1))
circos.track(ylim = c(0, 1), panel.fun = function(x, y) {
circos.raster(image, CELL_META$xcenter, CELL_META$ycenter, width = "2cm",
facing = "inside", niceFacing = TRUE)
})
circos.clear()
}

0 comments on commit d0ce2fc

Please sign in to comment.