% NOTE -- ONLY EDIT THE .Rnw FILE!!!  The .tex file is
% likely to be overwritten.
% \VignetteIndexEntry{SNPchip Vignette}
% \VignetteKeywords{copy number, genotype, SNP}
%\VignettePackage{SNPchip}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass[12pt]{article}

\usepackage{amsmath,pstricks,fullpage}
\usepackage[authoryear,round]{natbib}
\usepackage{hyperref}
\usepackage{setspace}
\parindent 0in  % Left justify
\newcommand{\scscst}{\scriptscriptstyle}
\newcommand{\scst}{\scriptstyle}

\newcommand{\Rpackage}[1]{\textit{#1}}
\newcommand{\Rfunction}[1]{\texttt{#1}}
\newcommand{\Robject}[1]{\texttt{#1}}


\title{Tools for high throughput SNP chip data}
\author{Robert Scharpf, Jonathan Pevsner, Jason Ting, and Ingo Ruczinski}

\begin{document}

\maketitle

\section*{Introduction}

\Rpackage{SNPchip} defines classes and methods useful for organizing
high throughput genomic data.  The classes defined here extend the
\Robject{eSet} class in \Rpackage{Biobase}, utilizing the existing
Bioconductor infrastructure for organizing high dimensional genomic
data.  This provides a foundation upon which statistical and
visualization tools can be further developed.

\section{Simple Usage}

We illustrate the structure of the class \Robject{AnnotatedSnpSet}
with a small dataset provided with the package.

<<exampleData>>=
library(SNPchip)
data(annSnpset)
annSnpset
@ 

\Robject{annSnpset} is an instance of the \Robject{AnnotatedSnpSet}
class.  Here, the assayData slot in \Robject{AnnotatedSnpSet} contains
\Sexpr{nrow(annSnpset)} SNPs with estimates of copy number and genotype
calls, as well as a corresponding confidence score.  Typically, such
an object would contain 100,000 - 500,000 estimates of genotype calls
and copy number.  We illustrate in Section \ref{classes} how to create
an instance of \Robject{AnnotatedSnpSet} from probe-level summaries of
SNP chip data.  In addition to estimates of genotype call and copy
number, the \Robject{annSnpset} contains both chromosome-level
annotation, as well as SNP-level annotation.  The chromosome-level
annotation includes the centromere start and stop sites and chromosome
size (in number of base pairs), and could be extended to include
location of cytobands, or any other feature of a chromosome.

<<chromosomeAnnotation>>=
data(chromosomeAnnotation)
chromosomeAnnotation[1:5, ]
@ 

The method \Robject{getSnpAnnotation} retrieves SNP-level annotation
from annotation packages maintained at Bioconductor.  A more rich
annotation is in development.  The appropriate pd.mapping library
needs to be loaded for this method to work.

<<annotationSlot, eval=FALSE>>=
annotation(annSnpset)
library("pd.mapping50k.xba240")
@ 

<<getSnpAnnotation, eval=FALSE>>=
featureData(annSnpset) <- getSnpAnnotation(annSnpset)
@ 

%As annotation packages for SNP chips become more fully developed and
%supported, the use of static tables for SNP annotation will be
%deprecated.
%
A genome-wide view of copy number and genotype calls versus physical
position can be made using \Rfunction{plotSnp}.  Here, we plot
chromosomes 1-22 and X (the integer 23 is used to represent X) of
samples 1 - 4 in the object \Robject{annSnpset}:

<<plotSnp, fig=TRUE, width=9, height=4>>=
plotSnp(annSnpset, chromosomes=c(1:22, "X"), 
        samples=1:4, width.right=10, cex.axis=1, lab=c(3, 3, 5),
        cex.lab=1.2, cex.legend=c(1, 1.2))
@ 

The copy number estimates have been centered to have mean zero -- a
centered copy number of 0 corresponds to a copy number of two. The
default plot layout generally works well, but can be adjusted through
the arguments mar, oma, and width.right in \Robject{plotSnp}.  The
latter argument specifies how much room to allow for the summary panel
relative to the size of the smallest chromosome plotted.  For
instance, if plotting chromosomes 1-22 and X, width.right set to 15
allows a plotting region for the summary paenl that is 15 times larger
than chromosome 21. A more focused view of chromosomes 1, 7, 16, 19,
and X of sample 2 could be obtained by

<<plotSnpChromosomes, fig=TRUE, width=9, height=4>>=
plotSnp(annSnpset, c(1, 7, 16, 19, "X"), c(2, 5), 
        cex=c(1, 1, 1), pch=c(20, 21, 20), bg=c("royalblue", "white", "royalblue"),
        bty="o", width.right=1.5, cex.axis=1.2, cex.lab=1.5, cex.legend=c(1.2, 1.2),
        xaxs="r")
@ 

A plot of just the p-arm in sample 2 of chromosome 1:
<<plotSnpChromosomes, fig=TRUE, width=9, height=4>>=
chr1 <- annSnpset[chromosome(annSnpset) == "1", ]
start <- min(position(chr1)[position(chr1) > chromosomeAnnotation["1", 1]], na.rm=TRUE)
plotSnp(chr1[position(chr1) > start, ], 1, 2, 
        xlim=range(position(chr1)[position(chr1) > start], na.rm=TRUE),
        cex=c(1, 1, 1), pch=c(20, 20, 20), bg=c("royalblue", "red", "royalblue"),
        bty="o", width.right=.3, cex.axis=1.2, cex.lab=1.5, cex.legend=c(1.2, 1.2))
@ 

Cytobands can be added to graphs as follows:
%\Rfunction{plotCytoband} is useful for visualization of  chromosome
%in sample 5.  The following code chunk illustrates how easy it is to
%subset 1 chromosome and one sample, and then plot the resulting
%\Robject{AnnotatedSnpSet} object.  Because an additional plotting
%region is needed to plot the cytoband, we specify two rows in the
%\Rfunction{layout}.

<<plotChromosomeExample, fig=TRUE, width=9, height=4>>=
data(annSnpset)
data(cytoband)
chr1 <- annSnpset[chromosome(annSnpset) == "1", ]
plotSnp(chr1, 1, 5, oma=c(6, 4, 0, 3), cex=c(3,3,3),
        cex.axis=1.2, cex.legend=c(1.2, 1.2), addCytoband=TRUE,
        legend.location=c("topleft", "bottomleft"),
        height.cytoband=0.2, width.right=0.2, bty="o", cex.lab=1.5, ncol=1, adj=0)
@ 

<<partialCytoband, fig=TRUE, width=9, height=4>>=
plotSnp(chr1[position(chr1) > start, ], 1, 2, 
        xlim=range(position(chr1)[position(chr1) > start], na.rm=TRUE),
        cex=c(1, 1, 1), pch=c(20, 20, 20), bg=c("royalblue", "red", "royalblue"),
        bty="l", width.right=.3, cex.axis=1.2, cex.lab=1.5, cex.legend=c(1.2, 1.2),
        addCytoband=TRUE)
@ 

\section{Available annotation}

Bioconductor annotation packages for high throughput SNP platforms are
under development.  Column headers for the annotation that is
currently available for each SNP is here:

<<loadAnnotation, eval=FALSE>>=
colnames(fData(annSnpset))
@ 
We store SNP-level attributes in the featureData slot.  The command
<<addFeatureData, eval=FALSE>>=
featureData(obj) <- getSnpAnnotation(annSnpset)
@ 

automatically loads the appropriate annotation package according to
the annotation slot.  The Bioconductor annotation packages must first
be downloaded.

Alternatively, one may obtain the NetAffx annotation saved as an R object here:
<<netAffxAnnotation, eval=FALSE>>=
try(load(url("http://biostat.jhsph.edu/~iruczins/publications/sm/2006.scharpf.bioinfo/mapping/mapping10k.rda")))
colnames(mapping10k$annotation)
@ 

%Accessors have not been written for all the available annotation.
%(afterall, annotation packages will be available for this purpose in
%the near future), but here is how one could retrieve the flanking
%sequence for the 1st 10 SNPs in the R object \Robject{obj}

<<flankingSeq, eval=FALSE, echo=FALSE>>=
pData(featureData(obj))$Flank[1:10]
@ 

For more detailed annotation on specific SNPs, see the R package
RSNPper available at Bioconductor.


\section{High throughput SNP classes}
\label{classes}

All that is needed to create an instance of
\Robject{AnnotatedSnpCallSet} or \Robject{AnnotatedSnpCopyNumberSet}is
a matrix of genotype calls and copy number, respectively, and their
corresponding confidence scores.  If estimates of both copy number and
genotype calls are available, we can create an
\Robject{AnnotatedSnpSet} that inherits methods from both
\Robject{AnnotatedSnpCopyNumberSet} and \Robject{AnnotatedSnpCallSet}.
In this way, \Rpackage{SNPchip} is completely independent of the
pre-processing method used to produce probe-level summaries.  To
illustrate, the following code chunk loads a list of matrices obtained
from normal subjects in the Hapmap project and pre-processed by CRLMM
(B. Carvalho {\it et.~al}, {\it Biostatistics}, in press).  Only every
10th SNP from the Xba 50k chip is included in the matrices.

<<loadData>>=
data(hapmap)
str(hapmap)
@ 

Each matrix in the list contains probeset summaries (rows) by column
(samples).  Currently, we only provide annotation for the Affymetrix
SNP chips and so the rownames of the matrices should be Affymetrix
probeset id's.  For purposes of visualization, an identifier from any
technology could be used so long as the SNP-level annotation stored in
the featureData slot is a data.frame with columns
\texttt{Physical.Position} and \texttt{chromosome}.

<<affyids>>=
rownames(hapmap$calls)[1:5]
@ 

<<SnpSetclass>>=
rowSds <- function(x) apply(x, 1, "sd")
colSds <- function(x) apply(x, 2, "sd")
nr <- nrow(hapmap$copyNumber)
nc <- ncol(hapmap$copyNumber)
snpset <- new("AnnotatedSnpSet", 
              calls=hapmap$calls,
              callsConfidence=hapmap$callsConfidence,
              copyNumber=hapmap$copyNumber, 
              cnConfidence=matrix(NA, nr, nc),
              annotation="pd.mapping50k.xba240",
              chromosomeAnnotation=chromosomeAnnotation)
@ 

%If you have an internet connection, you can add the SNP-level annotation:
<<addFeatureData, eval=FALSE>>=
library("pd.mapping50k.xba240")
annSnpset <- getSnpAnnotation(snpset)
@ 

This may take several minutes depending on your internet connection.
To do this manually using NetAffx annotation files, the annotation
files can be downloaded from
\texttt{http://biostat.jhsph.edu/~iruczins/publications/sm/2006.scharpf.bioinfo/mapping/}.
This object should be converted to an object of class
\Rfunction{AnnotatedDataFrame} with SNPs in the same order as in the
\Rfunction{AnnotatedSnpSet} object.  To download a static data.frame
of the NetAffx annotation for the 50k Xba SNP chip, execute the
following command:

<<retrieve100kAnnotation, eval=FALSE>>=
try(load(url("http://biostat.jhsph.edu/~iruczins/publications/sm/2006.scharpf.bioinfo/mapping/mapping50kXba240.rda")))
@

\Rfunction{data.frame}s for the 50k Hind and the 250k Nsp and Sty chips are also available:

<<otherAnnotation, eval=FALSE>>=
try(load(url("http://biostat.jhsph.edu/~iruczins/publications/sm/2006.scharpf.bioinfo/mapping/mapping50kHind240.rda")))
try(load(url("http://biostat.jhsph.edu/~iruczins/publications/sm/2006.scharpf.bioinfo/mapping/mapping250kNsp.rda")))
try(load(url("http://biostat.jhsph.edu/~iruczins/publications/sm/2006.scharpf.bioinfo/mapping/mapping250kSty.rda")))
@

Below, we illustrate how one might convert output from Affymetrix CNAT
software to an object of class \Robject{AnnotatedSnpSet}.  For
instance, any one of the .txt files for the CEPH trios provided at the
Affymetrix website can be converted as follows

<<cnatData,eval=FALSE>>=
cnat <- read.table("100k_trios.Hind.1.txt", as.is=TRUE, sep="\t", header=TRUE, row.names=1, skip=0)
cn <- as.matrix(cnat[, grep("SPA_CN", colnames(x))])
calls <- cnat[,grep("_Call", colnames(x))]
calls[calls == "AA"] <- 1
calls[calls == "AB"] <- 2
calls[calls == "BB"] <- 3
calls[calls == "NoCall"] <- 4
calls <- matrix(as.integer(as.matrix(calls)), nc = dim(calls)[2], byrow=FALSE)
cnConfidence <- as.matrix(cnat[, grep("SPA_pVal", colnames(cnat))])
callsConfidence <- as.matrix(cnat[, grep("LOH", colnames(cnat))])
rownames(calls) <- rownames(cn) <- rownames(cnConfidence) <- rownames(callsConfidence) <- x$Probe.Set
colnames(cn) <- colnames(calls) <- colnames(callsConfidence) <- colnames(cnConfidence) <- substr(colnames(cn), 1, 7)
trios <- new("AnnotatedSnpSet", 
             calls=calls, 
             copyNumber=copyNumber,
             callsConfidence=callsConfidence,
             cnConfidence=cnConfidence,
             annotation="pd.mapping50k.hind240",
             chromosomeAnnotation=chromosomeAnnotation)

library("pd.mapping50k.hind240")
featureData(trios) <- getSnpAnnotation(trios)
@ 

The SNP-level annotation for the trios data can be retrieved as
described previously.

<<snpcopynumberset, figure=TRUE, width=9, height=4>>=
cnset <- as(annSnpset, "AnnotatedSnpCopyNumberSet")
plotSnp(object=cnset, chromosomes=1:10, samples=1:3, cex=5, pch=".", 
        width.right=3, cex.axis=1, 
        cex.legend=c(1.2,1.2), legend=c(TRUE, FALSE))
@ 

\section{Descriptive and statistical summaries}

Descriptive statistics for copy number and genotype calls are provided
with the \Rfunction{summary} method. For each chromosome in the
\Robject{AnnotatedSnpSet}, \Rfunction{summary} calculates the average
and standard deviation of the copy number estimates, as well as the \%
homozygous and heterozygous calls.  In addition, summary calculates
the average copy number, standard deviation, \% homozygous and
heterozygous across all autosomes in the \Robject{AnnotatedSnpSet}.
The dimensions of the four matrices are S x C + 1, where S is the
number of samples and C is the number of chromosomes in the
\Robject{AnnotatedSnpSet}.
<<summary>>=
x <- summary(annSnpset, digits=1)
str(x)
##Would be useful to have a plot method for the summary object
@ 

Boxplot by chromosome:
<<summaryPlot, fig=TRUE, width=9, height=4>>=
par(mfrow=c(1,1), mar=c(4, 4, 3, 1), las=1)
boxplot(split(copyNumber(annSnpset[, 1]), chromosome(annSnpset)), 
        ylab="copy number", main=sampleNames(annSnpset)[1])
@ 

\subsection*{Smoothing example}

The basic unit for all of the above visualization tools and summary
methods is an \Robject{AnnotatedSnpSet} of a single chromosome.  For
instance, \Rfunction{plotSnp} converts the \Robject{AnnotatedSnpSet}
to a list of \Robject{AnnotatedSnpSet}, where each element in the list
is an \Robject{AnnotatedSnpSet} of a single chromosome.  In the code
below, we are interested in a quick method for smoothing copy number
estimates for each chromosome and apply a loess smoother to each
chromosome.  The following code chunk first assigns heterozygous calls
to the integer 1 and homozygous calls to the integer zero.  In this
way, regions of deletions will have homozygous calls of zero. We
simulated a deletion of 50 consecutive SNPs and then converted the
\Robject{AnnotatedSnpSet} to a list where each element in the list is
an \Robject{AnnotatedSnpSet} for a particular chromosome.

<<annotatedSnpSetList>>=
sim1 <- annSnpset[chromosome(annSnpset) %in% 1:5, 1:3]
sim1

##simulate a deletion on chromosome 1 in first sample
tmp <- sim1[chromosome(sim1) == "1", ]
tmp <- tmp[order(position(tmp)), ]
snps <- featureNames(tmp)[101:150]

ids <- match(snps, featureNames(sim1))
copyNumber(sim1)[ids, 1] <- copyNumber(sim1)[ids, 1] - 1
calls(sim1)[ids, 1] <- 1
@ 

<<smoothing, echo=TRUE>>=
##convert homozygous to 0 and heterozygous to 1
sim2 <- sim1
calls(sim2)[calls(sim2) == 1 | calls(sim2) == 3] <- 0
calls(sim2)[calls(sim2) == 2] <- 1
sim.list <- split(sim2, chromosome(sim2))
sim.list[[1]]
smoothChromosome <- function(obj, span){ 
  loessX <-  function(X, location, span){
    fit <- loess(X ~ location, span = span)$fitted 
    return(fit) 
  }
  ##Order by physical position before smoothing
  obj <- obj[order(position(obj)), ]
  cn.smooth <- apply(copyNumber(obj), 2, loessX, position(obj),
                     span = span)
  rownames(cn.smooth) <- featureNames(obj)
  call.smooth <- apply(calls(obj), 2, loessX,
                       location = position(obj), span = span)
  rownames(call.smooth) <- featureNames(obj)
  copyNumber(obj) <- cn.smooth
  calls(obj) <- call.smooth
  obj
}
smoothList <- lapply(sim.list, smoothChromosome, span=1/10)
smoothSet <- unsplitS4(smoothList, featureData(sim2))
@ 

Or equivalently,
<<smoothSnp>>=
##Insert a deletion in chromosome 1
smoothSet2 <- smoothSnp(sim1, 1:5, 1:3, span=1/10)
identical(copyNumber(smoothSet2), copyNumber(smoothSet))
identical(calls(smoothSet2), calls(smoothSet))
@ 

A plot of the smoothed calls versus copynumber can be used to
visualize the deletion and deciding on a threshold for calling
deletions.
<<plotSmooth,fig=TRUE, height=4, width=9>>=
par(las=1, mar=c(5, 4, 0.5, 0.5), oma=rep(0, 4))
plot(calls(smoothSet2), copyNumber(smoothSet2), 
     ylim=range(copyNumber(smoothSet2)), pch=".", cex=3,
     xlab="% heterozygous calls",
     ylab="smooth copy number", xaxt="n", xlim=c(-0.05, 30/70+.2))
axis(1, at=pretty(calls(smoothSet2)), labels=pretty(calls(smoothSet2)))
highlight <- calls(smoothSet2) <= 0.1 & copyNumber(smoothSet2) <= 1.5
points(calls(smoothSet2)[highlight], copyNumber(smoothSet2)[highlight],
       pch=20, col="royalblue", bg="white")
@ 

<<plot2, fig=TRUE, width=9, height=4>>=
copyNumber(sim1) <- copyNumber(sim1)+2
plotSnp(sim1, 1, 1, log="", width.right=0.5, cex.legend=c(1.2, 1.2), 
        legend.panel=c(TRUE, FALSE), cex=c(1, 1, 1), pch=rep(20,3),
        legend.location=c("topright", "bottomright"), addCytoband=TRUE)
##Highlight SNPs in deletion
##points(position(sim1)[ids], copyNumber(sim1)[ids, 1], pch=21, col="royalblue", bg="white")
@ 


\section{Integration with other Bioconductor packages}

To retreive additional annotation on the known SNP's in the region of
this simulated deletion, we could use the \Rpackage{RSNPper}.  The
installation instructions for \Rpackage{RSNPper} is available at
Bioconductor. 

<<nsnpsInRegion, eval=FALSE>>=
library(RSNPper)
(dbId <- dbSnpId(annSnpset)[snps[2] == featureNames(annSnpset)])
dbId <- strsplit(dbId, "rs")[[1]][2]
print(SNPinfo(dbId))
@ 

\end{document}
