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,
Aren't you supposed to use simuPOP.utils.export
instead of simuPOP.export
?
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).