From d947986752c22ddb71fe9d785c50fef24becece3 Mon Sep 17 00:00:00 2001 From: Zuguang Gu Date: Tue, 20 Nov 2018 15:29:04 +0100 Subject: [PATCH] update --- .travis.yml | 44 ++++---- DESCRIPTION | 6 +- NAMESPACE | 2 + NEWS | 2 + R/chordDiagram.R | 97 ++++++++++++++-- R/genomic.R | 163 +++++++++++++++++++-------- R/global.R | 2 +- R/utils.R | 30 ++++- man/calc_gap.rd | 30 +++++ man/chordDiagram.rd | 4 +- man/chordDiagramFromDataFrame.rd | 6 +- man/chordDiagramFromMatrix.rd | 4 +- man/circos.genomicAxis.rd | 32 ++++++ man/circos.genomicInitialize.rd | 4 +- man/circos.genomicRainfall.rd | 7 +- man/circos.initializeWithIdeogram.rd | 4 +- man/rainfallTransform.rd | 4 +- 17 files changed, 341 insertions(+), 100 deletions(-) create mode 100644 man/calc_gap.rd create mode 100644 man/circos.genomicAxis.rd diff --git a/.travis.yml b/.travis.yml index e533b349..6ccf3fa7 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,30 +1,30 @@ -language: r +## Sample .travis.yml file for use with metacran/r-builder +## See https://github.com/metacran/r-builder for details. +language: c sudo: required -# Be strict when checking our package -warnings_are_errors: true +before_install: + - curl -OL https://raw.githubusercontent.com/metacran/r-builder/master/pkg-build.sh + - chmod 755 pkg-build.sh + - ./pkg-build.sh bootstrap -r-packages: -- shape -- colorspace -- RColorBrewer -- testthat -- knitr -- markdown -- dendextend -- circlize +install: + - ./pkg-build.sh install_deps -bioc_packages: -- GenomicRanges -- HilbertVis +script: + - ./pkg-build.sh run_tests -r_github_packages: -- jokergoo/GlobalOptions -- jokergoo/GetoptLong -- jokergoo/HilbertCurve -- jimhester/covr -- jokergoo/ComplexHeatmap +after_failure: + - ./pkg-build.sh dump_logs -r_check_args: --no-vignettes --no-build-vignettes +notifications: + email: + on_success: change + on_failure: change +env: + matrix: + - RVERSION=oldrel + - RVERSION=release + - RVERSION=devel diff --git a/DESCRIPTION b/DESCRIPTION index f0c2705b..b7262a3b 100755 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,7 +2,7 @@ Package: circlize Type: Package Title: Circular Visualization Version: 0.4.5 -Date: 2018-7-9 +Date: 2018-11-19 Author: Zuguang Gu Maintainer: Zuguang Gu Depends: R (>= 3.0.0), graphics @@ -22,6 +22,6 @@ Description: Circular layout is an efficient way for the visualization of huge better understanding complex patterns behind multiple dimensional data. URL: https://github.com/jokergoo/circlize, http://jokergoo.github.io/circlize_book/book/ License: MIT + file LICENSE -Packaged: 2018-7-9 00:00:00 UTC; Administrator +Packaged: 2018-11-19 00:00:00 UTC; Administrator Repository: CRAN -Date/Publication: 2018-7-9 00:00:00 +Date/Publication: 2018-11-19 00:00:00 diff --git a/NAMESPACE b/NAMESPACE index 70903ac2..fe9ca1f3 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -5,6 +5,7 @@ export("print.CELL_META") export("CELL_META") export("add_transparency") export("adjacencyList2Matrix") +export("calc_gap") export("chordDiagram") export("chordDiagramFromDataFrame") export("chordDiagramFromMatrix") @@ -13,6 +14,7 @@ export("circos.arrow") export("circos.axis") export("circos.clear") export("circos.dendrogram") +export("circos.genomicAxis") export("circos.genomicDensity") export("circos.genomicHeatmap") export("circos.genomicIdeogram") diff --git a/NEWS b/NEWS index e6887302..acef9f3c 100755 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ Changes in version 0.4.5 * add `scale` in chordDiagram() * `circos.initialize()`: convert xlim and x to numeric * `colorRamp2()` is faster now. +* add `circos.genomicAxis()`. +* add `calc_gap()`. Changes in version 0.4.4 ------------------------------------------------------------------------- diff --git a/R/chordDiagram.R b/R/chordDiagram.R index f37028b0..c54ed56b 100755 --- a/R/chordDiagram.R +++ b/R/chordDiagram.R @@ -39,6 +39,11 @@ # -link.visible pass to `chordDiagramFromMatrix` or `chordDiagramFromDataFrame` # -link.rank order to add links to the circle, a large value means to add it later. # -scale scale each sector to same width +# -big.gap Gap between the two sets of sectors. If the input is a matrix, the two sets +# are row sectors and column sectors. If the input is a data frame, the two sets +# correspond to the first column and the second column. It only works when there +# is no intersection between the two sets. +# -small.gap Small gap between sectors. # -... pass to `circos.link`. # # == details @@ -79,7 +84,7 @@ chordDiagram = function(x, grid.col = NULL, grid.border = NA, transparency = 0.5 link.arr.type = "triangle", link.arr.lty = par("lty"), link.arr.lwd = par("lwd"), link.arr.col = par("col"), link.largest.ontop = FALSE, link.visible = TRUE, - link.rank = NULL, scale = FALSE, gap.degree = NULL, ...) { + link.rank = NULL, scale = FALSE, big.gap = 10, small.gap = 1, ...) { if(inherits(x, "table")) { if(length(dim(x)) == 2) { @@ -96,7 +101,7 @@ chordDiagram = function(x, grid.col = NULL, grid.border = NA, transparency = 0.5 link.border = link.border, link.lwd = link.lwd, link.lty = link.lty, link.sort = link.sort, link.decreasing = link.decreasing, link.arr.length = link.arr.length, link.arr.width = link.arr.width, link.arr.type = link.arr.type, link.arr.lty = link.arr.lty, link.arr.lwd = link.arr.lwd, link.arr.col = link.arr.col, link.largest.ontop = link.largest.ontop, - link.visible = link.visible, link.rank = link.rank, scale = scale, gap.degree = gap.degree, ...) + link.visible = link.visible, link.rank = link.rank, scale = scale, big.gap = big.gap, small.gap = small.gap, ...) } else if(inherits(x, "data.frame")) { if(ncol(x) > 3) { if(all(sapply(x, inherits, c("numeric", "integer")))) { @@ -109,7 +114,7 @@ chordDiagram = function(x, grid.col = NULL, grid.border = NA, transparency = 0.5 link.border = link.border, link.lwd = link.lwd, link.lty = link.lty, link.sort = link.sort, link.decreasing = link.decreasing, link.arr.length = link.arr.length, link.arr.width = link.arr.width, link.arr.type = link.arr.type, link.arr.lty = link.arr.lty, link.arr.lwd = link.arr.lwd, link.arr.col = link.arr.col, link.largest.ontop = link.largest.ontop, - link.visible = link.visible, link.rank = link.rank, scale = scale, gap.degree = gap.degree, ...))) + link.visible = link.visible, link.rank = link.rank, scale = scale, big.gap = big.gap, small.gap = small.gap, ...))) } else { chordDiagramFromDataFrame(x, grid.col = grid.col, grid.border = grid.border, transparency = transparency, col = col, order = order, directional = directional, direction.type = direction.type, @@ -118,7 +123,7 @@ chordDiagram = function(x, grid.col = NULL, grid.border = NA, transparency = 0.5 link.border = link.border, link.lwd = link.lwd, link.lty = link.lty, link.sort = link.sort, link.decreasing = link.decreasing, link.arr.length = link.arr.length, link.arr.width = link.arr.width, link.arr.type = link.arr.type, link.arr.lty = link.arr.lty, link.arr.lwd = link.arr.lwd, link.arr.col = link.arr.col, link.largest.ontop = link.largest.ontop, - link.visible = link.visible, link.rank = link.rank, scale = scale, gap.degree = gap.degree, ...) + link.visible = link.visible, link.rank = link.rank, scale = scale, big.gap = big.gap, small.gap = small.gap, ...) } } else { chordDiagramFromDataFrame(x, grid.col = grid.col, grid.border = grid.border, transparency = transparency, @@ -128,7 +133,7 @@ chordDiagram = function(x, grid.col = NULL, grid.border = NA, transparency = 0.5 link.border = link.border, link.lwd = link.lwd, link.lty = link.lty, link.sort = link.sort, link.decreasing = link.decreasing, link.arr.length = link.arr.length, link.arr.width = link.arr.width, link.arr.type = link.arr.type, link.arr.lty = link.arr.lty, link.arr.lwd = link.arr.lwd, link.arr.col = link.arr.col, link.largest.ontop = link.largest.ontop, - link.visible = link.visible, link.rank = link.rank, scale = scale, gap.degree = gap.degree, ...) + link.visible = link.visible, link.rank = link.rank, scale = scale, big.gap = big.gap, small.gap = small.gap, ...) } } else { stop("`x` can only be a matrix or a data frame.") @@ -325,6 +330,8 @@ mat2df = function(mat) { # plotted, but the space is still ocuppied. The format of this argument is same as ``link.lwd`` # -link.rank order to add links to the circle, a large value means to add it later. # -scale scale each sector to same width +# -big.gap Gap between row sectors and column sectors. +# -small.gap Small gap between sectors. # -... pass to `circos.link` # # == details @@ -347,7 +354,7 @@ chordDiagramFromMatrix = function(mat, grid.col = NULL, grid.border = NA, transp link.arr.type = "triangle", link.arr.lty = par("lty"), link.arr.lwd = par("lwd"), link.arr.col = par("col"), link.largest.ontop = FALSE, link.visible = TRUE, - link.rank = NULL, scale = FALSE, gap.degree = NULL, ...) { + link.rank = NULL, scale = FALSE, big.gap = 10, small.gap = 1, ...) { if(!is.matrix(mat)) { stop("`mat` can only be a matrix.") @@ -583,7 +590,8 @@ chordDiagramFromMatrix = function(mat, grid.col = NULL, grid.border = NA, transp link.visible = link.visible, link.rank = link.rank, scale = scale, - gap.degree = gap.degree, + big.gap = big.gap, + small.gap = small.gap, ...) } @@ -645,6 +653,8 @@ chordDiagramFromMatrix = function(mat, grid.col = NULL, grid.border = NA, transp # plotted, but the space is still ocuppied. The format of this argument is same as ``link.lwd`` # -link.rank order to add links to the circle, a large value means to add it later. # -scale scale each sector to same width +# -big.gap Gaps between the sectors in the first column of ``df`` and sectors in the second column in ``df``. +# -small.gap Small gap between sectors. # -... pass to `circos.link` # # == details @@ -668,7 +678,7 @@ chordDiagramFromDataFrame = function(df, grid.col = NULL, grid.border = NA, tran link.largest.ontop = FALSE, link.visible = TRUE, link.rank = seq_len(nrow(df)), scale = FALSE, - gap.degree = NULL, + big.gap = 10, small.gap = 1, ...) { if(nrow(df) != 2) { @@ -965,13 +975,30 @@ chordDiagramFromDataFrame = function(df, grid.col = NULL, grid.border = NA, tran o.cell.padding = circos.par("cell.padding") circos.par(cell.padding = c(0, 0, 0, 0)) - - if(!is.null(gap.degree)) { + o.start.degree = circos.par("start.degree") + o.gap.after = circos.par("gap.after") + + if((identical(circos.par("gap.after"), 1))) { # gap.after is not set in circos.par() if(length(intersect(df[, 1], df[, 2])) == 0) { n_df1 = length(unique(df[, 1])) n_df2 = length(unique(df[, 2])) - circos.par(start.degree = -gap.degree/2, gap.after = c(rep(1, n_df1 - 1), gap.degree, rep(1, n_df2 - 1), gap.degree)) + n_sector = n_df1 + n_df2 + s1 = sum(abs(df[, 3])) + s2 = sum(abs(df[, 4])) + d1 = (360 - small.gap*(n_sector - 2) - big.gap*2) * (s1/(s1 + s2)) + small.gap*(n_df1-1) + if(circos.par$start.degree == 1) circos.par$start.degree = 0 + if(circos.par$clock.wise) { + start_degree = circos.par$start.degree - (180 - d1)/2 + } else { + start_degree = circos.par$start.degree + (180 - d1)/2 + } + suppressWarnings(circos.par(start.degree = start_degree, + gap.after = c(rep(small.gap, n_df1 - 1), big.gap, rep(small.gap, n_df2 - 1), big.gap))) + } else { + # warning("The two sets of sectors overlap, ignore `gap.degree`.") } + } else { + # warning("You have changed the default value of circos.par('gap.degree') or circos.par('gap.after').\nIgnore `gap.degree` argument.") } circos.initialize(factors = factor(cate, levels = cate), xlim = cbind(rep(0, length(xsum)), xsum)) @@ -1084,10 +1111,56 @@ chordDiagramFromDataFrame = function(df, grid.col = NULL, grid.border = NA, tran df$col = col - circos.par("cell.padding" = o.cell.padding) + suppressWarnings(circos.par("cell.padding" = o.cell.padding, "start.degree" = o.start.degree, + "gap.after" = o.gap.after)) return(invisible(df)) } psubset = function(mat, ri, ci) { return(mat[ri + (ci - 1) * nrow(mat)]) } + +# == title +# Calculate gap to make two Chord diagram with same scale +# +# == param +# -x1 The matrix or the data frame for the first Chord diagram. +# -x2 The matrix or the data frame for the second Chord diagram. +# -big.gap ``big.gap`` for the first Chord diagram. +# -small.gap ``small.gap`` for both Chord diagrams. +# +# == details +# There should be no overlap between the two sets of sectors. +# +# == value +# A numeric value which can be directly set to ``big.gap`` in the second Chord diagram. +# +calc_gap = function(x1, x2, big.gap = 10, small.gap = 1) { + if(is.matrix(x1)) { + sum1 = sum(abs(x1)) + n1 = nrow(x1) + n2 = ncol(x1) + } else { + sum1 = sum(abs(x1[, 3])) + n1 = length(unique(x1[, 1])) + n2 = length(unique(x1[, 2])) + } + sum_gap1 = sum(c(rep(small.gap, n1 - 1), big.gap, rep(small.gap, n2 - 1), big.gap)) + + if(is.matrix(x2)) { + sum2 = sum(abs(x2)) + n1 = nrow(x2) + n2 = ncol(x2) + } else { + sum2 = sum(abs(x2[, 3])) + n1 = length(unique(x2[, 1])) + n2 = length(unique(x2[, 2])) + } + sum_gap2 = sum(rep(small.gap, n1 + n2 - 2)) + + percent = sum2 / sum1 + blank.degree = (360 - sum_gap1) * (1 - percent) + + (blank.degree - sum_gap2)/2 +} + diff --git a/R/genomic.R b/R/genomic.R index 796fb1be..0dc45517 100755 --- a/R/genomic.R +++ b/R/genomic.R @@ -18,7 +18,7 @@ # If it is set to ``NULL``, the function just initialize the plot but draw nothing. # -track.height Height of the track which contains "axis" and "labels". # -ideogram.height Height of the ideogram track -# -... Pass to `circos.initialize` +# -... Pass to `circos.genomicInitialize`. # # == details # The function will initialize the circular plot in which each sector corresponds to a chromosome. You can control the order of @@ -32,7 +32,7 @@ circos.initializeWithIdeogram = function(cytoband = system.file(package = "circl "extdata", "cytoBand.txt"), species = NULL, sort.chr = TRUE, chromosome.index = NULL, major.by = NULL, plotType = c("ideogram", "axis", "labels"), - track.height = convert_height(3, "mm"), ideogram.height = convert_height(2, "mm"), + track.height = NULL, ideogram.height = convert_height(2, "mm"), ...) { # proper order will be returned depending on cytoband and sort.chr @@ -149,8 +149,8 @@ circos.genomicIdeogram = function(cytoband = system.file(package = "circlize", # For more details on initializing genomic plot, please refer to the vignettes. circos.genomicInitialize = function(data, sector.names = NULL, major.by = NULL, plotType = c("axis", "labels"), tickLabelsStartFromZero = TRUE, - axis.labels.cex = 0.4*par("cex"), labels.cex = par("cex"), - track.height = convert_height(3, "mm"), ...) { + axis.labels.cex = 0.4*par("cex"), labels.cex = 0.8*par("cex"), + track.height = NULL, ...) { if(is.factor(data[[1]])) { fa = levels(data[[1]]) @@ -176,7 +176,20 @@ circos.genomicInitialize = function(data, sector.names = NULL, major.by = NULL, ow = circos.par("points.overflow.warning") circos.par(cell.padding = c(0, 0, 0, 0), points.overflow.warning = FALSE) circos.initialize(factor(fa, levels = fa), xlim = cbind(x1, x2), ...) - + + if(is.null(track.height)) { + if(all(c("axis", "labels") %in% plotType)) { + track.height = convert_unit_in_canvas_coordinate(1.5, "mm") + strheight("0", cex = axis.labels.cex) + + convert_unit_in_canvas_coordinate(0.5, "mm") + strheight("chr", cex = labels.cex) + } else if("labels" %in% plotType) { + track.height = strheight("chr", cex = labels.cex) + } else if("axis" %in% plotType) { + track.height = convert_unit_in_canvas_coordinate(1.5, "mm") + strheight("0", cex = axis.labels.cex) + } else { + track.height = convert_height(3, "mm") + } + } + # axis and chromosome names if(any(plotType %in% c("axis", "labels"))) { circos.genomicTrackPlotRegion(data, ylim = c(0, 1), bg.border = NA, track.height = track.height, @@ -184,58 +197,88 @@ circos.genomicInitialize = function(data, sector.names = NULL, major.by = NULL, sector.index = get.cell.meta.data("sector.index") xlim = get.cell.meta.data("xlim") - if(tickLabelsStartFromZero) { - offset = xlim[1] - if(is.null(major.by)) { - xlim = get.cell.meta.data("xlim") - major.by = .default.major.by() - } - major.at = seq(xlim[1], xlim[2], by = major.by) - major.at = c(major.at, major.at[length(major.at)] + major.by) - - if(major.by > 1e6) { - major.tick.labels = paste((major.at-offset)/1000000, "MB", sep = "") - } else if(major.by > 1e3) { - major.tick.labels = paste((major.at-offset)/1000, "KB", sep = "") - } else { - major.tick.labels = paste((major.at-offset), "bp", sep = "") - } - - } else { - if(is.null(major.by)) { - xlim = get.cell.meta.data("xlim") - major.by = .default.major.by() - } - major.at = seq(floor(xlim[1]/major.by)*major.by, xlim[2], by = major.by) - major.at = c(major.at, major.at[length(major.at)] + major.by) - - if(major.by > 1e6) { - major.tick.labels = paste(major.at/1000000, "MB", sep = "") - } else if(major.by > 1e3) { - major.tick.labels = paste(major.at/1000, "KB", sep = "") - } else { - major.tick.labels = paste(major.at, "bp", sep = "") - } - } - - if(all(c("axis", "labels") %in% plotType)) { - circos.axis(h = 0, major.at = major.at, labels = major.tick.labels, labels.cex = axis.labels.cex) - circos.text(mean(xlim), 1.3, labels = sector.names[sector.index], cex = labels.cex, adj = c(0.5, 0), niceFacing = TRUE) + circos.genomicAxis(h = "bottom", major.by = major.by, tickLabelsStartFromZero = tickLabelsStartFromZero, labels.cex = axis.labels.cex) + circos.text(mean(xlim), convert_y(1.5, "mm") + convert_y(strheight("chr", cex = axis.labels.cex), "canvas") + convert_y(0.5, "mm"), + labels = sector.names[sector.index], cex = labels.cex, adj = c(0.5, 0), niceFacing = TRUE) } else if("labels" %in% plotType) { circos.text(mean(xlim), 0, labels = sector.names[sector.index], cex = labels.cex, adj = c(0.5, 0), niceFacing = TRUE) } else if("axis" %in% plotType) { - circos.axis(h = 0, major.at = major.at, labels = major.tick.labels, labels.cex = axis.labels.cex) + circos.genomicAxis(h = "bottom", major.by = major.by, tickLabelsStartFromZero = tickLabelsStartFromZero,labels.cex = axis.labels.cex) } } ) } - circos.par("cell.padding" = op, "points.overflow.warning" = ow) return(invisible(NULL)) } +# == title +# Add genomic axes +# +# == param +# -h Position of the axes. "top" or "bottom". +# -major.by Increment of major ticks. It is calculated automatically if the value is not set (about every 10 degrees there is a major tick). +# -tickLabelsStartFromZero Whether axis tick labels start from 0? This will only affect the axis labels while not affect x-values in cells. +# -labels.cex the font size for the axis tick labels. +# -sector.index Index for the sector +# -track.index Index for the track +# -... Other arguments pass to `circos.axis`. +# +# == details +# It assigns proper tick labels under genomic coordinate. +# +# == example +# circos.initializeWithIdeogram(plotType = NULL) +# circos.track(ylim = c(0, 1), panel.fun = function(x, y) circos.genomicAxis()) +# circos.clear() +# +circos.genomicAxis = function(h = "top", major.by = NULL, tickLabelsStartFromZero = TRUE, + labels.cex = 0.4*par("cex"), sector.index = get.cell.meta.data("sector.index"), + track.index = get.cell.meta.data("track.index"), ...) { + + if(!h %in% c("top", "bottom")) { + stop("`h` can only be 'top' or 'bottom'.") + } + + xlim = get.cell.meta.data("xlim", sector.index = sector.index, track.index = track.index) + + if(tickLabelsStartFromZero) { + offset = xlim[1] + if(is.null(major.by)) { + major.by = .default.major.by() + } + major.at = seq(xlim[1], xlim[2], by = major.by) + major.at = c(major.at, major.at[length(major.at)] + major.by) + + if(major.by > 1e6) { + major.tick.labels = paste((major.at-offset)/1000000, "MB", sep = "") + } else if(major.by > 1e3) { + major.tick.labels = paste((major.at-offset)/1000, "KB", sep = "") + } else { + major.tick.labels = paste((major.at-offset), "bp", sep = "") + } + + } else { + if(is.null(major.by)) { + major.by = .default.major.by() + } + major.at = seq(floor(xlim[1]/major.by)*major.by, xlim[2], by = major.by) + major.at = c(major.at, major.at[length(major.at)] + major.by) + + if(major.by > 1e6) { + major.tick.labels = paste(major.at/1000000, "MB", sep = "") + } else if(major.by > 1e3) { + major.tick.labels = paste(major.at/1000, "KB", sep = "") + } else { + major.tick.labels = paste(major.at, "bp", sep = "") + } + } + circos.axis(h = h, major.at = major.at, labels = major.tick.labels, labels.cex = labels.cex, + sector.index = sector.index, track.index = track.index, ...) +} + # == title # Create a track for genomic graphics # @@ -1517,11 +1560,13 @@ normalizeToDataFrame = function(data, sort = FALSE) { # == param # -data A bed-file-like data frame or a list of data frames # -mode how to calculate the distance of two neighbouring regions, pass to `rainfallTransform` -# -ylim ylim for rainfall plot track. It's value should be log10(inter-distance+1) +# -ylim ylim for rainfall plot track. If ``normalize_to_width`` is ``FALSE``, the value should correspond to log10(dist+1), +# and if ``normalize_to_width`` is ``TRUE``, the value should correspond to log2(rel_dist). # -col Color of points. It should be length of one. If ``data`` is a list, the length of ``col`` # can also be the length of the list. # -pch Style of points # -cex Size of points +# -normalize_to_width If it is ``TRUE``, the value is the relative distance divided by the width of the region. # -... Pass to `circos.trackPlotRegion` # # == details @@ -1532,8 +1577,8 @@ normalizeToDataFrame = function(data, sort = FALSE) { # the plot, it means there is a cluster of regions at that area. # # On the plot, y-axis are log10-transformed. -circos.genomicRainfall = function(data, mode = "min", ylim = c(0, 9), col = "black", - pch = par("pch"), cex = par("cex"), ...) { +circos.genomicRainfall = function(data, mode = "min", ylim = NULL, col = "black", + pch = par("pch"), cex = par("cex"), normalize_to_width = FALSE, ...) { data = normalizeToDataFrame(data) @@ -1550,11 +1595,23 @@ circos.genomicRainfall = function(data, mode = "min", ylim = c(0, 9), col = "bla if(length(cex) == 1) { cex = rep(cex, length(data)) } + + if(is.null(ylim)) { + if(normalize_to_width) { + ylim = c(-10, 10) + } else { + ylim = c(0, 9) + } + } circos.genomicTrackPlotRegion(data, ylim = ylim, panel.fun = function(region, value, ...) { - df = rainfallTransform(region, mode = mode) + df = rainfallTransform(region, mode = mode, normalize_to_width = normalize_to_width) i = getI(...) - circos.genomicPoints(df[1:2], log10(df[3]+1), col = col[i], cex = cex[i], pch = pch[i]) + if(normalize_to_width) { + circos.genomicPoints(df[1:2], log10(df[3]), col = col[i], cex = cex[i], pch = pch[i]) + } else { + circos.genomicPoints(df[1:2], log10(df[3]+1), col = col[i], cex = cex[i], pch = pch[i]) + } }, ...) } @@ -1569,13 +1626,15 @@ circos.genomicRainfall = function(data, mode = "min", ylim = c(0, 9), col = "bla # -mode How to calculate inter-distance. For a region, there is a distance to the # prevous region and also there is a distance to the next region. ``mode`` # controls how to merge these two distances into one value. +# -normalize_to_width If it is ``TRUE``, the value is the relative distance divided by the width of the region. # # == values # If the input is a two-column data frame, the function returnes a data frame with three columns: start position, end position and distance. # And if the input is a bed-format data frame, there will be the chromosome column added. # # The row order of the returned data frame is as same as the input one. -rainfallTransform = function(region, mode = c("min", "max", "mean", "left", "right")) { +rainfallTransform = function(region, mode = c("min", "max", "mean", "left", "right"), + normalize_to_width = FALSE) { mode = match.arg(mode)[1] @@ -1641,6 +1700,10 @@ rainfallTransform = function(region, mode = c("min", "max", "mean", "left", "rig region = region_bk region$dist[region_order] = dist + + if(normalize_to_width) { + region$dist = region$dist/(region[, 3] - region[, 2]) + } return(region) } diff --git a/R/global.R b/R/global.R index f601bb7f..7c5f7f89 100755 --- a/R/global.R +++ b/R/global.R @@ -234,7 +234,7 @@ circos.initialize = function(factors, x = NULL, xlim = NULL, sector.width = NULL factors = factor(factors) } } - levels(factors) = intersect(levels(factors), as.character(factors)) + factors = factor(as.character(factors), intersect(levels(factors), as.character(factors))) le = levels(factors) if(!is.null(x)) { diff --git a/R/utils.R b/R/utils.R index fafbcae6..61e407e1 100755 --- a/R/utils.R +++ b/R/utils.R @@ -620,7 +620,7 @@ uh = function(...) { convert_length(...) } -convert_unit_in_data_coordinate = function(x, unit = c("mm", "cm", "inches"), +convert_unit_in_data_coordinate = function(x, unit = c("mm", "cm", "inches", "canvas"), direction = c("x", "y"), sector.index = get.current.sector.index(), track.index = get.current.track.index(), @@ -649,6 +649,8 @@ convert_unit_in_data_coordinate = function(x, unit = c("mm", "cm", "inches"), len = x * pt_per_inche1 * inche_per_mm } else if(unit == "cm") { len = x * pt_per_inche1 * inche_per_mm * 10 + } else if(unit == "canvas") { + len = x } xlim = get.cell.meta.data("xlim", sector.index = sector.index, track.index = track.index) @@ -792,6 +794,32 @@ uy = function(...) { convert_y(...) } +convert_unit_in_canvas_coordinate = function(x, unit = c("mm", "cm", "inches")) { + + pin = par("pin") + usr = par("usr") + + unit = match.arg(unit) + + pt_per_inche1 = (usr[2] - usr[1])/pin[1] + pt_per_inche2 = (usr[4] - usr[3])/pin[2] + + if(abs(pt_per_inche1 - pt_per_inche2) > 1e-3) { + warning("`convert_unit_in_data_coordinate()` only works when aspect of the coordinate is 1.") + } + + inche_per_mm = 0.0393700787401575 + # length in the data coordinate + if(unit == "inches") { + len = x * pt_per_inche1 + } else if(unit == "mm") { + len = x * pt_per_inche1 * inche_per_mm + } else if(unit == "cm") { + len = x * pt_per_inche1 * inche_per_mm * 10 + } + return(len) +} + stop_wrap = function(...) { x = paste0(...) x = paste(strwrap(x), collapse = "\n") diff --git a/man/calc_gap.rd b/man/calc_gap.rd new file mode 100644 index 00000000..258fae33 --- /dev/null +++ b/man/calc_gap.rd @@ -0,0 +1,30 @@ +\name{calc_gap} +\alias{calc_gap} +\title{ +Calculate gap to make two Chord diagram with same scale +} +\description{ +Calculate gap to make two Chord diagram with same scale +} +\usage{ +calc_gap(x1, x2, big.gap = 10, small.gap = 1) +} +\arguments{ + + \item{x1}{The matrix or the data frame for the first Chord diagram. } + \item{x2}{The matrix or the data frame for the second Chord diagram. } + \item{big.gap}{\code{big.gap} for the first Chord diagram. } + \item{small.gap}{\code{small.gap} for both Chord diagrams. } + +} +\details{ +There should be no overlap between the two sets of sectors. +} +\value{ +A numeric value which can be directly set to \code{big.gap} in the second Chord diagram. +} +\examples{ +# There is no example +NULL + +} diff --git a/man/chordDiagram.rd b/man/chordDiagram.rd index 5369d5a6..28da2380 100755 --- a/man/chordDiagram.rd +++ b/man/chordDiagram.rd @@ -23,7 +23,7 @@ chordDiagram(x, grid.col = NULL, grid.border = NA, transparency = 0.5, link.arr.type = "triangle", link.arr.lty = par("lty"), link.arr.lwd = par("lwd"), link.arr.col = par("col"), link.largest.ontop = FALSE, link.visible = TRUE, - link.rank = NULL, scale = FALSE, ...) + link.rank = NULL, scale = FALSE, big.gap = 10, small.gap = 1, ...) } \arguments{ @@ -61,6 +61,8 @@ chordDiagram(x, grid.col = NULL, grid.border = NA, transparency = 0.5, \item{link.visible}{pass to \code{\link{chordDiagramFromMatrix}} or \code{\link{chordDiagramFromDataFrame}} } \item{link.rank}{order to add links to the circle, a large value means to add it later. } \item{scale}{scale each sector to same width } + \item{big.gap}{Gap between the two sets of sectors. If the input is a matrix, the two sets are row sectors and column sectors. If the input is a data frame, the two sets correspond to the first column and the second column. It only works when there is no intersection between the two sets. } + \item{small.gap}{Small gap between sectors. } \item{...}{pass to \code{\link{circos.link}}. } } diff --git a/man/chordDiagramFromDataFrame.rd b/man/chordDiagramFromDataFrame.rd index 4e160ab1..ce6e2c9b 100755 --- a/man/chordDiagramFromDataFrame.rd +++ b/man/chordDiagramFromDataFrame.rd @@ -21,7 +21,9 @@ chordDiagramFromDataFrame(df, grid.col = NULL, grid.border = NA, transparency = link.arr.lwd = par("lwd"), link.arr.col = par("col"), link.largest.ontop = FALSE, link.visible = TRUE, link.rank = seq_len(nrow(df)), - scale = FALSE, ...) + scale = FALSE, + big.gap = 10, small.gap = 1, + ...) } \arguments{ @@ -55,6 +57,8 @@ chordDiagramFromDataFrame(df, grid.col = NULL, grid.border = NA, transparency = \item{link.visible}{whether plot the link. The value is logical, if it is set to \code{FALSE}, the corresponding link will not plotted, but the space is still ocuppied. The format of this argument is same as \code{link.lwd} } \item{link.rank}{order to add links to the circle, a large value means to add it later. } \item{scale}{scale each sector to same width } + \item{big.gap}{Gaps between the sectors in the first column of \code{df} and sectors in the second column in \code{df}. } + \item{small.gap}{Small gap between sectors. } \item{...}{pass to \code{\link{circos.link}} } } diff --git a/man/chordDiagramFromMatrix.rd b/man/chordDiagramFromMatrix.rd index 7f9f292e..4cf09047 100755 --- a/man/chordDiagramFromMatrix.rd +++ b/man/chordDiagramFromMatrix.rd @@ -21,7 +21,7 @@ chordDiagramFromMatrix(mat, grid.col = NULL, grid.border = NA, transparency = 0. link.arr.type = "triangle", link.arr.lty = par("lty"), link.arr.lwd = par("lwd"), link.arr.col = par("col"), link.largest.ontop = FALSE, link.visible = TRUE, - link.rank = NULL, scale = FALSE, ...) + link.rank = NULL, scale = FALSE, big.gap = 10, small.gap = 1, ...) } \arguments{ @@ -59,6 +59,8 @@ chordDiagramFromMatrix(mat, grid.col = NULL, grid.border = NA, transparency = 0. \item{link.visible}{whether plot the link. The value is logical, if it is set to \code{FALSE}, the corresponding link will not plotted, but the space is still ocuppied. The format of this argument is same as \code{link.lwd} } \item{link.rank}{order to add links to the circle, a large value means to add it later. } \item{scale}{scale each sector to same width } + \item{big.gap}{Gap between row sectors and column sectors. } + \item{small.gap}{Small gap between sectors. } \item{...}{pass to \code{\link{circos.link}} } } diff --git a/man/circos.genomicAxis.rd b/man/circos.genomicAxis.rd new file mode 100644 index 00000000..17e4ce7a --- /dev/null +++ b/man/circos.genomicAxis.rd @@ -0,0 +1,32 @@ +\name{circos.genomicAxis} +\alias{circos.genomicAxis} +\title{ +Add genomic axes +} +\description{ +Add genomic axes +} +\usage{ +circos.genomicAxis(h = "top", major.by = NULL, tickLabelsStartFromZero = TRUE, + labels.cex = 0.4*par("cex"), sector.index = get.cell.meta.data("sector.index"), + track.index = get.cell.meta.data("track.index"), ...) +} +\arguments{ + + \item{h}{Position of the axes. "top" or "bottom". } + \item{major.by}{Increment of major ticks. It is calculated automatically if the value is not set (about every 10 degrees there is a major tick). } + \item{tickLabelsStartFromZero}{Whether axis tick labels start from 0? This will only affect the axis labels while not affect x-values in cells. } + \item{labels.cex}{the font size for the axis tick labels. } + \item{sector.index}{Index for the sector } + \item{track.index}{Index for the track } + \item{...}{Other arguments pass to \code{\link{circos.axis}}. } + +} +\details{ +It assigns proper tick labels under genomic coordinate. +} +\examples{ +circos.initializeWithIdeogram(plotType = NULL) +circos.track(ylim = c(0, 1), panel.fun = function(x, y) circos.genomicAxis()) +circos.clear() +} diff --git a/man/circos.genomicInitialize.rd b/man/circos.genomicInitialize.rd index 6cfa82a0..7be93587 100755 --- a/man/circos.genomicInitialize.rd +++ b/man/circos.genomicInitialize.rd @@ -9,8 +9,8 @@ Initialize circular plot with any genomic data \usage{ circos.genomicInitialize(data, sector.names = NULL, major.by = NULL, plotType = c("axis", "labels"), tickLabelsStartFromZero = TRUE, - axis.labels.cex = 0.4*par("cex"), labels.cex = par("cex"), - track.height = convert_height(3, "mm"), ...) + axis.labels.cex = 0.4*par("cex"), labels.cex = 0.8*par("cex"), + track.height = NULL, ...) } \arguments{ diff --git a/man/circos.genomicRainfall.rd b/man/circos.genomicRainfall.rd index 1900527f..d52cf31f 100755 --- a/man/circos.genomicRainfall.rd +++ b/man/circos.genomicRainfall.rd @@ -7,17 +7,18 @@ Genomic rainfall plot Genomic rainfall plot } \usage{ -circos.genomicRainfall(data, mode = "min", ylim = c(0, 9), col = "black", - pch = par("pch"), cex = par("cex"), ...) +circos.genomicRainfall(data, mode = "min", ylim = NULL, col = "black", + pch = par("pch"), cex = par("cex"), normalize_to_width = FALSE, ...) } \arguments{ \item{data}{A bed-file-like data frame or a list of data frames } \item{mode}{how to calculate the distance of two neighbouring regions, pass to \code{\link{rainfallTransform}} } - \item{ylim}{ylim for rainfall plot track. It's value should be log10(inter-distance+1) } + \item{ylim}{ylim for rainfall plot track. If \code{normalize_to_width} is \code{FALSE}, the value should correspond to log10(dist+1), and if \code{normalize_to_width} is \code{TRUE}, the value should correspond to log2(rel_dist). } \item{col}{Color of points. It should be length of one. If \code{data} is a list, the length of \code{col} can also be the length of the list. } \item{pch}{Style of points } \item{cex}{Size of points } + \item{normalize_to_width}{If it is \code{TRUE}, the value is the relative distance divided by the width of the region. } \item{...}{Pass to \code{\link{circos.trackPlotRegion}} } } diff --git a/man/circos.initializeWithIdeogram.rd b/man/circos.initializeWithIdeogram.rd index 2b80ad63..3189b15b 100755 --- a/man/circos.initializeWithIdeogram.rd +++ b/man/circos.initializeWithIdeogram.rd @@ -11,7 +11,7 @@ circos.initializeWithIdeogram(cytoband = system.file(package = "circlize", "extdata", "cytoBand.txt"), species = NULL, sort.chr = TRUE, chromosome.index = NULL, major.by = NULL, plotType = c("ideogram", "axis", "labels"), - track.height = convert_height(3, "mm"), ideogram.height = convert_height(2, "mm"), + track.height = NULL, ideogram.height = convert_height(2, "mm"), ...) } \arguments{ @@ -24,7 +24,7 @@ circos.initializeWithIdeogram(cytoband = system.file(package = "circlize", \item{plotType}{Which tracks should be drawn. \code{ideogram} for ideogram rectangle, \code{axis} for genomic axis and \code{labels} for chromosome names. If there is no ideogram for specified species, \code{ideogram} will be enforced to be excluded. If it is set to \code{NULL}, the function just initialize the plot but draw nothing. } \item{track.height}{Height of the track which contains "axis" and "labels". } \item{ideogram.height}{Height of the ideogram track } - \item{...}{Pass to \code{\link{circos.initialize}} } + \item{...}{Pass to \code{\link{circos.genomicInitialize}}. } } \details{ diff --git a/man/rainfallTransform.rd b/man/rainfallTransform.rd index 9d678695..088cefa6 100755 --- a/man/rainfallTransform.rd +++ b/man/rainfallTransform.rd @@ -7,12 +7,14 @@ Calculate inter-distance of genomic regions Calculate inter-distance of genomic regions } \usage{ -rainfallTransform(region, mode = c("min", "max", "mean", "left", "right")) +rainfallTransform(region, mode = c("min", "max", "mean", "left", "right"), + normalize_to_width = FALSE) } \arguments{ \item{region}{Genomic positions. It can be a data frame with two columns which are start positions and end positions on a single chromosome. It can also be a bed-format data frame which contains the chromosome column. } \item{mode}{How to calculate inter-distance. For a region, there is a distance to the prevous region and also there is a distance to the next region. \code{mode} controls how to merge these two distances into one value. } + \item{normalize_to_width}{If it is \code{TRUE}, the value is the relative distance divided by the width of the region. } } \value{