BoPeng/simuPOP

How to export my simulation after saveCSV got deprecated?

Closed this issue · 2 comments

Dear Dr Peng,

I don't know if my doubt is due to my beginner knowledge in Python, so I apologize if I'm wasting your time in regards to this.
My question is: how do I export my simulation after I evolve my population, since simuPOP.saveCSV is deprecated?
I've been trying:

sim.utils.Exporter(format = 'csv', pop, filename="pop.csv")
and

sim.export(pop, filename="pop.csv",
                  infoFields=['ind_id', 'sex', 'allele1', 'allele2'],
                  sexFormatter ={1:'M', 2:'F'})

But both functions give me the error:

AttributeError: module 'simuPOP' has no attribute 'export'

I don't understand how to implement the " Please use export(format='csv') instead." suggested in the documentation.

Thank you so much for your time, it's much appreciated.
My full code follows below, in case you need it.

import simuPOP as sim
pop_size = 58

pop = sim.Population(size=pop_size, 
                     loci=[1]*2, #Time it by 2 because there are two types of chromosomes 
                     ancGen=2, #Number of the most recent ancestral generations 
                     #to keep during evolution, i.e., ancGen=2 keep parental and
                     #grandparental generations coexisting with the newest one.
                     infoFields=['sex', 'ind_id', 'allele1', 'allele2', 'wintering_grounds'],
                     chromTypes=[sim.AUTOSOME, sim.MITOCHONDRIAL])

# Read mitochondrial haplotypes Dirichlet distribution from the file:
with open('mtDNA_1.txt', 'r') as data_file:
    allele_data = data_file.readlines()
    for i, line in enumerate(allele_data):
        ind = pop.individual(i)
        ind.ind_id = i

        # Split the line into columns based on tabs
        columns = line.strip().split('\t')

        # Check the number of columns
        if len(columns) != 2:
            print(f"Error: Line '{line}' does not contain two columns separated by a tab.")
        
        # Check if the columns are valid decimal numbers
        try:
            float(columns[0])
            float(columns[1])
        except ValueError:
            print(f"Error: Line '{line}' contains non-numeric values.")

print("Data validation complete.") #Tidy code to check if the data was nicely added.

# Create a function to add these 'allele1' and 'allele2' attributes based on the mtDNA_1.txt file
def init_alleles(ind):
    # Convert ind.ind_id to an integer
    ind_id = int(ind.ind_id)
    # Split the data (e.g., using tab as the delimiter)
    data = allele_data[ind_id].strip().split('\t')

    print(f"Read data for individual {ind_id}: {data}")

    # Transform the decimal values into 0 or 1 based on the criteria
    allele1 = 0 if float(data[0]) < 0.01 else 1
    allele2 = 0 if float(data[1]) < 0.01 else 1

    # Assign data to the 'allele1' and 'allele2' attributes
    ind.allele1 = allele1
    ind.allele2 = allele2

# Determine the number of males and females
num_males = pop_size // 2  # Half of the population
num_females = pop_size - num_males

# Shuffle a list of indices to randomize the selection
indices = list(range(pop_size))
random.shuffle(indices)

# Initialize the 'sex' field for individuals based on the randomized indices
for i, ind in enumerate(pop.individuals()):
    if i in indices[:num_males]:
        ind.setSex(sim.MALE)
    else:
        ind.setSex(sim.FEMALE)

# Iterate through the population and print the sex of each individual
for ind in pop.individuals():
    if ind.sex() == sim.MALE:
        print(f"Individual {ind.ind_id}: Male")
    elif ind.sex() == sim.FEMALE:
        print(f"Individual {ind.ind_id}: Female")
    else:
        print(f"Individual {ind.ind_id}: Unknown sex")

#Does it truly have 29 of each? Count them:
# Initialize counters for males and females
male_count = 0
female_count = 0

# Iterate through the population and count males and females
for ind in pop.individuals():
    if ind.sex() == sim.MALE:
        male_count += 1
    elif ind.sex() == sim.FEMALE:
        female_count += 1

print(f"Number of males: {male_count}")
print(f"Number of females: {female_count}")

## Perfect!
# Now, add the wintering grounds:
wintering_grounds = ("Mainland", "AklIsland", "CblIsland")

# simuPOP didn't allow strings, only values. So I'll consider:
    # Mailand = 1
    # AklIsland = 2
    # CblIsland = 3
    
# List of integer values for "wintering_grounds"
wintering_grounds_values = [1, 2, 3]

# Iterate through individuals and assign random integer values to the infoField
for ind in pop.individuals():
    random_value = random.choice(wintering_grounds_values)
    ind.wintering_grounds = random_value

# Verify the values are assigned
for ind in pop.individuals():
    print(f"Individual {ind.ind_id}: wintering_grounds = {ind.wintering_grounds}")

# Initialize a dictionary to store the counts
wintering_ground_counts = {1: 0, 2: 0, 3: 0}

# Count individuals for each wintering ground
for ind in pop.individuals():
    wintering_ground = ind.wintering_grounds
    wintering_ground_counts[wintering_ground] += 1

# Define a dictionary to map wintering ground values to names
wintering_ground_names = {1: "Mainland", 2: "AklIsland", 3: "CblIsland"}

# Print the counts with names
for wintering_ground, count in wintering_ground_counts.items():
    print(f"Wintering Ground {wintering_ground_names[wintering_ground]}: Count = {count}")

#Great! Now, off to the simulation:

pop.evolve(
    initOps=[
        sim.InitSex(1- male_ratio, male_ratio), #sets the sex ratio in the population
        sim.InitGenotype(freq=[0.25]*4) # each of the 4 alleles have a 0.25 frequency
    ],
    #preOps=[
     #   sim.MapSelector(loci=[0, 1], fitness=fitness_values)
    #],
    matingScheme=sim.RandomMating(ops= [
        sim.Recombinator(rates=0.1), #10% recombination rate among adjacent loci
        sim.MitochondrialGenoTransmitter(), #makes sure mtDNA is transmitted
    ]),
    postOps=[
        sim.Stat(alleleFreq=[0, 1], step=10), #calculates the allele frequency every
        #10 generations to calculate the changes over time
        sim.PyEval(r'"%.2f %.2f %.2f %.2f\n" % (alleleNum[0][0],' ## this step
                   ## prints the allele frequencies for loci 0 and 1 at each 10 years
                   'alleleNum[0][1], alleleNum[1][0], alleleNum[1][1])', step=10),
    ],
    gen = 100
)

Kind regards from Aotearoa New Zealand,

BoPeng commented

Aren't you supposed to use simuPOP.utils.export instead of simuPOP.export?

BoPeng commented

Also, sim.utils.Exporter(format = 'csv', pop, filename="pop.csv") is wrong since Exporter is an operator, which is supposed to be used during evolve in parameters such as postOps without pop (pop is passed when the operator is called at each generation).