R/plots.R

Defines functions nomatch_logo nomatch_matrix view_tomtom_nomatch view_tomtom_hits cowplot_title

Documented in view_tomtom_hits

#' Add title to complex plot with cowplot
#'
#' @param plot plot object to add title to
#' @param title text of title
#' @param ... passed to [cowplot::draw_text()]
#'
#' @return
#'
#' @noRd
#'
cowplot_title <- function(plot, title, ...){
  title <- cowplot::ggdraw() +
    cowplot::draw_text(title, ...)
  cowplot::plot_grid(plotlist = list(title, plot), ncol = 1, rel_heights = c(0.1, 1))
}

#' Compare top tomtom hits to original motif
#'
#' Although TomTom does a good job of matching unknown motifs to known motifs,
#' sometimes the top hit is not the correct assignment. It can be useful to
#' manually inspect the hits. This function provides a quick utility to compare
#' matches.
#'
#' This is intended to be a function used interactively and may not always be
#' the best tool for creating publication-quality figures. Results with matches
#' return ggseqlogo outputs which can be further manipulated using
#' [ggplot2::theme()] calls, but results containing no matches are static plots.
#'
#' @param results results data.frame from [runTomTom()]
#' @param top_n number of matched motifs to return in plot (default: "all")
#'
#' @return plot of input motif vs the top n number of tomtom matched motifs. If
#'   no match found, will plot "No Match". Note: the "No Match" plots are not
#'   amenable to ggplot theme() manipulations, while all others are.
#' @export
#'
#' @examples
#' results <- importTomTomXML(system.file("extdata", "tomtom.xml", package = "memes"))
#' # show top 3 hits
#' view_tomtom_hits(results, top_n = 3)
view_tomtom_hits <- function(results, top_n = "all"){
  # TODO: if tomtom is empty, return NONE as plot below??
  purrr::map2(results$motif, results$tomtom, ~{

    if (is.null(.y)) {
      return(view_tomtom_nomatch(.x))
    }

    # Needed to handle when tomtom discovers no hits for any motifs, in which case
    # tomtom is NA instead of NULL so the column is kept in the dataframe
    if (all(is.na(.y))) {
      return(view_tomtom_nomatch(.x))
    }

    if (top_n == "all") {select <- seq_len(length(.y$match_motif))}
    else if (is.numeric(top_n)) {select <- seq_len(top_n)}
    else {
      stop("n must be either 'all' or a number.")
    }
    
    if (length(select) > length(.y$match_motif)){
      # If top_n > number of hits, just show all hits
      select <- seq_len(length(.y$match_motif))
    }

    # TODO: check that motifList below doesn't have AsIs?
    #motifList <- c(list(.x), .y$match_motif[select]) %>%
    #edit_motif <- function(x){
    #  class(x) <- NULL
    #  x
    #}
    motifList <- c(list(.x), .y$match_motif[select]) %>%
      purrr::discard(is.null)

    universalmotif::view_motifs(motifList)
  })
}

#' Plot motif with "No Match" below.
#'
#' NOTE: this doesn't do any checking, and is not meant to be called directly by
#' user. Used internally in [view_tomtom_hits()]
#'
#' @param motif universalmotif
#' @param ... passed to [universalmotif::view_motifs()]
#'
#' @return
#'
#' @importFrom ggplot2 ggtitle theme element_text
#'
#' @noRd
view_tomtom_nomatch <- function(motif){
  # Thanks, Hadley: http://r-pkgs.had.co.nz/description.html
  if (!requireNamespace("ggplot2", quietly = TRUE)) {
    stop("Package \"ggplot2\" needed for this function to work. Please install it.",
         call. = FALSE)
  }
  motif_logo <- universalmotif::view_motifs(motif)

  motif_logo <- motif_logo +
    ggtitle(motif@name) +
    theme(plot.title = element_text(hjust = 0.5))

   <- ()

  cowplot::plot_grid(motif_logo, , ncol = 1, rel_heights = c(1,0.6))
}


#' Returns motif matrix of "NO MATCH"
#'
#' To use ggseqlogo to render the "NO MATCH" text,
#' I need to build a matrix with custom alphabet
#'
#' In matrix form NO MATCH is a matrix with diagonal all 1,
#' except at "space" position where all values are 1
#'
#' This is a very silly hack, and I love it.
#'
#' @return
#'
#' @noRd
nomatch_matrix <- function(){
  m <- matrix(0,
              nrow = 7,
              ncol = 7)
  diag(m) <- 1
  n <- c("N", "O", "M", "A", "T", "C", "H")
  rownames(m) <- c("N", "O", "M", "A", "T", "C", "H")
  no <- m[,c(1,2)]
  match <- m[,c(3:7)]
  space <- matrix(1, nrow = 7, ncol = 1)
  mat <- cbind(no, space, match)

  return(mat)
}

#' Returns "NO MATCH" ggseqlogo
#'
#' @return

#' @importFrom ggplot2 element_text
#' @importFrom ggseqlogo make_col_scheme ggseqlogo
#' @noRd
 <- function(){
  mat <- nomatch_matrix()
  alph <- rownames(mat)
  col <- ggseqlogo::make_col_scheme(chars = alph, cols = rep("#333333", length(alph)))

  ggseqlogo::ggseqlogo(mat,
                       namespace = alph,
                       method = "bits",
                       col_scheme = col) +
    ggplot2::theme(axis.text = element_text(color = "white"),
                   axis.text.x = element_text(color = "white"),
                   axis.text.y = element_text(color = "white"),
                   axis.title = element_text(color = "white"))
}
snystrom/memes documentation built on April 29, 2024, 5:37 p.m.