\name{stackStringsFromBam}

\alias{stackStringsFromGAlignments}
\alias{stackStringsFromBam}
\alias{alphabetFrequencyFromBam}


\title{Stack the read sequences stored in a GAlignments object or a BAM file}

\description{
  \code{stackStringsFromGAlignments} stacks the read sequences (or
  their quality strings) stored in a \link{GAlignments} object over
  a user-specified region.

  \code{stackStringsFromBam} stacks the read sequences (or their quality
  strings) stored in a BAM file over a user-specified region.

  \code{alphabetFrequencyFromBam} computes the alphabet frequency of the
  reads over a user-specified region.

  All these functions take into account the CIGAR of each read to \emph{lay}
  the read sequence (or its quality string) alongside the reference space.
  This step ensures that each nucleotide in a read is associated with the
  correct position on the reference sequence.
}

\usage{
stackStringsFromGAlignments(x, region, what="seq",
                    D.letter="-", N.letter=".",
                    Lpadding.letter="+",
                    Rpadding.letter="+")

stackStringsFromBam(file, index=file, param,
                    what="seq", use.names=FALSE,
                    D.letter="-", N.letter=".",
                    Lpadding.letter="+", Rpadding.letter="+")

alphabetFrequencyFromBam(file, index=file, param, what="seq", ...)
}

\arguments{
  \item{x}{
    A \link{GAlignments} object with the read sequences in the \code{"seq"}
    metadata column (if \code{what} is set to \code{"seq"}), or with the
    the read quality strings in the \code{"qual"} metadata column (if
    \code{what} is set to \code{"qual"}).
    Such an object is typically obtained by specifying
    \code{param=\link[Rsamtools]{ScanBamParam}(what=c("seq", "qual"))}
    when reading a BAM file with calling \code{\link{readGAlignments}()}.
  }
  \item{region}{
    A \link[GenomicRanges]{GRanges} object with exactly 1 genomic range.
    The read sequences (or read quality strings) will be stacked over
    that region.
  }
  \item{what}{
    A single string. Either \code{"seq"} or \code{"qual"}. If \code{"seq"}
    (the default), the read sequences will be stacked. If \code{"qual"},
    the read quality strings will be stacked.
  }
  \item{D.letter, N.letter}{
    A single letter used as a filler for injections. The 2 arguments are
    passed down to the \code{\link{sequenceLayer}} function.
    See \code{?\link{sequenceLayer}} for more details.
  }
  \item{Lpadding.letter, Rpadding.letter}{
    A single letter to use for padding the sequences on the left, and another
    one to use for padding on the right. The 2 arguments are passed down to
    the \code{\link[Biostrings]{stackStrings}} function defined in the
    \pkg{Biostrings} package.
    See \code{?\link[Biostrings]{stackStrings}} in the \pkg{Biostrings}
    package for more details.
  }
  \item{file, index}{
    The path to the BAM file containing the reads, and to its index file,
    respectively. The latter is given \emph{without} the '.bai'
    extension. See \code{\link{scanBam}} for more information.
  }
  \item{param}{
    A \link{ScanBamParam} object containing exactly 1 genomic region
    (i.e. \code{unlist(bamWhich(param))} must have length 1).
    Alternatively, \code{param} can be a \link[GenomicRanges]{GRanges} or
    \link[IRanges]{IntegerRangesList} object containing exactly 1 genomic
    region (the strand will be ignored in case of a
    \link[GenomicRanges]{GRanges} object), or a character string specifying
    a single genomic region (in the \code{"chr14:5201-5300"} format).
  }
  \item{use.names}{
    Use the query template names (QNAME field) as the names of the returned
    object? If not (the default), then the returned object has no names.
  }
  \item{...}{
    Further arguments to be passed to \link[Biostrings]{alphabetFrequency}.
  }
}

\details{
  \code{stackStringsFromGAlignments} performs the 3 following steps:
  \enumerate{
    \item Subset \link{GAlignments} object \code{x} to keep only the
          alignments that overlap with the specified region.

    \item Lay the sequences in \code{x} alongside the reference space,
          using their CIGARs. This is done with the
          \code{\link{sequenceLayer}} function.

    \item Stack them on the specified region. This is done with the
          \code{\link[Biostrings]{stackStrings}} function defined in the
          \pkg{Biostrings} package.
  }

  \code{stackStringsFromBam} performs the 3 following steps:
  \enumerate{
    \item Load the read sequences (or their quality strings) from the BAM
          file. Only the read sequences that overlap with the specified region
          are loaded. This is done with the \code{\link{readGAlignments}}
          function. Note that if the file contains paired-end reads, the
          pairing is ignored.

    \item Same as \code{stackStringsFromGAlignments}.

    \item Same as \code{stackStringsFromGAlignments}.
  }

  \code{alphabetFrequencyFromBam} also performs steps 1. and 2. but,
  instead of stacking the sequences at step 3., it computes the nucleotide
  frequencies for each genomic position in the specified region.
}

\value{
  For \code{stackStringsFromBam}: A rectangular (i.e. constant-width)
  \link[Biostrings]{DNAStringSet} object (if \code{what} is \code{"seq"})
  or \link[Biostrings]{BStringSet} object (if \code{what} is \code{"qual"}).

  For \code{alphabetFrequencyFromBam}: By default a matrix like one returned
  by \code{\link[Biostrings]{alphabetFrequency}}. The matrix has 1 row per
  nucleotide position in the specified region.
}

