--- title: 'Input/output' author: "Kenneth B. Hoehn" date: '`r Sys.Date()`' output: pdf_document: dev: pdf fig_height: 4 fig_width: 7.5 highlight: pygments toc: yes html_document: fig_height: 4 fig_width: 7.5 highlight: pygments theme: readable toc: yes md_document: fig_height: 4 fig_width: 7.5 preserve_yaml: no toc: yes geometry: margin=1in fontsize: 11pt vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{Input and Output} %\VignetteEncoding{UTF-8} %\usepackage[utf8]{inputenc} --- This vignette covers how data gets into Dowser and the different ways Dowser objects and trees can be saved. These formats primarily follow the [Adaptive Immune Receptor Repertoire (AIRR) Community standard formats](https://docs.airr-community.org). Specifically this will cover AIRR TSV input, as well as AIRR Trees and Clones JSON format (`writeTreesJSON`/`readTreesJSON`), plain R serialization (`saveRDS`/`readRDS`), Newick tree export (`exportTrees`), and FASTA sequence export/import (`writeFasta`/`readFasta`). ## Reading AIRR Rearrangement sequencing data files The best input format for Dowser is the [AIRR Rearrangement](https://docs.airr-community.org/en/latest/datarep/rearrangements.html) TSV format. The `airr` package's `read_rearrangement` function reads such a file into a data frame: ```{r, eval=FALSE, warning=FALSE, message=FALSE} library(airr) library(dowser) # Read in an AIRR-formatted TSV file of Ig/TCR rearrangements airr_data <- read_rearrangement("sequences.tsv") ``` To keep this vignette self-contained, we'll instead use the `ExampleAirr` data object included with Dowser, which is the kind of data frame `read_rearrangement` would return. ```{r, eval=FALSE, warning=FALSE, message=FALSE} library(airr) library(dowser) # load example AIRR data, as if read in with read_rearrangement data(ExampleAirr) # subset data for this example ExampleAirr <- ExampleAirr[ExampleAirr$clone_id %in% c("3170", "3184"),] ``` From here, `formatClones` groups sequences into clones and reconstructs germlines, and `getTrees` builds a lineage tree for each clone (see the [Build Lineage Trees vignette](https://dowser.readthedocs.io/en/stable/vignettes/Building-Trees-Vignette/) for details on both steps). Before this step, it's important that the BCR sequences are already grouped into clones beforehand (they will have a `clone_id` column). This can be accomplished using [SCOPer](https://scoper.readthedocs.io). Further, it is imporant that each clonal germline V/J has has been reconstructed, which can be accomplished using (createGermlines)[https://dowser.readthedocs.io/en/stable/vignettes/Germlines-Vignette/]. This will generate a `germline_alignment_d_mask` column. To see all of these steps together, check out one of the full [Immcantation tutorials](https://immcantation.readthedocs.io/en/stable/getting_started/getting-started.html). ```{r, eval=FALSE, warning=FALSE, message=FALSE} # Process example data into proper format, store isotype (optional) clones <- formatClones(ExampleAirr, traits="c_call") # Build maximum parsimony trees for each clone trees <- getTrees(clones, nproc=1) print(trees) ``` `trees` is a standard Dowser object: a tibble with one row per clone with an `airrClone` object in the `data` column and a tree (`ape::phylo`, or `treeio::treedata` for time trees) in the `trees` column. The rest of this vignette covers ways to save and reload this object. ## scRepertoire and Dowser compatability While Dowser was designed to work downstream of [Immcantation](https://immcantation.org) packages, it is possible to use Dowser and other Immcantation packages in combination with [scRepertoire](https://www.borch.dev/uploads/screpertoire/). To learn how to do this, check out the scRepertoire team's excellent tutorial about [Combining Immcantation and scRepertoire](https://www.borch.dev/uploads/screpertoire/articles/immcantation). ## Saving and loading Dowser objects in AIRR Clone JSON format To save an entire Dowser object, including trees, use `writeTreesJSON` to write a Dowser object to an [AIRR Clone](https://docs.airr-community.org/en/latest/datarep/clone.html) JSON file. Conversely, `readTreesJSON` reads it back. This works for trees built with any `getTrees` `build` option, as well as time trees from `getTimeTrees`/ `getTimeTreesIterate`. By default, `writeTreesJSON` reloads the file it just wrote and checks that it matches the original object before returning. ```{r, eval=FALSE, warning=FALSE, message=FALSE} # Write tree object to a JSON file, checking it reads back identically writeTreesJSON(trees, "trees.json") # Read it back in trees_json <- readTreesJSON("trees.json") print(trees_json) ``` Because it's plain JSON with a documented schema, this format is useful for archiving trees long-term, sharing them with collaborators who aren't using R, or loading them into other tools. **Note** that internal node labels are not preserved when inputting/outputting in this schema, but this is only relevant if you're manually selecting particular nodes, such as [reconstructing internal node sequences](https://dowser.readthedocs.io/en/stable/vignettes/Sequences-Vignette/). All other aspects of the Dowser object are preserved and checked on output. ## Saving and loading Dowser objects as RDS If you're staying within R, `saveRDS`/`readRDS` is the simplest way to save a Dowser object exactly as-is, with no format translation, although it is a binary file that is unreadable outside of R. ```{r, eval=FALSE, warning=FALSE, message=FALSE} # Save tree object to an RDS file saveRDS(trees, "trees.rds") # Read it back in trees_rds <- readRDS("trees.rds") print(trees_rds) ``` ## Exporting trees in Newick format `exportTrees` writes the trees in a Dowser object in order to a single Newick file, one tree per line, using `ape::write.tree`. Alternatively, the list of tree objects in the `trees` column can be exported using many other output functions, for example `ape::write.tree`. ```{r, eval=FALSE, warning=FALSE, message=FALSE} # Export trees to a Newick file exportTrees(trees, "trees.newick") # write a single tree ape::write.tree(trees$trees[[1]], "clone1.tree") ``` ## Exporting and reading sequences as FASTA `writeFasta` writes a named list of sequences to a FASTA file, and `readFasta` reads a FASTA file back into a named list. These are generic sequence I/O functions and provided for convenience. ```{r, eval=FALSE, warning=FALSE, message=FALSE} # Get sequences and sequence IDs for the first clone seqs <- clones$data[[1]]@data$sequence names(seqs) <- clones$data[[1]]@data$sequence_id # Write them to a FASTA file writeFasta(seqs, "clone_3170.fasta") # Read them back in seqs_read <- readFasta("clone_3170.fasta") print(names(seqs_read)) ``` Alternatively, `dfToFasta` writes sequences straight from a data frame or tibble to a FASTA file, without needing to build a named list first. By default it reads sequence IDs and sequences from the `sequence_id`/`sequence` columns, strips IMGT gap characters (`.`), and can append extra columns to each sequence's header. ```{r, eval=FALSE, warning=FALSE, message=FALSE} # Get the data frame of sequences for the first clone df <- clones$data[[1]]@data # Write to FASTA, tagging each header with its isotype dfToFasta(df, "clone_3170_df.fasta", columns="c_call") cat(readLines("clone_3170_df.fasta")[1:2], sep="\n") ``` Use `id`/`seq` to point at differently-named columns, and `imgt_gaps=TRUE` to keep IMGT gaps rather than stripping them. ## Making and saving tree plots Now that trees are built and saved, see the [Plotting Trees vignette](https://dowser.readthedocs.io/en/stable/vignettes/Plotting-Trees-Vignette/) for how to visualize trees and save tree plots as files.