seekia/gui/viewAnalysisGui_Couple.go

3427 lines
142 KiB
Go
Raw Normal View History

package gui
// viewAnalysisGui_Couple.go implements pages to view a couple genetic analysis
import "fyne.io/fyne/v2"
import "fyne.io/fyne/v2/container"
import "fyne.io/fyne/v2/layout"
import "fyne.io/fyne/v2/theme"
import "fyne.io/fyne/v2/widget"
import "fyne.io/fyne/v2/canvas"
import "seekia/resources/trainedPredictionModels"
import "seekia/resources/geneticReferences/monogenicDiseases"
import "seekia/resources/geneticReferences/polygenicDiseases"
import "seekia/resources/geneticReferences/traits"
import "seekia/internal/appMemory"
import "seekia/internal/createCharts"
import "seekia/internal/encoding"
import "seekia/internal/genetics/geneticAnalysis"
import "seekia/internal/genetics/myGenomes"
import "seekia/internal/genetics/myPeople"
import "seekia/internal/genetics/readGeneticAnalysis"
import "seekia/internal/helpers"
import "seekia/internal/statisticsDatum"
import "slices"
import "image"
import "errors"
func setViewCoupleGeneticAnalysisPage(window fyne.Window, person1Identifier string, person2Identifier string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, numberOfPerson1GenomesAnalyzed int, numberOfPerson2GenomesAnalyzed int, previousPage func()){
appMemory.SetMemoryEntry("CurrentViewedPage", "ViewCoupleGeneticAnalysisPage")
currentPage := func(){setViewCoupleGeneticAnalysisPage(window, person1Identifier, person2Identifier, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, numberOfPerson1GenomesAnalyzed, numberOfPerson2GenomesAnalyzed, previousPage)}
title := getPageTitleCentered("Viewing Genetic Analysis")
backButton := getBackButtonCentered(previousPage)
warningLabel1 := getBoldLabelCentered("WARNING: Results are not accurate!")
warningLabel2 := getBoldLabelCentered("The analysis algorithms have known issues that are being worked on.")
person1Found, person1Name, _, _, err := myPeople.GetPersonInfo(person1Identifier)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
if (person1Found == false){
setErrorEncounteredPage(window, errors.New("Couple person 1 not found."), previousPage)
return
}
person2Found, person2Name, _, _, err := myPeople.GetPersonInfo(person2Identifier)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
if (person2Found == false){
setErrorEncounteredPage(window, errors.New("Couple person 2 not found."), previousPage)
return
}
coupleNameLabel := widget.NewLabel("Couple Name:")
coupleNameText := getBoldLabel(person1Name + " + " + person2Name)
coupleNameRow := container.NewHBox(layout.NewSpacer(), coupleNameLabel, coupleNameText, layout.NewSpacer())
numberOfAnalyzedGenomesLabel := getLabelCentered("Number of Analyzed Genomes:")
person1NameLabel := widget.NewLabel(person1Name + ":")
person1NumberOfGenomesAnalyzedString := helpers.ConvertIntToString(numberOfPerson1GenomesAnalyzed)
person1NumberOfGenomesAnalyzedLabel := getBoldLabel(person1NumberOfGenomesAnalyzedString)
person1NumberOfAnalyzedGenomesRow := container.NewHBox(layout.NewSpacer(), person1NameLabel, person1NumberOfGenomesAnalyzedLabel, layout.NewSpacer())
person2NameLabel := widget.NewLabel(person2Name + ":")
person2NumberOfGenomesAnalyzedString := helpers.ConvertIntToString(numberOfPerson2GenomesAnalyzed)
person2NumberOfGenomesAnalyzedLabel := getBoldLabel(person2NumberOfGenomesAnalyzedString)
person2NumberOfAnalyzedGenomesRow := container.NewHBox(layout.NewSpacer(), person2NameLabel, person2NumberOfGenomesAnalyzedLabel, layout.NewSpacer())
generalButton := widget.NewButton("General", func(){
//TODO: Offspring inbred rating (kinship of parents), ancestry
showUnderConstructionDialog(window)
})
monogenicDiseasesButton := widget.NewButton("Monogenic Diseases", func(){
setViewCoupleGeneticAnalysisMonogenicDiseasesPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, currentPage)
})
polygenicDiseasesButton := widget.NewButton("Polygenic Diseases", func(){
setViewCoupleGeneticAnalysisPolygenicDiseasesPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, currentPage)
})
discreteTraitsButton := widget.NewButton("Discrete Traits", func(){
setViewCoupleGeneticAnalysisDiscreteTraitsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, currentPage)
})
numericTraitsButton := widget.NewButton("Numeric Traits", func(){
setViewCoupleGeneticAnalysisNumericTraitsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, currentPage)
})
categoryButtonsGrid := getContainerCentered(container.NewGridWithColumns(1, generalButton, monogenicDiseasesButton, polygenicDiseasesButton, discreteTraitsButton, numericTraitsButton))
page := container.NewVBox(title, backButton, widget.NewSeparator(), warningLabel1, warningLabel2, widget.NewSeparator(), coupleNameRow, widget.NewSeparator(), numberOfAnalyzedGenomesLabel, person1NumberOfAnalyzedGenomesRow, person2NumberOfAnalyzedGenomesRow, widget.NewSeparator(), categoryButtonsGrid)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisMonogenicDiseasesPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisMonogenicDiseasesPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, previousPage)}
title := getPageTitleCentered("Viewing Genetic Analysis - Monogenic Diseases")
backButton := getBackButtonCentered(previousPage)
description := getLabelCentered("Below is an analysis of the monogenic disease probabilities for the couple's offspring.")
//TODO: Sort so highest risk diseases are at the top. Everything else should be in normal order
getMonogenicDiseasesGrid := func()(*fyne.Container, error){
pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, _, _, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject)
if (err != nil){ return nil, err }
emptyLabelA := widget.NewLabel("")
diseaseNameLabel := getItalicLabelCentered("Disease Name")
offspringProbabilityOfLabel := getItalicLabelCentered("Offspring Probability Of")
havingDiseaseLabel := getItalicLabelCentered("Having Disease")
emptyLabelB := widget.NewLabel("")
conflictExistsLabel := getItalicLabelCentered("Conflict Exists?")
emptyLabelC := widget.NewLabel("")
emptyLabelD := widget.NewLabel("")
diseaseNameColumn := container.NewVBox(emptyLabelA, diseaseNameLabel, widget.NewSeparator())
offspringProbabilityOfHavingDiseaseColumn := container.NewVBox(offspringProbabilityOfLabel, havingDiseaseLabel, widget.NewSeparator())
conflictExistsColumn := container.NewVBox(emptyLabelB, conflictExistsLabel, widget.NewSeparator())
viewButtonsColumn := container.NewVBox(emptyLabelC, emptyLabelD, widget.NewSeparator())
monogenicDiseaseNamesList, err := monogenicDiseases.GetMonogenicDiseaseNamesList()
if (err != nil){ return nil, err }
for _, diseaseName := range monogenicDiseaseNamesList{
pair1GenomeIdentifierSlice := slices.Concat(pair1Person1GenomeIdentifier[:], pair1Person2GenomeIdentifier[:])
pair1GenomeIdentifier := [32]byte(pair1GenomeIdentifierSlice)
offspringHasDiseaseProbabilityIsKnown, _, genomePairOffspringProbabilityOfHavingDisease, _, _, _, conflictExists, err := readGeneticAnalysis.GetOffspringMonogenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, pair1GenomeIdentifier)
if (err != nil) { return nil, err }
getOffspringProbabilityOfHavingDiseaseText := func()string{
if (offspringHasDiseaseProbabilityIsKnown == false){
result := translate("Unknown")
return result
}
return genomePairOffspringProbabilityOfHavingDisease
}
offspringProbabilityOfHavingDiseaseText := getOffspringProbabilityOfHavingDiseaseText()
diseaseNameText := getBoldLabelCentered(diseaseName)
diseaseNameColumn.Add(diseaseNameText)
offspringProbabilityOfHavingDiseaseLabel := getBoldLabelCentered(offspringProbabilityOfHavingDiseaseText)
offspringProbabilityOfHavingDiseaseColumn.Add(offspringProbabilityOfHavingDiseaseLabel)
conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists)
conflictExistsLabel := getBoldLabelCentered(conflictExistsString)
conflictExistsColumn.Add(conflictExistsLabel)
viewDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
setViewCoupleGeneticAnalysisMonogenicDiseaseDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, currentPage)
}))
viewButtonsColumn.Add(viewDetailsButton)
diseaseNameColumn.Add(widget.NewSeparator())
offspringProbabilityOfHavingDiseaseColumn.Add(widget.NewSeparator())
conflictExistsColumn.Add(widget.NewSeparator())
viewButtonsColumn.Add(widget.NewSeparator())
}
offspringProbabilityOfHavingDiseaseHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringProbabilityOfHavingMonogenicDiseaseExplainerPage(window, currentPage)
})
offspringProbabilityOfHavingDiseaseColumn.Add(offspringProbabilityOfHavingDiseaseHelpButton)
diseasesGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, offspringProbabilityOfHavingDiseaseColumn)
if (secondGenomePairExists == true){
conflictExistsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setCoupleGeneticAnalysisConflictExistsExplainerPage(window, currentPage)
})
conflictExistsColumn.Add(conflictExistsHelpButton)
diseasesGrid.Add(conflictExistsColumn)
}
diseasesGrid.Add(viewButtonsColumn)
diseasesGrid.Add(layout.NewSpacer())
return diseasesGrid, nil
}
monogenicDiseasesContainer, err := getMonogenicDiseasesGrid()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), monogenicDiseasesContainer)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisMonogenicDiseaseDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisMonogenicDiseaseDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, previousPage)}
title := getPageTitleCentered("Viewing Couple Analysis - " + diseaseName)
backButton := getBackButtonCentered(previousPage)
pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getDescriptionSection := func()*fyne.Container{
if (secondGenomePairExists == false){
description := getLabelCentered("Below are the disease probabilities for the couple's offspring.")
return description
}
description1 := getLabelCentered("Below are the disease probabilities for the couple's offspring.")
description2 := getLabelCentered("Each genome pair combines different genomes from each person.")
descriptionsSection := container.NewVBox(description1, description2)
return descriptionsSection
}
descriptionSection := getDescriptionSection()
diseaseNameLabel := widget.NewLabel("Disease:")
diseaseNameText := getBoldLabel(diseaseName)
diseaseNameInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewMonogenicDiseaseDetailsPage(window, diseaseName, currentPage)
})
diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, diseaseNameInfoButton, layout.NewSpacer())
emptyLabel1 := widget.NewLabel("")
emptyLabel2 := widget.NewLabel("")
emptyLabel3 := widget.NewLabel("")
emptyLabel4 := widget.NewLabel("")
offspringProbabilityOfLabel1 := getItalicLabelCentered("Offspring Probability Of")
havingDiseaseLabel := getItalicLabelCentered("Having Disease")
offspringProbabilityOfLabel2 := getItalicLabelCentered("Offspring Probability Of")
havingVariantLabel := getItalicLabelCentered("Having Variant")
emptyLabel5 := widget.NewLabel("")
emptyLabel6 := widget.NewLabel("")
viewGenomePairButtonsColumn := container.NewVBox(emptyLabel1, emptyLabel2, widget.NewSeparator())
pairNameColumn := container.NewVBox(emptyLabel3, emptyLabel4, widget.NewSeparator())
offspringProbabilityOfHavingDiseaseColumn := container.NewVBox(offspringProbabilityOfLabel1, havingDiseaseLabel, widget.NewSeparator())
offspringProbabilityOfHavingVariantColumn := container.NewVBox(offspringProbabilityOfLabel2, havingVariantLabel, widget.NewSeparator())
viewOffspringVariantButtonsColumn := container.NewVBox(emptyLabel5, emptyLabel6, widget.NewSeparator())
addGenomePairRow := func(genomePairName string, person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
genomePairIdentifierSlice := slices.Concat(person1GenomeIdentifier[:], person2GenomeIdentifier[:])
genomePairIdentifier := [32]byte(genomePairIdentifierSlice)
offspringProbabilityOfHavingDiseaseIsKnown, _, genomePairOffspringProbabilityOfHavingDisease, offspringProbabilityOfHavingAVariantIsKnown, _, genomePairOffspringProbabilityOfHavingAVariant, _, err := readGeneticAnalysis.GetOffspringMonogenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier)
if (err != nil) { return err }
getOffspringProbabilityOfHavingDiseaseText := func()string{
if (offspringProbabilityOfHavingDiseaseIsKnown == false){
result := translate("Unknown")
return result
}
return genomePairOffspringProbabilityOfHavingDisease
}
offspringProbabilityOfHavingDiseaseText := getOffspringProbabilityOfHavingDiseaseText()
getOffspringProbabilityOfHavingAVariantText := func()string{
if (offspringProbabilityOfHavingAVariantIsKnown == false){
result := translate("Unknown")
return result
}
return genomePairOffspringProbabilityOfHavingAVariant
}
offspringProbabilityOfHavingAVariantText := getOffspringProbabilityOfHavingAVariantText()
genomePairNameLabel := getBoldLabelCentered(genomePairName)
offspringProbabilityOfHavingDiseaseLabel := getBoldLabelCentered(offspringProbabilityOfHavingDiseaseText)
offspringProbabilityOfHavingAVariantLabel := getBoldLabelCentered(offspringProbabilityOfHavingAVariantText)
viewGenomePairButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewCoupleGeneticAnalysisMonogenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage)
})
viewOffspringVariantsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
setViewCoupleMonogenicDiseaseVariantsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage)
})
viewGenomePairButtonsColumn.Add(viewGenomePairButton)
pairNameColumn.Add(genomePairNameLabel)
offspringProbabilityOfHavingDiseaseColumn.Add(offspringProbabilityOfHavingDiseaseLabel)
offspringProbabilityOfHavingVariantColumn.Add(offspringProbabilityOfHavingAVariantLabel)
viewOffspringVariantButtonsColumn.Add(viewOffspringVariantsButton)
viewGenomePairButtonsColumn.Add(widget.NewSeparator())
pairNameColumn.Add(widget.NewSeparator())
offspringProbabilityOfHavingDiseaseColumn.Add(widget.NewSeparator())
offspringProbabilityOfHavingVariantColumn.Add(widget.NewSeparator())
viewOffspringVariantButtonsColumn.Add(widget.NewSeparator())
return nil
}
err = addGenomePairRow("Pair 1", pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
if (secondGenomePairExists == true){
err := addGenomePairRow("Pair 2", pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
}
offspringProbabilityOfHavingDiseaseHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringProbabilityOfHavingMonogenicDiseaseExplainerPage(window, currentPage)
})
offspringProbabilityOfHavingVariantHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringProbabilityOfHavingVariantExplainerPage(window, currentPage)
})
offspringProbabilityOfHavingDiseaseColumn.Add(offspringProbabilityOfHavingDiseaseHelpButton)
offspringProbabilityOfHavingVariantColumn.Add(offspringProbabilityOfHavingVariantHelpButton)
genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairButtonsColumn, pairNameColumn, offspringProbabilityOfHavingDiseaseColumn, offspringProbabilityOfHavingVariantColumn, viewOffspringVariantButtonsColumn, layout.NewSpacer())
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), genomesContainer)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisMonogenicDiseaseGenomePairDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte, genomePairName string, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisMonogenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, previousPage)}
title := getPageTitleCentered("Viewing Couple Genome Pair Info")
backButton := getBackButtonCentered(previousPage)
description := getLabelCentered("Below is the disease information for both genomes in the genome pair.")
diseaseNameLabel := widget.NewLabel("Disease:")
diseaseNameText := getBoldLabel(diseaseName)
diseaseNameInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewMonogenicDiseaseDetailsPage(window, diseaseName, currentPage)
})
diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, diseaseNameInfoButton, layout.NewSpacer())
genomePairLabel := widget.NewLabel("Genome Pair:")
genomePairNameLabel := getBoldLabel(genomePairName)
genomePairHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setCoupleGenomePairExplainerPage(window, currentPage)
})
genomePairRow := container.NewHBox(layout.NewSpacer(), genomePairLabel, genomePairNameLabel, genomePairHelpButton, layout.NewSpacer())
diseaseVariantsMap, err := monogenicDiseases.GetMonogenicDiseaseVariantsMap(diseaseName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
totalNumberOfVariants := len(diseaseVariantsMap)
totalNumberOfVariantsString := helpers.ConvertIntToString(totalNumberOfVariants)
emptyLabelA := widget.NewLabel("")
personNameLabel := getItalicLabelCentered("Person Name")
emptyLabelB := widget.NewLabel("")
genomeNameLabel := getItalicLabelCentered("Genome Name")
probabilityOfLabel := getItalicLabelCentered("Probability Of")
passingAVariantLabel := getItalicLabelCentered("Passing A Variant")
numberOfLabel := getItalicLabelCentered("Number Of")
variantsTestedLabel := getItalicLabelCentered("Variants Tested")
emptyLabelC := widget.NewLabel("")
emptyLabelD := widget.NewLabel("")
personNameColumn := container.NewVBox(emptyLabelA, personNameLabel, widget.NewSeparator())
genomeNameColumn := container.NewVBox(emptyLabelB, genomeNameLabel, widget.NewSeparator())
probabilityOfPassingAVariantColumn := container.NewVBox(probabilityOfLabel, passingAVariantLabel, widget.NewSeparator())
numberOfVariantsTestedColumn := container.NewVBox(numberOfLabel, variantsTestedLabel, widget.NewSeparator())
viewGenomeButtonsColumn := container.NewVBox(emptyLabelC, emptyLabelD, widget.NewSeparator())
addGenomeRow := func(isPerson1 bool, personName string, inputGenomeIdentifier [16]byte)error{
personAnalysisGenomeIdentifier, _, genomeIsCombined, combinedType, err := readGeneticAnalysis.GetMatchingPersonAnalysisGenomeIdentifierFromCoupleAnalysis(isPerson1, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, inputGenomeIdentifier)
if (err != nil) { return err }
personNameTrimmed, _, err := helpers.TrimAndFlattenString(personName, 10)
if (err != nil) { return err }
personNameLabel := getBoldLabelCentered(personNameTrimmed)
getPersonAnalysisObject := func()geneticAnalysis.PersonAnalysis{
if (isPerson1 == true){
return person1AnalysisObject
}
return person2AnalysisObject
}
personAnalysisObject := getPersonAnalysisObject()
getGenomeName := func()(string, error){
if (genomeIsCombined == false){
genomeFound, _, _, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(personAnalysisGenomeIdentifier)
if (err != nil) { return "", err }
if (genomeFound == false){
return "", errors.New("MyGenomeInfo for genome from analysisObject not found.")
}
return companyName, nil
}
return combinedType, nil
}
genomeName, err := getGenomeName()
if (err != nil) { return err }
genomeNameLabel := getBoldLabelCentered(genomeName)
probabilitiesKnown, _, _, probabilityOfPassingAVariantFormatted, personNumberOfVariantsTested, _, _, _, err := readGeneticAnalysis.GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, personAnalysisGenomeIdentifier)
if (err != nil) { return err }
getProbabilityOfPassingAVariantText := func()string{
if (probabilitiesKnown == false){
result := translate("Unknown")
return result
}
return probabilityOfPassingAVariantFormatted
}
genomeProbabilityOfPassingAVariantText := getProbabilityOfPassingAVariantText()
genomeProbabilityOfPassingAVariantLabel := getBoldLabelCentered(genomeProbabilityOfPassingAVariantText)
personNumberOfVariantsTestedString := helpers.ConvertIntToString(personNumberOfVariantsTested)
genomeNumberOfVariantsTestedLabel := getBoldLabelCentered(personNumberOfVariantsTestedString + "/" + totalNumberOfVariantsString)
viewGenomeButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
setViewPersonGenomeMonogenicDiseaseVariantsPage(window, personAnalysisObject, personAnalysisGenomeIdentifier, genomeName, diseaseName, currentPage)
})
personNameColumn.Add(personNameLabel)
genomeNameColumn.Add(genomeNameLabel)
probabilityOfPassingAVariantColumn.Add(genomeProbabilityOfPassingAVariantLabel)
numberOfVariantsTestedColumn.Add(genomeNumberOfVariantsTestedLabel)
viewGenomeButtonsColumn.Add(viewGenomeButton)
personNameColumn.Add(widget.NewSeparator())
genomeNameColumn.Add(widget.NewSeparator())
probabilityOfPassingAVariantColumn.Add(widget.NewSeparator())
numberOfVariantsTestedColumn.Add(widget.NewSeparator())
viewGenomeButtonsColumn.Add(widget.NewSeparator())
return nil
}
person1GenomeIdentifier, person2GenomeIdentifier := helpers.Split32ByteArrayInHalf(genomePairIdentifier)
err = addGenomeRow(true, person1Name, person1GenomeIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
err = addGenomeRow(false, person2Name, person2GenomeIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
probabilityOfPassingAVariantHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setPersonProbabilityOfPassingVariantExplainerPage(window, currentPage)
})
numberOfVariantsTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setNumberOfTestedVariantsExplainerPage(window, currentPage)
})
probabilityOfPassingAVariantColumn.Add(probabilityOfPassingAVariantHelpButton)
numberOfVariantsTestedColumn.Add(numberOfVariantsTestedHelpButton)
genomesGrid := container.NewHBox(layout.NewSpacer(), personNameColumn, genomeNameColumn, probabilityOfPassingAVariantColumn, numberOfVariantsTestedColumn, viewGenomeButtonsColumn, layout.NewSpacer())
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, diseaseNameRow, genomePairRow, widget.NewSeparator(), genomesGrid)
setPageContent(page, window)
}
// This function provides a page to view the offspring disease variant probabilities for a particular genome pair from a couple genetic analysis
func setViewCoupleMonogenicDiseaseVariantsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte, genomePairName string, previousPage func()){
setLoadingScreen(window, "Loading Disease Variants", "Loading disease variants...")
currentPage := func(){setViewCoupleMonogenicDiseaseVariantsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, previousPage)}
title := getPageTitleCentered("View Offspring Disease Variants - " + diseaseName)
backButton := getBackButtonCentered(previousPage)
description1 := widget.NewLabel("Below are the disease variant probabilities for offspring from this genome pair.")
variantsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setMonogenicDiseaseVariantsExplainerPage(window, currentPage)
})
description1Row := container.NewHBox(layout.NewSpacer(), description1, variantsHelpButton, layout.NewSpacer())
genomePairLabel := widget.NewLabel("Genome Pair:")
genomePairNameLabel := getBoldLabel(genomePairName)
viewGenomePairInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewCoupleGeneticAnalysisMonogenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage)
})
genomePairRow := container.NewHBox(layout.NewSpacer(), genomePairLabel, genomePairNameLabel, viewGenomePairInfoButton, layout.NewSpacer())
//Outputs:
// -int: Number of variants tested
// -int: Number of loci tested
// -int: Number of phased loci
getVariantAndLociInfo := func()(int, int, int, error){
person1GenomeIdentifier, person2GenomeIdentifier := helpers.Split32ByteArrayInHalf(genomePairIdentifier)
person1AnalysisGenomeIdentifier, _, _, _, err := readGeneticAnalysis.GetMatchingPersonAnalysisGenomeIdentifierFromCoupleAnalysis(true, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, person1GenomeIdentifier)
if (err != nil) { return 0, 0, 0, err }
_, _, _, _, person1NumberOfVariantsTested, person1NumberOfLociTested, person1NumberOfPhasedLoci, _, err := readGeneticAnalysis.GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(person1AnalysisObject, diseaseName, person1AnalysisGenomeIdentifier)
if (err != nil) { return 0, 0, 0, err }
person2AnalysisGenomeIdentifier, _, _, _, err := readGeneticAnalysis.GetMatchingPersonAnalysisGenomeIdentifierFromCoupleAnalysis(false, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, person2GenomeIdentifier)
if (err != nil) { return 0, 0, 0, err }
_, _, _, _, person2NumberOfVariantsTested, person2NumberOfLociTested, person2NumberOfPhasedLoci, _, err := readGeneticAnalysis.GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(person2AnalysisObject, diseaseName, person2AnalysisGenomeIdentifier)
if (err != nil) { return 0, 0, 0, err }
numberOfVariantsTested := person1NumberOfVariantsTested + person2NumberOfVariantsTested
numberOfLociTested := person1NumberOfLociTested + person2NumberOfLociTested
numberOfPhasedLoci := person1NumberOfPhasedLoci + person2NumberOfPhasedLoci
return numberOfVariantsTested, numberOfLociTested, numberOfPhasedLoci, nil
}
numberOfVariantsTested, numberOfLociTested, numberOfPhasedLoci, err := getVariantAndLociInfo()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
diseaseVariantsMap, err := monogenicDiseases.GetMonogenicDiseaseVariantsMap(diseaseName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
totalNumberOfVariants := len(diseaseVariantsMap) * 2
totalNumberOfVariantsString := helpers.ConvertIntToString(totalNumberOfVariants)
numberOfVariantsTestedString := helpers.ConvertIntToString(numberOfVariantsTested)
variantsTestedLabel := widget.NewLabel("Variants Tested:")
variantsTestedText := getBoldLabel(numberOfVariantsTestedString + "/" + totalNumberOfVariantsString)
variantsTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setNumberOfTestedVariantsExplainerPage(window, currentPage)
})
variantsTestedRow := container.NewHBox(layout.NewSpacer(), variantsTestedLabel, variantsTestedText, variantsTestedHelpButton, layout.NewSpacer())
numberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested)
numberOfPhasedLociString := helpers.ConvertIntToString(numberOfPhasedLoci)
phasedLociLabel := widget.NewLabel("Phased Loci:")
phasedLociText := getBoldLabel(numberOfPhasedLociString + "/" + numberOfLociTestedString)
phasedLociHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setNumberOfPhasedLociExplainerPage(window, currentPage)
})
phasedLociRow := container.NewHBox(layout.NewSpacer(), phasedLociLabel, phasedLociText, phasedLociHelpButton, layout.NewSpacer())
//TODO: Add navigation with pages
getVariantsGrid := func()(*fyne.Container, error){
emptyLabelA := widget.NewLabel("")
variantNameLabel := getItalicLabelCentered("Variant Name")
probabilityOfLabelA := getItalicLabelCentered("Probability Of")
zeroMutationsLabel := getItalicLabelCentered("0 Mutations")
probabilityOfLabelB := getItalicLabelCentered("Probability Of")
oneMutationLabel := getItalicLabelCentered("1 Mutation")
probabilityOfLabelC := getItalicLabelCentered("Probability Of")
twoMutationsLabel := getItalicLabelCentered("2 Mutations")
emptyLabelB := widget.NewLabel("")
emptyLabelC := widget.NewLabel("")
variantNameColumn := container.NewVBox(emptyLabelA, variantNameLabel, widget.NewSeparator())
probabilityOf0MutationsColumn := container.NewVBox(probabilityOfLabelA, zeroMutationsLabel, widget.NewSeparator())
probabilityOf1MutationColumn := container.NewVBox(probabilityOfLabelB, oneMutationLabel, widget.NewSeparator())
probabilityOf2MutationsColumn := container.NewVBox(probabilityOfLabelC, twoMutationsLabel, widget.NewSeparator())
variantInfoButtonsColumn := container.NewVBox(emptyLabelB, emptyLabelC, widget.NewSeparator())
addVariantRow := func(variantIdentifierHex string)error{
variantObject, exists := diseaseVariantsMap[variantIdentifierHex]
if (exists == false){
return errors.New("Cannot add variant row: Variant missing from diseaseVariantsMap")
}
variantIdentifier, err := encoding.DecodeHexStringTo3ByteArray(variantIdentifierHex)
if (err != nil){
return errors.New("addVariantRow called with invalid variantIdentifier: " + variantIdentifierHex)
}
variantName := variantObject.VariantNames[0]
offspringProbabilitiesKnown, probabilityOf0MutationsLowerBound, probabilityOf0MutationsUpperBound, probabilityOf0MutationsFormatted, probabilityOf1MutationLowerBound, probabilityOf1MutationUpperBound, probabilityOf1MutationFormatted, probabilityOf2MutationsLowerBound, probabilityOf2MutationsUpperBound, probabilityOf2MutationsFormatted, err := readGeneticAnalysis.GetOffspringMonogenicDiseaseVariantInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, variantIdentifier, genomePairIdentifier)
if (err != nil) { return err }
getProbabilityOf0MutationsText := func()string{
if (offspringProbabilitiesKnown == false){
result := translate("Unknown")
return result
}
if (probabilityOf0MutationsLowerBound == 0 && probabilityOf0MutationsUpperBound == 100){
result := translate("Unknown")
return result
}
return probabilityOf0MutationsFormatted
}
probabilityOf0MutationsText := getProbabilityOf0MutationsText()
getProbabilityOf1MutationText := func()string{
if (offspringProbabilitiesKnown == false){
result := translate("Unknown")
return result
}
if (probabilityOf1MutationLowerBound == 0 && probabilityOf1MutationUpperBound == 100){
result := translate("Unknown")
return result
}
return probabilityOf1MutationFormatted
}
probabilityOf1MutationText := getProbabilityOf1MutationText()
getProbabilityOf2MutationsText := func()string{
if (offspringProbabilitiesKnown == false){
result := translate("Unknown")
return result
}
if (probabilityOf2MutationsLowerBound == 0 && probabilityOf2MutationsUpperBound == 100){
result := translate("Unknown")
return result
}
return probabilityOf2MutationsFormatted
}
probabilityOf2MutationsText := getProbabilityOf2MutationsText()
variantNameLabel := getBoldLabelCentered(variantName)
probabilityOf0MutationsLabel := getBoldLabelCentered(probabilityOf0MutationsText)
probabilityOf1MutationLabel := getBoldLabelCentered(probabilityOf1MutationText)
probabilityOf2MutationsLabel := getBoldLabelCentered(probabilityOf2MutationsText)
viewVariantDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
setViewCoupleGeneticAnalysisMonogenicDiseaseVariantDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, variantIdentifier, currentPage)
})
variantNameColumn.Add(variantNameLabel)
probabilityOf0MutationsColumn.Add(probabilityOf0MutationsLabel)
probabilityOf1MutationColumn.Add(probabilityOf1MutationLabel)
probabilityOf2MutationsColumn.Add(probabilityOf2MutationsLabel)
variantInfoButtonsColumn.Add(viewVariantDetailsButton)
variantNameColumn.Add(widget.NewSeparator())
probabilityOf0MutationsColumn.Add(widget.NewSeparator())
probabilityOf1MutationColumn.Add(widget.NewSeparator())
probabilityOf2MutationsColumn.Add(widget.NewSeparator())
variantInfoButtonsColumn.Add(widget.NewSeparator())
return nil
}
variantsWithNonZeroRiskList := make([]string, 0)
variantsWithZeroRiskFullyKnownList := make([]string, 0)
variantsWithZeroRiskPartiallyKnownList := make([]string, 0)
variantsWithUnknownRiskList := make([]string, 0)
for variantIdentifierHex, _ := range diseaseVariantsMap{
variantIdentifier, err := encoding.DecodeHexStringTo3ByteArray(variantIdentifierHex)
if (err != nil){
return nil, errors.New("diseaseVariantsMap contains invalid variantIdentifier: " + variantIdentifierHex)
}
probabilitesKnown, probabilityOf0MutationsLowerBound, probabilityOf0MutationsUpperBound, _, probabilityOf1MutationLowerBound, probabilityOf1MutationUpperBound, _, probabilityOf2MutationsLowerBound, probabilityOf2MutationsUpperBound, _, err := readGeneticAnalysis.GetOffspringMonogenicDiseaseVariantInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, variantIdentifier, genomePairIdentifier)
if (err != nil) { return nil, err }
if (probabilitesKnown == false){
variantsWithUnknownRiskList = append(variantsWithUnknownRiskList, variantIdentifierHex)
continue
}
if (probabilityOf1MutationLowerBound != 0 || probabilityOf2MutationsLowerBound != 0){
variantsWithNonZeroRiskList = append(variantsWithNonZeroRiskList, variantIdentifierHex)
continue
}
// Risk is either 0 or partially unknown
if (probabilityOf0MutationsLowerBound == 100 && probabilityOf0MutationsUpperBound == 100 && probabilityOf1MutationLowerBound == 0 && probabilityOf1MutationUpperBound == 0 && probabilityOf2MutationsLowerBound == 0 && probabilityOf2MutationsUpperBound == 0){
variantsWithZeroRiskFullyKnownList = append(variantsWithZeroRiskFullyKnownList, variantIdentifierHex)
continue
}
variantsWithZeroRiskPartiallyKnownList = append(variantsWithZeroRiskPartiallyKnownList, variantIdentifierHex)
}
// We sort each list so the variants show up in the same order each time
helpers.SortStringListToUnicodeOrder(variantsWithNonZeroRiskList)
helpers.SortStringListToUnicodeOrder(variantsWithZeroRiskFullyKnownList)
helpers.SortStringListToUnicodeOrder(variantsWithZeroRiskPartiallyKnownList)
helpers.SortStringListToUnicodeOrder(variantsWithUnknownRiskList)
for _, variantIdentifier := range variantsWithNonZeroRiskList{
err = addVariantRow(variantIdentifier)
if (err != nil) { return nil, err }
}
for _, variantIdentifier := range variantsWithZeroRiskFullyKnownList{
err = addVariantRow(variantIdentifier)
if (err != nil) { return nil, err }
}
for _, variantIdentifier := range variantsWithZeroRiskPartiallyKnownList{
err = addVariantRow(variantIdentifier)
if (err != nil) { return nil, err }
}
for _, variantIdentifier := range variantsWithUnknownRiskList{
err = addVariantRow(variantIdentifier)
if (err != nil) { return nil, err }
}
variantsGrid := container.NewHBox(layout.NewSpacer(), variantNameColumn, probabilityOf0MutationsColumn, probabilityOf1MutationColumn, probabilityOf2MutationsColumn, variantInfoButtonsColumn, layout.NewSpacer())
return variantsGrid, nil
}
variantsGrid, err := getVariantsGrid()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1Row, widget.NewSeparator(), genomePairRow, widget.NewSeparator(), variantsTestedRow, widget.NewSeparator(), phasedLociRow, widget.NewSeparator(), variantsGrid)
setPageContent(page, window)
}
// This function provides a page to view the details of a specific variant from a genetic analysis
// It will show the variant details for all of the couple's genome pairs
func setViewCoupleGeneticAnalysisMonogenicDiseaseVariantDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, variantIdentifier [3]byte, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisMonogenicDiseaseVariantDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, variantIdentifier, previousPage)}
title := getPageTitleCentered("Disease Variant Details - " + diseaseName)
backButton := getBackButtonCentered(previousPage)
variantIdentifierHex := encoding.EncodeBytesToHexString(variantIdentifier[:])
variantObject, err := monogenicDiseases.GetMonogenicDiseaseVariantObject(diseaseName, variantIdentifierHex)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
variantName := variantObject.VariantNames[0]
description := getLabelCentered("Below is the disease variant analysis for the couple.")
variantNameLabel := widget.NewLabel("Variant Name:")
variantNameText := getBoldLabel(variantName)
variantInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewMonogenicDiseaseVariantDetailsPage(window, diseaseName, variantIdentifierHex, currentPage)
})
variantNameRow := container.NewHBox(layout.NewSpacer(), variantNameLabel, variantNameText, variantInfoButton, layout.NewSpacer())
getGenomePairsHaveVariantGrid := func()(*fyne.Container, error){
emptyLabelA := widget.NewLabel("")
emptyLabelB := widget.NewLabel("")
emptyLabelC := widget.NewLabel("")
genomePairLabel := getItalicLabelCentered("Genome Pair")
probabilityOfLabelA := getItalicLabelCentered("Probability Of")
zeroMutationsLabel := getItalicLabelCentered("0 Mutations")
probabilityOfLabelB := getItalicLabelCentered("Probability Of")
oneMutationLabel := getItalicLabelCentered("1 Mutation")
probabilityOfLabelC := getItalicLabelCentered("Probability Of")
twoMutationsLabel := getItalicLabelCentered("2 Mutations")
viewGenomePairInfoButtonsColumn := container.NewVBox(emptyLabelA, emptyLabelB, widget.NewSeparator())
genomePairNameColumn := container.NewVBox(emptyLabelC, genomePairLabel, widget.NewSeparator())
probabilityOf0MutationsColumn := container.NewVBox(probabilityOfLabelA, zeroMutationsLabel, widget.NewSeparator())
probabilityOf1MutationColumn := container.NewVBox(probabilityOfLabelB, oneMutationLabel, widget.NewSeparator())
probablityOf2MutationsColumn := container.NewVBox(probabilityOfLabelC, twoMutationsLabel, widget.NewSeparator())
addGenomePairRow := func(genomePairName string, genomePairIdentifier [32]byte)error{
probabilitiesKnown, probabilityOf0MutationsLowerBound, probabilityOf0MutationsUpperBound, probabilityOf0MutationsFormatted, probabilityOf1MutationLowerBound, probabilityOf1MutationUpperBound, probabilityOf1MutationFormatted, probabilityOf2MutationsLowerBound, probabilityOf2MutationsUpperBound, probabilityOf2MutationsFormatted, err := readGeneticAnalysis.GetOffspringMonogenicDiseaseVariantInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, variantIdentifier, genomePairIdentifier)
if (err != nil) { return err }
getProbabilityOf0MutationsText := func()string{
if (probabilitiesKnown == false){
result := translate("Unknown")
return result
}
if (probabilityOf0MutationsLowerBound == 0 && probabilityOf0MutationsUpperBound == 100){
result := translate("Unknown")
return result
}
return probabilityOf0MutationsFormatted
}
probabilityOf0MutationsText := getProbabilityOf0MutationsText()
getProbabilityOf1MutationText := func()string{
if (probabilitiesKnown == false){
result := translate("Unknown")
return result
}
if (probabilityOf1MutationLowerBound == 0 && probabilityOf1MutationUpperBound == 100){
result := translate("Unknown")
return result
}
return probabilityOf1MutationFormatted
}
probabilityOf1MutationText := getProbabilityOf1MutationText()
getProbabilityOf2MutationsText := func()string{
if (probabilitiesKnown == false){
result := translate("Unknown")
return result
}
if (probabilityOf2MutationsLowerBound == 0 && probabilityOf2MutationsUpperBound == 100){
result := translate("Unknown")
return result
}
return probabilityOf2MutationsFormatted
}
probabilityOf2MutationsText := getProbabilityOf2MutationsText()
viewGenomePairInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewCoupleGeneticAnalysisMonogenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage)
})
genomePairNameLabel := getBoldLabelCentered(genomePairName)
probabilityOf0MutationsLabel := getBoldLabelCentered(probabilityOf0MutationsText)
probabilityOf1MutationLabel := getBoldLabelCentered(probabilityOf1MutationText)
probabilityOf2MutationsLabel := getBoldLabelCentered(probabilityOf2MutationsText)
viewGenomePairInfoButtonsColumn.Add(viewGenomePairInfoButton)
genomePairNameColumn.Add(genomePairNameLabel)
probabilityOf0MutationsColumn.Add(probabilityOf0MutationsLabel)
probabilityOf1MutationColumn.Add(probabilityOf1MutationLabel)
probablityOf2MutationsColumn.Add(probabilityOf2MutationsLabel)
viewGenomePairInfoButtonsColumn.Add(widget.NewSeparator())
genomePairNameColumn.Add(widget.NewSeparator())
probabilityOf0MutationsColumn.Add(widget.NewSeparator())
probabilityOf1MutationColumn.Add(widget.NewSeparator())
probablityOf2MutationsColumn.Add(widget.NewSeparator())
return nil
}
pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject)
if (err != nil){ return nil, err }
genomePair1Identifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
err = addGenomePairRow("Pair 1", genomePair1Identifier)
if (err != nil) { return nil, err }
if (secondGenomePairExists == true){
genomePair2Identifier := helpers.JoinTwo16ByteArrays(pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier)
err := addGenomePairRow("Pair 2", genomePair2Identifier)
if (err != nil) { return nil, err }
}
genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairInfoButtonsColumn, genomePairNameColumn, probabilityOf0MutationsColumn, probabilityOf1MutationColumn, probablityOf2MutationsColumn, layout.NewSpacer())
return genomesContainer, nil
}
genomePairsHaveVariantGrid, err := getGenomePairsHaveVariantGrid()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), variantNameRow, widget.NewSeparator(), genomePairsHaveVariantGrid)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisPolygenicDiseasesPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, previousPage)}
title := getPageTitleCentered("Viewing Genetic Analysis - Polygenic Diseases")
backButton := getBackButtonCentered(previousPage)
description := getLabelCentered("Below is an analysis of the polygenic disease risk probabilities for the couple's offspring.")
getDiseasesGrid := func()(*fyne.Container, error){
pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, _, _, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject)
if (err != nil){ return nil, err }
mainGenomePairIdentifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
diseaseNameLabel := getItalicLabelCentered("Disease Name")
offspringRiskScoreLabel := getItalicLabelCentered("Offspring Risk Score")
confidenceRangeLabel := getItalicLabelCentered("Confidence Range")
conflictExistsLabel := getItalicLabelCentered("Conflict Exists?")
emptyLabel4 := widget.NewLabel("")
diseaseNameColumn := container.NewVBox(diseaseNameLabel, widget.NewSeparator())
offspringRiskScoreColumn := container.NewVBox(offspringRiskScoreLabel, widget.NewSeparator())
confidenceRangeColumn := container.NewVBox(confidenceRangeLabel, widget.NewSeparator())
conflictExistsColumn := container.NewVBox(conflictExistsLabel, widget.NewSeparator())
viewButtonsColumn := container.NewVBox(emptyLabel4, widget.NewSeparator())
diseaseObjectsList, err := polygenicDiseases.GetPolygenicDiseaseObjectsList()
if (err != nil) { return nil, err }
for _, diseaseObject := range diseaseObjectsList{
diseaseName := diseaseObject.DiseaseName
neuralNetworkExists := trainedPredictionModels.CheckIfAttributeNeuralNetworkExists(diseaseName)
if (neuralNetworkExists == false){
// We cannot analyze this disease
continue
}
diseaseNameText := getBoldLabelCentered(diseaseName)
analysisExists, offspringRiskScore, predictionConfidenceRangesMap, _, _, _, conflictExists, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, mainGenomePairIdentifier)
if (err != nil) { return nil, err }
getRiskScoreLabel := func()fyne.Widget{
if (analysisExists == false){
result := widget.NewLabel(translate("Unknown"))
return result
}
offspringRiskScoreString := helpers.ConvertIntToString(offspringRiskScore)
offspringRiskScoreFormatted := offspringRiskScoreString + "/10"
riskScoreLabel := getBoldLabel(offspringRiskScoreFormatted)
return riskScoreLabel
}
riskScoreLabel := getRiskScoreLabel()
riskScoreLabelCentered := getWidgetCentered(riskScoreLabel)
getConfidenceRangeLabel := func()(fyne.Widget, error){
if (analysisExists == false){
unknownLabel := widget.NewLabel("Unknown")
return unknownLabel, nil
}
// This is a list of the percentage accuracies in the map
// For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be
// accurate within that range
confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap)
// We sort the list so the percentage is always the same upon refreshing the page
slices.Sort(confidenceRangePercentagesList)
closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80)
if (err != nil) { return nil, err }
closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage]
if (exists == false){
return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.")
}
closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2)
closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage)
confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)"
confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted)
return confidenceRangeLabel, nil
}
confidenceRangeLabel, err := getConfidenceRangeLabel()
if (err != nil) { return nil, err }
conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists)
conflictExistsLabel := getBoldLabelCentered(conflictExistsString)
viewDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, currentPage)
}))
diseaseNameColumn.Add(diseaseNameText)
offspringRiskScoreColumn.Add(riskScoreLabelCentered)
confidenceRangeColumn.Add(confidenceRangeLabel)
conflictExistsColumn.Add(conflictExistsLabel)
viewButtonsColumn.Add(viewDetailsButton)
diseaseNameColumn.Add(widget.NewSeparator())
offspringRiskScoreColumn.Add(widget.NewSeparator())
confidenceRangeColumn.Add(widget.NewSeparator())
conflictExistsColumn.Add(widget.NewSeparator())
viewButtonsColumn.Add(widget.NewSeparator())
}
offspringRiskScoreHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringPolygenicDiseaseRiskScoreExplainerPage(window, currentPage)
})
offspringRiskScoreColumn.Add(offspringRiskScoreHelpButton)
confidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
confidenceRangeColumn.Add(confidenceRangeHelpButton)
diseasesGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, offspringRiskScoreColumn, confidenceRangeColumn)
if (secondGenomePairExists == true){
conflictExistsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setCoupleGeneticAnalysisConflictExistsExplainerPage(window, currentPage)
})
conflictExistsColumn.Add(conflictExistsHelpButton)
diseasesGrid.Add(conflictExistsColumn)
}
diseasesGrid.Add(viewButtonsColumn)
diseasesGrid.Add(layout.NewSpacer())
return diseasesGrid, nil
}
diseasesGrid, err := getDiseasesGrid()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), diseasesGrid)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, previousPage)}
neuralNetworkExists := trainedPredictionModels.CheckIfAttributeNeuralNetworkExists(diseaseName)
if (neuralNetworkExists == false){
// We cannot analyze this disease
setErrorEncounteredPage(window, errors.New("setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage called non-analyzable trait: " + diseaseName), previousPage)
return
}
diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
diseaseLociList := diseaseObject.LociList
title := getPageTitleCentered("Viewing Couple Analysis - " + diseaseName)
backButton := getBackButtonCentered(previousPage)
pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getDescriptionSection := func()*fyne.Container{
if (secondGenomePairExists == false){
description := getLabelCentered("Below is the disease analysis for the couple's offspring.")
return description
}
description1 := getLabelCentered("Below is the disease analysis for the couple's offspring.")
description2 := getLabelCentered("Each genome pair combines different genomes from each person.")
descriptionsSection := container.NewVBox(description1, description2)
return descriptionsSection
}
descriptionSection := getDescriptionSection()
diseaseNameLabel := widget.NewLabel("Disease:")
diseaseNameText := getBoldLabel(diseaseName)
diseaseNameInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewPolygenicDiseaseDetailsPage(window, diseaseName, currentPage)
})
diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, diseaseNameInfoButton, layout.NewSpacer())
emptyLabel1 := widget.NewLabel("")
emptyLabel2 := widget.NewLabel("")
emptyLabel3 := widget.NewLabel("")
emptyLabel4 := widget.NewLabel("")
offspringLabel := getItalicLabelCentered("Offspring")
riskScoreLabel := getItalicLabelCentered("Risk Score")
emptyLabel5 := widget.NewLabel("")
confidenceRangeLabel := getItalicLabelCentered("Confidence Range")
quantityOfLabel := getItalicLabelCentered("Quantity Of")
lociKnownLabel := getItalicLabelCentered("Loci Known")
emptyLabel6 := widget.NewLabel("")
emptyLabel7 := widget.NewLabel("")
emptyLabel8 := widget.NewLabel("")
emptyLabel9 := widget.NewLabel("")
emptyLabel10 := widget.NewLabel("")
emptyLabel11 := widget.NewLabel("")
viewGenomePairButtonsColumn := container.NewVBox(emptyLabel1, emptyLabel2, widget.NewSeparator())
pairNameColumn := container.NewVBox(emptyLabel3, emptyLabel4, widget.NewSeparator())
offspringRiskScoreColumn := container.NewVBox(offspringLabel, riskScoreLabel, widget.NewSeparator())
confidenceRangeColumn := container.NewVBox(emptyLabel5, confidenceRangeLabel, widget.NewSeparator())
quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator())
viewSampleOffspringsChartButtonsColumn := container.NewVBox(emptyLabel6, emptyLabel7, widget.NewSeparator())
viewLifetimeRiskButtonsColumn := container.NewVBox(emptyLabel8, emptyLabel9, widget.NewSeparator())
viewDetailsButtonsColumn := container.NewVBox(emptyLabel10, emptyLabel11, widget.NewSeparator())
addGenomePairRow := func(genomePairName string, person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
genomePairNameLabel := getBoldLabelCentered(genomePairName)
genomePairIdentifier := helpers.JoinTwo16ByteArrays(person1GenomeIdentifier, person2GenomeIdentifier)
analysisExists, offspringRiskScore, predictionConfidenceRangesMap, quantityOfLociKnown, _, sampleOffspringRiskScoresList, _, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier)
if (err != nil) { return err }
getRiskScoreLabel := func()fyne.Widget{
if (analysisExists == false){
result := widget.NewLabel(translate("Unknown"))
return result
}
offspringRiskScoreString := helpers.ConvertIntToString(offspringRiskScore)
offspringRiskScoreFormatted := offspringRiskScoreString + "/10"
offspringRiskScoreLabel := getBoldLabel(offspringRiskScoreFormatted)
return offspringRiskScoreLabel
}
riskScoreLabel := getRiskScoreLabel()
riskScoreLabelCentered := getWidgetCentered(riskScoreLabel)
getConfidenceRangeLabel := func()(fyne.Widget, error){
if (analysisExists == false){
unknownLabel := widget.NewLabel("Unknown")
return unknownLabel, nil
}
// This is a list of the percentage accuracies in the map
// For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be
// accurate within that range
confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap)
// We sort the list so the percentage is always the same upon refreshing the page
slices.Sort(confidenceRangePercentagesList)
closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80)
if (err != nil) { return nil, err }
closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage]
if (exists == false){
return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.")
}
closestConfidenceDistanceString := helpers.ConvertFloat64ToStringRounded(closestToEightyPercentageConfidenceDistance, 2)
closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage)
confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)"
confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted)
return confidenceRangeLabel, nil
}
confidenceRangeLabel, err := getConfidenceRangeLabel()
if (err != nil) { return err }
totalQuantityOfLoci := len(diseaseLociList)
quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown)
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
viewGenomePairButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage)
})
viewSampleOffspringsChartButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window, diseaseName, sampleOffspringRiskScoresList, quantityOfLociKnown, currentPage)
})
viewOffspringLifetimeRiskButton := widget.NewButtonWithIcon("", theme.HistoryIcon(), func(){
getPageMaleOrFemale := func()string{
//TODO: Get user sex from myLocalProfiles
diseaseEffectedSex := diseaseObject.EffectedSex
if (diseaseEffectedSex == "Both"){
return "Male"
}
return diseaseEffectedSex
}
pageMaleOrFemale := getPageMaleOrFemale()
setViewPersonPolygenicDiseaseLifetimeProbabilitiesPage(window, diseaseName, genomePairName, pageMaleOrFemale, currentPage)
})
viewOffspringDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
viewGenomePairButtonsColumn.Add(viewGenomePairButton)
pairNameColumn.Add(genomePairNameLabel)
offspringRiskScoreColumn.Add(riskScoreLabelCentered)
confidenceRangeColumn.Add(confidenceRangeLabel)
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
viewSampleOffspringsChartButtonsColumn.Add(viewSampleOffspringsChartButton)
viewLifetimeRiskButtonsColumn.Add(viewOffspringLifetimeRiskButton)
viewDetailsButtonsColumn.Add(viewOffspringDetailsButton)
viewGenomePairButtonsColumn.Add(widget.NewSeparator())
pairNameColumn.Add(widget.NewSeparator())
offspringRiskScoreColumn.Add(widget.NewSeparator())
confidenceRangeColumn.Add(widget.NewSeparator())
quantityOfLociKnownColumn.Add(widget.NewSeparator())
viewSampleOffspringsChartButtonsColumn.Add(widget.NewSeparator())
viewLifetimeRiskButtonsColumn.Add(widget.NewSeparator())
viewDetailsButtonsColumn.Add(widget.NewSeparator())
return nil
}
err = addGenomePairRow("Pair 1", pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
if (secondGenomePairExists == true){
err := addGenomePairRow("Pair 2", pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
}
offspringRiskScoreHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringPolygenicDiseaseRiskScoreExplainerPage(window, currentPage)
})
offspringRiskScoreColumn.Add(offspringRiskScoreHelpButton)
confidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
showUnderConstructionDialog(window)
//TODO
})
confidenceRangeColumn.Add(confidenceRangeHelpButton)
offspringQuantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage)
})
quantityOfLociKnownColumn.Add(offspringQuantityOfLociKnownHelpButton)
genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairButtonsColumn, pairNameColumn, offspringRiskScoreColumn, confidenceRangeColumn, quantityOfLociKnownColumn, viewSampleOffspringsChartButtonsColumn, viewLifetimeRiskButtonsColumn, viewDetailsButtonsColumn, layout.NewSpacer())
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), genomesContainer)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte, genomePairName string, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, previousPage)}
title := getPageTitleCentered("Viewing Couple Genome Pair Info")
backButton := getBackButtonCentered(previousPage)
description := getLabelCentered("Below is the disease information for both genomes in the genome pair.")
diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
diseaseLociList := diseaseObject.LociList
diseaseNameLabel := widget.NewLabel("Disease:")
diseaseNameText := getBoldLabel(diseaseName)
diseaseNameInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewPolygenicDiseaseDetailsPage(window, diseaseName, currentPage)
})
diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, diseaseNameInfoButton, layout.NewSpacer())
genomePairLabel := widget.NewLabel("Genome Pair:")
genomePairNameLabel := getBoldLabel(genomePairName)
genomePairHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setCoupleGenomePairExplainerPage(window, currentPage)
})
genomePairRow := container.NewHBox(layout.NewSpacer(), genomePairLabel, genomePairNameLabel, genomePairHelpButton, layout.NewSpacer())
emptyLabelA := widget.NewLabel("")
personNameLabel := getItalicLabelCentered("Person Name")
emptyLabelB := widget.NewLabel("")
genomeNameLabel := getItalicLabelCentered("Genome Name")
emptyLabelC := widget.NewLabel("")
riskScoreLabel := getItalicLabelCentered("Risk Score")
quantityOfLabel := getItalicLabelCentered("Quantity Of")
lociTestedLabel := getItalicLabelCentered("Loci Tested")
emptyLabelD := widget.NewLabel("")
emptyLabelE := widget.NewLabel("")
personNameColumn := container.NewVBox(emptyLabelA, personNameLabel, widget.NewSeparator())
genomeNameColumn := container.NewVBox(emptyLabelB, genomeNameLabel, widget.NewSeparator())
riskScoreColumn := container.NewVBox(emptyLabelC, riskScoreLabel, widget.NewSeparator())
quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociTestedLabel, widget.NewSeparator())
viewGenomeButtonsColumn := container.NewVBox(emptyLabelD, emptyLabelE, widget.NewSeparator())
addGenomeRow := func(isPerson1 bool, personName string, inputGenomeIdentifier [16]byte)error{
personAnalysisGenomeIdentifier, _, genomeIsCombined, combinedType, err := readGeneticAnalysis.GetMatchingPersonAnalysisGenomeIdentifierFromCoupleAnalysis(isPerson1, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, inputGenomeIdentifier)
if (err != nil) { return err }
personNameTrimmed, _, err := helpers.TrimAndFlattenString(personName, 10)
if (err != nil) { return err }
personNameLabel := getBoldLabelCentered(personNameTrimmed)
getPersonAnalysisObject := func()geneticAnalysis.PersonAnalysis{
if (isPerson1 == true){
return person1AnalysisObject
}
return person2AnalysisObject
}
personAnalysisObject := getPersonAnalysisObject()
getGenomeName := func()(string, error){
if (genomeIsCombined == false){
genomeFound, _, _, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(personAnalysisGenomeIdentifier)
if (err != nil) { return "", err }
if (genomeFound == false){
return "", errors.New("MyGenomeInfo for genome from analysisObject not found.")
}
return companyName, nil
}
return combinedType, nil
}
genomeName, err := getGenomeName()
if (err != nil) { return err }
genomeNameLabel := getBoldLabelCentered(genomeName)
analysisExists, personRiskScore, _, quantityOfLociKnown, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, personAnalysisGenomeIdentifier)
if (err != nil) { return err }
getPersonRiskScoreLabel := func()fyne.Widget{
if (analysisExists == false){
result := widget.NewLabel(translate("Unknown"))
return result
}
personRiskScoreString := helpers.ConvertIntToString(personRiskScore)
personRiskScoreFormatted := personRiskScoreString + "/10"
personRiskScoreLabel := getBoldLabel(personRiskScoreFormatted)
return personRiskScoreLabel
}
personRiskScoreLabel := getPersonRiskScoreLabel()
genomeRiskScoreLabelCentered := getWidgetCentered(personRiskScoreLabel)
totalQuantityOfLoci := len(diseaseLociList)
quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown)
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
viewGenomeButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
personNameColumn.Add(personNameLabel)
genomeNameColumn.Add(genomeNameLabel)
riskScoreColumn.Add(genomeRiskScoreLabelCentered)
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
viewGenomeButtonsColumn.Add(viewGenomeButton)
personNameColumn.Add(widget.NewSeparator())
genomeNameColumn.Add(widget.NewSeparator())
riskScoreColumn.Add(widget.NewSeparator())
quantityOfLociKnownColumn.Add(widget.NewSeparator())
viewGenomeButtonsColumn.Add(widget.NewSeparator())
return nil
}
person1GenomeIdentifier, person2GenomeIdentifier := helpers.Split32ByteArrayInHalf(genomePairIdentifier)
err = addGenomeRow(true, person1Name, person1GenomeIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
err = addGenomeRow(false, person2Name, person2GenomeIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
riskScoreHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setPolygenicDiseaseRiskScoreExplainerPage(window, currentPage)
})
riskScoreColumn.Add(riskScoreHelpButton)
quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage)
})
quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton)
genomesGrid := container.NewHBox(layout.NewSpacer(), personNameColumn, genomeNameColumn, riskScoreColumn, quantityOfLociKnownColumn, viewGenomeButtonsColumn, layout.NewSpacer())
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), genomePairRow, widget.NewSeparator(), genomesGrid)
setPageContent(page, window)
}
// This is a page that shows the user 100 sample offspring polygenic disease risk scores on a bar chart
// This helps users to visualize the standard deviation of their offspring's disease risk with this user
func setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window fyne.Window, diseaseName string, sampleOffspringRiskScoresList []int, numberOfLociTested int, previousPage func()){
currentPage := func(){setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window, diseaseName, sampleOffspringRiskScoresList, numberOfLociTested, previousPage)}
title := getPageTitleCentered("Viewing Sample Offspring Risk Scores Chart")
backButton := getBackButtonCentered(previousPage)
description := widget.NewLabel("Below is a chart of 100 sample offspring risk scores for this disease.")
descriptionHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
descriptionRow := container.NewHBox(layout.NewSpacer(), description, descriptionHelpButton, layout.NewSpacer())
diseaseNameTitle := widget.NewLabel("Disease Name:")
diseaseNameLabel := getBoldLabel(diseaseName)
diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameTitle, diseaseNameLabel, layout.NewSpacer())
if (len(sampleOffspringRiskScoresList) == 0){
description2 := getBoldLabelCentered("There is no offspring information available for this disease.")
description3 := getBoldLabelCentered("This is because there were no disease loci for which both prospective parents had information.")
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionRow, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), description2, description3)
setPageContent(page, window)
return
}
diseaseLocusObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
diseaseLociList := diseaseLocusObject.LociList
totalNumberOfLoci := len(diseaseLociList)
totalNumberOfLociString := helpers.ConvertIntToString(totalNumberOfLoci)
numberOfLociTestedTitle := widget.NewLabel("Number Of Loci Tested:")
numberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested)
numberOfLociTestedLabel := getBoldLabel(numberOfLociTestedString + "/" + totalNumberOfLociString)
lociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage)
})
numberOfLociTestedRow := container.NewHBox(layout.NewSpacer(), numberOfLociTestedTitle, numberOfLociTestedLabel, lociTestedHelpButton, layout.NewSpacer())
getOffspringSampleRiskScoresChartImage := func()(image.Image, error){
offspringStatisticsDatumsList := make([]statisticsDatum.StatisticsDatum, 0)
for riskScore:=0; riskScore <= 10; riskScore += 1{
offspringCount := helpers.CountMatchingElementsInSlice(sampleOffspringRiskScoresList, riskScore)
riskScoreString := helpers.ConvertIntToString(riskScore)
offspringCountString := helpers.ConvertIntToString(offspringCount)
newStatisticsDatum := statisticsDatum.StatisticsDatum{
Label: riskScoreString + "/10",
LabelFormatted: riskScoreString + "/10",
Value: float64(offspringCount),
ValueFormatted: offspringCountString,
}
offspringStatisticsDatumsList = append(offspringStatisticsDatumsList, newStatisticsDatum)
}
chartTitle := diseaseName + ": 100 Prospective Offspring Risk Scores"
formatYAxisValuesFunction := func(inputOffspringCount float64)(string, error){
offspringCountString := helpers.ConvertIntToString(int(inputOffspringCount))
return offspringCountString, nil
}
offspringsChart, err := createCharts.CreateBarChart(chartTitle, offspringStatisticsDatumsList, formatYAxisValuesFunction, true, " Offspring")
if (err != nil) { return nil, err }
return offspringsChart, nil
}
offspringRiskScoresChartImage, err := getOffspringSampleRiskScoresChartImage()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewChartFullscreenButton := getWidgetCentered(widget.NewButtonWithIcon("View Fullscreen", theme.ZoomInIcon(), func(){
setViewFullpageImagePage(window, offspringRiskScoresChartImage, currentPage)
}))
pageHeader := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionRow, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), numberOfLociTestedRow, widget.NewSeparator())
chartFyneImage := canvas.NewImageFromImage(offspringRiskScoresChartImage)
chartFyneImage.FillMode = canvas.ImageFillContain
page := container.NewBorder(pageHeader, viewChartFullscreenButton, nil, nil, chartFyneImage)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisDiscreteTraitsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisDiscreteTraitsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, previousPage)}
title := getPageTitleCentered("Viewing Genetic Analysis - Discrete Traits")
backButton := getBackButtonCentered(previousPage)
description := getLabelCentered("Below is an analysis of the average discrete trait outcomes for the couple's offspring.")
getTraitsGrid := func()(*fyne.Container, error){
pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, _, _, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject)
if (err != nil){ return nil, err }
mainGenomePairIdentifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
emptyLabel1 := widget.NewLabel("")
traitNameLabel := getItalicLabelCentered("Trait Name")
emptyLabel2 := widget.NewLabel("")
predictedProbabilitiesLabel := getItalicLabelCentered("Predicted Probabilities")
quantityOfLabel := getItalicLabelCentered("Quantity Of")
lociKnownLabel := getItalicLabelCentered("Loci Known")
emptyLabel3 := widget.NewLabel("")
conflictExistsLabel := getItalicLabelCentered("Conflict Exists?")
emptyLabel4 := widget.NewLabel("")
emptyLabel5 := widget.NewLabel("")
traitNameColumn := container.NewVBox(emptyLabel1, traitNameLabel, widget.NewSeparator())
predictedProbabilitiesColumn := container.NewVBox(emptyLabel2, predictedProbabilitiesLabel, widget.NewSeparator())
quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator())
conflictExistsColumn := container.NewVBox(emptyLabel3, conflictExistsLabel, widget.NewSeparator())
viewDetailsButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator())
traitObjectsList, err := traits.GetTraitObjectsList()
if (err != nil) { return nil, err }
for _, traitObject := range traitObjectsList{
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Discrete"){
continue
}
traitLociList := traitObject.LociList
traitRulesList := traitObject.RulesList
if (len(traitLociList) == 0 && len(traitRulesList) == 0){
// This trait does not have any loci or rules
// We cannot analyze it yet
continue
}
traitName := traitObject.TraitName
neuralNetworkExists, neuralNetworkAnalysisExists, offspringOutcomeProbabilitiesMap_NeuralNetwork, _, quantityOfLociKnown_NeuralNetwork, _, anyRulesExist, rulesAnalysisExists, offspringOutcomeProbabilitiesMap_Rules, _, _, quantityOfLociKnown_Rules, conflictExists, err := readGeneticAnalysis.GetOffspringDiscreteTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, mainGenomePairIdentifier)
if (err != nil) { return nil, err }
if (neuralNetworkExists == false && anyRulesExist == false){
// We cannot analyze this trait
continue
}
getQuantityOfLociKnown := func()int{
if (neuralNetworkExists == true){
return quantityOfLociKnown_NeuralNetwork
}
return quantityOfLociKnown_Rules
}
quantityOfLociKnown := getQuantityOfLociKnown()
getTotalQuantityOfLoci := func()int{
if (neuralNetworkExists == true){
totalQuantityOfLoci := len(traitLociList)
return totalQuantityOfLoci
}
traitLociList_Rules := traitObject.LociList_Rules
totalQuantityOfLoci := len(traitLociList_Rules)
return totalQuantityOfLoci
}
totalQuantityOfLoci := getTotalQuantityOfLoci()
quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown)
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
// We add each row except for the outcome rows
// The outcome grid cell can be multiple rows tall
traitNameLabel := getBoldLabelCentered(traitName)
conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists)
conflictExistsLabel := getBoldLabelCentered(conflictExistsString)
viewDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, currentPage)
}))
traitNameColumn.Add(traitNameLabel)
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
conflictExistsColumn.Add(conflictExistsLabel)
viewDetailsButtonsColumn.Add(viewDetailsButton)
// Outputs:
// -bool: Outcome probabilities exist
// -map[string]int: Outcome Name -> Probability of outcome (0-100)
getOutcomeProbabilitiesMap := func()(bool, map[string]int){
if (neuralNetworkExists == true){
if (neuralNetworkAnalysisExists == false){
return false, nil
}
return true, offspringOutcomeProbabilitiesMap_NeuralNetwork
}
//anyRulesExist must be true
if (rulesAnalysisExists == false){
return false, nil
}
return true, offspringOutcomeProbabilitiesMap_Rules
}
outcomeProbabilitiesExist, outcomeProbabilitiesMap := getOutcomeProbabilitiesMap()
if (outcomeProbabilitiesExist == false){
unknownLabel := getItalicLabelCentered("Unknown")
predictedProbabilitiesColumn.Add(unknownLabel)
} else {
outcomeNamesList := traitObject.OutcomesList
outcomeNamesListSorted := helpers.CopyAndSortStringListToUnicodeOrder(outcomeNamesList)
addedItems := 0
for _, outcomeName := range outcomeNamesListSorted{
outcomeProbability, exists := outcomeProbabilitiesMap[outcomeName]
if (exists == false){
continue
}
if (outcomeProbability == 0){
continue
}
outcomeProbabilityString := helpers.ConvertIntToString(outcomeProbability)
outcomeRowLabel := getBoldLabel(outcomeName + ": " + outcomeProbabilityString + "%")
predictedProbabilitiesColumn.Add(outcomeRowLabel)
addedItems += 1
if (addedItems != 1){
// We have to add whitespace to the other columns
traitNameColumn.Add(widget.NewLabel(""))
quantityOfLociKnownColumn.Add(widget.NewLabel(""))
conflictExistsColumn.Add(widget.NewLabel(""))
viewDetailsButtonsColumn.Add(widget.NewLabel(""))
}
}
}
traitNameColumn.Add(widget.NewSeparator())
predictedProbabilitiesColumn.Add(widget.NewSeparator())
quantityOfLociKnownColumn.Add(widget.NewSeparator())
conflictExistsColumn.Add(widget.NewSeparator())
viewDetailsButtonsColumn.Add(widget.NewSeparator())
}
predictedProbabilitiesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
predictedProbabilitiesColumn.Add(predictedProbabilitiesHelpButton)
quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton)
traitsGrid := container.NewHBox(layout.NewSpacer(), traitNameColumn, predictedProbabilitiesColumn, quantityOfLociKnownColumn)
if (secondGenomePairExists == true){
conflictExistsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setCoupleGeneticAnalysisConflictExistsExplainerPage(window, currentPage)
})
conflictExistsColumn.Add(conflictExistsHelpButton)
traitsGrid.Add(conflictExistsColumn)
}
traitsGrid.Add(viewDetailsButtonsColumn)
traitsGrid.Add(layout.NewSpacer())
return traitsGrid, nil
}
traitsGrid, err := getTraitsGrid()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), traitsGrid)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, traitName string, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, previousPage)}
title := getPageTitleCentered("Viewing Couple Analysis - " + traitName)
backButton := getBackButtonCentered(previousPage)
pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getDescriptionSection := func()*fyne.Container{
if (secondGenomePairExists == false){
description := getLabelCentered("Below is the trait analysis for the couple's offspring.")
return description
}
description1 := getLabelCentered("Below is the trait analysis for the couple's offspring.")
description2 := getLabelCentered("Each genome pair combines different genomes from each person.")
descriptionsSection := container.NewVBox(description1, description2)
return descriptionsSection
}
descriptionSection := getDescriptionSection()
traitNameLabel := widget.NewLabel("Trait:")
traitNameText := getBoldLabel(traitName)
traitNameInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewTraitDetailsPage(window, traitName, currentPage)
})
traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitNameInfoButton, layout.NewSpacer())
traitObject, err := traits.GetTraitObject(traitName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Discrete"){
setErrorEncounteredPage(window, errors.New("setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage called with non-discrete trait: " + traitName), previousPage)
return
}
neuralNetworkExists := trainedPredictionModels.CheckIfAttributeNeuralNetworkExists(traitName)
emptyLabel1 := widget.NewLabel("")
emptyLabel2 := widget.NewLabel("")
emptyLabel3 := widget.NewLabel("")
genomePairLabel := getItalicLabelCentered("Genome Pair")
emptyLabel4 := widget.NewLabel("")
predictedProbabilitiesLabel := getItalicLabelCentered("Predicted Probabilities")
predictionLabel := getItalicLabelCentered("Prediction")
confidenceLabel := getItalicLabelCentered("Confidence")
quantityOfLabel1 := getItalicLabelCentered("Quantity Of")
rulesTestedLabel := getItalicLabelCentered("Rules Tested")
quantityOfLabel2 := getItalicLabelCentered("Quantity Of")
lociKnownLabel := getItalicLabelCentered("Loci Known")
emptyLabel5 := widget.NewLabel("")
emptyLabel6 := widget.NewLabel("")
viewGenomePairButtonsColumn := container.NewVBox(emptyLabel1, emptyLabel2, widget.NewSeparator())
pairNameColumn := container.NewVBox(emptyLabel3, genomePairLabel, widget.NewSeparator())
predictedProbabilitiesColumn := container.NewVBox(emptyLabel4, predictedProbabilitiesLabel, widget.NewSeparator())
neuralNetworkPredictionConfidenceColumn := container.NewVBox(predictionLabel, confidenceLabel, widget.NewSeparator())
quantityOfRulesTestedColumn := container.NewVBox(quantityOfLabel1, rulesTestedLabel, widget.NewSeparator())
quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel2, lociKnownLabel, widget.NewSeparator())
viewDetailsButtonsColumn := container.NewVBox(emptyLabel5, emptyLabel6, widget.NewSeparator())
addGenomePairRow := func(genomePairName string, person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
genomePairIdentifier := helpers.JoinTwo16ByteArrays(person1GenomeIdentifier, person2GenomeIdentifier)
genomePairNameLabel := getBoldLabelCentered(genomePairName)
viewGenomePairButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewCoupleGeneticAnalysisDiscreteTraitGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, genomePairIdentifier, genomePairName, currentPage)
})
viewAnalysisDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
if (neuralNetworkExists == true){
//TODO
showUnderConstructionDialog(window)
} else {
setViewCoupleDiscreteTraitRulesPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, genomePairIdentifier, genomePairName, currentPage)
}
})
viewGenomePairButtonsColumn.Add(viewGenomePairButton)
pairNameColumn.Add(genomePairNameLabel)
viewDetailsButtonsColumn.Add(viewAnalysisDetailsButton)
neuralNetworkExists, neuralNetworkAnalysisExists, offspringOutcomeProbabilitiesMap_NeuralNetwork, neuralNetworkPredictionConfidence, quantityOfLociKnown_NeuralNetwork, _, anyRulesExist, rulesAnalysisExists, offspringOutcomeProbabilitiesMap_Rules, _, quantityOfRulesTested, _, _, err := readGeneticAnalysis.GetOffspringDiscreteTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, genomePairIdentifier)
if (err != nil) { return err }
if (neuralNetworkExists == false && anyRulesExist == false){
return errors.New("setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage called with trait that is not analyzable.")
}
// First we add analysis details to their respective column
if (neuralNetworkExists == true){
if (neuralNetworkAnalysisExists == false){
neuralNetworkPredictionConfidenceColumn.Add(getLabelCentered("-"))
} else {
predictionConfidenceString := helpers.ConvertIntToString(neuralNetworkPredictionConfidence)
predictionConfidenceLabel := getBoldLabelCentered(predictionConfidenceString + "%")
neuralNetworkPredictionConfidenceColumn.Add(predictionConfidenceLabel)
}
traitLociList := traitObject.LociList
totalQuantityOfLoci := len(traitLociList)
quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown_NeuralNetwork)
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
} else {
if (anyRulesExist == false){
return errors.New("setViewCoupleGeneticAnalysisDiscreteTraitDetailsPage called with analysis which is missing ")
}
traitRulesList := traitObject.RulesList
totalNumberOfRules := len(traitRulesList)
totalNumberOfRulesString := helpers.ConvertIntToString(totalNumberOfRules)
quantityOfRulesTestedString := helpers.ConvertIntToString(quantityOfRulesTested)
quantityOfRulesTestedFormatted := quantityOfRulesTestedString + "/" + totalNumberOfRulesString
quantityOfRulesTestedLabel := getBoldLabelCentered(quantityOfRulesTestedFormatted)
quantityOfRulesTestedColumn.Add(quantityOfRulesTestedLabel)
}
// Now we add the outcome probabilities cell
// Outputs:
// -bool: Outcome probabilities exist
// -map[string]int: Outcome Name -> Probability of outcome (0-100)
getOutcomeProbabilitiesMap := func()(bool, map[string]int){
if (neuralNetworkExists == true){
if (neuralNetworkAnalysisExists == false){
return false, nil
}
return true, offspringOutcomeProbabilitiesMap_NeuralNetwork
}
//anyRulesExist must be true
if (rulesAnalysisExists == false){
return false, nil
}
return true, offspringOutcomeProbabilitiesMap_Rules
}
outcomeProbabilitiesExist, outcomeProbabilitiesMap := getOutcomeProbabilitiesMap()
if (outcomeProbabilitiesExist == false){
unknownLabel := getItalicLabelCentered("Unknown")
predictedProbabilitiesColumn.Add(unknownLabel)
} else {
outcomeNamesList := traitObject.OutcomesList
outcomeNamesListSorted := helpers.CopyAndSortStringListToUnicodeOrder(outcomeNamesList)
addedItems := 0
for _, outcomeName := range outcomeNamesListSorted{
outcomeProbability, exists := outcomeProbabilitiesMap[outcomeName]
if (exists == false){
continue
}
if (outcomeProbability == 0){
continue
}
outcomeProbabilityString := helpers.ConvertIntToString(outcomeProbability)
outcomeRowLabel := getBoldLabel(outcomeName + ": " + outcomeProbabilityString + "%")
predictedProbabilitiesColumn.Add(outcomeRowLabel)
addedItems += 1
if (addedItems > 1){
// We have to add whitespace to the other columns
viewGenomePairButtonsColumn.Add(widget.NewLabel(""))
pairNameColumn.Add(widget.NewLabel(""))
neuralNetworkPredictionConfidenceColumn.Add(widget.NewLabel(""))
quantityOfRulesTestedColumn.Add(widget.NewLabel(""))
quantityOfLociKnownColumn.Add(widget.NewLabel(""))
viewDetailsButtonsColumn.Add(widget.NewLabel(""))
}
}
}
viewGenomePairButtonsColumn.Add(widget.NewSeparator())
pairNameColumn.Add(widget.NewSeparator())
predictedProbabilitiesColumn.Add(widget.NewSeparator())
neuralNetworkPredictionConfidenceColumn.Add(widget.NewSeparator())
quantityOfRulesTestedColumn.Add(widget.NewSeparator())
quantityOfLociKnownColumn.Add(widget.NewSeparator())
viewDetailsButtonsColumn.Add(widget.NewSeparator())
return nil
}
err = addGenomePairRow("Pair 1", pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
if (secondGenomePairExists == true){
err := addGenomePairRow("Pair 2", pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
}
predictedProbabilitiesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
predictedProbabilitiesColumn.Add(predictedProbabilitiesHelpButton)
if (neuralNetworkExists == true){
neuralNetworkPredictionConfidenceHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringDiscreteTraitNeuralNetworkPredictionExplainerPage(window, currentPage)
})
neuralNetworkPredictionConfidenceColumn.Add(neuralNetworkPredictionConfidenceHelpButton)
quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
showUnderConstructionDialog(window)
//TODO
})
quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton)
} else {
quantityOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
})
quantityOfRulesTestedColumn.Add(quantityOfRulesTestedHelpButton)
}
genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairButtonsColumn, pairNameColumn, predictedProbabilitiesColumn)
if (neuralNetworkExists == true){
genomesContainer.Add(neuralNetworkPredictionConfidenceColumn)
genomesContainer.Add(quantityOfLociKnownColumn)
} else {
genomesContainer.Add(quantityOfRulesTestedColumn)
}
genomesContainer.Add(viewDetailsButtonsColumn)
genomesContainer.Add(layout.NewSpacer())
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), genomesContainer)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisDiscreteTraitGenomePairDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, traitName string, genomePairIdentifier [32]byte, genomePairName string, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisDiscreteTraitGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, genomePairIdentifier, genomePairName, previousPage)}
title := getPageTitleCentered("Viewing Couple Genome Pair Info")
backButton := getBackButtonCentered(previousPage)
description := getLabelCentered("Below is the trait information for both genomes in the genome pair.")
traitNameLabel := widget.NewLabel("Trait:")
traitNameText := getBoldLabel(traitName)
traitNameInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewTraitDetailsPage(window, traitName, currentPage)
})
traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitNameInfoButton, layout.NewSpacer())
genomePairLabel := widget.NewLabel("Genome Pair:")
genomePairNameLabel := getBoldLabel(genomePairName)
genomePairHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setCoupleGenomePairExplainerPage(window, currentPage)
})
genomePairRow := container.NewHBox(layout.NewSpacer(), genomePairLabel, genomePairNameLabel, genomePairHelpButton, layout.NewSpacer())
emptyLabel1 := widget.NewLabel("")
personNameLabel := getItalicLabelCentered("Person Name")
emptyLabel2 := widget.NewLabel("")
genomeNameLabel := getItalicLabelCentered("Genome Name")
emptyLabel3 := widget.NewLabel("")
predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome")
quantityOfLabel1 := getItalicLabelCentered("Quantity Of")
lociKnownLabel := getItalicLabelCentered("Loci Known")
quantityOfLabel2 := getItalicLabelCentered("Quantity Of")
rulesTestedLabel := getItalicLabelCentered("Rules Tested")
emptyLabel4 := widget.NewLabel("")
emptyLabel5 := widget.NewLabel("")
personNameColumn := container.NewVBox(emptyLabel1, personNameLabel, widget.NewSeparator())
genomeNameColumn := container.NewVBox(emptyLabel2, genomeNameLabel, widget.NewSeparator())
predictedOutcomeColumn := container.NewVBox(emptyLabel3, predictedOutcomeLabel, widget.NewSeparator())
quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel1, lociKnownLabel, widget.NewSeparator())
quantityOfRulesTestedColumn := container.NewVBox(quantityOfLabel2, rulesTestedLabel, widget.NewSeparator())
viewGenomeButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator())
addGenomeRow := func(isPerson1 bool, personName string, inputGenomeIdentifier [16]byte)error{
personAnalysisGenomeIdentifier, _, genomeIsCombined, combinedType, err := readGeneticAnalysis.GetMatchingPersonAnalysisGenomeIdentifierFromCoupleAnalysis(isPerson1, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, inputGenomeIdentifier)
if (err != nil) { return err }
personNameTrimmed, _, err := helpers.TrimAndFlattenString(personName, 10)
if (err != nil) { return err }
personNameLabel := getBoldLabelCentered(personNameTrimmed)
getPersonAnalysisObject := func()geneticAnalysis.PersonAnalysis{
if (isPerson1 == true){
return person1AnalysisObject
}
return person2AnalysisObject
}
personAnalysisObject := getPersonAnalysisObject()
getGenomeName := func()(string, error){
if (genomeIsCombined == false){
genomeFound, _, _, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(personAnalysisGenomeIdentifier)
if (err != nil) { return "", err }
if (genomeFound == false){
return "", errors.New("MyGenomeInfo for genome from analysisObject not found.")
}
return companyName, nil
}
return combinedType, nil
}
genomeName, err := getGenomeName()
if (err != nil) { return err }
genomeNameLabel := getBoldLabelCentered(genomeName)
neuralNetworkExists, neuralNetworkAnalysisExists, neuralNetworkPredictedOutcome, _, neuralNetworkQuantityOfLociTested, _, _, rulesAnalysisExists, _, rulesPredictedOutcomeExists, rulesPredictedOutcome, quantityOfRulesTested, _, _, err := readGeneticAnalysis.GetPersonDiscreteTraitInfoFromGeneticAnalysis(personAnalysisObject, traitName, personAnalysisGenomeIdentifier)
if (err != nil) { return err }
personNameColumn.Add(personNameLabel)
genomeNameColumn.Add(genomeNameLabel)
//Outputs:
// -bool: Outcome is known
// -string: Prediction outcome
getPredictedOutcome := func()(bool, string){
if (neuralNetworkExists == true){
if (neuralNetworkAnalysisExists == false){
return false, ""
}
return true, neuralNetworkPredictedOutcome
}
// Analysis must be rule-based
if (rulesAnalysisExists == false || rulesPredictedOutcomeExists == false){
return false, ""
}
return true, rulesPredictedOutcome
}
predictedOutcomeExists, predictedOutcome := getPredictedOutcome()
if (predictedOutcomeExists == false){
unknownLabel := getItalicLabelCentered(translate("Unknown"))
predictedOutcomeColumn.Add(unknownLabel)
} else {
predictedOutcomeLabel := getBoldLabelCentered(predictedOutcome)
predictedOutcomeColumn.Add(predictedOutcomeLabel)
}
// Now we add outcome details
traitObject, err := traits.GetTraitObject(traitName)
if (err != nil) { return err }
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Discrete"){
return errors.New("setViewCoupleGeneticAnalysisDiscreteTraitGenomePairDetailsPage called with non-discrete trait: " + traitName)
}
if (neuralNetworkExists == true){
traitLociList := traitObject.LociList
totalQuantityOfLoci := len(traitLociList)
quantityOfLociKnownString := helpers.ConvertIntToString(neuralNetworkQuantityOfLociTested)
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
} else {
// Analysis is rule-based
traitRulesList := traitObject.RulesList
totalQuantityOfRules := len(traitRulesList)
quantityOfRulesTestedString := helpers.ConvertIntToString(quantityOfRulesTested)
totalQuantityOfRulesString := helpers.ConvertIntToString(totalQuantityOfRules)
quantityOfRulesTestedFormatted := quantityOfRulesTestedString + "/" + totalQuantityOfRulesString
quantityOfRulesTestedLabel := getBoldLabelCentered(quantityOfRulesTestedFormatted)
quantityOfRulesTestedColumn.Add(quantityOfRulesTestedLabel)
}
viewGenomeButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
if (neuralNetworkExists == true){
//TODO
showUnderConstructionDialog(window)
} else {
setViewPersonGenomeDiscreteTraitRulesPage(window, personAnalysisObject, traitName, personAnalysisGenomeIdentifier, genomeName, currentPage)
}
})
viewGenomeButtonsColumn.Add(viewGenomeButton)
personNameColumn.Add(widget.NewSeparator())
genomeNameColumn.Add(widget.NewSeparator())
predictedOutcomeColumn.Add(widget.NewSeparator())
quantityOfLociKnownColumn.Add(widget.NewSeparator())
quantityOfRulesTestedColumn.Add(widget.NewSeparator())
viewGenomeButtonsColumn.Add(widget.NewSeparator())
return nil
}
person1GenomeIdentifier, person2GenomeIdentifier := helpers.Split32ByteArrayInHalf(genomePairIdentifier)
err := addGenomeRow(true, person1Name, person1GenomeIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
err = addGenomeRow(false, person2Name, person2GenomeIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
neuralNetworkExists := trainedPredictionModels.CheckIfAttributeNeuralNetworkExists(traitName)
predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
if (neuralNetworkExists == true){
setDiscreteTraitNeuralNetworkPredictionExplainerPage(window, currentPage)
} else {
setOffspringDiscreteTraitNeuralNetworkPredictionExplainerPage(window, currentPage)
}
})
predictedOutcomeColumn.Add(predictedOutcomeHelpButton)
quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton)
numberOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
})
quantityOfRulesTestedColumn.Add(numberOfRulesTestedHelpButton)
genomesGrid := container.NewHBox(layout.NewSpacer(), personNameColumn, genomeNameColumn, predictedOutcomeColumn)
if (neuralNetworkExists == true){
genomesGrid.Add(quantityOfLociKnownColumn)
} else {
genomesGrid.Add(quantityOfRulesTestedColumn)
}
genomesGrid.Add(viewGenomeButtonsColumn)
genomesGrid.Add(layout.NewSpacer())
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), genomePairRow, widget.NewSeparator(), genomesGrid)
setPageContent(page, window)
}
// This function provides a page to view the couple offspring rule probabilities for a particular genome pair
func setViewCoupleDiscreteTraitRulesPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, traitName string, genomePairIdentifier [32]byte, genomePairName string, previousPage func()){
setLoadingScreen(window, "Loading Trait Rules", "Loading trait rules...")
currentPage := func(){setViewCoupleDiscreteTraitRulesPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, genomePairIdentifier, genomePairName, previousPage)}
title := getPageTitleCentered("View Offspring Trait Rules - " + traitName)
backButton := getBackButtonCentered(previousPage)
description1 := widget.NewLabel("Below are the trait rule probabilities for offspring from this genome pair.")
traitRulesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringDiscreteTraitRulesExplainerPage(window, currentPage)
})
description1Row := container.NewHBox(layout.NewSpacer(), description1, traitRulesHelpButton, layout.NewSpacer())
genomePairLabel := widget.NewLabel("Genome Pair:")
genomePairNameLabel := getBoldLabel(genomePairName)
viewGenomePairInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewCoupleGeneticAnalysisDiscreteTraitGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, genomePairIdentifier, genomePairName, currentPage)
})
genomePairRow := container.NewHBox(layout.NewSpacer(), genomePairLabel, genomePairNameLabel, viewGenomePairInfoButton, layout.NewSpacer())
neuralNetworkExists, _, _, _, _, _, anyRulesExist, rulesAnalysisExists, _, _, quantityOfRulesTested, _, _, err := readGeneticAnalysis.GetOffspringDiscreteTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, genomePairIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (neuralNetworkExists == true){
setErrorEncounteredPage(window, errors.New("setViewCoupleTraitRulesPage called when neural network analysis for trait exists."), previousPage)
return
}
if (anyRulesExist == false){
setErrorEncounteredPage(window, errors.New("GetOffspringTraitInfoFromGeneticAnalysis claiming that no analysis method exists for triat: " + traitName), previousPage)
return
}
quantityOfRulesTestedString := helpers.ConvertIntToString(quantityOfRulesTested)
traitRulesMap, err := traits.GetTraitRulesMap(traitName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
totalNumberOfRules := len(traitRulesMap)
totalNumberOfRulesString := helpers.ConvertIntToString(totalNumberOfRules)
rulesTestedLabel := widget.NewLabel("Rules Tested:")
rulesTestedText := getBoldLabel(quantityOfRulesTestedString + "/" + totalNumberOfRulesString)
rulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
})
rulesTestedRow := container.NewHBox(layout.NewSpacer(), rulesTestedLabel, rulesTestedText, rulesTestedHelpButton, layout.NewSpacer())
getRulesGrid := func()(*fyne.Container, error){
emptyLabelA := widget.NewLabel("")
ruleIdentifierLabel := getItalicLabelCentered("Rule Identifier")
emptyLabelB := widget.NewLabel("")
ruleEffectsLabel := getItalicLabelCentered("Rule Effects")
offspringProbabilityOfLabel := getItalicLabelCentered("Offspring Probability Of")
passingRuleLabel := getItalicLabelCentered("Passing Rule")
emptyLabelC := widget.NewLabel("")
emptyLabelD := widget.NewLabel("")
ruleIdentifierColumn := container.NewVBox(emptyLabelA, ruleIdentifierLabel, widget.NewSeparator())
ruleEffectsColumn := container.NewVBox(emptyLabelB, ruleEffectsLabel, widget.NewSeparator())
offspringProbabilityOfPassingRuleColumn := container.NewVBox(offspringProbabilityOfLabel, passingRuleLabel, widget.NewSeparator())
ruleInfoButtonsColumn := container.NewVBox(emptyLabelC, emptyLabelD, widget.NewSeparator())
addRuleRow := func(ruleIdentifierHex string)error{
ruleIdentifierLabel := getBoldLabelCentered(ruleIdentifierHex)
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
if (err != nil) { return err }
getProbabilityOfPassingRuleText := func()(string, error){
if (rulesAnalysisExists == false){
// No rules were tested
result := translate("Unknown")
return result, nil
}
offspringRuleProbabilityKnown, _, offspringProbabilityOfPassingRuleFormatted, err := readGeneticAnalysis.GetOffspringDiscreteTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, ruleIdentifier, genomePairIdentifier)
if (err != nil) { return "", err }
if (offspringRuleProbabilityKnown == false){
result := translate("Unknown")
return result, nil
}
return offspringProbabilityOfPassingRuleFormatted, nil
}
probabilityOfPassingRuleText, err := getProbabilityOfPassingRuleText()
if (err != nil) { return err }
probabilityOfPassingRuleTextLabel := getBoldLabelCentered(probabilityOfPassingRuleText)
viewRuleDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
setViewCoupleGeneticAnalysisDiscreteTraitRuleDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, ruleIdentifier, currentPage)
})
// We add all of the columns except for the rule effects column
// We do this because the rule effects column may be multiple rows tall
ruleIdentifierColumn.Add(ruleIdentifierLabel)
offspringProbabilityOfPassingRuleColumn.Add(probabilityOfPassingRuleTextLabel)
ruleInfoButtonsColumn.Add(viewRuleDetailsButton)
traitRuleObject, exists := traitRulesMap[ruleIdentifierHex]
if (exists == false){
return errors.New("Trait rule not found after being found already: " + ruleIdentifierHex)
}
ruleOutcomePointsMap := traitRuleObject.OutcomePointsMap
outcomeNamesList := helpers.GetListOfMapKeys(ruleOutcomePointsMap)
// We have to sort the outcome names so they always show up in the same order
helpers.SortStringListToUnicodeOrder(outcomeNamesList)
for index, outcomeName := range outcomeNamesList{
outcomeChange, exists := ruleOutcomePointsMap[outcomeName]
if (exists == false){
return errors.New("OutcomeName not found in ruleOutcomePointsMap after being found already: " + outcomeName)
}
getOutcomeEffectString := func()string{
outcomeChangeString := helpers.ConvertIntToString(outcomeChange)
if (outcomeChange < 0){
return outcomeChangeString
}
outcomeEffect := "+" + outcomeChangeString
return outcomeEffect
}
outcomeEffect := getOutcomeEffectString()
outcomeRow := getBoldLabelCentered(outcomeName + ": " + outcomeEffect)
ruleEffectsColumn.Add(outcomeRow)
if (index > 0){
emptyLabelA := widget.NewLabel("")
emptyLabelB := widget.NewLabel("")
emptyLabelC := widget.NewLabel("")
ruleIdentifierColumn.Add(emptyLabelA)
offspringProbabilityOfPassingRuleColumn.Add(emptyLabelB)
ruleInfoButtonsColumn.Add(emptyLabelC)
}
}
ruleIdentifierColumn.Add(widget.NewSeparator())
ruleEffectsColumn.Add(widget.NewSeparator())
offspringProbabilityOfPassingRuleColumn.Add(widget.NewSeparator())
ruleInfoButtonsColumn.Add(widget.NewSeparator())
return nil
}
rulesWithKnownProbabilityList := make([]string, 0)
rulesWithUnknownProbabilityList := make([]string, 0)
for ruleIdentifierHex, _ := range traitRulesMap{
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
if (err != nil) { return nil, err }
offspringRuleProbabilityKnown, _, _, err := readGeneticAnalysis.GetOffspringDiscreteTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, ruleIdentifier, genomePairIdentifier)
if (err != nil) { return nil, err }
if (offspringRuleProbabilityKnown == true){
rulesWithKnownProbabilityList = append(rulesWithKnownProbabilityList, ruleIdentifierHex)
} else {
rulesWithUnknownProbabilityList = append(rulesWithUnknownProbabilityList, ruleIdentifierHex)
}
}
// Now we sort rules so they show up in the same order each time
helpers.SortStringListToUnicodeOrder(rulesWithKnownProbabilityList)
helpers.SortStringListToUnicodeOrder(rulesWithUnknownProbabilityList)
for _, ruleIdentifier := range rulesWithKnownProbabilityList{
err = addRuleRow(ruleIdentifier)
if (err != nil) { return nil, err }
}
for _, ruleIdentifier := range rulesWithUnknownProbabilityList{
err = addRuleRow(ruleIdentifier)
if (err != nil) { return nil, err }
}
ruleEffectsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setDiscreteTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
})
ruleEffectsColumn.Add(ruleEffectsHelpButton)
offspringProbabilityOfPassingRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringProbabilityOfPassingTraitRuleExplainerPage(window, currentPage)
})
offspringProbabilityOfPassingRuleColumn.Add(offspringProbabilityOfPassingRuleHelpButton)
rulesGrid := container.NewHBox(layout.NewSpacer(), ruleIdentifierColumn, ruleEffectsColumn, offspringProbabilityOfPassingRuleColumn, ruleInfoButtonsColumn, layout.NewSpacer())
return rulesGrid, nil
}
rulesGrid, err := getRulesGrid()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1Row, widget.NewSeparator(), genomePairRow, widget.NewSeparator(), rulesTestedRow, widget.NewSeparator(), rulesGrid)
setPageContent(page, window)
}
// This function implements a page to view the details of a specific rule from a genetic analysis
// It will show the rule details for all of the couple's genome pairs
func setViewCoupleGeneticAnalysisDiscreteTraitRuleDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, traitName string, ruleIdentifier [3]byte, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisDiscreteTraitRuleDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, ruleIdentifier, previousPage)}
title := getPageTitleCentered("Trait Rule Details - " + traitName)
backButton := getBackButtonCentered(previousPage)
description := getLabelCentered("Below is the trait rule analysis for the couple.")
ruleIdentifierHex := encoding.EncodeBytesToHexString(ruleIdentifier[:])
ruleIdentifierLabel := widget.NewLabel("Rule Identifier:")
ruleIdentifierText := getBoldLabel(ruleIdentifierHex)
ruleInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewDiscreteTraitRuleDetailsPage(window, traitName, ruleIdentifierHex, currentPage)
})
ruleIdentifierRow := container.NewHBox(layout.NewSpacer(), ruleIdentifierLabel, ruleIdentifierText, ruleInfoButton, layout.NewSpacer())
getGenomePairsRuleInfoGrid := func()(*fyne.Container, error){
emptyLabelA := widget.NewLabel("")
emptyLabelB := widget.NewLabel("")
emptyLabelC := widget.NewLabel("")
genomePairLabel := getItalicLabelCentered("Genome Pair")
offspringProbabilityOfLabel := getItalicLabelCentered("Offspring Probability Of")
passingRuleLabel := getItalicLabelCentered("Passing Rule")
viewGenomePairInfoButtonsColumn := container.NewVBox(emptyLabelA, emptyLabelB, widget.NewSeparator())
genomePairNameColumn := container.NewVBox(emptyLabelC, genomePairLabel, widget.NewSeparator())
offspringProbabilityOfPassingRuleColumn := container.NewVBox(offspringProbabilityOfLabel, passingRuleLabel, widget.NewSeparator())
addGenomePairRow := func(genomePairName string, genomePairIdentifier [32]byte)error{
offspringRuleProbabilityKnown, _, offspringProbabilityOfPassingRuleFormatted, err := readGeneticAnalysis.GetOffspringDiscreteTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, ruleIdentifier, genomePairIdentifier)
if (err != nil) { return err }
getOffspringProbabilityOfPassingRuleText := func()string{
if (offspringRuleProbabilityKnown == false){
result := translate("Unknown")
return result
}
return offspringProbabilityOfPassingRuleFormatted
}
offspringProbabilityOfPassingRuleText := getOffspringProbabilityOfPassingRuleText()
viewGenomePairInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewCoupleGeneticAnalysisDiscreteTraitGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, genomePairIdentifier, genomePairName, currentPage)
})
genomePairNameLabel := getBoldLabelCentered(genomePairName)
offspringProbabilityOfPassingRuleLabel := getBoldLabelCentered(offspringProbabilityOfPassingRuleText)
viewGenomePairInfoButtonsColumn.Add(viewGenomePairInfoButton)
genomePairNameColumn.Add(genomePairNameLabel)
offspringProbabilityOfPassingRuleColumn.Add(offspringProbabilityOfPassingRuleLabel)
viewGenomePairInfoButtonsColumn.Add(widget.NewSeparator())
genomePairNameColumn.Add(widget.NewSeparator())
offspringProbabilityOfPassingRuleColumn.Add(widget.NewSeparator())
return nil
}
pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject)
if (err != nil){ return nil, err }
genomePair1Identifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
err = addGenomePairRow("Pair 1", genomePair1Identifier)
if (err != nil) { return nil, err }
if (secondGenomePairExists == true){
genomePair2Identifier := helpers.JoinTwo16ByteArrays(pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier)
err := addGenomePairRow("Pair 2", genomePair2Identifier)
if (err != nil) { return nil, err }
}
genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairInfoButtonsColumn, genomePairNameColumn, offspringProbabilityOfPassingRuleColumn, layout.NewSpacer())
return genomesContainer, nil
}
genomePairsRuleInfoGrid, err := getGenomePairsRuleInfoGrid()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), ruleIdentifierRow, widget.NewSeparator(), genomePairsRuleInfoGrid)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisNumericTraitsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisNumericTraitsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, previousPage)}
title := getPageTitleCentered("Viewing Genetic Analysis - Numeric Traits")
backButton := getBackButtonCentered(previousPage)
description := getLabelCentered("Below is an analysis of the average numeric trait outcomes for the couple's offspring.")
getTraitsGrid := func()(*fyne.Container, error){
pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, _, _, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject)
if (err != nil){ return nil, err }
mainGenomePairIdentifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
traitNameLabel := getItalicLabelCentered("Trait Name")
predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome")
confidenceRangeLabel := getItalicLabelCentered("Confidence Range")
conflictExistsLabel := getItalicLabelCentered("Conflict Exists?")
emptyLabel5 := widget.NewLabel("")
traitNameColumn := container.NewVBox(traitNameLabel, widget.NewSeparator())
predictedOutcomeColumn := container.NewVBox(predictedOutcomeLabel, widget.NewSeparator())
confidenceRangeColumn := container.NewVBox(confidenceRangeLabel, widget.NewSeparator())
conflictExistsColumn := container.NewVBox(conflictExistsLabel, widget.NewSeparator())
viewDetailsButtonsColumn := container.NewVBox(emptyLabel5, widget.NewSeparator())
traitObjectsList, err := traits.GetTraitObjectsList()
if (err != nil) { return nil, err }
for _, traitObject := range traitObjectsList{
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Numeric"){
continue
}
traitLociList := traitObject.LociList
if (len(traitLociList) == 0){
// This trait does not have any loci
// We cannot analyze it yet
continue
}
traitName := traitObject.TraitName
neuralNetworkExists := trainedPredictionModels.CheckIfAttributeNeuralNetworkExists(traitName)
if (neuralNetworkExists == false){
// We cannot analyze this trait
continue
}
traitNameLabel := getBoldLabelCentered(traitName)
analysisExists, offspringAverageOutcome, predictionConfidenceRangesMap, _, _, _, conflictExists, err := readGeneticAnalysis.GetOffspringNumericTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, mainGenomePairIdentifier)
if (err != nil) { return nil, err }
outcomeFormatter := traitObject.NumericValueFormatter
getPredictedOutcomeLabel := func()(fyne.Widget, error){
if (analysisExists == false){
result := widget.NewLabel("Unknown")
return result, nil
}
predictedOutcomeFormatted, err := outcomeFormatter(offspringAverageOutcome, true)
if (err != nil) { return nil, err }
outcomeLabel := getBoldLabel(predictedOutcomeFormatted)
return outcomeLabel, nil
}
predictedOutcomeLabel, err := getPredictedOutcomeLabel()
if (err != nil) { return nil, err }
predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel)
getConfidenceRangeLabel := func()(fyne.Widget, error){
if (analysisExists == false){
result := widget.NewLabel("Unknown")
return result, nil
}
// This is a list of the percentage accuracies in the map
// For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be
// accurate within that range
confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap)
// We sort the list so the percentage is always the same upon refreshing the page
slices.Sort(confidenceRangePercentagesList)
closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80)
if (err != nil) { return nil, err }
closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage]
if (exists == false){
return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.")
}
closestConfidenceDistanceString, err := outcomeFormatter(closestToEightyPercentageConfidenceDistance, false)
if (err != nil) { return nil, err }
closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage)
confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)"
confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted)
return confidenceRangeLabel, nil
}
confidenceRangeLabel, err := getConfidenceRangeLabel()
if (err != nil) { return nil, err }
confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel)
conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists)
conflictExistsLabel := getBoldLabelCentered(conflictExistsString)
viewDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
setViewCoupleGeneticAnalysisNumericTraitDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, currentPage)
}))
traitNameColumn.Add(traitNameLabel)
predictedOutcomeColumn.Add(predictedOutcomeLabelCentered)
confidenceRangeColumn.Add(confidenceRangeLabelCentered)
conflictExistsColumn.Add(conflictExistsLabel)
viewDetailsButtonsColumn.Add(viewDetailsButton)
traitNameColumn.Add(widget.NewSeparator())
predictedOutcomeColumn.Add(widget.NewSeparator())
confidenceRangeColumn.Add(widget.NewSeparator())
conflictExistsColumn.Add(widget.NewSeparator())
viewDetailsButtonsColumn.Add(widget.NewSeparator())
}
predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
predictedOutcomeColumn.Add(predictedOutcomeHelpButton)
confidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
confidenceRangeColumn.Add(confidenceRangeHelpButton)
traitsGrid := container.NewHBox(layout.NewSpacer(), traitNameColumn, predictedOutcomeColumn, confidenceRangeColumn)
if (secondGenomePairExists == true){
conflictExistsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setCoupleGeneticAnalysisConflictExistsExplainerPage(window, currentPage)
})
conflictExistsColumn.Add(conflictExistsHelpButton)
traitsGrid.Add(conflictExistsColumn)
}
traitsGrid.Add(viewDetailsButtonsColumn)
traitsGrid.Add(layout.NewSpacer())
return traitsGrid, nil
}
traitsGrid, err := getTraitsGrid()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), traitsGrid)
setPageContent(page, window)
}
func setViewCoupleGeneticAnalysisNumericTraitDetailsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, traitName string, previousPage func()){
currentPage := func(){setViewCoupleGeneticAnalysisNumericTraitDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, traitName, previousPage)}
title := getPageTitleCentered("Viewing Couple Analysis - " + traitName)
backButton := getBackButtonCentered(previousPage)
pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier, secondGenomePairExists, pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier, _, _, _, _, _, _, err := readGeneticAnalysis.GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisObject)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getDescriptionSection := func()*fyne.Container{
if (secondGenomePairExists == false){
description := getLabelCentered("Below is the trait analysis for the couple's offspring.")
return description
}
description1 := getLabelCentered("Below is the trait analysis for the couple's offspring.")
description2 := getLabelCentered("Each genome pair combines different genomes from each person.")
descriptionsSection := container.NewVBox(description1, description2)
return descriptionsSection
}
descriptionSection := getDescriptionSection()
traitNameLabel := widget.NewLabel("Trait:")
traitNameText := getBoldLabel(traitName)
traitNameInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewTraitDetailsPage(window, traitName, currentPage)
})
traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitNameInfoButton, layout.NewSpacer())
neuralNetworkExists := trainedPredictionModels.CheckIfAttributeNeuralNetworkExists(traitName)
if (neuralNetworkExists == false){
// We cannot analyze this trait
setErrorEncounteredPage(window, errors.New("setViewCoupleGeneticAnalysisNumericTraitDetailsPage called non-analyzable trait: " + traitName), previousPage)
return
}
traitObject, err := traits.GetTraitObject(traitName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
if (traitIsDiscreteOrNumeric != "Numeric"){
setErrorEncounteredPage(window, errors.New("setViewCoupleGeneticAnalysisNumericTraitDetailsPage called with non-numeric trait: " + traitName), previousPage)
return
}
traitLociList := traitObject.LociList
emptyLabel1 := widget.NewLabel("")
emptyLabel2 := widget.NewLabel("")
emptyLabel3 := widget.NewLabel("")
genomePairLabel := getItalicLabelCentered("Genome Pair")
emptyLabel4 := widget.NewLabel("")
predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome")
emptyLabel5 := widget.NewLabel("")
confidenceRangeLabel := getItalicLabelCentered("Confidence Range")
quantityOfLabel := getItalicLabelCentered("Quantity Of")
lociKnownLabel := getItalicLabelCentered("Loci Known")
emptyLabel6 := widget.NewLabel("")
emptyLabel7 := widget.NewLabel("")
emptyLabel8 := widget.NewLabel("")
emptyLabel9 := widget.NewLabel("")
viewGenomePairButtonsColumn := container.NewVBox(emptyLabel1, emptyLabel2, widget.NewSeparator())
pairNameColumn := container.NewVBox(emptyLabel3, genomePairLabel, widget.NewSeparator())
predictedOutcomeColumn := container.NewVBox(emptyLabel4, predictedOutcomeLabel, widget.NewSeparator())
predictionConfidenceRangeColumn := container.NewVBox(emptyLabel5, confidenceRangeLabel, widget.NewSeparator())
quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator())
viewSampleOffspringButtonsColumn := container.NewVBox(emptyLabel6, emptyLabel7, widget.NewSeparator())
viewDetailsButtonsColumn := container.NewVBox(emptyLabel8, emptyLabel9, widget.NewSeparator())
addGenomePairRow := func(genomePairName string, person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
genomePairIdentifier := helpers.JoinTwo16ByteArrays(person1GenomeIdentifier, person2GenomeIdentifier)
genomePairNameLabel := getBoldLabelCentered(genomePairName)
viewGenomePairButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
analysisExists, offspringAverageOutcome, predictionConfidenceRangesMap, quantityOfLociKnown, _, sampleOffspringOutcomesList, _, err := readGeneticAnalysis.GetOffspringNumericTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, genomePairIdentifier)
if (err != nil) { return err }
outcomeFormatter := traitObject.NumericValueFormatter
getPredictedOutcomeLabel := func()(fyne.Widget, error){
if (analysisExists == false){
unknownLabel := widget.NewLabel("Unknown")
return unknownLabel, nil
}
offspringAverageOutcomeFormatted, err := outcomeFormatter(offspringAverageOutcome, true)
if (err != nil) { return nil, err }
predictedOutcomeLabel := getBoldLabel(offspringAverageOutcomeFormatted)
return predictedOutcomeLabel, nil
}
predictedOutcomeLabel, err := getPredictedOutcomeLabel()
if (err != nil) { return err }
predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel)
getConfidenceRangeLabel := func()(fyne.Widget, error){
if (analysisExists == false){
result := widget.NewLabel("Unknown")
return result, nil
}
// This is a list of the percentage accuracies in the map
// For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be
// accurate within that range
confidenceRangePercentagesList := helpers.GetListOfMapKeys(predictionConfidenceRangesMap)
// We sort the list so the percentage is always the same upon refreshing the page
slices.Sort(confidenceRangePercentagesList)
closestToEightyPercentage, err := helpers.GetClosestIntInList(confidenceRangePercentagesList, 80)
if (err != nil) { return nil, err }
closestToEightyPercentageConfidenceDistance, exists := predictionConfidenceRangesMap[closestToEightyPercentage]
if (exists == false){
return nil, errors.New("GetListOfMapKeys returning list of elements which contains element which is not in the map.")
}
closestConfidenceDistanceString, err := outcomeFormatter(closestToEightyPercentageConfidenceDistance, false)
if (err != nil) { return nil, err }
closestToEightyPercentageString := helpers.ConvertIntToString(closestToEightyPercentage)
confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)"
confidenceRangeLabel := getBoldLabel(confidenceRangeLabelValueFormatted)
return confidenceRangeLabel, nil
}
confidenceRangeLabel, err := getConfidenceRangeLabel()
if (err != nil) { return err }
confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel)
totalQuantityOfLoci := len(traitLociList)
quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown)
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
viewSampleOffspringsButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
setViewNumericTraitSampleOffspringOutcomesChart(window, traitName, sampleOffspringOutcomesList, quantityOfLociKnown, currentPage)
})
viewAnalysisDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
viewGenomePairButtonsColumn.Add(viewGenomePairButton)
pairNameColumn.Add(genomePairNameLabel)
predictedOutcomeColumn.Add(predictedOutcomeLabelCentered)
predictionConfidenceRangeColumn.Add(confidenceRangeLabelCentered)
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
viewSampleOffspringButtonsColumn.Add(viewSampleOffspringsButton)
viewDetailsButtonsColumn.Add(viewAnalysisDetailsButton)
viewGenomePairButtonsColumn.Add(widget.NewSeparator())
pairNameColumn.Add(widget.NewSeparator())
predictedOutcomeColumn.Add(widget.NewSeparator())
predictionConfidenceRangeColumn.Add(widget.NewSeparator())
quantityOfLociKnownColumn.Add(widget.NewSeparator())
viewSampleOffspringButtonsColumn.Add(widget.NewSeparator())
viewDetailsButtonsColumn.Add(widget.NewSeparator())
return nil
}
err = addGenomePairRow("Pair 1", pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
if (secondGenomePairExists == true){
err := addGenomePairRow("Pair 2", pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
}
predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
predictedOutcomeColumn.Add(predictedOutcomeHelpButton)
confidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
predictionConfidenceRangeColumn.Add(confidenceRangeHelpButton)
quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton)
genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairButtonsColumn, pairNameColumn, predictedOutcomeColumn, predictionConfidenceRangeColumn, quantityOfLociKnownColumn, viewSampleOffspringButtonsColumn, viewDetailsButtonsColumn, layout.NewSpacer())
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), genomesContainer)
setPageContent(page, window)
}
// This is a page that shows the user 100 sample offspring trait outcomes on a bar chart
// This helps users to visualize the standard deviation of their offspring's trait outcomes with this user
func setViewNumericTraitSampleOffspringOutcomesChart(window fyne.Window, traitName string, sampleOffspringOutcomesList []float64, quantityOfLociKnown int, previousPage func()){
currentPage := func(){setViewNumericTraitSampleOffspringOutcomesChart(window, traitName, sampleOffspringOutcomesList, quantityOfLociKnown, previousPage)}
title := getPageTitleCentered("Viewing Sample Offspring Outcomes Chart")
backButton := getBackButtonCentered(previousPage)
description := widget.NewLabel("Below is a chart of 100 sample offspring trait outcomes for this disease.")
descriptionHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
descriptionRow := container.NewHBox(layout.NewSpacer(), description, descriptionHelpButton, layout.NewSpacer())
traitNameTitle := widget.NewLabel("Trait Name:")
traitNameLabel := getBoldLabel(traitName)
traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameTitle, traitNameLabel, layout.NewSpacer())
if (len(sampleOffspringOutcomesList) == 0){
description2 := getBoldLabelCentered("There is no offspring information available for this trait.")
description3 := getBoldLabelCentered("This is because there were no trait loci for which both prospective parents had information.")
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionRow, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), description2, description3)
setPageContent(page, window)
return
}
traitObject, err := traits.GetTraitObject(traitName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
traitLociList := traitObject.LociList
totalNumberOfLoci := len(traitLociList)
totalNumberOfLociString := helpers.ConvertIntToString(totalNumberOfLoci)
numberOfLociKnownTitle := widget.NewLabel("Quantity Of Loci Known:")
numberOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown)
numberOfLociKnownLabel := getBoldLabel(numberOfLociKnownString + "/" + totalNumberOfLociString)
lociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
//TODO
showUnderConstructionDialog(window)
})
quantityOfLociKnownRow := container.NewHBox(layout.NewSpacer(), numberOfLociKnownTitle, numberOfLociKnownLabel, lociKnownHelpButton, layout.NewSpacer())
getOffspringSampleOutcomesChartImage := func()(image.Image, error){
if (len(sampleOffspringOutcomesList) != 100){
return nil, errors.New("setViewNumericTraitSampleOffspringOutcomesChart called with offspringOutcomesList that is not 100 items in length.")
}
// We sort the list in ascending order
slices.Sort(sampleOffspringOutcomesList)
outcomeFormatter := traitObject.NumericValueFormatter
getOffspringStatisticsDatumsList := func()([]statisticsDatum.StatisticsDatum, error){
offspringStatisticsDatumsList := make([]statisticsDatum.StatisticsDatum, 0)
smallestItem := sampleOffspringOutcomesList[0]
largestItem := sampleOffspringOutcomesList[99]
if (smallestItem == largestItem){
// We can't split the values into groups
// Every offspring has the same value
onlyValue := helpers.ConvertFloat64ToString(smallestItem)
onlyValueFormatted, err := outcomeFormatter(smallestItem, true)
if (err != nil) { return nil, err }
newStatisticsDatum := statisticsDatum.StatisticsDatum{
Label: onlyValue,
LabelFormatted: onlyValueFormatted,
Value: float64(100),
ValueFormatted: "100",
}
offspringStatisticsDatumsList = append(offspringStatisticsDatumsList, newStatisticsDatum)
return offspringStatisticsDatumsList, nil
}
// We split all outcomes into ten groups
sizeOfEachGroup := (largestItem-smallestItem)/10
index := float64(smallestItem)
for {
getGroupUpperBound := func()float64{
if (len(offspringStatisticsDatumsList) == 9){
// We are adding the last datum
return largestItem
}
groupUpperBound := index + sizeOfEachGroup
return groupUpperBound
}
groupUpperBound := getGroupUpperBound()
offspringInGroupCount := 0
for _, outcomeValue := range sampleOffspringOutcomesList{
if (outcomeValue >= index && outcomeValue < groupUpperBound){
offspringInGroupCount += 1
}
}
groupLowerBoundString, err := outcomeFormatter(index, true)
if (err != nil) { return nil, err }
groupUpperBoundString, err := outcomeFormatter(groupUpperBound, true)
if (err != nil) { return nil, err }
groupDescription := groupLowerBoundString + "-" + groupUpperBoundString
offspringCountString := helpers.ConvertIntToString(offspringInGroupCount)
newStatisticsDatum := statisticsDatum.StatisticsDatum{
Label: groupDescription,
LabelFormatted: groupDescription,
Value: float64(offspringInGroupCount),
ValueFormatted: offspringCountString,
}
offspringStatisticsDatumsList = append(offspringStatisticsDatumsList, newStatisticsDatum)
if (len(offspringStatisticsDatumsList) == 10){
break
}
index += sizeOfEachGroup
}
return offspringStatisticsDatumsList, nil
}
offspringStatisticsDatumsList, err := getOffspringStatisticsDatumsList()
if (err != nil) { return nil, err }
chartTitle := traitName + ": 100 Prospective Offspring Values"
formatYAxisValuesFunction := func(inputOffspringCount float64)(string, error){
result := helpers.ConvertIntToString(int(inputOffspringCount))
return result, nil
}
offspringsChart, err := createCharts.CreateBarChart(chartTitle, offspringStatisticsDatumsList, formatYAxisValuesFunction, true, " Offspring")
if (err != nil) { return nil, err }
return offspringsChart, nil
}
offspringOutcomesChartImage, err := getOffspringSampleOutcomesChartImage()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewChartFullscreenButton := getWidgetCentered(widget.NewButtonWithIcon("View Fullscreen", theme.ZoomInIcon(), func(){
setViewFullpageImagePage(window, offspringOutcomesChartImage, currentPage)
}))
pageHeader := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionRow, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), quantityOfLociKnownRow, widget.NewSeparator())
chartFyneImage := canvas.NewImageFromImage(offspringOutcomesChartImage)
chartFyneImage.FillMode = canvas.ImageFillContain
page := container.NewBorder(pageHeader, viewChartFullscreenButton, nil, nil, chartFyneImage)
setPageContent(page, window)
}