From 86583997c92baaa2b7dc31df2972412d244e9f14 Mon Sep 17 00:00:00 2001 From: jahn Date: Thu, 4 Jul 2024 14:33:25 +0200 Subject: [PATCH 1/6] fix: typos in color scale --- R/geom_coverage.R | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/R/geom_coverage.R b/R/geom_coverage.R index 6bc5d96..af33518 100644 --- a/R/geom_coverage.R +++ b/R/geom_coverage.R @@ -126,9 +126,9 @@ geom_coverage <- function(data, mapping = NULL, color = NULL, rect.color = NA, if (is.null(names(fill.color))) { names(fill.color) <- unique(data[, group.key]) } - sacle_fill_cols <- scale_fill_manual(values = fill.color) + scale_fill_cols <- scale_fill_manual(values = fill.color) } else { - sacle_fill_cols <- NULL + scale_fill_cols <- NULL } if (!single.nuc) { mapping <- aes_string(xmin = "start", xmax = "end", ymin = "0", ymax = "score", fill = group.key) @@ -180,9 +180,9 @@ geom_coverage <- function(data, mapping = NULL, color = NULL, rect.color = NA, names(fill.color) <- unique(data[, fill.str]) } } - sacle_fill_cols <- scale_fill_manual(values = fill.color) + scale_fill_cols <- scale_fill_manual(values = fill.color) } else { - sacle_fill_cols <- NULL + scale_fill_cols <- NULL } } else if (plot.type == "joint") { message("For joint visualization, the mapping should contains start, score, color.") @@ -255,8 +255,8 @@ geom_coverage <- function(data, mapping = NULL, color = NULL, rect.color = NA, plot.ele <- list(region.rect, region.facet) # color the track - if (!is.null(sacle_fill_cols)) { - plot.ele <- append(plot.ele, sacle_fill_cols) + if (!is.null(scale_fill_cols)) { + plot.ele <- append(plot.ele, scale_fill_cols) } if (range.position == "in") { From e1857766600847fa4673fcf6d18a39a6a5a0e79d Mon Sep 17 00:00:00 2001 From: jahn Date: Thu, 4 Jul 2024 14:34:03 +0200 Subject: [PATCH 2/6] feat: added functions to customize colors in geom_peak --- DESCRIPTION | 2 +- NAMESPACE | 1 + R/geom_coverage.R | 10 ++-- R/geom_feature.R | 2 +- R/geom_peak.R | 133 +++++++++++++++++++++++++++++----------------- R/utils.R | 12 ++--- man/geom_peak.Rd | 75 ++++++++++++++++---------- 7 files changed, 145 insertions(+), 90 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 70a3a6a..9f30a29 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -57,4 +57,4 @@ VignetteBuilder: knitr biocViews: Encoding: UTF-8 -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 diff --git a/NAMESPACE b/NAMESPACE index a59ad92..9c56902 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -114,6 +114,7 @@ importFrom(ggplot2,ggplot_add) importFrom(ggplot2,labs) importFrom(ggplot2,margin) importFrom(ggplot2,rel) +importFrom(ggplot2,scale_color_continuous) importFrom(ggplot2,scale_color_gradientn) importFrom(ggplot2,scale_color_manual) importFrom(ggplot2,scale_fill_manual) diff --git a/R/geom_coverage.R b/R/geom_coverage.R index af33518..2556a43 100644 --- a/R/geom_coverage.R +++ b/R/geom_coverage.R @@ -119,7 +119,7 @@ geom_coverage <- function(data, mapping = NULL, color = NULL, rect.color = NA, if (length(color) < length(unique(data[, group.key]))) { warning("Fewer colors provided than there are groups in ", group.key, " variable, falling back to default colors") # sample group with same color - fill.color <- AutoColor(data = data, n = 9, name = "Set1", key = group.key) + fill.color <- AutoColor(data = data[[group.key]], pal = "Set1") } else { fill.color <- color } @@ -140,7 +140,7 @@ geom_coverage <- function(data, mapping = NULL, color = NULL, rect.color = NA, if (length(color) != length(unique(data[, group.key]))) { warning("The color you provided is not as long as ", group.key, " column in data, select automatically!") # sample group with same color - tmp.color <- AutoColor(data = data, n = 9, name = "Set1", key = group.key) + tmp.color <- AutoColor(data = data[[group.key]], pal = "Set1") # change group key color color.color.df <- merge(unique(data[c(group.key)]), data.frame(color = tmp.color), by.x = group.key, by.y = 0) color.color <- color.color.df$color @@ -169,7 +169,7 @@ geom_coverage <- function(data, mapping = NULL, color = NULL, rect.color = NA, fill.str.len <- length(unique(data[, fill.str])) if (is.null(color) | length(color) != fill.str.len) { # sample group with same color - tmp.color <- AutoColor(data = data, n = 9, name = "Set1", key = group.key) + tmp.color <- AutoColor(data = data[[group.key]], pal = "Set1") # change color fill.color.df <- merge(unique(data[c(fill.str, group.key)]), data.frame(color = tmp.color), by.x = group.key, by.y = 0) fill.color <- fill.color.df$color @@ -191,7 +191,7 @@ geom_coverage <- function(data, mapping = NULL, color = NULL, rect.color = NA, color.str.len <- length(unique(data[, color.str])) if (is.null(color) | length(color) != color.str.len) { # sample group with same color - tmp.color <- AutoColor(data = data, n = 9, name = "Set1", key = group.key) + tmp.color <- AutoColor(data = data[[group.key]], pal = "Set1") # change color if (color.str == group.key) { color.color.df <- merge(unique(data[c(color.str)]), data.frame(color = tmp.color), by.x = group.key, by.y = 0) @@ -223,7 +223,7 @@ geom_coverage <- function(data, mapping = NULL, color = NULL, rect.color = NA, # facet color if (is.null(facet.color)) { - facet.color <- AutoColor(data = data, n = 12, name = "Set3", key = facet.key) + facet.color <- AutoColor(data = data[[facet.key]], pal = "Set3") } # facet formula diff --git a/R/geom_feature.R b/R/geom_feature.R index 7565fbe..0ee0196 100644 --- a/R/geom_feature.R +++ b/R/geom_feature.R @@ -99,7 +99,7 @@ ggplot_add.feature <- function(object, plot, object_name) { } } else { warning("The color you provided is smaller than Type column in data, select automatically!") - used.feature.color <- AutoColor(data = valid.feature, n = 9, name = "Set1", key = "Type") + used.feature.color <- AutoColor(data = valid.feature$Type, pal = "Set1") } # create plot diff --git a/R/geom_peak.R b/R/geom_peak.R index 2a33ca5..b5e40e8 100644 --- a/R/geom_peak.R +++ b/R/geom_peak.R @@ -2,51 +2,69 @@ #' #' @param bed.file The path to consensus peaks file. Default: NULL. #' @param peak.df The dataframe contains consensus peaks. Default: NULL. -#' @param peak.color Peak color. Default: black. +#' @param peak.color Peak colors. Default: NULL. #' @param peak.size The line size of peak. Default: 5. +#' @param color.by Name of optional column in bed file/data frame which is used for coloring. Default: NULL. #' @param plot.space Top and bottom margin. Default: 0.1. -#' @param plot.height The relative height of peak annotation to coverage plot. Default: 0.2. +#' @param plot.height The relative height of peak annotation to coverage plot. Default: 0.1. #' #' @return Plot. #' @importFrom utils read.table #' @importFrom dplyr arrange #' @importFrom dplyr %>% -#' @importFrom ggplot2 ggplot_add ggplot geom_segment aes_string theme_classic theme element_blank element_text -#' element_rect margin scale_x_continuous scale_y_continuous coord_cartesian +#' @importFrom ggplot2 ggplot_add ggplot geom_segment aes_string theme_classic +#' theme element_blank element_text element_rect margin scale_x_continuous +#' scale_y_continuous scale_color_continuous coord_cartesian #' @export #' #' @examples -#' # library(ggcoverage) -#' # library(rtracklayer) -#' # sample.meta <- data.frame( -#' # SampleName = c("Chr18_MCF7_ER_1", "Chr18_MCF7_ER_2", "Chr18_MCF7_ER_3", "Chr18_MCF7_input"), -#' # Type = c("MCF7_ER_1", "MCF7_ER_2", "MCF7_ER_3", "MCF7_input"), -#' # Group = c("IP", "IP", "IP", "Input") -#' # ) -#' # track folder -#' # track.folder <- system.file("extdata", "ChIP-seq", package = "ggcoverage") -#' # load bigwig file -#' # track.df <- LoadTrackFile( -#' # track.folder = track.folder, format = "bw", -#' # meta.info = sample.meta -#' # ) -#' # gtf.file <- system.file("extdata", "used_hg19.gtf", package = "ggcoverage") -#' # gtf.gr <- rtracklayer::import.gff(con = gtf.file, format = "gtf") -#' # create mark region -#' # mark.region <- data.frame(start = c(76822533), end = c(76823743), label = c("Promoter")) -#' # basic.coverage <- ggcoverage( -#' # data = track.df, color = "auto", region = "chr18:76822285-76900000", -#' # mark.region = mark.region, show.mark.label = FALSE -#' # ) -#' # get consensus peak file -#' # peak.file <- system.file("extdata", "ChIP-seq", "consensus.peak", package = "ggcoverage") -#' # basic.coverage + geom_gene(gtf.gr = gtf.gr) + geom_peak(bed.file = peak.file) -geom_peak <- function(bed.file = NULL, peak.df = NULL, peak.color = "black", peak.size = 5, - plot.space = 0.1, plot.height = 0.1) { +#' # load metadata +#' sample_meta <- data.frame( +#' SampleName = c( +#' "Chr18_MCF7_ER_1", +#' "Chr18_MCF7_ER_2", +#' "Chr18_MCF7_ER_3", +#' "Chr18_MCF7_input" +#' ), +#' Type = c("MCF7_ER_1", "MCF7_ER_2", "MCF7_ER_3", "MCF7_input"), +#' Group = c("IP", "IP", "IP", "Input") +#' ) +#' +#' # import coverage track +#' track_folder <- system.file("extdata", "ChIP-seq", package = "ggcoverage") +#' track_df <- LoadTrackFile( +#' track.folder = track_folder, +#' format = "bw", +#' region = "chr18:76822285-76900000", +#' meta.info = sample_meta +#' ) +#' +#' # create mock peak file +#' df_peaks <- data.frame( +#' seqnames = c("chr18", "chr18", "chr18"), +#' start = c(76822533, 76846900, 76880000), +#' end = c(76836900, 76860000, 76887000), +#' score = c(4, 6, 13) +#' ) +#' +#' # plot with default color +#' ggcoverage(data = track_df) + +#' geom_peak(peak.df = df_peaks, peak.size = 3) +#' +#' # plot with color by 'score' variable +#' ggcoverage(data = track_df) + +#' geom_peak(peak.df = df_peaks, peak.size = 3, color.by = "score") +#' +#' # plot with color by 'score' variable and custom color scale +#' ggcoverage(data = track_df) + +#' geom_peak(peak.df = df_peaks, peak.size = 3, color.by = "score", peak.color = rainbow(5)) +#' +geom_peak <- function(bed.file = NULL, peak.df = NULL, peak.color = NULL, peak.size = 5, + color.by = NULL, plot.space = 0.1, plot.height = 0.1) { structure( list( bed.file = bed.file, peak.df = peak.df, peak.color = peak.color, peak.size = peak.size, - plot.space = plot.space, plot.height = plot.height + color.by = color.by, plot.space = plot.space, plot.height = plot.height ), class = "peak" ) @@ -54,22 +72,13 @@ geom_peak <- function(bed.file = NULL, peak.df = NULL, peak.color = "black", pea #' @export ggplot_add.peak <- function(object, plot, object_name) { - # get plot data - # plot.data <- plot$layers[[1]]$data - # get plot data, plot data should contain bins if ("patchwork" %in% class(plot)) { plot.data <- plot[[1]]$layers[[1]]$data } else { plot.data <- plot$layers[[1]]$data } - # prepare plot range - # the plot region are not normal, so start is minimum value plot.chr <- as.character(plot.data[1, "seqnames"]) - # plot.region.start <- plot$coordinates$limits$x[1] - # plot.region.end <- plot$coordinates$limits$x[2] - # plot.region.start <- plot.data[1, "start"] plot.region.start <- min(plot.data[, "start"]) - # plot.region.end <- plot.data[nrow(plot.data), "end"] plot.region.end <- max(plot.data[, "end"]) # get parameters @@ -77,6 +86,7 @@ ggplot_add.peak <- function(object, plot, object_name) { peak.df <- object$peak.df peak.color <- object$peak.color peak.size <- object$peak.size + color.by <- object$color.by plot.space <- object$plot.space plot.height <- object$plot.height @@ -86,14 +96,36 @@ ggplot_add.peak <- function(object, plot, object_name) { } else if (!is.null(peak.df)) { bed.info <- peak.df } - bed.info <- bed.info[c(1, 2, 3)] - colnames(bed.info) <- c("seqnames", "start", "end") - # convert to 1-based + colnames(bed.info)[c(1, 2, 3)] <- c("seqnames", "start", "end") bed.info$start <- as.numeric(bed.info$start) + 1 - - # get valid bed valid.bed <- GetRegion(chr = plot.chr, df = bed.info, start = plot.region.start, end = plot.region.end) + # color management + if (!is.null(color.by)) { + if (is.numeric(valid.bed[[color.by]])) { + if (!is.null(peak.color)) { + scale_colors <- scale_color_gradientn(colours = peak.color) + } else { + scale_colors <- scale_color_continuous() + } + } else { + if (length(peak.color) < length(unique(valid.bed[[color.by]]))) { + warning("Fewer colors provided than there are groups in ", color.by, " variable, falling back to default colors") + auto_colors <- AutoColor(data = valid.bed[[color.by]], pal = "Set3") + scale_colors <- scale_color_manual(values = auto_colors) + } else { + scale_colors <- scale_color_manual(values = peak.color) + } + } + } else { + color.by <- "color" + if (is.null(peak.color)) { + peak.color <- "black" + } + valid.bed$color <- peak.color[1] + scale_colors <- scale_color_manual(values = peak.color) + } + peak.plot <- ggplot() + geom_segment( data = valid.bed, @@ -101,15 +133,18 @@ ggplot_add.peak <- function(object, plot, object_name) { x = "start", y = "1", xend = "end", - yend = "1" + yend = "1", + color = color.by ), size = peak.size, - color = peak.color ) + + scale_colors + labs(y = "Peak") # add theme - peak.plot <- peak.plot + theme_peak(margin.len = plot.space, x.range = c(plot.region.start, plot.region.end)) + peak.plot <- peak.plot + + theme_peak(margin.len = plot.space, x.range = c(plot.region.start, plot.region.end)) + + theme(legend.position = "none") # assemble plot patchwork::wrap_plots(plot + theme(plot.margin = margin(t = plot.space, b = plot.space)), peak.plot, diff --git a/R/utils.R b/R/utils.R index c4d187c..ae39d01 100644 --- a/R/utils.R +++ b/R/utils.R @@ -55,18 +55,18 @@ PrepareRegion <- function(region = NULL, } # select color automatically -AutoColor <- function(data, n, name, key) { +AutoColor <- function(data, pal) { palettes <- list( Set1 = c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999"), Set2 = c("#66C2A5", "#FC8D62", "#8DA0CB", "#E78AC3", "#A6D854", "#FFD92F", "#E5C494", "#B3B3B3"), Set3 = c("#8DD3C7", "#FFFFB3", "#BEBADA", "#FB8072", "#80B1D3", "#FDB462", "#B3DE69", "#FCCDE5", "#D9D9D9") ) - getPalette <- grDevices::colorRampPalette(palettes[[name]]) + get_palette <- grDevices::colorRampPalette(palettes[[pal]]) # sample group with same color - group.info <- unique(data[, key]) - fill.color <- getPalette(length(group.info)) - names(fill.color) <- group.info - return(fill.color) + data_levels <- unique(data) + cols <- get_palette(length(data_levels)) + names(cols) <- data_levels + return(cols) } # create aa plot dataframe with padding offset diff --git a/man/geom_peak.Rd b/man/geom_peak.Rd index 02c87f4..19f8f1c 100644 --- a/man/geom_peak.Rd +++ b/man/geom_peak.Rd @@ -7,8 +7,9 @@ geom_peak( bed.file = NULL, peak.df = NULL, - peak.color = "black", + peak.color = NULL, peak.size = 5, + color.by = NULL, plot.space = 0.1, plot.height = 0.1 ) @@ -18,13 +19,15 @@ geom_peak( \item{peak.df}{The dataframe contains consensus peaks. Default: NULL.} -\item{peak.color}{Peak color. Default: black.} +\item{peak.color}{Peak colors. Default: NULL.} \item{peak.size}{The line size of peak. Default: 5.} +\item{color.by}{Name of optional column in bed file/data frame which is used for coloring. Default: NULL.} + \item{plot.space}{Top and bottom margin. Default: 0.1.} -\item{plot.height}{The relative height of peak annotation to coverage plot. Default: 0.2.} +\item{plot.height}{The relative height of peak annotation to coverage plot. Default: 0.1.} } \value{ Plot. @@ -33,29 +36,45 @@ Plot. Add Peak Annotation to Coverage Plot. } \examples{ -# library(ggcoverage) -# library(rtracklayer) -# sample.meta <- data.frame( -# SampleName = c("Chr18_MCF7_ER_1", "Chr18_MCF7_ER_2", "Chr18_MCF7_ER_3", "Chr18_MCF7_input"), -# Type = c("MCF7_ER_1", "MCF7_ER_2", "MCF7_ER_3", "MCF7_input"), -# Group = c("IP", "IP", "IP", "Input") -# ) -# track folder -# track.folder <- system.file("extdata", "ChIP-seq", package = "ggcoverage") -# load bigwig file -# track.df <- LoadTrackFile( -# track.folder = track.folder, format = "bw", -# meta.info = sample.meta -# ) -# gtf.file <- system.file("extdata", "used_hg19.gtf", package = "ggcoverage") -# gtf.gr <- rtracklayer::import.gff(con = gtf.file, format = "gtf") -# create mark region -# mark.region <- data.frame(start = c(76822533), end = c(76823743), label = c("Promoter")) -# basic.coverage <- ggcoverage( -# data = track.df, color = "auto", region = "chr18:76822285-76900000", -# mark.region = mark.region, show.mark.label = FALSE -# ) -# get consensus peak file -# peak.file <- system.file("extdata", "ChIP-seq", "consensus.peak", package = "ggcoverage") -# basic.coverage + geom_gene(gtf.gr = gtf.gr) + geom_peak(bed.file = peak.file) +# load metadata +sample_meta <- data.frame( + SampleName = c( + "Chr18_MCF7_ER_1", + "Chr18_MCF7_ER_2", + "Chr18_MCF7_ER_3", + "Chr18_MCF7_input" + ), + Type = c("MCF7_ER_1", "MCF7_ER_2", "MCF7_ER_3", "MCF7_input"), + Group = c("IP", "IP", "IP", "Input") +) + +# import coverage track +track_folder <- system.file("extdata", "ChIP-seq", package = "ggcoverage") +track_df <- LoadTrackFile( + track.folder = track_folder, + format = "bw", + region = "chr18:76822285-76900000", + meta.info = sample_meta +) + +# create mock peak file +df_peaks <- data.frame( + seqnames = c("chr18", "chr18", "chr18"), + start = c(76822533, 76846900, 76880000), + end = c(76836900, 76860000, 76887000), + score = c(4, 6, 13) +) + +# plot with default color +ggcoverage(data = track_df) + + geom_peak(peak.df = df_peaks, peak.size = 3) + +# plot with color by 'score' variable +ggcoverage(data = track_df) + + geom_peak(peak.df = df_peaks, peak.size = 3, color.by = "score") + +# plot with color by 'score' variable and custom color scale +ggcoverage(data = track_df) + + geom_peak(peak.df = df_peaks, peak.size = 3, color.by = "score", peak.color = rainbow(5)) + } From 859139c5dd4fca880f7171abd1cfc94810d30bc6 Mon Sep 17 00:00:00 2001 From: jahn Date: Wed, 9 Oct 2024 22:04:38 +0200 Subject: [PATCH 3/6] feat: initial draft for styling gene arrows; closes #38 --- R/geom_gene.R | 94 ++++++++++++++++++++++++++++++++++++--------------- R/utils.R | 73 ++++++++++++++------------------------- 2 files changed, 91 insertions(+), 76 deletions(-) diff --git a/R/geom_gene.R b/R/geom_gene.R index 8424399..5747662 100644 --- a/R/geom_gene.R +++ b/R/geom_gene.R @@ -4,10 +4,14 @@ #' @param overlap.gene.gap The gap between gene groups. Default: 0.1. #' @param overlap.style The style of gene groups, choose from loose (each gene occupies single line) #' and tight (place non-overlap genes in one line). Default: loose. -#' @param gene.size The line size of gene. Default: 1. -#' @param utr.size The line size of UTR. Default: 2. -#' @param exon.size The line size of exon. Default: 3. -#' @param arrow.size The line size of arrow. Default: 1.5. +#' @param gene.size The line width of genes. Default: 1. +#' @param utr.size The line width of UTRs. Default: 2. +#' @param exon.size The line width of exons. Default: 3. +#' @param arrow.angle Angle of the arrow head. Default 35° +#' @param arrow.length Length of arrows. Default: 1.5 +#' @param arrow.type Whether to draw "closed" or "open" (default) arrow heads + +#' @param #' @param arrow.gap The gap distance between intermittent arrows. Default: NULL. #' Set arrow.num and arrow.gap to NULL to suppress intermittent arrows. #' @param arrow.num Total number of intermittent arrows over whole region. Default: 50. @@ -21,6 +25,13 @@ #' @param plot.space Top and bottom margin. Default: 0.1. #' @param plot.height The relative height of gene annotation to coverage plot. Default: 0.2. #' + +arrow.gap = NULL, +arrow.num = 50, +arrow.size.im = 0.5, +arrow.length.im = 1.5, +arrow.type.im = "closed", +color.by.im = NULL, #' @return Plot. #' @importFrom dplyr %>% #' @importFrom rlang .data @@ -61,16 +72,37 @@ #' basic.coverage <- ggcoverage(data = track_df, range.position = "out") #' basic.coverage + #' geom_gene(gtf.gr = gtf_gr) +#' +#'# plot with custom style +#' basic_coverage + +#' geom_gene( +#' gtf.gr = gtf_gr, +#' exon.size = 2.0, +#' arrow.size.im = 1.0, +#' arrow.length.im = 5, +#' arrow.type.im = "open", +#' color.by.im = "strand", +#' fill.color = c( +#' "-" = "darkblue", +#' "+" = "darkgreen" +#' ) +#' ) geom_gene <- function(gtf.gr, overlap.gene.gap = 0.1, overlap.style = "loose", gene.size = 1, utr.size = 2, exon.size = 3, - arrow.size = 1.5, + arrow.angle = 35, + arrow.length = 1.5, + arrow.type = "open", + color.by = "strand", arrow.gap = NULL, arrow.num = 50, - color.by = "strand", + arrow.size.im = 0.5, + arrow.length.im = 1.5, + arrow.type.im = "closed", + color.by.im = NULL, fill.color = c( "-" = "cornflowerblue", "+" = "darkolivegreen3" @@ -88,10 +120,16 @@ geom_gene <- function(gtf.gr, gene.size = gene.size, utr.size = utr.size, exon.size = exon.size, - arrow.size = arrow.size, + arrow.angle = arrow.angle, + arrow.length = arrow.length, + arrow.type = arrow.type, + color.by = color.by, arrow.gap = arrow.gap, arrow.num = arrow.num, - color.by = color.by, + arrow.size.im = arrow.size.im, + arrow.length.im = arrow.length.im, + arrow.type.im = arrow.type.im, + color.by.im = color.by.im, fill.color = fill.color, show.utr = show.utr, label.size = label.size, @@ -121,22 +159,9 @@ ggplot_add.gene <- function(object, plot, object_name) { ranges = IRanges::IRanges(plot.range.start, plot.range.end) ) # get parameters - gtf.gr <- object$gtf.gr - overlap.gene.gap <- object$overlap.gene.gap - overlap.style <- object$overlap.style - gene.size <- object$gene.size - utr.size <- object$utr.size - exon.size <- object$exon.size - arrow.size <- object$arrow.size - color.by <- object$color.by - fill.color <- object$fill.color - show.utr <- object$show.utr - arrow.gap <- object$arrow.gap - arrow.num <- object$arrow.num - label.size <- object$label.size - label.vjust <- object$label.vjust - plot.space <- object$plot.space - plot.height <- object$plot.height + for (ob in names(object)) { + assign(x = ob, value = object[[ob]]) + } # get gene in region gtf.df.used <- IRanges::subsetByOverlaps(x = gtf.gr, ranges = plot.range.gr) %>% as.data.frame() @@ -203,11 +228,11 @@ ggplot_add.gene <- function(object, plot, object_name) { gene.info.used.utr <- gene.exon.utr$utr } gene.plot <- ggplot() + - geom_arrows(gene.info.used.gene, color.by, gene.size, arrow.size) + - geom_arrows(gene.info.used.exon, color.by, exon.size, arrow.size) + geom_arrows(gene.info.used.gene, color.by, gene.size, arrow.length, arrow.angle, arrow.type) + + geom_arrows(gene.info.used.exon, color.by, exon.size, arrow.length, arrow.angle, arrow.type) if (show.utr) { gene.plot <- gene.plot + - geom_arrows(gene.info.used.utr, color.by, utr.size, arrow.size) + geom_arrows(gene.info.used.utr, color.by, utr.size, arrow.length, arrow.angle, arrow.type) } if (!is.null(arrow.gap) || !is.null(arrow.num)) { @@ -251,8 +276,21 @@ ggplot_add.gene <- function(object, plot, object_name) { arrow.df$start <- as.numeric(arrow.df$start) arrow.df$end <- as.numeric(arrow.df$end) arrow.df$group <- as.numeric(arrow.df$group) + if (is.null(color.by.im)) { + color.by.im <- color.by + arrow.df[[color.by]] <- "im" + fill.color["im"] <- grDevices::grey(1, alpha = 0.5) + } else if (color.by.im %in% colnames(arrow.df)) { + stopifnot(unique(arrow.df[[color.by.im]]) %in% names(fill.color)) + } else { + stop(paste0( + "The selected variable '", + color.by.im , + "' for 'color.by.im' is not available in the data" + )) + } gene.plot <- gene.plot + - geom_arrows(arrow.df, color.by, gene.size / 2, arrow.size, 35, TRUE) + geom_arrows(arrow.df, color.by.im, arrow.size.im, arrow.length.im, arrow.angle, arrow.type.im) } label.df <- data.frame( diff --git a/R/utils.R b/R/utils.R index ae39d01..9a755cd 100644 --- a/R/utils.R +++ b/R/utils.R @@ -355,9 +355,8 @@ GetPlotData <- function(plot, layer.num = 1) { #' @param color name of the color column in the data frame #' @param line_width line_width of the (arrow) segment #' @param arrow_size size of the arrow -#' @param arrow_angle angle of the arrow. Default: 35° -#' @param intermittent If TRUE, arrows are only drawn intermittently in -#' half-transparent white color. Default: FALSE. +#' @param arrow_angle angle of the arrow in degrees +#' @param arrow_type type of arrow, either 'open' or 'closed' #' @importFrom grDevices grey #' @return A geom layer for ggplot2 objects. #' @export @@ -366,54 +365,32 @@ geom_arrows <- color, line_width, arrow_size, - arrow_angle = 35, - intermittent = FALSE) { + arrow_angle, + arrow_type) { if (nrow(data)) { if (!"strand" %in% colnames(data)) { data$strand <- "+" } - if (!intermittent) { - geom_segment( - data = data, - mapping = aes_string( - x = "start", - y = "group", - xend = "end", - yend = "group", - color = color - ), - arrow = arrow( - ends = ifelse(data$strand == "+", "last", "first"), - angle = arrow_angle, - length = unit(arrow_size, "points"), - type = "open" - ), - lineend = "butt", - linejoin = "mitre", - show.legend = FALSE, - linewidth = line_width - ) - } else { - geom_segment( - data = data, - mapping = aes_string( - x = "start", - y = "group", - xend = "end", - yend = "group" - ), - arrow = arrow( - ends = ifelse(data$strand == "+", "last", "first"), - angle = arrow_angle, - length = unit(arrow_size, "points"), - type = "closed" - ), - lineend = "butt", - linejoin = "mitre", - show.legend = FALSE, - linewidth = line_width, - color = grDevices::grey(1, alpha = 0.5) - ) - } + geom_segment( + inherit.aes = TRUE, + data = data, + mapping = aes( + x = .data[["start"]], + y = .data[["group"]], + xend = .data[["end"]], + yend = .data[["group"]], + color = .data[[color]] + ), + arrow = arrow( + ends = ifelse(data$strand == "+", "last", "first"), + angle = arrow_angle, + length = unit(arrow_size, "points"), + type = arrow_type + ), + lineend = "butt", + linejoin = "mitre", + show.legend = FALSE, + linewidth = line_width + ) } } From b416a04248cfda227e9f733307f87ef0c7db7b43 Mon Sep 17 00:00:00 2001 From: jahn Date: Thu, 10 Oct 2024 11:06:36 +0200 Subject: [PATCH 4/6] feat: further improvements for styling gene arrows #38 --- R/geom_gene.R | 77 +++++++++++++-------- R/geom_transcript.R | 151 ++++++++++++++++++++++++++++------------- R/utils.R | 1 - man/geom_arrows.Rd | 14 +--- man/geom_gene.Rd | 69 +++++++++++++++---- man/geom_transcript.Rd | 73 +++++++++++++++----- 6 files changed, 267 insertions(+), 118 deletions(-) diff --git a/R/geom_gene.R b/R/geom_gene.R index 5747662..1dfd4ff 100644 --- a/R/geom_gene.R +++ b/R/geom_gene.R @@ -1,46 +1,50 @@ #' Add Gene Annotation to Coverage Plot. #' -#' @param gtf.gr Granges object of GTF, created with \code{\link{import.gff}}. Default: NULL. +#' @param gtf.gr Granges object of GTF, created with \code{\link{import.gff}}. +#' Default: NULL. #' @param overlap.gene.gap The gap between gene groups. Default: 0.1. -#' @param overlap.style The style of gene groups, choose from loose (each gene occupies single line) -#' and tight (place non-overlap genes in one line). Default: loose. -#' @param gene.size The line width of genes. Default: 1. -#' @param utr.size The line width of UTRs. Default: 2. -#' @param exon.size The line width of exons. Default: 3. +#' @param overlap.style The style of gene groups, choose from loose (each gene +#' occupies single line) and tight (place non-overlap genes in one line). +#' Default: loose. +#' @param gene.size Line width of genes. Default: 1. +#' @param utr.size Line width of UTRs. Default: 2. +#' @param exon.size Line width of exons. Default: 3. #' @param arrow.angle Angle of the arrow head. Default 35° #' @param arrow.length Length of arrows. Default: 1.5 #' @param arrow.type Whether to draw "closed" or "open" (default) arrow heads - -#' @param +#' @param color.by Color the lines/arrows by variable. Default: "strand". #' @param arrow.gap The gap distance between intermittent arrows. Default: NULL. #' Set arrow.num and arrow.gap to NULL to suppress intermittent arrows. -#' @param arrow.num Total number of intermittent arrows over whole region. Default: 50. -#' Set arrow.num and arrow.gap to NULL to suppress intermittent arrows. -#' @param color.by Color the line by. Default: strand. +#' @param arrow.num Total number of intermittent arrows over whole region. +#' Default: 50. Set arrow.num and arrow.gap to NULL to suppress intermittent +#' arrows. +#' @param arrow.size.im Line width of intermittent arrows. Default: 0.5 +#' @param arrow.length.im Length of intermittent arrows. Default: 1.5 +#' @param arrow.type.im Whether to draw "closed" (default) or "open" heads for +#' intermittent arrows +#' @param color.by.im Color the intermittent arrows by variable. Default: NULL +#' (draws semi-transparent, white arrows) #' @param fill.color Color used for \code{color.by}. -#' Default: blue for - (minus strand), green for + (plus strand). +#' Default: blue for - (minus strand), green for + (plus strand). #' @param show.utr Logical value, whether to show UTR. Default: TRUE. #' @param label.size The size of gene label. Default: 3. #' @param label.vjust The vjust of gene label. Default: 2. #' @param plot.space Top and bottom margin. Default: 0.1. -#' @param plot.height The relative height of gene annotation to coverage plot. Default: 0.2. +#' @param plot.height The relative height of gene annotation to coverage plot. +#' Default: 0.2. #' - -arrow.gap = NULL, -arrow.num = 50, -arrow.size.im = 0.5, -arrow.length.im = 1.5, -arrow.type.im = "closed", -color.by.im = NULL, #' @return Plot. #' @importFrom dplyr %>% #' @importFrom rlang .data #' @importFrom GenomicRanges GRanges makeGRangesFromDataFrame setdiff #' @importFrom IRanges IRanges subsetByOverlaps findOverlaps #' @importFrom dplyr filter select arrange -#' @importFrom ggplot2 ggplot_add ggplot geom_segment aes_string arrow unit geom_text labs theme_classic theme element_blank -#' element_text element_rect margin scale_y_continuous scale_color_manual scale_x_continuous coord_cartesian +#' @importFrom ggplot2 ggplot_add ggplot geom_segment aes_string arrow unit +#' geom_text labs theme_classic theme element_blank element_text element_rect +#' margin scale_y_continuous scale_color_manual scale_x_continuous +#' coord_cartesian #' @importFrom patchwork wrap_plots +#' @importFrom grDevices grey #' @export #' #' @examples @@ -69,8 +73,8 @@ color.by.im = NULL, #' gtf_gr <- rtracklayer::import.gff(con = gtf_file, format = "gtf") #' #' # plot coverage and gene annotation -#' basic.coverage <- ggcoverage(data = track_df, range.position = "out") -#' basic.coverage + +#' basic_coverage <- ggcoverage(data = track_df, range.position = "out") +#' basic_coverage + #' geom_gene(gtf.gr = gtf_gr) #' #'# plot with custom style @@ -159,9 +163,28 @@ ggplot_add.gene <- function(object, plot, object_name) { ranges = IRanges::IRanges(plot.range.start, plot.range.end) ) # get parameters - for (ob in names(object)) { - assign(x = ob, value = object[[ob]]) - } + gtf.gr <- object$gtf.gr + overlap.gene.gap <- object$overlap.gene.gap + overlap.style <- object$overlap.style + gene.size <- object$gene.size + utr.size <- object$utr.size + exon.size <- object$exon.size + arrow.angle <- object$arrow.angle + arrow.length <- object$arrow.length + arrow.type <- object$arrow.type + color.by <- object$color.by + arrow.gap <- object$arrow.gap + arrow.num <- object$arrow.num + arrow.size.im <- object$arrow.size.im + arrow.length.im <- object$arrow.length.im + arrow.type.im <- object$arrow.type.im + color.by.im <- object$color.by.im + fill.color <- object$fill.color + show.utr <- object$show.utr + label.size <- object$label.size + label.vjust <- object$label.vjust + plot.space <- object$plot.space + plot.height <- object$plot.height # get gene in region gtf.df.used <- IRanges::subsetByOverlaps(x = gtf.gr, ranges = plot.range.gr) %>% as.data.frame() diff --git a/R/geom_transcript.R b/R/geom_transcript.R index ac4a103..d877402 100644 --- a/R/geom_transcript.R +++ b/R/geom_transcript.R @@ -1,25 +1,37 @@ #' Add Transcript Annotation to Coverage Plot. #' -#' @param gtf.gr Granges object of GTF, created with \code{\link{import.gff}}. Default: NULL. +#' @param gtf.gr Granges object of GTF, created with \code{\link{import.gff}}. +#' Default: NULL. #' @param gene.name Gene name of all transcripts. Default: HNRNPC. #' @param overlap.tx.gap The gap between transcript groups. Default: 0.1. -#' @param overlap.style The style of transcript groups, choose from loose (each transcript occupies single line) -#' and tight (place non-overlap transcripts in one line). Default: loose. -#' @param tx.size The line size of transcript. Default: 1. -#' @param utr.size The line size of UTR. Default: 2. -#' @param exon.size The line size of exon. Default: 3. -#' @param arrow.size The line size of arrow. Default: 1.5. +#' @param overlap.style The style of transcript groups, choose from loose (each +#' transcript occupies single line) and tight (place non-overlap transcripts +#' in one line). Default: loose. +#' @param tx.size Line size of transcript. Default: 1. +#' @param utr.size Line size of UTR. Default: 2. +#' @param exon.size Line size of exon. Default: 3. +#' @param arrow.angle Angle of the arrow head. Default 35° +#' @param arrow.length Length of arrows. Default: 1.5 +#' @param arrow.type Whether to draw "closed" or "open" (default) arrow heads +#' @param color.by Color the line by. Default: strand. #' @param arrow.gap The gap distance between intermittent arrows. Default: NULL. #' Set arrow.num and arrow.gap to NULL to suppress intermittent arrows. -#' @param arrow.num Total number of intermittent arrows over whole region. Default: 50. -#' Set arrow.num and arrow.gap to NULL to suppress intermittent arrows. -#' @param color.by Color the line by. Default: strand. -#' @param fill.color Color used for \code{color.by}. -#' Default: blue for - (minus strand), green for + (plus strand). +#' @param arrow.num Total number of intermittent arrows over whole region. +#' Default: 50. Set arrow.num and arrow.gap to NULL to suppress intermittent +#' arrows. +#' @param arrow.size.im Line width of intermittent arrows. Default: 0.5 +#' @param arrow.length.im Length of intermittent arrows. Default: 1.5 +#' @param arrow.type.im Whether to draw "closed" (default) or "open" heads for +#' intermittent arrows +#' @param color.by.im Color the intermittent arrows by variable. Default: NULL +#' (draws semi-transparent, white arrows) +#' @param fill.color Color used for \code{color.by}. Default: blue for - (minus +#' strand), green for + (plus strand). #' @param label.size The size of transcript label. Default: 3. #' @param label.vjust The vjust of transcript label. Default: 2. #' @param plot.space Top and bottom margin. Default: 0.1. -#' @param plot.height The relative height of transcript annotation to coverage plot. Default: 0.2. +#' @param plot.height The relative height of transcript annotation to coverage +#' plot. Default: 0.2. #' #' @return Plot. #' @importFrom dplyr %>% @@ -30,6 +42,7 @@ #' @importFrom ggplot2 ggplot_add ggplot geom_segment aes_string arrow unit geom_text labs theme_classic theme element_blank #' element_text element_rect margin scale_y_continuous scale_color_manual scale_x_continuous coord_cartesian #' @importFrom patchwork wrap_plots +#' @importFrom grDevices grey #' @export #' #' @examples @@ -58,9 +71,24 @@ #' gtf_gr <- rtracklayer::import.gff(con = gtf_file, format = "gtf") #' #' # plot coverage and gene annotation -#' basic.coverage <- ggcoverage(data = track_df, range.position = "out") -#' basic.coverage + +#' basic_coverage <- ggcoverage(data = track_df, range.position = "out") +#' basic_coverage + #' geom_transcript(gtf.gr = gtf_gr, label.vjust = 1.5) +#' +#' # plot with custom style +#' basic_coverage + +#' geom_transcript( +#' gtf.gr = gtf_gr, +#' exon.size = 2.0, +#' arrow.size.im = 1.0, +#' arrow.length.im = 5, +#' arrow.type.im = "open", +#' color.by.im = "strand", +#' fill.color = c( +#' "-" = "darkblue", +#' "+" = "darkgreen" +#' ) +#' ) geom_transcript <- function(gtf.gr, gene.name = "HNRNPC", @@ -69,10 +97,16 @@ geom_transcript <- tx.size = 1, utr.size = 2, exon.size = 3, - arrow.size = 3, + arrow.angle = 35, + arrow.length = 1.5, + arrow.type = "open", + color.by = "strand", arrow.gap = NULL, arrow.num = 50, - color.by = "strand", + arrow.size.im = 0.5, + arrow.length.im = 1.5, + arrow.type.im = "closed", + color.by.im = NULL, fill.color = c( "-" = "cornflowerblue", "+" = "darkolivegreen3" @@ -81,33 +115,37 @@ geom_transcript <- label.vjust = 2, plot.space = 0.1, plot.height = 1) { - structure( - list( - gtf.gr = gtf.gr, - gene.name = gene.name, - overlap.tx.gap = overlap.tx.gap, - overlap.style = overlap.style, - tx.size = tx.size, - utr.size = utr.size, - exon.size = exon.size, - arrow.size = arrow.size, - arrow.gap = arrow.gap, - arrow.num = arrow.num, - color.by = color.by, - fill.color = fill.color, - label.size = label.size, - label.vjust = label.vjust, - plot.space = plot.space, - plot.height = plot.height - ), - class = "transcript" - ) - } + structure( + list( + gtf.gr = gtf.gr, + gene.name = gene.name, + overlap.tx.gap = overlap.tx.gap, + overlap.style = overlap.style, + tx.size = tx.size, + utr.size = utr.size, + exon.size = exon.size, + arrow.angle = arrow.angle, + arrow.length = arrow.length, + arrow.type = arrow.type, + color.by = color.by, + arrow.gap = arrow.gap, + arrow.num = arrow.num, + arrow.size.im = arrow.size.im, + arrow.length.im = arrow.length.im, + arrow.type.im = arrow.type.im, + color.by.im = color.by.im, + fill.color = fill.color, + label.size = label.size, + label.vjust = label.vjust, + plot.space = plot.space, + plot.height = plot.height + ), + class = "transcript" + ) +} #' @export ggplot_add.transcript <- function(object, plot, object_name) { - # get plot data - # track.data <- plot$layers[[1]]$data # get plot data, plot data should contain bins if ("patchwork" %in% class(plot)) { track.data <- plot[[1]]$layers[[1]]$data @@ -135,11 +173,17 @@ ggplot_add.transcript <- function(object, plot, object_name) { tx.size <- object$tx.size utr.size <- object$utr.size exon.size <- object$exon.size - arrow.size <- object$arrow.size + arrow.angle <- object$arrow.angle + arrow.length <- object$arrow.length + arrow.type <- object$arrow.type color.by <- object$color.by - fill.color <- object$fill.color arrow.gap <- object$arrow.gap arrow.num <- object$arrow.num + arrow.size.im <- object$arrow.size.im + arrow.length.im <- object$arrow.length.im + arrow.type.im <- object$arrow.type.im + color.by.im <- object$color.by.im + fill.color <- object$fill.color label.size <- object$label.size label.vjust <- object$label.vjust plot.space <- object$plot.space @@ -202,17 +246,17 @@ ggplot_add.transcript <- function(object, plot, object_name) { # create basic plot tx.plot <- ggplot() + - geom_arrows(gene.tx.df.tx, color.by, tx.size, arrow.size) + geom_arrows(gene.tx.df.tx, color.by, tx.size, arrow.length, arrow.angle, arrow.type) # deal with missing UTR if (is.null(gene.tx.df.utr)) { warning("No UTR detected in provided GTF!") } else { tx.plot <- tx.plot + - geom_arrows(gene.tx.df.utr, color.by, utr.size, arrow.size) + geom_arrows(gene.tx.df.utr, color.by, utr.size, arrow.length, arrow.angle, arrow.type) } tx.plot <- tx.plot + - geom_arrows(gene.tx.df.exon, color.by, exon.size, arrow.size) + + geom_arrows(gene.tx.df.exon, color.by, exon.size, arrow.length, arrow.angle, arrow.type) + theme_classic() if (is.null(arrow.gap)) { @@ -258,9 +302,22 @@ ggplot_add.transcript <- function(object, plot, object_name) { arrow.df$start <- as.numeric(arrow.df$start) arrow.df$end <- as.numeric(arrow.df$end) arrow.df$group <- as.numeric(arrow.df$group) + if (is.null(color.by.im)) { + color.by.im <- color.by + arrow.df[[color.by]] <- "im" + fill.color["im"] <- grDevices::grey(1, alpha = 0.5) + } else if (color.by.im %in% colnames(arrow.df)) { + stopifnot(unique(arrow.df[[color.by.im]]) %in% names(fill.color)) + } else { + stop(paste0( + "The selected variable '", + color.by.im , + "' for 'color.by.im' is not available in the data" + )) + } # add arrow tx.arrow.plot <- tx.plot + - geom_arrows(arrow.df, color.by, tx.size / 2, arrow.size, 35, TRUE) + geom_arrows(arrow.df, color.by.im, arrow.size.im, arrow.length.im, arrow.angle, arrow.type.im) # prepare label dataframe label.df <- data.frame( diff --git a/R/utils.R b/R/utils.R index 9a755cd..e298989 100644 --- a/R/utils.R +++ b/R/utils.R @@ -357,7 +357,6 @@ GetPlotData <- function(plot, layer.num = 1) { #' @param arrow_size size of the arrow #' @param arrow_angle angle of the arrow in degrees #' @param arrow_type type of arrow, either 'open' or 'closed' -#' @importFrom grDevices grey #' @return A geom layer for ggplot2 objects. #' @export geom_arrows <- diff --git a/man/geom_arrows.Rd b/man/geom_arrows.Rd index bb1db5d..0d357fe 100644 --- a/man/geom_arrows.Rd +++ b/man/geom_arrows.Rd @@ -4,14 +4,7 @@ \alias{geom_arrows} \title{Plot genomic features as arrows.} \usage{ -geom_arrows( - data, - color, - line_width, - arrow_size, - arrow_angle = 35, - intermittent = FALSE -) +geom_arrows(data, color, line_width, arrow_size, arrow_angle, arrow_type) } \arguments{ \item{data}{data frame describing arrow position, with columns @@ -23,10 +16,9 @@ start, end, group, and a custom 'color' column} \item{arrow_size}{size of the arrow} -\item{arrow_angle}{angle of the arrow. Default: 35°} +\item{arrow_angle}{angle of the arrow in degrees} -\item{intermittent}{If TRUE, arrows are only drawn intermittently in -half-transparent white color. Default: FALSE.} +\item{arrow_type}{type of arrow, either 'open' or 'closed'} } \value{ A geom layer for ggplot2 objects. diff --git a/man/geom_gene.Rd b/man/geom_gene.Rd index 6664129..79c5495 100644 --- a/man/geom_gene.Rd +++ b/man/geom_gene.Rd @@ -11,10 +11,16 @@ geom_gene( gene.size = 1, utr.size = 2, exon.size = 3, - arrow.size = 1.5, + arrow.angle = 35, + arrow.length = 1.5, + arrow.type = "open", + color.by = "strand", arrow.gap = NULL, arrow.num = 50, - color.by = "strand", + arrow.size.im = 0.5, + arrow.length.im = 1.5, + arrow.type.im = "closed", + color.by.im = NULL, fill.color = c(`-` = "cornflowerblue", `+` = "darkolivegreen3"), show.utr = FALSE, label.size = 3, @@ -24,28 +30,45 @@ geom_gene( ) } \arguments{ -\item{gtf.gr}{Granges object of GTF, created with \code{\link{import.gff}}. Default: NULL.} +\item{gtf.gr}{Granges object of GTF, created with \code{\link{import.gff}}. +Default: NULL.} \item{overlap.gene.gap}{The gap between gene groups. Default: 0.1.} -\item{overlap.style}{The style of gene groups, choose from loose (each gene occupies single line) -and tight (place non-overlap genes in one line). Default: loose.} +\item{overlap.style}{The style of gene groups, choose from loose (each gene +occupies single line) and tight (place non-overlap genes in one line). +Default: loose.} + +\item{gene.size}{Line width of genes. Default: 1.} + +\item{utr.size}{Line width of UTRs. Default: 2.} + +\item{exon.size}{Line width of exons. Default: 3.} -\item{gene.size}{The line size of gene. Default: 1.} +\item{arrow.angle}{Angle of the arrow head. Default 35°} -\item{utr.size}{The line size of UTR. Default: 2.} +\item{arrow.length}{Length of arrows. Default: 1.5} -\item{exon.size}{The line size of exon. Default: 3.} +\item{arrow.type}{Whether to draw "closed" or "open" (default) arrow heads} -\item{arrow.size}{The line size of arrow. Default: 1.5.} +\item{color.by}{Color the lines/arrows by variable. Default: "strand".} \item{arrow.gap}{The gap distance between intermittent arrows. Default: NULL. Set arrow.num and arrow.gap to NULL to suppress intermittent arrows.} -\item{arrow.num}{Total number of intermittent arrows over whole region. Default: 50. -Set arrow.num and arrow.gap to NULL to suppress intermittent arrows.} +\item{arrow.num}{Total number of intermittent arrows over whole region. +Default: 50. Set arrow.num and arrow.gap to NULL to suppress intermittent +arrows.} + +\item{arrow.size.im}{Line width of intermittent arrows. Default: 0.5} + +\item{arrow.length.im}{Length of intermittent arrows. Default: 1.5} -\item{color.by}{Color the line by. Default: strand.} +\item{arrow.type.im}{Whether to draw "closed" (default) or "open" heads for +intermittent arrows} + +\item{color.by.im}{Color the intermittent arrows by variable. Default: NULL +(draws semi-transparent, white arrows)} \item{fill.color}{Color used for \code{color.by}. Default: blue for - (minus strand), green for + (plus strand).} @@ -58,7 +81,8 @@ Default: blue for - (minus strand), green for + (plus strand).} \item{plot.space}{Top and bottom margin. Default: 0.1.} -\item{plot.height}{The relative height of gene annotation to coverage plot. Default: 0.2.} +\item{plot.height}{The relative height of gene annotation to coverage plot. +Default: 0.2.} } \value{ Plot. @@ -92,7 +116,22 @@ gtf_file <- system.file("extdata", "used_hg19.gtf", package = "ggcoverage") gtf_gr <- rtracklayer::import.gff(con = gtf_file, format = "gtf") # plot coverage and gene annotation -basic.coverage <- ggcoverage(data = track_df, range.position = "out") -basic.coverage + +basic_coverage <- ggcoverage(data = track_df, range.position = "out") +basic_coverage + geom_gene(gtf.gr = gtf_gr) + +# plot with custom style +basic_coverage + + geom_gene( + gtf.gr = gtf_gr, + exon.size = 2.0, + arrow.size.im = 1.0, + arrow.length.im = 5, + arrow.type.im = "open", + color.by.im = "strand", + fill.color = c( + "-" = "darkblue", + "+" = "darkgreen" + ) + ) } diff --git a/man/geom_transcript.Rd b/man/geom_transcript.Rd index a2fb109..f2d8be6 100644 --- a/man/geom_transcript.Rd +++ b/man/geom_transcript.Rd @@ -12,10 +12,16 @@ geom_transcript( tx.size = 1, utr.size = 2, exon.size = 3, - arrow.size = 3, + arrow.angle = 35, + arrow.length = 1.5, + arrow.type = "open", + color.by = "strand", arrow.gap = NULL, arrow.num = 50, - color.by = "strand", + arrow.size.im = 0.5, + arrow.length.im = 1.5, + arrow.type.im = "closed", + color.by.im = NULL, fill.color = c(`-` = "cornflowerblue", `+` = "darkolivegreen3"), label.size = 3, label.vjust = 2, @@ -24,33 +30,50 @@ geom_transcript( ) } \arguments{ -\item{gtf.gr}{Granges object of GTF, created with \code{\link{import.gff}}. Default: NULL.} +\item{gtf.gr}{Granges object of GTF, created with \code{\link{import.gff}}. +Default: NULL.} \item{gene.name}{Gene name of all transcripts. Default: HNRNPC.} \item{overlap.tx.gap}{The gap between transcript groups. Default: 0.1.} -\item{overlap.style}{The style of transcript groups, choose from loose (each transcript occupies single line) -and tight (place non-overlap transcripts in one line). Default: loose.} +\item{overlap.style}{The style of transcript groups, choose from loose (each +transcript occupies single line) and tight (place non-overlap transcripts +in one line). Default: loose.} + +\item{tx.size}{Line size of transcript. Default: 1.} -\item{tx.size}{The line size of transcript. Default: 1.} +\item{utr.size}{Line size of UTR. Default: 2.} -\item{utr.size}{The line size of UTR. Default: 2.} +\item{exon.size}{Line size of exon. Default: 3.} -\item{exon.size}{The line size of exon. Default: 3.} +\item{arrow.angle}{Angle of the arrow head. Default 35°} -\item{arrow.size}{The line size of arrow. Default: 1.5.} +\item{arrow.length}{Length of arrows. Default: 1.5} + +\item{arrow.type}{Whether to draw "closed" or "open" (default) arrow heads} + +\item{color.by}{Color the line by. Default: strand.} \item{arrow.gap}{The gap distance between intermittent arrows. Default: NULL. Set arrow.num and arrow.gap to NULL to suppress intermittent arrows.} -\item{arrow.num}{Total number of intermittent arrows over whole region. Default: 50. -Set arrow.num and arrow.gap to NULL to suppress intermittent arrows.} +\item{arrow.num}{Total number of intermittent arrows over whole region. +Default: 50. Set arrow.num and arrow.gap to NULL to suppress intermittent +arrows.} -\item{color.by}{Color the line by. Default: strand.} +\item{arrow.size.im}{Line width of intermittent arrows. Default: 0.5} + +\item{arrow.length.im}{Length of intermittent arrows. Default: 1.5} -\item{fill.color}{Color used for \code{color.by}. -Default: blue for - (minus strand), green for + (plus strand).} +\item{arrow.type.im}{Whether to draw "closed" (default) or "open" heads for +intermittent arrows} + +\item{color.by.im}{Color the intermittent arrows by variable. Default: NULL +(draws semi-transparent, white arrows)} + +\item{fill.color}{Color used for \code{color.by}. Default: blue for - (minus +strand), green for + (plus strand).} \item{label.size}{The size of transcript label. Default: 3.} @@ -58,7 +81,8 @@ Default: blue for - (minus strand), green for + (plus strand).} \item{plot.space}{Top and bottom margin. Default: 0.1.} -\item{plot.height}{The relative height of transcript annotation to coverage plot. Default: 0.2.} +\item{plot.height}{The relative height of transcript annotation to coverage +plot. Default: 0.2.} } \value{ Plot. @@ -92,7 +116,22 @@ gtf_file <- system.file("extdata", "used_hg19.gtf", package = "ggcoverage") gtf_gr <- rtracklayer::import.gff(con = gtf_file, format = "gtf") # plot coverage and gene annotation -basic.coverage <- ggcoverage(data = track_df, range.position = "out") -basic.coverage + +basic_coverage <- ggcoverage(data = track_df, range.position = "out") +basic_coverage + geom_transcript(gtf.gr = gtf_gr, label.vjust = 1.5) + +# plot with custom style +basic_coverage + + geom_transcript( + gtf.gr = gtf_gr, + exon.size = 2.0, + arrow.size.im = 1.0, + arrow.length.im = 5, + arrow.type.im = "open", + color.by.im = "strand", + fill.color = c( + "-" = "darkblue", + "+" = "darkgreen" + ) + ) } From e146f3db23161e280bb049687d028688e0558b21 Mon Sep 17 00:00:00 2001 From: jahn Date: Wed, 23 Oct 2024 14:55:57 +0200 Subject: [PATCH 5/6] fix: mark region boundaries, closes #39 --- R/geom_coverage.R | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/R/geom_coverage.R b/R/geom_coverage.R index 2556a43..2a54f7c 100644 --- a/R/geom_coverage.R +++ b/R/geom_coverage.R @@ -31,7 +31,7 @@ #' @importFrom stats as.formula #' @importFrom ggh4x facet_wrap2 strip_themed elem_list_rect #' @importFrom dplyr group_by summarise -#' @importFrom dplyr %>% +#' @importFrom dplyr %>% filter #' @importFrom ggrepel geom_text_repel #' @importFrom utils tail #' @@ -336,34 +336,24 @@ geom_coverage <- function(data, mapping = NULL, color = NULL, rect.color = NA, # add rect if (!is.null(mark.region)) { # get valid mark region - region.start <- data[1, "start"] - region.end <- data[nrow(data), "end"] - valid.region.list <- list() - for (r in 1:nrow(mark.region)) { - if (mark.region[r, "start"] <= region.end & mark.region[r, "end"] >= region.start) { - if (mark.region[r, "end"] >= region.end) { - mark.region[r, "end"] <- region.end - } - if (mark.region[r, "start"] <= region.start) { - mark.region[r, "start"] <- region.start - } - valid.region.list[[r]] <- mark.region[r, ] - } - } - valid.region.df <- do.call(rbind, valid.region.list) %>% as.data.frame() - colnames(valid.region.df) <- colnames(mark.region) - + region.start <- min(data$start) + region.end <- max(data$end) + mark.region <- dplyr::filter( + mark.region, + .data[["start"]] >= region.start, + .data[["end"]] <= region.end + ) region.mark <- geom_rect( - data = valid.region.df, + data = mark.region, aes_string(xmin = "start", xmax = "end", ymin = "-Inf", ymax = "Inf"), fill = mark.color, alpha = mark.alpha ) plot.ele <- append(plot.ele, region.mark) # add rect label if (show.mark.label) { - if ("label" %in% colnames(valid.region.df)) { + if ("label" %in% colnames(mark.region)) { # create mark region label - region.label <- valid.region.df + region.label <- mark.region if (plot.type == "facet") { region.label[, facet.key] <- facet.order[1] } From 1d9174f659ac27572c0e051faf2be7380d901a47 Mon Sep 17 00:00:00 2001 From: jahn Date: Fri, 3 Jan 2025 10:49:10 +0100 Subject: [PATCH 6/6] fix: facet order with region labels, closes #40 --- R/geom_coverage.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/geom_coverage.R b/R/geom_coverage.R index 2a54f7c..8203d11 100644 --- a/R/geom_coverage.R +++ b/R/geom_coverage.R @@ -355,7 +355,10 @@ geom_coverage <- function(data, mapping = NULL, color = NULL, rect.color = NA, # create mark region label region.label <- mark.region if (plot.type == "facet") { - region.label[, facet.key] <- facet.order[1] + region.label[, facet.key] <- factor( + rep(facet.order[1], nrow(mark.region)), + facet.order + ) } region.mark.label <- geom_text_repel( data = region.label,