Improved the creation process of genetic analyses in various ways. A sample of offspring polygenic disease risk scores are now created and viewable by users.
This commit is contained in:
parent
ee976f49b3
commit
649bf318c2
17 changed files with 1606 additions and 1417 deletions
|
@ -6,6 +6,7 @@ Small and insignificant changes may not be included in this log.
|
||||||
|
|
||||||
## Unversioned Changes
|
## Unversioned Changes
|
||||||
|
|
||||||
|
* Improved the creation process of genetic analyses in various ways. A sample of offspring polygenic disease risk scores are now created and viewable by users. - *Simon Sarasova*
|
||||||
* Improved the genetic analysis creation process in various ways. Recombination breakpoints are more accurately predicted now. - *Simon Sarasova*
|
* Improved the genetic analysis creation process in various ways. Recombination breakpoints are more accurately predicted now. - *Simon Sarasova*
|
||||||
* Improved the identity hash generation tool. The fastest quantity of goroutines is now identified and used. - *Simon Sarasova*
|
* Improved the identity hash generation tool. The fastest quantity of goroutines is now identified and used. - *Simon Sarasova*
|
||||||
* Improved the creation procedures, encoding format, and graphical presentation of genetic analyses. Map lists have been replaced by custom objects. - *Simon Sarasova*
|
* Improved the creation procedures, encoding format, and graphical presentation of genetic analyses. Map lists have been replaced by custom objects. - *Simon Sarasova*
|
||||||
|
|
|
@ -9,4 +9,4 @@ Many other people have written code for modules which are imported by Seekia. Th
|
||||||
|
|
||||||
Name | Date Of First Commit | Number Of Commits
|
Name | Date Of First Commit | Number Of Commits
|
||||||
--- | --- | ---
|
--- | --- | ---
|
||||||
Simon Sarasova | June 13, 2023 | 250
|
Simon Sarasova | June 13, 2023 | 251
|
|
@ -18,6 +18,7 @@ import "seekia/internal/helpers"
|
||||||
import "seekia/internal/network/appNetworkType/getAppNetworkType"
|
import "seekia/internal/network/appNetworkType/getAppNetworkType"
|
||||||
import "seekia/internal/profiles/attributeDisplay"
|
import "seekia/internal/profiles/attributeDisplay"
|
||||||
import "seekia/internal/profiles/userStatistics"
|
import "seekia/internal/profiles/userStatistics"
|
||||||
|
import "seekia/internal/statisticsDatum"
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
import "image"
|
import "image"
|
||||||
|
@ -146,13 +147,13 @@ func setViewUserAttributeStatisticsPage_BarChart(
|
||||||
showYAxisPercentage bool,
|
showYAxisPercentage bool,
|
||||||
statisticsReady bool,
|
statisticsReady bool,
|
||||||
anyUsersExist bool,
|
anyUsersExist bool,
|
||||||
statisticsItemsList []userStatistics.StatisticsItem,
|
statisticsDatumsList []statisticsDatum.StatisticsDatum,
|
||||||
groupingPerformed bool,
|
groupingPerformed bool,
|
||||||
groupedStatisticsItemsList []userStatistics.StatisticsItem,
|
groupedStatisticsDatumsList []statisticsDatum.StatisticsDatum,
|
||||||
chartImage image.Image,
|
chartImage image.Image,
|
||||||
previousPage func()){
|
previousPage func()){
|
||||||
|
|
||||||
currentPage := func(){setViewUserAttributeStatisticsPage_BarChart(window, identityType, xAxisAttributeName, yAxisAttribute, yAxisUnits, showYAxisPercentage, statisticsReady, anyUsersExist, statisticsItemsList, groupingPerformed, groupedStatisticsItemsList, chartImage, previousPage)}
|
currentPage := func(){setViewUserAttributeStatisticsPage_BarChart(window, identityType, xAxisAttributeName, yAxisAttribute, yAxisUnits, showYAxisPercentage, statisticsReady, anyUsersExist, statisticsDatumsList, groupingPerformed, groupedStatisticsDatumsList, chartImage, previousPage)}
|
||||||
|
|
||||||
pageIdentifier, err := helpers.GetNewRandomHexString(16)
|
pageIdentifier, err := helpers.GetNewRandomHexString(16)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
|
@ -264,7 +265,7 @@ func setViewUserAttributeStatisticsPage_BarChart(
|
||||||
}
|
}
|
||||||
|
|
||||||
viewDataButton := widget.NewButtonWithIcon("View Data", theme.ListIcon(), func(){
|
viewDataButton := widget.NewButtonWithIcon("View Data", theme.ListIcon(), func(){
|
||||||
setViewUserStatisticsDataPage(window, xAxisAttributeTitle, yAxisAttribute, showYAxisPercentage, statisticsItemsList, groupingPerformed, groupedStatisticsItemsList, true, xAxisUnits, yAxisUnits, currentPage)
|
setViewUserStatisticsDataPage(window, xAxisAttributeTitle, yAxisAttribute, showYAxisPercentage, statisticsDatumsList, groupingPerformed, groupedStatisticsDatumsList, true, xAxisUnits, yAxisUnits, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
viewFullscreenButton := widget.NewButtonWithIcon("View Fullscreen", theme.ZoomInIcon(), func(){
|
viewFullscreenButton := widget.NewButtonWithIcon("View Fullscreen", theme.ZoomInIcon(), func(){
|
||||||
|
@ -336,7 +337,7 @@ func setViewUserAttributeStatisticsPage_BarChart(
|
||||||
|
|
||||||
go updateLoadingBindingFunction()
|
go updateLoadingBindingFunction()
|
||||||
|
|
||||||
totalAnalyzedUsers, statisticsItemsList, groupingPerformed, groupedStatisticsItemsList, formatYAxisValuesFunction, err := userStatistics.GetUserStatisticsItemsLists_BarChart(identityType, appNetworkType, xAxisAttributeName, xAxisIsNumerical, formatXAxisValuesFunction, unknownXAxisValuesTextTranslated, yAxisAttribute)
|
totalAnalyzedUsers, statisticsDatumsList, groupingPerformed, groupedStatisticsDatumsList, formatYAxisValuesFunction, err := userStatistics.GetUserStatisticsDatumsLists_BarChart(identityType, appNetworkType, xAxisAttributeName, xAxisIsNumerical, formatXAxisValuesFunction, unknownXAxisValuesTextTranslated, yAxisAttribute)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
|
|
||||||
functionCompleteBoolMutex.Lock()
|
functionCompleteBoolMutex.Lock()
|
||||||
|
@ -350,7 +351,7 @@ func setViewUserAttributeStatisticsPage_BarChart(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(statisticsItemsList) == 0){
|
if (len(statisticsDatumsList) == 0){
|
||||||
|
|
||||||
functionCompleteBoolMutex.Lock()
|
functionCompleteBoolMutex.Lock()
|
||||||
functionCompleteBool = true
|
functionCompleteBool = true
|
||||||
|
@ -363,14 +364,14 @@ func setViewUserAttributeStatisticsPage_BarChart(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
getChartStatisticsItemsList := func()[]userStatistics.StatisticsItem{
|
getChartStatisticsDatumsList := func()[]statisticsDatum.StatisticsDatum{
|
||||||
if (groupingPerformed == false){
|
if (groupingPerformed == false){
|
||||||
return statisticsItemsList
|
return statisticsDatumsList
|
||||||
}
|
}
|
||||||
return groupedStatisticsItemsList
|
return groupedStatisticsDatumsList
|
||||||
}
|
}
|
||||||
|
|
||||||
chartStatisticsItemsList := getChartStatisticsItemsList()
|
chartStatisticsDatumsList := getChartStatisticsDatumsList()
|
||||||
|
|
||||||
getChartTitle := func()string{
|
getChartTitle := func()string{
|
||||||
|
|
||||||
|
@ -401,7 +402,7 @@ func setViewUserAttributeStatisticsPage_BarChart(
|
||||||
|
|
||||||
chartTitle := getChartTitle()
|
chartTitle := getChartTitle()
|
||||||
|
|
||||||
newChartImage, err := createCharts.CreateBarChart(chartTitle, chartStatisticsItemsList, formatYAxisValuesFunction, true, yAxisUnits)
|
newChartImage, err := createCharts.CreateBarChart(chartTitle, chartStatisticsDatumsList, formatYAxisValuesFunction, true, yAxisUnits)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
|
|
||||||
functionCompleteBoolMutex.Lock()
|
functionCompleteBoolMutex.Lock()
|
||||||
|
@ -421,7 +422,7 @@ func setViewUserAttributeStatisticsPage_BarChart(
|
||||||
|
|
||||||
pageHasChanged := checkIfPageHasChangedFunction()
|
pageHasChanged := checkIfPageHasChangedFunction()
|
||||||
if (pageHasChanged == false){
|
if (pageHasChanged == false){
|
||||||
setViewUserAttributeStatisticsPage_BarChart(window, identityType, xAxisAttributeName, yAxisAttribute, yAxisUnits, showYAxisPercentage, true, true, statisticsItemsList, groupingPerformed, groupedStatisticsItemsList, newChartImage, previousPage)
|
setViewUserAttributeStatisticsPage_BarChart(window, identityType, xAxisAttributeName, yAxisAttribute, yAxisUnits, showYAxisPercentage, true, true, statisticsDatumsList, groupingPerformed, groupedStatisticsDatumsList, newChartImage, previousPage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,13 +442,13 @@ func setViewUserAttributeStatisticsPage_DonutChart(
|
||||||
attributeName string,
|
attributeName string,
|
||||||
statisticsReady bool,
|
statisticsReady bool,
|
||||||
anyUsersExist bool,
|
anyUsersExist bool,
|
||||||
statisticsItemsList []userStatistics.StatisticsItem,
|
statisticsDatumsList []statisticsDatum.StatisticsDatum,
|
||||||
groupingPerformed bool,
|
groupingPerformed bool,
|
||||||
groupedStatisticsItemsList []userStatistics.StatisticsItem,
|
groupedStatisticsDatumsList []statisticsDatum.StatisticsDatum,
|
||||||
chartImage image.Image,
|
chartImage image.Image,
|
||||||
previousPage func()){
|
previousPage func()){
|
||||||
|
|
||||||
currentPage := func(){setViewUserAttributeStatisticsPage_DonutChart(window, identityType, attributeName, statisticsReady, anyUsersExist, statisticsItemsList, groupingPerformed, groupedStatisticsItemsList, chartImage, previousPage)}
|
currentPage := func(){setViewUserAttributeStatisticsPage_DonutChart(window, identityType, attributeName, statisticsReady, anyUsersExist, statisticsDatumsList, groupingPerformed, groupedStatisticsDatumsList, chartImage, previousPage)}
|
||||||
|
|
||||||
pageIdentifier, err := helpers.GetNewRandomHexString(16)
|
pageIdentifier, err := helpers.GetNewRandomHexString(16)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
|
@ -545,7 +546,7 @@ func setViewUserAttributeStatisticsPage_DonutChart(
|
||||||
|
|
||||||
viewDataButton := widget.NewButtonWithIcon("View Data", theme.ListIcon(), func(){
|
viewDataButton := widget.NewButtonWithIcon("View Data", theme.ListIcon(), func(){
|
||||||
|
|
||||||
setViewUserStatisticsDataPage(window, attributeTitle, "Number Of Users", true, statisticsItemsList, groupingPerformed, groupedStatisticsItemsList, true, attributeUnits, "Users", currentPage)
|
setViewUserStatisticsDataPage(window, attributeTitle, "Number Of Users", true, statisticsDatumsList, groupingPerformed, groupedStatisticsDatumsList, true, attributeUnits, "Users", currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
viewFullscreenButton := widget.NewButtonWithIcon("View Fullscreen", theme.ZoomInIcon(), func(){
|
viewFullscreenButton := widget.NewButtonWithIcon("View Fullscreen", theme.ZoomInIcon(), func(){
|
||||||
|
@ -616,7 +617,7 @@ func setViewUserAttributeStatisticsPage_DonutChart(
|
||||||
|
|
||||||
go updateLoadingBindingFunction()
|
go updateLoadingBindingFunction()
|
||||||
|
|
||||||
totalAnalyzedUsers, statisticsItemsList, groupingPerformed, groupedStatisticsItemsList, err := userStatistics.GetUserStatisticsItemsLists_DonutChart(identityType, appNetworkType, attributeName, attributeIsNumerical, formatAttributeValuesFunction, unknownValuesTextTranslated)
|
totalAnalyzedUsers, statisticsDatumsList, groupingPerformed, groupedStatisticsDatumsList, err := userStatistics.GetUserStatisticsDatumsLists_DonutChart(identityType, appNetworkType, attributeName, attributeIsNumerical, formatAttributeValuesFunction, unknownValuesTextTranslated)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
|
|
||||||
functionCompleteBoolMutex.Lock()
|
functionCompleteBoolMutex.Lock()
|
||||||
|
@ -630,7 +631,7 @@ func setViewUserAttributeStatisticsPage_DonutChart(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(statisticsItemsList) == 0){
|
if (len(statisticsDatumsList) == 0){
|
||||||
|
|
||||||
functionCompleteBoolMutex.Lock()
|
functionCompleteBoolMutex.Lock()
|
||||||
functionCompleteBool = true
|
functionCompleteBool = true
|
||||||
|
@ -643,14 +644,14 @@ func setViewUserAttributeStatisticsPage_DonutChart(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
getChartStatisticsItemsList := func()[]userStatistics.StatisticsItem{
|
getChartStatisticsDatumsList := func()[]statisticsDatum.StatisticsDatum{
|
||||||
if (groupingPerformed == false){
|
if (groupingPerformed == false){
|
||||||
return statisticsItemsList
|
return statisticsDatumsList
|
||||||
}
|
}
|
||||||
return groupedStatisticsItemsList
|
return groupedStatisticsDatumsList
|
||||||
}
|
}
|
||||||
|
|
||||||
chartStatisticsItemsList := getChartStatisticsItemsList()
|
chartStatisticsDatumsList := getChartStatisticsDatumsList()
|
||||||
|
|
||||||
getChartTitle := func()string{
|
getChartTitle := func()string{
|
||||||
|
|
||||||
|
@ -672,7 +673,7 @@ func setViewUserAttributeStatisticsPage_DonutChart(
|
||||||
|
|
||||||
chartTitle := getChartTitle()
|
chartTitle := getChartTitle()
|
||||||
|
|
||||||
newChartImage, err := createCharts.CreateDonutChart(chartTitle, chartStatisticsItemsList)
|
newChartImage, err := createCharts.CreateDonutChart(chartTitle, chartStatisticsDatumsList)
|
||||||
if (err != nil){
|
if (err != nil){
|
||||||
|
|
||||||
functionCompleteBoolMutex.Lock()
|
functionCompleteBoolMutex.Lock()
|
||||||
|
@ -692,7 +693,7 @@ func setViewUserAttributeStatisticsPage_DonutChart(
|
||||||
|
|
||||||
pageHasChanged := checkIfPageHasChangedFunction()
|
pageHasChanged := checkIfPageHasChangedFunction()
|
||||||
if (pageHasChanged == false){
|
if (pageHasChanged == false){
|
||||||
setViewUserAttributeStatisticsPage_DonutChart(window, identityType, attributeName, true, true, statisticsItemsList, groupingPerformed, groupedStatisticsItemsList, newChartImage, previousPage)
|
setViewUserAttributeStatisticsPage_DonutChart(window, identityType, attributeName, true, true, statisticsDatumsList, groupingPerformed, groupedStatisticsDatumsList, newChartImage, previousPage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -934,9 +935,9 @@ func setViewUserStatisticsDataPage(
|
||||||
attributeTitle string,
|
attributeTitle string,
|
||||||
rightColumnName string,
|
rightColumnName string,
|
||||||
showPercentageColumn bool,
|
showPercentageColumn bool,
|
||||||
statisticsItemsList []userStatistics.StatisticsItem,
|
statisticsDatumsList []statisticsDatum.StatisticsDatum,
|
||||||
groupingPerformed bool,
|
groupingPerformed bool,
|
||||||
groupedStatisticsItemsList []userStatistics.StatisticsItem,
|
groupedStatisticsDatumsList []statisticsDatum.StatisticsDatum,
|
||||||
showGroupedStatistics bool,
|
showGroupedStatistics bool,
|
||||||
attributeColumnUnits string,
|
attributeColumnUnits string,
|
||||||
rightColumnUnits string,
|
rightColumnUnits string,
|
||||||
|
@ -954,13 +955,13 @@ func setViewUserStatisticsDataPage(
|
||||||
|
|
||||||
if (showGroupedStatistics == false){
|
if (showGroupedStatistics == false){
|
||||||
showDataGroupedButton := getWidgetCentered(widget.NewButton("Show Data Grouped", func(){
|
showDataGroupedButton := getWidgetCentered(widget.NewButton("Show Data Grouped", func(){
|
||||||
setViewUserStatisticsDataPage(window, attributeTitle, rightColumnName, showPercentageColumn, statisticsItemsList, true, groupedStatisticsItemsList, true, attributeColumnUnits, rightColumnUnits, previousPage)
|
setViewUserStatisticsDataPage(window, attributeTitle, rightColumnName, showPercentageColumn, statisticsDatumsList, true, groupedStatisticsDatumsList, true, attributeColumnUnits, rightColumnUnits, previousPage)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
header.Add(showDataGroupedButton)
|
header.Add(showDataGroupedButton)
|
||||||
} else {
|
} else {
|
||||||
showDataRawButton := getWidgetCentered(widget.NewButton("Show Data Raw", func(){
|
showDataRawButton := getWidgetCentered(widget.NewButton("Show Data Raw", func(){
|
||||||
setViewUserStatisticsDataPage(window, attributeTitle, rightColumnName, showPercentageColumn, statisticsItemsList, true, groupedStatisticsItemsList, false, attributeColumnUnits, rightColumnUnits, previousPage)
|
setViewUserStatisticsDataPage(window, attributeTitle, rightColumnName, showPercentageColumn, statisticsDatumsList, true, groupedStatisticsDatumsList, false, attributeColumnUnits, rightColumnUnits, previousPage)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
header.Add(showDataRawButton)
|
header.Add(showDataRawButton)
|
||||||
|
@ -968,14 +969,14 @@ func setViewUserStatisticsDataPage(
|
||||||
header.Add(widget.NewSeparator())
|
header.Add(widget.NewSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatisticsItemsListToShow := func()[]userStatistics.StatisticsItem{
|
getStatisticsDatumsListToShow := func()[]statisticsDatum.StatisticsDatum{
|
||||||
if (groupingPerformed == true && showGroupedStatistics == true){
|
if (groupingPerformed == true && showGroupedStatistics == true){
|
||||||
return groupedStatisticsItemsList
|
return groupedStatisticsDatumsList
|
||||||
}
|
}
|
||||||
return statisticsItemsList
|
return statisticsDatumsList
|
||||||
}
|
}
|
||||||
|
|
||||||
statisticsItemsToShowList := getStatisticsItemsListToShow()
|
statisticsDatumsToShowList := getStatisticsDatumsListToShow()
|
||||||
|
|
||||||
getStatisticsDataGrid := func()(*fyne.Container, error){
|
getStatisticsDataGrid := func()(*fyne.Container, error){
|
||||||
|
|
||||||
|
@ -983,38 +984,38 @@ func setViewUserStatisticsDataPage(
|
||||||
|
|
||||||
if (showPercentageColumn == true){
|
if (showPercentageColumn == true){
|
||||||
|
|
||||||
for _, item := range statisticsItemsToShowList{
|
for _, datum := range statisticsDatumsToShowList{
|
||||||
|
|
||||||
itemValue := item.Value
|
datumValue := datum.Value
|
||||||
|
|
||||||
allValuesSummed += itemValue
|
allValuesSummed += datumValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeColumnValuesList := make([]string, 0, len(statisticsItemsToShowList))
|
attributeColumnValuesList := make([]string, 0, len(statisticsDatumsToShowList))
|
||||||
rightColumnValuesList := make([]string, 0, len(statisticsItemsToShowList))
|
rightColumnValuesList := make([]string, 0, len(statisticsDatumsToShowList))
|
||||||
percentageColumnValuesList := make([]string, 0, len(statisticsItemsToShowList))
|
percentageColumnValuesList := make([]string, 0, len(statisticsDatumsToShowList))
|
||||||
|
|
||||||
for _, item := range statisticsItemsToShowList{
|
for _, datum := range statisticsDatumsToShowList{
|
||||||
|
|
||||||
// Each item is represents a row in the data grid.
|
// Each datum is represents a row in the data grid.
|
||||||
|
|
||||||
itemLabelFormatted := item.LabelFormatted
|
datumLabelFormatted := datum.LabelFormatted
|
||||||
|
|
||||||
itemValueFormatted := item.ValueFormatted
|
datumValueFormatted := datum.ValueFormatted
|
||||||
|
|
||||||
attributeColumnValuesList = append(attributeColumnValuesList, itemLabelFormatted)
|
attributeColumnValuesList = append(attributeColumnValuesList, datumLabelFormatted)
|
||||||
rightColumnValuesList = append(rightColumnValuesList, itemValueFormatted)
|
rightColumnValuesList = append(rightColumnValuesList, datumValueFormatted)
|
||||||
|
|
||||||
if (showPercentageColumn == true){
|
if (showPercentageColumn == true){
|
||||||
|
|
||||||
itemValue := item.Value
|
datumValue := datum.Value
|
||||||
|
|
||||||
getValuePercentage := func()float64{
|
getValuePercentage := func()float64{
|
||||||
if (allValuesSummed == 0){
|
if (allValuesSummed == 0){
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
valuePercentage := (itemValue/allValuesSummed)*100
|
valuePercentage := (datumValue/allValuesSummed)*100
|
||||||
return valuePercentage
|
return valuePercentage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,20 +8,24 @@ import "fyne.io/fyne/v2/container"
|
||||||
import "fyne.io/fyne/v2/layout"
|
import "fyne.io/fyne/v2/layout"
|
||||||
import "fyne.io/fyne/v2/theme"
|
import "fyne.io/fyne/v2/theme"
|
||||||
import "fyne.io/fyne/v2/widget"
|
import "fyne.io/fyne/v2/widget"
|
||||||
|
import "fyne.io/fyne/v2/canvas"
|
||||||
|
|
||||||
import "seekia/resources/geneticReferences/monogenicDiseases"
|
import "seekia/resources/geneticReferences/monogenicDiseases"
|
||||||
import "seekia/resources/geneticReferences/polygenicDiseases"
|
import "seekia/resources/geneticReferences/polygenicDiseases"
|
||||||
import "seekia/resources/geneticReferences/traits"
|
import "seekia/resources/geneticReferences/traits"
|
||||||
|
|
||||||
import "seekia/internal/appMemory"
|
import "seekia/internal/appMemory"
|
||||||
|
import "seekia/internal/createCharts"
|
||||||
import "seekia/internal/encoding"
|
import "seekia/internal/encoding"
|
||||||
import "seekia/internal/genetics/geneticAnalysis"
|
import "seekia/internal/genetics/geneticAnalysis"
|
||||||
import "seekia/internal/genetics/myGenomes"
|
import "seekia/internal/genetics/myGenomes"
|
||||||
import "seekia/internal/genetics/myPeople"
|
import "seekia/internal/genetics/myPeople"
|
||||||
import "seekia/internal/genetics/readGeneticAnalysis"
|
import "seekia/internal/genetics/readGeneticAnalysis"
|
||||||
import "seekia/internal/helpers"
|
import "seekia/internal/helpers"
|
||||||
|
import "seekia/internal/statisticsDatum"
|
||||||
|
|
||||||
import "slices"
|
import "slices"
|
||||||
|
import "image"
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1006,7 +1010,7 @@ func setViewCoupleGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso
|
||||||
|
|
||||||
mainGenomePairIdentifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
|
mainGenomePairIdentifier := helpers.JoinTwo16ByteArrays(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
|
||||||
|
|
||||||
offspringRiskScoreKnown, _, offspringRiskScoreFormatted, _, conflictExists, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, mainGenomePairIdentifier)
|
offspringRiskScoreKnown, _, offspringRiskScoreFormatted, _, _, conflictExists, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, mainGenomePairIdentifier)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
getRiskScoreLabelText := func()string{
|
getRiskScoreLabelText := func()string{
|
||||||
|
@ -1116,25 +1120,27 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
||||||
})
|
})
|
||||||
diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, diseaseNameInfoButton, layout.NewSpacer())
|
diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameLabel, diseaseNameText, diseaseNameInfoButton, layout.NewSpacer())
|
||||||
|
|
||||||
emptyLabelA := widget.NewLabel("")
|
emptyLabel1 := widget.NewLabel("")
|
||||||
emptyLabelB := widget.NewLabel("")
|
emptyLabel2 := widget.NewLabel("")
|
||||||
|
|
||||||
offspringRiskScoreLabel := getItalicLabelCentered("Offspring Risk Score")
|
offspringRiskScoreLabel := getItalicLabelCentered("Offspring Risk Score")
|
||||||
|
|
||||||
emptyLabelC := widget.NewLabel("")
|
emptyLabel3 := widget.NewLabel("")
|
||||||
emptyLabelD := widget.NewLabel("")
|
emptyLabel4 := widget.NewLabel("")
|
||||||
|
emptyLabel5 := widget.NewLabel("")
|
||||||
|
|
||||||
viewGenomePairButtonsColumn := container.NewVBox(emptyLabelA, widget.NewSeparator())
|
viewGenomePairButtonsColumn := container.NewVBox(emptyLabel1, widget.NewSeparator())
|
||||||
pairNameColumn := container.NewVBox(emptyLabelB, widget.NewSeparator())
|
pairNameColumn := container.NewVBox(emptyLabel2, widget.NewSeparator())
|
||||||
offspringRiskScoreColumn := container.NewVBox(offspringRiskScoreLabel, widget.NewSeparator())
|
offspringRiskScoreColumn := container.NewVBox(offspringRiskScoreLabel, widget.NewSeparator())
|
||||||
viewLifetimeRiskButtonsColumn := container.NewVBox(emptyLabelC, widget.NewSeparator())
|
viewSampleOffspringsChartButtonsColumn := container.NewVBox(emptyLabel3, widget.NewSeparator())
|
||||||
viewOffspringLociButtonsColumn := container.NewVBox(emptyLabelD, widget.NewSeparator())
|
viewLifetimeRiskButtonsColumn := container.NewVBox(emptyLabel4, widget.NewSeparator())
|
||||||
|
viewOffspringLociButtonsColumn := container.NewVBox(emptyLabel5, widget.NewSeparator())
|
||||||
|
|
||||||
addGenomePairRow := func(genomePairName string, person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
addGenomePairRow := func(genomePairName string, person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
||||||
|
|
||||||
genomePairIdentifier := helpers.JoinTwo16ByteArrays(person1GenomeIdentifier, person2GenomeIdentifier)
|
genomePairIdentifier := helpers.JoinTwo16ByteArrays(person1GenomeIdentifier, person2GenomeIdentifier)
|
||||||
|
|
||||||
offspringRiskScoreKnown, _, offspringRiskScoreFormatted, _, _, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier)
|
offspringRiskScoreKnown, _, offspringRiskScoreFormatted, sampleOffspringRiskScoresList, numberOfLociTested, _, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
getRiskScoreLabelText := func()string{
|
getRiskScoreLabelText := func()string{
|
||||||
|
@ -1158,6 +1164,10 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
||||||
setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage)
|
setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window, person1Name, person2Name, person1AnalysisObject, person2AnalysisObject, coupleAnalysisObject, diseaseName, genomePairIdentifier, genomePairName, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
viewSampleOffspringsChartButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
||||||
|
setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window, diseaseName, sampleOffspringRiskScoresList, numberOfLociTested, currentPage)
|
||||||
|
})
|
||||||
|
|
||||||
viewOffspringLifetimeRiskButton := widget.NewButtonWithIcon("", theme.HistoryIcon(), func(){
|
viewOffspringLifetimeRiskButton := widget.NewButtonWithIcon("", theme.HistoryIcon(), func(){
|
||||||
|
|
||||||
diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName)
|
diseaseObject, err := polygenicDiseases.GetPolygenicDiseaseObject(diseaseName)
|
||||||
|
@ -1190,12 +1200,15 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
||||||
viewGenomePairButtonsColumn.Add(viewGenomePairButton)
|
viewGenomePairButtonsColumn.Add(viewGenomePairButton)
|
||||||
pairNameColumn.Add(genomePairNameLabel)
|
pairNameColumn.Add(genomePairNameLabel)
|
||||||
offspringRiskScoreColumn.Add(offspringRiskScoreLabel)
|
offspringRiskScoreColumn.Add(offspringRiskScoreLabel)
|
||||||
|
viewSampleOffspringsChartButtonsColumn.Add(viewSampleOffspringsChartButton)
|
||||||
viewLifetimeRiskButtonsColumn.Add(viewOffspringLifetimeRiskButton)
|
viewLifetimeRiskButtonsColumn.Add(viewOffspringLifetimeRiskButton)
|
||||||
viewOffspringLociButtonsColumn.Add(viewOffspringLociButton)
|
viewOffspringLociButtonsColumn.Add(viewOffspringLociButton)
|
||||||
|
|
||||||
viewGenomePairButtonsColumn.Add(widget.NewSeparator())
|
viewGenomePairButtonsColumn.Add(widget.NewSeparator())
|
||||||
pairNameColumn.Add(widget.NewSeparator())
|
pairNameColumn.Add(widget.NewSeparator())
|
||||||
offspringRiskScoreColumn.Add(widget.NewSeparator())
|
offspringRiskScoreColumn.Add(widget.NewSeparator())
|
||||||
|
viewSampleOffspringsChartButtonsColumn.Add(widget.NewSeparator())
|
||||||
|
viewLifetimeRiskButtonsColumn.Add(widget.NewSeparator())
|
||||||
viewOffspringLociButtonsColumn.Add(widget.NewSeparator())
|
viewOffspringLociButtonsColumn.Add(widget.NewSeparator())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -1221,7 +1234,7 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
||||||
|
|
||||||
offspringRiskScoreColumn.Add(offspringRiskScoreHelpButton)
|
offspringRiskScoreColumn.Add(offspringRiskScoreHelpButton)
|
||||||
|
|
||||||
genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairButtonsColumn, pairNameColumn, offspringRiskScoreColumn, viewOffspringLociButtonsColumn, layout.NewSpacer())
|
genomesContainer := container.NewHBox(layout.NewSpacer(), viewGenomePairButtonsColumn, pairNameColumn, offspringRiskScoreColumn, viewSampleOffspringsChartButtonsColumn, viewLifetimeRiskButtonsColumn, viewOffspringLociButtonsColumn, layout.NewSpacer())
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), genomesContainer)
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), genomesContainer)
|
||||||
|
|
||||||
|
@ -1314,7 +1327,7 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseGenomePairDetailsPage(window fy
|
||||||
|
|
||||||
genomeNameLabel := getBoldLabelCentered(genomeName)
|
genomeNameLabel := getBoldLabelCentered(genomeName)
|
||||||
|
|
||||||
personRiskScoreKnown, _, personRiskScoreFormatted, numberOfLociTested, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, personAnalysisGenomeIdentifier)
|
personRiskScoreKnown, _, personRiskScoreFormatted, _, numberOfLociTested, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, personAnalysisGenomeIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
getPersonRiskScoreLabelText := func()string{
|
getPersonRiskScoreLabelText := func()string{
|
||||||
|
@ -1408,7 +1421,7 @@ func setViewCouplePolygenicDiseaseLociPage(window fyne.Window, person1Name strin
|
||||||
|
|
||||||
genomePairRow := container.NewHBox(layout.NewSpacer(), genomePairLabel, genomePairNameLabel, viewGenomePairInfoButton, layout.NewSpacer())
|
genomePairRow := container.NewHBox(layout.NewSpacer(), genomePairLabel, genomePairNameLabel, viewGenomePairInfoButton, layout.NewSpacer())
|
||||||
|
|
||||||
_, _, _, numberOfLociTested, _, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier)
|
_, _, _, _, numberOfLociTested, _, err := readGeneticAnalysis.GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier)
|
||||||
if (err != nil){
|
if (err != nil){
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
|
@ -1719,6 +1732,133 @@ func setViewCoupleGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window fyne.Wi
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a page that shows the user 100 sample offspring polygenic disease risk scores on a bar chart
|
||||||
|
// This helps users to visualize the standard deviation of their offspring's disease risk with this user
|
||||||
|
func setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window fyne.Window, diseaseName string, sampleOffspringRiskScoresList []int, numberOfLociTested int, previousPage func()){
|
||||||
|
|
||||||
|
currentPage := func(){setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window, diseaseName, sampleOffspringRiskScoresList, numberOfLociTested, previousPage)}
|
||||||
|
|
||||||
|
title := getPageTitleCentered("Viewing Sample Offspring Risk Scores Chart")
|
||||||
|
|
||||||
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
|
||||||
|
description := widget.NewLabel("Below is a chart of 100 sample offspring risk scores for this disease.")
|
||||||
|
descriptionHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
|
//TODO
|
||||||
|
showUnderConstructionDialog(window)
|
||||||
|
})
|
||||||
|
descriptionRow := container.NewHBox(layout.NewSpacer(), description, descriptionHelpButton, layout.NewSpacer())
|
||||||
|
|
||||||
|
diseaseNameTitle := widget.NewLabel("Disease Name:")
|
||||||
|
diseaseNameLabel := getBoldLabel(diseaseName)
|
||||||
|
diseaseNameRow := container.NewHBox(layout.NewSpacer(), diseaseNameTitle, diseaseNameLabel, layout.NewSpacer())
|
||||||
|
|
||||||
|
if (len(sampleOffspringRiskScoresList) == 0){
|
||||||
|
description2 := getBoldLabelCentered("There is no offspring information available for this disease.")
|
||||||
|
description3 := getBoldLabelCentered("This is because there were no disease loci for which both prospective parents had information.")
|
||||||
|
|
||||||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionRow, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), description2, description3)
|
||||||
|
|
||||||
|
setPageContent(page, window)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
diseaseLociMap, err := polygenicDiseases.GetPolygenicDiseaseLociMap(diseaseName)
|
||||||
|
if (err != nil){
|
||||||
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
totalNumberOfLoci := len(diseaseLociMap)
|
||||||
|
totalNumberOfLociString := helpers.ConvertIntToString(totalNumberOfLoci)
|
||||||
|
|
||||||
|
numberOfLociTestedTitle := widget.NewLabel("Number Of Loci Tested:")
|
||||||
|
numberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested)
|
||||||
|
numberOfLociTestedLabel := getBoldLabel(numberOfLociTestedString + "/" + totalNumberOfLociString)
|
||||||
|
|
||||||
|
lociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
|
setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage)
|
||||||
|
})
|
||||||
|
|
||||||
|
numberOfLociTestedRow := container.NewHBox(layout.NewSpacer(), numberOfLociTestedTitle, numberOfLociTestedLabel, lociTestedHelpButton, layout.NewSpacer())
|
||||||
|
|
||||||
|
getOffspringSampleRiskScoresChartImage := func()(image.Image, error){
|
||||||
|
|
||||||
|
// Map Structure: Risk Score -> Number of offspring with that risk score
|
||||||
|
offspringRiskScoreCountsMap := make(map[int]int)
|
||||||
|
|
||||||
|
for _, offspringRiskScore := range sampleOffspringRiskScoresList{
|
||||||
|
offspringRiskScoreCountsMap[offspringRiskScore] += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Move StatisticsDatum to its own package, because we are using it for non-user purposes, and will continue to do so
|
||||||
|
offspringStatisticsDatumsList := make([]statisticsDatum.StatisticsDatum, 0)
|
||||||
|
|
||||||
|
for riskScore:=0; riskScore <= 10; riskScore += 1{
|
||||||
|
|
||||||
|
getOffspringCount := func()int{
|
||||||
|
|
||||||
|
offspringCount, exists := offspringRiskScoreCountsMap[riskScore]
|
||||||
|
if (exists == false){
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return offspringCount
|
||||||
|
}
|
||||||
|
|
||||||
|
offspringCount := getOffspringCount()
|
||||||
|
|
||||||
|
riskScoreString := helpers.ConvertIntToString(riskScore)
|
||||||
|
offspringCountString := helpers.ConvertIntToString(offspringCount)
|
||||||
|
|
||||||
|
newStatisticsDatum := statisticsDatum.StatisticsDatum{
|
||||||
|
|
||||||
|
Label: riskScoreString + "/10",
|
||||||
|
LabelFormatted: riskScoreString + "/10",
|
||||||
|
Value: float64(offspringCount),
|
||||||
|
ValueFormatted: offspringCountString,
|
||||||
|
}
|
||||||
|
|
||||||
|
offspringStatisticsDatumsList = append(offspringStatisticsDatumsList, newStatisticsDatum)
|
||||||
|
}
|
||||||
|
|
||||||
|
chartTitle := diseaseName + ": 100 Prospective Offspring Risk Scores"
|
||||||
|
|
||||||
|
formatYAxisValuesFunction := func(inputRiskScore float64)(string, error){
|
||||||
|
|
||||||
|
inputRiskScoreInt, err := helpers.FloorFloat64ToInt(inputRiskScore)
|
||||||
|
if (err != nil){ return "", err }
|
||||||
|
|
||||||
|
inputRiskScoreString := helpers.ConvertIntToString(inputRiskScoreInt)
|
||||||
|
|
||||||
|
return inputRiskScoreString, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
offspringsChart, err := createCharts.CreateBarChart(chartTitle, offspringStatisticsDatumsList, formatYAxisValuesFunction, true, " Offspring")
|
||||||
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
|
return offspringsChart, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
offspringRiskScoresChartImage, err := getOffspringSampleRiskScoresChartImage()
|
||||||
|
if (err != nil){
|
||||||
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
viewChartFullscreenButton := getWidgetCentered(widget.NewButtonWithIcon("View Fullscreen", theme.ZoomInIcon(), func(){
|
||||||
|
setViewFullpageImagePage(window, offspringRiskScoresChartImage, currentPage)
|
||||||
|
}))
|
||||||
|
|
||||||
|
pageHeader := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionRow, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), numberOfLociTestedRow, widget.NewSeparator())
|
||||||
|
|
||||||
|
chartFyneImage := canvas.NewImageFromImage(offspringRiskScoresChartImage)
|
||||||
|
chartFyneImage.FillMode = canvas.ImageFillContain
|
||||||
|
|
||||||
|
page := container.NewBorder(pageHeader, viewChartFullscreenButton, nil, nil, chartFyneImage)
|
||||||
|
|
||||||
|
setPageContent(page, window)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func setViewCoupleGeneticAnalysisTraitsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, previousPage func()){
|
func setViewCoupleGeneticAnalysisTraitsPage(window fyne.Window, person1Name string, person2Name string, person1AnalysisObject geneticAnalysis.PersonAnalysis, person2AnalysisObject geneticAnalysis.PersonAnalysis, coupleAnalysisObject geneticAnalysis.CoupleAnalysis, previousPage func()){
|
||||||
|
|
||||||
|
|
|
@ -935,7 +935,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso
|
||||||
|
|
||||||
diseaseNameText := getBoldLabelCentered(diseaseName)
|
diseaseNameText := getBoldLabelCentered(diseaseName)
|
||||||
|
|
||||||
personRiskScoreKnown, _, personRiskScoreFormatted, _, conflictExists, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, mainGenomeIdentifier)
|
personRiskScoreKnown, _, personRiskScoreFormatted, _, _, conflictExists, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, mainGenomeIdentifier)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
getPersonRiskScoreLabelText := func()string{
|
getPersonRiskScoreLabelText := func()string{
|
||||||
|
@ -1096,7 +1096,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
||||||
|
|
||||||
genomeNameCell := getGenomeNameCell()
|
genomeNameCell := getGenomeNameCell()
|
||||||
|
|
||||||
diseaseRiskScoreKnown, _, diseaseRiskScoreFormatted, numberOfLociTested, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, genomeIdentifier)
|
diseaseRiskScoreKnown, _, diseaseRiskScoreFormatted, _, numberOfLociTested, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(analysisObject, diseaseName, genomeIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
getRiskScoreLabelText := func()string{
|
getRiskScoreLabelText := func()string{
|
||||||
|
@ -1418,7 +1418,7 @@ func setViewPersonGenomePolygenicDiseaseLociPage(window fyne.Window, geneticAnal
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
locusRiskWeightIsKnown, genomeLocusRiskWeight, _, _, _, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier)
|
locusRiskWeightIsKnown, genomeLocusRiskWeight, _, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
|
@ -1484,7 +1484,7 @@ func setViewPersonGenomePolygenicDiseaseLociPage(window fyne.Window, geneticAnal
|
||||||
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
|
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
locusRiskWeightIsKnown, genomeLocusRiskWeight, _, _, locusOddsRatioIsKnown, _, locusOddsRatioFormatted, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier)
|
locusRiskWeightIsKnown, genomeLocusRiskWeight, locusOddsRatioIsKnown, _, locusOddsRatioFormatted, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
getGenomeLocusRiskWeightText := func()string{
|
getGenomeLocusRiskWeightText := func()string{
|
||||||
|
@ -1635,7 +1635,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window fyne.Wi
|
||||||
|
|
||||||
addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{
|
addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{
|
||||||
|
|
||||||
genomeRiskWeightKnown, genomeRiskWeight, _, _, genomeOddsRatioKnown, _, genomeOddsRatioFormatted, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier)
|
genomeRiskWeightKnown, genomeRiskWeight, genomeOddsRatioIsKnown, _, genomeOddsRatioFormatted, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(geneticAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
getGenomeRiskWeightText := func()string{
|
getGenomeRiskWeightText := func()string{
|
||||||
|
@ -1654,7 +1654,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window fyne.Wi
|
||||||
|
|
||||||
getGenomeOddsRatioText := func()string{
|
getGenomeOddsRatioText := func()string{
|
||||||
|
|
||||||
if (genomeOddsRatioKnown == false){
|
if (genomeOddsRatioIsKnown == false){
|
||||||
result := translate("Unknown")
|
result := translate("Unknown")
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -2567,9 +2567,6 @@ func setViewMateProfilePage_TotalDiseaseRisk(window fyne.Window, getAnyUserProfi
|
||||||
|
|
||||||
numberOfOffspringPolygenicDiseasesTestedRow := container.NewHBox(layout.NewSpacer(), numberOfOffspringPolygenicDiseasesTestedTitle, numberOfOffspringPolygenicDiseasesTestedLabel, layout.NewSpacer())
|
numberOfOffspringPolygenicDiseasesTestedRow := container.NewHBox(layout.NewSpacer(), numberOfOffspringPolygenicDiseasesTestedTitle, numberOfOffspringPolygenicDiseasesTestedLabel, layout.NewSpacer())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//TODO: Add help buttons
|
//TODO: Add help buttons
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), offspringProbabilityOfAnyMonogenicDiseaseRow, numberOfOffspringMonogenicDiseasesTestedRow, widget.NewSeparator(), userTotalPolygenicDiseaseRiskScoreRow, numberOfUserPolygenicDiseasesTestedRow, widget.NewSeparator(), offspringTotalPolygenicDiseaseRiskScoreRow, numberOfOffspringPolygenicDiseasesTestedRow)
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), offspringProbabilityOfAnyMonogenicDiseaseRow, numberOfOffspringMonogenicDiseasesTestedRow, widget.NewSeparator(), userTotalPolygenicDiseaseRiskScoreRow, numberOfUserPolygenicDiseasesTestedRow, widget.NewSeparator(), offspringTotalPolygenicDiseaseRiskScoreRow, numberOfOffspringPolygenicDiseasesTestedRow)
|
||||||
|
@ -2876,13 +2873,13 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
||||||
|
|
||||||
getDiseaseInfoGrid := func()(*fyne.Container, error){
|
getDiseaseInfoGrid := func()(*fyne.Container, error){
|
||||||
|
|
||||||
emptyLabelA := widget.NewLabel("")
|
emptyLabel1 := widget.NewLabel("")
|
||||||
diseaseNameLabel := getItalicLabelCentered("Disease Name")
|
diseaseNameLabel := getItalicLabelCentered("Disease Name")
|
||||||
|
|
||||||
emptyLabelB := widget.NewLabel("")
|
emptyLabel2 := widget.NewLabel("")
|
||||||
userRiskScoreLabel := getItalicLabelCentered("User Risk Score")
|
userRiskScoreLabel := getItalicLabelCentered("User Risk Score")
|
||||||
|
|
||||||
emptyLabelC := widget.NewLabel("")
|
emptyLabel3 := widget.NewLabel("")
|
||||||
offspringRiskScoreLabel := getItalicLabelCentered("Offspring Risk Score")
|
offspringRiskScoreLabel := getItalicLabelCentered("Offspring Risk Score")
|
||||||
|
|
||||||
userNumberOfLabel := getItalicLabelCentered("User Number Of")
|
userNumberOfLabel := getItalicLabelCentered("User Number Of")
|
||||||
|
@ -2891,15 +2888,19 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
||||||
offspringNumberOfLabel := getItalicLabelCentered("Offspring Number Of")
|
offspringNumberOfLabel := getItalicLabelCentered("Offspring Number Of")
|
||||||
lociTestedLabelB := getItalicLabelCentered("Loci Tested")
|
lociTestedLabelB := getItalicLabelCentered("Loci Tested")
|
||||||
|
|
||||||
emptyLabelD := widget.NewLabel("")
|
emptyLabel4 := widget.NewLabel("")
|
||||||
emptyLabelE := widget.NewLabel("")
|
emptyLabel5 := widget.NewLabel("")
|
||||||
|
|
||||||
diseaseNameColumn := container.NewVBox(emptyLabelA, diseaseNameLabel, widget.NewSeparator())
|
emptyLabel6 := widget.NewLabel("")
|
||||||
userRiskScoreColumn := container.NewVBox(emptyLabelB, userRiskScoreLabel, widget.NewSeparator())
|
emptyLabel7 := widget.NewLabel("")
|
||||||
offspringRiskScoreColumn := container.NewVBox(emptyLabelC, offspringRiskScoreLabel, widget.NewSeparator())
|
|
||||||
|
diseaseNameColumn := container.NewVBox(emptyLabel1, diseaseNameLabel, widget.NewSeparator())
|
||||||
|
userRiskScoreColumn := container.NewVBox(emptyLabel2, userRiskScoreLabel, widget.NewSeparator())
|
||||||
|
offspringRiskScoreColumn := container.NewVBox(emptyLabel3, offspringRiskScoreLabel, widget.NewSeparator())
|
||||||
userNumberOfLociTestedColumn := container.NewVBox(userNumberOfLabel, lociTestedLabelA, widget.NewSeparator())
|
userNumberOfLociTestedColumn := container.NewVBox(userNumberOfLabel, lociTestedLabelA, widget.NewSeparator())
|
||||||
offspringNumberOfLociTestedColumn := container.NewVBox(offspringNumberOfLabel, lociTestedLabelB, widget.NewSeparator())
|
offspringNumberOfLociTestedColumn := container.NewVBox(offspringNumberOfLabel, lociTestedLabelB, widget.NewSeparator())
|
||||||
viewDiseaseInfoButtonsColumn := container.NewVBox(emptyLabelD, emptyLabelE, widget.NewSeparator())
|
viewSampleOffspringsChartButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator())
|
||||||
|
viewDiseaseInfoButtonsColumn := container.NewVBox(emptyLabel6, emptyLabel7, widget.NewSeparator())
|
||||||
|
|
||||||
myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis()
|
myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis()
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
@ -2912,129 +2913,98 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
||||||
diseaseName := diseaseObject.DiseaseName
|
diseaseName := diseaseObject.DiseaseName
|
||||||
diseaseLociList := diseaseObject.LociList
|
diseaseLociList := diseaseObject.LociList
|
||||||
|
|
||||||
userRiskWeightSum := 0
|
//Outputs:
|
||||||
userMinimumPossibleRiskWeightSum := 0
|
// -map[int64]locusValue.LocusValue
|
||||||
userMaximumPossibleRiskWeightSum := 0
|
// -error
|
||||||
userNumberOfLociTested := 0
|
getMyDiseaseLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
||||||
|
|
||||||
offspringRiskWeightSum := 0
|
if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){
|
||||||
offspringMinimumPossibleRiskWeightSum := 0
|
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||||
offspringMaximumPossibleRiskWeightSum := 0
|
return emptyMap, nil
|
||||||
offspringNumberOfLociTested := 0
|
}
|
||||||
|
|
||||||
|
anyMyLociValuesExist, _, _, myDiseaseLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myAnalysisObject, diseaseName, myGenomeIdentifier)
|
||||||
|
if (err != nil) { return nil, err }
|
||||||
|
if (anyMyLociValuesExist == false){
|
||||||
|
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
return emptyMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return myDiseaseLocusValuesMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
myDiseaseLocusValuesMap, err := getMyDiseaseLocusValuesMap()
|
||||||
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
|
// Map Structure: Locus rsID -> Locus Value
|
||||||
|
userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
|
||||||
for _, locusObject := range diseaseLociList{
|
for _, locusObject := range diseaseLociList{
|
||||||
|
|
||||||
locusIdentifierHex := locusObject.LocusIdentifier
|
|
||||||
|
|
||||||
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
|
|
||||||
if (err != nil){ return nil, err }
|
|
||||||
|
|
||||||
locusRSID := locusObject.LocusRSID
|
locusRSID := locusObject.LocusRSID
|
||||||
|
|
||||||
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
||||||
|
|
||||||
locusRiskWeightsMap := locusObject.RiskWeightsMap
|
|
||||||
locusOddsRatiosMap := locusObject.OddsRatiosMap
|
|
||||||
locusMinimumRiskWeight := locusObject.MinimumRiskWeight
|
|
||||||
locusMaximumRiskWeight := locusObject.MaximumRiskWeight
|
|
||||||
|
|
||||||
locusValueAttributeName := "LocusValue_rs" + locusRSIDString
|
locusValueAttributeName := "LocusValue_rs" + locusRSIDString
|
||||||
|
|
||||||
userLocusBasePairExists, _, userLocusBasePair, err := getAnyUserProfileAttributeFunction(locusValueAttributeName)
|
userLocusBasePairExists, _, userLocusBasePair, err := getAnyUserProfileAttributeFunction(locusValueAttributeName)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
if (userLocusBasePairExists == true){
|
if (userLocusBasePairExists == false){
|
||||||
|
continue
|
||||||
userNumberOfLociTested += 1
|
|
||||||
|
|
||||||
userMinimumPossibleRiskWeightSum += locusMinimumRiskWeight
|
|
||||||
userMaximumPossibleRiskWeightSum += locusMaximumRiskWeight
|
|
||||||
|
|
||||||
userLocusRiskWeight, exists := locusRiskWeightsMap[userLocusBasePair]
|
|
||||||
if (exists == false){
|
|
||||||
// We do not know the risk weight for this base pair
|
|
||||||
// We treat this as a 0 risk weight
|
|
||||||
} else {
|
|
||||||
userRiskWeightSum += userLocusRiskWeight
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//Outputs:
|
|
||||||
// -bool: My locus base pair exists
|
|
||||||
// -string: My locus base 1
|
|
||||||
// -string: My locus base 2
|
|
||||||
// -error
|
|
||||||
getMyLocusInfo := func()(bool, string, string, error){
|
|
||||||
if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){
|
|
||||||
return false, "", "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
locusInfoKnown, _, locusBase1, locusBase2, _, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(myAnalysisObject, diseaseName, locusIdentifier, myGenomeIdentifier)
|
|
||||||
if (err != nil){ return false, "", "", err }
|
|
||||||
if (locusInfoKnown == false){
|
|
||||||
return false, "", "", nil
|
|
||||||
}
|
|
||||||
return true, locusBase1, locusBase2, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
myLocusBasePairExists, myLocusBase1, myLocusBase2, err := getMyLocusInfo()
|
|
||||||
if (err != nil) { return nil, err }
|
|
||||||
|
|
||||||
if (userLocusBasePairExists == true && myLocusBasePairExists == true){
|
|
||||||
|
|
||||||
userLocusBase1, userLocusBase2, semicolonFound := strings.Cut(userLocusBasePair, ";")
|
userLocusBase1, userLocusBase2, semicolonFound := strings.Cut(userLocusBasePair, ";")
|
||||||
if (semicolonFound == false){
|
if (semicolonFound == false){
|
||||||
return nil, errors.New("Database contains profile containing invalid " + locusValueAttributeName + ": " + userLocusBasePair)
|
return nil, errors.New("Database corrupt: Contains profile with invalid " + locusValueAttributeName + " value: " + userLocusBasePair)
|
||||||
}
|
}
|
||||||
|
|
||||||
offspringLocusRiskWeight, _, _, _, err := createGeneticAnalysis.GetOffspringPolygenicDiseaseLocusInfo(locusRiskWeightsMap, locusOddsRatiosMap, myLocusBase1, myLocusBase2, userLocusBase1, userLocusBase2)
|
userLocusValue := locusValue.LocusValue{
|
||||||
|
Base1Value: userLocusBase1,
|
||||||
|
Base2Value: userLocusBase2,
|
||||||
|
//TODO: Share LocusIsPhased information in user profiles and retrieve it into this value
|
||||||
|
LocusIsPhased: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
userDiseaseLocusValuesMap[locusRSID] = userLocusValue
|
||||||
|
}
|
||||||
|
|
||||||
|
userDiseaseInfoIsKnown, userDiseaseRiskScore, userNumberOfLociTested, _, err := createGeneticAnalysis.GetPersonGenomePolygenicDiseaseInfo(diseaseLociList, userDiseaseLocusValuesMap, true)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
offspringNumberOfLociTested += 1
|
|
||||||
|
|
||||||
offspringMinimumPossibleRiskWeightSum += locusMinimumRiskWeight
|
|
||||||
offspringMaximumPossibleRiskWeightSum += locusMaximumRiskWeight
|
|
||||||
|
|
||||||
offspringRiskWeightSum += offspringLocusRiskWeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getUserDiseaseRiskScoreString := func()(string, error){
|
getUserDiseaseRiskScoreString := func()(string, error){
|
||||||
|
|
||||||
if (userNumberOfLociTested == 0){
|
if (userDiseaseInfoIsKnown == false){
|
||||||
result := translate("Unknown")
|
result := translate("Unknown")
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
userRiskScore, err := helpers.ScaleNumberProportionally(true, userRiskWeightSum, userMinimumPossibleRiskWeightSum, userMaximumPossibleRiskWeightSum, 0, 10)
|
userRiskScoreString := helpers.ConvertIntToString(userDiseaseRiskScore)
|
||||||
if (err != nil) { return "", err }
|
|
||||||
|
|
||||||
userRiskScoreString := helpers.ConvertIntToString(userRiskScore)
|
|
||||||
resultFormatted := userRiskScoreString + "/10"
|
resultFormatted := userRiskScoreString + "/10"
|
||||||
|
|
||||||
return resultFormatted, nil
|
return resultFormatted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
userDiseaseRiskScore, err := getUserDiseaseRiskScoreString()
|
userDiseaseRiskScoreString, err := getUserDiseaseRiskScoreString()
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
getOffspringDiseaseRiskScoreString := func()(string, error){
|
anyOffspringLociTested, offspringDiseaseRiskScore, offspringNumberOfLociTested, _, offspringSampleRiskScoresList, err := createGeneticAnalysis.GetOffspringPolygenicDiseaseInfo(diseaseLociList, myDiseaseLocusValuesMap, userDiseaseLocusValuesMap)
|
||||||
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
if (offspringNumberOfLociTested == 0){
|
getOffspringDiseaseRiskScoreFormatted := func()(string, error){
|
||||||
|
|
||||||
|
if (anyOffspringLociTested == false){
|
||||||
result := translate("Unknown")
|
result := translate("Unknown")
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
offspringRiskScore, err := helpers.ScaleNumberProportionally(true, offspringRiskWeightSum, offspringMinimumPossibleRiskWeightSum, offspringMaximumPossibleRiskWeightSum, 0, 10)
|
offspringRiskScoreString := helpers.ConvertIntToString(offspringDiseaseRiskScore)
|
||||||
if (err != nil) { return "", err }
|
|
||||||
|
|
||||||
offspringRiskScoreString := helpers.ConvertIntToString(offspringRiskScore)
|
|
||||||
resultFormatted := offspringRiskScoreString + "/10"
|
resultFormatted := offspringRiskScoreString + "/10"
|
||||||
return resultFormatted, nil
|
return resultFormatted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
offspringDiseaseRiskScore, err := getOffspringDiseaseRiskScoreString()
|
offspringDiseaseRiskScoreFormatted, err := getOffspringDiseaseRiskScoreFormatted()
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
totalNumberOfDiseaseLoci := len(diseaseLociList)
|
totalNumberOfDiseaseLoci := len(diseaseLociList)
|
||||||
|
@ -3046,10 +3016,16 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
||||||
offspringNumberOfLociTestedFormatted := offspringNumberOfLociTestedString + "/" + totalNumberOfDiseaseLociString
|
offspringNumberOfLociTestedFormatted := offspringNumberOfLociTestedString + "/" + totalNumberOfDiseaseLociString
|
||||||
|
|
||||||
diseaseNameText := getBoldLabelCentered(diseaseName)
|
diseaseNameText := getBoldLabelCentered(diseaseName)
|
||||||
userRiskScoreLabel := getBoldLabelCentered(userDiseaseRiskScore)
|
userRiskScoreLabel := getBoldLabelCentered(userDiseaseRiskScoreString)
|
||||||
offspringRiskScoreLabel := getBoldLabelCentered(offspringDiseaseRiskScore)
|
offspringRiskScoreLabel := getBoldLabelCentered(offspringDiseaseRiskScoreFormatted)
|
||||||
userNumberOfLociTestedLabel := getBoldLabelCentered(userNumberOfLociTestedFormatted)
|
userNumberOfLociTestedLabel := getBoldLabelCentered(userNumberOfLociTestedFormatted)
|
||||||
offspringNumberOfLociTestedLabel := getBoldLabelCentered(offspringNumberOfLociTestedFormatted)
|
offspringNumberOfLociTestedLabel := getBoldLabelCentered(offspringNumberOfLociTestedFormatted)
|
||||||
|
|
||||||
|
viewSampleOffspringsChartButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
||||||
|
|
||||||
|
setViewPolygenicDiseaseSampleOffspringRiskScoresChart(window, diseaseName, offspringSampleRiskScoresList, offspringNumberOfLociTested, currentPage)
|
||||||
|
})
|
||||||
|
|
||||||
viewDiseaseDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
viewDiseaseDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
||||||
setViewMateProfilePage_PolygenicDiseaseLoci(window, diseaseName, userOrOffspring, getAnyUserProfileAttributeFunction, currentPage)
|
setViewMateProfilePage_PolygenicDiseaseLoci(window, diseaseName, userOrOffspring, getAnyUserProfileAttributeFunction, currentPage)
|
||||||
})
|
})
|
||||||
|
@ -3059,6 +3035,7 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
||||||
offspringRiskScoreColumn.Add(offspringRiskScoreLabel)
|
offspringRiskScoreColumn.Add(offspringRiskScoreLabel)
|
||||||
userNumberOfLociTestedColumn.Add(userNumberOfLociTestedLabel)
|
userNumberOfLociTestedColumn.Add(userNumberOfLociTestedLabel)
|
||||||
offspringNumberOfLociTestedColumn.Add(offspringNumberOfLociTestedLabel)
|
offspringNumberOfLociTestedColumn.Add(offspringNumberOfLociTestedLabel)
|
||||||
|
viewSampleOffspringsChartButtonsColumn.Add(viewSampleOffspringsChartButton)
|
||||||
viewDiseaseInfoButtonsColumn.Add(viewDiseaseDetailsButton)
|
viewDiseaseInfoButtonsColumn.Add(viewDiseaseDetailsButton)
|
||||||
|
|
||||||
diseaseNameColumn.Add(widget.NewSeparator())
|
diseaseNameColumn.Add(widget.NewSeparator())
|
||||||
|
@ -3066,6 +3043,7 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
||||||
offspringRiskScoreColumn.Add(widget.NewSeparator())
|
offspringRiskScoreColumn.Add(widget.NewSeparator())
|
||||||
userNumberOfLociTestedColumn.Add(widget.NewSeparator())
|
userNumberOfLociTestedColumn.Add(widget.NewSeparator())
|
||||||
offspringNumberOfLociTestedColumn.Add(widget.NewSeparator())
|
offspringNumberOfLociTestedColumn.Add(widget.NewSeparator())
|
||||||
|
viewSampleOffspringsChartButtonsColumn.Add(widget.NewSeparator())
|
||||||
viewDiseaseInfoButtonsColumn.Add(widget.NewSeparator())
|
viewDiseaseInfoButtonsColumn.Add(widget.NewSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3076,18 +3054,18 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
||||||
offspringRiskScoreHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
offspringRiskScoreHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setOffspringPolygenicDiseaseRiskScoreExplainerPage(window, currentPage)
|
setOffspringPolygenicDiseaseRiskScoreExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
userNumberOfLociTestedButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
userNumberOfLociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage)
|
setPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
offspringNumberOfLociTestedButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
offspringNumberOfLociTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage)
|
setOffspringPolygenicDiseaseNumberOfLociTestedExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
userRiskScoreColumn.Add(userRiskScoreHelpButton)
|
userRiskScoreColumn.Add(userRiskScoreHelpButton)
|
||||||
offspringRiskScoreColumn.Add(offspringRiskScoreHelpButton)
|
offspringRiskScoreColumn.Add(offspringRiskScoreHelpButton)
|
||||||
userNumberOfLociTestedColumn.Add(userNumberOfLociTestedButton)
|
userNumberOfLociTestedColumn.Add(userNumberOfLociTestedHelpButton)
|
||||||
offspringNumberOfLociTestedColumn.Add(offspringNumberOfLociTestedButton)
|
offspringNumberOfLociTestedColumn.Add(offspringNumberOfLociTestedHelpButton)
|
||||||
|
|
||||||
if (userOrOffspring == "User"){
|
if (userOrOffspring == "User"){
|
||||||
diseaseInfoGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, userRiskScoreColumn, userNumberOfLociTestedColumn, viewDiseaseInfoButtonsColumn, layout.NewSpacer())
|
diseaseInfoGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, userRiskScoreColumn, userNumberOfLociTestedColumn, viewDiseaseInfoButtonsColumn, layout.NewSpacer())
|
||||||
|
@ -3095,7 +3073,7 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
||||||
return diseaseInfoGrid, nil
|
return diseaseInfoGrid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
diseaseInfoGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, offspringRiskScoreColumn, offspringNumberOfLociTestedColumn, viewDiseaseInfoButtonsColumn, layout.NewSpacer())
|
diseaseInfoGrid := container.NewHBox(layout.NewSpacer(), diseaseNameColumn, offspringRiskScoreColumn, offspringNumberOfLociTestedColumn, viewSampleOffspringsChartButtonsColumn, viewDiseaseInfoButtonsColumn, layout.NewSpacer())
|
||||||
|
|
||||||
return diseaseInfoGrid, nil
|
return diseaseInfoGrid, nil
|
||||||
}
|
}
|
||||||
|
@ -3148,114 +3126,107 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
||||||
|
|
||||||
numberOfDiseaseLoci := len(diseaseLocusObjectsList)
|
numberOfDiseaseLoci := len(diseaseLocusObjectsList)
|
||||||
|
|
||||||
|
// Outputs:
|
||||||
|
// -map[int64]locusValue.LocusValue: Map Structure: Locus rsID -> Locus Value
|
||||||
|
// -error
|
||||||
|
getMyDiseaseLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
||||||
|
|
||||||
myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis()
|
myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis()
|
||||||
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
|
if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){
|
||||||
|
|
||||||
|
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
return emptyMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
anyLocusValuesExist, _, _, myLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myAnalysisObject, diseaseName, myGenomeIdentifier)
|
||||||
|
if (err != nil) { return nil, err }
|
||||||
|
if (anyLocusValuesExist == false){
|
||||||
|
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
return emptyMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return myLocusValuesMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
myDiseaseLocusValuesMap, err := getMyDiseaseLocusValuesMap()
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//Outputs:
|
getUserLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
||||||
// -bool: User locus Info is known
|
|
||||||
// -int: User locus Risk weight
|
// Map Structure: Locus rsID -> Locus Value
|
||||||
// -string: Locus base pair
|
userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||||
// -bool: User locus odds ratio known
|
|
||||||
// -string: User locus odds ratio formatted
|
for _, locusObject := range diseaseLocusObjectsList{
|
||||||
// -error
|
|
||||||
getUserLocusInfo := func(locusRSID int64, locusRiskWeightsMap map[string]int, locusOddsRatiosMap map[string]float64)(bool, int, string, bool, string, error){
|
locusRSID := locusObject.LocusRSID
|
||||||
|
|
||||||
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
||||||
|
|
||||||
locusValueAttributeName := "LocusValue_rs" + locusRSIDString
|
locusValueAttributeName := "LocusValue_rs" + locusRSIDString
|
||||||
|
|
||||||
userLocusBasePairExists, _, userLocusBasePair, err := getAnyUserProfileAttributeFunction(locusValueAttributeName)
|
userLocusBasePairExists, _, userLocusBasePair, err := getAnyUserProfileAttributeFunction(locusValueAttributeName)
|
||||||
if (err != nil) { return false, 0, "", false, "", err }
|
if (err != nil) { return nil, err }
|
||||||
if (userLocusBasePairExists == false){
|
if (userLocusBasePairExists == false){
|
||||||
return false, 0, "", false, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
userLocusRiskWeight, exists := locusRiskWeightsMap[userLocusBasePair]
|
|
||||||
if (exists == false){
|
|
||||||
// We do not know the risk weight for this base pair
|
|
||||||
// We treat this as a 0 risk weight
|
|
||||||
return true, 0, userLocusBasePair, false, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
locusOddsRatio, exists := locusOddsRatiosMap[userLocusBasePair]
|
|
||||||
if (exists == false){
|
|
||||||
return true, userLocusRiskWeight, userLocusBasePair, false, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
locusOddsRatioString := helpers.ConvertFloat64ToStringRounded(locusOddsRatio, 2)
|
|
||||||
|
|
||||||
locusOddsRatioFormatted := locusOddsRatioString + "x"
|
|
||||||
|
|
||||||
return true, userLocusRiskWeight, userLocusBasePair, true, locusOddsRatioFormatted, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//Outputs:
|
|
||||||
// -bool: My locus Info is known
|
|
||||||
// -string: My locus base 1
|
|
||||||
// -string: My locus base 2
|
|
||||||
// -error
|
|
||||||
getMyLocusInfo := func(locusIdentifierHex string)(bool, string, string, error){
|
|
||||||
if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){
|
|
||||||
return false, "", "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
|
|
||||||
if (err != nil) { return false, "", "", err }
|
|
||||||
|
|
||||||
locusInfoKnown, _, locusBase1, locusBase2, _, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(myAnalysisObject, diseaseName, locusIdentifier, myGenomeIdentifier)
|
|
||||||
if (err != nil){ return false, "", "", err }
|
|
||||||
if (locusInfoKnown == false){
|
|
||||||
return false, "", "", nil
|
|
||||||
}
|
|
||||||
return true, locusBase1, locusBase2, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
getNumberOfLociTested := func()(int, error){
|
|
||||||
|
|
||||||
if (userOrOffspring == "Offspring"){
|
|
||||||
if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
numberOfLociTested := 0
|
|
||||||
|
|
||||||
for _, locusObject := range diseaseLocusObjectsList{
|
|
||||||
|
|
||||||
locusIdentifier := locusObject.LocusIdentifier
|
|
||||||
locusRSID := locusObject.LocusRSID
|
|
||||||
locusRiskWeightsMap := locusObject.RiskWeightsMap
|
|
||||||
locusOddsRatiosMap := locusObject.OddsRatiosMap
|
|
||||||
|
|
||||||
userLocusInfoIsKnown, _, _, _, _, err := getUserLocusInfo(locusRSID, locusRiskWeightsMap, locusOddsRatiosMap)
|
|
||||||
if (err != nil) { return 0, err }
|
|
||||||
if (userLocusInfoIsKnown == false){
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userOrOffspring == "Offspring") {
|
userLocusBase1, userLocusBase2, semicolonFound := strings.Cut(userLocusBasePair, ";")
|
||||||
|
if (semicolonFound == false){
|
||||||
myLocusInfoKnown, _, _, err := getMyLocusInfo(locusIdentifier)
|
return nil, errors.New("Database corrupt: Contains profile with invalid " + locusValueAttributeName + " value: " + userLocusBasePair)
|
||||||
if (err != nil) { return 0, err }
|
|
||||||
if (myLocusInfoKnown == false){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfLociTested += 1
|
userLocusValue := locusValue.LocusValue{
|
||||||
|
Base1Value: userLocusBase1,
|
||||||
|
Base2Value: userLocusBase2,
|
||||||
|
//TODO: Share LocusIsPhased information in user profiles and retrieve it into this value
|
||||||
|
LocusIsPhased: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
return numberOfLociTested, nil
|
userDiseaseLocusValuesMap[locusRSID] = userLocusValue
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfLociTested, err := getNumberOfLociTested()
|
return userDiseaseLocusValuesMap, nil
|
||||||
if (err != nil){
|
}
|
||||||
|
|
||||||
|
userDiseaseLocusValuesMap, err := getUserLocusValuesMap()
|
||||||
|
if (err != nil) {
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
anyUserLociTested, _, userNumberOfLociTested, userDiseaseLocusInfoMap, err := createGeneticAnalysis.GetPersonGenomePolygenicDiseaseInfo(diseaseLocusObjectsList, userDiseaseLocusValuesMap, true)
|
||||||
|
if (err != nil) {
|
||||||
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
anyOffspringLociTested, _, offspringNumberOfLociTested, offspringLociInfoMap, _, err := createGeneticAnalysis.GetOffspringPolygenicDiseaseInfo(diseaseLocusObjectsList, myDiseaseLocusValuesMap, userDiseaseLocusValuesMap)
|
||||||
|
if (err != nil) {
|
||||||
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
getNumberOfLociTested := func()int{
|
||||||
|
|
||||||
|
if (userOrOffspring == "Offspring"){
|
||||||
|
|
||||||
|
if (anyOffspringLociTested == false){
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return offspringNumberOfLociTested
|
||||||
|
}
|
||||||
|
|
||||||
|
return userNumberOfLociTested
|
||||||
|
}
|
||||||
|
|
||||||
|
numberOfLociTested := getNumberOfLociTested()
|
||||||
|
|
||||||
numberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested)
|
numberOfLociTestedString := helpers.ConvertIntToString(numberOfLociTested)
|
||||||
totalNumberOfDiseaseLociString := helpers.ConvertIntToString(numberOfDiseaseLoci)
|
totalNumberOfDiseaseLociString := helpers.ConvertIntToString(numberOfDiseaseLoci)
|
||||||
lociTestedString := numberOfLociTestedString + "/" + totalNumberOfDiseaseLociString
|
lociTestedString := numberOfLociTestedString + "/" + totalNumberOfDiseaseLociString
|
||||||
|
@ -3299,19 +3270,50 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
||||||
|
|
||||||
for _, locusObject := range diseaseLocusObjectsList{
|
for _, locusObject := range diseaseLocusObjectsList{
|
||||||
|
|
||||||
locusIdentifier := locusObject.LocusIdentifier
|
locusIdentifierHex := locusObject.LocusIdentifier
|
||||||
|
|
||||||
|
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
|
||||||
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
locusRSID := locusObject.LocusRSID
|
locusRSID := locusObject.LocusRSID
|
||||||
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
||||||
locusName := "rs" + locusRSIDString
|
locusName := "rs" + locusRSIDString
|
||||||
|
|
||||||
locusRiskWeightsMap := locusObject.RiskWeightsMap
|
//Outputs:
|
||||||
locusOddsRatiosMap := locusObject.OddsRatiosMap
|
// -bool: User locus Info is known
|
||||||
|
// -int: User locus Risk weight
|
||||||
|
// -bool: User locus odds ratio known
|
||||||
|
// -string: User locus odds ratio formatted
|
||||||
|
// -error
|
||||||
|
getUserLocusInfo := func()(bool, int, bool, string, error){
|
||||||
|
|
||||||
userLocusInfoIsKnown, userLocusRiskWeight, userLocusBasePair, userLocusOddsRatioKnown, userLocusOddsRatioFormatted, err := getUserLocusInfo(locusRSID, locusRiskWeightsMap, locusOddsRatiosMap)
|
if (anyUserLociTested == false){
|
||||||
if (err != nil) { return nil, err }
|
return false, 0, false, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
myLocusInfoIsKnown, myLocusBase1, myLocusBase2, err := getMyLocusInfo(locusIdentifier)
|
locusInfoObject, exists := userDiseaseLocusInfoMap[locusIdentifier]
|
||||||
|
if (exists == false){
|
||||||
|
return false, 0, false, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userLocusRiskWeight := locusInfoObject.RiskWeight
|
||||||
|
|
||||||
|
oddsRatioIsKnown := locusInfoObject.OddsRatioIsKnown
|
||||||
|
|
||||||
|
if (oddsRatioIsKnown == false){
|
||||||
|
return true, userLocusRiskWeight, false, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userLocusOddsRatio := locusInfoObject.OddsRatio
|
||||||
|
|
||||||
|
locusOddsRatioString := helpers.ConvertFloat64ToStringRounded(userLocusOddsRatio, 2)
|
||||||
|
|
||||||
|
locusOddsRatioFormatted := locusOddsRatioString + "x"
|
||||||
|
|
||||||
|
return true, userLocusRiskWeight, true, locusOddsRatioFormatted, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userLocusInfoIsKnown, userLocusRiskWeight, userLocusOddsRatioIsKnown, userLocusOddsRatioFormatted, err := getUserLocusInfo()
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
getUserRiskWeightString := func()string{
|
getUserRiskWeightString := func()string{
|
||||||
|
@ -3328,7 +3330,7 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
||||||
userRiskWeightString := getUserRiskWeightString()
|
userRiskWeightString := getUserRiskWeightString()
|
||||||
|
|
||||||
getUserOddsRatioString := func()string{
|
getUserOddsRatioString := func()string{
|
||||||
if (userLocusOddsRatioKnown == false){
|
if (userLocusOddsRatioIsKnown == false){
|
||||||
result := translate("Unknown")
|
result := translate("Unknown")
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -3345,22 +3347,25 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
||||||
// -error
|
// -error
|
||||||
getOffspringDiseaseLocusInfo := func()(bool, int, bool, string, error){
|
getOffspringDiseaseLocusInfo := func()(bool, int, bool, string, error){
|
||||||
|
|
||||||
if (userLocusInfoIsKnown == false || myLocusInfoIsKnown == false){
|
if (anyOffspringLociTested == false){
|
||||||
return false, 0, false, "", nil
|
return false, 0, false, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
userLocusBase1, userLocusBase2, semicolonExists := strings.Cut(userLocusBasePair, ";")
|
offspringLocusInfoObject, exists := offspringLociInfoMap[locusIdentifier]
|
||||||
if (semicolonExists == false){
|
if (exists == false){
|
||||||
return false, 0, false, "", errors.New("Database corrupt: Contains profile with invalid " + locusName + " value: " + userLocusBasePair)
|
return false, 0, false, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
offspringLocusRiskWeight, offspringOddsRatioIsKnown, offspringOddsRatio, unknownOddsRatiosWeightSum, err := createGeneticAnalysis.GetOffspringPolygenicDiseaseLocusInfo(locusRiskWeightsMap, locusOddsRatiosMap, myLocusBase1, myLocusBase2, userLocusBase1, userLocusBase2)
|
offspringLocusRiskWeight := offspringLocusInfoObject.OffspringAverageRiskWeight
|
||||||
if (err != nil) { return false, 0, false, "", err }
|
offspringOddsRatioIsKnown := offspringLocusInfoObject.OffspringOddsRatioIsKnown
|
||||||
|
|
||||||
if (offspringOddsRatioIsKnown == false){
|
if (offspringOddsRatioIsKnown == false){
|
||||||
return true, offspringLocusRiskWeight, false, "", nil
|
return true, offspringLocusRiskWeight, false, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offspringOddsRatio := offspringLocusInfoObject.OffspringAverageOddsRatio
|
||||||
|
unknownOddsRatiosWeightSum := offspringLocusInfoObject.OffspringAverageUnknownOddsRatiosWeightSum
|
||||||
|
|
||||||
getOddsRatioFormatted := func()string{
|
getOddsRatioFormatted := func()string{
|
||||||
|
|
||||||
offspringOddsRatioString := helpers.ConvertFloat64ToStringRounded(offspringOddsRatio, 2)
|
offspringOddsRatioString := helpers.ConvertFloat64ToStringRounded(offspringOddsRatio, 2)
|
||||||
|
@ -3414,7 +3419,7 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
||||||
userOddsRatioLabel := getBoldLabelCentered(userOddsRatioString)
|
userOddsRatioLabel := getBoldLabelCentered(userOddsRatioString)
|
||||||
offspringOddsRatioLabel := getBoldLabelCentered(offspringOddsRatioString)
|
offspringOddsRatioLabel := getBoldLabelCentered(offspringOddsRatioString)
|
||||||
locusInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
locusInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
||||||
setViewPolygenicDiseaseLocusDetailsPage(window, diseaseName, locusIdentifier, currentPage)
|
setViewPolygenicDiseaseLocusDetailsPage(window, diseaseName, locusIdentifierHex, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
locusNameColumn.Add(locusNameLabel)
|
locusNameColumn.Add(locusNameLabel)
|
||||||
|
@ -3460,7 +3465,7 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), diseaseNameRow, lociTestedRow, widget.NewSeparator(), diseaseLociGrid)
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), diseaseNameRow, widget.NewSeparator(), lociTestedRow, widget.NewSeparator(), diseaseLociGrid)
|
||||||
|
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
@ -3554,6 +3559,39 @@ func setViewMateProfilePage_GeneticTraits(window fyne.Window, userOrOffspring st
|
||||||
|
|
||||||
viewTraitDetailsButtonsColumn.Add(viewTraitDetailsButton)
|
viewTraitDetailsButtonsColumn.Add(viewTraitDetailsButton)
|
||||||
|
|
||||||
|
// We construct the user's trait locus values map
|
||||||
|
// Map Structure: Locus rsID -> locusValue.LocusValue
|
||||||
|
userTraitLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
|
||||||
|
traitLociList := traitObject.LociList
|
||||||
|
|
||||||
|
for _, rsID := range traitLociList{
|
||||||
|
|
||||||
|
rsIDString := helpers.ConvertInt64ToString(rsID)
|
||||||
|
|
||||||
|
userLocusValueAttributeName := "LocusValue_rs" + rsIDString
|
||||||
|
|
||||||
|
userLocusBasePairIsKnown, _, userLocusBasePair, err := getAnyUserProfileAttributeFunction(userLocusValueAttributeName)
|
||||||
|
if (err != nil) { return nil, err }
|
||||||
|
if (userLocusBasePairIsKnown == false){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
userLocusBase1, userLocusBase2, semicolonFound := strings.Cut(userLocusBasePair, ";")
|
||||||
|
if (semicolonFound == false){
|
||||||
|
return nil, errors.New("Database corrupt: Contains profile with invalid " + userLocusValueAttributeName + " value: " + userLocusBasePair)
|
||||||
|
}
|
||||||
|
|
||||||
|
userLocusValue := locusValue.LocusValue{
|
||||||
|
Base1Value: userLocusBase1,
|
||||||
|
Base2Value: userLocusBase2,
|
||||||
|
//TODO: Share LocusIsPhased information in user profiles and retrieve it into this value
|
||||||
|
LocusIsPhased: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
userTraitLocusValuesMap[rsID] = userLocusValue
|
||||||
|
}
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: At least 1 rule is known
|
// -bool: At least 1 rule is known
|
||||||
// -map[string]int: Outcome name -> Outcome score
|
// -map[string]int: Outcome name -> Outcome score
|
||||||
|
@ -3566,49 +3604,9 @@ func setViewMateProfilePage_GeneticTraits(window fyne.Window, userOrOffspring st
|
||||||
|
|
||||||
for _, traitRuleObject := range traitRulesList{
|
for _, traitRuleObject := range traitRulesList{
|
||||||
|
|
||||||
// Outputs:
|
|
||||||
// -bool: Status is known
|
|
||||||
// -bool: User passes rule
|
|
||||||
// -error
|
|
||||||
getUserPassesRuleStatus := func()(bool, bool, error){
|
|
||||||
|
|
||||||
ruleLociList := traitRuleObject.LociList
|
ruleLociList := traitRuleObject.LociList
|
||||||
allRuleLociKnown := true
|
|
||||||
|
|
||||||
for _, ruleLocusObject := range ruleLociList{
|
userRuleStatusIsKnown, userPassesRule, err := createGeneticAnalysis.GetGenomePassesTraitRuleStatus(ruleLociList, userTraitLocusValuesMap, true)
|
||||||
|
|
||||||
locusRSID := ruleLocusObject.LocusRSID
|
|
||||||
|
|
||||||
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
|
||||||
|
|
||||||
userLocusValueAttributeName := "LocusValue_rs" + locusRSIDString
|
|
||||||
|
|
||||||
userLocusBasePairIsKnown, _, userLocusBasePair, err := getAnyUserProfileAttributeFunction(userLocusValueAttributeName)
|
|
||||||
if (err != nil) { return false, false, err }
|
|
||||||
if (userLocusBasePairIsKnown == false){
|
|
||||||
// We know rule is not passed
|
|
||||||
// We keep searching to see if ruleIsPassed status is No or Unknown
|
|
||||||
allRuleLociKnown = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ruleLocusBasePairsList := ruleLocusObject.BasePairsList
|
|
||||||
|
|
||||||
userPassesRuleLocus := slices.Contains(ruleLocusBasePairsList, userLocusBasePair)
|
|
||||||
if (userPassesRuleLocus == false){
|
|
||||||
// We know the rule is not passed
|
|
||||||
return true, false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (allRuleLociKnown == false){
|
|
||||||
// Rule status is unknown. Any loci which we knew must have passed.
|
|
||||||
return false, false, nil
|
|
||||||
}
|
|
||||||
// Rule is passed
|
|
||||||
return true, true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
userRuleStatusIsKnown, userPassesRule, err := getUserPassesRuleStatus()
|
|
||||||
if (err != nil) { return false, nil, 0, err }
|
if (err != nil) { return false, nil, 0, err }
|
||||||
if (userRuleStatusIsKnown == false){
|
if (userRuleStatusIsKnown == false){
|
||||||
continue
|
continue
|
||||||
|
@ -3660,39 +3658,6 @@ func setViewMateProfilePage_GeneticTraits(window fyne.Window, userOrOffspring st
|
||||||
myTraitLocusValuesMap, _, _, _, _, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(myAnalysisObject, traitName, myGenomeIdentifier)
|
myTraitLocusValuesMap, _, _, _, _, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(myAnalysisObject, traitName, myGenomeIdentifier)
|
||||||
if (err != nil) { return false, nil, 0, err }
|
if (err != nil) { return false, nil, 0, err }
|
||||||
|
|
||||||
// We construct the user's trait locus values map
|
|
||||||
// Map Structure: Locus rsID -> locusValue.LocusValue
|
|
||||||
userTraitLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
|
||||||
|
|
||||||
traitLociList := traitObject.LociList
|
|
||||||
|
|
||||||
for _, rsID := range traitLociList{
|
|
||||||
|
|
||||||
rsIDString := helpers.ConvertInt64ToString(rsID)
|
|
||||||
|
|
||||||
userLocusValueAttributeName := "LocusValue_rs" + rsIDString
|
|
||||||
|
|
||||||
userLocusBasePairIsKnown, _, userLocusBasePair, err := getAnyUserProfileAttributeFunction(userLocusValueAttributeName)
|
|
||||||
if (err != nil) { return false, nil, 0, err }
|
|
||||||
if (userLocusBasePairIsKnown == false){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
userLocusBase1, userLocusBase2, semicolonFound := strings.Cut(userLocusBasePair, ";")
|
|
||||||
if (semicolonFound == false){
|
|
||||||
return false, nil, 0, errors.New("Database corrupt: Contains profile with invalid " + userLocusValueAttributeName + " value: " + userLocusBasePair)
|
|
||||||
}
|
|
||||||
|
|
||||||
userLocusValue := locusValue.LocusValue{
|
|
||||||
Base1Value: userLocusBase1,
|
|
||||||
Base2Value: userLocusBase2,
|
|
||||||
//TODO: Share LocusIsPhased information in user profiles and retrieve it into this value
|
|
||||||
LocusIsPhased: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
userTraitLocusValuesMap[rsID] = userLocusValue
|
|
||||||
}
|
|
||||||
|
|
||||||
anyRuleTested, offspringNumberOfRulesTested, _, offspringAverageOutcomeScoresMap, err := createGeneticAnalysis.GetOffspringTraitInfo(traitObject, myTraitLocusValuesMap, userTraitLocusValuesMap)
|
anyRuleTested, offspringNumberOfRulesTested, _, offspringAverageOutcomeScoresMap, err := createGeneticAnalysis.GetOffspringTraitInfo(traitObject, myTraitLocusValuesMap, userTraitLocusValuesMap)
|
||||||
if (err != nil) { return false, nil, 0, err }
|
if (err != nil) { return false, nil, 0, err }
|
||||||
if (anyRuleTested == false){
|
if (anyRuleTested == false){
|
||||||
|
@ -3944,50 +3909,6 @@ func setViewMateProfilePage_TraitRules(window fyne.Window, traitName string, use
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//Outputs:
|
|
||||||
// -bool: Status is known
|
|
||||||
// -bool: User passes rule
|
|
||||||
// -error
|
|
||||||
getUserPassesRuleBool := func(ruleLociList []traits.RuleLocus)(bool, bool, error){
|
|
||||||
|
|
||||||
if (anyUserTraitLocusValueExists == false){
|
|
||||||
return false, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
allRuleLociKnown := true
|
|
||||||
|
|
||||||
for _, ruleLocusObject := range ruleLociList{
|
|
||||||
|
|
||||||
locusRSID := ruleLocusObject.LocusRSID
|
|
||||||
|
|
||||||
userLocusValue, userLocusValueIsKnown := userTraitLocusValuesMap[locusRSID]
|
|
||||||
if (userLocusValueIsKnown == false){
|
|
||||||
// We know rule is not passed
|
|
||||||
// We keep searching to see if ruleIsPassed status is No or Unknown
|
|
||||||
allRuleLociKnown = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
userLocusBase1Value := userLocusValue.Base1Value
|
|
||||||
userLocusBase2Value := userLocusValue.Base2Value
|
|
||||||
|
|
||||||
userLocusBasePair := userLocusBase1Value + ";" + userLocusBase2Value
|
|
||||||
|
|
||||||
ruleLocusBasePairsList := ruleLocusObject.BasePairsList
|
|
||||||
|
|
||||||
userPassesRuleLocus := slices.Contains(ruleLocusBasePairsList, userLocusBasePair)
|
|
||||||
if (userPassesRuleLocus == false){
|
|
||||||
// We know the rule is not passed
|
|
||||||
return true, false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (allRuleLociKnown == false){
|
|
||||||
// We don't know if the user passes the rule. Any loci which we knew must have passed.
|
|
||||||
return false, false, nil
|
|
||||||
}
|
|
||||||
return true, true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: Any offspring probability of passing rule is known
|
// -bool: Any offspring probability of passing rule is known
|
||||||
// -map[[3]byte]int: Offspring probability of passing rules map
|
// -map[[3]byte]int: Offspring probability of passing rules map
|
||||||
|
@ -4026,13 +3947,17 @@ func setViewMateProfilePage_TraitRules(window fyne.Window, traitName string, use
|
||||||
return numberOfRulesTested, nil
|
return numberOfRulesTested, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (anyUserTraitLocusValueExists == false){
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
numberOfRulesTested := 0
|
numberOfRulesTested := 0
|
||||||
|
|
||||||
for _, ruleObject := range traitRulesList{
|
for _, ruleObject := range traitRulesList{
|
||||||
|
|
||||||
ruleLociList := ruleObject.LociList
|
ruleLociList := ruleObject.LociList
|
||||||
|
|
||||||
ruleStatusIsKnown, _, err := getUserPassesRuleBool(ruleLociList)
|
ruleStatusIsKnown, _, err := createGeneticAnalysis.GetGenomePassesTraitRuleStatus(ruleLociList, userTraitLocusValuesMap, true)
|
||||||
if (err != nil) { return 0, err }
|
if (err != nil) { return 0, err }
|
||||||
if (ruleStatusIsKnown == true){
|
if (ruleStatusIsKnown == true){
|
||||||
numberOfRulesTested += 1
|
numberOfRulesTested += 1
|
||||||
|
@ -4125,7 +4050,7 @@ func setViewMateProfilePage_TraitRules(window fyne.Window, traitName string, use
|
||||||
|
|
||||||
getUserPassesRuleString := func()(string, error){
|
getUserPassesRuleString := func()(string, error){
|
||||||
|
|
||||||
userRuleStatusIsKnown, userPassesRule, err := getUserPassesRuleBool(ruleLociList)
|
userRuleStatusIsKnown, userPassesRule, err := createGeneticAnalysis.GetGenomePassesTraitRuleStatus(ruleLociList, userTraitLocusValuesMap, true)
|
||||||
if (err != nil) { return "", err }
|
if (err != nil) { return "", err }
|
||||||
|
|
||||||
if (userRuleStatusIsKnown == false){
|
if (userRuleStatusIsKnown == false){
|
||||||
|
@ -4300,7 +4225,7 @@ func setViewMateProfilePage_Diet(window fyne.Window, getAnyUserProfileAttributeF
|
||||||
|
|
||||||
getRatingLabel := func()*fyne.Container{
|
getRatingLabel := func()*fyne.Container{
|
||||||
if (ratingExists == false){
|
if (ratingExists == false){
|
||||||
result := getBoldItalicLabelCentered(translate("Unknown"))
|
result := getBoldItalicLabelCentered(translate("No Response"))
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
package createCharts
|
package createCharts
|
||||||
|
|
||||||
import "seekia/internal/profiles/userStatistics"
|
import "seekia/internal/statisticsDatum"
|
||||||
|
|
||||||
import goChart "github.com/wcharczuk/go-chart/v2"
|
import goChart "github.com/wcharczuk/go-chart/v2"
|
||||||
import "github.com/wcharczuk/go-chart/v2/drawing"
|
import "github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
|
@ -15,7 +15,7 @@ import "errors"
|
||||||
|
|
||||||
// Inputs:
|
// Inputs:
|
||||||
// -string: Chart title
|
// -string: Chart title
|
||||||
// -[]userStatistics.StatisticsItem: Statistics items list
|
// -[]statisticsDatum.StatisticsDatum: Statistics datums list
|
||||||
// -func(float64)(string, error): formatYAxisValuesFunction
|
// -func(float64)(string, error): formatYAxisValuesFunction
|
||||||
// -This will take values such as 1000000 and turn them to "1 million"
|
// -This will take values such as 1000000 and turn them to "1 million"
|
||||||
// -bool: Y-axis units exist
|
// -bool: Y-axis units exist
|
||||||
|
@ -23,38 +23,38 @@ import "errors"
|
||||||
// Outputs:
|
// Outputs:
|
||||||
// -image.Image
|
// -image.Image
|
||||||
// -error
|
// -error
|
||||||
func CreateBarChart(chartTitle string, chartStatisticsItemsList []userStatistics.StatisticsItem, formatYAxisValuesFunction func(float64)(string, error), yAxisUnitsProvided bool, yAxisUnits string)(image.Image, error){
|
func CreateBarChart(chartTitle string, chartStatisticsDatumsList []statisticsDatum.StatisticsDatum, formatYAxisValuesFunction func(float64)(string, error), yAxisUnitsProvided bool, yAxisUnits string)(image.Image, error){
|
||||||
|
|
||||||
if (len(chartStatisticsItemsList) == 0) {
|
if (len(chartStatisticsDatumsList) == 0) {
|
||||||
return nil, errors.New("CreateBarChart called with empty chartStatisticsItemsList")
|
return nil, errors.New("CreateBarChart called with empty chartStatisticsDatumsList")
|
||||||
}
|
}
|
||||||
|
|
||||||
chartItemsList := make([]goChart.Value, 0, len(chartStatisticsItemsList))
|
chartDatumsList := make([]goChart.Value, 0, len(chartStatisticsDatumsList))
|
||||||
|
|
||||||
for _, statisticsItem := range chartStatisticsItemsList{
|
for _, statisticsDatum := range chartStatisticsDatumsList{
|
||||||
|
|
||||||
itemLabel := statisticsItem.LabelFormatted
|
datumLabel := statisticsDatum.LabelFormatted
|
||||||
|
|
||||||
itemValue := statisticsItem.Value
|
datumValue := statisticsDatum.Value
|
||||||
|
|
||||||
// We make sure this function does not error
|
// We make sure this function does not error
|
||||||
_, err := formatYAxisValuesFunction(itemValue)
|
_, err := formatYAxisValuesFunction(datumValue)
|
||||||
if (err != nil){
|
if (err != nil){
|
||||||
return nil, errors.New("Invalid chartStatisticsItemsList: Item value is invalid. Reason: " + err.Error())
|
return nil, errors.New("Invalid chartStatisticsDatumsList: Datum value is invalid. Reason: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
newChartValue := goChart.Value{
|
newChartValue := goChart.Value{
|
||||||
Label: itemLabel,
|
Label: datumLabel,
|
||||||
Value: itemValue,
|
Value: datumValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
chartItemsList = append(chartItemsList, newChartValue)
|
chartDatumsList = append(chartDatumsList, newChartValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(chartItemsList) == 1){
|
if (len(chartDatumsList) == 1){
|
||||||
|
|
||||||
// This package cannot create bar charts with only 1 item
|
// This package cannot create bar charts with only 1 datum
|
||||||
// Thus, we must add an empty item
|
// Thus, we must add an empty datum
|
||||||
|
|
||||||
newChartValue := goChart.Value{
|
newChartValue := goChart.Value{
|
||||||
Style: goChart.Style{
|
Style: goChart.Style{
|
||||||
|
@ -65,7 +65,7 @@ func CreateBarChart(chartTitle string, chartStatisticsItemsList []userStatistics
|
||||||
Value: .001,
|
Value: .001,
|
||||||
}
|
}
|
||||||
|
|
||||||
chartItemsList = append(chartItemsList, newChartValue)
|
chartDatumsList = append(chartDatumsList, newChartValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
chartStyleObject := goChart.Style{
|
chartStyleObject := goChart.Style{
|
||||||
|
@ -110,7 +110,7 @@ func CreateBarChart(chartTitle string, chartStatisticsItemsList []userStatistics
|
||||||
Background: chartStyleObject,
|
Background: chartStyleObject,
|
||||||
Height: 500,
|
Height: 500,
|
||||||
BarWidth: 60,
|
BarWidth: 60,
|
||||||
Bars: chartItemsList,
|
Bars: chartDatumsList,
|
||||||
YAxis: yAxisObject,
|
YAxis: yAxisObject,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,28 +123,28 @@ func CreateBarChart(chartTitle string, chartStatisticsItemsList []userStatistics
|
||||||
return goImage, nil
|
return goImage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateDonutChart(chartTitle string, chartStatisticsItemsList []userStatistics.StatisticsItem)(image.Image, error){
|
func CreateDonutChart(chartTitle string, chartStatisticsDatumsList []statisticsDatum.StatisticsDatum)(image.Image, error){
|
||||||
|
|
||||||
if (len(chartStatisticsItemsList) == 0) {
|
if (len(chartStatisticsDatumsList) == 0) {
|
||||||
|
|
||||||
return nil, errors.New("CreateDonutChart called with empty chartStatisticsItemsList")
|
return nil, errors.New("CreateDonutChart called with empty chartStatisticsDatumsList")
|
||||||
}
|
}
|
||||||
|
|
||||||
chartItemsList := make([]goChart.Value, 0, len(chartStatisticsItemsList))
|
chartDatumsList := make([]goChart.Value, 0, len(chartStatisticsDatumsList))
|
||||||
|
|
||||||
for _, statisticsItem := range chartStatisticsItemsList{
|
for _, statisticsDatum := range chartStatisticsDatumsList{
|
||||||
|
|
||||||
itemLabel := statisticsItem.LabelFormatted
|
datumLabel := statisticsDatum.LabelFormatted
|
||||||
|
|
||||||
// Value is always a number representing the percentage of the donut
|
// Value is always a number representing the percentage of the donut
|
||||||
itemValue := statisticsItem.Value
|
datumValue := statisticsDatum.Value
|
||||||
|
|
||||||
newChartValue := goChart.Value{
|
newChartValue := goChart.Value{
|
||||||
Label: itemLabel,
|
Label: datumLabel,
|
||||||
Value: itemValue,
|
Value: datumValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
chartItemsList = append(chartItemsList, newChartValue)
|
chartDatumsList = append(chartDatumsList, newChartValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
chartStyleObject := goChart.Style{
|
chartStyleObject := goChart.Style{
|
||||||
|
@ -166,10 +166,10 @@ func CreateDonutChart(chartTitle string, chartStatisticsItemsList []userStatisti
|
||||||
TitleStyle: titleStyleObject,
|
TitleStyle: titleStyleObject,
|
||||||
Background: chartStyleObject,
|
Background: chartStyleObject,
|
||||||
Height: 500,
|
Height: 500,
|
||||||
Values: chartItemsList,
|
Values: chartDatumsList,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(chartItemsList) == 1){
|
if (len(chartDatumsList) == 1){
|
||||||
|
|
||||||
// Default is transparent, we need to add color
|
// Default is transparent, we need to add color
|
||||||
sliceStyleObject := goChart.Style{
|
sliceStyleObject := goChart.Style{
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -98,6 +98,11 @@ type PersonGenomePolygenicDiseaseInfo struct{
|
||||||
// This should be len(LociInfoList)
|
// This should be len(LociInfoList)
|
||||||
NumberOfLociTested int
|
NumberOfLociTested int
|
||||||
|
|
||||||
|
// This map contains the locus values for the genome for this trait
|
||||||
|
// If an locus's entry doesn't exist, its value is unknown
|
||||||
|
// Map Structure: Locus rsID -> Locus Value
|
||||||
|
LocusValuesMap map[int64]locusValue.LocusValue
|
||||||
|
|
||||||
// This is total risk score for this disease for the person's genome
|
// This is total risk score for this disease for the person's genome
|
||||||
// This is a number between 1-10
|
// This is a number between 1-10
|
||||||
RiskScore int
|
RiskScore int
|
||||||
|
@ -110,11 +115,6 @@ type PersonGenomePolygenicDiseaseInfo struct{
|
||||||
|
|
||||||
type PersonGenomePolygenicDiseaseLocusInfo struct{
|
type PersonGenomePolygenicDiseaseLocusInfo struct{
|
||||||
|
|
||||||
// The person's genome locus base pair value for this variant's locus
|
|
||||||
// Example: "G", "C"
|
|
||||||
LocusBase1 string
|
|
||||||
LocusBase2 string
|
|
||||||
|
|
||||||
// This is the risk weight that this person's genome has for this variant
|
// This is the risk weight that this person's genome has for this variant
|
||||||
// A higher risk weight means more risk of getting the disease
|
// A higher risk weight means more risk of getting the disease
|
||||||
RiskWeight int
|
RiskWeight int
|
||||||
|
@ -141,10 +141,10 @@ type PersonTraitInfo struct{
|
||||||
|
|
||||||
type PersonGenomeTraitInfo struct{
|
type PersonGenomeTraitInfo struct{
|
||||||
|
|
||||||
// This should be len(RulesList)
|
// This should be len(GenomePassesRulesMap)
|
||||||
NumberOfRulesTested int
|
NumberOfRulesTested int
|
||||||
|
|
||||||
// This map contains the locus values for the genome
|
// This map contains the locus values for the genome for this trait
|
||||||
// If an locus's entry doesn't exist, its value is unknown
|
// If an locus's entry doesn't exist, its value is unknown
|
||||||
// Map Structure: Locus rsID -> Locus Value
|
// Map Structure: Locus rsID -> Locus Value
|
||||||
LocusValuesMap map[int64]locusValue.LocusValue
|
LocusValuesMap map[int64]locusValue.LocusValue
|
||||||
|
@ -262,33 +262,38 @@ type OffspringGenomePairPolygenicDiseaseInfo struct{
|
||||||
// This should be len(DiseaseLociList)
|
// This should be len(DiseaseLociList)
|
||||||
NumberOfLociTested int
|
NumberOfLociTested int
|
||||||
|
|
||||||
// A number between 1-10 representing the offspring's risk
|
// A number between 1-10 representing the offspring's average risk score
|
||||||
// 1 == lowest risk, 10 == highest risk
|
// 1 == lowest risk, 10 == highest risk
|
||||||
OffspringRiskScore int
|
OffspringAverageRiskScore int
|
||||||
|
|
||||||
// A map of the offspring's locus information
|
// A map of the offspring's locus information
|
||||||
// Map Structure: Locus Identifier -> OffspringPolygenicDiseaseLocusInfo
|
// Map Structure: Locus Identifier -> OffspringPolygenicDiseaseLocusInfo
|
||||||
LociInfoMap map[[3]byte]OffspringPolygenicDiseaseLocusInfo
|
LociInfoMap map[[3]byte]OffspringPolygenicDiseaseLocusInfo
|
||||||
|
|
||||||
|
// This is a list of prospective offspring risk scores
|
||||||
|
// This is useful for plotting on a graph to understand the standard deviation of risk
|
||||||
|
SampleOffspringRiskScoresList []int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type OffspringPolygenicDiseaseLocusInfo struct{
|
type OffspringPolygenicDiseaseLocusInfo struct{
|
||||||
|
|
||||||
// This is the offspring's risk weight for this locus value
|
// This is the offspring's average risk weight for this locus value
|
||||||
// A higher weight means a higher risk of the disease
|
// A higher weight means a higher risk of the disease
|
||||||
OffspringRiskWeight int
|
OffspringAverageRiskWeight int
|
||||||
|
|
||||||
|
// This is true if any of the 100 prospective offspring had a known odds ratio for this locus
|
||||||
OffspringOddsRatioIsKnown bool
|
OffspringOddsRatioIsKnown bool
|
||||||
|
|
||||||
// This value represent's the offspring's average odds ratio for the disease locus
|
// This value represent's the offspring's average odds ratio for the disease locus
|
||||||
// A value <1 denotes a lesser risk, a value >1 denotes an increased risk
|
// A value <1 denotes a lesser risk, a value >1 denotes an increased risk
|
||||||
OffspringOddsRatio float64
|
OffspringAverageOddsRatio float64
|
||||||
|
|
||||||
// This is the sum of weights for the loci which have no odds ratios
|
// This is the average of the sum of weights for the loci which have no odds ratios for each prospective offspring
|
||||||
// We do this to understand what effect those loci are having on the odds ratio
|
// We do this to understand what effect those loci are having on the odds ratio
|
||||||
// If the sum is <0, we say the ratio is probably lower
|
// If the sum is <0, we say the ratio is probably lower
|
||||||
// If the sum is >0, we say the ratio is probably higher
|
// If the sum is >0, we say the ratio is probably higher
|
||||||
OffspringUnknownOddsRatiosWeightSum int
|
OffspringAverageUnknownOddsRatiosWeightSum int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -482,118 +482,119 @@ func GetOffspringMonogenicDiseaseVariantInfoFromGeneticAnalysis(coupleAnalysisOb
|
||||||
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: Polygenic Disease Risk Score known
|
// -bool: Polygenic Disease Risk Score known (any loci values exist)
|
||||||
// -int: Disease risk score
|
// -int: Person Disease risk score
|
||||||
// -string: Disease risk score formatted (has "/10" suffix)
|
// -string: Person Disease risk score formatted (has "/10" suffix)
|
||||||
|
// -map[int]locusValue.LocusValue: Person locus values map
|
||||||
// -int: Number of loci tested
|
// -int: Number of loci tested
|
||||||
// -bool: Conflict exists
|
// -bool: Conflict exists
|
||||||
// -error
|
// -error
|
||||||
func GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, genomeIdentifier [16]byte)(bool, int, string, int, bool, error){
|
func GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, genomeIdentifier [16]byte)(bool, int, string, map[int64]locusValue.LocusValue, int, bool, error){
|
||||||
|
|
||||||
personPolygenicDiseasesMap := personAnalysisObject.PolygenicDiseasesMap
|
personPolygenicDiseasesMap := personAnalysisObject.PolygenicDiseasesMap
|
||||||
|
|
||||||
personPolygenicDiseaseInfo, exists := personPolygenicDiseasesMap[diseaseName]
|
personPolygenicDiseaseInfo, exists := personPolygenicDiseasesMap[diseaseName]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, 0, "", 0, false, nil
|
return false, 0, "", nil, 0, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
personPolygenicDiseaseInfoMap := personPolygenicDiseaseInfo.PolygenicDiseaseInfoMap
|
personPolygenicDiseaseInfoMap := personPolygenicDiseaseInfo.PolygenicDiseaseInfoMap
|
||||||
|
|
||||||
genomePolygenicDiseaseInfo, exists := personPolygenicDiseaseInfoMap[genomeIdentifier]
|
genomePolygenicDiseaseInfo, exists := personPolygenicDiseaseInfoMap[genomeIdentifier]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, 0, "", 0, false, nil
|
return false, 0, "", nil, 0, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
conflictExists := personPolygenicDiseaseInfo.ConflictExists
|
conflictExists := personPolygenicDiseaseInfo.ConflictExists
|
||||||
|
|
||||||
personDiseaseRiskScore := genomePolygenicDiseaseInfo.RiskScore
|
personDiseaseRiskScore := genomePolygenicDiseaseInfo.RiskScore
|
||||||
|
|
||||||
numberOfLociTested := genomePolygenicDiseaseInfo.NumberOfLociTested
|
|
||||||
|
|
||||||
personDiseaseRiskScoreString := helpers.ConvertIntToString(personDiseaseRiskScore)
|
personDiseaseRiskScoreString := helpers.ConvertIntToString(personDiseaseRiskScore)
|
||||||
|
|
||||||
personDiseaseRiskScoreFormatted := personDiseaseRiskScoreString + "/10"
|
personDiseaseRiskScoreFormatted := personDiseaseRiskScoreString + "/10"
|
||||||
|
|
||||||
return true, personDiseaseRiskScore, personDiseaseRiskScoreFormatted, numberOfLociTested, conflictExists, nil
|
personLocusValuesMap := genomePolygenicDiseaseInfo.LocusValuesMap
|
||||||
|
|
||||||
|
numberOfLociTested := genomePolygenicDiseaseInfo.NumberOfLociTested
|
||||||
|
|
||||||
|
return true, personDiseaseRiskScore, personDiseaseRiskScoreFormatted, personLocusValuesMap, numberOfLociTested, conflictExists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: Offspring Disease Risk Score known
|
// -bool: Offspring Disease Risk Score known
|
||||||
// -int: Disease risk score
|
// -int: Offspring average disease risk score
|
||||||
// -string: Disease risk score formatted (has "/10" suffix)
|
// -string: Offspring Disease average risk score formatted (has "/10" suffix)
|
||||||
|
// -[]int: Sample Offspring Risk Scores List
|
||||||
// -int: Number of loci tested
|
// -int: Number of loci tested
|
||||||
// -bool: Conflict exists
|
// -bool: Conflict exists
|
||||||
// -error
|
// -error
|
||||||
func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte)(bool, int, string, int, bool, error){
|
func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte)(bool, int, string, []int, int, bool, error){
|
||||||
|
|
||||||
couplePolygenicDiseasesMap := coupleAnalysisObject.PolygenicDiseasesMap
|
couplePolygenicDiseasesMap := coupleAnalysisObject.PolygenicDiseasesMap
|
||||||
|
|
||||||
couplePolygenicDiseaseInfo, exists := couplePolygenicDiseasesMap[diseaseName]
|
couplePolygenicDiseaseInfo, exists := couplePolygenicDiseasesMap[diseaseName]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, 0, "", 0, false, nil
|
return false, 0, "", nil, 0, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
polygenicDiseaseInfoMap := couplePolygenicDiseaseInfo.PolygenicDiseaseInfoMap
|
polygenicDiseaseInfoMap := couplePolygenicDiseaseInfo.PolygenicDiseaseInfoMap
|
||||||
|
|
||||||
genomePairPolygenicDiseaseInfo, exists := polygenicDiseaseInfoMap[genomePairIdentifier]
|
genomePairPolygenicDiseaseInfo, exists := polygenicDiseaseInfoMap[genomePairIdentifier]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, 0, "", 0, false, nil
|
return false, 0, "", nil, 0, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
conflictExists := couplePolygenicDiseaseInfo.ConflictExists
|
conflictExists := couplePolygenicDiseaseInfo.ConflictExists
|
||||||
|
|
||||||
numberOfLociTested := genomePairPolygenicDiseaseInfo.NumberOfLociTested
|
numberOfLociTested := genomePairPolygenicDiseaseInfo.NumberOfLociTested
|
||||||
|
|
||||||
offspringRiskScore := genomePairPolygenicDiseaseInfo.OffspringRiskScore
|
offspringAverageRiskScore := genomePairPolygenicDiseaseInfo.OffspringAverageRiskScore
|
||||||
|
|
||||||
offspringRiskScoreString := helpers.ConvertIntToString(offspringRiskScore)
|
offspringAverageRiskScoreString := helpers.ConvertIntToString(offspringAverageRiskScore)
|
||||||
|
|
||||||
offspringRiskScoreFormatted := offspringRiskScoreString + "/10"
|
offspringAverageRiskScoreFormatted := offspringAverageRiskScoreString + "/10"
|
||||||
|
|
||||||
return true, offspringRiskScore, offspringRiskScoreFormatted, numberOfLociTested, conflictExists, nil
|
sampleOffspringRiskScoresList := genomePairPolygenicDiseaseInfo.SampleOffspringRiskScoresList
|
||||||
|
|
||||||
|
return true, offspringAverageRiskScore, offspringAverageRiskScoreFormatted, sampleOffspringRiskScoresList, numberOfLociTested, conflictExists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: Risk Weight and base pair known
|
// -bool: Risk Weight and base pair known
|
||||||
// -int: Locus risk weight
|
// -int: Locus risk weight
|
||||||
// -string: Locus base 1
|
|
||||||
// -string: Locus base 2
|
|
||||||
// -bool: Locus odds ratio known
|
// -bool: Locus odds ratio known
|
||||||
// -float64: Locus odds ratio
|
// -float64: Locus odds ratio
|
||||||
// -string: Locus odds ratio formatted (with x suffix)
|
// -string: Locus odds ratio formatted (with x suffix)
|
||||||
// -error
|
// -error
|
||||||
func GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalyisObject geneticAnalysis.PersonAnalysis, diseaseName string, locusIdentifier [3]byte, genomeIdentifier [16]byte)(bool, int, string, string, bool, float64, string, error){
|
func GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalyisObject geneticAnalysis.PersonAnalysis, diseaseName string, locusIdentifier [3]byte, genomeIdentifier [16]byte)(bool, int, bool, float64, string, error){
|
||||||
|
|
||||||
personPolygenicDiseasesMap := personAnalyisObject.PolygenicDiseasesMap
|
personPolygenicDiseasesMap := personAnalyisObject.PolygenicDiseasesMap
|
||||||
|
|
||||||
personPolygenicDiseaseMap, exists := personPolygenicDiseasesMap[diseaseName]
|
personPolygenicDiseaseMap, exists := personPolygenicDiseasesMap[diseaseName]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, 0, "", "", false, 0, "", nil
|
return false, 0, false, 0, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
personPolygenicDiseaseInfoMap := personPolygenicDiseaseMap.PolygenicDiseaseInfoMap
|
personPolygenicDiseaseInfoMap := personPolygenicDiseaseMap.PolygenicDiseaseInfoMap
|
||||||
|
|
||||||
personGenomePolygenicDiseaseInfo, exists := personPolygenicDiseaseInfoMap[genomeIdentifier]
|
personGenomePolygenicDiseaseInfo, exists := personPolygenicDiseaseInfoMap[genomeIdentifier]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, 0, "", "", false, 0, "", nil
|
return false, 0, false, 0, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
genomeLociInfoMap := personGenomePolygenicDiseaseInfo.LociInfoMap
|
genomeLociInfoMap := personGenomePolygenicDiseaseInfo.LociInfoMap
|
||||||
|
|
||||||
locusInfoObject, exists := genomeLociInfoMap[locusIdentifier]
|
locusInfoObject, exists := genomeLociInfoMap[locusIdentifier]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, 0, "", "", false, 0, "", nil
|
return false, 0, false, 0, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
locusRiskWeight := locusInfoObject.RiskWeight
|
locusRiskWeight := locusInfoObject.RiskWeight
|
||||||
|
|
||||||
locusBase1 := locusInfoObject.LocusBase1
|
|
||||||
locusBase2 := locusInfoObject.LocusBase2
|
|
||||||
|
|
||||||
locusOddsRatioIsKnown := locusInfoObject.OddsRatioIsKnown
|
locusOddsRatioIsKnown := locusInfoObject.OddsRatioIsKnown
|
||||||
if (locusOddsRatioIsKnown == false){
|
if (locusOddsRatioIsKnown == false){
|
||||||
return true, locusRiskWeight, locusBase1, locusBase2, false, 0, "", nil
|
return true, locusRiskWeight, false, 0, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
locusOddsRatio := locusInfoObject.OddsRatio
|
locusOddsRatio := locusInfoObject.OddsRatio
|
||||||
|
@ -602,7 +603,7 @@ func GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalyisObject g
|
||||||
|
|
||||||
locusOddsRatioFormatted := genomeLocusOddsRatioString + "x"
|
locusOddsRatioFormatted := genomeLocusOddsRatioString + "x"
|
||||||
|
|
||||||
return true, locusRiskWeight, locusBase1, locusBase2, true, locusOddsRatio, locusOddsRatioFormatted, nil
|
return true, locusRiskWeight, true, locusOddsRatio, locusOddsRatioFormatted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
|
@ -635,40 +636,40 @@ func GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisObje
|
||||||
return false, 0, false, 0, "", nil
|
return false, 0, false, 0, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
offspringRiskWeight := locusInfoObject.OffspringRiskWeight
|
offspringAverageRiskWeight := locusInfoObject.OffspringAverageRiskWeight
|
||||||
offspringOddsRatioIsKnown := locusInfoObject.OffspringOddsRatioIsKnown
|
offspringOddsRatioIsKnown := locusInfoObject.OffspringOddsRatioIsKnown
|
||||||
|
|
||||||
if (offspringOddsRatioIsKnown == false){
|
if (offspringOddsRatioIsKnown == false){
|
||||||
return true, offspringRiskWeight, false, 0, "", nil
|
return true, offspringAverageRiskWeight, false, 0, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
offspringOddsRatio := locusInfoObject.OffspringOddsRatio
|
offspringAverageOddsRatio := locusInfoObject.OffspringAverageOddsRatio
|
||||||
|
|
||||||
getOddsRatioFormatted := func()string{
|
getOddsRatioFormatted := func()string{
|
||||||
|
|
||||||
offspringUnknownOddsRatiosWeightSum := locusInfoObject.OffspringUnknownOddsRatiosWeightSum
|
offspringAverageUnknownOddsRatiosWeightSum := locusInfoObject.OffspringAverageUnknownOddsRatiosWeightSum
|
||||||
|
|
||||||
offspringOddsRatioString := helpers.ConvertFloat64ToStringRounded(offspringOddsRatio, 2)
|
offspringAverageOddsRatioString := helpers.ConvertFloat64ToStringRounded(offspringAverageOddsRatio, 2)
|
||||||
|
|
||||||
if (offspringUnknownOddsRatiosWeightSum == 0){
|
if (offspringAverageUnknownOddsRatiosWeightSum == 0){
|
||||||
result := offspringOddsRatioString + "x"
|
result := offspringAverageOddsRatioString + "x"
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
if (offspringUnknownOddsRatiosWeightSum < 0){
|
if (offspringAverageUnknownOddsRatiosWeightSum < 0){
|
||||||
result := "<" + offspringOddsRatioString + "x"
|
result := "<" + offspringAverageOddsRatioString + "x"
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
// offspringUnknownOddsRatiosWeightSum > 0
|
// offspringAverageUnknownOddsRatiosWeightSum > 0
|
||||||
result := offspringOddsRatioString + "x+"
|
result := offspringAverageOddsRatioString + "x+"
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
oddsRatioFormatted := getOddsRatioFormatted()
|
oddsRatioFormatted := getOddsRatioFormatted()
|
||||||
|
|
||||||
return true, offspringRiskWeight, true, offspringOddsRatio, oddsRatioFormatted, nil
|
return true, offspringAverageRiskWeight, true, offspringAverageOddsRatio, oddsRatioFormatted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
|
@ -858,7 +859,7 @@ func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnal
|
||||||
|
|
||||||
for _, genomeIdentifier := range allGenomeIdentifiersList{
|
for _, genomeIdentifier := range allGenomeIdentifiersList{
|
||||||
|
|
||||||
_, _, _, _, _, err := GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, genomeIdentifier)
|
_, _, _, _, _, _, err := GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, genomeIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,7 +874,7 @@ func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnal
|
||||||
|
|
||||||
for _, genomeIdentifier := range allGenomeIdentifiersList{
|
for _, genomeIdentifier := range allGenomeIdentifiersList{
|
||||||
|
|
||||||
_, _, _, _, _, _, _, err := GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier)
|
_, _, _, _, _, err := GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, locusIdentifier, genomeIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -970,7 +971,7 @@ func VerifyCoupleGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnal
|
||||||
|
|
||||||
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
|
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
|
||||||
|
|
||||||
_, _, _, _, _, err := GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier)
|
_, _, _, _, _, _, err := GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject, diseaseName, genomePairIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -19,6 +19,7 @@ import "seekia/internal/desires/myMateDesires"
|
||||||
import "seekia/internal/encoding"
|
import "seekia/internal/encoding"
|
||||||
import "seekia/internal/genetics/companyAnalysis"
|
import "seekia/internal/genetics/companyAnalysis"
|
||||||
import "seekia/internal/genetics/createGeneticAnalysis"
|
import "seekia/internal/genetics/createGeneticAnalysis"
|
||||||
|
import "seekia/internal/genetics/locusValue"
|
||||||
import "seekia/internal/genetics/myChosenAnalysis"
|
import "seekia/internal/genetics/myChosenAnalysis"
|
||||||
import "seekia/internal/genetics/readGeneticAnalysis"
|
import "seekia/internal/genetics/readGeneticAnalysis"
|
||||||
import "seekia/internal/helpers"
|
import "seekia/internal/helpers"
|
||||||
|
@ -677,12 +678,10 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
||||||
|
|
||||||
for _, diseaseObject := range polygenicDiseaseObjectsList{
|
for _, diseaseObject := range polygenicDiseaseObjectsList{
|
||||||
|
|
||||||
diseaseLociList := diseaseObject.LociList
|
// Map Structure: Locus rsID -> Locus Value
|
||||||
|
userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
|
||||||
userRiskWeightSum := 0
|
diseaseLociList := diseaseObject.LociList
|
||||||
userMinimumPossibleRiskWeightSum := 0
|
|
||||||
userMaximumPossibleRiskWeightSum := 0
|
|
||||||
userNumberOfLociTested := 0
|
|
||||||
|
|
||||||
for _, locusObject := range diseaseLociList{
|
for _, locusObject := range diseaseLociList{
|
||||||
|
|
||||||
|
@ -690,10 +689,6 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
||||||
|
|
||||||
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
||||||
|
|
||||||
locusRiskWeightsMap := locusObject.RiskWeightsMap
|
|
||||||
locusMinimumRiskWeight := locusObject.MinimumRiskWeight
|
|
||||||
locusMaximumRiskWeight := locusObject.MaximumRiskWeight
|
|
||||||
|
|
||||||
locusValueAttributeName := "LocusValue_rs" + locusRSIDString
|
locusValueAttributeName := "LocusValue_rs" + locusRSIDString
|
||||||
|
|
||||||
userLocusBasePairExists, _, userLocusBasePair, err := getProfileAttributesFunction(locusValueAttributeName)
|
userLocusBasePairExists, _, userLocusBasePair, err := getProfileAttributesFunction(locusValueAttributeName)
|
||||||
|
@ -702,30 +697,30 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
userNumberOfLociTested += 1
|
userLocusBase1, userLocusBase2, semicolonFound := strings.Cut(userLocusBasePair, ";")
|
||||||
|
if (semicolonFound == false){
|
||||||
userMinimumPossibleRiskWeightSum += locusMinimumRiskWeight
|
return false, 0, "", errors.New("Database corrupt: Contains profile with invalid " + locusValueAttributeName + " value: " + userLocusBasePair)
|
||||||
userMaximumPossibleRiskWeightSum += locusMaximumRiskWeight
|
|
||||||
|
|
||||||
userLocusRiskWeight, exists := locusRiskWeightsMap[userLocusBasePair]
|
|
||||||
if (exists == false){
|
|
||||||
// We do not know the risk weight for this base pair
|
|
||||||
// We treat this as a 0 risk weight
|
|
||||||
} else {
|
|
||||||
userRiskWeightSum += userLocusRiskWeight
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userNumberOfLociTested == 0){
|
userLocusValue := locusValue.LocusValue{
|
||||||
|
Base1Value: userLocusBase1,
|
||||||
|
Base2Value: userLocusBase2,
|
||||||
|
//TODO: Share LocusIsPhased information in user profiles and retrieve it into this value
|
||||||
|
LocusIsPhased: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
userDiseaseLocusValuesMap[locusRSID] = userLocusValue
|
||||||
|
}
|
||||||
|
|
||||||
|
anyLocusTested, userDiseaseRiskScore, _, _, err := createGeneticAnalysis.GetPersonGenomePolygenicDiseaseInfo(diseaseLociList, userDiseaseLocusValuesMap, true)
|
||||||
|
if (err != nil) { return false, 0, "", err }
|
||||||
|
if (anyLocusTested == false){
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfDiseasesTested += 1
|
numberOfDiseasesTested += 1
|
||||||
|
|
||||||
userDiseaseRiskScore, err := helpers.ScaleNumberProportionally(true, userRiskWeightSum, userMinimumPossibleRiskWeightSum, userMaximumPossibleRiskWeightSum, 0, 100)
|
userRiskScoreFraction := float64(userDiseaseRiskScore)/float64(10)
|
||||||
if (err != nil) { return false, 0, "", err }
|
|
||||||
|
|
||||||
userRiskScoreFraction := float64(userDiseaseRiskScore)/float64(100)
|
|
||||||
|
|
||||||
allDiseasesAverageRiskScoreNumerator += userRiskScoreFraction
|
allDiseasesAverageRiskScoreNumerator += userRiskScoreFraction
|
||||||
}
|
}
|
||||||
|
@ -787,35 +782,20 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
||||||
diseaseName := diseaseObject.DiseaseName
|
diseaseName := diseaseObject.DiseaseName
|
||||||
diseaseLociList := diseaseObject.LociList
|
diseaseLociList := diseaseObject.LociList
|
||||||
|
|
||||||
offspringRiskWeightSum := 0
|
_, _, _, myDiseaseLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myGeneticAnalysisObject, diseaseName, myGenomeIdentifier)
|
||||||
offspringMinimumPossibleRiskWeightSum := 0
|
if (err != nil) { return false, 0, "", err }
|
||||||
offspringMaximumPossibleRiskWeightSum := 0
|
|
||||||
offspringNumberOfLociTested := 0
|
// Map Structure: rsID -> Locus Value
|
||||||
|
userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
|
||||||
for _, locusObject := range diseaseLociList{
|
for _, locusObject := range diseaseLociList{
|
||||||
|
|
||||||
locusIdentifierHex := locusObject.LocusIdentifier
|
|
||||||
|
|
||||||
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
|
|
||||||
if (err != nil) { return false, 0, "", err }
|
|
||||||
|
|
||||||
locusRSID := locusObject.LocusRSID
|
locusRSID := locusObject.LocusRSID
|
||||||
|
|
||||||
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
||||||
|
|
||||||
locusRiskWeightsMap := locusObject.RiskWeightsMap
|
|
||||||
locusOddsRatiosMap := locusObject.OddsRatiosMap
|
|
||||||
locusMinimumRiskWeight := locusObject.MinimumRiskWeight
|
|
||||||
locusMaximumRiskWeight := locusObject.MaximumRiskWeight
|
|
||||||
|
|
||||||
locusValueAttributeName := "LocusValue_rs" + locusRSIDString
|
locusValueAttributeName := "LocusValue_rs" + locusRSIDString
|
||||||
|
|
||||||
myLocusInfoIsKnown, _, myLocusBase1, myLocusBase2, _, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(myGeneticAnalysisObject, diseaseName, locusIdentifier, myGenomeIdentifier)
|
|
||||||
if (err != nil) { return false, 0, "", err }
|
|
||||||
if (myLocusInfoIsKnown == false){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
userLocusBasePairExists, _, userLocusBasePair, err := getProfileAttributesFunction(locusValueAttributeName)
|
userLocusBasePairExists, _, userLocusBasePair, err := getProfileAttributesFunction(locusValueAttributeName)
|
||||||
if (err != nil) { return false, 0, "", err }
|
if (err != nil) { return false, 0, "", err }
|
||||||
if (userLocusBasePairExists == false){
|
if (userLocusBasePairExists == false){
|
||||||
|
@ -827,27 +807,25 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
||||||
return false, 0, "", errors.New("GetAnyProfileAttributeIncludingCalculated called with profile containing invalid " + locusValueAttributeName + ": " + userLocusBasePair)
|
return false, 0, "", errors.New("GetAnyProfileAttributeIncludingCalculated called with profile containing invalid " + locusValueAttributeName + ": " + userLocusBasePair)
|
||||||
}
|
}
|
||||||
|
|
||||||
offspringLocusRiskWeight, _, _, _, err := createGeneticAnalysis.GetOffspringPolygenicDiseaseLocusInfo(locusRiskWeightsMap, locusOddsRatiosMap, myLocusBase1, myLocusBase2, userLocusBase1, userLocusBase2)
|
newLocusValue := locusValue.LocusValue{
|
||||||
if (err != nil) { return false, 0, "", err }
|
Base1Value: userLocusBase1,
|
||||||
|
Base2Value: userLocusBase2,
|
||||||
offspringNumberOfLociTested += 1
|
//TODO: Share locusIsPhased information in user profiles are put it here
|
||||||
|
LocusIsPhased: false,
|
||||||
offspringMinimumPossibleRiskWeightSum += locusMinimumRiskWeight
|
|
||||||
offspringMaximumPossibleRiskWeightSum += locusMaximumRiskWeight
|
|
||||||
|
|
||||||
offspringRiskWeightSum += offspringLocusRiskWeight
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offspringNumberOfLociTested == 0){
|
userDiseaseLocusValuesMap[locusRSID] = newLocusValue
|
||||||
|
}
|
||||||
|
|
||||||
|
anyLocusValuesTested, offspringAverageRiskScore, _, err := createGeneticAnalysis.GetOffspringPolygenicDiseaseInfo_Fast(diseaseLociList, myDiseaseLocusValuesMap, userDiseaseLocusValuesMap)
|
||||||
|
if (err != nil) { return false, 0, "", err }
|
||||||
|
if (anyLocusValuesTested == false){
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfDiseasesTested += 1
|
numberOfDiseasesTested += 1
|
||||||
|
|
||||||
offspringRiskScore, err := helpers.ScaleNumberProportionally(true, offspringRiskWeightSum, offspringMinimumPossibleRiskWeightSum, offspringMaximumPossibleRiskWeightSum, 0, 100)
|
offspringRiskScoreFraction := float64(offspringAverageRiskScore)/float64(10)
|
||||||
if (err != nil) { return false, 0, "", err }
|
|
||||||
|
|
||||||
offspringRiskScoreFraction := float64(offspringRiskScore)/float64(100)
|
|
||||||
|
|
||||||
allDiseasesAverageRiskScoreNumerator += offspringRiskScoreFraction
|
allDiseasesAverageRiskScoreNumerator += offspringRiskScoreFraction
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,26 +205,19 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
diseaseLociList := diseaseObject.LociList
|
_, _, _, myDiseaseLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myGeneticAnalysisObject, diseaseName, genomeIdentifierToShare)
|
||||||
|
|
||||||
for _, locusObject := range diseaseLociList{
|
|
||||||
|
|
||||||
locusIdentifierHex := locusObject.LocusIdentifier
|
|
||||||
|
|
||||||
locusIdentifier, err := encoding.DecodeHexStringTo3ByteArray(locusIdentifierHex)
|
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
locusValueKnown, _, locusBase1, locusBase2, _, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(myGeneticAnalysisObject, diseaseName, locusIdentifier, genomeIdentifierToShare)
|
for rsID, locusValueObject := range myDiseaseLocusValuesMap{
|
||||||
if (err != nil) { return err }
|
|
||||||
if (locusValueKnown == false){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
locusRSID := locusObject.LocusRSID
|
rsIDString := helpers.ConvertInt64ToString(rsID)
|
||||||
|
|
||||||
locusRSIDString := helpers.ConvertInt64ToString(locusRSID)
|
locusBase1 := locusValueObject.Base1Value
|
||||||
|
locusBase2 := locusValueObject.Base2Value
|
||||||
|
|
||||||
profileMap["LocusValue_rs" + locusRSIDString] = locusBase1 + ";" + locusBase2
|
basePairValue := locusBase1 + ";" + locusBase2
|
||||||
|
|
||||||
|
profileMap["LocusValue_rs" + rsIDString] = basePairValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import "seekia/internal/profiles/calculatedAttributes"
|
||||||
import "seekia/internal/profiles/profileStorage"
|
import "seekia/internal/profiles/profileStorage"
|
||||||
import "seekia/internal/profiles/attributeDisplay"
|
import "seekia/internal/profiles/attributeDisplay"
|
||||||
import "seekia/internal/translation"
|
import "seekia/internal/translation"
|
||||||
|
import "seekia/internal/statisticsDatum"
|
||||||
|
|
||||||
import "slices"
|
import "slices"
|
||||||
import "strings"
|
import "strings"
|
||||||
|
@ -21,61 +22,27 @@ import "errors"
|
||||||
import "math"
|
import "math"
|
||||||
|
|
||||||
|
|
||||||
type StatisticsItem struct{
|
|
||||||
|
|
||||||
// The label for the statistics item
|
|
||||||
// For a bar chart, this represents the name of an X axis bar.
|
|
||||||
// For a donut chart, this represents the name of a donut slice
|
|
||||||
// Example: "Man", "100-200"
|
|
||||||
// This will never be translated, unless it is the Unknown/No Response item, in which case
|
|
||||||
// the label will be "Unknown"/"No Response" translated to the user's current app language
|
|
||||||
Label string
|
|
||||||
|
|
||||||
// This is the formatted, human readable version of the label
|
|
||||||
// This will be translated into the application language
|
|
||||||
// Sometimes, the LabelFormatted will be identical to Label
|
|
||||||
// This does not include units (Example: " days", " users")
|
|
||||||
// Example:
|
|
||||||
// -"1000000-2000000" -> "1 million-2 million"
|
|
||||||
LabelFormatted string
|
|
||||||
|
|
||||||
// The value corresponding to the label
|
|
||||||
// For a bar chart, this represents the Y axis value for a bar.
|
|
||||||
// For a donut chart, this represents the value (size) of one of the donut slices
|
|
||||||
// This will never be translated
|
|
||||||
// For example, the value could be 500 if 500 men responded Yes.
|
|
||||||
Value float64
|
|
||||||
|
|
||||||
// This is the formatted version of the value
|
|
||||||
// This does not include units (Example: " days", " users")
|
|
||||||
// Examples:
|
|
||||||
// -5 -> "5/10"
|
|
||||||
// -1500000000000 -> "1.5 trillion"
|
|
||||||
ValueFormatted string
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -int: Number of users analyzed in statistics
|
// -int: Number of users analyzed in statistics
|
||||||
// -[]StatisticsItem: Statistics items list (sorted, not grouped)
|
// -[]statisticsDatum.StatisticsDatum: Statistics datums list (sorted, not grouped)
|
||||||
// -bool: Grouping performed
|
// -bool: Grouping performed
|
||||||
// -[]StatisticsItem: Grouped items list
|
// -[]statisticsDatum.StatisticsDatum: Grouped datums list
|
||||||
// -func(float64)(string, error): Function to format y axis values
|
// -func(float64)(string, error): Function to format y axis values
|
||||||
// -This is used because the values must be passed to the chart code as pure floats, but they must be formatted after to be human readable
|
// -This is used because the values must be passed to the chart code as pure floats, but they must be formatted after to be human readable
|
||||||
// -Example: "1000000" -> "1 million"
|
// -Example: "1000000" -> "1 million"
|
||||||
// -error
|
// -error
|
||||||
func GetUserStatisticsItemsLists_BarChart(identityType string,
|
func GetUserStatisticsDatumsLists_BarChart(identityType string,
|
||||||
networkType byte,
|
networkType byte,
|
||||||
xAxisAttribute string,
|
xAxisAttribute string,
|
||||||
xAxisIsNumerical bool,
|
xAxisIsNumerical bool,
|
||||||
formatXAxisValuesFunction func(string)(string, error),
|
formatXAxisValuesFunction func(string)(string, error),
|
||||||
xAxisUnknownLabel string,
|
xAxisUnknownLabel string,
|
||||||
yAxisAttribute string)(int, []StatisticsItem, bool, []StatisticsItem, func(float64)(string, error), error){
|
yAxisAttribute string)(int, []statisticsDatum.StatisticsDatum, bool, []statisticsDatum.StatisticsDatum, func(float64)(string, error), error){
|
||||||
|
|
||||||
isValid := helpers.VerifyNetworkType(networkType)
|
isValid := helpers.VerifyNetworkType(networkType)
|
||||||
if (isValid == false){
|
if (isValid == false){
|
||||||
networkTypeString := helpers.ConvertByteToString(networkType)
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||||||
return 0, nil, false, nil, nil, errors.New("GetUserStatisticsItemsLists_BarChart called with invalid networkType: " + networkTypeString)
|
return 0, nil, false, nil, nil, errors.New("GetUserStatisticsDatumsLists_BarChart called with invalid networkType: " + networkTypeString)
|
||||||
}
|
}
|
||||||
|
|
||||||
getYAxisRoundingPrecision := func()int{
|
getYAxisRoundingPrecision := func()int{
|
||||||
|
@ -95,16 +62,16 @@ func GetUserStatisticsItemsLists_BarChart(identityType string,
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -int: Total analyzed users
|
// -int: Total analyzed users
|
||||||
// -[]StatisticsItem: Statistics items list
|
// -[]statisticsDatum.StatisticsDatum: Statistics datums list
|
||||||
// -map[string]int: Response Counts map (X axis attribute response -> Number of y axis responses)
|
// -map[string]int: Response Counts map (X axis attribute response -> Number of y axis responses)
|
||||||
// -bool: yAxisIsAverage
|
// -bool: yAxisIsAverage
|
||||||
// -map[string]float64: Response Sums map (X axis attribute response -> all y axis responses summed) (If yAxisIsAverage == true)
|
// -map[string]float64: Response Sums map (X axis attribute response -> all y axis responses summed) (If yAxisIsAverage == true)
|
||||||
// -func(float64)(string, error): Function to format statistics values
|
// -func(float64)(string, error): Function to format statistics values
|
||||||
// -bool: Include a No Response/Unknown value item
|
// -bool: Include a No Response/Unknown value datum
|
||||||
// -This is only needed if at least 1 user did not respond to the X axis attribute on their profile.
|
// -This is only needed if at least 1 user did not respond to the X axis attribute on their profile.
|
||||||
// -StatisticsItem: The unknown value item.
|
// -statisticsDatum.StatisticsDatum: The unknown value datum.
|
||||||
// -error
|
// -error
|
||||||
getStatisticsItemsList := func()(int, []StatisticsItem, map[string]int, bool, map[string]float64, func(float64)(string, error), bool, StatisticsItem, error){
|
getStatisticsDatumsList := func()(int, []statisticsDatum.StatisticsDatum, map[string]int, bool, map[string]float64, func(float64)(string, error), bool, statisticsDatum.StatisticsDatum, error){
|
||||||
|
|
||||||
//TODO: Add "Probability Of ..."
|
//TODO: Add "Probability Of ..."
|
||||||
// This will allow viewing of choice attribute probabilities
|
// This will allow viewing of choice attribute probabilities
|
||||||
|
@ -113,8 +80,8 @@ func GetUserStatisticsItemsLists_BarChart(identityType string,
|
||||||
|
|
||||||
if (yAxisAttribute == "Number Of Users"){
|
if (yAxisAttribute == "Number Of Users"){
|
||||||
|
|
||||||
totalAnalyzedUsers, statisticsItemsList, responseCountsMap, numberOfUnknownValueUsers, err := getProfileAttributeCountStatisticsItemsList(identityType, networkType, xAxisAttribute, formatXAxisValuesFunction)
|
totalAnalyzedUsers, statisticsDatumsList, responseCountsMap, numberOfUnknownValueUsers, err := getProfileAttributeCountStatisticsDatumsList(identityType, networkType, xAxisAttribute, formatXAxisValuesFunction)
|
||||||
if (err != nil) { return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, err }
|
if (err != nil) { return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, err }
|
||||||
|
|
||||||
formatValuesFunction := func(input float64)(string, error){
|
formatValuesFunction := func(input float64)(string, error){
|
||||||
|
|
||||||
|
@ -126,23 +93,23 @@ func GetUserStatisticsItemsLists_BarChart(identityType string,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numberOfUnknownValueUsers == 0){
|
if (numberOfUnknownValueUsers == 0){
|
||||||
return totalAnalyzedUsers, statisticsItemsList, responseCountsMap, false, nil, formatValuesFunction, false, StatisticsItem{}, nil
|
return totalAnalyzedUsers, statisticsDatumsList, responseCountsMap, false, nil, formatValuesFunction, false, statisticsDatum.StatisticsDatum{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
unknownValueFormatted := helpers.ConvertIntToString(numberOfUnknownValueUsers)
|
unknownValueFormatted := helpers.ConvertIntToString(numberOfUnknownValueUsers)
|
||||||
|
|
||||||
unknownItem := StatisticsItem{
|
unknownDatum := statisticsDatum.StatisticsDatum{
|
||||||
Label: xAxisUnknownLabel,
|
Label: xAxisUnknownLabel,
|
||||||
LabelFormatted: xAxisUnknownLabel,
|
LabelFormatted: xAxisUnknownLabel,
|
||||||
Value: float64(numberOfUnknownValueUsers),
|
Value: float64(numberOfUnknownValueUsers),
|
||||||
ValueFormatted: unknownValueFormatted,
|
ValueFormatted: unknownValueFormatted,
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalAnalyzedUsers, statisticsItemsList, responseCountsMap, false, nil, formatValuesFunction, true, unknownItem, nil
|
return totalAnalyzedUsers, statisticsDatumsList, responseCountsMap, false, nil, formatValuesFunction, true, unknownDatum, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
userIdentityHashesToAnalyzeList, err := getUserIdentityHashesToAnalyzeList(identityType)
|
userIdentityHashesToAnalyzeList, err := getUserIdentityHashesToAnalyzeList(identityType)
|
||||||
if (err != nil) { return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, err }
|
if (err != nil) { return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, err }
|
||||||
|
|
||||||
yAxisIsAverage := strings.HasPrefix(yAxisAttribute, "Average ")
|
yAxisIsAverage := strings.HasPrefix(yAxisAttribute, "Average ")
|
||||||
if (yAxisIsAverage == true){
|
if (yAxisIsAverage == true){
|
||||||
|
@ -153,69 +120,72 @@ func GetUserStatisticsItemsLists_BarChart(identityType string,
|
||||||
|
|
||||||
attributeTitle := strings.TrimPrefix(yAxisAttribute, "Average ")
|
attributeTitle := strings.TrimPrefix(yAxisAttribute, "Average ")
|
||||||
|
|
||||||
if (attributeTitle == "Wealth"){
|
switch attributeTitle{
|
||||||
|
|
||||||
|
case "Wealth":{
|
||||||
return "WealthInGold"
|
return "WealthInGold"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "23andMe Neanderthal Variants"){
|
case "23andMe Neanderthal Variants":{
|
||||||
return "23andMe_NeanderthalVariants"
|
return "23andMe_NeanderthalVariants"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Body Fat"){
|
case "Body Fat":{
|
||||||
return "BodyFat"
|
return "BodyFat"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Body Muscle"){
|
case "Body Muscle":{
|
||||||
return "BodyMuscle"
|
return "BodyMuscle"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Fruit Rating"){
|
case "Fruit Rating":{
|
||||||
return "FruitRating"
|
return "FruitRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Vegetables Rating"){
|
case "Vegetables Rating":{
|
||||||
return "VegetablesRating"
|
return "VegetablesRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Nuts Rating"){
|
case "Nuts Rating":{
|
||||||
return "NutsRating"
|
return "NutsRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Grains Rating"){
|
case "Grains Rating":{
|
||||||
return "GrainsRating"
|
return "GrainsRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Dairy Rating"){
|
case "Dairy Rating":{
|
||||||
return "DairyRating"
|
return "DairyRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Seafood Rating"){
|
case "Seafood Rating":{
|
||||||
return "SeafoodRating"
|
return "SeafoodRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Beef Rating"){
|
case "Beef Rating":{
|
||||||
return "BeefRating"
|
return "BeefRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Pork Rating"){
|
case "Pork Rating":{
|
||||||
return "PorkRating"
|
return "PorkRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Poultry Rating"){
|
case "Poultry Rating":{
|
||||||
return "PoultryRating"
|
return "PoultryRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Eggs Rating"){
|
case "Eggs Rating":{
|
||||||
return "EggsRating"
|
return "EggsRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Beans Rating"){
|
case "Beans Rating":{
|
||||||
return "BeansRating"
|
return "BeansRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Alcohol Frequency"){
|
case "Alcohol Frequency":{
|
||||||
return "AlcoholFrequency"
|
return "AlcoholFrequency"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Tobacco Frequency"){
|
case "Tobacco Frequency":{
|
||||||
return "TobaccoFrequency"
|
return "TobaccoFrequency"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Cannabis Frequency"){
|
case "Cannabis Frequency":{
|
||||||
return "CannabisFrequency"
|
return "CannabisFrequency"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Pets Rating"){
|
case "Pets Rating":{
|
||||||
return "PetsRating"
|
return "PetsRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Dogs Rating"){
|
case "Dogs Rating":{
|
||||||
return "DogsRating"
|
return "DogsRating"
|
||||||
}
|
}
|
||||||
if (attributeTitle == "Cats Rating"){
|
case "Cats Rating":{
|
||||||
return "CatsRating"
|
return "CatsRating"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return attributeTitle
|
return attributeTitle
|
||||||
}
|
}
|
||||||
|
@ -240,19 +210,19 @@ func GetUserStatisticsItemsLists_BarChart(identityType string,
|
||||||
for _, userIdentityHash := range userIdentityHashesToAnalyzeList{
|
for _, userIdentityHash := range userIdentityHashesToAnalyzeList{
|
||||||
|
|
||||||
profileFound, getAnyUserAttributeValueFunction, err := getRetrieveAnyAttributeFromUserNewestProfileFunction(userIdentityHash, networkType)
|
profileFound, getAnyUserAttributeValueFunction, err := getRetrieveAnyAttributeFromUserNewestProfileFunction(userIdentityHash, networkType)
|
||||||
if (err != nil) { return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, err }
|
if (err != nil) { return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, err }
|
||||||
if (profileFound == false){
|
if (profileFound == false){
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
userIsDisabled, _, _, err := getAnyUserAttributeValueFunction("Disabled")
|
userIsDisabled, _, _, err := getAnyUserAttributeValueFunction("Disabled")
|
||||||
if (err != nil) { return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, err }
|
if (err != nil) { return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, err }
|
||||||
if (userIsDisabled == true){
|
if (userIsDisabled == true){
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeExists, _, userAttributeToGetAverageForValue, err := getAnyUserAttributeValueFunction(attributeToGetAverageFor)
|
attributeExists, _, userAttributeToGetAverageForValue, err := getAnyUserAttributeValueFunction(attributeToGetAverageFor)
|
||||||
if (err != nil) { return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, err }
|
if (err != nil) { return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, err }
|
||||||
if (attributeExists == false){
|
if (attributeExists == false){
|
||||||
// This user did not respond to the attribute we are getting the average for
|
// This user did not respond to the attribute we are getting the average for
|
||||||
// We will not add them to the statistics maps
|
// We will not add them to the statistics maps
|
||||||
|
@ -263,11 +233,11 @@ func GetUserStatisticsItemsLists_BarChart(identityType string,
|
||||||
|
|
||||||
userAttributeToGetAverageForValueFloat64, err := helpers.ConvertStringToFloat64(userAttributeToGetAverageForValue)
|
userAttributeToGetAverageForValueFloat64, err := helpers.ConvertStringToFloat64(userAttributeToGetAverageForValue)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, errors.New("Database corrupt: Contains invalid " + userAttributeToGetAverageForValue + " value: " + userAttributeToGetAverageForValue)
|
return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, errors.New("Database corrupt: Contains invalid " + userAttributeToGetAverageForValue + " value: " + userAttributeToGetAverageForValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeFound, _, userXAxisAttributeValue, err := getAnyUserAttributeValueFunction(xAxisAttribute)
|
attributeFound, _, userXAxisAttributeValue, err := getAnyUserAttributeValueFunction(xAxisAttribute)
|
||||||
if (err != nil) { return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, err }
|
if (err != nil) { return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, err }
|
||||||
if (attributeFound == false){
|
if (attributeFound == false){
|
||||||
// This user did not respond to the X axis attribute
|
// This user did not respond to the X axis attribute
|
||||||
// We calculate the average for users who do not respond and put it in its own category
|
// We calculate the average for users who do not respond and put it in its own category
|
||||||
|
@ -283,18 +253,18 @@ func GetUserStatisticsItemsLists_BarChart(identityType string,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, formatYAxisValuesFunction, _, _, err := attributeDisplay.GetProfileAttributeDisplayInfo(attributeToGetAverageFor)
|
_, _, formatYAxisValuesFunction, _, _, err := attributeDisplay.GetProfileAttributeDisplayInfo(attributeToGetAverageFor)
|
||||||
if (err != nil) { return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, err }
|
if (err != nil) { return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, err }
|
||||||
|
|
||||||
statisticsItemsList := make([]StatisticsItem, 0, len(responseCountsMap))
|
statisticsDatumsList := make([]statisticsDatum.StatisticsDatum, 0, len(responseCountsMap))
|
||||||
|
|
||||||
for attributeResponse, responsesCount := range responseCountsMap{
|
for attributeResponse, responsesCount := range responseCountsMap{
|
||||||
|
|
||||||
attributeResponseFormatted, err := formatXAxisValuesFunction(attributeResponse)
|
attributeResponseFormatted, err := formatXAxisValuesFunction(attributeResponse)
|
||||||
if (err != nil) { return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, err }
|
if (err != nil) { return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, err }
|
||||||
|
|
||||||
allResponsesSum, exists := responseSumsMap[attributeResponse]
|
allResponsesSum, exists := responseSumsMap[attributeResponse]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, errors.New("Response sums map missing attribute value")
|
return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, errors.New("Response sums map missing attribute value")
|
||||||
}
|
}
|
||||||
|
|
||||||
averageValue := allResponsesSum/float64(responsesCount)
|
averageValue := allResponsesSum/float64(responsesCount)
|
||||||
|
@ -302,16 +272,16 @@ func GetUserStatisticsItemsLists_BarChart(identityType string,
|
||||||
averageValueString := helpers.ConvertFloat64ToStringRounded(averageValue, yAxisRoundingPrecision)
|
averageValueString := helpers.ConvertFloat64ToStringRounded(averageValue, yAxisRoundingPrecision)
|
||||||
|
|
||||||
averageValueFormatted, err := formatYAxisValuesFunction(averageValueString)
|
averageValueFormatted, err := formatYAxisValuesFunction(averageValueString)
|
||||||
if (err != nil) { return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, err }
|
if (err != nil) { return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, err }
|
||||||
|
|
||||||
newStatisticsItem := StatisticsItem{
|
newStatisticsDatum := statisticsDatum.StatisticsDatum{
|
||||||
Label: attributeResponse,
|
Label: attributeResponse,
|
||||||
LabelFormatted: attributeResponseFormatted,
|
LabelFormatted: attributeResponseFormatted,
|
||||||
Value: averageValue,
|
Value: averageValue,
|
||||||
ValueFormatted: averageValueFormatted,
|
ValueFormatted: averageValueFormatted,
|
||||||
}
|
}
|
||||||
|
|
||||||
statisticsItemsList = append(statisticsItemsList, newStatisticsItem)
|
statisticsDatumsList = append(statisticsDatumsList, newStatisticsDatum)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use this function to format values after grouping, if grouping is needed
|
// We use this function to format values after grouping, if grouping is needed
|
||||||
|
@ -326,111 +296,111 @@ func GetUserStatisticsItemsLists_BarChart(identityType string,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numberOfUsersWithUnknownXAxisValue == 0){
|
if (numberOfUsersWithUnknownXAxisValue == 0){
|
||||||
return totalAnalyzedUsers, statisticsItemsList, responseCountsMap, true, responseSumsMap, formatValuesFunction, false, StatisticsItem{}, nil
|
return totalAnalyzedUsers, statisticsDatumsList, responseCountsMap, true, responseSumsMap, formatValuesFunction, false, statisticsDatum.StatisticsDatum{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
unknownResponsesAverage := usersWithUnknownXAxisValueYAxisValuesSum/float64(numberOfUsersWithUnknownXAxisValue)
|
unknownResponsesAverage := usersWithUnknownXAxisValueYAxisValuesSum/float64(numberOfUsersWithUnknownXAxisValue)
|
||||||
|
|
||||||
unknownResponsesValueFormatted, err := formatValuesFunction(unknownResponsesAverage)
|
unknownResponsesValueFormatted, err := formatValuesFunction(unknownResponsesAverage)
|
||||||
if (err != nil) { return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, err }
|
if (err != nil) { return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, err }
|
||||||
|
|
||||||
// This item represents the average value for the yAxisAttribute for users who did not respond.
|
// This datum represents the average value for the yAxisAttribute for users who did not respond.
|
||||||
// For example, if the xAxisAttribute is Height, and the yAxisAttribute is AverageWealth, this value
|
// For example, if the xAxisAttribute is Height, and the yAxisAttribute is AverageWealth, this value
|
||||||
// will represent the average wealth for users who did not provide Height on their profile.
|
// will represent the average wealth for users who did not provide Height on their profile.
|
||||||
unknownStatisticsItem := StatisticsItem{
|
unknownStatisticsDatum := statisticsDatum.StatisticsDatum{
|
||||||
Label: xAxisUnknownLabel,
|
Label: xAxisUnknownLabel,
|
||||||
LabelFormatted: xAxisUnknownLabel,
|
LabelFormatted: xAxisUnknownLabel,
|
||||||
Value: unknownResponsesAverage,
|
Value: unknownResponsesAverage,
|
||||||
ValueFormatted: unknownResponsesValueFormatted,
|
ValueFormatted: unknownResponsesValueFormatted,
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalAnalyzedUsers, statisticsItemsList, responseCountsMap, true, responseSumsMap, formatValuesFunction, true, unknownStatisticsItem, nil
|
return totalAnalyzedUsers, statisticsDatumsList, responseCountsMap, true, responseSumsMap, formatValuesFunction, true, unknownStatisticsDatum, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, nil, nil, false, nil, nil, false, StatisticsItem{}, errors.New("Invalid y-axis attribute: " + yAxisAttribute)
|
return 0, nil, nil, false, nil, nil, false, statisticsDatum.StatisticsDatum{}, errors.New("Invalid y-axis attribute: " + yAxisAttribute)
|
||||||
}
|
}
|
||||||
|
|
||||||
totalAnalyzedUsers, statisticsItemsList, responseCountsMap, yAxisIsAverage, responseSumsMap, formatValuesFunction, includeUnknownItem, unknownValueItem, err := getStatisticsItemsList()
|
totalAnalyzedUsers, statisticsDatumsList, responseCountsMap, yAxisIsAverage, responseSumsMap, formatValuesFunction, includeUnknownDatum, unknownValueDatum, err := getStatisticsDatumsList()
|
||||||
if (err != nil) { return 0, nil, false, nil, nil, err }
|
if (err != nil) { return 0, nil, false, nil, nil, err }
|
||||||
|
|
||||||
sortStatisticsItemsList(statisticsItemsList, xAxisIsNumerical)
|
sortStatisticsDatumsList(statisticsDatumsList, xAxisIsNumerical)
|
||||||
|
|
||||||
// We now see if we need to group the items in the list together
|
// We now see if we need to group the datums in the list together
|
||||||
// We do this if there are more than 10 categories
|
// We do this if there are more than 10 categories
|
||||||
|
|
||||||
if (len(statisticsItemsList) <= 10){
|
if (len(statisticsDatumsList) <= 10){
|
||||||
|
|
||||||
// No grouping needed. We are done.
|
// No grouping needed. We are done.
|
||||||
|
|
||||||
if (includeUnknownItem == true){
|
if (includeUnknownDatum == true){
|
||||||
statisticsItemsList = append(statisticsItemsList, unknownValueItem)
|
statisticsDatumsList = append(statisticsDatumsList, unknownValueDatum)
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalAnalyzedUsers, statisticsItemsList, false, nil, formatValuesFunction, nil
|
return totalAnalyzedUsers, statisticsDatumsList, false, nil, formatValuesFunction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
groupedStatisticsItemsList, err := getStatisticsItemsListGrouped(10, statisticsItemsList, xAxisIsNumerical, responseCountsMap, yAxisIsAverage, responseSumsMap, formatValuesFunction)
|
groupedStatisticsDatumsList, err := getStatisticsDatumsListGrouped(10, statisticsDatumsList, xAxisIsNumerical, responseCountsMap, yAxisIsAverage, responseSumsMap, formatValuesFunction)
|
||||||
if (err != nil) { return 0, nil, false, nil, nil, err }
|
if (err != nil) { return 0, nil, false, nil, nil, err }
|
||||||
|
|
||||||
if (includeUnknownItem == true){
|
if (includeUnknownDatum == true){
|
||||||
statisticsItemsList = append(statisticsItemsList, unknownValueItem)
|
statisticsDatumsList = append(statisticsDatumsList, unknownValueDatum)
|
||||||
groupedStatisticsItemsList = append(groupedStatisticsItemsList, unknownValueItem)
|
groupedStatisticsDatumsList = append(groupedStatisticsDatumsList, unknownValueDatum)
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalAnalyzedUsers, statisticsItemsList, true, groupedStatisticsItemsList, formatValuesFunction, nil
|
return totalAnalyzedUsers, statisticsDatumsList, true, groupedStatisticsDatumsList, formatValuesFunction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -int: Number of users analyzed in statistics
|
// -int: Number of users analyzed in statistics
|
||||||
// -[]StatisticsItem: Statistics items list (sorted, not grouped)
|
// -[]statisticsDatum.StatisticsDatum: Statistics datums list (sorted, not grouped)
|
||||||
// -bool: Grouping performed
|
// -bool: Grouping performed
|
||||||
// -[]StatisticsItem: Grouped items list
|
// -[]statisticsDatum.StatisticsDatum: Grouped datums list
|
||||||
// -error
|
// -error
|
||||||
func GetUserStatisticsItemsLists_DonutChart(identityType string,
|
func GetUserStatisticsDatumsLists_DonutChart(identityType string,
|
||||||
networkType byte,
|
networkType byte,
|
||||||
attributeToAnalyze string,
|
attributeToAnalyze string,
|
||||||
attributeIsNumerical bool,
|
attributeIsNumerical bool,
|
||||||
formatAttributeLabelsFunction func(string)(string, error),
|
formatAttributeLabelsFunction func(string)(string, error),
|
||||||
unknownLabelTranslated string)(int, []StatisticsItem, bool, []StatisticsItem, error){
|
unknownLabelTranslated string)(int, []statisticsDatum.StatisticsDatum, bool, []statisticsDatum.StatisticsDatum, error){
|
||||||
|
|
||||||
isValid := helpers.VerifyNetworkType(networkType)
|
isValid := helpers.VerifyNetworkType(networkType)
|
||||||
if (isValid == false){
|
if (isValid == false){
|
||||||
networkTypeString := helpers.ConvertByteToString(networkType)
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||||||
return 0, nil, false, nil, errors.New("GetUserStatisticsItemsLists_DonutChart called with invalid networkType: " + networkTypeString)
|
return 0, nil, false, nil, errors.New("GetUserStatisticsDatumsLists_DonutChart called with invalid networkType: " + networkTypeString)
|
||||||
}
|
}
|
||||||
|
|
||||||
totalAnalyzedUsers, statisticsItemsList, attributeCountsMap, numberOfUnknownResponders, err := getProfileAttributeCountStatisticsItemsList(identityType, networkType, attributeToAnalyze, formatAttributeLabelsFunction)
|
totalAnalyzedUsers, statisticsDatumsList, attributeCountsMap, numberOfUnknownResponders, err := getProfileAttributeCountStatisticsDatumsList(identityType, networkType, attributeToAnalyze, formatAttributeLabelsFunction)
|
||||||
if (err != nil) { return 0, nil, false, nil, err }
|
if (err != nil) { return 0, nil, false, nil, err }
|
||||||
|
|
||||||
sortStatisticsItemsList(statisticsItemsList, attributeIsNumerical)
|
sortStatisticsDatumsList(statisticsDatumsList, attributeIsNumerical)
|
||||||
|
|
||||||
getUnknownValueItem := func()StatisticsItem{
|
getUnknownValueDatum := func()statisticsDatum.StatisticsDatum{
|
||||||
|
|
||||||
numberOfUnknownRespondersString := helpers.ConvertIntToString(numberOfUnknownResponders)
|
numberOfUnknownRespondersString := helpers.ConvertIntToString(numberOfUnknownResponders)
|
||||||
|
|
||||||
unknownValueItem := StatisticsItem{
|
unknownValueDatum := statisticsDatum.StatisticsDatum{
|
||||||
Label: unknownLabelTranslated,
|
Label: unknownLabelTranslated,
|
||||||
LabelFormatted: unknownLabelTranslated,
|
LabelFormatted: unknownLabelTranslated,
|
||||||
Value: float64(numberOfUnknownResponders),
|
Value: float64(numberOfUnknownResponders),
|
||||||
ValueFormatted: numberOfUnknownRespondersString,
|
ValueFormatted: numberOfUnknownRespondersString,
|
||||||
}
|
}
|
||||||
|
|
||||||
return unknownValueItem
|
return unknownValueDatum
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(statisticsItemsList) <= 8){
|
if (len(statisticsDatumsList) <= 8){
|
||||||
|
|
||||||
// No grouping needed.
|
// No grouping needed.
|
||||||
|
|
||||||
if (numberOfUnknownResponders != 0){
|
if (numberOfUnknownResponders != 0){
|
||||||
|
|
||||||
unknownValueItem := getUnknownValueItem()
|
unknownValueDatum := getUnknownValueDatum()
|
||||||
|
|
||||||
statisticsItemsList = append(statisticsItemsList, unknownValueItem)
|
statisticsDatumsList = append(statisticsDatumsList, unknownValueDatum)
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalAnalyzedUsers, statisticsItemsList, false, nil, nil
|
return totalAnalyzedUsers, statisticsDatumsList, false, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
formatValuesFunction := func(input float64)(string, error){
|
formatValuesFunction := func(input float64)(string, error){
|
||||||
|
@ -443,35 +413,35 @@ func GetUserStatisticsItemsLists_DonutChart(identityType string,
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
groupedStatisticsItemsList, err := getStatisticsItemsListGrouped(8, statisticsItemsList, attributeIsNumerical, attributeCountsMap, false, nil, formatValuesFunction)
|
groupedStatisticsDatumsList, err := getStatisticsDatumsListGrouped(8, statisticsDatumsList, attributeIsNumerical, attributeCountsMap, false, nil, formatValuesFunction)
|
||||||
if (err != nil) { return 0, nil, false, nil, err }
|
if (err != nil) { return 0, nil, false, nil, err }
|
||||||
|
|
||||||
if (numberOfUnknownResponders != 0){
|
if (numberOfUnknownResponders != 0){
|
||||||
|
|
||||||
unknownValueItem := getUnknownValueItem()
|
unknownValueDatum := getUnknownValueDatum()
|
||||||
|
|
||||||
statisticsItemsList = append(statisticsItemsList, unknownValueItem)
|
statisticsDatumsList = append(statisticsDatumsList, unknownValueDatum)
|
||||||
groupedStatisticsItemsList = append(groupedStatisticsItemsList, unknownValueItem)
|
groupedStatisticsDatumsList = append(groupedStatisticsDatumsList, unknownValueDatum)
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalAnalyzedUsers, statisticsItemsList, true, groupedStatisticsItemsList, nil
|
return totalAnalyzedUsers, statisticsDatumsList, true, groupedStatisticsDatumsList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This function will return a statistics items list of the following format:
|
// This function will return a statistics datums list of the following format:
|
||||||
// "Label": Attribute name (Example: "Male")
|
// "Label": Attribute name (Example: "Male")
|
||||||
// "Value": The number of users who responded with the attribute (in this example: "Male")
|
// "Value": The number of users who responded with the attribute (in this example: "Male")
|
||||||
//
|
//
|
||||||
// All users of provided identityType who are not disabled will be analyzed
|
// All users of provided identityType who are not disabled will be analyzed
|
||||||
// -int: Number of analyzed users
|
// -int: Number of analyzed users
|
||||||
// -[]StatisticsItem: Statistics items list (not sorted or grouped)
|
// -[]statisticsDatum.StatisticsDatum: Statistics datums list (not sorted or grouped)
|
||||||
// -map[string]int: Response counts map (Response -> Number of responders)
|
// -map[string]int: Response counts map (Response -> Number of responders)
|
||||||
// -int: Number of No Response/Unknown value responders
|
// -int: Number of No Response/Unknown value responders
|
||||||
// -error
|
// -error
|
||||||
func getProfileAttributeCountStatisticsItemsList(identityType string,
|
func getProfileAttributeCountStatisticsDatumsList(identityType string,
|
||||||
networkType byte,
|
networkType byte,
|
||||||
attributeName string,
|
attributeName string,
|
||||||
formatLabelsFunction func(string)(string, error))(int, []StatisticsItem, map[string]int, int, error){
|
formatLabelsFunction func(string)(string, error))(int, []statisticsDatum.StatisticsDatum, map[string]int, int, error){
|
||||||
|
|
||||||
userIdentityHashesToAnalyzeList, err := getUserIdentityHashesToAnalyzeList(identityType)
|
userIdentityHashesToAnalyzeList, err := getUserIdentityHashesToAnalyzeList(identityType)
|
||||||
if (err != nil) { return 0, nil, nil, 0, err }
|
if (err != nil) { return 0, nil, nil, 0, err }
|
||||||
|
@ -509,7 +479,7 @@ func getProfileAttributeCountStatisticsItemsList(identityType string,
|
||||||
responseCountsMap[attributeValue] += 1
|
responseCountsMap[attributeValue] += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
statisticsItemsList := make([]StatisticsItem, 0, len(responseCountsMap))
|
statisticsDatumsList := make([]statisticsDatum.StatisticsDatum, 0, len(responseCountsMap))
|
||||||
|
|
||||||
for attributeResponse, numberOfUsers := range responseCountsMap{
|
for attributeResponse, numberOfUsers := range responseCountsMap{
|
||||||
|
|
||||||
|
@ -518,88 +488,88 @@ func getProfileAttributeCountStatisticsItemsList(identityType string,
|
||||||
|
|
||||||
attributeNumberOfUsersString := helpers.ConvertIntToString(numberOfUsers)
|
attributeNumberOfUsersString := helpers.ConvertIntToString(numberOfUsers)
|
||||||
|
|
||||||
newStatisticsItem := StatisticsItem{
|
newStatisticsDatum := statisticsDatum.StatisticsDatum{
|
||||||
Label: attributeResponse,
|
Label: attributeResponse,
|
||||||
LabelFormatted: attributeResponseFormatted,
|
LabelFormatted: attributeResponseFormatted,
|
||||||
Value: float64(numberOfUsers),
|
Value: float64(numberOfUsers),
|
||||||
ValueFormatted: attributeNumberOfUsersString,
|
ValueFormatted: attributeNumberOfUsersString,
|
||||||
}
|
}
|
||||||
|
|
||||||
statisticsItemsList = append(statisticsItemsList, newStatisticsItem)
|
statisticsDatumsList = append(statisticsDatumsList, newStatisticsDatum)
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalAnalyzedUsers, statisticsItemsList, responseCountsMap, numberOfUnknownValueUsers, nil
|
return totalAnalyzedUsers, statisticsDatumsList, responseCountsMap, numberOfUnknownValueUsers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortStatisticsItemsList(inputStatisticsItemsList []StatisticsItem, labelIsNumerical bool){
|
func sortStatisticsDatumsList(inputStatisticsDatumsList []statisticsDatum.StatisticsDatum, labelIsNumerical bool){
|
||||||
|
|
||||||
if (len(inputStatisticsItemsList) <= 1){
|
if (len(inputStatisticsDatumsList) <= 1){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (labelIsNumerical == true){
|
if (labelIsNumerical == true){
|
||||||
|
|
||||||
// We sort the items by label values in ascending order
|
// We sort the datums by label values in ascending order
|
||||||
// Example: Bar chart columns are ages, in order of youngest to oldest
|
// Example: Bar chart columns are ages, in order of youngest to oldest
|
||||||
|
|
||||||
compareItemsFunction := func(itemA StatisticsItem, itemB StatisticsItem)int{
|
compareDatumsFunction := func(datumA statisticsDatum.StatisticsDatum, datumB statisticsDatum.StatisticsDatum)int{
|
||||||
|
|
||||||
itemALabel := itemA.Label
|
datumALabel := datumA.Label
|
||||||
itemBLabel := itemB.Label
|
datumBLabel := datumB.Label
|
||||||
|
|
||||||
itemAFloat64, err := helpers.ConvertStringToFloat64(itemALabel)
|
datumAFloat64, err := helpers.ConvertStringToFloat64(datumALabel)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
panic("Invalid statistics item: Item Label is not float: " + itemALabel)
|
panic("Invalid statistics datum: Datum Label is not float: " + datumALabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
itemBFloat64, err := helpers.ConvertStringToFloat64(itemBLabel)
|
datumBFloat64, err := helpers.ConvertStringToFloat64(datumBLabel)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
panic("Invalid statistics item: Item Label is not float: " + itemBLabel)
|
panic("Invalid statistics datum: Datum Label is not float: " + datumBLabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemAFloat64 == itemBFloat64){
|
if (datumAFloat64 == datumBFloat64){
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemAFloat64 < itemBFloat64){
|
if (datumAFloat64 < datumBFloat64){
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
slices.SortFunc(inputStatisticsItemsList, compareItemsFunction)
|
slices.SortFunc(inputStatisticsDatumsList, compareDatumsFunction)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// We sort the items by their values in descending order
|
// We sort the datums by their values in descending order
|
||||||
|
|
||||||
compareItemsFunction := func(itemA StatisticsItem, itemB StatisticsItem)int{
|
compareDatumsFunction := func(datum1 statisticsDatum.StatisticsDatum, datum2 statisticsDatum.StatisticsDatum)int{
|
||||||
|
|
||||||
itemAValue := itemA.Value
|
datum1Value := datum1.Value
|
||||||
itemBValue := itemB.Value
|
datum2Value := datum2.Value
|
||||||
|
|
||||||
if (itemAValue == itemBValue){
|
if (datum1Value == datum2Value){
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemAValue < itemBValue){
|
if (datum1Value < datum2Value){
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
slices.SortFunc(inputStatisticsItemsList, compareItemsFunction)
|
slices.SortFunc(inputStatisticsDatumsList, compareDatumsFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function will group a statistics items list.
|
// This function will group a statistics datums list.
|
||||||
// It will group Labels and their values to fit into a specified number of groups
|
// It will group Labels and their values to fit into a specified number of groups
|
||||||
// Example: "1","2","3","4" -> "1-2", "3-4"
|
// Example: "1","2","3","4" -> "1-2", "3-4"
|
||||||
//Inputs:
|
//Inputs:
|
||||||
// -int: Maximum groups to create
|
// -int: Maximum groups to create
|
||||||
// -[]StatisticsItem: Statistics items list to group
|
// -[]statisticsDatum.StatisticsDatum: Statistics datums list to group
|
||||||
// -bool: Label is numerical
|
// -bool: Label is numerical
|
||||||
// -If it is, we will group labels into groups of numbers.
|
// -If it is, we will group labels into groups of numbers.
|
||||||
// -Otherwise, we will group all categories after the first maximumGroupsToCreate into a group called Other
|
// -Otherwise, we will group all categories after the first maximumGroupsToCreate into a group called Other
|
||||||
|
@ -612,27 +582,27 @@ func sortStatisticsItemsList(inputStatisticsItemsList []StatisticsItem, labelIsN
|
||||||
// -Response Sums map (X-axis attribute response -> all Y-axis responses summed) (If yAxisIsAverage == true)
|
// -Response Sums map (X-axis attribute response -> all Y-axis responses summed) (If yAxisIsAverage == true)
|
||||||
// -func(float64)(string, error): This is the function we use to format the values
|
// -func(float64)(string, error): This is the function we use to format the values
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -[]StatisticsItem: Grouped statistics items list
|
// -[]statisticsDatum.StatisticsDatum: Grouped statistics datums list
|
||||||
// -error
|
// -error
|
||||||
func getStatisticsItemsListGrouped(maximumGroupsToCreate int,
|
func getStatisticsDatumsListGrouped(maximumGroupsToCreate int,
|
||||||
inputStatisticsItemsList []StatisticsItem,
|
inputStatisticsDatumsList []statisticsDatum.StatisticsDatum,
|
||||||
labelIsNumerical bool,
|
labelIsNumerical bool,
|
||||||
responseCountsMap map[string]int,
|
responseCountsMap map[string]int,
|
||||||
valueIsAverage bool,
|
valueIsAverage bool,
|
||||||
responseSumsMap map[string]float64,
|
responseSumsMap map[string]float64,
|
||||||
formatValuesFunction func(float64)(string, error))([]StatisticsItem, error){
|
formatValuesFunction func(float64)(string, error))([]statisticsDatum.StatisticsDatum, error){
|
||||||
|
|
||||||
if (len(inputStatisticsItemsList) <= maximumGroupsToCreate){
|
if (len(inputStatisticsDatumsList) <= maximumGroupsToCreate){
|
||||||
return nil, errors.New("maximumGroupsToCreate is <= length of input statistics items list")
|
return nil, errors.New("maximumGroupsToCreate is <= length of input statistics datums list")
|
||||||
}
|
}
|
||||||
|
|
||||||
// We deep copy the statistics items list to retain the sorted version
|
// We deep copy the statistics datums list to retain the sorted version
|
||||||
// We need to retain both versions because the user can view the raw or grouped data in the GUI
|
// We need to retain both versions because the user can view the raw or grouped data in the GUI
|
||||||
|
|
||||||
statisticsItemsList := slices.Clone(inputStatisticsItemsList)
|
statisticsDatumsList := slices.Clone(inputStatisticsDatumsList)
|
||||||
|
|
||||||
// We use this function to get the new value for a group of labels
|
// We use this function to get the new value for a group of labels
|
||||||
getGroupValue := func(itemsToCombineList []StatisticsItem)(float64, error){
|
getGroupValue := func(datumsToCombineList []statisticsDatum.StatisticsDatum)(float64, error){
|
||||||
|
|
||||||
// This will count the total number of users who responded with the responses within this group
|
// This will count the total number of users who responded with the responses within this group
|
||||||
// Example: Labels are "Blue", "Green", this variable will store the number of users who responded with either Blue or Green
|
// Example: Labels are "Blue", "Green", this variable will store the number of users who responded with either Blue or Green
|
||||||
|
@ -642,22 +612,22 @@ func getStatisticsItemsListGrouped(maximumGroupsToCreate int,
|
||||||
// We only need to add to this sum if valueIsAverage == true
|
// We only need to add to this sum if valueIsAverage == true
|
||||||
allReponsesSummed := float64(0)
|
allReponsesSummed := float64(0)
|
||||||
|
|
||||||
for _, statisticsItem := range itemsToCombineList{
|
for _, statisticsDatum := range datumsToCombineList{
|
||||||
|
|
||||||
itemLabel := statisticsItem.Label
|
datumLabel := statisticsDatum.Label
|
||||||
|
|
||||||
responderCount, exists := responseCountsMap[itemLabel]
|
responderCount, exists := responseCountsMap[datumLabel]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return 0, errors.New("responseCountsMap missing label: " + itemLabel)
|
return 0, errors.New("responseCountsMap missing label: " + datumLabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
totalRespondersCount += float64(responderCount)
|
totalRespondersCount += float64(responderCount)
|
||||||
|
|
||||||
if (valueIsAverage == true){
|
if (valueIsAverage == true){
|
||||||
|
|
||||||
yAxisAttributeResponsesSum, exists := responseSumsMap[itemLabel]
|
yAxisAttributeResponsesSum, exists := responseSumsMap[datumLabel]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return 0, errors.New("responseSumsMap missing label: " + itemLabel)
|
return 0, errors.New("responseSumsMap missing label: " + datumLabel)
|
||||||
}
|
}
|
||||||
allReponsesSummed += yAxisAttributeResponsesSum
|
allReponsesSummed += yAxisAttributeResponsesSum
|
||||||
}
|
}
|
||||||
|
@ -670,9 +640,9 @@ func getStatisticsItemsListGrouped(maximumGroupsToCreate int,
|
||||||
|
|
||||||
// The value is an average
|
// The value is an average
|
||||||
// We need to find the average for all of the user responses for the labels in the input list
|
// We need to find the average for all of the user responses for the labels in the input list
|
||||||
// The Values in the inputStatisticsItemsList are averages
|
// The Values in the inputStatisticsDatumsList are averages
|
||||||
// We can't average out the averages, because that will not give us the true average
|
// We can't average out the averages, because that will not give us the true average
|
||||||
// We have to use the original sums for all group items and average them
|
// We have to use the original sums for all group datums and average them
|
||||||
|
|
||||||
if (totalRespondersCount == 0){
|
if (totalRespondersCount == 0){
|
||||||
return 0, errors.New("totalRespondersCount is 0.")
|
return 0, errors.New("totalRespondersCount is 0.")
|
||||||
|
@ -685,82 +655,82 @@ func getStatisticsItemsListGrouped(maximumGroupsToCreate int,
|
||||||
|
|
||||||
if (labelIsNumerical == true){
|
if (labelIsNumerical == true){
|
||||||
|
|
||||||
maximumItemsPerCategory := int(math.Ceil(float64(len(statisticsItemsList))/float64(maximumGroupsToCreate)))
|
maximumDatumsPerCategory := int(math.Ceil(float64(len(statisticsDatumsList))/float64(maximumGroupsToCreate)))
|
||||||
|
|
||||||
statisticsItemsListSublists, err := helpers.SplitListIntoSublists(statisticsItemsList, maximumItemsPerCategory)
|
statisticsDatumsListSublists, err := helpers.SplitListIntoSublists(statisticsDatumsList, maximumDatumsPerCategory)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
groupedItemsList := make([]StatisticsItem, 0, len(statisticsItemsListSublists))
|
groupedDatumsList := make([]statisticsDatum.StatisticsDatum, 0, len(statisticsDatumsListSublists))
|
||||||
|
|
||||||
for _, groupItemsListSublist := range statisticsItemsListSublists{
|
for _, groupDatumsListSublist := range statisticsDatumsListSublists{
|
||||||
|
|
||||||
if (len(groupItemsListSublist) == 1){
|
if (len(groupDatumsListSublist) == 1){
|
||||||
// Sometimes, a group with 1 item will be created
|
// Sometimes, a group with 1 datum will be created
|
||||||
// This happens if the groups cannot be evenly divided, so there is a remainder of 1.
|
// This happens if the groups cannot be evenly divided, so there is a remainder of 1.
|
||||||
// Example: 10->4 groups = 3, 3, 3, 1.
|
// Example: 10->4 groups = 3, 3, 3, 1.
|
||||||
//TODO: Prevent this from happening so groups always have more than 1 subitem
|
//TODO: Prevent this from happening so groups always have more than 1 subdatum
|
||||||
|
|
||||||
groupItem := groupItemsListSublist[0]
|
groupDatum := groupDatumsListSublist[0]
|
||||||
|
|
||||||
groupedItemsList = append(groupedItemsList, groupItem)
|
groupedDatumsList = append(groupedDatumsList, groupDatum)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
finalIndex := len(groupItemsListSublist)-1
|
finalIndex := len(groupDatumsListSublist)-1
|
||||||
|
|
||||||
initialItem := groupItemsListSublist[0]
|
initialDatum := groupDatumsListSublist[0]
|
||||||
finalItem := groupItemsListSublist[finalIndex]
|
finalDatum := groupDatumsListSublist[finalIndex]
|
||||||
|
|
||||||
initialLabel := initialItem.Label
|
initialLabel := initialDatum.Label
|
||||||
initialLabelFormatted := initialItem.LabelFormatted
|
initialLabelFormatted := initialDatum.LabelFormatted
|
||||||
|
|
||||||
finalLabel := finalItem.Label
|
finalLabel := finalDatum.Label
|
||||||
finalLabelFormatted := finalItem.LabelFormatted
|
finalLabelFormatted := finalDatum.LabelFormatted
|
||||||
|
|
||||||
groupValue, err := getGroupValue(groupItemsListSublist)
|
groupValue, err := getGroupValue(groupDatumsListSublist)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
groupValueFormatted, err := formatValuesFunction(groupValue)
|
groupValueFormatted, err := formatValuesFunction(groupValue)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
newGroupStatisticsItem := StatisticsItem{
|
newGroupStatisticsDatum := statisticsDatum.StatisticsDatum{
|
||||||
Label: initialLabel + "-" + finalLabel,
|
Label: initialLabel + "-" + finalLabel,
|
||||||
LabelFormatted: initialLabelFormatted + "-" + finalLabelFormatted,
|
LabelFormatted: initialLabelFormatted + "-" + finalLabelFormatted,
|
||||||
Value: groupValue,
|
Value: groupValue,
|
||||||
ValueFormatted: groupValueFormatted,
|
ValueFormatted: groupValueFormatted,
|
||||||
}
|
}
|
||||||
|
|
||||||
groupedItemsList = append(groupedItemsList, newGroupStatisticsItem)
|
groupedDatumsList = append(groupedDatumsList, newGroupStatisticsDatum)
|
||||||
}
|
}
|
||||||
|
|
||||||
return groupedItemsList, nil
|
return groupedDatumsList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Label is not numerical
|
// Label is not numerical
|
||||||
// We combine all categories after the first maximumGroupsToCreate into a category called Other
|
// We combine all categories after the first maximumGroupsToCreate into a category called Other
|
||||||
|
|
||||||
itemsToKeep := statisticsItemsList[:maximumGroupsToCreate]
|
datumsToKeep := statisticsDatumsList[:maximumGroupsToCreate]
|
||||||
|
|
||||||
itemsToCombine := statisticsItemsList[maximumGroupsToCreate:]
|
datumsToCombine := statisticsDatumsList[maximumGroupsToCreate:]
|
||||||
|
|
||||||
otherTranslated := translation.TranslateTextFromEnglishToMyLanguage("Other")
|
otherTranslated := translation.TranslateTextFromEnglishToMyLanguage("Other")
|
||||||
|
|
||||||
otherGroupValue, err := getGroupValue(itemsToCombine)
|
otherGroupValue, err := getGroupValue(datumsToCombine)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
otherGroupValueFormatted, err := formatValuesFunction(otherGroupValue)
|
otherGroupValueFormatted, err := formatValuesFunction(otherGroupValue)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
otherGroupItem := StatisticsItem{
|
otherGroupDatum := statisticsDatum.StatisticsDatum{
|
||||||
Label: "Other",
|
Label: "Other",
|
||||||
LabelFormatted: otherTranslated,
|
LabelFormatted: otherTranslated,
|
||||||
Value: otherGroupValue,
|
Value: otherGroupValue,
|
||||||
ValueFormatted: otherGroupValueFormatted,
|
ValueFormatted: otherGroupValueFormatted,
|
||||||
}
|
}
|
||||||
|
|
||||||
groupedStatisticsItemsList := append(itemsToKeep, otherGroupItem)
|
groupedStatisticsDatumsList := append(datumsToKeep, otherGroupDatum)
|
||||||
|
|
||||||
return groupedStatisticsItemsList, nil
|
return groupedStatisticsDatumsList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
39
internal/statisticsDatum/statisticsDatum.go
Normal file
39
internal/statisticsDatum/statisticsDatum.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
//statisticsDatum implements the StatisticsDatum struct
|
||||||
|
|
||||||
|
package statisticsDatum
|
||||||
|
|
||||||
|
|
||||||
|
type StatisticsDatum struct{
|
||||||
|
|
||||||
|
// The label for the statistics datum
|
||||||
|
// For a bar chart, this represents the name of an X axis bar.
|
||||||
|
// For a donut chart, this represents the name of a donut slice
|
||||||
|
// Example: "Man", "100-200"
|
||||||
|
// This will never be translated, unless it is the Unknown/No Response value, in which case
|
||||||
|
// the label will be "Unknown"/"No Response" translated to the user's current app language
|
||||||
|
Label string
|
||||||
|
|
||||||
|
// This is the formatted, human readable version of the label
|
||||||
|
// This will be translated into the application language
|
||||||
|
// Sometimes, the LabelFormatted will be identical to Label
|
||||||
|
// This does not include units (Example: " days", " users")
|
||||||
|
// Example:
|
||||||
|
// -"1000000-2000000" -> "1 million-2 million"
|
||||||
|
LabelFormatted string
|
||||||
|
|
||||||
|
// The value corresponding to the label
|
||||||
|
// For a bar chart, this represents the Y axis value for a bar.
|
||||||
|
// For a donut chart, this represents the value (size) of one of the donut slices
|
||||||
|
// This will never be translated
|
||||||
|
// For example, the value could be 500 if 500 men responded Yes.
|
||||||
|
Value float64
|
||||||
|
|
||||||
|
// This is the formatted version of the value
|
||||||
|
// This does not include units (Example: " days", " users")
|
||||||
|
// Examples:
|
||||||
|
// -5 -> "5/10"
|
||||||
|
// -1500000000000 -> "1.5 trillion"
|
||||||
|
ValueFormatted string
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue