---
title: "Using SynExtend"
author: "Nicholas Cooley"
date: "`r Sys.Date()`"
output:
  BiocStyle::html_document
vignette: >
  %\VignetteIndexEntry{UsingSynExtend}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
editor_options:
  chunk_output_type: console
---

# Introduction

`SynExtend` started out as a package of tools for working with objects of class `Synteny` built from the package `DECIPHER`'s `FindSynteny()` function.

Synteny maps provide a powerful tool for quantifying and visualizing where pairs of genomes share ordered information. Typically these maps are built from predictions of orthologous feature pairs, where groups of pairs that provide contiguous and sequential blocks in their respective genomes are referred to as a 'syntenic block'. The identification of syntenic blocks can then be used to further interrogate the predicted orthologs themselves, or query topics like genomic rearrangements, ancestral genome reconstruction, or shared functional neighborhoods.

`FindSynteny` takes a different approach, finding exactly matched shared k-mers and determining where shared k-mers, or blocks of proximally shared k-mers are significant. Combining the information generated by `FindSynteny` with locations of genomic features allows us to simply mark where features are linked by syntenic k-mers. These linked features represent potential orthologous pairs, and can be easily evaluated on the basis of the k-mers that they share, or alignment.

# Package Structure

Currently `SynExtend` contains a set of functions for inferring orthologous relationships between features in different genomes, as well as tools for predicting feature interaction networks.

## Installation

1. Install the latest version of R using [CRAN](https://cran.r-project.org/).
2. Install `SynExtend` with `BiocManager`:

```{r, eval = FALSE}
if (!requireNamespace("BiocManager",
                      quietly = TRUE)) {
  install.packages("BiocManager")
}
BiocManager::install("SynExtend")
```

# Usage

Using the `FindSynteny` function in `DECIPHER` builds an object of class `Synteny`. In this tutorial, a prebuilt `DECIPHER` database is used. For database construction see `?Seqs2DB` in `DECIPHER`. This example starts with a database containing three endosymbiont genomes that were chosen to keep package data to a minimum.

```{r, build_synteny_object}
suppressMessages(library(SynExtend))
suppressMessages(library(DBI))

file01 <- system.file("extdata",
                      "example_db.sqlite",
                      package = "SynExtend")

# later on there are some auto-adds to the DB, we create a tmp db here so that
# the db that's passed around for examples remains as small as possible...
tmp_db <- tempfile()
system(command = paste("cp",
                       file01,
                       tmp_db))

drv <- dbDriver("SQLite")
conn01 <- dbConnect(drv = drv,
                    tmp_db)

syn <- FindSynteny(dbFile = conn01)
```

Synteny maps represent where genomes share order. Simply printing a synteny object to the console displays a gross level view of the data inside. Objects of class `Synteny` can also be plotted to provide clear visual representations of the data inside. The genomes used in this example are distantly related and fairly dissimilar.

```{r, synplots01}
syn
pairs(syn)
```

Data present inside objects of class `Synteny` can also be accessed relatively easily. The object itself is functionally a matrix of lists, with data describing exactly matched k-mers present in the upper triangle, and data describing blocks of chained k-mers in the lower triangle. For more information see `?FindSynteny` in the package `DECIPHER`.

The upper triangle of the synteny upbject is populated by the individual hits.
```{r, synplots02}
print(head(syn[[1, 2]]))
```

The lower triangle of the synteny object is populated by the block assignments of the hits.
```{r, synplots03}
print(head(syn[[2, 1]]))
```

To take advantage of these synteny maps, we can then overlay the gene calls for each genome present on top of our map.

Next, GFF annotations for the associated genomes are parsed to provide gene calls in a use-able format. GFFs are not the only possible source of appropriate gene calls, but they are the source that was used during package construction and testing. GFFs are imported via `rtracklater::import`, and converted to a DataFrame via `SquaregffBy`. Gene calls for both the `SummarizePairs` and `NucleotideOverlap` functions must be a named list, and those names must all be present within `dimnames(syn)[[1]]`.

```{r, generate_genecalls}

gr_obj <- rtracklayer::import(system.file("extdata",
                                          "GCF_023585725.1_ASM2358572v1_genomic.gff.gz",
                                          package = "SynExtend"))
genecalls_object <- SquaregffBy(gff_object = gr_obj,
                                verbose = TRUE)

head(genecalls_object)

# in an effort to be space conscious, not all original gffs are kept within this package
genecalls <- get(data("genecalls", package = "SynExtend"))
```

`SynExtend`'s `gffToDataFrame` function will directly import gff files into a usable format, and includes other extracted information.

```{r, print_gene_calls}
# this is similar to what was printed above...
head(genecalls[[1]])
```

`SynExtend`'s primary functions provide a way to identify where pairs of genes are explicitly linked by syntenic hits, and then summarize those links. The first step is just identifying those links. We're appending some funny business before generating the links because the example database that was loaded above is shipped *without* amino acid sequences to be conscious about package size.

```{r, generate_initial_links}
l01 <- NucleotideOverlap(SyntenyObject = syn,
                         GeneCalls = genecalls,
                         Verbose = TRUE)
```

The `l01` object generated by NucleotideOverlap is a raw representation of positions on the synteny map where shared k-mers link genes between paired genomes. As such, it is analagous in shape to objects of class `Synteny`. This raw object is unlikely to be useful to most users, but has been left exposed to ensure that this data remains accessible should it be advantageous.

```{r, link_printing}
head(l01[[1, 2]])
head(l01[[2, 1]])
```

This raw data can be processed to provide a straightforward summary of candidate pairs.

```{r, describe_links}
p01 <- SummarizePairs(SynExtendObject = l01,
                      DataBase01 = conn01,
                      Verbose = TRUE)

hist(p01$Approx_Global_PID,
     breaks = seq(from = 0,
                  to = 1,
                  by = 0.01))
```

The object `p01` is a data.frame where each row is populated by information about a candidate orthologous pair. `SummarizePairs` is just summarizing the pairs identified by `NucleotideOverlap`, and offers no direct assignment of accuracy or truthiness. We can pass the object created by it to `EvaluatePairs` to get a sense of which candidates are acceptable to keep. `EvaluatePairs` has an un-intuitive mix of functionalities, but in its most basic form, it will generate a decoy data set is `FALSE` pairs, and drop initial candidates that appear below a False Discovery Rate threshold 

```{r, evaluate_links}
p02 <- EvaluatePairs(InputPairs = p01,
                            DataBase01 = conn01,
                            EvaluationMethod = "none",
                            FDRCriteria = c("Delta_Background" = 0.001)) # this is the default behavior

hist(p02$Approx_Global_PID,
     breaks = seq(from = 0,
                  to = 1,
                  by = 0.01))
```

SynExtend also has a variety of other helper functions and a suite of other tools. This is the most basic usage of the tools present here.

Session Info:

```{r}
sessionInfo()
```




