---
kernelspec:
  name: python3
  display_name: python3
jupytext:
  text_representation:
    extension: .md
    format_name: myst
    format_version: '0.13'
    jupytext_version: 1.13.8
---

```{eval-rst}
.. currentmodule:: tstrait
```

(environment_noise)=

# Environmental noise

This page describes how environmental noise is simulated in tstrait. Please refer to
{ref}`phenotype_model` for mathematical details on the phenotype model.

**Learning Objectives**

After this effect size page, you will be able to:

- Understand how to simulate environmental noise in tstrati
- Understand how to use the user's defined distribution to simulate environmental noise

## Environmental noise simulation

Environmental noise can be simulated by using {py:func}`sim_env`. The required inputs are

genetic_df

: Genetic value dataframe. Please see {ref}`req_genetic_df` for requirements.

h2

: Narrow-sense heritability.

(req_genetic_df)=

### Dataframe requirements

The simplest way to simulate environmental noise is by using the genetic value dataframe
output of {py:func}`sim_genetic`. If you would like to define your own genetic value
dataframe, there are some requirements that you must follow.

#### Columns

The following columns must be included in `trait_df`:

> - **trait_id**: Trait ID. This will be used in multi-trait simulation.
> - **individual_id**: Individual ID.
> - **genetic_value**: Simulated genetic value.

#### Data requirement

Trait IDs in **trait_id** column must start from 0 and be consecutive. If you are simulating
a single trait, you should be using an array that is filled with zeros.

## Example

We will be showing an example of environmental noise simulating by using a simulated tree
sequence data with 10,000 individuals. The narrow-sense heritability is set to be 0.3.

:::{seealso}
- [msprime](msprime:sec_intro) for simulating whole genome in tree sequence data.
- [](effect_size) for simulating trait dataframe in tstrait.
- [](genetic_value) for simulating the genetic value dataframe in tstrait.
:::

```{code-cell}

    import msprime
    import tstrait

    ts = msprime.sim_ancestry(
        samples=10_000,
        recombination_rate=1e-8,
        sequence_length=1_000_000,
        population_size=10_000,
        random_seed=5,
    )
    ts = msprime.sim_mutations(ts, rate=1e-8, random_seed=5)

    model = tstrait.trait_model(distribution="normal", mean=0, var=1)
    trait_df = tstrait.sim_trait(ts, num_causal=1000, model=model, random_seed=5)
    genetic_result = tstrait.sim_genetic(ts, trait_df, random_seed=5)

    phenotype_df = tstrait.sim_env(genetic_result.genetic, h2=0.3, random_seed=5)
    phenotype_df.head()
```

The resulting dataframe has the following columns:

> - **trait_id**: Trait ID.
> - **individual_id**: Individual ID inside the tree sequence input.
> - **genetic_value**: Simulated genetic values.
> - **environmental_noise**: Simulated environmental noise.
> - **phenotype**: Simulated phenotype.

The distribution of simulated environmental noise is shown below.

```{code-cell}

    import matplotlib.pyplot as plt

    plt.hist(phenotype_df["environmental_noise"], bins=40)
    plt.title("Environmental Noise")
    plt.show()
```

The simulated environmental noise is following a normal distribution as expected.

## User-defined environmental noise

It would be possible for the user to define their own environmental noise, and
there are several options available for the user.

### Simulating from the output of {py:func}`sim_genetic`

The output of {py:func}`sim_genetic` only includes genetic values, and it doesn't
simulate environmental noise. For example, if the user wants to simulate
environmental noise from a normal distribution with mean 0 and variance 1, it
would be possible to run the following code:

```{code-cell}

    genetic_df = genetic_result.genetic
    genetic_df.head()
```

Recall that `genetic_result` is the output of {py:func}`sim_genetic` function.
We will be drawing random samples from a normal distribuion by using
{py:meth}`numpy.random.Generator.normal`.

```{code-cell}

    import numpy as np

    rng = np.random.default_rng(seed=50)
    env_noise = rng.normal(loc=0, scale=1, size=len(genetic_df))
    genetic_df["environmental_noise"] = env_noise
    genetic_df["phenotype"] = (
        genetic_df["environmental_noise"] + genetic_df["genetic_value"]
    )
    genetic_df.head()
```

### Setting `h2` to be 1

When `h2` is set to be 1 in {py:func}`sim_phenotype` or {py:func}`sim_env`, the
environmental noise will be a vector of zeros. After obtaining the output, the user
can define their own environmental noise.

```{code-cell}

  sim_result = tstrait.sim_phenotype(
      ts=ts, num_causal=100, model=model, h2=1, random_seed=1
  )
  sim_result.phenotype.head()
```
