plyranges icon indicating copy to clipboard operation
plyranges copied to clipboard

flip_strand() function?

Open eggrandio opened this issue 2 years ago • 1 comments

Hello,

I was wondering if it would be useful to add a flip_strand() function to switch strand from "+" to "-" and viceversa, leaving "*" if unstranded. I am not aware of a function that does this in GenomicRanges.

I adapted the flip_strand_info() function from TranscriptomeReconstructoR. It does not cover the "*" case.

Probably there is a more elegant/efficient way of doing this:

#' Flip strand orientation of a GenomicRanges object
#'
#' @param gr \code{GRanges} or \code{GRangesList} object
#' @return Object of the same class as input with positive and negative strands flipped
#' @export
flip_strand <- function(gr) {
  stopifnot(class(gr) == "GRanges" || BiocGenerics::grepl("GRangesList", class(gr)))
  if (class(gr) == "GRanges") {
    BiocGenerics::strand(gr) <- ifelse(BiocGenerics::strand(gr) == "*", "*",
                                       ifelse(BiocGenerics::strand(gr) == "+", "-", "+"))
  } else {
    unl <- BiocGenerics::unlist(gr, use.names = FALSE)
    BiocGenerics::strand(unl) <- ifelse(BiocGenerics::strand(unl) == "*", "*",
                                        ifelse(BiocGenerics::strand(unl) == "+", "-", "+"))
    gr <- BiocGenerics::relist(unl, gr)
  }
  return(gr)
}

eggrandio avatar Feb 14 '23 16:02 eggrandio

This sounds like a useful feature. I've certainly hand-rolled this a few times.

Two use-cases come to mind for me:

  1. Wanting to flip an entire granges object, like flip_strand(my_features)
  2. Wanting to flip the strand of a feature inside of a mutate conditional on some other element like:
my_features %>%
   mutate(strand = ifelse(some_condition, flip_strand(strand), strand))

I think 1. is solved by an approach like you posted above (for plyranges we'd want to change the implementation to use method dispatch).

I am not certain, but I think 2. might be a bit more fiddly because I think it needs some plyranges::set_strand() stuff in order to actually change the value in a mutate, but I might be wrong. If that's the case it could be that flip_strand could work by taking a conditional function argument:

# Flips everything
my_features %>%
  flip_strand()

# Flip only features with a score > 10
my_features %>%
  flip_strand(~ .x$score > 10)

snystrom avatar Feb 17 '23 14:02 snystrom