# A simple calculator to calculate the frequency of a recessive allele

It's based on the Hardy-Weinberg formula. I used the easygui module because I don't fully understand events in Tkinter yet. It's my first relatively useful script so any constructive criticism would be helpful.

from __future__ import division
import sys
from easygui import *
def calculate_frequency(recessive,total):
q = (recessive/total)**0.5 #square root of q^2
p = 1-q #since p + q = 1, p = 1-q
hzDominantNum = round((p**2)*total,2) #number of homozygous dominant, not percent
hzRecessiveNum = round((q**2)*total,2)
heterozygousNum = round((2*p*q)*total,2)
hzDominantFreq = round((p**2)*100,2) #frequency (percent)
hzRecessiveFreq = round((q**2)*100,2)
heterozygousFreq = round((2*p*q)*100,2)
return hzDominantNum,hzRecessiveNum,heterozygousNum,hzDominantFreq,hzRecessiveFreq,heterozygousFreq #returns all calculations to be printed
while True: #loops program until terminated
msg = "Leave Total as 100 if you want to enter the percent." #main message lets user know how to input as percent
fieldNames = ["How many have the recessive trait","Total population"]
fieldValues = ['',100] #first one is blank, the second is defaulted to 100 to make inputing percents easier
test = 0 #tests if the proper information has been entered. Test will equal 1 if the conditions are met.
while test == 0:
fieldValues = multenterbox(msg=msg, title='Enter information about the population', fields=fieldNames, values=fieldValues)
if fieldValues == None: sys.exit() #None is returned when the user clicks "Cancel"
elif not fieldValues[0].isdigit() or not fieldValues[1].isdigit():
if not ccbox("Please fill out all fields.",'ERROR',('OK','Quit')): sys.exit()
elif int(fieldValues[0])>int(fieldValues[1]):
if not ccbox("The amount of people with the recessive trait can't be bigger than the total population.",'ERROR',('OK','Quit')): sys.exit()
else: test=1
recessive = int(fieldValues[0])
total = int(fieldValues[1])

hzDominantNum,hzRecessiveNum,heterozygousNum,hzDominantFreq,hzRecessiveFreq,heterozygousFreq = calculate_frequency(recessive,total)
#displays all the information
msg = str(hzDominantNum)+'/'+str(total)+' ('+str(hzDominantFreq)+'%) are normal (homozygous dominant).\n'+'''
'''+str(heterozygousNum)+'/'+str(total)+' ('+str(heterozygousFreq)+'%) are carriers (heterozygous).\n'+'''
'''+str(hzRecessiveNum)+'/'+str(total)+' ('+str(hzRecessiveFreq)+'%) have the recessive trait (homozygous recessive).'
#sees if user wants to quit or continue
if not ccbox(msg=msg, title='RESULTS', choices=('Continue', 'Quit'), image=None): sys.exit()


Some suggestions:

• call variables this_way not thisWay
• put your interaction with user into separate functions
• if code will be splited properly you will be able to user return and while True: instead of test variable
• return object or dict from calculate_frequency rather than long tuple
• don't create strings like that:

str(hzDominantNum)+'/'+str(total)+' ('+str(hzDominantFreq)+'%) are normal (homozygous dominant).\n'

this is mutch better:

'%f/%f (%d%%) are normal (homozygous dominant).\n' % (hzDominantNum, total, hzDominantFreq)


if you have to run this as a program do it this way:

def main():
print "test"

if __name__ == "__main__":
main()

• Good advice. What exactly is the purpose of adding a main loop if I want to run it as a program? Aug 21, 2012 at 0:21
• that's not a main loop, but the if __name__ == "__main__": entrypoint is used so that you can also reuse module.calculate_frequency from another file later if you want to; this also makes it much easier to write unit tests Aug 21, 2012 at 13:47

Whitespace!
1 + 1 and not 1+1
value, value and not value,value

Blank lines after imports, loops, function definitions and after five lines of code without (just kidding about the latter)

Break your lines if they're getting too long (http://www.python.org/dev/peps/pep-0008/#maximum-line-length)

And generally have a look at PEP8