\note{
  TWO IMPORTANT CAVEATS ABOUT \code{stackStringsFromGAlignments} AND
  \code{stackStringsFromBam}:

  Specifying a big genomic region, say >= 100000 bp, can require a lot of
  memory (especially with high coverage reads) so is not recommended.
  See the \code{\link{pileLettersAt}} function for piling the read letters
  on top of a set of genomic positions, which is more flexible and more
  memory efficient.

  Paired-end reads are treated as single-end reads (i.e. they're not paired).
}

\author{Hervé Pagès}

\seealso{
  \itemize{
    \item The \code{\link{pileLettersAt}} function for piling the letters
          of a set of aligned reads on top of a set of genomic positions.

    \item The \code{\link{readGAlignments}} function for loading read
          sequences (or their quality strings) from a BAM file (via a
          \link{GAlignments} object).

    \item The \code{\link{sequenceLayer}} function for laying read sequences
          alongside the reference space, using their CIGARs.

    \item The \code{\link[Biostrings]{stackStrings}} function in the
          \pkg{Biostrings} package for stacking an arbitrary
          \link[Biostrings]{XStringSet} object.

    \item The \code{\link[Biostrings]{alphabetFrequency}} function in the
          \pkg{Biostrings} package.

    \item The SAMtools mpileup command available at
          \url{http://samtools.sourceforge.net/} as part of the
          SAMtools project.
  }
}

\examples{
## ---------------------------------------------------------------------
## A. EXAMPLE WITH TOY DATA
## ---------------------------------------------------------------------

bamfile1 <- BamFile(system.file("extdata", "ex1.bam", package="Rsamtools"))

region1 <- GRanges("seq1", IRanges(1, 60))  # region of interest

## Stack the read sequences directly from the BAM file:
stackStringsFromBam(bamfile1, param=region1, use.names=TRUE)

## or, alternatively, from a GAlignments object:
gal1 <- readGAlignments(bamfile1, param=ScanBamParam(what="seq"),
                        use.names=TRUE)
stackStringsFromGAlignments(gal1, region1)

## Compute the "consensus matrix" (1 column per nucleotide position
## in the region of interest):
af <- alphabetFrequencyFromBam(bamfile1, param=region1, baseOnly=TRUE)
cm1a <- t(af[ , DNA_BASES])
cm1a

## Stack their quality strings:
stackStringsFromBam(bamfile1, param=region1, what="qual")

## Control the number of reads to display:
options(showHeadLines=18)
options(showTailLines=6)
stackStringsFromBam(bamfile1, param=GRanges("seq1", IRanges(61, 120)))

stacked_qseq <- stackStringsFromBam(bamfile1, param="seq2:1509-1519")
stacked_qseq  # deletion in read 13
af <- alphabetFrequencyFromBam(bamfile1, param="seq2:1509-1519",
                                baseOnly=TRUE)
cm1b <- t(af[ , DNA_BASES])  # consensus matrix
cm1b

## Sanity check:
stopifnot(identical(consensusMatrix(stacked_qseq)[DNA_BASES, ], cm1b))

stackStringsFromBam(bamfile1, param="seq2:1509-1519", what="qual")

## ---------------------------------------------------------------------
## B. EXAMPLE WITH REAL DATA
## ---------------------------------------------------------------------

library(RNAseqData.HNRNPC.bam.chr14)
bamfile2 <- BamFile(RNAseqData.HNRNPC.bam.chr14_BAMFILES[1])

## Region of interest:
region2 <- GRanges("chr14", IRanges(19650095, 19650159))

## Stack the read sequences directly from the BAM file:
stackStringsFromBam(bamfile2, param=region2)

## or, alternatively, from a GAlignments object:
gal2 <- readGAlignments(bamfile2, param=ScanBamParam(what="seq"))
stackStringsFromGAlignments(gal2, region2)

af <- alphabetFrequencyFromBam(bamfile2, param=region2, baseOnly=TRUE)
cm2 <- t(af[ , DNA_BASES])  # consensus matrix
cm2

## ---------------------------------------------------------------------
## C. COMPUTE READ CONSENSUS SEQUENCE FOR REGION OF INTEREST
## ---------------------------------------------------------------------

## Let's write our own little naive function to go from consensus matrix
## to consensus sequence. For each nucleotide position in the region of
## interest (i.e. each column in the matrix), we select the letter with
## highest frequency. We also use special letter "*" at positions where
## there is a tie, and special letter "." at positions where all the
## frequencies are 0 (a particular type of tie):
cm_to_cs <- function(cm)
{
    stopifnot(is.matrix(cm))
    nr <- nrow(cm)
    rnames <- rownames(cm)
    stopifnot(!is.null(rnames) && all(nchar(rnames) == 1L))
    selection <- apply(cm, 2,
                       function(x) {
                         i <- which.max(x)
                         if (x[i] == 0L)
                           return(nr + 1L)
                         if (sum(x == x[i]) != 1L)
                           return(nr + 2L)
                         i
                       })
    paste0(c(rnames, ".", "*")[selection], collapse="")
}

cm_to_cs(cm1a)
cm_to_cs(cm1b)
cm_to_cs(cm2)

## Note that the consensus sequences we obtain are relative to the
## plus strand of the reference sequence.
}

\keyword{methods}
\keyword{manip}
