---
title: Pedigree object
author: Terry Therneau, Elizabeth Atkinson, Louis Le Nezet
date: '`r format(Sys.time(),"%d %B, %Y")`'
output:
    BiocStyle::html_document:
        toc: true
        toc_depth: 2
header-includes: \usepackage{tabularx}
vignette: |
    %\VignetteIndexEntry{Pedigree object}
    %\VignetteEncoding{UTF-8}
    %\VignetteEngine{knitr::rmarkdown}
---

Introduction
===============

The pedigree routines came out of a simple need -- to quickly draw a
Pedigree structure on the screen, within R, that was "good enough" to
help with debugging the actual routines of interest, which were those for
fitting mixed effecs Cox models to large family data. As such the routine
had compactness and automation as primary goals; complete annotation
(monozygous twins, multiple types of affected status) and most certainly
elegance were not on the list. Other software could do that much
better.

It therefore came as a major surprise when these routines proved useful
to others. Through their constant feedback, application to more
complex pedigrees, and ongoing requests for one more feature, the routine has 
become what it is today. This routine is still not 
suitable for really large pedigrees, nor for heavily inbred ones such as in
animal studies, and will likely not evolve in that way. The authors fondest
hope is that others will pick up the project.

Pedigree Constructor
========================

## Arguments

The Pedigree function is the first step, creating an object of class
Pedigree.
It accepts the following input

- `ped_df` A dataframe containing the columns
    - `id` A numeric or character vector of subject identifiers.
    - `dadid` The identifier of the father.
    - `momid` The identifier of the mother.
    - `famid` Optional, a numeric or character vector of family
    identifiers.
    - `sex` The gender of the individual. This can be a numeric
    variable with codes of `1`=male, `2`=female, `3`=unknown,
    or NA=unknown.
    A character or factor variable can also be supplied containing
    the above; the string may be truncated and of arbitrary case.
    - `fertility` Optional, will be transformed to an ordered factor using the
    `fertility_to_factor()` function.
    `infertile_choice_na`, `infertile`, `fertile`
    The following values are recognized:
        - character() or factor() : "fertile", "infertile", "steril",
        "infertile_choice", "infertile_na", "infertile_choice_na"
        - numeric() : 1 = "fertile", 0 = "infertile"
        - logical() : `TRUE` = "fertile", `FALSE` = "infertile"
    - `miscarriage` Optional, will be transformed to an factor using the
    `miscarriage_to_factor()` function.
    `TOP`, `SAB`, `ECT`, `FALSE`
    The following values are recognized:
        - character() or factor() : "spontaneous", "spontaenous abortion",
        "termination", "terminated", "termination of pregnancy",
        "ectopic", "ectopic pregnancy", "false"
        - numeric() : 0 = "FALSE", `NA` = "FALSE"
        - logical() : `FALSE` = "FALSE"
    - `deceased` Optional, a logical variable with `0`=alive and
    `1`=dead.
    - `avail` Optional, a logical variable with `0`=unavailable
    and `1`=available.
    - `evaluated` Optional, a logical variable with `0`=not evaluated
    and `1`=evaluated.
    - `consultand` Optional, a logical variable with `0`=not consultand
    and `1`=consultand.
    - `proband` Optional, a logical variable with `0`=not proband
    and `1`=proband.
    - `affected` Optional, a logical variable with `0`=unaffected
    and `1`=affected.
    - `carrier` Optional, a logical variable with `0`=not a carrier
    `1`=carrier and `NA`=unknown.
    - `asymptomatic` Optional, a logical variable with `0`=not asymptomatic
    `1`=asymptomatic and `NA`=asymptomatic.
    - `adopted` Optional, a logical variable with `0`=not adopted
    `1`=adopted.
- `rel_df` Optional, a data frame with three columns or four columns.
    - `id1` identifier values of the subject pairs
    - `id2` identifier values of the subject pairs
    - `code` relationship codification : `1`=Monozygotic twin,
    `2`=Dizygotic twin, `3`=twin of unknown zygosity, `4`=Spouse.
    - `famid` Optional, a numeric or character vector of family
    identifiers.
