Added the Height trait to the Create Genetic Models utility.

This commit is contained in:
Simon Sarasova 2024-08-07 07:45:31 +00:00
parent d538afc7a2
commit fe754cb6a2
No known key found for this signature in database
GPG key ID: EEDA4103C9C36944
21 changed files with 861 additions and 199 deletions

View file

@ -6,6 +6,7 @@ Small and insignificant changes may not be included in this log.
## Unversioned Changes ## Unversioned Changes
* Added the Height trait to the Create Genetic Models utility. - *Simon Sarasova*
* Added LocusIsPhased information to the local user profile creation process. - *Simon Sarasova* * Added LocusIsPhased information to the local user profile creation process. - *Simon Sarasova*
* Added the Height trait the traits package. Migrated locus metadata from json encoding to gob encoding. - *Simon Sarasova* * Added the Height trait the traits package. Migrated locus metadata from json encoding to gob encoding. - *Simon Sarasova*
* Upgraded Fyne to version 2.5.0. - *Simon Sarasova* * Upgraded Fyne to version 2.5.0. - *Simon Sarasova*

View file

@ -9,4 +9,4 @@ Many other people have written code for modules which are imported by Seekia. Th
Name | Date Of First Commit | Number Of Commits Name | Date Of First Commit | Number Of Commits
--- | --- | --- --- | --- | ---
Simon Sarasova | June 13, 2023 | 270 Simon Sarasova | June 13, 2023 | 271

View file

