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) }