- `cols_ren_ped` Optional, a named list for the renaming of the
`ped_df` dataframe
- `cols_ren_rel` Optional, a named list for the renaming of the
`rel_df` dataframe
- `normalize` Optional, a logical to know if the data should be normalised.
- `hints` Optional, a list containing the horder in which to plot the
individuals and the matrix of the spouse.

## Notes

Note that a factor variable is not listed as one of the choices for the
subject identifier. This is on purpose. Factors
were designed to accomodate character strings whose values came from a limited
class -- things like race or gender, and are not appropriate for a subject
identifier. All of their special properties as compared to a character
variable turn out to be backwards for this case, in particular a memory
of the original level set when subscripting is done.

However, due to the awful decision early on in S to automatically turn every
character into a factor, unless you stood at the door with a club to
head the package off, most users have become ingrained to the idea of
using them for every character variable.

(I encourage you to set the global option `stringsAsFactors = FALSE` to turn
off autoconversion, it will measurably improve your R experience).

Therefore, to avoid unnecessary hassle for our users 
the code will accept a factor as input for the id variables, but
the final structure does not retain it.
Gender and relation do become factors.
Status follows the pattern of the survival routines and remains an integer.

## Column renaming

Based on the dataframe given for `ped_df` and `rel_df` and their
corresponding named list, the columns are renamed for them to be used
correctly.
The renaming is done as follow

```{r, column_renaming}
rel_df <- data.frame(
    indId1 = c("110", "204"),
    indId2 = c("112", "205"),
    code = c(1, 2),
    family = c("1", "2")
)
cols_ren_rel <- list(
    id1 = "indId1",
    id2 = "indId2",
    famid = "family"
)

## Rename columns rel
old_cols <- as.vector(unlist(cols_ren_rel))
new_cols <- names(cols_ren_rel)
cols_to_ren <- match(old_cols, names(rel_df))
names(rel_df)[cols_to_ren[!is.na(cols_to_ren)]] <-
    new_cols[!is.na(cols_to_ren)]
print(rel_df)
```

## Normalisation

If the normalisation process is selected `normalize = TRUE`, then both
dataframe will be checked by their dedicated normalization function.
It will ensure that all modalities are written correctly and set up the
right way. If a `famid` column is present in the dataframe, then it will
be aggregated to the id of each individual and separated by an ''_'' to
ensure the uniqueness of the individuals identifiers.

```{r, normalisation}
library(Pedixplorer)
data("sampleped")
cols <- c("sex", "id", "avail")
summary(sampleped[cols])
pedi <- Pedigree(sampleped)
summary(as.data.frame(ped(pedi))[cols])
```

### Errors present after the normalisation process

If any error is detected after the normalisation process, then the normalised
dataframe is gave back to the user with errors column added describing the
encountered problems.

```{r, rel_df_errors}
rel_wrong <- rel_df
rel_wrong$code[2] <- "A"
df <- Pedigree(sampleped, rel_wrong)
print(df)
```

## Validation

Now that the data for the Pedigree object creation are ready, they are
given to a new `Pedigree` object, trigerring the *validation* process.

This validation step will check up for many errors such as:

- All necessary columns are present
- No duplicated `id`
- All `momid` and `dadid` are present in `id`
- `sex` column only contain "male", "female", "unknown" values
- `fertility` column only contain "fertile", "infertile", "infertile_choice_na"
- `miscarriage` column only contain "SAB", "TOP", "ECT", "FALSE"
- `deceased`, `avail`, `evaluated`, `consultand`, `proband`,
`affected`, `carrier`, `asymptomatic`, `adopted` only contains 0, 1 or NA values
- Father are males and Mother are females
- Twins have same parents and MZ twins have same sex
- Hints object is valid and ids contained is in the Ped object
- ...

Pedigree Class
========================

After validation an $S4$ object is generated.
This new concept make it possible to easily setup methods for this new
type of object.
The controls of the parameters is also more precise.

The `Pedigree` object contains 4 slots, each of them contains a different
$S4$ object containing a specific type of information used for the Pedigree
construction.