@ -26,19 +26,19 @@ func ApplyCartoonEffect(inputImage image.Image, effectStrength int)(image.Image,
} }
blurKernelSize, err := helpers.ScaleNumberProportionally(true, effectStrength, 0, 100, 1, 3) blurKernelSize, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 1, 3)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
if (blurKernelSize % 2 == 0){ if (blurKernelSize % 2 == 0){
blurKernelSize += 1 blurKernelSize += 1
} }
edgeThreshold, err := helpers.ScaleNumberProportionally(false, effectStrength, 0, 100, 5, 200) edgeThreshold, err := helpers.ScaleIntProportionally(false, effectStrength, 0, 100, 5, 200)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
oilFilterSize, err := helpers.ScaleNumberProportionally(true, effectStrength, 0, 100, 5, 20) oilFilterSize, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 5, 20)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
oilLevels, err := helpers.ScaleNumberProportionally(true, effectStrength, 0, 100, 1, 3) oilLevels, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 1, 3)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
options := CTOpts{ options := CTOpts{
@ -78,7 +78,7 @@ func ApplyPencilEffect(inputImage image.Image, effectStrength int)(image.Image,
goeffectsImageObject, err := convertGolangImageObjectToGoeffectsImageObject(inputImage) goeffectsImageObject, err := convertGolangImageObjectToGoeffectsImageObject(inputImage)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
blurAmount, err := helpers.ScaleNumberProportionally(true, effectStrength, 0, 100, 1, 20) blurAmount, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 1, 20)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
if (blurAmount % 2 == 0) { if (blurAmount % 2 == 0) {
@ -119,7 +119,7 @@ func ApplyWireframeEffect(inputImage image.Image, effectStrength int, lightMode
grayscaleGoeffectsImage, err := grayscaleEffectObject.Apply(&goeffectsImageObject, 5) grayscaleGoeffectsImage, err := grayscaleEffectObject.Apply(&goeffectsImageObject, 5)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
threshold, err := helpers.ScaleNumberProportionally(false, effectStrength, 0, 100, 10, 100) threshold, err := helpers.ScaleIntProportionally(false, effectStrength, 0, 100, 10, 100)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
sobelEffectObject := NewSobel(threshold, lightMode) sobelEffectObject := NewSobel(threshold, lightMode)
@ -146,10 +146,10 @@ func ApplyOilPaintingEffect(inputImage image.Image, effectStrength int)(image.Im
return inputImage, nil return inputImage, nil
} }
filterSize, err := helpers.ScaleNumberProportionally(true, effectStrength, 0, 100, 10, 30) filterSize, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 10, 30)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
levels, err := helpers.ScaleNumberProportionally(true, effectStrength, 0, 100, 10, 70) levels, err := helpers.ScaleIntProportionally(true, effectStrength, 0, 100, 10, 70)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
oilPaintingEffectObject := NewOilPainting(filterSize, levels) oilPaintingEffectObject := NewOilPainting(filterSize, levels)

View file

@ -40,7 +40,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
person1PrepareRawGenomesUpdatePercentageCompleteFunction := func(newPercentage int)error{ person1PrepareRawGenomesUpdatePercentageCompleteFunction := func(newPercentage int)error{
newPercentageCompletion, err := helpers.ScaleNumberProportionally(true, newPercentage, 0, 100, 0, 25) newPercentageCompletion, err := helpers.ScaleIntProportionally(true, newPercentage, 0, 100, 0, 25)
if (err != nil){ return err } if (err != nil){ return err }
err = updatePercentageCompleteFunction(newPercentageCompletion) err = updatePercentageCompleteFunction(newPercentageCompletion)
@ -49,8 +49,18 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
return nil return nil
} }
person1GenomesWithMetadataList, allPerson1RawGenomeIdentifiersList, person1HasMultipleGenomes, person1OnlyExcludeConflictsGenomeIdentifier, person1OnlyIncludeSharedGenomeIdentifier, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(person1GenomesList, person1PrepareRawGenomesUpdatePercentageCompleteFunction) anyUsefulLocationsExist, person1GenomesWithMetadataList, allPerson1RawGenomeIdentifiersList, person1HasMultipleGenomes, person1OnlyExcludeConflictsGenomeIdentifier, person1OnlyIncludeSharedGenomeIdentifier, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(person1GenomesList, person1PrepareRawGenomesUpdatePercentageCompleteFunction)
if (err != nil) { return false, "", err } if (err != nil) { return false, "", err }
if (anyUsefulLocationsExist == false){
// We should have checked for this when genomes were first imported.
return false, "", errors.New("CreateCoupleGeneticAnalysis called with person1GenomesList that does not contain any useful genomes")
}
if (len(person1GenomesList) > 1 && (len(person1GenomesList) != (len(person1GenomesWithMetadataList)-2)) ){
// If there is more than 1 genome, 2 combined genomes are created
// We are checking to make sure that none of the input genomes were dropped due to not having any locations
// We should have checked to make sure each input genome has useful locations when each genome was first imported.
return false, "", errors.New("CreateCoupleGeneticAnalysis called with person1GenomesList containing at least 1 genome without useful locations.")
}
processIsStopped := checkIfProcessIsStopped() processIsStopped := checkIfProcessIsStopped()
if (processIsStopped == true){ if (processIsStopped == true){
@ -59,7 +69,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
person2PrepareRawGenomesUpdatePercentageCompleteFunction := func(newPercentage int)error{ person2PrepareRawGenomesUpdatePercentageCompleteFunction := func(newPercentage int)error{
newPercentageCompletion, err := helpers.ScaleNumberProportionally(true, newPercentage, 0, 100, 25, 50) newPercentageCompletion, err := helpers.ScaleIntProportionally(true, newPercentage, 0, 100, 25, 50)
if (err != nil){ return err } if (err != nil){ return err }
err = updatePercentageCompleteFunction(newPercentageCompletion) err = updatePercentageCompleteFunction(newPercentageCompletion)
@ -68,8 +78,18 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
return nil return nil
} }
person2GenomesWithMetadataList, allPerson2RawGenomeIdentifiersList, person2HasMultipleGenomes, person2OnlyExcludeConflictsGenomeIdentifier, person2OnlyIncludeSharedGenomeIdentifier, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(person2GenomesList, person2PrepareRawGenomesUpdatePercentageCompleteFunction) anyUsefulLocationsExist, person2GenomesWithMetadataList, allPerson2RawGenomeIdentifiersList, person2HasMultipleGenomes, person2OnlyExcludeConflictsGenomeIdentifier, person2OnlyIncludeSharedGenomeIdentifier, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(person2GenomesList, person2PrepareRawGenomesUpdatePercentageCompleteFunction)
if (err != nil) { return false, "", err } if (err != nil) { return false, "", err }
if (anyUsefulLocationsExist == false){
// We should have checked for this when genomes were first imported.
return false, "", errors.New("CreateCoupleGeneticAnalysis called with person2GenomesList that does not contain any useful genomes")
}
if (len(person2GenomesList) > 1 && (len(person2GenomesList) != (len(person2GenomesWithMetadataList)-2)) ){
// If there is more than 1 genome, 2 combined genomes are created
// We are checking to make sure that none of the input genomes were dropped due to not having any locations
// We should have checked to make sure each input genome has useful locations when each genome was first imported.
return false, "", errors.New("CreateCoupleGeneticAnalysis called with person2GenomesList containing at least 1 genome without useful locations.")
}
processIsStopped = checkIfProcessIsStopped() processIsStopped = checkIfProcessIsStopped()
if (processIsStopped == true){ if (processIsStopped == true){
@ -936,7 +956,7 @@ func GetOffspringPolygenicDiseaseInfo_Fast(diseaseLociList []polygenicDiseases.D
offspringMaximumPossibleRiskWeightSum += locusMaximumWeight offspringMaximumPossibleRiskWeightSum += locusMaximumWeight
} }
offspringAverageDiseaseRiskScore, err := helpers.ScaleNumberProportionally(true, offspringSummedRiskWeights, offspringMinimumPossibleRiskWeightSum, offspringMaximumPossibleRiskWeightSum, 0, 10) offspringAverageDiseaseRiskScore, err := helpers.ScaleIntProportionally(true, offspringSummedRiskWeights, offspringMinimumPossibleRiskWeightSum, offspringMaximumPossibleRiskWeightSum, 0, 10)
if (err != nil) { return false, 0, 0, err } if (err != nil) { return false, 0, 0, err }
if (numberOfLociTested == 0){ if (numberOfLociTested == 0){
@ -1061,7 +1081,7 @@ func GetOffspringPolygenicDiseaseInfo(diseaseLociList []polygenicDiseases.Diseas
offspringMaximumPossibleRiskWeightSum += locusMaximumWeight offspringMaximumPossibleRiskWeightSum += locusMaximumWeight
} }
offspringAverageDiseaseRiskScore, err := helpers.ScaleNumberProportionally(true, offspringSummedRiskWeights, offspringMinimumPossibleRiskWeightSum, offspringMaximumPossibleRiskWeightSum, 0, 10) offspringAverageDiseaseRiskScore, err := helpers.ScaleIntProportionally(true, offspringSummedRiskWeights, offspringMinimumPossibleRiskWeightSum, offspringMaximumPossibleRiskWeightSum, 0, 10)
if (err != nil) { return false, 0, 0, nil, nil, err } if (err != nil) { return false, 0, 0, nil, nil, err }
sampleOffspringRiskScoresList = append(sampleOffspringRiskScoresList, offspringAverageDiseaseRiskScore) sampleOffspringRiskScoresList = append(sampleOffspringRiskScoresList, offspringAverageDiseaseRiskScore)

View file

@ -40,7 +40,7 @@ func CreatePersonGeneticAnalysis(genomesList []prepareRawGenomes.RawGenomeWithMe
prepareRawGenomesUpdatePercentageCompleteFunction := func(newPercentage int)error{ prepareRawGenomesUpdatePercentageCompleteFunction := func(newPercentage int)error{
newPercentageCompletion, err := helpers.ScaleNumberProportionally(true, newPercentage, 0, 100, 0, 50) newPercentageCompletion, err := helpers.ScaleIntProportionally(true, newPercentage, 0, 100, 0, 50)
if (err != nil){ return err } if (err != nil){ return err }
err = updatePercentageCompleteFunction(newPercentageCompletion) err = updatePercentageCompleteFunction(newPercentageCompletion)
@ -49,8 +49,18 @@ func CreatePersonGeneticAnalysis(genomesList []prepareRawGenomes.RawGenomeWithMe
return nil return nil
} }
genomesWithMetadataList, allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(genomesList, prepareRawGenomesUpdatePercentageCompleteFunction) anyUsefulLocationsExist, genomesWithMetadataList, allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(genomesList, prepareRawGenomesUpdatePercentageCompleteFunction)
if (err != nil) { return false, "", err } if (err != nil) { return false, "", err }
if (anyUsefulLocationsExist == false){
// We should have checked for this when genomes were first imported.
return false, "", errors.New("CreatePersonGeneticAnalysis called with genomeList containing no genomes with useful locations.")
}
if (len(genomesList) > 1 && (len(genomesList) != (len(genomesWithMetadataList)-2)) ){
// If there is more than 1 genome, 2 combined genomes are created
// We are checking to make sure that none of the input genomes were dropped due to not having any locations
// We should have checked to make sure each input genome has useful locations when each genome was first imported.
return false, "", errors.New("CreatePersonGeneticAnalysis called with genomeList containing at least 1 genome without useful locations.")
}
// This map stores each genome's locus values // This map stores each genome's locus values
// Map Structure: Genome Identifier -> Genome locus values map (rsID -> Locus Value) // Map Structure: Genome Identifier -> Genome locus values map (rsID -> Locus Value)
@ -716,7 +726,7 @@ func GetPersonGenomePolygenicDiseaseInfo(diseaseLociList []polygenicDiseases.Dis
return false, 0, 0, nil, nil return false, 0, 0, nil, nil
} }
diseaseRiskScore, err := helpers.ScaleNumberProportionally(true, summedDiseaseRiskWeight, minimumPossibleRiskWeightSum, maximumPossibleRiskWeightSum, 0, 10) diseaseRiskScore, err := helpers.ScaleIntProportionally(true, summedDiseaseRiskWeight, minimumPossibleRiskWeightSum, maximumPossibleRiskWeightSum, 0, 10)
if (err != nil) { return false, 0, 0, nil, err } if (err != nil) { return false, 0, 0, nil, err }
return true, diseaseRiskScore, numberOfLociTested, genomeLociInfoMap, nil return true, diseaseRiskScore, numberOfLociTested, genomeLociInfoMap, nil

View file

@ -218,7 +218,7 @@ type DiscreteTraitPredictionAccuracyInfoMap map[DiscreteTraitOutcomeInfo]Discret
type DiscreteTraitOutcomeInfo struct{ type DiscreteTraitOutcomeInfo struct{
// This is the outcome which was found // This is the outcome which was predicted
// Example: "Blue" // Example: "Blue"
OutcomeName string OutcomeName string
@ -283,6 +283,65 @@ func DecodeBytesToDiscreteTraitPredictionAccuracyInfoMap(inputBytes []byte)(Disc
return newDiscreteTraitPredictionAccuracyInfoMap, nil return newDiscreteTraitPredictionAccuracyInfoMap, nil
} }
type NumericTraitPredictionAccuracyInfoMap map[NumericTraitOutcomeInfo]NumericTraitPredictionAccuracyRangesMap
type NumericTraitOutcomeInfo struct{
// This is the outcome which was predicted
// Example: 150 centimeters
OutcomeValue float64
// This is a value between 0-100 which describes the percentage of the loci which were tested for the input for the prediction
PercentageOfLociTested int
// This is a value between 0-100 which describes the percentage of the tested loci which were phased for the input for the prediction
PercentageOfPhasedLoci int
}
// Map Structure: Accuracy Percentage (AP) -> Amount needed to deviate from prediction for the value to be accurate (AP)% of the time
// For example, if the model predicted that someone was 150 centimeters tall, how many centimeters would we have to deviate in both directions
// in order for the true outcome to fall into the range 10% of the time, 20% of the time, 30% of the time, etc...
// Example:
// -90%+: 50 centimeters
// If you travel 50 centimeters in both directions from the prediction,
// the true height value will fall into this range 90% of the time.
// -50%+: 20 centimeters
// -10%+: 10 centimeters
type NumericTraitPredictionAccuracyRangesMap map[int]float64
func EncodeNumericTraitPredictionAccuracyInfoMapToBytes(inputMap NumericTraitPredictionAccuracyInfoMap)([]byte, error){
buffer := new(bytes.Buffer)
encoder := gob.NewEncoder(buffer)
err := encoder.Encode(inputMap)
if (err != nil) { return nil, err }
inputMapBytes := buffer.Bytes()
return inputMapBytes, nil
}
func DecodeBytesToNumericTraitPredictionAccuracyInfoMap(inputBytes []byte)(NumericTraitPredictionAccuracyInfoMap, error){
if (inputBytes == nil){
return nil, errors.New("DecodeBytesToNumericTraitPredictionAccuracyInfoMap called with nil inputBytes.")
}
buffer := bytes.NewBuffer(inputBytes)
decoder := gob.NewDecoder(buffer)
var newNumericTraitPredictionAccuracyInfoMap NumericTraitPredictionAccuracyInfoMap
err := decoder.Decode(&newNumericTraitPredictionAccuracyInfoMap)
if (err != nil){ return nil, err }
return newNumericTraitPredictionAccuracyInfoMap, nil
}
//Outputs: //Outputs:
// -bool: Neural network model exists for this trait (trait prediction is possible for this trait) // -bool: Neural network model exists for this trait (trait prediction is possible for this trait)
// -bool: Trait prediction is possible for this user (User has at least 1 known trait locus value) // -bool: Trait prediction is possible for this user (User has at least 1 known trait locus value)
@ -378,7 +437,7 @@ func GetNeuralNetworkDiscreteTraitPredictionFromGenomeMap(traitName string, geno
outputLayer, err := GetNeuralNetworkRawPrediction(&neuralNetworkObject, false, neuralNetworkInput) outputLayer, err := GetNeuralNetworkRawPrediction(&neuralNetworkObject, false, neuralNetworkInput)
if (err != nil) { return false, false, "", 0, 0, 0, err } if (err != nil) { return false, false, "", 0, 0, 0, err }
predictedOutcomeName, err := GetOutcomeNameFromOutputLayer(traitName, false, outputLayer) predictedOutcomeName, err := GetDiscreteOutcomeNameFromOutputLayer(traitName, false, outputLayer)
if (err != nil) { return false, false, "", 0, 0, 0, err } if (err != nil) { return false, false, "", 0, 0, 0, err }
modelTraitAccuracyInfoFile, err := geneticPredictionModels.GetPredictionModelDiscreteTraitAccuracyInfoBytes(traitName) modelTraitAccuracyInfoFile, err := geneticPredictionModels.GetPredictionModelDiscreteTraitAccuracyInfoBytes(traitName)
@ -521,7 +580,7 @@ func GetLociInfoFromNetworkInputLayer(inputLayer []float32)(int, int, int, error
// Outputs: // Outputs:
// -string: Output Name (Example: "Blue") // -string: Output Name (Example: "Blue")
// -error // -error
func GetOutcomeNameFromOutputLayer(traitName string, verifyOutputLayer bool, outputLayer []float32)(string, error){ func GetDiscreteOutcomeNameFromOutputLayer(traitName string, verifyOutputLayer bool, outputLayer []float32)(string, error){
if (verifyOutputLayer == true){ if (verifyOutputLayer == true){
@ -534,7 +593,7 @@ func GetOutcomeNameFromOutputLayer(traitName string, verifyOutputLayer bool, out
} }
// We allow a small amount of inaccuracy due to the imprecise nature of floats. // We allow a small amount of inaccuracy due to the imprecise nature of floats.
if (summedNeurons > 1.1 || summedNeurons < .99){ if (summedNeurons > 1.01 || summedNeurons < .99){
summedNeuronsString := helpers.ConvertFloat32ToString(summedNeurons) summedNeuronsString := helpers.ConvertFloat32ToString(summedNeurons)
return "", errors.New("GetOutcomeNameFromOutputLayer called with layer containing neuron values which don't sum to 1: " + summedNeuronsString) return "", errors.New("GetOutcomeNameFromOutputLayer called with layer containing neuron values which don't sum to 1: " + summedNeuronsString)
} }
@ -607,6 +666,45 @@ func GetOutcomeNameFromOutputLayer(traitName string, verifyOutputLayer bool, out
} }
// This function returns which outcome is being described from a neural network's final output layer
// This is only used for discrete traits
// Outputs:
// -float64: Output Value (example: 150 centimeters)
// -error
func GetNumericOutcomeValueFromOutputLayer(traitName string, outputLayer []float32)(float64, error){
if (len(outputLayer) != 1){
return 0, errors.New("GetNumericOutcomeValueFromOutputLayer called with output layer which is not length of 1")
}
outputNeuron := outputLayer[0]
if (outputNeuron < 0 || outputNeuron > 1){
return 0, errors.New("GetNumericOutcomeValueFromOutputLayer called with output layer contains out-of-bounds neuron")
}
getOutcomeMinAndMax := func()(float64, float64, error){
switch traitName{
case "Height":{
// Shortest person of all time: 54 cm
// Tallest person of all time: 272 cm
return 54, 272, nil
}
}
return 0, 0, errors.New("GetNumericOutcomeValueFromOutputLayer called with unknown traitName: " + traitName)
}
outcomeMin, outcomeMax, err := getOutcomeMinAndMax()
if (err != nil) { return 0, err }
outcomeValue, err := helpers.ScaleFloat64Proportionally(true, float64(outputNeuron), 0, 1, outcomeMin, outcomeMax)
if (err != nil) { return 0, err }
return outcomeValue, nil
}
//Outputs: //Outputs:
// -int: Layer 1 neuron count (input layer) // -int: Layer 1 neuron count (input layer)
// -int: Layer 2 neuron count // -int: Layer 2 neuron count
@ -631,6 +729,11 @@ func getNeuralNetworkLayerSizes(traitName string)(int, int, int, int, error){
// There are 2 output neurons, each representing a tolerance: Tolerant, Intolerant // There are 2 output neurons, each representing a tolerance: Tolerant, Intolerant
return 6, 4, 3, 2, nil return 6, 4, 3, 2, nil
} }
case "Height":{
// There are 3000 input neurons
// There is 1 output neuron, representing a height value
return 3000, 2, 2, 1, nil
}
} }
return 0, 0, 0, 0, errors.New("getNeuralNetworkLayerSizes called with unknown traitName: " + traitName) return 0, 0, 0, 0, errors.New("getNeuralNetworkLayerSizes called with unknown traitName: " + traitName)
@ -682,7 +785,7 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
userPhenotypeDataObject readBiobankData.PhenotypeData_OpenSNP, userPhenotypeDataObject readBiobankData.PhenotypeData_OpenSNP,
userLocusValuesMap map[int64]locusValue.LocusValue)(bool, []TrainingData, error){ userLocusValuesMap map[int64]locusValue.LocusValue)(bool, []TrainingData, error){
if (traitName != "Eye Color" && traitName != "Lactose Tolerance"){ if (traitName != "Eye Color" && traitName != "Lactose Tolerance" && traitName != "Height"){
return false, nil, errors.New("CreateGeneticPredictionTrainingData_OpenSNP called with unknown traitName: " + traitName) return false, nil, errors.New("CreateGeneticPredictionTrainingData_OpenSNP called with unknown traitName: " + traitName)
} }
@ -800,6 +903,27 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
return true, []float32{0, 1}, nil return true, []float32{0, 1}, nil
} }
case "Height":{
userHeightIsKnown := userPhenotypeDataObject.HeightIsKnown
if (userHeightIsKnown == false){
return false, nil, nil
}
userHeight := userPhenotypeDataObject.Height
// Shortest person of all time: 54 cm
// Tallest person of all time: 272 cm
outputValue, err := helpers.ScaleFloat64Proportionally(true, userHeight, 54, 272, 0, 1)
if (err != nil) { return false, nil, err }
outputValueFloat32 := float32(outputValue)
outputLayer := []float32{outputValueFloat32}
return true, outputLayer, nil
}
} }
return false, nil, errors.New("Unknown traitName: " + traitName) return false, nil, errors.New("Unknown traitName: " + traitName)
@ -911,55 +1035,49 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
anyLocusExists = true anyLocusExists = true
getLocusAlleles := func()(string, string){ //Outputs:
// -float32: Final neuron value
// -0 == Value is unknown
// -0.5 == Value is known, phase is unknown
// -1 == Value is known, phase is known
// -string: Allele 1 value
// -string: Allele 2 value
getFirstNeuronAndLocusAlleles := func()(float32, string, string){
locusAllele1 := userLocusValue.Base1Value locusAllele1 := userLocusValue.Base1Value
locusAllele2 := userLocusValue.Base2Value locusAllele2 := userLocusValue.Base2Value
if (randomizePhaseBool == false){ if (locusAllele1 == locusAllele2){
return locusAllele1, locusAllele2 // Locus phase is unimportant
return 1, locusAllele1, locusAllele2
}
locusIsPhased := userLocusValue.LocusIsPhased
if (randomizePhaseBool == false && locusIsPhased == true){
return 1, locusAllele1, locusAllele2
} }
// We randomize the phase of the locus // We randomize the phase of the locus
// We always do this if the locus is not phased, because the genome data might actually be partially/fully phased,
// even if it is not advertised as being phased
randomNumber := pseudorandomNumberGenerator.IntN(2) randomNumber := pseudorandomNumberGenerator.IntN(2)
if (randomNumber == 1){ if (randomNumber == 1){
// This has a 50% chance of being true. // This has a 50% chance of being true.
return locusAllele1, locusAllele2 return 0.5, locusAllele1, locusAllele2
} }
return locusAllele2, locusAllele1 return 0.5, locusAllele2, locusAllele1
} }
locusAllele1, locusAllele2 := getLocusAlleles() locusIsKnownAndPhasedNeuronValue, locusAllele1, locusAllele2 := getFirstNeuronAndLocusAlleles()
locusAllele1NeuronValue, err := convertAlleleToNeuron(locusAllele1) locusAllele1NeuronValue, err := convertAlleleToNeuron(locusAllele1)
if (err != nil){ return false, nil, err } if (err != nil){ return false, nil, err }
locusAllele2NeuronValue, err := convertAlleleToNeuron(locusAllele2) locusAllele2NeuronValue, err := convertAlleleToNeuron(locusAllele2)
if (err != nil) { return false, nil, err } if (err != nil) { return false, nil, err }
getLocusIsKnownAndPhasedNeuronValue := func()float32{
if (locusAllele1 == locusAllele2){
// Phase of locus must be known.
// Swapping the loci would change nothing.
return 1
}
if (randomizePhaseBool == true){
return 0.5
}
locusIsPhased := userLocusValue.LocusIsPhased
if (locusIsPhased == true){
return 1
}
return 0.5
}
locusIsKnownAndPhasedNeuronValue := getLocusIsKnownAndPhasedNeuronValue()
inputLayer = append(inputLayer, locusIsKnownAndPhasedNeuronValue, locusAllele1NeuronValue, locusAllele2NeuronValue) inputLayer = append(inputLayer, locusIsKnownAndPhasedNeuronValue, locusAllele1NeuronValue, locusAllele2NeuronValue)
} }

View file

@ -627,7 +627,7 @@ func StartCreateNewPersonGeneticAnalysis(personIdentifier string)(string, error)
for index, genomeMap := range personGenomesMapList{ for index, genomeMap := range personGenomesMapList{
newPercentageProgress, err := helpers.ScaleNumberProportionally(true, index, 0, finalIndex, 0, 10) newPercentageProgress, err := helpers.ScaleIntProportionally(true, index, 0, finalIndex, 0, 10)
if (err != nil) { return err } if (err != nil) { return err }
err = updatePercentageCompleteFunction(newPercentageProgress) err = updatePercentageCompleteFunction(newPercentageProgress)
@ -665,7 +665,7 @@ func StartCreateNewPersonGeneticAnalysis(personIdentifier string)(string, error)
analysisUpdatePercentageCompleteFunction := func(inputProgress int)error{ analysisUpdatePercentageCompleteFunction := func(inputProgress int)error{
newPercentageProgress, err := helpers.ScaleNumberProportionally(true, inputProgress, 0, 100, 10, 10) newPercentageProgress, err := helpers.ScaleIntProportionally(true, inputProgress, 0, 100, 10, 10)
if (err != nil) { return err } if (err != nil) { return err }
err = updatePercentageCompleteFunction(newPercentageProgress) err = updatePercentageCompleteFunction(newPercentageProgress)
@ -899,7 +899,7 @@ func StartCreateNewCoupleGeneticAnalysis(inputPerson1Identifier string, inputPer
break break
} }
personPercentageComplete, err := helpers.ScaleNumberProportionally(true, processPercentageComplete, 0, 100, personPercentageRangeStart, personPercentageRangeEnd) personPercentageComplete, err := helpers.ScaleIntProportionally(true, processPercentageComplete, 0, 100, personPercentageRangeStart, personPercentageRangeEnd)
if (err != nil) { return err } if (err != nil) { return err }
err = updatePercentageCompleteFunction(personPercentageComplete) err = updatePercentageCompleteFunction(personPercentageComplete)
@ -978,7 +978,7 @@ func StartCreateNewCoupleGeneticAnalysis(inputPerson1Identifier string, inputPer
updateCoupleAnalysisPercentageCompleteFunction := func(newPercentage int)error{ updateCoupleAnalysisPercentageCompleteFunction := func(newPercentage int)error{
personPercentageComplete, err := helpers.ScaleNumberProportionally(true, newPercentage, 0, 100, 74, 100) personPercentageComplete, err := helpers.ScaleIntProportionally(true, newPercentage, 0, 100, 74, 100)
if (err != nil) { return err } if (err != nil) { return err }
err = updatePercentageCompleteFunction(personPercentageComplete) err = updatePercentageCompleteFunction(personPercentageComplete)

View file

@ -68,16 +68,17 @@ func CreateRawGenomeWithMetadataObject(genomeIdentifier [16]byte, rawGenomeStrin
// -[]RawGenomeWithMetadata // -[]RawGenomeWithMetadata
// -func(int)error: Update Percentage Complete Function // -func(int)error: Update Percentage Complete Function
//Outputs: //Outputs:
// -bool: Any useful locations exist in any of the provided genomes
// -[]GenomeWithMetadata: Genomes with metadata list // -[]GenomeWithMetadata: Genomes with metadata list
// -[][16]byte: All raw genome identifiers list (not including combined genomes) // -[][16]byte: All raw genome identifiers list (not including combined genomes)
// -bool: Combined genomes exist // -bool: Combined genomes exist
// -[16]byte: Only exclude conflicts genome identifier // -[16]byte: Only exclude conflicts genome identifier
// -[16]byte: Only include shared genome identifier // -[16]byte: Only include shared genome identifier
// -error // -error
func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWithMetadata, updatePercentageCompleteFunction func(int)error)([]GenomeWithMetadata, [][16]byte, bool, [16]byte, [16]byte, error){ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWithMetadata, updatePercentageCompleteFunction func(int)error)(bool, []GenomeWithMetadata, [][16]byte, bool, [16]byte, [16]byte, error){
if (len(inputGenomesList) == 0){ if (len(inputGenomesList) == 0){
return nil, nil, false, [16]byte{}, [16]byte{}, errors.New("GetGenomesWithMetadataListFromRawGenomesList called with empty inputGenomesList") return false, nil, nil, false, [16]byte{}, [16]byte{}, errors.New("GetGenomesWithMetadataListFromRawGenomesList called with empty inputGenomesList")
} }
// The reading of genomes will take up the first 20% of the percentage range // The reading of genomes will take up the first 20% of the percentage range
@ -87,18 +88,17 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
// Each map stores a genome from a company or a combined genome. // Each map stores a genome from a company or a combined genome.
genomesWithMetadataList := make([]GenomeWithMetadata, 0) genomesWithMetadataList := make([]GenomeWithMetadata, 0)
numberOfGenomesRead := 0 finalIndex := len(inputGenomesList) - 1
totalNumberOfGenomesToRead := len(inputGenomesList)
allRawGenomeIdentifiersList := make([][16]byte, 0) allRawGenomeIdentifiersList := make([][16]byte, 0)
for _, rawGenomeWithMetadataObject := range inputGenomesList{ for index, rawGenomeWithMetadataObject := range inputGenomesList{
newPercentageCompletion, err := helpers.ScaleNumberProportionally(true, numberOfGenomesRead, 0, totalNumberOfGenomesToRead, 0, 20) newPercentageCompletion, err := helpers.ScaleIntProportionally(true, index, 0, finalIndex, 0, 20)
if (err != nil) { return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil) { return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
err = updatePercentageCompleteFunction(newPercentageCompletion) err = updatePercentageCompleteFunction(newPercentageCompletion)
if (err != nil) { return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil) { return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
genomeIdentifier := rawGenomeWithMetadataObject.GenomeIdentifier genomeIdentifier := rawGenomeWithMetadataObject.GenomeIdentifier
genomeIsPhased := rawGenomeWithMetadataObject.GenomeIsPhased genomeIsPhased := rawGenomeWithMetadataObject.GenomeIsPhased
@ -107,12 +107,11 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
// Now we convert rawGenomeMap to a genomeMap // Now we convert rawGenomeMap to a genomeMap
anyValuesExist, genomeMap, err := ConvertRawGenomeToGenomeMap(rawGenomeMap, genomeIsPhased) anyValuesExist, genomeMap, err := ConvertRawGenomeToGenomeMap(rawGenomeMap, genomeIsPhased)
if (err != nil) { return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil) { return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
if (anyValuesExist == false){ if (anyValuesExist == false){
// We have to make sure this never happens so the user isn't confused as to why genomes // This genome is not useful
// that were imported were not included in the analysis // No useful locations exist
// We make sure this doesn't happen by verifying the genome at the time of importing continue
return nil, nil, false, [16]byte{}, [16]byte{}, errors.New("Genome supplied to GetGenomesWithMetadataListFromRawGenomesList has no valid locations.")
} }
genomeWithMetadataObject := GenomeWithMetadata{ genomeWithMetadataObject := GenomeWithMetadata{
@ -123,17 +122,20 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
genomesWithMetadataList = append(genomesWithMetadataList, genomeWithMetadataObject) genomesWithMetadataList = append(genomesWithMetadataList, genomeWithMetadataObject)
allRawGenomeIdentifiersList = append(allRawGenomeIdentifiersList, genomeIdentifier) allRawGenomeIdentifiersList = append(allRawGenomeIdentifiersList, genomeIdentifier)
}
numberOfGenomesRead += 1 if (len(genomesWithMetadataList) == 0){
// None of the provided genomes contained any useful locations
return false, nil, nil, false, [16]byte{}, [16]byte{}, nil
} }
containsDuplicates, _ := helpers.CheckIfListContainsDuplicates(allRawGenomeIdentifiersList) containsDuplicates, _ := helpers.CheckIfListContainsDuplicates(allRawGenomeIdentifiersList)
if (containsDuplicates == true){ if (containsDuplicates == true){
return nil, nil, false, [16]byte{}, [16]byte{}, errors.New("GetGenomesWithMetadataListFromRawGenomesList called with inputGenomesList containing duplicate genomeIdentifiers.") return false, nil, nil, false, [16]byte{}, [16]byte{}, errors.New("GetGenomesWithMetadataListFromRawGenomesList called with inputGenomesList containing duplicate genomeIdentifiers.")
} }
err := updatePercentageCompleteFunction(20) err := updatePercentageCompleteFunction(20)
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil){ return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
if (len(genomesWithMetadataList) <= 1){ if (len(genomesWithMetadataList) <= 1){
@ -141,9 +143,9 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
// No genome combining is needed. // No genome combining is needed.
err = updatePercentageCompleteFunction(100) err = updatePercentageCompleteFunction(100)
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil){ return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
return genomesWithMetadataList, allRawGenomeIdentifiersList, false, [16]byte{}, [16]byte{}, nil return true, genomesWithMetadataList, allRawGenomeIdentifiersList, false, [16]byte{}, [16]byte{}, nil
} }
// Now we create the shared genomes // Now we create the shared genomes
@ -156,15 +158,15 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
// This map stores all RSIDs across all genomes // This map stores all RSIDs across all genomes
allRSIDsMap := make(map[int64]struct{}) allRSIDsMap := make(map[int64]struct{})
finalIndex := len(genomesWithMetadataList) - 1 finalIndex = len(genomesWithMetadataList) - 1
for index, genomeWithMetadataObject := range genomesWithMetadataList{ for index, genomeWithMetadataObject := range genomesWithMetadataList{
newPercentageCompletion, err := helpers.ScaleNumberProportionally(true, index, 0, finalIndex, 20, 50) newPercentageCompletion, err := helpers.ScaleIntProportionally(true, index, 0, finalIndex, 20, 50)
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil){ return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
err = updatePercentageCompleteFunction(newPercentageCompletion) err = updatePercentageCompleteFunction(newPercentageCompletion)
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil){ return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
genomeMap := genomeWithMetadataObject.GenomeMap genomeMap := genomeWithMetadataObject.GenomeMap
@ -185,11 +187,11 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
for rsID, _ := range allRSIDsMap{ for rsID, _ := range allRSIDsMap{
newPercentageCompletion, err := helpers.ScaleNumberProportionally(true, index, 0, finalIndex, 50, 100) newPercentageCompletion, err := helpers.ScaleIntProportionally(true, index, 0, finalIndex, 50, 100)
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil){ return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
err = updatePercentageCompleteFunction(newPercentageCompletion) err = updatePercentageCompleteFunction(newPercentageCompletion)
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil){ return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
index += 1 index += 1
@ -200,7 +202,7 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
} }
anyAliasesExist, rsidAliasesList, err := locusMetadata.GetRSIDAliases(rsID) anyAliasesExist, rsidAliasesList, err := locusMetadata.GetRSIDAliases(rsID)
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil){ return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
if (anyAliasesExist == true){ if (anyAliasesExist == true){
for _, rsidAlias := range rsidAliasesList{ for _, rsidAlias := range rsidAliasesList{
@ -386,7 +388,7 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
} }
locusBase1, locusBase2, phaseIsKnown_OnlyExcludeConflicts, phaseIsKnown_OnlyIncludeShared, err := getLocusBasePair() locusBase1, locusBase2, phaseIsKnown_OnlyExcludeConflicts, phaseIsKnown_OnlyIncludeShared, err := getLocusBasePair()
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil){ return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
// Now we add to the combined genome maps // Now we add to the combined genome maps
// The OnlyExcludeConflicts will only omit when there is a tie // The OnlyExcludeConflicts will only omit when there is a tie
@ -436,7 +438,7 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
} }
onlyExcludeConflictsGenomeIdentifier, err := helpers.GetNewRandom16ByteArray() onlyExcludeConflictsGenomeIdentifier, err := helpers.GetNewRandom16ByteArray()
if (err != nil) { return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil) { return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
onlyExcludeConflictsGenomeWithMetadataObject := GenomeWithMetadata{ onlyExcludeConflictsGenomeWithMetadataObject := GenomeWithMetadata{
GenomeType: "OnlyExcludeConflicts", GenomeType: "OnlyExcludeConflicts",
@ -445,7 +447,7 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
} }
onlyIncludeSharedGenomeIdentifier, err := helpers.GetNewRandom16ByteArray() onlyIncludeSharedGenomeIdentifier, err := helpers.GetNewRandom16ByteArray()
if (err != nil) { return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil) { return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
onlyIncludeSharedGenomeWithMetadataObject := GenomeWithMetadata{ onlyIncludeSharedGenomeWithMetadataObject := GenomeWithMetadata{
GenomeType: "OnlyIncludeShared", GenomeType: "OnlyIncludeShared",
@ -456,9 +458,9 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
genomesWithMetadataList = append(genomesWithMetadataList, onlyExcludeConflictsGenomeWithMetadataObject, onlyIncludeSharedGenomeWithMetadataObject) genomesWithMetadataList = append(genomesWithMetadataList, onlyExcludeConflictsGenomeWithMetadataObject, onlyIncludeSharedGenomeWithMetadataObject)
err = updatePercentageCompleteFunction(100) err = updatePercentageCompleteFunction(100)
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err } if (err != nil){ return false, nil, nil, false, [16]byte{}, [16]byte{}, err }
return genomesWithMetadataList, allRawGenomeIdentifiersList, true, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, nil return true, genomesWithMetadataList, allRawGenomeIdentifiersList, true, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, nil
} }
//Outputs: //Outputs:

View file

@ -7,6 +7,7 @@ import "seekia/internal/helpers"
import "encoding/csv" import "encoding/csv"
import "os" import "os"
import "io" import "io"
import "strings"
type PhenotypeData_OpenSNP struct{ type PhenotypeData_OpenSNP struct{
@ -273,64 +274,88 @@ func ReadOpenSNPPhenotypesFile(fileObject *os.File)(bool, []PhenotypeData_OpenSN
case `4'9"`:{ case `4'9"`:{
return true, 144.78 return true, 144.78
} }
case `4'10"`:{ case `4'10"`, `4'10`:{
return true, 147.32 return true, 147.32
} }
case `4'11"`:{ case `4'11"`, `4' 11"`:{
return true, 149.86 return true, 149.86
} }
case `5'`:{ case `5'`, `5' 0"`, `5' 0'`, `5'0"`, `5'0`:{
return true, 152.4 return true, 152.4
} }
case `5'1"`:{ case `5'1"`, `5'1" or 155cm`:{
return true, 154.94 return true, 154.94
} }
case `5'1.5"`:{
return true, 156.21
}
case `5'2"`:{ case `5'2"`:{
return true, 157.48 return true, 157.48
} }
case `5'3"`, `5'3''`, `160 cm`:{ case `5' 2 1/2"`:{
return true, 158.75
}
case `5'2.75" at max`:{
return true, 159.385
}
case `5'3"`, `5'3''`:{
return true, 160 return true, 160
} }
case `5'4"`:{ case `5' 3.5" `:{
return true, 161.29
}
case `5'4"`, `5'4`, `5'4''`, "162.56", `64"`:{
return true, 162.56 return true, 162.56
} }
case `5'5"`:{ case `5'4 3/4, taller than all females in my family`:{
return true, 164.465
}
case `5'5"`, `5' 5"`, `5'5" `, `55”`:{
return true, 165.1 return true, 165.1
} }
case `5'6"`:{ case "167":{
return true, 167
}
case `5'6"`, `56`:{
return true, 167.64 return true, 167.64
} }
case `168 cm`:{ case `5' 6.5" `:{
return true, 168 return true, 168.91
}
case `169.316`:{
return true, 169.316
} }
case `5'7"`:{ case `5'7"`:{
return true, 170.18 return true, 170.18
} }
case `Average ( 165cm < x < 180cm )`:{
return true, 172.5
}
case `5'8"`:{ case `5'8"`:{
return true, 172.72 return true, 172.72
} }
case `5'9"`:{ case `Average 173cm`:{
return true, 173
}
case `5'8.5"`:{
return true, 173.99
}
case `5'9"`, `5'9"/176cm`:{
return true, 175.26 return true, 175.26
} }
case `5" 9 1/2"`:{
return true, 176.53
}
case `5'10"`, `5'10''`:{ case `5'10"`, `5'10''`:{
return true, 177.8 return true, 177.8
} }
case `179 cm`:{
return true, 179
}
case `180cm`:{
return true, 180
}
case `5'11"`:{ case `5'11"`:{
return true, 180.34 return true, 180.34
} }
case `6'`:{ case `6'`, `6 ft 0 in`, `6'0" - 183cm`:{
return true, 182.88 return true, 182.88
} }
case `183 cm`:{ case `6'1"`, `6' 1" - 185 cm`:{
return true, 183
}
case `6'1"`:{
return true, 185.42 return true, 185.42
} }
case `6'2"`:{ case `6'2"`:{
@ -339,6 +364,9 @@ func ReadOpenSNPPhenotypesFile(fileObject *os.File)(bool, []PhenotypeData_OpenSN
case `6'3"`:{ case `6'3"`:{
return true, 190.5 return true, 190.5
} }
case "192":{
return true, 192
}
case `6'4"`:{ case `6'4"`:{
return true, 193.04 return true, 193.04
} }
@ -348,6 +376,9 @@ func ReadOpenSNPPhenotypesFile(fileObject *os.File)(bool, []PhenotypeData_OpenSN
case `6'6"`:{ case `6'6"`:{
return true, 198.12 return true, 198.12
} }
case `>200cm`:{
return true, 200
}
case `6'7"`:{ case `6'7"`:{
return true, 200.66 return true, 200.66
} }
@ -366,8 +397,28 @@ func ReadOpenSNPPhenotypesFile(fileObject *os.File)(bool, []PhenotypeData_OpenSN
case `7'`:{ case `7'`:{
return true, 213.36 return true, 213.36
} }
}
//TODO: Add more responses trimmedHeight, suffixExists := strings.CutSuffix(userHeightRaw, "cm")
if (suffixExists == true){
heightFloat64, err := helpers.ConvertStringToFloat64(trimmedHeight)
if (err == nil){
return true, heightFloat64
}
}
trimmedHeight, suffixExists = strings.CutSuffix(userHeightRaw, " cm")
if (suffixExists == true){
heightFloat64, err := helpers.ConvertStringToFloat64(trimmedHeight)
if (err == nil){
return true, heightFloat64
}
}
// This is an outcome with backticks and quotes
result := "6`" + `2"`
if (userHeightRaw == result){
return true, 187.96
} }
return false, 0 return false, 0

View file

@ -1948,29 +1948,29 @@ func ConvertFloat64ToRoundedStringWithTranslatedUnits(inputFloat float64)(string
} }
// This function takes a number and the min and max range of that number // This function takes an int and the min and max range of that int
// It returns a number scaled between a new min and max // It returns an int scaled between a new min and max
func ScaleNumberProportionally(ascending bool, input int, inputMin int, inputMax int, newMin int, newMax int)(int, error){ func ScaleIntProportionally(ascending bool, input int, inputMin int, inputMax int, newMin int, newMax int)(int, error){
if (inputMin == inputMax) { if (inputMin == inputMax) {
return inputMin, nil return inputMin, nil
} }
if (inputMin > inputMax) { if (inputMin > inputMax) {
return 0, errors.New("ScaleNumberProportionally error: InputMin is greater than inputMax") return 0, errors.New("ScaleIntProportionally error: InputMin is greater than inputMax")
} }
if (input < inputMin) { if (input < inputMin) {
return 0, errors.New("ScaleNumberProportionally error: Input is less than inputMin") return 0, errors.New("ScaleIntProportionally error: Input is less than inputMin")
} }
if (input > inputMax) { if (input > inputMax) {
return 0, errors.New("ScaleNumberProportionally error: Input is greater than inputMax") return 0, errors.New("ScaleIntProportionally error: Input is greater than inputMax")
} }
if (newMin == newMax) { if (newMin == newMax) {
return newMin, nil return newMin, nil
} }
if (newMin > newMin){ if (newMin > newMin){
return 0, errors.New("ScaleNumberProportionally error: newMin is greater than newMin.") return 0, errors.New("ScaleIntProportionally error: newMin is greater than newMin.")
} }
inputRangePortionLength := input - inputMin inputRangePortionLength := input - inputMin
@ -2002,6 +2002,58 @@ func ScaleNumberProportionally(ascending bool, input int, inputMin int, inputMax
return result, nil return result, nil
} }
// This function takes an float64 and the min and max range of that float64
// It returns a float64 scaled between a new min and max
func ScaleFloat64Proportionally(ascending bool, input float64, inputMin float64, inputMax float64, newMin float64, newMax float64)(float64, error){
if (inputMin == inputMax) {
return inputMin, nil
}
if (inputMin > inputMax) {
return 0, errors.New("ScaleFloat64Proportionally error: InputMin is greater than inputMax")
}
if (input < inputMin) {
return 0, errors.New("ScaleFloat64Proportionally error: Input is less than inputMin")
}
if (input > inputMax) {
return 0, errors.New("ScaleFloat64Proportionally error: Input is greater than inputMax")
}
if (newMin == newMax) {
return newMin, nil
}
if (newMin > newMin){
return 0, errors.New("ScaleFloat64Proportionally error: newMin is greater than newMin.")
}
inputRangePortionLength := input - inputMin
inputRangeDistance := inputMax - inputMin
inputRangePortion := inputRangePortionLength/inputRangeDistance
// This represents the portion of our output range that we want to travel across
getOutputRangePortion := func()float64{
if (ascending == true){
return inputRangePortion
}
outputRangePortion := 1 - inputRangePortion
return outputRangePortion
}
outputRangePortion := getOutputRangePortion()
outputRangeDistance := newMax - newMin
outputRangePortionLength := outputRangeDistance * outputRangePortion
result := newMin + outputRangePortionLength
return result, nil
}
func XORTwo32ByteArrays(array1 [32]byte, array2 [32]byte)[32]byte{ func XORTwo32ByteArrays(array1 [32]byte, array2 [32]byte)[32]byte{
var newArray [32]byte var newArray [32]byte

View file

@ -321,86 +321,86 @@ func TestSliceFunctions(t *testing.T){
func TestNumberProportionalScaling(t *testing.T){ func TestNumberProportionalScaling(t *testing.T){
result, err := helpers.ScaleNumberProportionally(true, 50, 0, 100, 0, 50) result, err := helpers.ScaleIntProportionally(true, 50, 0, 100, 0, 50)
if (err != nil){ if (err != nil){
t.Fatalf("ScaleNumberProportionally failed: " + err.Error()) t.Fatalf("ScaleIntProportionally failed: " + err.Error())
} }
if (result != 25){ if (result != 25){
t.Fatalf("ScaleNumberProportionally failed test 1.") t.Fatalf("ScaleIntProportionally failed test 1.")
} }
result, err = helpers.ScaleNumberProportionally(true, 25, 0, 100, 0, 200) result, err = helpers.ScaleIntProportionally(true, 25, 0, 100, 0, 200)
if (err != nil){ if (err != nil){
t.Fatalf("ScaleNumberProportionally failed: " + err.Error()) t.Fatalf("ScaleIntProportionally failed: " + err.Error())
} }
if (result != 50){ if (result != 50){
t.Fatalf("ScaleNumberProportionally failed test 2.") t.Fatalf("ScaleIntProportionally failed test 2.")
} }
result, err = helpers.ScaleNumberProportionally(false, 25, 0, 100, 0, 200) result, err = helpers.ScaleIntProportionally(false, 25, 0, 100, 0, 200)
if (err != nil){ if (err != nil){
t.Fatalf("ScaleNumberProportionally failed: " + err.Error()) t.Fatalf("ScaleIntProportionally failed: " + err.Error())
} }
if (result != 150){ if (result != 150){
t.Fatalf("ScaleNumberProportionally failed test 3.") t.Fatalf("ScaleIntProportionally failed test 3.")
} }
result, err = helpers.ScaleNumberProportionally(true, 1, 0, 10, 0, 200) result, err = helpers.ScaleIntProportionally(true, 1, 0, 10, 0, 200)
if (err != nil){ if (err != nil){
t.Fatalf("ScaleNumberProportionally failed: " + err.Error()) t.Fatalf("ScaleIntProportionally failed: " + err.Error())
} }
if (result != 20){ if (result != 20){
t.Fatalf("ScaleNumberProportionally failed test 4.") t.Fatalf("ScaleIntProportionally failed test 4.")
} }
result, err = helpers.ScaleNumberProportionally(true, -50, -100, 0, 0, 200) result, err = helpers.ScaleIntProportionally(true, -50, -100, 0, 0, 200)
if (err != nil){ if (err != nil){
t.Fatalf("ScaleNumberProportionally failed: " + err.Error()) t.Fatalf("ScaleIntProportionally failed: " + err.Error())
} }
if (result != 100){ if (result != 100){
t.Fatalf("ScaleNumberProportionally failed test 5.") t.Fatalf("ScaleIntProportionally failed test 5.")
} }
result, err = helpers.ScaleNumberProportionally(true, -25, -100, 0, 0, 200) result, err = helpers.ScaleIntProportionally(true, -25, -100, 0, 0, 200)
if (err != nil){ if (err != nil){
t.Fatalf("ScaleNumberProportionally failed: " + err.Error()) t.Fatalf("ScaleIntProportionally failed: " + err.Error())
} }
if (result != 150){ if (result != 150){
t.Fatalf("ScaleNumberProportionally failed test 6.") t.Fatalf("ScaleIntProportionally failed test 6.")
} }
result, err = helpers.ScaleNumberProportionally(true, 50, 0, 100, 0, 2) result, err = helpers.ScaleIntProportionally(true, 50, 0, 100, 0, 2)
if (err != nil){ if (err != nil){
t.Fatalf("ScaleNumberProportionally failed: " + err.Error()) t.Fatalf("ScaleIntProportionally failed: " + err.Error())
} }
if (result != 1){ if (result != 1){
t.Fatalf("ScaleNumberProportionally failed test 7.") t.Fatalf("ScaleIntProportionally failed test 7.")
} }
result, err = helpers.ScaleNumberProportionally(true, 10, 0, 100, 5, 25) result, err = helpers.ScaleIntProportionally(true, 10, 0, 100, 5, 25)
if (err != nil){ if (err != nil){
t.Fatalf("ScaleNumberProportionally failed: " + err.Error()) t.Fatalf("ScaleIntProportionally failed: " + err.Error())
} }
if (result != 7){ if (result != 7){
t.Fatalf("ScaleNumberProportionally failed test 8.") t.Fatalf("ScaleIntProportionally failed test 8.")
} }
result, err = helpers.ScaleNumberProportionally(true, 100, 0, 100, 2, 22) result, err = helpers.ScaleIntProportionally(true, 100, 0, 100, 2, 22)
if (err != nil){ if (err != nil){
t.Fatalf("ScaleNumberProportionally failed: " + err.Error()) t.Fatalf("ScaleIntProportionally failed: " + err.Error())
} }
if (result != 22){ if (result != 22){
t.Fatalf("ScaleNumberProportionally failed test 9.") t.Fatalf("ScaleIntProportionally failed test 9.")
} }
result, err = helpers.ScaleNumberProportionally(false, 0, 0, 100, 2, 22) result, err = helpers.ScaleIntProportionally(false, 0, 0, 100, 2, 22)
if (err != nil){ if (err != nil){
t.Fatalf("ScaleNumberProportionally failed: " + err.Error()) t.Fatalf("ScaleIntProportionally failed: " + err.Error())
} }
if (result != 22){ if (result != 22){
t.Fatalf("ScaleNumberProportionally failed test 10.") t.Fatalf("ScaleIntProportionally failed test 10.")
} }
} }

View file

@ -121,7 +121,7 @@ func GetImageWithEmojiOverlay(inputImage image.Image, emojiImage image.Image, em
imageLongerSideLength := max(imageWidth, imageHeight) imageLongerSideLength := max(imageWidth, imageHeight)
// This is the length of the longest side of the emoji we will draw // This is the length of the longest side of the emoji we will draw
emojiLongerSideMaximumLength, err := helpers.ScaleNumberProportionally(true, emojiScale, 0, 100, 1, imageLongerSideLength) emojiLongerSideMaximumLength, err := helpers.ScaleIntProportionally(true, emojiScale, 0, 100, 1, imageLongerSideLength)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
newEmoji, err := imagery.ResizeGolangImage(emojiImage, emojiLongerSideMaximumLength) newEmoji, err := imagery.ResizeGolangImage(emojiImage, emojiLongerSideMaximumLength)
@ -130,10 +130,10 @@ func GetImageWithEmojiOverlay(inputImage image.Image, emojiImage image.Image, em
// Now we get the X and Y Coordinate point for where we will draw the emoji // Now we get the X and Y Coordinate point for where we will draw the emoji
// We first find the center coordinate of the emoji we are drawing // We first find the center coordinate of the emoji we are drawing
emojiCenterXCoordinate, err := helpers.ScaleNumberProportionally(true, xAxisPercentage, 0, 100, 0, imageWidth) emojiCenterXCoordinate, err := helpers.ScaleIntProportionally(true, xAxisPercentage, 0, 100, 0, imageWidth)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
emojiCenterYCoordinate, err := helpers.ScaleNumberProportionally(false, yAxisPercentage, 0, 100, 0, imageHeight) emojiCenterYCoordinate, err := helpers.ScaleIntProportionally(false, yAxisPercentage, 0, 100, 0, imageHeight)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
emojiWidth, emojiHeight, err := imagery.GetImageWidthAndHeightPixels(newEmoji) emojiWidth, emojiHeight, err := imagery.GetImageWidthAndHeightPixels(newEmoji)

View file

@ -497,7 +497,7 @@ func PixelateGolangImage(inputImage image.Image, amount0to100 int)(image.Image,
longerSideLength := max(widthPixels, heightPixels) longerSideLength := max(widthPixels, heightPixels)
pixelationAmountInt, err := helpers.ScaleNumberProportionally(true, amount0to100, 0, 100, 0, longerSideLength/5) pixelationAmountInt, err := helpers.ScaleIntProportionally(true, amount0to100, 0, 100, 0, longerSideLength/5)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
rectangle := image.Rect(0, 0, widthPixels, heightPixels) rectangle := image.Rect(0, 0, widthPixels, heightPixels)

View file

@ -469,7 +469,7 @@ func StartUpdatingMyConversations(identityType string, networkType byte) error{
// Input is a value between 0-100 // Input is a value between 0-100
// We reduce it down to a value between 0-50 // We reduce it down to a value between 0-50
newProgressInt, err := helpers.ScaleNumberProportionally(true, input, 0, 100, 0, 50) newProgressInt, err := helpers.ScaleIntProportionally(true, input, 0, 100, 0, 50)
if (err != nil) { return err } if (err != nil) { return err }
newPercentageProgressFloat := float64(newProgressInt)/100 newPercentageProgressFloat := float64(newProgressInt)/100
@ -715,7 +715,7 @@ func StartUpdatingMyConversations(identityType string, networkType byte) error{
return nil return nil
} }
newScaledPercentageInt, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 70, 85) newScaledPercentageInt, err := helpers.ScaleIntProportionally(true, index, 0, maximumIndex, 70, 85)
if (err != nil) { return err } if (err != nil) { return err }
newProgressFloat := float64(newScaledPercentageInt)/100 newProgressFloat := float64(newScaledPercentageInt)/100

View file

@ -268,7 +268,7 @@ func GetUpdatedMyChatMessagesMapList(myIdentityType string, networkType byte, up
for messageHash, messageInbox := range myRawInboxMessageHashesMap{ for messageHash, messageInbox := range myRawInboxMessageHashesMap{
newPercentageProgress, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 20, 100) newPercentageProgress, err := helpers.ScaleIntProportionally(true, index, 0, maximumIndex, 20, 100)
if (err != nil){ return err } if (err != nil){ return err }
err = updateProgressFunction(newPercentageProgress) err = updateProgressFunction(newPercentageProgress)

View file

@ -480,7 +480,7 @@ func StartUpdatingViewedContent(networkType byte)error{
return nil return nil
} }
newScaledPercentageInt, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 50, 80) newScaledPercentageInt, err := helpers.ScaleIntProportionally(true, index, 0, maximumIndex, 50, 80)
if (err != nil) { return err } if (err != nil) { return err }
newProgressFloat := float64(newScaledPercentageInt)/100 newProgressFloat := float64(newScaledPercentageInt)/100

View file

@ -365,7 +365,7 @@ func StartUpdatingViewedModerators(networkType byte)error{
return nil return nil
} }
progressPercentage, err := helpers.ScaleNumberProportionally(true, index, 0, numberOfModerators-1, 20, 50) progressPercentage, err := helpers.ScaleIntProportionally(true, index, 0, numberOfModerators-1, 20, 50)
if (err != nil) { return err } if (err != nil) { return err }
progressFloat := float64(progressPercentage)/100 progressFloat := float64(progressPercentage)/100
@ -452,7 +452,7 @@ func StartUpdatingViewedModerators(networkType byte)error{
return nil return nil
} }
newScaledPercentageInt, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 50, 80) newScaledPercentageInt, err := helpers.ScaleIntProportionally(true, index, 0, maximumIndex, 50, 80)
if (err != nil) { return err } if (err != nil) { return err }
newProgressFloat := float64(newScaledPercentageInt)/100 newProgressFloat := float64(newScaledPercentageInt)/100

View file

@ -323,7 +323,7 @@ func StartUpdatingMyMatches(networkType byte)error{
return nil return nil
} }
progressPercentage, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 0, 50) progressPercentage, err := helpers.ScaleIntProportionally(true, index, 0, maximumIndex, 0, 50)
if (err != nil) { return err } if (err != nil) { return err }
progressFloat := float64(progressPercentage)/100 progressFloat := float64(progressPercentage)/100
@ -449,7 +449,7 @@ func StartUpdatingMyMatches(networkType byte)error{
return nil return nil
} }
newScaledPercentageInt, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 50, 80) newScaledPercentageInt, err := helpers.ScaleIntProportionally(true, index, 0, maximumIndex, 50, 80)
if (err != nil) { return err } if (err != nil) { return err }
newProgressFloat := float64(newScaledPercentageInt)/100 newProgressFloat := float64(newScaledPercentageInt)/100

View file

@ -335,7 +335,7 @@ func StartUpdatingViewedHosts(networkType byte)error{
return nil return nil
} }
progressPercentage, err := helpers.ScaleNumberProportionally(true, index, 0, numberOfEnabledHosts-1, 0, 50) progressPercentage, err := helpers.ScaleIntProportionally(true, index, 0, numberOfEnabledHosts-1, 0, 50)
if (err != nil) { return err } if (err != nil) { return err }
progressFloat := float64(progressPercentage)/100 progressFloat := float64(progressPercentage)/100
@ -419,7 +419,7 @@ func StartUpdatingViewedHosts(networkType byte)error{
return nil return nil
} }
newScaledPercentageInt, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 50, 80) newScaledPercentageInt, err := helpers.ScaleIntProportionally(true, index, 0, maximumIndex, 50, 80)
if (err != nil) { return err } if (err != nil) { return err }
newProgressFloat := float64(newScaledPercentageInt)/100 newProgressFloat := float64(newScaledPercentageInt)/100
@ -429,47 +429,47 @@ func StartUpdatingViewedHosts(networkType byte)error{
appMemory.SetMemoryEntry("ViewedHostsReadyProgressStatus", newProgressString) appMemory.SetMemoryEntry("ViewedHostsReadyProgressStatus", newProgressString)
} }
compareHostsFunction := func(identityHashA string, identityHashB string)int{ compareHostsFunction := func(identityHash1 string, identityHash2 string)int{
if (identityHashA == identityHashB){ if (identityHash1 == identityHash2){
panic("compareHostsFunction called with duplicate hosts.") panic("compareHostsFunction called with duplicate hosts.")
} }
attributeValueA, attributeValueAExists := hostAttributeValuesMap[identityHashA] attributeValue1, attributeValue1Exists := hostAttributeValuesMap[identityHash1]
attributeValueB, attributeValueBExists := hostAttributeValuesMap[identityHashB] attributeValue2, attributeValue2Exists := hostAttributeValuesMap[identityHash2]
if (attributeValueAExists == false && attributeValueBExists == false){ if (attributeValue1Exists == false && attributeValue2Exists == false){
// We don't know the attribute value for either host // We don't know the attribute value for either host
// We sort hosts in unicode order // We sort hosts in unicode order
if (identityHashA < identityHashB){ if (identityHash1 < identityHash2){
return -1 return -1
} }
return 1 return 1
} else if (attributeValueAExists == true && attributeValueBExists == false){ } else if (attributeValue1Exists == true && attributeValue2Exists == false){
// We sort unknown attribute hosts to the back of the list // We sort unknown attribute hosts to the back of the list
return -1 return -1
} else if (attributeValueAExists == false && attributeValueBExists == true){ } else if (attributeValue1Exists == false && attributeValue2Exists == true){
return 1 return 1
} }
// Both attribute values exist // Both attribute values exist
if (attributeValueA == attributeValueB){ if (attributeValue1 == attributeValue2){
// We sort identity hashes in unicode order // We sort identity hashes in unicode order
if (identityHashA < identityHashB){ if (identityHash1 < identityHash2){
return -1 return -1
} }
return 1 return 1
} }
if (attributeValueA < attributeValueB){ if (attributeValue1 < attributeValue2){
if (currentSortDirection == "Ascending"){ if (currentSortDirection == "Ascending"){
return -1 return -1

View file

@ -153,11 +153,6 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myGeneticAnalysisObject) _, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myGeneticAnalysisObject)
if (err != nil) { return err } if (err != nil) { return err }
myGenomeLocusValuesMap, exists := myGenomesMap[genomeIdentifierToShare]
if (exists == false){
return errors.New("GetMyChosenMateGeneticAnalysis returning genetic analysis which has GenomesMap which is missing my genome identifier.")
}
monogenicDiseaseNamesList, err := monogenicDiseases.GetMonogenicDiseaseNamesList() monogenicDiseaseNamesList, err := monogenicDiseases.GetMonogenicDiseaseNamesList()
if (err != nil) { return err } if (err != nil) { return err }
@ -253,6 +248,11 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{
} }
} }
myGenomeLocusValuesMap, exists := myGenomesMap[genomeIdentifierToShare]
if (exists == false){
return errors.New("GetMyChosenMateGeneticAnalysis returning genetic analysis which has GenomesMap which is missing my genome identifier.")
}
for rsID, _ := range myLociToShareMap{ for rsID, _ := range myLociToShareMap{
locusValueObject, exists := myGenomeLocusValuesMap[rsID] locusValueObject, exists := myGenomeLocusValuesMap[rsID]

View file

@ -38,6 +38,7 @@ import "os"
import "strings" import "strings"
import "sync" import "sync"
import "slices" import "slices"
import "math"
import mathRand "math/rand/v2" import mathRand "math/rand/v2"
import goFilepath "path/filepath" import goFilepath "path/filepath"
import "time" import "time"
@ -722,7 +723,7 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
if (err != nil) { return false, false, err } if (err != nil) { return false, false, err }
//TODO: Add more traits //TODO: Add more traits
traitNamesList := []string{"Eye Color", "Lactose Tolerance"} traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"}
// We create the folders for each trait's training data // We create the folders for each trait's training data
@ -765,7 +766,7 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
err = progressDetailsBinding.Set(progressDetailsStatus) err = progressDetailsBinding.Set(progressDetailsStatus)
if (err != nil) { return false, false, err } if (err != nil) { return false, false, err }
trainingProgressPercentage, err := helpers.ScaleNumberProportionally(true, index, 0, maximumIndex, 0, 100) trainingProgressPercentage, err := helpers.ScaleIntProportionally(true, index, 0, maximumIndex, 0, 100)
if (err != nil) { return false, false, err } if (err != nil) { return false, false, err }
trainingProgressFloat64 := float64(trainingProgressPercentage)/100 trainingProgressFloat64 := float64(trainingProgressPercentage)/100
@ -837,18 +838,26 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
continue continue
} }
getUserLociValuesMap := func()(map[int64]locusValue.LocusValue, error){ //Outputs:
// -bool: Any useful locations exist in any of the user's genomes
// -map[int64]locusValue.LocusValue
// -error
getUserLociValuesMap := func()(bool, map[int64]locusValue.LocusValue, error){
updatePercentageCompleteFunction := func(_ int)error{ updatePercentageCompleteFunction := func(_ int)error{
return nil return nil
} }
genomesWithMetadataList, _, combinedGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(userRawGenomesWithMetadataList, updatePercentageCompleteFunction) anyUsefulLocationsExist, genomesWithMetadataList, _, combinedGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(userRawGenomesWithMetadataList, updatePercentageCompleteFunction)
if (err != nil) { return nil, err } if (err != nil) { return false, nil, err }
if (anyUsefulLocationsExist == false){
// None of the user's genomes have any useful locations
return false, nil, nil
}
if (combinedGenomesExist == false){ if (combinedGenomesExist == false){
if (len(genomesWithMetadataList) != 1){ if (len(genomesWithMetadataList) != 1){
return nil, errors.New("GetGenomesWithMetadataListFromRawGenomesList returning non-1 length genomesWithMetadataList when combinedGenomesExist == false") return false, nil, errors.New("GetGenomesWithMetadataListFromRawGenomesList returning non-1 length genomesWithMetadataList when combinedGenomesExist == false")
} }
// Only 1 genome exists // Only 1 genome exists
@ -857,7 +866,7 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
genomeMap := genomeWithMetadataObject.GenomeMap genomeMap := genomeWithMetadataObject.GenomeMap
return genomeMap, nil return true, genomeMap, nil
} }
for _, genomeWithMetadataObject := range genomesWithMetadataList{ for _, genomeWithMetadataObject := range genomesWithMetadataList{
@ -868,15 +877,19 @@ func setStartAndMonitorCreateTrainingDataPage(window fyne.Window, previousPage f
genomeMap := genomeWithMetadataObject.GenomeMap genomeMap := genomeWithMetadataObject.GenomeMap
return genomeMap, nil return true, genomeMap, nil
} }
} }
return nil, errors.New("OnlyExcludeConflicts genome not found from GetGenomesWithMetadataListFromRawGenomesList's returned list.") return false, nil, errors.New("OnlyExcludeConflicts genome not found from GetGenomesWithMetadataListFromRawGenomesList's returned list.")
} }
userLociValuesMap, err := getUserLociValuesMap() anyUsefulLocationsExist, userLociValuesMap, err := getUserLociValuesMap()
if (err != nil) { return false, false, err } if (err != nil) { return false, false, err }
if (anyUsefulLocationsExist == false){
// None of the user's genome files contain any useful locations
continue
}
for _, traitName := range traitNamesList{ for _, traitName := range traitNamesList{
@ -980,7 +993,7 @@ func setTrainModelsPage(window fyne.Window, previousPage func()){
description3 := getLabelCentered("This will take a while.") description3 := getLabelCentered("This will take a while.")
description4 := getLabelCentered("You must select a trait model to train.") description4 := getLabelCentered("You must select a trait model to train.")
traitNamesList := []string{"Eye Color", "Lactose Tolerance"} traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"}
traitNameSelector := widget.NewSelect(traitNamesList, nil) traitNameSelector := widget.NewSelect(traitNamesList, nil)
@ -1305,7 +1318,7 @@ func setTestModelsPage(window fyne.Window, previousPage func()){
description5 := getLabelCentered("The results will also be saved in the ModelAccuracies folder.") description5 := getLabelCentered("The results will also be saved in the ModelAccuracies folder.")
description6 := getLabelCentered("You must select a trait model to test.") description6 := getLabelCentered("You must select a trait model to test.")
traitNamesList := []string{"Eye Color", "Lactose Tolerance"} traitNamesList := []string{"Eye Color", "Lactose Tolerance", "Height"}
traitNameSelector := widget.NewSelect(traitNamesList, nil) traitNameSelector := widget.NewSelect(traitNamesList, nil)
@ -1383,7 +1396,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
//Outputs: //Outputs:
// -bool: Process completed (true == was not stopped mid-way) // -bool: Process completed (true == was not stopped mid-way)
// -geneticPrediction.TraitPredictionAccuracyInfoMap // -geneticPrediction.DiscreteTraitPredictionAccuracyInfoMap
// -error // -error
testModel := func()(bool, geneticPrediction.DiscreteTraitPredictionAccuracyInfoMap, error){ testModel := func()(bool, geneticPrediction.DiscreteTraitPredictionAccuracyInfoMap, error){
@ -1464,10 +1477,10 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
return false, nil, errors.New("Neural network prediction output length does not match expected output length.") return false, nil, errors.New("Neural network prediction output length does not match expected output length.")
} }
correctOutcomeName, err := geneticPrediction.GetOutcomeNameFromOutputLayer(traitName, true, trainingDataExpectedOutputLayer) correctOutcomeName, err := geneticPrediction.GetDiscreteOutcomeNameFromOutputLayer(traitName, true, trainingDataExpectedOutputLayer)
if (err != nil) { return false, nil, err } if (err != nil) { return false, nil, err }
predictedOutcomeName, err := geneticPrediction.GetOutcomeNameFromOutputLayer(traitName, true, predictionLayer) predictedOutcomeName, err := geneticPrediction.GetDiscreteOutcomeNameFromOutputLayer(traitName, true, predictionLayer)
if (err != nil) { return false, nil, err } if (err != nil) { return false, nil, err }
getPredictionIsCorrectBool := func()bool{ getPredictionIsCorrectBool := func()bool{
@ -1565,7 +1578,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
// This map stores the accuracy for each outcome // This map stores the accuracy for each outcome
traitPredictionAccuracyInfoMap := make(map[geneticPrediction.DiscreteTraitOutcomeInfo]geneticPrediction.DiscreteTraitPredictionAccuracyInfo) traitPredictionAccuracyInfoMap := make(map[geneticPrediction.DiscreteTraitOutcomeInfo]geneticPrediction.DiscreteTraitPredictionAccuracyInfo)
for traitAccuracyData, value := range traitPredictionInfoMap{ for traitPredictionInfo, value := range traitPredictionInfoMap{
quantityOfExamples := value.QuantityOfExamples quantityOfExamples := value.QuantityOfExamples
quantityOfPredictions := value.QuantityOfPredictions quantityOfPredictions := value.QuantityOfPredictions
@ -1601,7 +1614,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
newTraitPredictionAccuracyInfo.ProbabilityOfCorrectOutcomePrediction = percentageOfCorrectOutcomePredictions newTraitPredictionAccuracyInfo.ProbabilityOfCorrectOutcomePrediction = percentageOfCorrectOutcomePredictions
} }
traitPredictionAccuracyInfoMap[traitAccuracyData] = newTraitPredictionAccuracyInfo traitPredictionAccuracyInfoMap[traitPredictionInfo] = newTraitPredictionAccuracyInfo
} }
// Testing is complete. // Testing is complete.
@ -1635,6 +1648,224 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
} }
setViewModelTestingDiscreteTraitResultsPage(window, traitName, traitPredictionAccuracyInfoMap, previousPage) setViewModelTestingDiscreteTraitResultsPage(window, traitName, traitPredictionAccuracyInfoMap, previousPage)
} else {
// traitIsDiscreteOrNumeric == "Numeric"
//Outputs:
// -bool: Process completed (true == was not stopped mid-way)
// -geneticPrediction.NumericTraitPredictionAccuracyInfoMap
// -error
testModel := func()(bool, geneticPrediction.NumericTraitPredictionAccuracyInfoMap, error){
// We use this map to count up the information about predictions
// We use information from this map to construct the final accuracy information map
// Map Structure: NumericTraitOutcomeInfo -> List of true outcomes
traitPredictionInfoMap := make(map[geneticPrediction.NumericTraitOutcomeInfo][]float64)
_, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(traitName)
if (err != nil) { return false, nil, err }
traitNameWithoutWhitespaces := strings.ReplaceAll(traitName, " ", "")
// We read the trained model for this trait
modelFilename := traitNameWithoutWhitespaces + "Model.gob"
trainedModelFilepath := goFilepath.Join("./TrainedModels/", modelFilename)
fileExists, fileContents, err := localFilesystem.GetFileContents(trainedModelFilepath)
if (err != nil) { return false, nil, err }
if (fileExists == false){
return false, nil, errors.New("TrainedModel not found: " + trainedModelFilepath)
}
neuralNetworkObject, err := geneticPrediction.DecodeBytesToNeuralNetworkObject(fileContents)
if (err != nil) { return false, nil, err }
numberOfTrainingDatas := len(testingSetFilepathsList)
numberOfTrainingDatasString := helpers.ConvertIntToString(numberOfTrainingDatas)
finalIndex := numberOfTrainingDatas - 1
for index, filePath := range testingSetFilepathsList{
testModelIsStoppedBoolMutex.RLock()
testModelIsStopped := testModelIsStoppedBool
testModelIsStoppedBoolMutex.RUnlock()
if (testModelIsStopped == true){
// User exited the process
return false, nil, nil
}
fileExists, fileContents, err := localFilesystem.GetFileContents(filePath)
if (err != nil) { return false, nil, err }
if (fileExists == false){
return false, nil, errors.New("TrainingData file not found: " + filePath)
}
trainingDataObject, err := geneticPrediction.DecodeBytesToTrainingDataObject(fileContents)
if (err != nil) { return false, nil, err }
trainingDataInputLayer := trainingDataObject.InputLayer
trainingDataExpectedOutputLayer := trainingDataObject.OutputLayer
predictionLayer, err := geneticPrediction.GetNeuralNetworkRawPrediction(&neuralNetworkObject, false, trainingDataInputLayer)
if (err != nil) { return false, nil, err }
if (len(predictionLayer) != 1){
return false, nil, errors.New("Neural network numeric prediction output layer length is not 1.")
}
if (len(trainingDataExpectedOutputLayer) != 1){
return false, nil, errors.New("Neural network training data prediction output layer length is not 1.")
}
correctOutcomeValue, err := geneticPrediction.GetNumericOutcomeValueFromOutputLayer(traitName, trainingDataExpectedOutputLayer)
if (err != nil) { return false, nil, err }
predictedOutcomeValue, err := geneticPrediction.GetNumericOutcomeValueFromOutputLayer(traitName, predictionLayer)
if (err != nil) { return false, nil, err }
numberOfKnownLoci, numberOfKnownAndPhasedLoci, numberOfLoci, err := geneticPrediction.GetLociInfoFromNetworkInputLayer(trainingDataInputLayer)
if (err != nil) { return false, nil, err }
proportionOfLociTested := float64(numberOfKnownLoci)/float64(numberOfLoci)
percentageOfLociTested := int(100*proportionOfLociTested)
proportionOfPhasedLoci := float64(numberOfKnownAndPhasedLoci)/float64(numberOfKnownLoci)
percentageOfPhasedLoci := int(100*proportionOfPhasedLoci)
newNumericTraitOutcomeInfo := geneticPrediction.NumericTraitOutcomeInfo{
OutcomeValue: predictedOutcomeValue,
PercentageOfLociTested: percentageOfLociTested,
PercentageOfPhasedLoci: percentageOfPhasedLoci,
}
existingList, exists := traitPredictionInfoMap[newNumericTraitOutcomeInfo]
if (exists == false){
traitPredictionInfoMap[newNumericTraitOutcomeInfo] = []float64{correctOutcomeValue}
} else {
existingList = append(existingList, correctOutcomeValue)
traitPredictionInfoMap[newNumericTraitOutcomeInfo] = existingList
}
exampleIndexString := helpers.ConvertIntToString(index+1)
numberOfExamplesProgress := "Tested " + exampleIndexString + "/" + numberOfTrainingDatasString + " Examples"
progressDetailsBinding.Set(numberOfExamplesProgress)
newProgressFloat64 := float64(index)/float64(finalIndex)
progressPercentageBinding.Set(newProgressFloat64)
}
// Now we construct the TraitAccuracyInfoMap
// This map stores the accuracy for each outcome
traitPredictionAccuracyInfoMap := make(map[geneticPrediction.NumericTraitOutcomeInfo]geneticPrediction.NumericTraitPredictionAccuracyRangesMap)
for traitPredictionInfo, realOutcomesList := range traitPredictionInfoMap{
if (len(realOutcomesList) == 0){
return false, nil, errors.New("traitPredictionInfoMap contains empty realOutcomesList.")
}
// This is the predicted height value for this set of real outcomes
predictionValue := traitPredictionInfo.OutcomeValue
// Map Structure: Accuracy Percentage (AP) -> Amount needed to deviate from prediction
// for the value to be accurate (AP)% of the time
newNumericTraitPredictionAccuracyRangesMap := make(map[int]float64)
rangeDistance := float64(0)
for {
rangeMin := predictionValue - rangeDistance
rangeMax := predictionValue + rangeDistance
valuesInRangeList := make([]float64, 0)
valuesOutOfRangeList := make([]float64, 0)
for _, outcomeValue := range realOutcomesList{
if (outcomeValue <= rangeMax && outcomeValue >= rangeMin){
valuesInRangeList = append(valuesInRangeList, outcomeValue)
} else {
valuesOutOfRangeList = append(valuesOutOfRangeList, outcomeValue)
}
}
quantityOfValuesInRange := len(valuesInRangeList)
totalQuantityOfValues := len(realOutcomesList)
proportionOfValuesInRange := float64(quantityOfValuesInRange)/float64(totalQuantityOfValues)
percentageOfValuesInRange := proportionOfValuesInRange * 100
if (percentageOfValuesInRange >= 1){
percentageOfValuesInRangeInt := int(percentageOfValuesInRange)
newNumericTraitPredictionAccuracyRangesMap[percentageOfValuesInRangeInt] = rangeDistance
}
if (quantityOfValuesInRange == totalQuantityOfValues){
newNumericTraitPredictionAccuracyRangesMap[100] = rangeDistance
break
}
// Now we increase rangeDistance
// We find the distance to the next closest item in the list that isn't already in our range
nearestValueDistance := float64(0)
for index, outcomeValue := range valuesOutOfRangeList{
distance := math.Abs(predictionValue - outcomeValue)
if (index == 0 || distance < nearestValueDistance){
nearestValueDistance = distance
}
}
rangeDistance += nearestValueDistance
}
traitPredictionAccuracyInfoMap[traitPredictionInfo] = newNumericTraitPredictionAccuracyRangesMap
}
// Testing is complete.
// We save the info map as a file in the ModelAccuracies folder
fileBytes, err := geneticPrediction.EncodeNumericTraitPredictionAccuracyInfoMapToBytes(traitPredictionAccuracyInfoMap)
if (err != nil) { return false, nil, err }
_, err = localFilesystem.CreateFolder("./ModelAccuracies")
if (err != nil) { return false, nil, err }
modelAccuracyFilename := traitNameWithoutWhitespaces + "ModelAccuracy.gob"
err = localFilesystem.CreateOrOverwriteFile(fileBytes, "./ModelAccuracies/", modelAccuracyFilename)
if (err != nil) { return false, nil, err }
progressPercentageBinding.Set(1)
return true, traitPredictionAccuracyInfoMap, nil
}
processIsComplete, traitPredictionAccuracyInfoMap, err := testModel()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (processIsComplete == false){
// User exited the page
return
}
setViewModelTestingNumericTraitResultsPage(window, traitName, traitPredictionAccuracyInfoMap, previousPage)
} }
} }
@ -1680,6 +1911,11 @@ func setViewModelTestingDiscreteTraitResultsPage(window fyne.Window, traitName s
traitObject, err := traits.GetTraitObject(traitName) traitObject, err := traits.GetTraitObject(traitName)
if (err != nil) { return nil, err } if (err != nil) { return nil, err }
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Discrete"){
return nil, errors.New("setViewModelTestingDiscreteTraitResultsPage called with non-discrete trait: " + traitName)
}
outcomeNamesList := traitObject.OutcomesList outcomeNamesList := traitObject.OutcomesList
for _, outcomeName := range outcomeNamesList{ for _, outcomeName := range outcomeNamesList{
@ -1801,6 +2037,175 @@ func setViewModelTestingDiscreteTraitResultsPage(window fyne.Window, traitName s
} }
// This is a page to view the details of testing for a specific trait's model
func setViewModelTestingNumericTraitResultsPage(window fyne.Window, traitName string, traitAccuracyInfoMap geneticPrediction.NumericTraitPredictionAccuracyInfoMap, exitPage func()){
title := getBoldLabelCentered("Numeric Trait Prediction Accuracy Details")
exitButton := getWidgetCentered(widget.NewButtonWithIcon("Exit", theme.CancelIcon(), exitPage))
description1 := getLabelCentered("The results of the prediction accuracy for this trait are below.")
traitNameTitle := widget.NewLabel("Trait Name:")
traitNameLabel := getBoldLabel(traitName)
traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameTitle, traitNameLabel, layout.NewSpacer())
description2 := getLabelCentered("Each value is a range that the prediction must be widened by to be accurate X% of the time.")
description3 := getLabelCentered("For example, for a height prediction to be accurate 90% of the time, allow a +/-10 cm range.")
getResultsGrid := func()(*fyne.Container, error){
probabilityOfTitle := getItalicLabelCentered("Probability Of")
correctPredictionTitle := getItalicLabelCentered("Correct Prediction")
accuracyRangeTitle1 := getItalicLabelCentered("Accuracy Range")
knownLociLabel_0to33 := getItalicLabelCentered("0-33% Known Loci")
accuracyRangeTitle2 := getItalicLabelCentered("Accuracy Range")
knownLociLabel_34to66 := getItalicLabelCentered("34-66% Known Loci")
accuracyRangeTitle3 := getItalicLabelCentered("Accuracy Range")
knownLociLabel_67to100 := getItalicLabelCentered("67-100% Known Loci")
probabilityOfCorrectPredictionColumn := container.NewVBox(probabilityOfTitle, correctPredictionTitle, widget.NewSeparator())
accuracyRangeColumn_0to33 := container.NewVBox(accuracyRangeTitle1, knownLociLabel_0to33, widget.NewSeparator())
accuracyRangeColumn_34to66 := container.NewVBox(accuracyRangeTitle2, knownLociLabel_34to66, widget.NewSeparator())
accuracyRangeColumn_67to100 := container.NewVBox(accuracyRangeTitle3, knownLociLabel_67to100, widget.NewSeparator())
traitObject, err := traits.GetTraitObject(traitName)
if (err != nil) { return nil, err }
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Numeric"){
return nil, errors.New("setViewModelTestingNumericTraitResultsPage called with non-discrete trait: " + traitName)
}
probabilityMinimumRange := 1
for {
if (probabilityMinimumRange == 100){
break
}
getProbabilityMaximumRange := func()int{
if (probabilityMinimumRange == 90){
return 100
}
probabilityMaximumRange := probabilityMinimumRange + 9
return probabilityMaximumRange
}
probabilityMaximumRange := getProbabilityMaximumRange()
probabilityMinimumRangeString := helpers.ConvertIntToString(probabilityMinimumRange)
probabilityMaximumRangeString := helpers.ConvertIntToString(probabilityMaximumRange)
probabilityOfCorrectPredictionRangeFormatted := probabilityMinimumRangeString + "% - " + probabilityMaximumRangeString + "%"
probabilityOfCorrectPredictionRangeLabel := getBoldLabelCentered(probabilityOfCorrectPredictionRangeFormatted)
// We use the below variables to sum up the accuracy distances so we can average them
predictionAccuracyDistancesSum_0to33 := float64(0)
distancesCount_0to33 := 0
predictionAccuracyDistancesSum_34to66 := float64(0)
distancesCount_34to66 := 0
predictionAccuracyDistancesSum_67to100 := float64(0)
distancesCount_67to100 := 0
for traitOutcomeInfo, traitPredictionAccuracyRangesMap := range traitAccuracyInfoMap{
percentageOfLociTested := traitOutcomeInfo.PercentageOfLociTested
for percentageCorrect, distance := range traitPredictionAccuracyRangesMap{
if (percentageCorrect < probabilityMinimumRange || percentageCorrect > probabilityMaximumRange){
continue
}
if (percentageOfLociTested <= 33){
predictionAccuracyDistancesSum_0to33 += distance
distancesCount_0to33 += 1
} else if (percentageOfLociTested > 33 && percentageOfLociTested <= 66){
predictionAccuracyDistancesSum_34to66 += distance
distancesCount_34to66 += 1
} else {
predictionAccuracyDistancesSum_67to100 += distance
distancesCount_67to100 += 1
}
}
}
getAverageAccuracyText := func(distancesSum float64, distancesCount int)string{
if (distancesCount == 0){
return "Unknown"
}
averageDistance := distancesSum/float64(distancesCount)
averageDistanceString := helpers.ConvertFloat64ToStringRounded(averageDistance, 1)
//TODO: Retrieve units from traits package?
result := "+/- " + averageDistanceString + " centimeters"
return result
}
averageDistanceText_0to33 := getAverageAccuracyText(predictionAccuracyDistancesSum_0to33, distancesCount_0to33)
averageDistanceText_34to66 := getAverageAccuracyText(predictionAccuracyDistancesSum_34to66, distancesCount_34to66)
averageDistanceText_67to100 := getAverageAccuracyText(predictionAccuracyDistancesSum_67to100, distancesCount_67to100)
averageDistanceLabel_0to33 := getBoldLabelCentered(averageDistanceText_0to33)
averageDistanceLabel_34to66 := getBoldLabelCentered(averageDistanceText_34to66)
averageDistanceLabel_67to100 := getBoldLabelCentered(averageDistanceText_67to100)
probabilityOfCorrectPredictionColumn.Add(probabilityOfCorrectPredictionRangeLabel)
accuracyRangeColumn_0to33.Add(averageDistanceLabel_0to33)
accuracyRangeColumn_34to66.Add(averageDistanceLabel_34to66)
accuracyRangeColumn_67to100.Add(averageDistanceLabel_67to100)
probabilityOfCorrectPredictionColumn.Add(widget.NewSeparator())
accuracyRangeColumn_0to33.Add(widget.NewSeparator())
accuracyRangeColumn_34to66.Add(widget.NewSeparator())
accuracyRangeColumn_67to100.Add(widget.NewSeparator())
if (probabilityMinimumRange == 1){
probabilityMinimumRange = 10
} else {
probabilityMinimumRange += 10
}
}
resultsGrid := container.NewHBox(layout.NewSpacer(), probabilityOfCorrectPredictionColumn, accuracyRangeColumn_0to33, accuracyRangeColumn_34to66, accuracyRangeColumn_67to100, layout.NewSpacer())
return resultsGrid, nil
}
resultsGrid, err := getResultsGrid()
if (err != nil){
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
return
}
page := container.NewVBox(title, exitButton, widget.NewSeparator(), description1, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), description2, description3, widget.NewSeparator(), resultsGrid)
pageScrollable := container.NewVScroll(page)
window.SetContent(pageScrollable)
}
// This function returns a list of training data and testing data filepaths for a trait. // This function returns a list of training data and testing data filepaths for a trait.
//Outputs: //Outputs:
// -[]string: Sorted list of training data filepaths // -[]string: Sorted list of training data filepaths
@ -1808,7 +2213,7 @@ func setViewModelTestingDiscreteTraitResultsPage(window fyne.Window, traitName s
// -error // -error
func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string, error){ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string, error){
if (traitName != "Eye Color" && traitName != "Lactose Tolerance"){ if (traitName != "Eye Color" && traitName != "Lactose Tolerance" && traitName != "Height"){
return nil, nil, errors.New("getTrainingAndTestingDataFilepathLists called with invalid traitName: " + traitName) return nil, nil, errors.New("getTrainingAndTestingDataFilepathLists called with invalid traitName: " + traitName)
} }
@ -1845,11 +2250,14 @@ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string
if (traitName == "Eye Color"){ if (traitName == "Eye Color"){
return 112953, nil return 113648, nil
} else if (traitName == "Lactose Tolerance"){ } else if (traitName == "Lactose Tolerance"){
return 24808, nil return 24872, nil
} else if (traitName == "Height"){
return 92281, nil
} }
return 0, errors.New("Unknown traitName: " + traitName) return 0, errors.New("Unknown traitName: " + traitName)
@ -1862,7 +2270,7 @@ func getTrainingAndTestingDataFilepathLists(traitName string)([]string, []string
numberOfTrainingDataFilesString := helpers.ConvertIntToString(numberOfTrainingDataFiles) numberOfTrainingDataFilesString := helpers.ConvertIntToString(numberOfTrainingDataFiles)
return nil, nil, errors.New(traitName + " number of training datas is unexpected: " + numberOfTrainingDataFilesString) return nil, nil, errors.New(traitName + " quantity of training datas is unexpected: " + numberOfTrainingDataFilesString)
} }
// We sort the training data to be in a deterministically random order // We sort the training data to be in a deterministically random order