---
title: "An R interface to the Ontology Lookup Service"
author:
- name: Laurent Gatto
  affiliation: https://lgatto.github.io/about/
package: rols
abstract: >
  How to query the Ontology Lookup Service directly from R and how to
  create and parse controlled vocabulary.
output:
  BiocStyle::html_document:
    toc_float: true
vignette: >
  %\VignetteIndexEntry{An R interface to the Ontology Lookup Service}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteKeywords{Infrastructure, Bioinformatics, ontology, data}
  %\VignetteEncoding{UTF-8}
---

```{r env, echo=FALSE}
suppressPackageStartupMessages(library("GO.db"))
suppressPackageStartupMessages(library("BiocStyle"))
suppressPackageStartupMessages(library("rols"))
suppressPackageStartupMessages(library("DT"))
nonto <- length(ol <- Ontologies())
```

# Introduction

## Installation

`r Biocpkg("rols")` is a Bioconductor package and should hence be
installed using the dedicated functionality

```{r install, eval=FALSE}
## try http:// if https:// URLs are not supported
if (!requireNamespace("BiocManager", quietly=TRUE))
    install.packages("BiocManager")
BiocManager::install("rols")
```

## Getting help

To get help, either post your question on the
[Bioconductor support site](https://support.bioconductor.org/) or open
an issue on the `r Biocpkg("rols")`
[github page](https://github.com/lgatto/rols/issues).

## The resource

The [Ontology Lookup Service](http://www.ebi.ac.uk/ontology-lookup/)
(OLS)
[[1](http://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-7-97),
[2](http://nar.oxfordjournals.org/content/36/suppl_2/W372)] is
originally spin-off of the
[PRoteomics IDEntifications](http://www.ebi.ac.uk/pride/archive/)
database (PRIDE) service, located at the EBI, and is now developed and
maintained by the
[Samples, Phenotypes and Ontologies](http://www.ebi.ac.uk/about/spot-team)
team at EMBL-EBI.

## The package

The OLS provides a REST interface to hundreds of ontologies from a
single location with a unified output format. The `r Biocpkg("rols")`
package make this possible from within R. Do do so, it relies on the
`r CRANpkg("httr")` package to query the REST interface, and access
and retrieve data.


There are `r nonto` ontologies available in the OLS, listed in the
table below. Their name is to be use to defined which ontology to
query.


```{r ontTable, echo = FALSE}
datatable(as(ol, "data.frame"))
```

# A Brief rols overview

The `r Biocpkg('rols')` package is build around a few classes that
enable to query the OLS and retrieve, store and manipulate data. Each of
these classes are described in more details in their respective manual
pages. We start by loading the package.

```{r}
library("rols")
```

## Ontologies

The `Ontology` and `Ontologies` classes can store information about
single of multiple ontologies. The latter can be easily subset using
`[` and `[[`, as one would for lists.

```{r ol}
ol <- Ontologies()
ol
```

```{r}
head(olsNamespace(ol))
ol[["go"]]
```

It is also possible to initialise a single ontology

```{r}
go <- Ontology("go")
go
```

## Terms

Single ontology terms are stored in `Term` objects. When more terms
need to be manipulated, they are stored as `Terms` objects. It is easy
to obtain all terms of an ontology of interest, and the resulting
`Terms` object can be subset using `[` and `[[`, as one would for
lists.

```{r}
gotrms <- terms(go) ## or terms("go")
gotrms
gotrms[1:10]
gotrms[["GO:0090575"]]
```

It is also possible to initialise a single term

```{r}
trm <- term(go, "GO:0090575")
termId(trm)
termLabel(trm)
```

It is then possible to extract the `ancestors`, `descendants`,
`parents` and `children` terms. Each of these functions return a
`Terms` object

```{r}
parents(trm)
children(trm)
```

Similarly, the `partOf` and `derivesFrom` functions return, for an
input term, the terms it is a part of and derived from.

Finally, a single term or terms object can be coerced to a
`data.frame` using `as(x, "data.frame")`.

## Properties

Properties (relationships) of single or multiple terms or complete
ontologies can be queries with the `properties` method, as briefly
illustrated below.

```{r propex}
trm <- term("uberon", "UBERON:0002107")
trm
p <- properties(trm)
p
p[[1]]
termLabel(p[[1]])
```

# Use case

```{r, echo=FALSE}
alltgns <- OlsSearch(q = "trans-golgi network")
```

A researcher might be interested in the trans-Golgi network. Searching
the OLS is assured by the `OlsSearch` and `olsSearch`
classes/functions. The first step is to defined the search query with
`OlsSearch`, as shown below. This creates an search object of class
`OlsSearch` that stores the query and its parameters. In records the
number of requested results (default is 20) and the total number of
possible results (there are `r alltgns@numFound` results across all
ontologies, in this case). At this stage, the results have not yet
been downloaded, as shown by the `r nrow(alltgns@response)` responses.

```{r tgnquery, eval = TRUE}
OlsSearch(q = "trans-golgi network")
```

`r alltgns@numFound` results are probably too many to be
relevant. Below we show how to perform an exact search by setting
`exact = TRUE`, and limiting the search the the GO ontology by
specifying `ontology = "GO"`, or doing both.

```{r tgnquery1, eval = TRUE}
OlsSearch(q = "trans-golgi network", exact = TRUE)
OlsSearch(q = "trans-golgi network", ontology = "GO")
OlsSearch(q = "trans-golgi network", ontology = "GO", exact = TRUE)
```

One case set the `rows` argument to set the number of desired results.

```{r tgnquery2}
OlsSearch(q = "trans-golgi network", ontology = "GO", rows = 200)
```

Alternatively, one can call the `allRows` function to request all results.

```{r tgnquery3}
(tgnq <- OlsSearch(q = "trans-golgi network", ontology = "GO"))
(tgnq <- allRows(tgnq))
```

```{r tgnsear4, echo=FALSE}
qry <- OlsSearch(q = "trans-golgi network", exact = TRUE)
```

Let's proceed with the exact search and retrieve the results. Even if
we request the default 20 results, only the `r qry@numFound` relevant
result will be retrieved. The `olsSearch` function updates the
previously created object (called `qry` below) by adding the results
to it.

```{r tgnquery5}
qry <- OlsSearch(q = "trans-golgi network", exact = TRUE)
(qry <- olsSearch(qry))
```

We can now transform this search result object into a fully fledged
`Terms` object or a `data.frame`.

```{r tgnres}
(qtrms <- as(qry, "Terms"))
str(qdrf <- as(qry, "data.frame"))
```

In this case, we can see that we actually retrieve the same term used
across different ontologies. In such cases, it might be useful to keep
only non-redundant term instances. Here, this would have been
equivalent to searching the `r termOntology(unique(qtrms))` ontology

```{r uterms}
qtrms <- unique(qtrms)
termOntology(qtrms)
termNamespace(qtrms)
```

Below, we execute the same query using the `r Biocpkg("GO.db")` package.

```{r go.db, message=FALSE}
library("GO.db")
GOTERM[["GO:0005802"]]
```

# On-line vs. off-line data

It is possible to observe different results with `r Biocpkg("rols")`
and `r Biocpkg("GO.db")`, as a result of the different ways they
access the data. `r Biocpkg("rols")` or `r Biocpkg("biomaRt")`
perform direct online queries, while `r Biocpkg("GO.db")` and other
annotation packages use database snapshot that are updated every
release.

Both approaches have advantages. While online queries allow to obtain
the latest up-to-date information, such approaches rely on network
availability and quality. If reproducibility is a major issue, the
version of the database to be queried can easily be controlled with
off-line approaches. In the case of `r Biocpkg("rols")`, although the
load date of a specific ontology can be queried with `olsVersion`, it
is not possible to query a specific version of an ontology.


# Changes in version 2.0

`r Biocpkg("rols")` 2.0 has substantially changed. While the table
below shows some correspondence between the old and new interface,
this is not always the case. The new interface relies on the
`Ontology`/`Ontologies`, `Term`/`Terms` and `OlsSearch` classes, that
need to be instantiated and can then be queried, as described above.


| version < 1.99     | version >= 1.99 |
|--------------------|-----------------|
| `ontologyLoadDate` | `olsLoaded`  and `olsUpdated` |
| `ontologyNames`    | `Ontologies` |
| `olsVersion`       | `olsVersion` |
| `allIds`           | `terms`      |
| `isIdObsolete`     | `isObsolete` |
| `rootId`           | `olsRoot`    |
| `olsQuery`         | `OlsSearch` and `olsSearch` |

Not all functionality is currently available. If there is anything
that you need but not available in the new version, please contact the
maintained by opening an
[issue](https://github.com/lgatto/rols/issues) on the package
development site.


# CVParams

The `CVParam` class is used to handle controlled vocabulary. It can be
used for user-defined parameters

```{r}
CVParam(name = "A user param", value = "the value")
```

or official controlled vocabulary (which triggers a query to the OLS
service)

```{r}
CVParam(label = "MS", accession = "MS:1000073")
```

See `?CVParam` for more details and examples.


# Session information

```{r si, echo=FALSE}
print(sessionInfo(), locale = FALSE)
```