- `ped` a Ped object for the Pedigree information with at least the following
slots:
    - `id` the identifiers of the individuals
    - `dadid` the identifiers of the fathers
    - `momid` the identifiers of the mothers
    - `sex` the gender of each individuals
- `rel` a Rel object describing all special relationship beetween individuals
that can't be descibed in the `ped` slot.
The minimal slots needed are :
    - `id1` the identifiers of the 1st individuals
    - `id2` the identifiers of the 2nd individuals
    - `code` factor describing the type of relationship
    ("MZ twin", "DZ twin", "UZ twin", "Spouse")
- `scales` a Scales object with two slots :
    - `fill` a dataframe describing which modalities in which columns
    correspond to an affected individuals.
    Plotting information such as colour, angle and density are also provided
    - `border` a dataframe describing which modalities in which columns to
    use to plot the border of the plot elements.
- `hints` a Hints object with two slots :
    - `horder` numeric vector for the ordering of the individuals plotting
    - `spouse` a matrix of the spouses

For more information on each object:

- `help(Ped)`
- `help(Rel)`
- `help(Scales)`
- `help(Hints)`

Pedigree accessors
========================

As the Pedigree object is now an $S4$ class, we have made available a number
of accessors.
Most of them can be used as a getter or as a setter to modify a value in the
correponding slot of the object

## For the Pedigree object

- Get/Set slots : `ped()`, `rel()`, `scales()`, `hints()`
- Wrapper to the Ped object: `mcols()`
- Wrapper of the Scales object: `fill()`, `border()`
- Wrapper of the Hints object: `horder()`, `spouse()`

## For the Ped object

- Identity input: `id()`, `dadid()`, `momid()`, `famid()`, `sex()`
- Other infos used : `fertility()`, `miscarriage()`, `deceased()`,
`avail()`, `evaluated()`, `consultand()`, `proband()`,
`affected()`, `carrier()`, `asymptomatic()`, `adopted()`
- Computed : `isinf()`, `kin()`, `useful()`
- Metadata : `mcols()`

## For the Rel object

- `id1()`, `id2()`, `code()`, `famid()`

## For the Scales object

- `fill()`, `border()`

## For the Hints object

- `horder()`, `spouse()`

## Focus on `mcols()`

The `mcols()` accessors is the one you should use to add more
informations to your individuals.

```{r, mcols}
pedi <- Pedigree(sampleped)
mcols(pedi)
## Add new columns as a threshold if identifiers of individuals superior
## to a given threshold for example
mcols(pedi)$idth <- ifelse(as.numeric(
    stringr::str_split_i(id(ped(pedi)), "_", 2)
) < 200, "A", "B")
mcols(pedi)$idth
```


Pedigree methods
========================

With this new S4 object comes multiple methods to ease the use of it:

- `plot()`
- `summary()`
- `print()`
- `show()`
- `as.list()`
- `[`
- `shrink()`
- `generate_colors()`
- `is_informative()`
- `kindepth()`
- `kinship()`
- `make_famid()`
- `upd_famid()`
- `num_child()`
- `unrelated()`
- `useful_inds()`

```{r, pedigree_methods, fig.alt = "Pedigree plot", fig.align = 'center'}
## We can change the family name based on an other column
pedi <- upd_famid(pedi, mcols(pedi)$idth)

## We can substract a given family
ped_a <- pedi[famid(ped(pedi)) == "A"]

## Plot it
plot(ped_a, cex = 0.5)

## Do a summary
summary(ped_a)

## Coerce it to a list
as.list(ped_a)[[1]][1:3]

## Shrink it to keep only the necessary information
lst1_s <- shrink(ped_a, max_bits = 10)
plot(lst1_s$pedObj, cex = 0.5)

## Compute the kinship individuals matrix
adopted(ped(ped_a)) <- FALSE # Set adopted to FALSE
kinship(ped_a)[1:10, 1:10]

## Get the useful individuals
ped_a <- is_informative(ped_a, informative = "AvAf", col_aff = "affection")
ped_a <- useful_inds(ped_a)
as.data.frame(ped(ped_a))["useful"][1:10, ]
```

Session information
===================

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