package gui // viewAnalysisGui_Person.go implements pages to view a person genetic analysis //TODO: Use person's sex to show opposite sex diseases and traits in different section // For example, Ovarian Cancer for men, and Testicular Cancer for women // We still want these risks/traits to be viewable, just put into a different part of the gui 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 "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/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 "slices" import "errors" func setViewPersonGeneticAnalysisPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, numberOfGenomesAnalyzed int, previousPage func()){ appMemory.SetMemoryEntry("CurrentViewedPage", "ViewGeneticAnalysisPage") currentPage := func(){setViewPersonGeneticAnalysisPage(window, personIdentifier, analysisObject, numberOfGenomesAnalyzed, 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.") personFound, personName, _, _, err := myPeople.GetPersonInfo(personIdentifier) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } if (personFound == false){ setErrorEncounteredPage(window, errors.New("setViewPersonGeneticAnalysisPage called with unknown personIdentifier: " + personIdentifier), previousPage) return } personNameLabel := widget.NewLabel("Person Name:") personNameText := getBoldLabel(personName) personNameRow := container.NewHBox(layout.NewSpacer(), personNameLabel, personNameText, layout.NewSpacer()) numberOfGenomesAnalyzedString := helpers.ConvertIntToString(numberOfGenomesAnalyzed) numberOfAnalyzedGenomesLabel := widget.NewLabel("Number of Analyzed Genomes:") numberOfAnalyzedGenomesText := getBoldLabel(numberOfGenomesAnalyzedString) numberOfAnalyzedGenomesRow := container.NewHBox(layout.NewSpacer(), numberOfAnalyzedGenomesLabel, numberOfAnalyzedGenomesText, layout.NewSpacer()) generalButton := widget.NewButton("General", func(){ //TODO: Inbred rating (parent relatedness), ancestry showUnderConstructionDialog(window) }) monogenicDiseasesButton := widget.NewButton("Monogenic Diseases", func(){ setViewPersonGeneticAnalysisMonogenicDiseasesPage(window, analysisObject, currentPage) }) polygenicDiseasesButton := widget.NewButton("Polygenic Diseases", func(){ setViewPersonGeneticAnalysisPolygenicDiseasesPage(window, personIdentifier, analysisObject, currentPage) }) discreteTraitsButton := widget.NewButton("Discrete Traits", func(){ setViewPersonGeneticAnalysisDiscreteTraitsPage(window, personIdentifier, analysisObject, currentPage) }) numericTraitsButton := widget.NewButton("Numeric Traits", func(){ setViewPersonGeneticAnalysisNumericTraitsPage(window, personIdentifier, analysisObject, currentPage) }) categoryButtonsGrid := getContainerCentered(container.NewGridWithColumns(1, generalButton, monogenicDiseasesButton, polygenicDiseasesButton, discreteTraitsButton, numericTraitsButton)) page := container.NewVBox(title, backButton, widget.NewSeparator(), warningLabel1, warningLabel2, widget.NewSeparator(), personNameRow, numberOfAnalyzedGenomesRow, widget.NewSeparator(), categoryButtonsGrid) setPageContent(page, window) } func setViewPersonGeneticAnalysisMonogenicDiseasesPage(window fyne.Window, analysisObject geneticAnalysis.PersonAnalysis, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisMonogenicDiseasesPage(window, analysisObject, previousPage)} title := getPageTitleCentered("Viewing Genetic Analysis - Monogenic Diseases") backButton := getBackButtonCentered(previousPage) description := getLabelCentered("Below is an analysis of the monogenic diseases found in the person's genome.") getMonogenicDiseasesContainer := func()(*fyne.Container, error){ allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) if (err != nil){ return nil, err } // Outputs: // -[16]byte: Main genome identifier (Is either the combined Only exclude conflicts genome or the only genome) // -error getMainGenomeIdentifier := func()([16]byte, error){ if (multipleGenomesExist == true){ return onlyExcludeConflictsGenomeIdentifier, nil } // Only 1 genome exists genomeIdentifier := allRawGenomeIdentifiersList[0] return genomeIdentifier, nil } mainGenomeIdentifier, err := getMainGenomeIdentifier() if (err != nil){ return nil, err } diseaseNameLabel := getItalicLabelCentered("Disease Name") emptyLabelA := widget.NewLabel("") personLabel := getItalicLabelCentered("Person") hasDiseaseLabel := getItalicLabelCentered("Has Disease") probabilityOfLabel := getItalicLabelCentered("Probability of") passingVariantLabel := getItalicLabelCentered("Passing Variant") emptyLabelB := widget.NewLabel("") conflictExistsLabel := getItalicLabelCentered("Conflict Exists?") emptyLabelC := widget.NewLabel("") emptyLabelD := widget.NewLabel("") diseaseNameColumn := container.NewVBox(emptyLabelA, diseaseNameLabel, widget.NewSeparator()) personHasDiseaseColumn := container.NewVBox(personLabel, hasDiseaseLabel, widget.NewSeparator()) probabilityOfPassingVariantColumn := container.NewVBox(probabilityOfLabel, passingVariantLabel, 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{ diseaseInfoIsKnown, personHasDisease, _, probabilityOfPassingAVariantFormatted, _, _, _, conflictExistsBool, err := readGeneticAnalysis.GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, mainGenomeIdentifier) if (err != nil) { return nil, err } getPersonHasDiseaseText := func()string{ if (diseaseInfoIsKnown == false){ result := translate("Unknown") return result } personHasDiseaseString := helpers.ConvertBoolToYesOrNoString(personHasDisease) return personHasDiseaseString } personHasDiseaseText := getPersonHasDiseaseText() getProbabilityOfPassingAVariantText := func()string{ if (diseaseInfoIsKnown == false){ result := translate("Unknown") return result } return probabilityOfPassingAVariantFormatted } probabilityOfPassingAVariantText := getProbabilityOfPassingAVariantText() diseaseNameText := getBoldLabelCentered(diseaseName) diseaseNameColumn.Add(diseaseNameText) personHasDiseaseLabel := getBoldLabelCentered(personHasDiseaseText) personHasDiseaseColumn.Add(personHasDiseaseLabel) probabilityOfPassingVariantLabel := getBoldLabelCentered(probabilityOfPassingAVariantText) probabilityOfPassingVariantColumn.Add(probabilityOfPassingVariantLabel) conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExistsBool) conflictExistsLabel := getBoldLabelCentered(conflictExistsString) conflictExistsColumn.Add(conflictExistsLabel) viewDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ setViewPersonGeneticAnalysisMonogenicDiseaseDetailsPage(window, analysisObject, diseaseName, currentPage) })) viewButtonsColumn.Add(viewDetailsButton) diseaseNameColumn.Add(widget.NewSeparator()) personHasDiseaseColumn.Add(widget.NewSeparator()) probabilityOfPassingVariantColumn.Add(widget.NewSeparator()) conflictExistsColumn.Add(widget.NewSeparator()) viewButtonsColumn.Add(widget.NewSeparator()) } personHasDiseaseHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPersonHasMonogenicDiseaseExplainerPage(window, currentPage) }) personHasDiseaseColumn.Add(personHasDiseaseHelpButton) probabilityOfPassingVariantHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPersonProbabilityOfPassingVariantExplainerPage(window, currentPage) }) probabilityOfPassingVariantColumn.Add(probabilityOfPassingVariantHelpButton) diseasesContainer := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, personHasDiseaseColumn, probabilityOfPassingVariantColumn) if (multipleGenomesExist == true){ conflictExistsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPersonGeneticAnalysisConflictExistsExplainerPage(window, currentPage) }) conflictExistsColumn.Add(conflictExistsHelpButton) diseasesContainer.Add(conflictExistsColumn) } diseasesContainer.Add(viewButtonsColumn) diseasesContainer.Add(layout.NewSpacer()) return diseasesContainer, nil } monogenicDiseasesContainer, err := getMonogenicDiseasesContainer() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), monogenicDiseasesContainer) setPageContent(page, window) } func setViewPersonGeneticAnalysisMonogenicDiseaseDetailsPage(window fyne.Window, analysisObject geneticAnalysis.PersonAnalysis, diseaseName string, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisMonogenicDiseaseDetailsPage(window, analysisObject, diseaseName, previousPage)} title := getPageTitleCentered("Viewing Genetic Analysis - " + diseaseName) backButton := getBackButtonCentered(previousPage) allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } getDescriptionSection := func()*fyne.Container{ if (multipleGenomesExist == false){ description := getLabelCentered("Below is the disease information for this person's genome.") return description } description1 := getLabelCentered("Below is the disease information for this person's genomes.") description2 := getLabelCentered("The first two genomes are created by combining multiple genomes.") 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()) getGenomesContainer := func()(*fyne.Container, error){ diseaseVariantsMap, err := monogenicDiseases.GetMonogenicDiseaseVariantsMap(diseaseName) if (err != nil){ return nil, err } totalNumberOfVariants := len(diseaseVariantsMap) totalNumberOfVariantsString := helpers.ConvertIntToString(totalNumberOfVariants) emptyLabelA := widget.NewLabel("") genomeNameLabel := getItalicLabelCentered("Genome Name") personLabel := getItalicLabelCentered("Person") hasDiseaseLabel := getItalicLabelCentered("Has Disease") probabilityOfLabel := getItalicLabelCentered("Probability of") passingVariantLabel := getItalicLabelCentered("Passing Variant") numberOfLabel1 := getItalicLabelCentered("Number of") variantsTestedLabel := getItalicLabelCentered("Variants Tested") numberOfLabel2 := getItalicLabelCentered("Number of") phasedLociLabel := getItalicLabelCentered("Phased Loci") emptyLabelB := widget.NewLabel("") emptyLabelC := widget.NewLabel("") genomeNameColumn := container.NewVBox(emptyLabelA, genomeNameLabel, widget.NewSeparator()) personHasDiseaseColumn := container.NewVBox(personLabel, hasDiseaseLabel, widget.NewSeparator()) probabilityOfPassingAVariantColumn := container.NewVBox(probabilityOfLabel, passingVariantLabel, widget.NewSeparator()) numberOfVariantsTestedColumn := container.NewVBox(numberOfLabel1, variantsTestedLabel, widget.NewSeparator()) numberOfPhasedLociColumn := container.NewVBox(numberOfLabel2, phasedLociLabel, widget.NewSeparator()) viewButtonsColumn := container.NewVBox(emptyLabelB, emptyLabelC, widget.NewSeparator()) addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{ diseaseInfoIsKnown, personHasDisease, _, probabilityOfPassingAVariantFormatted, numberOfVariantsTested, numberOfLociTested, numberOfPhasedLoci, _, err := readGeneticAnalysis.GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, genomeIdentifier) if (err != nil) { return err } getPersonHasDiseaseText := func()string{ if (diseaseInfoIsKnown == false){ result := translate("Unknown") return result } personHasDiseaseString := helpers.ConvertBoolToYesOrNoString(personHasDisease) return personHasDiseaseString } personHasDiseaseText := getPersonHasDiseaseText() getProbabilityOfPassingAVariantText := func()string{ if (diseaseInfoIsKnown == false){ result := translate("Unknown") return result } return probabilityOfPassingAVariantFormatted } probabilityOfPassingAVariantText := getProbabilityOfPassingAVariantText() getGenomeNameCell := func()*fyne.Container{ if (isACombinedGenome == false){ genomeNameLabel := getBoldLabelCentered(genomeName) return genomeNameLabel } viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setCombinedGenomesExplainerPage(window, currentPage) }) genomeNameLabel := getBoldLabel(genomeName) genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer()) return genomeNameCell } genomeNameCell := getGenomeNameCell() genomeNameColumn.Add(genomeNameCell) personHasDiseaseLabel := getBoldLabelCentered(personHasDiseaseText) personHasDiseaseColumn.Add(personHasDiseaseLabel) probabilityOfPassingAVariantLabel := getBoldLabelCentered(probabilityOfPassingAVariantText) probabilityOfPassingAVariantColumn.Add(probabilityOfPassingAVariantLabel) numberOfVariantsTestedString := helpers.ConvertIntToString(numberOfVariantsTested) numberOfVariantsTestedFormatted := numberOfVariantsTestedString + "/" + totalNumberOfVariantsString numberOfVariantsTestedLabel := getBoldLabelCentered(numberOfVariantsTestedFormatted) numberOfVariantsTestedColumn.Add(numberOfVariantsTestedLabel) numberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested) numberOfPhasedLociString := helpers.ConvertIntToString(numberOfPhasedLoci) numberOfPhasedLociFormatted := numberOfPhasedLociString + "/" + numberOfLociTestedString numberOfPhasedLociLabel := getBoldLabelCentered(numberOfPhasedLociFormatted) numberOfPhasedLociColumn.Add(numberOfPhasedLociLabel) viewButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ setViewPersonGenomeMonogenicDiseaseVariantsPage(window, analysisObject, genomeIdentifier, genomeName, diseaseName, currentPage) }) viewButtonsColumn.Add(viewButton) genomeNameColumn.Add(widget.NewSeparator()) personHasDiseaseColumn.Add(widget.NewSeparator()) probabilityOfPassingAVariantColumn.Add(widget.NewSeparator()) numberOfVariantsTestedColumn.Add(widget.NewSeparator()) numberOfPhasedLociColumn.Add(widget.NewSeparator()) viewButtonsColumn.Add(widget.NewSeparator()) return nil } if (multipleGenomesExist == true){ err := addGenomeRow("Only Exclude Conflicts", onlyExcludeConflictsGenomeIdentifier, true) if (err != nil){ return nil, err } err = addGenomeRow("Only Include Shared", onlyIncludeSharedGenomeIdentifier, true) if (err != nil){ return nil, err } } for _, genomeIdentifier := range allRawGenomeIdentifiersList{ getGenomeName := func()(string, error){ genomeFound, _, timeGenomeWasExported, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(genomeIdentifier) if (err != nil) { return "", err } if (genomeFound == false){ return "", errors.New("MyGenomeInfo for genome from analysisObject not found.") } if (multipleGenomesExist == false){ return companyName, nil } // We show the date that the genome was exported exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasExported, false) if (err != nil){ return "", err } genomeName := companyName + " (Exported " + exportTimeAgo + ")" return genomeName, nil } genomeName, err := getGenomeName() if (err != nil) { return nil, err } err = addGenomeRow(genomeName, genomeIdentifier, false) if (err != nil){ return nil, err } } personHasDiseaseHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPersonHasMonogenicDiseaseExplainerPage(window, currentPage) }) personHasDiseaseColumn.Add(personHasDiseaseHelpButton) probabilityOfPassingAVariantHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPersonProbabilityOfPassingVariantExplainerPage(window, currentPage) }) probabilityOfPassingAVariantColumn.Add(probabilityOfPassingAVariantHelpButton) numberOfVariantsTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setNumberOfTestedVariantsExplainerPage(window, currentPage) }) numberOfVariantsTestedColumn.Add(numberOfVariantsTestedHelpButton) numberOfPhasedLociHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setNumberOfPhasedLociExplainerPage(window, currentPage) }) numberOfPhasedLociColumn.Add(numberOfPhasedLociHelpButton) genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, personHasDiseaseColumn, probabilityOfPassingAVariantColumn, numberOfVariantsTestedColumn, numberOfPhasedLociColumn, viewButtonsColumn, layout.NewSpacer()) return genomesContainer, nil } genomesContainer, err := getGenomesContainer() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), genomesContainer) setPageContent(page, window) } // This page is used to view the person's variants for a particular genome func setViewPersonGenomeMonogenicDiseaseVariantsPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, genomeIdentifier [16]byte, genomeName string, diseaseName string, previousPage func()){ setLoadingScreen(window, "Loading Disease Variants", "Loading disease variants...") currentPage := func(){setViewPersonGenomeMonogenicDiseaseVariantsPage(window, geneticAnalysisObject, genomeIdentifier, genomeName, diseaseName, previousPage)} title := getPageTitleCentered("View Monogenic Disease Variants - " + diseaseName) backButton := getBackButtonCentered(previousPage) description1 := widget.NewLabel("Below are the monogenic disease variant results for this genome.") variantsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setMonogenicDiseaseVariantsExplainerPage(window, currentPage) }) description1Row := container.NewHBox(layout.NewSpacer(), description1, variantsHelpButton, layout.NewSpacer()) getGenomeNameRow := func()*fyne.Container{ genomeLabel := widget.NewLabel("Genome:") genomeNameLabel := getBoldLabel(genomeName) if (genomeName == "Only Exclude Conflicts" || genomeName == "Only Include Shared"){ genomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setCombinedGenomesExplainerPage(window, currentPage) }) genomeNameRow := container.NewHBox(layout.NewSpacer(), genomeLabel, genomeNameLabel, genomeHelpButton, layout.NewSpacer()) return genomeNameRow } genomeNameRow := container.NewHBox(layout.NewSpacer(), genomeLabel, genomeNameLabel, layout.NewSpacer()) return genomeNameRow } genomeNameRow := getGenomeNameRow() _, _, _, _, numberOfVariantsTested, numberOfLociTested, numberOfPhasedLoci, _, err := readGeneticAnalysis.GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, genomeIdentifier) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } diseaseVariantsMap, err := monogenicDiseases.GetMonogenicDiseaseVariantsMap(diseaseName) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } totalNumberOfVariants := len(diseaseVariantsMap) 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 buttons and pages getVariantsGrid := func()(*fyne.Container, error){ variantNameLabel := getItalicLabelCentered("Variant Name") genomeHasMutationLabel := getItalicLabelCentered("Genome Has Mutation") numberOfMutationsLabel := getItalicLabelCentered("Number of Mutations") emptyLabel := widget.NewLabel("") variantNameColumn := container.NewVBox(variantNameLabel, widget.NewSeparator()) genomeHasMutationColumn := container.NewVBox(genomeHasMutationLabel, widget.NewSeparator()) numberOfMutationsColumn := container.NewVBox(numberOfMutationsLabel, widget.NewSeparator()) viewButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator()) addVariantRow := func(variantIdentifierHex string)error{ variantObject, exists := diseaseVariantsMap[variantIdentifierHex] if (exists == false) { return errors.New("Cannot add variantRow: diseaseVariantsMap missing variant.") } variantName := variantObject.VariantNames[0] variantIdentifier, err := encoding.DecodeHexStringTo3ByteArray(variantIdentifierHex) if (err != nil) { return err } numberOfMutationsIsKnown, genomeNumberOfMutations, err := readGeneticAnalysis.GetPersonMonogenicDiseaseVariantInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, variantIdentifier, genomeIdentifier) if (err != nil) { return err } variantNameLabel := getBoldLabelCentered(variantName) variantNameColumn.Add(variantNameLabel) getGenomeHasMutationString := func()string{ if (numberOfMutationsIsKnown == false){ result := translate("Unknown") return result } if (genomeNumberOfMutations == 0){ result := translate("No") return result } result := translate("Yes") return result } genomeHasMutationString := getGenomeHasMutationString() genomeHasMutationLabel := getBoldLabelCentered(genomeHasMutationString) genomeHasMutationColumn.Add(genomeHasMutationLabel) getNumberOfVariantMutationsString := func()string{ if (numberOfMutationsIsKnown == false){ result := translate("Unknown") return result } variantNumberOfMutationsString := helpers.ConvertIntToString(genomeNumberOfMutations) return variantNumberOfMutationsString } numberOfVariantMutationsString := getNumberOfVariantMutationsString() genomeNumberOfMutationsLabel := getBoldLabelCentered(numberOfVariantMutationsString) numberOfMutationsColumn.Add(genomeNumberOfMutationsLabel) viewMutationButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ setViewPersonGeneticAnalysisMonogenicDiseaseVariantDetailsPage(window, geneticAnalysisObject, diseaseName, variantIdentifier, currentPage) }) viewButtonsColumn.Add(viewMutationButton) variantNameColumn.Add(widget.NewSeparator()) genomeHasMutationColumn.Add(widget.NewSeparator()) numberOfMutationsColumn.Add(widget.NewSeparator()) viewButtonsColumn.Add(widget.NewSeparator()) return nil } variantsList_2Mutations := make([]string, 0) variantsList_1Mutation := make([]string, 0) variantsList_0Mutations := make([]string, 0) variantsList_Unknown := make([]string, 0) for variantIdentifierHex, _ := range diseaseVariantsMap{ variantIdentifier, err := encoding.DecodeHexStringTo3ByteArray(variantIdentifierHex) if (err != nil) { return nil, err } numberOfMutationsIsKnown, genomeNumberOfMutations, err := readGeneticAnalysis.GetPersonMonogenicDiseaseVariantInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, variantIdentifier, genomeIdentifier) if (err != nil) { return nil, err } if (numberOfMutationsIsKnown == false){ variantsList_Unknown = append(variantsList_Unknown, variantIdentifierHex) continue } if (genomeNumberOfMutations == 0){ variantsList_0Mutations = append(variantsList_0Mutations, variantIdentifierHex) } else if (genomeNumberOfMutations == 1) { variantsList_1Mutation = append(variantsList_1Mutation, variantIdentifierHex) } else if (genomeNumberOfMutations == 2){ variantsList_2Mutations = append(variantsList_2Mutations, variantIdentifierHex) } else { return nil, errors.New("GetPersonMonogenicDiseaseVariantInfoFromGeneticAnalysis returning invalid genome number of mutations") } } // Items within each group are sorted so they will display the same way whenever user refreshes page helpers.SortStringListToUnicodeOrder(variantsList_2Mutations) helpers.SortStringListToUnicodeOrder(variantsList_1Mutation) helpers.SortStringListToUnicodeOrder(variantsList_0Mutations) helpers.SortStringListToUnicodeOrder(variantsList_Unknown) for _, variantIdentifier := range variantsList_2Mutations{ err = addVariantRow(variantIdentifier) if (err != nil) { return nil, err } } for _, variantIdentifier := range variantsList_1Mutation{ err = addVariantRow(variantIdentifier) if (err != nil) { return nil, err } } for _, variantIdentifier := range variantsList_0Mutations{ err = addVariantRow(variantIdentifier) if (err != nil) { return nil, err } } for _, variantIdentifier := range variantsList_Unknown{ err = addVariantRow(variantIdentifier) if (err != nil) { return nil, err } } genomeHasMutationHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setGenomeHasMonogenicDiseaseVariantMutationExplainerPage(window, currentPage) }) genomeHasMutationColumn.Add(genomeHasMutationHelpButton) genomeNumberOfMutationsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setMonogenicDiseaseVariantsExplainerPage(window, currentPage) }) numberOfMutationsColumn.Add(genomeNumberOfMutationsHelpButton) variantsGrid := container.NewHBox(layout.NewSpacer(), variantNameColumn, genomeHasMutationColumn, numberOfMutationsColumn, viewButtonsColumn, 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(), genomeNameRow, widget.NewSeparator(), variantsTestedRow, widget.NewSeparator(), phasedLociRow, widget.NewSeparator(), variantsGrid) setPageContent(page, window) } // This page will show the details of a specific variant from a person's genetic analysis // It will show the variant details for all of the person's genomes func setViewPersonGeneticAnalysisMonogenicDiseaseVariantDetailsPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, variantIdentifier [3]byte, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisMonogenicDiseaseVariantDetailsPage(window, geneticAnalysisObject, diseaseName, variantIdentifier, previousPage)} title := getPageTitleCentered("Monogenic 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 variant status for the person's genomes.") variantNameLabel := widget.NewLabel("Variant Name:") variantNameText := getBoldLabel(variantName) variantNameHelpButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ setViewMonogenicDiseaseVariantDetailsPage(window, diseaseName, variantIdentifierHex, currentPage) }) variantNameRow := container.NewHBox(layout.NewSpacer(), variantNameLabel, variantNameText, variantNameHelpButton, layout.NewSpacer()) getGenomesHaveVariantGrid := func()(*fyne.Container, error){ allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(geneticAnalysisObject) if (err != nil) { return nil, err } genomeNameLabel := getItalicLabelCentered("Genome Name") genomeHasMutationLabel := getItalicLabelCentered("Genome Has Mutation") numberOfMutationsLabel := getItalicLabelCentered("Number of Mutations") genomeNameColumn := container.NewVBox(genomeNameLabel, widget.NewSeparator()) genomeHasMutationColumn := container.NewVBox(genomeHasMutationLabel, widget.NewSeparator()) numberOfMutationsColumn := container.NewVBox(numberOfMutationsLabel, widget.NewSeparator()) addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{ genomeMutationsKnown, genomeNumberOfMutations, err := readGeneticAnalysis.GetPersonMonogenicDiseaseVariantInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, variantIdentifier, genomeIdentifier) if (err != nil) { return err } getGenomeNameCell := func()*fyne.Container{ if (isACombinedGenome == false){ genomeNameLabel := getBoldLabelCentered(genomeName) return genomeNameLabel } viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setCombinedGenomesExplainerPage(window, currentPage) }) genomeNameLabel := getBoldLabel(genomeName) genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer()) return genomeNameCell } genomeNameCell := getGenomeNameCell() genomeNameColumn.Add(genomeNameCell) getGenomeHasMutationText := func()string{ if (genomeMutationsKnown == false){ result := translate("Unknown") return result } if (genomeNumberOfMutations == 0){ result := translate("No") return result } result := translate("Yes") return result } genomeHasMutationText := getGenomeHasMutationText() getGenomeNumberOfMutationsText := func()string{ if (genomeMutationsKnown == false){ result := translate("Unknown") return result } genomeNumberOfMutationsString := helpers.ConvertIntToString(genomeNumberOfMutations) return genomeNumberOfMutationsString } genomeNumberOfMutationsText := getGenomeNumberOfMutationsText() genomeHasMutationLabel := getBoldLabelCentered(genomeHasMutationText) genomeHasMutationColumn.Add(genomeHasMutationLabel) genomeNumberOfMutationsLabel := getBoldLabelCentered(genomeNumberOfMutationsText) numberOfMutationsColumn.Add(genomeNumberOfMutationsLabel) genomeNameColumn.Add(widget.NewSeparator()) genomeHasMutationColumn.Add(widget.NewSeparator()) numberOfMutationsColumn.Add(widget.NewSeparator()) return nil } if (multipleGenomesExist == true){ err := addGenomeRow("Only Exclude Conflicts", onlyExcludeConflictsGenomeIdentifier, true) if (err != nil){ return nil, err } err = addGenomeRow("Only Include Shared", onlyIncludeSharedGenomeIdentifier, true) if (err != nil){ return nil, err } } for _, genomeIdentifier := range allRawGenomeIdentifiersList{ getGenomeName := func()(string, error){ genomeFound, _, timeGenomeWasExported, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(genomeIdentifier) if (err != nil) { return "", err } if (genomeFound == false){ return "", errors.New("MyGenomeInfo for genome from analysisObject not found.") } if (multipleGenomesExist == false){ return companyName, nil } // We show the date that the genome was exported exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasExported, false) if (err != nil){ return "", err } genomeName := companyName + " (Exported " + exportTimeAgo + ")" return genomeName, nil } genomeName, err := getGenomeName() if (err != nil) { return nil, err } err = addGenomeRow(genomeName, genomeIdentifier, false) if (err != nil){ return nil, err } } genomeHasMutationHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setGenomeHasMonogenicDiseaseVariantMutationExplainerPage(window, currentPage) }) genomeHasMutationColumn.Add(genomeHasMutationHelpButton) genomeNumberOfMutationsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setMonogenicDiseaseVariantsExplainerPage(window, currentPage) }) numberOfMutationsColumn.Add(genomeNumberOfMutationsHelpButton) genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, genomeHasMutationColumn, numberOfMutationsColumn, layout.NewSpacer()) return genomesContainer, nil } genomesHaveVariantGrid, err := getGenomesHaveVariantGrid() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), variantNameRow, widget.NewSeparator(), genomesHaveVariantGrid) setPageContent(page, window) } func setViewPersonGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisPolygenicDiseasesPage(window, personIdentifier, analysisObject, previousPage)} title := getPageTitleCentered("Viewing Genetic Analysis - Polygenic Diseases") backButton := getBackButtonCentered(previousPage) description := getLabelCentered("Below is an analysis of the polygenic disease risks for this person's genome.") getPolygenicDiseasesContainer := func()(*fyne.Container, error){ allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) if (err != nil){ return nil, err } // Outputs: // -[16]byte: Main genome identifier (Is either the combined Only exclude conflicts genome or the only genome) // -error getMainGenomeIdentifier := func()([16]byte, error){ if (multipleGenomesExist == true){ return onlyExcludeConflictsGenomeIdentifier, nil } // Only 1 genome exists genomeIdentifier := allRawGenomeIdentifiersList[0] return genomeIdentifier, nil } mainGenomeIdentifier, err := getMainGenomeIdentifier() if (err != nil){ return nil, err } diseaseNameLabel := getItalicLabelCentered("Disease Name") riskScoreLabel := getItalicLabelCentered("Risk Score") confidenceRangeLabel := getItalicLabelCentered("Confidence Range") conflictExistsLabel := getItalicLabelCentered("Conflict Exists?") emptyLabel5 := widget.NewLabel("") diseaseNameColumn := container.NewVBox(diseaseNameLabel, widget.NewSeparator()) riskScoreColumn := container.NewVBox(riskScoreLabel, widget.NewSeparator()) confidenceRangeColumn := container.NewVBox(confidenceRangeLabel, widget.NewSeparator()) conflictExistsColumn := container.NewVBox(conflictExistsLabel, widget.NewSeparator()) viewButtonsColumn := container.NewVBox(emptyLabel5, widget.NewSeparator()) polygenicDiseasesList, err := polygenicDiseases.GetPolygenicDiseaseObjectsList() if (err != nil) { return nil, err } for _, diseaseObject := range polygenicDiseasesList{ diseaseName := diseaseObject.DiseaseName neuralNetworkExists := trainedPredictionModels.CheckIfAttributeNeuralNetworkExists(diseaseName) if (neuralNetworkExists == false){ // We can't analyze this trait continue } diseaseNameLabel := getBoldLabelCentered(diseaseName) analysisExists, personRiskScore, predictionConfidenceRangesMap, _, _, conflictExists, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, mainGenomeIdentifier) if (err != nil) { return nil, err } getPersonRiskScoreLabel := func()fyne.Widget{ if (analysisExists == false){ result := widget.NewLabel(translate("Unknown")) return result } riskScoreString := helpers.ConvertIntToString(personRiskScore) riskScoreFormatted := riskScoreString + "/10" riskScoreLabel := getBoldLabel(riskScoreFormatted) return riskScoreLabel } personRiskScoreLabel := getPersonRiskScoreLabel() personRiskScoreLabelCentered := getWidgetCentered(personRiskScoreLabel) 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(){ setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window, personIdentifier, analysisObject, diseaseName, currentPage) })) diseaseNameColumn.Add(diseaseNameLabel) riskScoreColumn.Add(personRiskScoreLabelCentered) confidenceRangeColumn.Add(confidenceRangeLabel) conflictExistsColumn.Add(conflictExistsLabel) viewButtonsColumn.Add(viewDetailsButton) diseaseNameColumn.Add(widget.NewSeparator()) riskScoreColumn.Add(widget.NewSeparator()) confidenceRangeColumn.Add(widget.NewSeparator()) conflictExistsColumn.Add(widget.NewSeparator()) viewButtonsColumn.Add(widget.NewSeparator()) } riskScoreHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPolygenicDiseaseRiskScoreExplainerPage(window, currentPage) }) riskScoreColumn.Add(riskScoreHelpButton) confidenceRangeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ //TODO showUnderConstructionDialog(window) }) confidenceRangeColumn.Add(confidenceRangeHelpButton) diseasesContainer := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, riskScoreColumn, confidenceRangeColumn) if (multipleGenomesExist == true){ conflictExistsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPersonGeneticAnalysisConflictExistsExplainerPage(window, currentPage) }) conflictExistsColumn.Add(conflictExistsHelpButton) diseasesContainer.Add(conflictExistsColumn) } diseasesContainer.Add(viewButtonsColumn) diseasesContainer.Add(layout.NewSpacer()) return diseasesContainer, nil } diseasesContainer, err := getPolygenicDiseasesContainer() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), diseasesContainer) setPageContent(page, window) } func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, diseaseName string, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window, personIdentifier, analysisObject, diseaseName, previousPage)} title := getPageTitleCentered("Viewing Genetic Analysis - " + diseaseName) backButton := getBackButtonCentered(previousPage) allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } getDescriptionSection := func()*fyne.Container{ if (multipleGenomesExist == false){ description := getLabelCentered("Below is the disease information for this person's genome.") return description } description1 := getLabelCentered("Below is the disease information for this person's genomes.") description2 := getLabelCentered("The first two genomes are created by combining multiple genomes.") descriptionsSection := container.NewVBox(description1, description2) return descriptionsSection } descriptionSection := getDescriptionSection() diseaseNameLabel := widget.NewLabel("Disease:") diseaseNameText := getBoldLabel(diseaseName) diseaseInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ setViewPolygenicDiseaseDetailsPage(window, diseaseName, currentPage) }) diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, diseaseInfoButton, layout.NewSpacer()) getGenomesContainer := func()(*fyne.Container, error){ diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName) if (err != nil){ return nil, err } diseaseLociList := diseaseObject.LociList totalQuantityOfLoci := len(diseaseLociList) totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci) emptyLabel1 := widget.NewLabel("") genomeNameLabel := getItalicLabelCentered("Genome Name") emptyLabel2 := widget.NewLabel("") riskScoreLabel := getItalicLabelCentered("Risk Score") emptyLabel3 := widget.NewLabel("") predictionConfidenceLabel := getItalicLabelCentered("Confidence Range") quantityOfLabel := getItalicLabelCentered("Quantity of") lociKnownLabel := getItalicLabelCentered("Loci Known") emptyLabel4 := widget.NewLabel("") emptyLabel5 := widget.NewLabel("") emptyLabel6 := widget.NewLabel("") emptyLabel7 := widget.NewLabel("") genomeNameColumn := container.NewVBox(emptyLabel1, genomeNameLabel, widget.NewSeparator()) riskScoreColumn := container.NewVBox(emptyLabel2, riskScoreLabel, widget.NewSeparator()) predictionConfidenceColumn := container.NewVBox(emptyLabel3, predictionConfidenceLabel, widget.NewSeparator()) quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator()) viewLifetimeRiskButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator()) viewDetailsButtonsColumn := container.NewVBox(emptyLabel6, emptyLabel7, widget.NewSeparator()) addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{ getGenomeNameCell := func()*fyne.Container{ if (isACombinedGenome == false){ genomeNameLabel := getBoldLabelCentered(genomeName) return genomeNameLabel } viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setCombinedGenomesExplainerPage(window, currentPage) }) genomeNameLabel := getBoldLabel(genomeName) genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer()) return genomeNameCell } genomeNameCell := getGenomeNameCell() analysisExists, predictedRiskScore, predictionConfidenceRangesMap, quantityOfLociKnown, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, genomeIdentifier) if (err != nil) { return err } getRiskScoreLabel := func()fyne.Widget{ if (analysisExists == false){ result := widget.NewLabel(translate("Unknown")) return result } riskScoreString := helpers.ConvertIntToString(predictedRiskScore) riskScoreFormatted := riskScoreString + "/10" riskScoreLabel := getBoldLabel(riskScoreFormatted) return riskScoreLabel } genomeRiskScoreLabel := getRiskScoreLabel() genomeRiskScoreLabelCentered := getWidgetCentered(genomeRiskScoreLabel) 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 } confidenceRangeLabelCentered := getWidgetCentered(confidenceRangeLabel) genomeQuantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown) quantityOfLociKnownLabel := getBoldLabelCentered(genomeQuantityOfLociKnownString + "/" + totalQuantityOfLociString) viewLifetimeRiskButton := widget.NewButtonWithIcon("", theme.HistoryIcon(), func(){ personFound, _, _, personSex, err := myPeople.GetPersonInfo(personIdentifier) if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } if (personFound == false){ setErrorEncounteredPage(window, errors.New("setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage called with unknown personIdentifier"), currentPage) return } getSexToDisplay := func()string{ if (personSex == "Male" || personSex == "Female"){ return personSex } return "Male" } sexToDisplay := getSexToDisplay() setViewPersonPolygenicDiseaseLifetimeProbabilitiesPage(window, diseaseName, genomeName, sexToDisplay, currentPage) }) viewDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ //TODO showUnderConstructionDialog(window) }) genomeNameColumn.Add(genomeNameCell) riskScoreColumn.Add(genomeRiskScoreLabelCentered) predictionConfidenceColumn.Add(confidenceRangeLabelCentered) quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) viewLifetimeRiskButtonsColumn.Add(viewLifetimeRiskButton) viewDetailsButtonsColumn.Add(viewDetailsButton) genomeNameColumn.Add(widget.NewSeparator()) riskScoreColumn.Add(widget.NewSeparator()) predictionConfidenceColumn.Add(widget.NewSeparator()) quantityOfLociKnownColumn.Add(widget.NewSeparator()) viewLifetimeRiskButtonsColumn.Add(widget.NewSeparator()) viewDetailsButtonsColumn.Add(widget.NewSeparator()) return nil } if (multipleGenomesExist == true){ err := addGenomeRow("Only Exclude Conflicts", onlyExcludeConflictsGenomeIdentifier, true) if (err != nil){ return nil, err } err = addGenomeRow("Only Include Shared", onlyIncludeSharedGenomeIdentifier, true) if (err != nil){ return nil, err } } for _, genomeIdentifier := range allRawGenomeIdentifiersList{ getGenomeName := func()(string, error){ genomeFound, _, timeGenomeWasExported, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(genomeIdentifier) if (err != nil) { return "", err } if (genomeFound == false){ return "", errors.New("MyGenomeInfo for genome from analysisObject not found.") } if (multipleGenomesExist == false){ return companyName, nil } // We show the date the genome was exported exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasExported, false) if (err != nil){ return "", err } genomeName := companyName + " (Exported " + exportTimeAgo + ")" return genomeName, nil } genomeName, err := getGenomeName() if (err != nil) { return nil, err } err = addGenomeRow(genomeName, genomeIdentifier, false) if (err != nil){ return nil, err } } riskScoreHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPolygenicDiseaseRiskScoreExplainerPage(window, currentPage) }) riskScoreColumn.Add(riskScoreHelpButton) predictionConfidenceHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ showUnderConstructionDialog(window) }) predictionConfidenceColumn.Add(predictionConfidenceHelpButton) quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage) }) quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, riskScoreColumn, predictionConfidenceColumn, quantityOfLociKnownColumn, viewLifetimeRiskButtonsColumn, viewDetailsButtonsColumn, layout.NewSpacer()) return genomesContainer, nil } genomesContainer, err := getGenomesContainer() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), genomesContainer) setPageContent(page, window) } func setViewPersonPolygenicDiseaseLifetimeProbabilitiesPage(window fyne.Window, diseaseName string, genomeName string, maleOrFemale string, previousPage func()){ currentPage := func(){setViewPersonPolygenicDiseaseLifetimeProbabilitiesPage(window, diseaseName, genomeName, maleOrFemale, previousPage)} title := getPageTitleCentered("Viewing Disease Lifetime Probabilities") backButton := getBackButtonCentered(previousPage) description1 := getLabelCentered("Below are the lifetime probabilities for this disease.") description2 := getLabelCentered("The average risk column describes the probability for the average person.") //TODO: Once we understand how to calculate it, we will add adjusted risk column with estimated probability getGenomeNameRow := func()*fyne.Container{ genomeLabel := widget.NewLabel("Genome:") genomeNameLabel := getBoldLabel(genomeName) if (genomeName == "Only Exclude Conflicts" || genomeName == "Only Include Shared"){ genomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setCombinedGenomesExplainerPage(window, currentPage) }) genomeNameRow := container.NewHBox(layout.NewSpacer(), genomeLabel, genomeNameLabel, genomeHelpButton, layout.NewSpacer()) return genomeNameRow } genomeNameRow := container.NewHBox(layout.NewSpacer(), genomeLabel, genomeNameLabel, layout.NewSpacer()) return genomeNameRow } genomeNameRow := getGenomeNameRow() getTabContainer := func(tabMaleOrFemale string)(*container.TabItem, error){ ageLabel := getItalicLabelCentered("Age") averageRiskLabel := getItalicLabelCentered("Average Risk") ageColumn := container.NewVBox(ageLabel, widget.NewSeparator()) averageRiskColumn := container.NewVBox(averageRiskLabel, widget.NewSeparator()) diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName) if (err != nil) { return nil, err } getAverageRiskProbabilitiesFunction := diseaseObject.GetAverageRiskProbabilitiesFunction rowInitialValuesSet := false rowInitialAge := 0 rowInitialAgeRisk := float64(0) rowSummedRisks := float64(0) for age := 0; age <= 110; age++{ ageRisk, err := getAverageRiskProbabilitiesFunction(tabMaleOrFemale, age) if (err != nil) { return nil, err } if (rowInitialValuesSet == false){ rowInitialValuesSet = true rowInitialAge = age rowInitialAgeRisk = ageRisk rowSummedRisks = ageRisk continue } rowSummedRisks += ageRisk nextAge := age+1 if (nextAge % 10 != 0){ continue } if (age < 109 && rowInitialAgeRisk == ageRisk){ continue } // We make a new row averageRisk := rowSummedRisks / float64(age - rowInitialAge + 1) if (rowInitialAge >= age){ return nil, errors.New("rowInitialAge is >= age.") } startAgeString := helpers.ConvertIntToString(rowInitialAge) endAgeString := helpers.ConvertIntToString(age) averageRiskPercentage := averageRisk * 100 averageRiskString := helpers.ConvertFloat64ToStringRounded(averageRiskPercentage, 2) ageRangeLabel := getBoldLabel(startAgeString + " - " + endAgeString) averageRiskLabel := getBoldLabelCentered(averageRiskString + "%") ageColumn.Add(ageRangeLabel) averageRiskColumn.Add(averageRiskLabel) ageColumn.Add(widget.NewSeparator()) averageRiskColumn.Add(widget.NewSeparator()) rowInitialValuesSet = false } averageRiskHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPolygenicDiseaseAverageLifetimeRiskExplainerPage(window, currentPage) }) averageRiskColumn.Add(averageRiskHelpButton) ageProbabilitiesGrid := container.NewHBox(layout.NewSpacer(), ageColumn, averageRiskColumn, layout.NewSpacer()) ageProbabilitiesTabItem := container.NewTabItem(tabMaleOrFemale, ageProbabilitiesGrid) return ageProbabilitiesTabItem, nil } maleTab, err := getTabContainer("Male") if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } femaleTab, err := getTabContainer("Female") if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } ageProbabilityTabs := container.NewAppTabs(maleTab, femaleTab) if (maleOrFemale == "Male"){ ageProbabilityTabs.Select(maleTab) } else { ageProbabilityTabs.Select(femaleTab) } ageProbabilityTabsCentered := getContainerCentered(getAppTabsBoxed(ageProbabilityTabs)) page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), genomeNameRow, widget.NewSeparator(), ageProbabilityTabsCentered) setPageContent(page, window) } func setViewPersonGeneticAnalysisDiscreteTraitsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisDiscreteTraitsPage(window, personIdentifier, analysisObject, previousPage)} title := getPageTitleCentered("Viewing Genetic Analysis - Discrete Traits") backButton := getBackButtonCentered(previousPage) description := getLabelCentered("Below is an analysis of the discrete traits for this person's genome.") getTraitsContainer := func()(*fyne.Container, error){ allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) if (err != nil){ return nil, err } // Outputs: // -[16]byte: Main genome identifier (Is either the combined Only exclude conflicts genome or the only genome) // -error getMainGenomeIdentifier := func()([16]byte, error){ if (multipleGenomesExist == true){ return onlyExcludeConflictsGenomeIdentifier, nil } // Only 1 genome exists genomeIdentifier := allRawGenomeIdentifiersList[0] return genomeIdentifier, nil } mainGenomeIdentifier, err := getMainGenomeIdentifier() if (err != nil){ return nil, err } emptyLabel1 := widget.NewLabel("") traitNameLabel := getItalicLabelCentered("Trait Name") emptyLabel2 := widget.NewLabel("") predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome") 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()) predictedOutcomeColumn := container.NewVBox(emptyLabel2, predictedOutcomeLabel, widget.NewSeparator()) quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator()) conflictExistsColumn := container.NewVBox(emptyLabel3, conflictExistsLabel, widget.NewSeparator()) viewButtonsColumn := 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 } traitName := traitObject.TraitName traitLociList := traitObject.LociList traitRulesList := traitObject.RulesList if (len(traitLociList) == 0 && len(traitRulesList) == 0){ // This trait does not have any rules or loci to analyze // We cannot analyze it yet continue } traitNameText := getBoldLabelCentered(traitName) neuralNetworkExists, neuralNetworkAnalysisExists, neuralNetworkPredictedOutcome, _, quantityOfLociKnown_NeuralNetwork, _, anyRulesExist, rulesAnalysisExists, _, rulesPredictedOutcomeExists, rulesPredictedOutcome, _, quantityOfLociKnown_Rules, conflictExists, err := readGeneticAnalysis.GetPersonDiscreteTraitInfoFromGeneticAnalysis(analysisObject, traitName, mainGenomeIdentifier) if (err != nil) { return nil, err } if (neuralNetworkExists == false && anyRulesExist == false){ // We can't analyze this trait continue } getPredictionLabel := func()fyne.Widget{ if (neuralNetworkExists == true){ if (neuralNetworkAnalysisExists == false){ result := getItalicLabel("Unknown") return result } result := getBoldLabel(neuralNetworkPredictedOutcome) return result } // anyRulesExist must be true if (rulesAnalysisExists == false || rulesPredictedOutcomeExists == false){ result := getItalicLabel("Unknown") return result } result := getBoldLabel(rulesPredictedOutcome) return result } predictionLabel := getPredictionLabel() predictionLabelCentered := getWidgetCentered(predictionLabel) 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) conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists) conflictExistsLabel := getBoldLabelCentered(conflictExistsString) viewDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window, personIdentifier, analysisObject, traitName, currentPage) })) traitNameColumn.Add(traitNameText) predictedOutcomeColumn.Add(predictionLabelCentered) quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) conflictExistsColumn.Add(conflictExistsLabel) viewButtonsColumn.Add(viewDetailsButton) traitNameColumn.Add(widget.NewSeparator()) predictedOutcomeColumn.Add(widget.NewSeparator()) quantityOfLociKnownColumn.Add(widget.NewSeparator()) conflictExistsColumn.Add(widget.NewSeparator()) viewButtonsColumn.Add(widget.NewSeparator()) } predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ //TODO showUnderConstructionDialog(window) }) predictedOutcomeColumn.Add(predictedOutcomeHelpButton) quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ //TODO showUnderConstructionDialog(window) }) quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) traitsContainer := container.NewHBox(layout.NewSpacer(), traitNameColumn, predictedOutcomeColumn, quantityOfLociKnownColumn) if (multipleGenomesExist == true){ conflictExistsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPersonGeneticAnalysisConflictExistsExplainerPage(window, currentPage) }) conflictExistsColumn.Add(conflictExistsHelpButton) traitsContainer.Add(conflictExistsColumn) } traitsContainer.Add(viewButtonsColumn) traitsContainer.Add(layout.NewSpacer()) return traitsContainer, nil } traitsContainer, err := getTraitsContainer() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), traitsContainer) setPageContent(page, window) } func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, traitName string, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window, personIdentifier, analysisObject, traitName, previousPage)} title := getPageTitleCentered("Viewing Genetic Analysis - " + traitName) backButton := getBackButtonCentered(previousPage) allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } getDescriptionSection := func()*fyne.Container{ if (multipleGenomesExist == false){ description := getLabelCentered("Below is the trait information for this person's genome.") return description } description1 := getLabelCentered("Below is the trait information for this person's genomes.") description2 := getLabelCentered("The first two genomes are created by combining multiple genomes.") descriptionsSection := container.NewVBox(description1, description2) return descriptionsSection } descriptionSection := getDescriptionSection() traitNameLabel := widget.NewLabel("Trait:") traitNameText := getBoldLabel(traitName) traitInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ setViewTraitDetailsPage(window, traitName, currentPage) }) traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitInfoButton, layout.NewSpacer()) getGenomesContainer := func()(*fyne.Container, error){ traitObject, err := traits.GetTraitObject(traitName) if (err != nil) { return nil, err } emptyLabel1 := widget.NewLabel("") genomeNameLabel := getItalicLabelCentered("Genome Name") emptyLabel2 := widget.NewLabel("") predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome") emptyLabel3 := widget.NewLabel("") predictionConfidenceLabel := getItalicLabelCentered("Prediction Confidence") quantityOfLabel1 := getItalicLabelCentered("Quantity Of") lociKnownLabel := getItalicLabelCentered("Loci Known") quantityOfLabel2 := getItalicLabelCentered("Quantity Of") rulesTestedLabel := getItalicLabelCentered("Rules Tested") emptyLabel4 := widget.NewLabel("") emptyLabel5 := widget.NewLabel("") genomeNameColumn := container.NewVBox(emptyLabel1, genomeNameLabel, widget.NewSeparator()) predictedOutcomeColumn := container.NewVBox(emptyLabel2, predictedOutcomeLabel, widget.NewSeparator()) neuralNetworkPredictionConfidenceColumn := container.NewVBox(emptyLabel3, predictionConfidenceLabel, widget.NewSeparator()) quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel1, lociKnownLabel, widget.NewSeparator()) numberOfRulesTestedColumn := container.NewVBox(quantityOfLabel2, rulesTestedLabel, widget.NewSeparator()) viewDetailsButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator()) addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{ getGenomeNameCell := func()*fyne.Container{ if (isACombinedGenome == false){ genomeNameLabel := getBoldLabelCentered(genomeName) return genomeNameLabel } viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setCombinedGenomesExplainerPage(window, currentPage) }) genomeNameLabel := getBoldLabel(genomeName) genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer()) return genomeNameCell } genomeNameCell := getGenomeNameCell() neuralNetworkExists, neuralNetworkAnalysisExists, neuralNetworkPredictedOutcome, neuralNetworkPredictionConfidence, quantityOfLociKnown_NeuralNetwork, _, anyRulesExist, rulesAnalysisExists, _, rulesPredictedOutcomeExists, rulesPredictedOutcome, quantityOfRulesTested, _, _, err := readGeneticAnalysis.GetPersonDiscreteTraitInfoFromGeneticAnalysis(analysisObject, traitName, genomeIdentifier) if (err != nil) { return err } if (neuralNetworkExists == false && anyRulesExist == false){ // This trait is not analyzable return errors.New("setViewPersonGeneticAnalysisTraitDetailsPage called with trait which cannot be analyzed via neural networks and traits.") } getPredictedOutcomeLabel := func()fyne.Widget{ if (neuralNetworkExists == true){ if (neuralNetworkAnalysisExists == false){ predictedOutcomeLabel := getItalicLabel("Unknown") return predictedOutcomeLabel } predictedOutcomeLabel := getBoldLabel(neuralNetworkPredictedOutcome) return predictedOutcomeLabel } // anyRulesExist must be true if (rulesAnalysisExists == false || rulesPredictedOutcomeExists == false){ predictedOutcomeLabel := getItalicLabel("Unknown") return predictedOutcomeLabel } predictedOutcomeLabel := getBoldLabel(rulesPredictedOutcome) return predictedOutcomeLabel } predictedOutcomeLabel := getPredictedOutcomeLabel() predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel) if (neuralNetworkExists == true){ if (neuralNetworkAnalysisExists == false){ predictedOutcomeConfidenceLabel := getItalicLabelCentered("Unknown") neuralNetworkPredictionConfidenceColumn.Add(predictedOutcomeConfidenceLabel) } else { neuralNetworkPredictionConfidenceString := helpers.ConvertIntToString(neuralNetworkPredictionConfidence) predictedOutcomeConfidenceLabel := getBoldLabelCentered(neuralNetworkPredictionConfidenceString + "%") neuralNetworkPredictionConfidenceColumn.Add(predictedOutcomeConfidenceLabel) } 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 { traitRulesMap, err := traits.GetTraitRulesMap(traitName) if (err != nil){ return err } totalNumberOfRules := len(traitRulesMap) totalNumberOfRulesString := helpers.ConvertIntToString(totalNumberOfRules) quantityOfRulesTestedString := helpers.ConvertIntToString(quantityOfRulesTested) quantityOfRulesTestedLabel := getBoldLabelCentered(quantityOfRulesTestedString + "/" + totalNumberOfRulesString) numberOfRulesTestedColumn.Add(quantityOfRulesTestedLabel) } viewDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ if (neuralNetworkExists == true){ //TODO showUnderConstructionDialog(window) } else { setViewPersonGenomeDiscreteTraitRulesPage(window, analysisObject, traitName, genomeIdentifier, genomeName, currentPage) } }) genomeNameColumn.Add(genomeNameCell) predictedOutcomeColumn.Add(predictedOutcomeLabelCentered) viewDetailsButtonsColumn.Add(viewDetailsButton) genomeNameColumn.Add(widget.NewSeparator()) predictedOutcomeColumn.Add(widget.NewSeparator()) neuralNetworkPredictionConfidenceColumn.Add(widget.NewSeparator()) quantityOfLociKnownColumn.Add(widget.NewSeparator()) numberOfRulesTestedColumn.Add(widget.NewSeparator()) viewDetailsButtonsColumn.Add(widget.NewSeparator()) return nil } if (multipleGenomesExist == true){ err := addGenomeRow("Only Exclude Conflicts", onlyExcludeConflictsGenomeIdentifier, true) if (err != nil){ return nil, err } err = addGenomeRow("Only Include Shared", onlyIncludeSharedGenomeIdentifier, true) if (err != nil){ return nil, err } } for _, genomeIdentifier := range allRawGenomeIdentifiersList{ getGenomeName := func()(string, error){ genomeFound, _, timeGenomeWasExported, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(genomeIdentifier) if (err != nil) { return "", err } if (genomeFound == false){ return "", errors.New("MyGenomeInfo for genome from analysisObject not found.") } if (multipleGenomesExist == false){ return companyName, nil } // We show the date that the genome was exported exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasExported, false) if (err != nil){ return "", err } genomeName := companyName + " (Exported " + exportTimeAgo + ")" return genomeName, nil } genomeName, err := getGenomeName() if (err != nil) { return nil, err } err = addGenomeRow(genomeName, genomeIdentifier, false) if (err != nil){ return nil, err } } neuralNetworkExists := trainedPredictionModels.CheckIfAttributeNeuralNetworkExists(traitName) if (neuralNetworkExists == true){ neuralNetworksHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setDiscreteTraitNeuralNetworkPredictionExplainerPage(window, currentPage) }) predictedOutcomeColumn.Add(neuralNetworksHelpButton) } else { rulesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setDiscreteTraitRulesPredictionExplainerPage(window, currentPage) }) predictedOutcomeColumn.Add(rulesHelpButton) } neuralNetworkConfidenceHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ showUnderConstructionDialog(window) //TODO }) neuralNetworkPredictionConfidenceColumn.Add(neuralNetworkConfidenceHelpButton) numberOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage) }) numberOfRulesTestedColumn.Add(numberOfRulesTestedHelpButton) quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ //TODO showUnderConstructionDialog(window) }) quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, predictedOutcomeColumn) if (neuralNetworkExists == true){ genomesContainer.Add(neuralNetworkPredictionConfidenceColumn) genomesContainer.Add(quantityOfLociKnownColumn) } else { genomesContainer.Add(numberOfRulesTestedColumn) } genomesContainer.Add(viewDetailsButtonsColumn) genomesContainer.Add(layout.NewSpacer()) return genomesContainer, nil } genomesContainer, err := getGenomesContainer() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), genomesContainer) setPageContent(page, window) } // Ths function provides a page to view the discrete trait rules for a particular genome from a genetic analysis func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, genomeIdentifier [16]byte, genomeName string, previousPage func()){ setLoadingScreen(window, "Loading Trait Rules", "Loading trait rules...") currentPage := func(){setViewPersonGenomeDiscreteTraitRulesPage(window, geneticAnalysisObject, traitName, genomeIdentifier, genomeName, previousPage)} title := getPageTitleCentered("View Trait Rules - " + traitName) backButton := getBackButtonCentered(previousPage) description1 := widget.NewLabel("Below are the trait rule results for this genome.") rulesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setDiscreteTraitRulesExplainerPage(window, currentPage) }) description1Row := container.NewHBox(layout.NewSpacer(), description1, rulesHelpButton, layout.NewSpacer()) getGenomeNameRow := func()*fyne.Container{ genomeLabel := widget.NewLabel("Genome:") genomeNameLabel := getBoldLabel(genomeName) if (genomeName == "Only Exclude Conflicts" || genomeName == "Only Include Shared"){ genomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setCombinedGenomesExplainerPage(window, currentPage) }) genomeNameRow := container.NewHBox(layout.NewSpacer(), genomeLabel, genomeNameLabel, genomeHelpButton, layout.NewSpacer()) return genomeNameRow } genomeNameRow := container.NewHBox(layout.NewSpacer(), genomeLabel, genomeNameLabel, layout.NewSpacer()) return genomeNameRow } genomeNameRow := getGenomeNameRow() traitRulesMap, err := traits.GetTraitRulesMap(traitName) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } numberOfRulesTested := 0 rulesList_RulePassed := make([]string, 0) rulesList_RuleNotPassed := make([]string, 0) rulesList_Unknown := make([]string, 0) for ruleIdentifierHex, _ := range traitRulesMap{ ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } ruleStatusIsKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } if (ruleStatusIsKnown == false){ rulesList_Unknown = append(rulesList_Unknown, ruleIdentifierHex) continue } numberOfRulesTested += 1 if (genomePassesRule == true){ rulesList_RulePassed = append(rulesList_RulePassed, ruleIdentifierHex) } else { rulesList_RuleNotPassed = append(rulesList_RuleNotPassed, ruleIdentifierHex) } } numberOfRulesTestedString := helpers.ConvertIntToString(numberOfRulesTested) totalNumberOfRules := len(traitRulesMap) totalNumberOfRulesString := helpers.ConvertIntToString(totalNumberOfRules) rulesTestedLabel := widget.NewLabel("Rules Tested:") rulesTestedText := getBoldLabel(numberOfRulesTestedString + "/" + totalNumberOfRulesString) rulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage) }) rulesTestedRow := container.NewHBox(layout.NewSpacer(), rulesTestedLabel, rulesTestedText, rulesTestedHelpButton, layout.NewSpacer()) getTraitRulesGrid := func()(*fyne.Container, error){ ruleIdentifierLabel := getItalicLabelCentered("Rule Identifier") ruleEffectsLabel := getItalicLabelCentered("Rule Effects") genomePassesRuleLabel := getItalicLabelCentered("Genome Passes Rule") emptyLabel := widget.NewLabel("") ruleIdentifierColumn := container.NewVBox(ruleIdentifierLabel, widget.NewSeparator()) ruleEffectsColumn := container.NewVBox(ruleEffectsLabel, widget.NewSeparator()) genomePassesRuleColumn := container.NewVBox(genomePassesRuleLabel, widget.NewSeparator()) viewButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator()) addRuleRow := func(ruleIdentifierHex string)error{ ruleIdentifierLabel := getBoldLabelCentered(ruleIdentifierHex) ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex) if (err != nil){ return err } ruleStatusIsKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier) if (err != nil) { return err } getGenomePassesRuleText := func()string{ if (ruleStatusIsKnown == false){ result := translate("Unknown") return result } genomePassesRuleString := helpers.ConvertBoolToYesOrNoString(genomePassesRule) genomePassesRuleTranslated := translate(genomePassesRuleString) return genomePassesRuleTranslated } genomePassesRuleText := getGenomePassesRuleText() genomePassesRuleLabel := getBoldLabelCentered(genomePassesRuleText) // 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 viewRuleButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window, geneticAnalysisObject, traitName, ruleIdentifier, currentPage) }) ruleIdentifierColumn.Add(ruleIdentifierLabel) genomePassesRuleColumn.Add(genomePassesRuleLabel) viewButtonsColumn.Add(viewRuleButton) traitRuleObject, exists := traitRulesMap[ruleIdentifierHex] if (exists == false){ return errors.New("Trait rule not found after being found already.") } 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{ outcomeEffectInt, exists := ruleOutcomePointsMap[outcomeName] if (exists == false){ return errors.New("OutcomeName not found in ruleOutcomePointsMap after being found already: " + outcomeName) } getOutcomeEffectString := func()string{ outcomeEffectString := helpers.ConvertIntToString(outcomeEffectInt) if (outcomeEffectInt < 0){ return outcomeEffectString } outcomeEffect := "+" + outcomeEffectString 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) genomePassesRuleColumn.Add(emptyLabelB) viewButtonsColumn.Add(emptyLabelC) } } ruleIdentifierColumn.Add(widget.NewSeparator()) ruleEffectsColumn.Add(widget.NewSeparator()) genomePassesRuleColumn.Add(widget.NewSeparator()) viewButtonsColumn.Add(widget.NewSeparator()) return nil } // Items within each group are sorted so they will display the same way whenever user refreshes page helpers.SortStringListToUnicodeOrder(rulesList_RulePassed) helpers.SortStringListToUnicodeOrder(rulesList_RuleNotPassed) helpers.SortStringListToUnicodeOrder(rulesList_Unknown) for _, ruleIdentifier := range rulesList_RulePassed{ err = addRuleRow(ruleIdentifier) if (err != nil) { return nil, err } } for _, ruleIdentifier := range rulesList_RuleNotPassed{ err = addRuleRow(ruleIdentifier) if (err != nil) { return nil, err } } for _, ruleIdentifier := range rulesList_Unknown{ err = addRuleRow(ruleIdentifier) if (err != nil) { return nil, err } } ruleEffectsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setDiscreteTraitRuleOutcomeEffectsExplainerPage(window, currentPage) }) ruleEffectsColumn.Add(ruleEffectsHelpButton) genomePassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setGenomePassesDiscreteTraitRuleExplainerPage(window, currentPage) }) genomePassesRuleColumn.Add(genomePassesRuleHelpButton) traitRulesGrid := container.NewHBox(layout.NewSpacer(), ruleIdentifierColumn, ruleEffectsColumn, genomePassesRuleColumn, viewButtonsColumn, layout.NewSpacer()) return traitRulesGrid, nil } traitRulesGrid, err := getTraitRulesGrid() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), description1Row, widget.NewSeparator(), genomeNameRow, widget.NewSeparator(), rulesTestedRow, widget.NewSeparator(), traitRulesGrid) setPageContent(page, window) } // This function provides a page to view the details of a specific trait rule from a person genetic analysis // The page will show the rule details for all of the person's genomes func setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, ruleIdentifier [3]byte, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window, geneticAnalysisObject, traitName, ruleIdentifier, previousPage)} title := getPageTitleCentered("Trait Rule Details - " + traitName) backButton := getBackButtonCentered(previousPage) description := getLabelCentered("Below is the rule result for the person's genomes.") 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()) getGenomesRuleInfoGrid := func()(*fyne.Container, error){ allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(geneticAnalysisObject) if (err != nil) { return nil, err } genomeNameLabel := getItalicLabelCentered("Genome Name") genomePassesRuleLabel := getItalicLabelCentered("Genome Passes Rule") genomeNameColumn := container.NewVBox(genomeNameLabel, widget.NewSeparator()) genomePassesRuleColumn := container.NewVBox(genomePassesRuleLabel, widget.NewSeparator()) addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{ genomeRuleStatusKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier) if (err != nil) { return err } getGenomePassesRuleText := func()string{ if (genomeRuleStatusKnown == false){ result := translate("Unknown") return result } genomePassesRuleString := helpers.ConvertBoolToYesOrNoString(genomePassesRule) genomePassesRuleTranslated := translate(genomePassesRuleString) return genomePassesRuleTranslated } genomePassesRuleText := getGenomePassesRuleText() getGenomeNameCell := func()*fyne.Container{ if (isACombinedGenome == false){ genomeNameLabel := getBoldLabelCentered(genomeName) return genomeNameLabel } viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setCombinedGenomesExplainerPage(window, currentPage) }) genomeNameLabel := getBoldLabel(genomeName) genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer()) return genomeNameCell } genomeNameCell := getGenomeNameCell() genomeNameColumn.Add(genomeNameCell) genomePassesRuleLabel := getBoldLabelCentered(genomePassesRuleText) genomePassesRuleColumn.Add(genomePassesRuleLabel) genomeNameColumn.Add(widget.NewSeparator()) genomePassesRuleColumn.Add(widget.NewSeparator()) return nil } if (multipleGenomesExist == true){ err := addGenomeRow("Only Exclude Conflicts", onlyExcludeConflictsGenomeIdentifier, true) if (err != nil){ return nil, err } err = addGenomeRow("Only Include Shared", onlyIncludeSharedGenomeIdentifier, true) if (err != nil){ return nil, err } } for _, genomeIdentifier := range allRawGenomeIdentifiersList{ getGenomeName := func()(string, error){ genomeFound, _, timeGenomeWasExported, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(genomeIdentifier) if (err != nil) { return "", err } if (genomeFound == false){ return "", errors.New("MyGenomeInfo for genome from analysisObject not found.") } if (multipleGenomesExist == false){ return companyName, nil } // We show the date that the genome was exported exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasExported, false) if (err != nil){ return "", err } genomeName := companyName + " (Exported " + exportTimeAgo + ")" return genomeName, nil } genomeName, err := getGenomeName() if (err != nil) { return nil, err } err = addGenomeRow(genomeName, genomeIdentifier, false) if (err != nil){ return nil, err } } genomePassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setGenomePassesDiscreteTraitRuleExplainerPage(window, currentPage) }) genomePassesRuleColumn.Add(genomePassesRuleHelpButton) genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, genomePassesRuleColumn, layout.NewSpacer()) return genomesContainer, nil } genomesRuleInfoGrid, err := getGenomesRuleInfoGrid() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), ruleIdentifierRow, widget.NewSeparator(), genomesRuleInfoGrid) setPageContent(page, window) } func setViewPersonGeneticAnalysisNumericTraitsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisNumericTraitsPage(window, personIdentifier, analysisObject, previousPage)} title := getPageTitleCentered("Viewing Genetic Analysis - Numeric Traits") backButton := getBackButtonCentered(previousPage) description := getLabelCentered("Below is an analysis of the numeric traits for this person's genome.") getTraitsContainer := func()(*fyne.Container, error){ allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) if (err != nil){ return nil, err } // Outputs: // -[16]byte: Main genome identifier (Is either the combined Only exclude conflicts genome or the only genome) // -error getMainGenomeIdentifier := func()([16]byte, error){ if (multipleGenomesExist == true){ return onlyExcludeConflictsGenomeIdentifier, nil } // Only 1 genome exists genomeIdentifier := allRawGenomeIdentifiersList[0] return genomeIdentifier, nil } mainGenomeIdentifier, err := getMainGenomeIdentifier() if (err != nil){ return nil, err } 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()) viewButtonsColumn := 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 } traitName := traitObject.TraitName traitLociList := traitObject.LociList if (len(traitLociList) == 0){ // This trait does not have any loci to analyze // We cannot analyze it yet continue } traitNameText := getBoldLabelCentered(traitName) neuralNetworkExists := trainedPredictionModels.CheckIfAttributeNeuralNetworkExists(traitName) if (neuralNetworkExists == false){ // This trait has no neural network // We cannot analyze it continue } analysisExists, predictedOutcome, confidenceRangesMap, _, _, conflictExists, err := readGeneticAnalysis.GetPersonNumericTraitInfoFromGeneticAnalysis(analysisObject, traitName, mainGenomeIdentifier) if (err != nil) { return nil, err } outcomeFormatter := traitObject.NumericValueFormatter getPredictionLabel := func()(fyne.Widget, error){ if (analysisExists == false){ result := getItalicLabel("Unknown") return result, nil } predictedOutcomeString, err := outcomeFormatter(predictedOutcome, true) if (err != nil) { return nil, err } result := getBoldLabel(predictedOutcomeString) return result, nil } predictionLabel, err := getPredictionLabel() if (err != nil) { return nil, err } predictionLabelCentered := getWidgetCentered(predictionLabel) 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(confidenceRangesMap) // 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 := confidenceRangesMap[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(){ setViewPersonGeneticAnalysisNumericTraitDetailsPage(window, personIdentifier, analysisObject, traitName, currentPage) })) traitNameColumn.Add(traitNameText) predictedOutcomeColumn.Add(predictionLabelCentered) confidenceRangeColumn.Add(confidenceRangeLabelCentered) conflictExistsColumn.Add(conflictExistsLabel) viewButtonsColumn.Add(viewDetailsButton) traitNameColumn.Add(widget.NewSeparator()) predictedOutcomeColumn.Add(widget.NewSeparator()) confidenceRangeColumn.Add(widget.NewSeparator()) conflictExistsColumn.Add(widget.NewSeparator()) viewButtonsColumn.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) traitsContainer := container.NewHBox(layout.NewSpacer(), traitNameColumn, predictedOutcomeColumn, confidenceRangeColumn) if (multipleGenomesExist == true){ conflictExistsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setPersonGeneticAnalysisConflictExistsExplainerPage(window, currentPage) }) conflictExistsColumn.Add(conflictExistsHelpButton) traitsContainer.Add(conflictExistsColumn) } traitsContainer.Add(viewButtonsColumn) traitsContainer.Add(layout.NewSpacer()) return traitsContainer, nil } traitsContainer, err := getTraitsContainer() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), traitsContainer) setPageContent(page, window) } func setViewPersonGeneticAnalysisNumericTraitDetailsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, traitName string, previousPage func()){ currentPage := func(){setViewPersonGeneticAnalysisNumericTraitDetailsPage(window, personIdentifier, analysisObject, traitName, previousPage)} title := getPageTitleCentered("Viewing Genetic Analysis - " + traitName) backButton := getBackButtonCentered(previousPage) allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } getDescriptionSection := func()*fyne.Container{ if (multipleGenomesExist == false){ description := getLabelCentered("Below is the trait information for this person's genome.") return description } description1 := getLabelCentered("Below is the trait information for this person's genomes.") description2 := getLabelCentered("The first two genomes are created by combining multiple genomes.") descriptionsSection := container.NewVBox(description1, description2) return descriptionsSection } descriptionSection := getDescriptionSection() traitNameLabel := widget.NewLabel("Trait:") traitNameText := getBoldLabel(traitName) traitInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){ setViewTraitDetailsPage(window, traitName, currentPage) }) traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitInfoButton, layout.NewSpacer()) getGenomesContainer := func()(*fyne.Container, error){ traitObject, err := traits.GetTraitObject(traitName) if (err != nil){ return nil, err } traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric if (traitIsDiscreteOrNumeric != "Numeric"){ return nil, errors.New("setViewPersonGeneticAnalysisNumericTraitDetailsPage called with non-numeric trait: " + traitName) } traitLociList := traitObject.LociList totalQuantityOfLoci := len(traitLociList) totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci) emptyLabel1 := widget.NewLabel("") genomeNameLabel := getItalicLabelCentered("Genome Name") emptyLabel2 := widget.NewLabel("") predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome") emptyLabel3 := widget.NewLabel("") predictionConfidenceLabel := getItalicLabelCentered("Confidence Range") quantityOfLabel := getItalicLabelCentered("Quantity of") lociKnownLabel := getItalicLabelCentered("Loci Known") emptyLabel4 := widget.NewLabel("") emptyLabel5 := widget.NewLabel("") genomeNameColumn := container.NewVBox(emptyLabel1, genomeNameLabel, widget.NewSeparator()) predictedOutcomeColumn := container.NewVBox(emptyLabel2, predictedOutcomeLabel, widget.NewSeparator()) predictionConfidenceColumn := container.NewVBox(emptyLabel3, predictionConfidenceLabel, widget.NewSeparator()) quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator()) viewDetailsButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator()) addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{ getGenomeNameCell := func()*fyne.Container{ if (isACombinedGenome == false){ genomeNameLabel := getBoldLabelCentered(genomeName) return genomeNameLabel } viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setCombinedGenomesExplainerPage(window, currentPage) }) genomeNameLabel := getBoldLabel(genomeName) genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer()) return genomeNameCell } genomeNameCell := getGenomeNameCell() analysisExists, predictedOutcome, predictionConfidenceRangesMap, quantityOfLociKnown, _, _, err := readGeneticAnalysis.GetPersonNumericTraitInfoFromGeneticAnalysis(analysisObject, traitName, genomeIdentifier) if (err != nil) { return err } outcomeFormatter := traitObject.NumericValueFormatter getPredictedOutcomeLabel := func()(fyne.Widget, error){ if (analysisExists == false){ result := widget.NewLabel(translate("Unknown")) return result, nil } outcomeFormatted, err := outcomeFormatter(predictedOutcome, true) if (err != nil) { return nil, err } outcomeLabel := getBoldLabel(outcomeFormatted) return outcomeLabel, nil } predictedOutcomeLabel, err := getPredictedOutcomeLabel() if (err != nil) { return err } predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel) 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, 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) genomeQuantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown) quantityOfLociKnownLabel := getBoldLabelCentered(genomeQuantityOfLociKnownString + "/" + totalQuantityOfLociString) viewDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){ //TODO showUnderConstructionDialog(window) }) genomeNameColumn.Add(genomeNameCell) predictedOutcomeColumn.Add(predictedOutcomeLabelCentered) predictionConfidenceColumn.Add(confidenceRangeLabelCentered) quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel) viewDetailsButtonsColumn.Add(viewDetailsButton) genomeNameColumn.Add(widget.NewSeparator()) predictedOutcomeColumn.Add(widget.NewSeparator()) predictionConfidenceColumn.Add(widget.NewSeparator()) quantityOfLociKnownColumn.Add(widget.NewSeparator()) viewDetailsButtonsColumn.Add(widget.NewSeparator()) return nil } if (multipleGenomesExist == true){ err := addGenomeRow("Only Exclude Conflicts", onlyExcludeConflictsGenomeIdentifier, true) if (err != nil){ return nil, err } err = addGenomeRow("Only Include Shared", onlyIncludeSharedGenomeIdentifier, true) if (err != nil){ return nil, err } } for _, genomeIdentifier := range allRawGenomeIdentifiersList{ getGenomeName := func()(string, error){ genomeFound, _, timeGenomeWasExported, _, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(genomeIdentifier) if (err != nil) { return "", err } if (genomeFound == false){ return "", errors.New("MyGenomeInfo for genome from analysisObject not found.") } if (multipleGenomesExist == false){ return companyName, nil } // We show the date the genome was exported exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasExported, false) if (err != nil){ return "", err } genomeName := companyName + " (Exported " + exportTimeAgo + ")" return genomeName, nil } genomeName, err := getGenomeName() if (err != nil) { return nil, err } err = addGenomeRow(genomeName, genomeIdentifier, false) if (err != nil){ return nil, err } } predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ showUnderConstructionDialog(window) //TODO }) predictedOutcomeColumn.Add(predictedOutcomeHelpButton) predictionConfidenceHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ showUnderConstructionDialog(window) }) predictionConfidenceColumn.Add(predictionConfidenceHelpButton) quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ //TODO showUnderConstructionDialog(window) }) quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton) genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, predictedOutcomeColumn, predictionConfidenceColumn, quantityOfLociKnownColumn, viewDetailsButtonsColumn, layout.NewSpacer()) return genomesContainer, nil } genomesContainer, err := getGenomesContainer() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), traitNameRow, widget.NewSeparator(), genomesContainer) setPageContent(page, window) }