Simulation of neutral evolution in populations of different sizes

We consider the evolution of a neutral allele starting at frequency 50%.

Useful functions


In [48]:
import numpy as np
from cycler import cycler
import matplotlib.pyplot as plt
from pylab import rcParams


numIndividuals = 100



def generation (genolist):
    newGenos = list()
    length = len(genolist)
    selection = np.random.choice(length, length)
    for i in range(length):
        newGenos.append(genolist[selection[i]])
    return(newGenos)


#############################
def simulate (numIndividuals, numGenerations, numPopulations):
    # Two alleles: true and false
    init = [True]*int(numIndividuals/2) + [False] * int(numIndividuals/2)
    allFreqs = list()
    for pop in range(numPopulations):
        freqs = list()
        freqs.append(sum(init)/ numIndividuals)
        current = init
        for gen in range(numGenerations):
            new = generation(current)
            freqs.append(sum(new) / numIndividuals)
            current = new
        allFreqs.append(freqs)
    return allFreqs



def plotFreqs (allFreqs):
    %matplotlib inline
    rcParams['figure.figsize'] = 18, 8
    rcParams['xtick.labelsize'] = 20 
    rcParams['ytick.labelsize'] = 20 
    plt.ylim([0,1.0])
    plt.suptitle('Allele frequency over generations', fontsize=20, fontweight='bold')
    plt.rc('lines', linewidth=2)
    plt.rc('axes', prop_cycle=(cycler('color', ['r', 'g', 'b', 'y'])))
    # +  cycler('linestyle', ['-', '--', ':', '-.'])))
    for i in range(len(allFreqs)):
        plt.plot (allFreqs[i]) #(position, coverage, 'r-')
    plt.xlabel ('Generation', fontsize=18)
    plt.ylabel ('Allele frequency', fontsize=18)
    #plt.tight_layout()

Neutral evolution in a small population of 20 individuals


In [49]:
plotFreqs(simulate (20, 50, 10))


Neutral evolution in a larger population of 200 individuals


In [51]:
plotFreqs(simulate (200, 50, 10))


Neutral evolution in an even larger population of size 2000


In [53]:
plotFreqs(simulate (2000, 50, 10))


Simulation of evolution under natural selection in poplations of different sizes

Same idea as above, except that the "True" allele now has a selective advantage of 5%.


In [63]:
def generationSelection (genolist):
    newGenos = list()
    length = len(genolist)
    weights = list()
    for i in range(length):
        if genolist[i]:
            weights.append(1.05)
        else:
            weights.append(1.0)
    probas = [weights[i]/sum(weights) for i in range(len(weights))]
    newGenos = np.random.choice(genolist, length, p=probas)
    return(newGenos)

#############################
def simulateSelection (numIndividuals, numGenerations, numPopulations):
    # Two alleles: true and false
    init = [True]*int(numIndividuals/2) + [False] * int(numIndividuals/2)
    allFreqs = list()
    for pop in range(numPopulations):
        freqs = list()
        freqs.append(sum(init)/ numIndividuals)
        current = init
        for gen in range(numGenerations):
            new = generationSelection(current)
            freqs.append(sum(new) / numIndividuals)
            current = new
        allFreqs.append(freqs)
    return allFreqs

Selection in a population of 20 individuals


In [64]:
plotFreqs(simulateSelection (20, 50, 10))


Selection in a population of 200 individuals


In [65]:
plotFreqs(simulateSelection (200, 50, 10))


Selection in a population of 2000 individuals


In [68]:
plotFreqs(simulateSelection (2000, 50, 10))



In [ ]: