def generate_f_one(self, pop: sim.Population): """ A very basic implementation of the F_1 cross between pairs of individuals. Relies on pre-formatting of desired mating pairs into an ordered list. [1, 3, 5, 11, 12, 9, 22, 2] The mating pattern would be: 1x3, 5x11, 12x9, 22x2. Rearranging the order of the indices would change the mating pairs. :param pop: :type pop: :return: :rtype: """ pop.dvars().generations[1] = 'F_1' pop.dvars().gen = 1 pairs_of_founders = int(pop.popSize() / 2) self.odd_to_even(pop) print("Creating the F_one population from selected founders.") return pop.evolve( preOps=[ sim.PyEval(r'"Generation: %d\n" % gen'), operators.CalcTripletFrequencies(), sim.PyExec('triplet_freq[gen]=tripletFreq'), sim.SplitSubPops(sizes=[2] * pairs_of_founders, randomize=False), ], matingScheme=sim.RandomMating(subPopSize=[1] * pairs_of_founders, ops=[sim.Recombinator(rates=0.01), sim.IdTagger(), sim.PedigreeTagger()]), gen=1, )
def _assertSize(self, sizes, initSize=[], startGen=0): '''This function is provided for testing purpose. ''' self.intended_size = sizes pop = Population(size=initSize if initSize else self.init_size, infoFields=self.info_fields) pop.dvars().gen = startGen pop.evolve(matingScheme=RandomSelection(subPopSize=self), postOps=PyOperator(self._checkSize, param=startGen), finalOps=PyOperator(self._checkSize, param=startGen), gen=self.num_gens)
def plot(self, filename='', title='', initSize=[]): '''Evolve a haploid population using a ``RandomSelection`` mating scheme using the demographic model. Print population size changes duringe evolution. An initial population size could be specified using parameter ``initSize`` for a demographic model with dynamic initial population size. If a filename is specified and if matplotlib is available, this function draws a figure to depict the demographic model and save it to ``filename``. An optional ``title`` could be specified to the figure. Note that this function can not be plot demographic models that works for particular mating schemes (e.g. genotype dependent).''' if not self.init_size: if initSize: self.init_size = initSize else: raise ValueError( 'Specific self does not have a valid initial population size' ) if filename and not has_plotter: raise RuntimeError( 'This function requires module numpy and matplotlib') self.draw_figure = filename and has_plotter self.pop_regions = OrderedDict() self.pop_base = OrderedDict() # self._reset() if title: print(title) pop = Population(self.init_size, infoFields=self.info_fields, ploidy=1) pop.evolve(matingScheme=RandomSelection(subPopSize=self), postOps=PyOperator(self._recordPopSize), gen=self.num_gens) self._recordPopSize(pop) # if self.draw_figure: fig = plt.figure() ax = fig.add_subplot(111) ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') for name, region in self.pop_regions.items(): region = region.reshape(region.size / 4, 4) points = np.append(region[:, 0:2], region[::-1, 2:4], axis=0) plt.fill(points[:, 0], points[:, 1], label=name, linewidth=0, edgecolor='w') leg = plt.legend(loc=2) leg.draw_frame(False) if title: plt.title(title) plt.savefig(filename) plt.close()
def _assertSize(self, sizes, initSize=[], startGen=0): '''This function is provided for testing purpose. ''' self.intended_size = sizes pop = Population(size=initSize if initSize else self.init_size, infoFields=self.info_fields) pop.dvars().gen = startGen pop.evolve( matingScheme=RandomSelection(subPopSize=self), postOps=PyOperator(self._checkSize, param=startGen), finalOps=PyOperator(self._checkSize, param=startGen), gen=self.num_gens )
def plot(self, filename='', title='', initSize=[]): '''Evolve a haploid population using a ``RandomSelection`` mating scheme using the demographic model. Print population size changes duringe evolution. An initial population size could be specified using parameter ``initSize`` for a demographic model with dynamic initial population size. If a filename is specified and if matplotlib is available, this function draws a figure to depict the demographic model and save it to ``filename``. An optional ``title`` could be specified to the figure. Note that this function can not be plot demographic models that works for particular mating schemes (e.g. genotype dependent).''' if not self.init_size: if initSize: self.init_size = initSize else: raise ValueError('Specific self does not have a valid initial population size') if filename and not has_plotter: raise RuntimeError('This function requires module numpy and matplotlib') self.draw_figure = filename and has_plotter self.pop_regions = OrderedDict() self.pop_base = OrderedDict() # self._reset() if title: print(title) pop = Population(self.init_size, infoFields=self.info_fields, ploidy=1) pop.evolve( matingScheme=RandomSelection(subPopSize=self), postOps=PyOperator(self._recordPopSize), gen=self.num_gens ) self._recordPopSize(pop) # if self.draw_figure: fig = plt.figure() ax = fig.add_subplot(111) ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') for name, region in self.pop_regions.items(): region = region.reshape(region.size / 4, 4) points = np.append(region[:, 0:2], region[::-1, 2:4], axis=0) plt.fill(points[:,0], points[:,1], label=name, linewidth=0, edgecolor='w') leg = plt.legend(loc=2) leg.draw_frame(False) if title: plt.title(title) plt.savefig(filename) plt.close()
def calculate_additive_trait(pop: sim.Population, trait_information_field: str, allele_effects_array: np.ndarray): """ Calculates additive trait ``trait_information_field`` by summing allele effects at each qtl. :param pop: :param trait_information_field: :param allele_effects_array: :return: """ for ind in pop.individuals(): ind.setInfo( sum(allele_effects_array[range(pop.totNumLoci()), np.asarray(ind.genotype(ploidy=0))] + allele_effects_array[range(pop.totNumLoci()), np.asarray(ind.genotype(ploidy=1))]), trait_information_field)
def meta_population_information_writer(meta_pop: sim.Population, info_field_list: list, filename: str): """ Writes information equivalent to a simuPOP.utils Exporter; however, this function is much more flexible. I am uncertain of what information will be necessary in the future. :param info_field_list: List of information fields to be included in output file. :param filename: Name of output file. :return: CSV File 'filename' """ for i in range(meta_pop.numSubPop()): full_filename = filename + "_" + str(i) + ".txt" with open(full_filename, 'w') as info: info_writer = csv.writer(info, delimiter=',') info_writer.writerow(info_field_list) for ind in meta_pop.individuals(i): info_writer.writerow( [ind.ind_id, ind.mother_id, ind.father_id, ind.ge, ind.pe])
def _generate_f_two(self, pop: sim.Population) -> sim.Population: """ Creates an F2 subpopulations generation by selfing the individuals of 'pop'. Works on a population with one or more subpopulations. """ pop.vars()['generations'][2] = 'F_2' self.odd_to_even(pop) num_sub_pops = pop.numSubPop() progeny_per_individual = int(self.selected_population_size/2) print("Creating the F_two population.") return pop.evolve( preOps=[ sim.MergeSubPops(), sim.PyEval(r'"Generation: %d\n" % gen'), operators.CalcTripletFreq(), sim.PyExec('triplet_freq[gen]=tripletFreq'), sim.SplitSubPops(sizes=[1]*num_sub_pops, randomize=False), ], matingScheme=sim.SelfMating(subPopSize=[progeny_per_individual] * num_sub_pops, numOffspring=progeny_per_individual, ops=[sim.Recombinator(rates=0.01), sim.IdTagger(), sim.PedigreeTagger()], ), gen=1, )
def _mate_and_merge(self, pop: sim.Population): starting_gen = pop.vars()['gen'] print("Initiating recombinatorial convergence at generation: %d" % pop.dvars().gen) while pop.numSubPop() > 1: pop.vars()['generations'][pop.vars()['gen']] = 'IG'+str(pop.vars()['gen'] - starting_gen) self.pop_halver(pop) self.odd_to_even(pop) self.pairwise_merge_protocol(pop) sub_pop_sizes = list(pop.subPopSizes()) pop.evolve( preOps=[ sim.MergeSubPops(), sim.PyEval(r'"Generation: %d\n" % gen'), operators.CalcTripletFreq(), sim.PyExec('triplet_freq[gen]=tripletFreq'), sim.SplitSubPops(sizes=sub_pop_sizes, randomize=False), ], matingScheme=sim.RandomMating(ops=[sim.Recombinator(rates=0.01), sim.IdTagger(), sim.PedigreeTagger()]), gen=1, )
def find_minor_alleles(pop: sim.Population): minor_allele_frequencies = col.OrderedDict() minor_alleles = np.empty(pop.totNumLoci()) for locus in range(pop.totNumLoci()): if len(list(pop.dvars().alleleFreq[locus].keys())) >= 2: minor_allele_frequencies[locus] = min( pop.dvars().alleleFreq[locus].values()) for k in pop.dvars().alleleFreq[locus].keys(): if pop.dvars( ).alleleFreq[locus][k] == minor_allele_frequencies[locus]: minor_alleles[locus] = k elif len(list(pop.dvars().alleleFreq[locus].keys())) == 1: # If an allele is at fixation then we want to show a zero for the MAC format. minor_alleles[locus] = 7 return minor_alleles
def population_information_writer(pop: sim.Population, info_field_list: list, filename: str): """ Writes information equivalent to a simuPOP.utils Exporter; however, this function is much more flexible. I am uncertain of what information will be necessary in the future. :param pop: sim.Population :param info_field_list: List of information fields to be included in output file. :param filename: Name of output file. :return: CSV File 'filename' """ with open(filename, 'w') as info: info_writer = csv.writer(info, delimiter=',') info_writer.writerow(info_field_list) for ind in pop.individuals(): info_writer.writerow([ ind.ind_id, ind.mother_id, ind.father_id, ind.ge, ind.pe, ind.fitness, ind.genotype() ])
def write_info_fields_to_file(pop: sim.Population, info_fields: list, output_filename: str, fmt_string): """ Utilize numpy's simple numpy.savetxt function to write various types of pop.IndInfo(info_string) to files. Superior solution to using csv.writer's for simple .txt output. + Example ---------- pop.infoFields() = ('ind_id', 'ge', 'pe') info_fields = ['ind_id', 'ge', 'pe'] info_array = np.array([pop.indInfo(info) for info in info_fields]) np.savetxt(output_filename, info_array, delimiter='\t', newline='\n', header=">Generation: pop.dvars().gen", comments='') """ info_array = np.array([pop.indInfo(info) for info in info_fields]).T np.savetxt(output_filename, info_array, fmt='%d\t%.2f\t%.2f', delimiter='\t', newline='\n', header=">Generation: 0\nID\tG\tP", comments='')
# Copyright (C) 2004 - 2010 Bo Peng ([email protected]) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # This script is an example in the simuPOP user's guide. Please refer to # the user's guide (http://simupop.sourceforge.net/manual) for a detailed # description of this example. # from simuPOP import InitGenotype, Population def initGenotype(pop, *args, **kwargs): InitGenotype(*args, **kwargs).apply(pop) pop = Population(1000, loci=[2, 3]) initGenotype(pop, freq=[.2, .3, .5])
def table_for_development(prefounders: sim.Population, founders: list, pop: sim.Population, replicate_type: str): """ Function to generate a summary data table for population subjected to either drift or selection. :param prefounders: Population from which all populations are derived :param founders: List of integers specifying which prefounders to use in making a population :param pop: Population subjected to either drift or selection :param replicate_type: String either 'drift' or 'selection' reflecting whether 'pop' is subjected to drift or selection :return: hierarchically indexed pandas.DataFrame with frequency and effect data for all qtl """ data = [] columns = [ 'QTL', 'Chromosome', 'cM_Position', 'Singlet', 'SingletEffect', 'SingletFrequency', 'Triplet', 'TripletEffect', 'NumberOfFounders' ] generational_columns = [ pop.dvars().generations[i] for i in range(pop.dvars().gen) ] columns.extend(generational_columns) chromosomes, relative_positions = chromosome_abs_and_rel(pop) qtls = [] stf = test_subloci_calc_freq(prefounders, pop) for i in range(len(pop.dvars().properQTL)): qtls.append(prefounders.dvars().properQTL[i] - 1) qtls.append(prefounders.dvars().properQTL[i]) qtls.append(prefounders.dvars().properQTL[i] + 1) for qtl in pop.dvars().properQTL: for trip in sorted(list(pop.vars()['triplet_freq'][0][qtl].keys())): for i in range(3): datarow = [ qtl, # locus chromosomes[qtl], # chromosome of locus relative_positions[qtl] + index_to_cM(i), # position in cM trip[i], # singlet pop.dvars().alleleEffects[qtl + i - 1, int(trip[i])], # singlet effect stf[qtl, qtl + i - 1][trip[i]], # singlet frequency trip, # triplet sum([ pop.dvars().alleleEffects[ qtl - 1, int(trip[0])], # triplet effect pop.dvars().alleleEffects[qtl, int(trip[1])], pop.dvars().alleleEffects[qtl + 1, int(trip[2])] ]), len(founders) ] # number of founders selected from prefounders frq_per_gen = [ pop.vars()['triplet_freq'][j][qtl][trip] for j in range(8) ] rep_frq_per_gen = [ pop.vars()[replicate_type + '_triplet_freq'][k][qtl][trip] for k in range(8, pop.dvars().gen) ] frq_per_gen.extend(rep_frq_per_gen) datarow.extend(frq_per_gen) data.append(datarow) s = pd.DataFrame(data, columns=columns) for i in range(8, 13): for term in pop.dvars().mav_terms: s.set_value(term, pop.dvars().generations[i], pop.dvars().mavs[i, term]) return s.fillna(0)