Compare commits
No commits in common. "62887d48b5a6f2e650222e88cc81c50f582b8995" and "75331a22d3c67893a2c358f6e5a969985759967b" have entirely different histories.
62887d48b5
...
75331a22d3
42 changed files with 1709 additions and 3369 deletions
|
@ -6,8 +6,6 @@ Small and insignificant changes may not be included in this log.
|
||||||
|
|
||||||
## Unversioned Changes
|
## Unversioned Changes
|
||||||
|
|
||||||
* Upgraded Fyne to version 2.5.0. - *Simon Sarasova*
|
|
||||||
* Added neural network trait prediction to genetic analyses. - *Simon Sarasova*
|
|
||||||
* Improved the Create Genetic Models utility and neural network training code. Models are now able to predict traits with some accuracy. - *Simon Sarasova*
|
* Improved the Create Genetic Models utility and neural network training code. Models are now able to predict traits with some accuracy. - *Simon Sarasova*
|
||||||
* Improved ReadMe.md. - *Simon Sarasova*
|
* Improved ReadMe.md. - *Simon Sarasova*
|
||||||
* Improved Seekia's slogan and Whitepaper.md. - *Simon Sarasova*
|
* Improved Seekia's slogan and Whitepaper.md. - *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 | 267
|
Simon Sarasova | June 13, 2023 | 265
|
32
go.mod
32
go.mod
|
@ -5,7 +5,7 @@ replace seekia => ./
|
||||||
go 1.22
|
go 1.22
|
||||||
|
|
||||||
require (
|
require (
|
||||||
fyne.io/fyne/v2 v2.5.0
|
fyne.io/fyne/v2 v2.4.5
|
||||||
github.com/chai2010/webp v1.1.1
|
github.com/chai2010/webp v1.1.1
|
||||||
github.com/cloudflare/circl v1.3.9
|
github.com/cloudflare/circl v1.3.9
|
||||||
github.com/dgraph-io/badger/v4 v4.2.0
|
github.com/dgraph-io/badger/v4 v4.2.0
|
||||||
|
@ -15,15 +15,14 @@ require (
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||||
github.com/wcharczuk/go-chart/v2 v2.1.1
|
github.com/wcharczuk/go-chart/v2 v2.1.1
|
||||||
github.com/zeebo/blake3 v0.2.3
|
github.com/zeebo/blake3 v0.2.3
|
||||||
golang.org/x/crypto v0.23.0
|
golang.org/x/crypto v0.21.0
|
||||||
golang.org/x/image v0.18.0
|
golang.org/x/image v0.15.0
|
||||||
gorgonia.org/gorgonia v0.9.18
|
gorgonia.org/gorgonia v0.9.18
|
||||||
gorgonia.org/tensor v0.9.24
|
gorgonia.org/tensor v0.9.24
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
fyne.io/systray v1.11.0 // indirect
|
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e // indirect
|
||||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
|
||||||
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 // indirect
|
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 // indirect
|
||||||
github.com/awalterschulze/gographviz v2.0.3+incompatible // indirect
|
github.com/awalterschulze/gographviz v2.0.3+incompatible // indirect
|
||||||
github.com/blend/go-sdk v1.20220411.3 // indirect
|
github.com/blend/go-sdk v1.20220411.3 // indirect
|
||||||
|
@ -33,13 +32,13 @@ require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||||
github.com/fredbi/uri v1.1.0 // indirect
|
github.com/fredbi/uri v1.0.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe // indirect
|
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe // indirect
|
||||||
github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a // indirect
|
github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 // indirect
|
||||||
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 // indirect
|
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 // indirect
|
||||||
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect
|
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240306074159-ea2d69986ecb // indirect
|
||||||
github.com/go-text/render v0.1.0 // indirect
|
github.com/go-text/render v0.1.0 // indirect
|
||||||
github.com/go-text/typesetting v0.1.0 // indirect
|
github.com/go-text/typesetting v0.1.0 // indirect
|
||||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
|
@ -52,25 +51,23 @@ require (
|
||||||
github.com/google/flatbuffers v23.5.26+incompatible // indirect
|
github.com/google/flatbuffers v23.5.26+incompatible // indirect
|
||||||
github.com/google/uuid v1.5.0 // indirect
|
github.com/google/uuid v1.5.0 // indirect
|
||||||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||||
github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49 // indirect
|
|
||||||
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
|
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
|
||||||
github.com/klauspost/compress v1.13.1 // indirect
|
github.com/klauspost/compress v1.13.1 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
||||||
github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353 // indirect
|
github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353 // indirect
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rymdport/portal v0.2.2 // indirect
|
|
||||||
github.com/stretchr/testify v1.8.4 // indirect
|
github.com/stretchr/testify v1.8.4 // indirect
|
||||||
|
github.com/tevino/abool v1.2.0 // indirect
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||||
github.com/xtgo/set v1.0.0 // indirect
|
github.com/xtgo/set v1.0.0 // indirect
|
||||||
github.com/yuin/goldmark v1.7.1 // indirect
|
github.com/yuin/goldmark v1.5.5 // indirect
|
||||||
go.opencensus.io v0.23.0 // indirect
|
go.opencensus.io v0.23.0 // indirect
|
||||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 // indirect
|
go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 // indirect
|
||||||
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect
|
golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda // indirect
|
||||||
golang.org/x/net v0.25.0 // indirect
|
golang.org/x/net v0.21.0 // indirect
|
||||||
golang.org/x/sys v0.20.0 // indirect
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||||
gonum.org/v1/gonum v0.14.0 // indirect
|
gonum.org/v1/gonum v0.14.0 // indirect
|
||||||
google.golang.org/protobuf v1.32.0 // indirect
|
google.golang.org/protobuf v1.32.0 // indirect
|
||||||
|
@ -79,4 +76,5 @@ require (
|
||||||
gorgonia.org/dawson v1.2.0 // indirect
|
gorgonia.org/dawson v1.2.0 // indirect
|
||||||
gorgonia.org/vecf32 v0.9.0 // indirect
|
gorgonia.org/vecf32 v0.9.0 // indirect
|
||||||
gorgonia.org/vecf64 v0.9.0 // indirect
|
gorgonia.org/vecf64 v0.9.0 // indirect
|
||||||
|
honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 // indirect
|
||||||
)
|
)
|
||||||
|
|
83
go.sum
83
go.sum
|
@ -37,15 +37,13 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
fyne.io/fyne/v2 v2.5.0 h1:lEjEIso0Vi4sJXYngIMoXOM6aUjqnPjK7pBpxRxG9aI=
|
fyne.io/fyne/v2 v2.4.5 h1:W6jpAEmLoBbKyBB+EXqI7GMJ7kLgHQWCa0wZHUV2VfQ=
|
||||||
fyne.io/fyne/v2 v2.5.0/go.mod h1:9D4oT3NWeG+MLi/lP7ItZZyujHC/qqMJpoGTAYX5Uqc=
|
fyne.io/fyne/v2 v2.4.5/go.mod h1:SlOgbca0y80cRObu/JOhxIJdIgtoW7aCyqUVlTMgs0Y=
|
||||||
fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg=
|
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e h1:Hvs+kW2VwCzNToF3FmnIAzmivNgrclwPgoUdVSrjkP8=
|
||||||
fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
|
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE=
|
||||||
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
|
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
|
||||||
git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc=
|
git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
|
||||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
|
github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
|
||||||
github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
|
github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
|
||||||
|
@ -124,19 +122,17 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
|
||||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
|
||||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8=
|
github.com/fredbi/uri v1.0.0 h1:s4QwUAZ8fz+mbTsukND+4V5f+mJ/wjaTokwstGUAemg=
|
||||||
github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4=
|
github.com/fredbi/uri v1.0.0/go.mod h1:1xC40RnIOGCaQzswaOvrzvG/3M3F0hyDVb3aO/1iGy0=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||||
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe h1:A/wiwvQ0CAjPkuJytaD+SsXkPU0asQ+guQEIg1BJGX4=
|
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe h1:A/wiwvQ0CAjPkuJytaD+SsXkPU0asQ+guQEIg1BJGX4=
|
||||||
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe/go.mod h1:d4clgH0/GrRwWjRzJJQXxT/h1TyuNSfF/X64zb/3Ggg=
|
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe/go.mod h1:d4clgH0/GrRwWjRzJJQXxT/h1TyuNSfF/X64zb/3Ggg=
|
||||||
github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a h1:ybgRdYvAHTn93HW79bLiBiJwVL4jVeyGQRZMgImoeWs=
|
github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 h1:+31CdF/okdokeFNoy9L/2PccG3JFidQT3ev64/r4pYU=
|
||||||
github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a/go.mod h1:gsGA2dotD4v0SR6PmPCYvS9JuOeMwAtmfvDE7mbYXMY=
|
github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504/go.mod h1:gLRWYfYnMA9TONeppRSikMdXlHQ97xVsPojddUv3b/E=
|
||||||
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 h1:hnLq+55b7Zh7/2IRzWCpiTcAvjv/P8ERF+N7+xXbZhk=
|
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 h1:hnLq+55b7Zh7/2IRzWCpiTcAvjv/P8ERF+N7+xXbZhk=
|
||||||
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2/go.mod h1:eO7W361vmlPOrykIg+Rsh1SZ3tQBaOsfzZhsIOb/Lm0=
|
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2/go.mod h1:eO7W361vmlPOrykIg+Rsh1SZ3tQBaOsfzZhsIOb/Lm0=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
@ -150,8 +146,9 @@ github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVin
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240306074159-ea2d69986ecb h1:S9I8pIVT5JHKDvmI1vQ0qs5fqxzUfhcZm/YbUC/8k1k=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240306074159-ea2d69986ecb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gota/gota v0.12.0/go.mod h1:UT+NsWpZC/FhaOyWb9Hui0jXg0Iq8e/YugZHTbyW/34=
|
github.com/go-gota/gota v0.12.0/go.mod h1:UT+NsWpZC/FhaOyWb9Hui0jXg0Iq8e/YugZHTbyW/34=
|
||||||
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
|
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
|
||||||
github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk=
|
github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk=
|
||||||
|
@ -249,8 +246,6 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
|
||||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
|
|
||||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
@ -266,6 +261,7 @@ github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfre
|
||||||
github.com/gorgonia/bindgen v0.0.0-20180812032444-09626750019e/go.mod h1:YzKk63P9jQHkwAo2rXHBv02yPxDzoQT2cBV0x5bGV/8=
|
github.com/gorgonia/bindgen v0.0.0-20180812032444-09626750019e/go.mod h1:YzKk63P9jQHkwAo2rXHBv02yPxDzoQT2cBV0x5bGV/8=
|
||||||
github.com/gorgonia/bindgen v0.0.0-20210223094355-432cd89e7765/go.mod h1:BLHSe436vhQKRfm6wxJgebeK4fDY+ER/8jV3vVH9yYU=
|
github.com/gorgonia/bindgen v0.0.0-20210223094355-432cd89e7765/go.mod h1:BLHSe436vhQKRfm6wxJgebeK4fDY+ER/8jV3vVH9yYU=
|
||||||
github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfIyATps4G2ai7/hLwLkc5TrPqONuXY=
|
github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfIyATps4G2ai7/hLwLkc5TrPqONuXY=
|
||||||
|
github.com/goxjs/glfw v0.0.0-20191126052801-d2efb5f20838/go.mod h1:oS8P8gVOT4ywTcjV6wZlOU4GuVFQ8F5328KY3MJ79CY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
|
@ -290,8 +286,6 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49 h1:Po+wkNdMmN+Zj1tDsJQy7mJlPlwGNQd9JZoPjObagf8=
|
|
||||||
github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49/go.mod h1:YiutDnxPRLk5DLUFj6Rw4pRBBURZY07GFr54NdV9mQg=
|
|
||||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
|
@ -309,6 +303,7 @@ github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
|
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
@ -337,10 +332,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||||
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
|
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
|
||||||
|
@ -351,8 +342,6 @@ github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuR
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
|
||||||
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
|
||||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -368,8 +357,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||||
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
|
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
|
||||||
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=
|
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/rymdport/portal v0.2.2 h1:P2Q/4k673zxdFAsbD8EESZ7psfuO6/4jNu6EDrDICkM=
|
|
||||||
github.com/rymdport/portal v0.2.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||||
|
@ -388,6 +375,7 @@ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS
|
||||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
|
||||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
@ -397,9 +385,12 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
|
github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
|
||||||
|
github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||||
|
@ -416,8 +407,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
||||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U=
|
github.com/yuin/goldmark v1.5.5 h1:IJznPe8wOzfIKETmMkd06F8nXkmlhaHqFRM9l1hAGsU=
|
||||||
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
github.com/yuin/goldmark v1.5.5/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||||
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||||
|
@ -452,8 +443,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
@ -487,8 +478,8 @@ golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeap
|
||||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||||
golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||||
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
||||||
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
|
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||||
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
@ -504,8 +495,8 @@ golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPI
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
golang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
|
golang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
|
||||||
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a h1:sYbmY3FwUWCBTodZL1S3JUuOvaW6kM2o+clDzzDNBWg=
|
golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda h1:O+EUvnBNPwI4eLthn8W5K+cS8zQZfgTABPLNm6Bna34=
|
||||||
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a/go.mod h1:Ede7gF0KGoHlj822RtphAHK1jLdrcuRBZg0sF1Q+SPc=
|
golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
@ -563,8 +554,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -644,10 +635,11 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
@ -662,8 +654,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -866,8 +858,8 @@ google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7
|
||||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
@ -875,7 +867,6 @@ gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@ -904,6 +895,8 @@ gorgonia.org/vecf32 v0.9.0/go.mod h1:NCc+5D2oxddRL11hd+pCB1PEyXWOyiQxfZ/1wwhOXCA
|
||||||
gorgonia.org/vecf64 v0.7.0/go.mod h1:1y4pmcSd+wh3phG+InwWQjYrqwyrtN9h27WLFVQfV1Q=
|
gorgonia.org/vecf64 v0.7.0/go.mod h1:1y4pmcSd+wh3phG+InwWQjYrqwyrtN9h27WLFVQfV1Q=
|
||||||
gorgonia.org/vecf64 v0.9.0 h1:bgZDP5x0OzBF64PjMGC3EvTdOoMEcmfAh1VCUnZFm1A=
|
gorgonia.org/vecf64 v0.9.0 h1:bgZDP5x0OzBF64PjMGC3EvTdOoMEcmfAh1VCUnZFm1A=
|
||||||
gorgonia.org/vecf64 v0.9.0/go.mod h1:hp7IOWCnRiVQKON73kkC/AUMtEXyf9kGlVrtPQ9ccVA=
|
gorgonia.org/vecf64 v0.9.0/go.mod h1:hp7IOWCnRiVQKON73kkC/AUMtEXyf9kGlVrtPQ9ccVA=
|
||||||
|
honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 h1:oomkgU6VaQDsV6qZby2uz1Lap0eXmku8+2em3A/l700=
|
||||||
|
honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2/go.mod h1:sUMDUKNB2ZcVjt92UnLy3cdGs+wDAcrPdV3JP6sVgA4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
|
@ -424,7 +424,7 @@ func setBuildMateProfilePage_Wealth(window fyne.Window, previousPage func()){
|
||||||
}
|
}
|
||||||
|
|
||||||
isLowerBoundHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
isLowerBoundHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setWealthIsLowerBoundExplainerPage(window, currentPage)
|
setWealthOrIncomeIsLowerBoundExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
isLowerBoundCheckRow := container.NewHBox(layout.NewSpacer(), isLowerBoundCheck, isLowerBoundHelpButton, layout.NewSpacer())
|
isLowerBoundCheckRow := container.NewHBox(layout.NewSpacer(), isLowerBoundCheck, isLowerBoundHelpButton, layout.NewSpacer())
|
||||||
|
|
||||||
|
|
156
gui/helpGui.go
156
gui/helpGui.go
|
@ -674,95 +674,45 @@ func setPolygenicDiseaseLocusRiskWeightProbabilityExplainerPage(window fyne.Wind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func setDiscreteTraitNeuralNetworkPredictionExplainerPage(window fyne.Window, previousPage func()){
|
func setTraitOutcomeScoresExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Neural Network Prediction")
|
title := getPageTitleCentered("Help - Outcome Scores")
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Discrete Trait Neural Network Prediction")
|
subtitle := getPageSubtitleCentered("Trait Outcome Scores")
|
||||||
|
|
||||||
description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.")
|
description1 := getLabelCentered("Person genetic analyses contain trait analyses.")
|
||||||
description2 := getLabelCentered("There are 2 discrete trait analysis methods: Neural Networks and Rules.")
|
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||||
description3 := getLabelCentered("Each trait can be analyzed by either rules or a neural network.")
|
description3 := getLabelCentered("Points are added to an outcome to represent a higher probability.")
|
||||||
description4 := getLabelCentered("Neural network prediction is calculated by inputing a genome's loci into a neural network.")
|
description4 := getLabelCentered("Points are subtracted from an outcome to represent a lower probability.")
|
||||||
description5 := getLabelCentered("Each trait has multiple outcomes, and the neural network predicts a single outcome.")
|
description5 := getLabelCentered("The more rules that are tested, the higher the accuracy of the result will be.")
|
||||||
description6 := getLabelCentered("The higher the quantity of tested loci, the more accurate the result is.")
|
|
||||||
description7 := getLabelCentered("The probability that a neural network's prediction is accurate is called its Confidence.")
|
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, description7)
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5)
|
||||||
|
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setOffspringDiscreteTraitNeuralNetworkPredictionExplainerPage(window fyne.Window, previousPage func()){
|
func setOffspringTraitOutcomeScoresExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Neural Network Prediction")
|
title := getPageTitleCentered("Help - Outcome Scores")
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Offspring Discrete Trait Neural Network Prediction")
|
subtitle := getPageSubtitleCentered("Offspring Trait Outcome Scores")
|
||||||
|
|
||||||
description1 := getLabelCentered("Couple genetic analyses contain discrete trait analyses.")
|
description1 := getLabelCentered("Couple genetic analyses contain trait analyses for the offspring.")
|
||||||
description2 := getLabelCentered("There are 2 discrete trait analysis methods: Neural Networks and Rules.")
|
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||||
description3 := getLabelCentered("Each trait can be analyzed by either rules or a neural network.")
|
description3 := getLabelCentered("Points are added to an outcome to represent a higher probability.")
|
||||||
description4 := getLabelCentered("Neural network prediction is calculated by inputing a genome's loci into a neural network.")
|
description4 := getLabelCentered("Points are subtracted from an outcome to represent a lower probability.")
|
||||||
description5 := getLabelCentered("Each trait has multiple outcomes, and the neural network predicts the probability of each outcome.")
|
description5 := getLabelCentered("The more rules that are tested, the higher the accuracy of the result will be.")
|
||||||
description6 := getLabelCentered("The higher the quantity of known loci, the more accurate the result is.")
|
|
||||||
description7 := getLabelCentered("The probability that a neural network's prediction is accurate is called its Confidence.")
|
|
||||||
description8 := getLabelCentered("For couples, the Confidence is the average of the confidence of 100 prospective offspring predictions.")
|
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, description7, description8)
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5)
|
||||||
|
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDiscreteTraitRulesPredictionExplainerPage(window fyne.Window, previousPage func()){
|
func setTraitRulesExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Rules Prediction")
|
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Discrete Trait Rules Prediction")
|
|
||||||
|
|
||||||
description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.")
|
|
||||||
description2 := getLabelCentered("There are 2 discrete trait analysis methods: Neural Networks and Rules.")
|
|
||||||
description3 := getLabelCentered("Each trait can be analyzed by either rules or a neural network.")
|
|
||||||
description4 := getLabelCentered("Rule prediction is calculated by testing many predictive rules.")
|
|
||||||
description5 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
|
||||||
description6 := getLabelCentered("Points are added to an outcome to represent a higher probability.")
|
|
||||||
description7 := getLabelCentered("Points are subtracted from an outcome to represent a lower probability.")
|
|
||||||
description8 := getLabelCentered("The more rules that are tested, the higher the accuracy of the result will be.")
|
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, description7, description8)
|
|
||||||
|
|
||||||
setPageContent(page, window)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setOffspringDiscreteTraitRulesPredictionExplainerPage(window fyne.Window, previousPage func()){
|
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Rules Prediction")
|
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Offspring Discrete Trait Rules Prediction")
|
|
||||||
|
|
||||||
description1 := getLabelCentered("Couple genetic analyses contain discrete trait analyses for the offspring.")
|
|
||||||
description2 := getLabelCentered("There are 2 discrete trait analysis methods: Neural Networks and Rules.")
|
|
||||||
description3 := getLabelCentered("Each trait can be analyzed by either rules or a neural network.")
|
|
||||||
description4 := getLabelCentered("Rule prediction is calculated by testing many predictive rules.")
|
|
||||||
description5 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
|
||||||
description6 := getLabelCentered("Points are added to an outcome to represent a higher probability.")
|
|
||||||
description7 := getLabelCentered("Points are subtracted from an outcome to represent a lower probability.")
|
|
||||||
description8 := getLabelCentered("The more rules that are tested, the higher the accuracy of the result will be.")
|
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, description7, description8)
|
|
||||||
|
|
||||||
setPageContent(page, window)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func setDiscreteTraitRulesExplainerPage(window fyne.Window, previousPage func()){
|
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Trait Rules")
|
title := getPageTitleCentered("Help - Trait Rules")
|
||||||
|
|
||||||
|
@ -770,8 +720,8 @@ func setDiscreteTraitRulesExplainerPage(window fyne.Window, previousPage func())
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Trait Rules")
|
subtitle := getPageSubtitleCentered("Trait Rules")
|
||||||
|
|
||||||
description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.")
|
description1 := getLabelCentered("Person genetic analyses contain trait analyses.")
|
||||||
description2 := getLabelCentered("Discrete traits has multiple outcomes, and each outcome has an associated score.")
|
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||||
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
||||||
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
||||||
description5 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
description5 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
||||||
|
@ -782,16 +732,16 @@ func setDiscreteTraitRulesExplainerPage(window fyne.Window, previousPage func())
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setOffspringDiscreteTraitRulesExplainerPage(window fyne.Window, previousPage func()){
|
func setOffspringTraitRulesExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Trait Rules")
|
title := getPageTitleCentered("Help - Trait Rules")
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Discrete Trait Rules")
|
subtitle := getPageSubtitleCentered("Trait Rules")
|
||||||
|
|
||||||
description1 := getLabelCentered("Offspring genetic analyses contain discrete trait analyses for a couple's offspring.")
|
description1 := getLabelCentered("Offspring genetic analyses contain trait analyses for a couple's offspring.")
|
||||||
description2 := getLabelCentered("Each discrete trait has multiple outcomes, and each outcome has an associated score.")
|
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||||
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
||||||
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
||||||
description5 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
description5 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
||||||
|
@ -803,15 +753,15 @@ func setOffspringDiscreteTraitRulesExplainerPage(window fyne.Window, previousPag
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDiscreteTraitQuantityOfRulesTestedExplainerPage(window fyne.Window, previousPage func()){
|
func setTraitNumberOfRulesTestedExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Quantity Of Rules Tested")
|
title := getPageTitleCentered("Help - Number Of Rules Tested")
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Quantity Of Trait Rules Tested")
|
subtitle := getPageSubtitleCentered("Number Of Trait Rules Tested")
|
||||||
|
|
||||||
description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.")
|
description1 := getLabelCentered("Person genetic analyses contain trait analyses.")
|
||||||
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||||
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represent the opposite.")
|
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represent the opposite.")
|
||||||
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
||||||
|
@ -825,13 +775,13 @@ func setDiscreteTraitQuantityOfRulesTestedExplainerPage(window fyne.Window, prev
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setOffspringDiscreteTraitQuantityOfRulesTestedExplainerPage(window fyne.Window, previousPage func()){
|
func setOffspringTraitNumberOfRulesTestedExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Quantity Of Rules Tested")
|
title := getPageTitleCentered("Help - Number Of Rules Tested")
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Offspring Trait Quantity Of Rules Tested")
|
subtitle := getPageSubtitleCentered("Offspring Trait Number Of Rules Tested")
|
||||||
|
|
||||||
description1 := getLabelCentered("Offspring genetic analyses contain trait analyses for a couple's offspring.")
|
description1 := getLabelCentered("Offspring genetic analyses contain trait analyses for a couple's offspring.")
|
||||||
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||||
|
@ -856,8 +806,8 @@ func setOffspringProbabilityOfPassingTraitRuleExplainerPage(window fyne.Window,
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Offspring Probability Of Passing Trait Rule")
|
subtitle := getPageSubtitleCentered("Offspring Probability Of Passing Trait Rule")
|
||||||
|
|
||||||
description1 := getLabelCentered("Offspring genetic analyses contain discrete trait analyses for a couple's offspring.")
|
description1 := getLabelCentered("Offspring genetic analyses contain trait analyses for a couple's offspring.")
|
||||||
description2 := getLabelCentered("Each discrete trait has multiple outcomes, and each outcome has an associated score.")
|
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||||
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
||||||
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
||||||
description5 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
description5 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
||||||
|
@ -871,7 +821,8 @@ func setOffspringProbabilityOfPassingTraitRuleExplainerPage(window fyne.Window,
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPersonPassesDiscreteTraitRuleExplainerPage(window fyne.Window, previousPage func()){
|
|
||||||
|
func setPersonPassesTraitRuleExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Trait Rules")
|
title := getPageTitleCentered("Help - Trait Rules")
|
||||||
|
|
||||||
|
@ -879,8 +830,8 @@ func setPersonPassesDiscreteTraitRuleExplainerPage(window fyne.Window, previousP
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Person Passes Trait Rule")
|
subtitle := getPageSubtitleCentered("Person Passes Trait Rule")
|
||||||
|
|
||||||
description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.")
|
description1 := getLabelCentered("Person genetic analyses contain trait analyses.")
|
||||||
description2 := getLabelCentered("Each discrete trait has multiple outcomes, and each outcome has an associated score.")
|
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||||
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
||||||
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
||||||
description5 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
description5 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
||||||
|
@ -891,7 +842,7 @@ func setPersonPassesDiscreteTraitRuleExplainerPage(window fyne.Window, previousP
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setGenomePassesDiscreteTraitRuleExplainerPage(window fyne.Window, previousPage func()){
|
func setGenomePassesTraitRuleExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Genome Passes Rule")
|
title := getPageTitleCentered("Help - Genome Passes Rule")
|
||||||
|
|
||||||
|
@ -899,23 +850,22 @@ func setGenomePassesDiscreteTraitRuleExplainerPage(window fyne.Window, previousP
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered("Genome Passes Trait Rule")
|
subtitle := getPageSubtitleCentered("Genome Passes Trait Rule")
|
||||||
|
|
||||||
description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.")
|
description1 := getLabelCentered("Person genetic analyses contain trait analyses.")
|
||||||
description2 := getLabelCentered("There are 2 discrete trait analysis methods: Rules and Neural Networks.")
|
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||||
description3 := getLabelCentered("For rule-based analyses, each trait's outcome has an associated score.")
|
description3 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
||||||
description4 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
||||||
description5 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
description5 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
||||||
description6 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
description6 := getLabelCentered("If a person passes a rule, its effects will be applied to their outcome(s).")
|
||||||
description7 := getLabelCentered("If a person passes a rule, its effects will be applied to their outcome(s).")
|
description7 := getLabelCentered("If a person has imported multiple genomes, each genome may or may not pass the rule.")
|
||||||
description8 := getLabelCentered("If a person has imported multiple genomes, each genome may or may not pass the rule.")
|
description8 := getLabelCentered("If one genome passes and another does not, it means that one genome has an invalid value.")
|
||||||
description9 := getLabelCentered("If one genome passes and another does not, it means that one genome has an invalid value.")
|
description9 := getLabelCentered("This happens because genome sequencing technology is not perfectly accurate.")
|
||||||
description10 := getLabelCentered("This happens because genome sequencing technology is not perfectly accurate.")
|
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, description7, description8, description9, description10)
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, description7, description8, description9)
|
||||||
|
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDiscreteTraitRuleOutcomeEffectsExplainerPage(window fyne.Window, previousPage func()){
|
func setTraitRuleOutcomeEffectsExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Outcome Effects")
|
title := getPageTitleCentered("Help - Outcome Effects")
|
||||||
|
|
||||||
|
@ -935,7 +885,7 @@ func setDiscreteTraitRuleOutcomeEffectsExplainerPage(window fyne.Window, previou
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func setWealthIsLowerBoundExplainerPage(window fyne.Window, previousPage func()){
|
func setWealthOrIncomeIsLowerBoundExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Is Lower Bound")
|
title := getPageTitleCentered("Help - Is Lower Bound")
|
||||||
|
|
||||||
|
@ -955,7 +905,7 @@ func setWealthIsLowerBoundExplainerPage(window fyne.Window, previousPage func())
|
||||||
|
|
||||||
|
|
||||||
func setMemoExplainerPage(window fyne.Window, previousPage func()){
|
func setMemoExplainerPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
title := getPageTitleCentered("Help - Memo")
|
title := getPageTitleCentered("Help - Memo")
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
@ -1076,7 +1026,7 @@ func setHostingHelpPage(window fyne.Window, previousPage func()){
|
||||||
description1 := getLabelCentered("Be a Seekia host.")
|
description1 := getLabelCentered("Be a Seekia host.")
|
||||||
description2 := getLabelCentered("Your computer will seed content to the network.")
|
description2 := getLabelCentered("Your computer will seed content to the network.")
|
||||||
description3 := getLabelCentered("You can choose to host as much or as little as you desire.")
|
description3 := getLabelCentered("You can choose to host as much or as little as you desire.")
|
||||||
|
|
||||||
//TODO: Add buttons to show more help
|
//TODO: Add buttons to show more help
|
||||||
//TODO: Describe how hosting works and associated risks
|
//TODO: Describe how hosting works and associated risks
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,6 @@ 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 "seekia/resources/geneticPredictionModels"
|
|
||||||
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"
|
||||||
|
@ -71,15 +70,11 @@ func setViewPersonGeneticAnalysisPage(window fyne.Window, personIdentifier strin
|
||||||
polygenicDiseasesButton := widget.NewButton("Polygenic Diseases", func(){
|
polygenicDiseasesButton := widget.NewButton("Polygenic Diseases", func(){
|
||||||
setViewPersonGeneticAnalysisPolygenicDiseasesPage(window, personIdentifier, analysisObject, currentPage)
|
setViewPersonGeneticAnalysisPolygenicDiseasesPage(window, personIdentifier, analysisObject, currentPage)
|
||||||
})
|
})
|
||||||
discreteTraitsButton := widget.NewButton("Discrete Traits", func(){
|
traitsButton := widget.NewButton("Traits", func(){
|
||||||
setViewPersonGeneticAnalysisDiscreteTraitsPage(window, personIdentifier, analysisObject, currentPage)
|
setViewPersonGeneticAnalysisTraitsPage(window, personIdentifier, analysisObject, currentPage)
|
||||||
})
|
|
||||||
numericTraitsButton := widget.NewButton("Numeric Traits", func(){
|
|
||||||
//TODO
|
|
||||||
showUnderConstructionDialog(window)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
categoryButtonsGrid := getContainerCentered(container.NewGridWithColumns(1, generalButton, monogenicDiseasesButton, polygenicDiseasesButton, discreteTraitsButton, numericTraitsButton))
|
categoryButtonsGrid := getContainerCentered(container.NewGridWithColumns(1, generalButton, monogenicDiseasesButton, polygenicDiseasesButton, traitsButton))
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), warningLabel1, warningLabel2, widget.NewSeparator(), personNameRow, numberOfAnalyzedGenomesRow, widget.NewSeparator(), categoryButtonsGrid)
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), warningLabel1, warningLabel2, widget.NewSeparator(), personNameRow, numberOfAnalyzedGenomesRow, widget.NewSeparator(), categoryButtonsGrid)
|
||||||
|
|
||||||
|
@ -99,7 +94,7 @@ func setViewPersonGeneticAnalysisMonogenicDiseasesPage(window fyne.Window, analy
|
||||||
|
|
||||||
getMonogenicDiseasesContainer := func()(*fyne.Container, error){
|
getMonogenicDiseasesContainer := func()(*fyne.Container, error){
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||||
if (err != nil){ return nil, err }
|
if (err != nil){ return nil, err }
|
||||||
|
|
||||||
// Outputs:
|
// Outputs:
|
||||||
|
@ -245,8 +240,8 @@ func setViewPersonGeneticAnalysisMonogenicDiseaseDetailsPage(window fyne.Window,
|
||||||
title := getPageTitleCentered("Viewing Genetic Analysis - " + diseaseName)
|
title := getPageTitleCentered("Viewing Genetic Analysis - " + diseaseName)
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
|
@ -285,6 +280,8 @@ func setViewPersonGeneticAnalysisMonogenicDiseaseDetailsPage(window fyne.Window,
|
||||||
totalNumberOfVariants := len(diseaseVariantsMap)
|
totalNumberOfVariants := len(diseaseVariantsMap)
|
||||||
totalNumberOfVariantsString := helpers.ConvertIntToString(totalNumberOfVariants)
|
totalNumberOfVariantsString := helpers.ConvertIntToString(totalNumberOfVariants)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
emptyLabelA := widget.NewLabel("")
|
emptyLabelA := widget.NewLabel("")
|
||||||
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
||||||
|
|
||||||
|
@ -739,7 +736,7 @@ func setViewPersonGeneticAnalysisMonogenicDiseaseVariantDetailsPage(window fyne.
|
||||||
|
|
||||||
getGenomesHaveVariantGrid := func()(*fyne.Container, error){
|
getGenomesHaveVariantGrid := func()(*fyne.Container, error){
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(geneticAnalysisObject)
|
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(geneticAnalysisObject)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
||||||
|
@ -897,7 +894,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso
|
||||||
|
|
||||||
getPolygenicDiseasesContainer := func()(*fyne.Container, error){
|
getPolygenicDiseasesContainer := func()(*fyne.Container, error){
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||||
if (err != nil){ return nil, err }
|
if (err != nil){ return nil, err }
|
||||||
|
|
||||||
// Outputs:
|
// Outputs:
|
||||||
|
@ -938,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{
|
||||||
|
@ -1018,7 +1015,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
|
@ -1057,6 +1054,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
||||||
totalNumberOfLoci := len(diseaseLociMap)
|
totalNumberOfLoci := len(diseaseLociMap)
|
||||||
totalNumberOfLociString := helpers.ConvertIntToString(totalNumberOfLoci)
|
totalNumberOfLociString := helpers.ConvertIntToString(totalNumberOfLoci)
|
||||||
|
|
||||||
|
|
||||||
emptyLabelA := widget.NewLabel("")
|
emptyLabelA := widget.NewLabel("")
|
||||||
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
||||||
|
|
||||||
|
@ -1089,7 +1087,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
||||||
viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setCombinedGenomesExplainerPage(window, currentPage)
|
setCombinedGenomesExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
genomeNameLabel := getBoldLabel(genomeName)
|
genomeNameLabel := getBoldLabel(genomeName)
|
||||||
genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer())
|
genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer())
|
||||||
|
|
||||||
|
@ -1098,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{
|
||||||
|
@ -1624,7 +1622,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window fyne.Wi
|
||||||
|
|
||||||
getGenomesLocusInfoGrid := func()(*fyne.Container, error){
|
getGenomesLocusInfoGrid := func()(*fyne.Container, error){
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(geneticAnalysisObject)
|
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(geneticAnalysisObject)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
||||||
|
@ -1767,19 +1765,19 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window fyne.Wi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func setViewPersonGeneticAnalysisDiscreteTraitsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, previousPage func()){
|
func setViewPersonGeneticAnalysisTraitsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, previousPage func()){
|
||||||
|
|
||||||
currentPage := func(){setViewPersonGeneticAnalysisDiscreteTraitsPage(window, personIdentifier, analysisObject, previousPage)}
|
currentPage := func(){setViewPersonGeneticAnalysisTraitsPage(window, personIdentifier, analysisObject, previousPage)}
|
||||||
|
|
||||||
title := getPageTitleCentered("Viewing Genetic Analysis - Discrete Traits")
|
title := getPageTitleCentered("Viewing Genetic Analysis - Traits")
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
|
||||||
description := getLabelCentered("Below is an analysis of the discrete traits for this person's genome.")
|
description := getLabelCentered("Below is an analysis of the traits for this person's genome.")
|
||||||
|
|
||||||
getTraitsContainer := func()(*fyne.Container, error){
|
getTraitsContainer := func()(*fyne.Container, error){
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||||
if (err != nil){ return nil, err }
|
if (err != nil){ return nil, err }
|
||||||
|
|
||||||
// Outputs:
|
// Outputs:
|
||||||
|
@ -1800,154 +1798,102 @@ func setViewPersonGeneticAnalysisDiscreteTraitsPage(window fyne.Window, personId
|
||||||
mainGenomeIdentifier, err := getMainGenomeIdentifier()
|
mainGenomeIdentifier, err := getMainGenomeIdentifier()
|
||||||
if (err != nil){ return nil, err }
|
if (err != nil){ return nil, err }
|
||||||
|
|
||||||
emptyLabel1 := widget.NewLabel("")
|
|
||||||
traitNameLabel := getItalicLabelCentered("Trait Name")
|
traitNameLabel := getItalicLabelCentered("Trait Name")
|
||||||
|
|
||||||
emptyLabel2 := widget.NewLabel("")
|
outcomeScoresLabel := getItalicLabelCentered("Outcome Scores")
|
||||||
predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome")
|
|
||||||
|
|
||||||
quantityOfLabel := getItalicLabelCentered("Quantity Of")
|
|
||||||
lociKnownLabel := getItalicLabelCentered("Loci Known")
|
|
||||||
|
|
||||||
emptyLabel3 := widget.NewLabel("")
|
|
||||||
conflictExistsLabel := getItalicLabelCentered("Conflict Exists?")
|
conflictExistsLabel := getItalicLabelCentered("Conflict Exists?")
|
||||||
|
|
||||||
emptyLabel4 := widget.NewLabel("")
|
emptyLabel := widget.NewLabel("")
|
||||||
emptyLabel5 := widget.NewLabel("")
|
|
||||||
|
|
||||||
traitNameColumn := container.NewVBox(emptyLabel1, traitNameLabel, widget.NewSeparator())
|
traitNameColumn := container.NewVBox(traitNameLabel, widget.NewSeparator())
|
||||||
predictedOutcomeColumn := container.NewVBox(emptyLabel2, predictedOutcomeLabel, widget.NewSeparator())
|
outcomeScoresColumn := container.NewVBox(outcomeScoresLabel, widget.NewSeparator())
|
||||||
quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator())
|
conflictExistsColumn := container.NewVBox(conflictExistsLabel, widget.NewSeparator())
|
||||||
conflictExistsColumn := container.NewVBox(emptyLabel3, conflictExistsLabel, widget.NewSeparator())
|
viewButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator())
|
||||||
viewButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator())
|
|
||||||
|
|
||||||
traitObjectsList, err := traits.GetTraitObjectsList()
|
traitObjectsList, err := traits.GetTraitObjectsList()
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
for _, traitObject := range traitObjectsList{
|
for _, traitObject := range traitObjectsList{
|
||||||
|
|
||||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
|
||||||
if (traitIsDiscreteOrNumeric != "Discrete"){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
traitName := traitObject.TraitName
|
traitName := traitObject.TraitName
|
||||||
traitLociList := traitObject.LociList
|
|
||||||
traitRulesList := traitObject.RulesList
|
traitRulesList := traitObject.RulesList
|
||||||
|
|
||||||
if (len(traitLociList) == 0 && len(traitRulesList) == 0){
|
if (len(traitRulesList) == 0){
|
||||||
// This trait does not have any rules or loci to analyze
|
// This trait does not have any rules
|
||||||
// We cannot analyze it yet
|
// We cannot analyze it yet
|
||||||
|
// We will add neural network prediction so we can predict these traits
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
traitOutcomeNamesList := traitObject.OutcomesList
|
||||||
|
|
||||||
traitNameText := getBoldLabelCentered(traitName)
|
_, anyTraitRuleTested, outcomeScoresMap, _, conflictExists, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(analysisObject, traitName, mainGenomeIdentifier)
|
||||||
|
|
||||||
neuralNetworkExists, neuralNetworkAnalysisExists, neuralNetworkPredictedOutcome, _, quantityOfLociKnown_NeuralNetwork, _, anyRulesExist, rulesAnalysisExists, _, rulesPredictedOutcomeExists, rulesPredictedOutcome, _, quantityOfLociKnown_Rules, conflictExists, err := readGeneticAnalysis.GetPersonDiscreteTraitInfoFromGeneticAnalysis(analysisObject, traitName, mainGenomeIdentifier)
|
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
if (neuralNetworkExists == false && anyRulesExist == false){
|
|
||||||
// We can't analyze this trait
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
getPredictionLabel := func()fyne.Widget{
|
// We add all of the columns except for the trait outcomes column, which may be multiple rows high
|
||||||
|
|
||||||
if (neuralNetworkExists == true){
|
|
||||||
|
|
||||||
if (neuralNetworkAnalysisExists == false){
|
|
||||||
result := getItalicLabel("Unknown")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
result := getBoldLabel(neuralNetworkPredictedOutcome)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
// anyRulesExist must be true
|
|
||||||
|
|
||||||
if (rulesAnalysisExists == false || rulesPredictedOutcomeExists == false){
|
|
||||||
result := getItalicLabel("Unknown")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
result := getBoldLabel(rulesPredictedOutcome)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
predictionLabel := getPredictionLabel()
|
|
||||||
|
|
||||||
predictionLabelCentered := getWidgetCentered(predictionLabel)
|
|
||||||
|
|
||||||
getQuantityOfLociKnown := func()int{
|
|
||||||
|
|
||||||
if (neuralNetworkExists == true){
|
|
||||||
|
|
||||||
return quantityOfLociKnown_NeuralNetwork
|
|
||||||
}
|
|
||||||
return quantityOfLociKnown_Rules
|
|
||||||
}
|
|
||||||
|
|
||||||
quantityOfLociKnown := getQuantityOfLociKnown()
|
|
||||||
|
|
||||||
getTotalQuantityOfLoci := func()int{
|
|
||||||
|
|
||||||
if (neuralNetworkExists == true){
|
|
||||||
|
|
||||||
totalQuantityOfLoci := len(traitLociList)
|
|
||||||
|
|
||||||
return totalQuantityOfLoci
|
|
||||||
}
|
|
||||||
|
|
||||||
traitLociList_Rules := traitObject.LociList_Rules
|
|
||||||
|
|
||||||
totalQuantityOfLoci := len(traitLociList_Rules)
|
|
||||||
|
|
||||||
return totalQuantityOfLoci
|
|
||||||
}
|
|
||||||
|
|
||||||
totalQuantityOfLoci := getTotalQuantityOfLoci()
|
|
||||||
|
|
||||||
quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown)
|
|
||||||
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
|
|
||||||
|
|
||||||
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
|
|
||||||
|
|
||||||
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
|
|
||||||
|
|
||||||
conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists)
|
conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists)
|
||||||
conflictExistsLabel := getBoldLabelCentered(conflictExistsString)
|
conflictExistsLabel := getBoldLabelCentered(conflictExistsString)
|
||||||
|
|
||||||
viewDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
viewDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
||||||
setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window, personIdentifier, analysisObject, traitName, currentPage)
|
setViewPersonGeneticAnalysisTraitDetailsPage(window, personIdentifier, analysisObject, traitName, currentPage)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
traitNameText := getBoldLabelCentered(traitName)
|
||||||
|
|
||||||
traitNameColumn.Add(traitNameText)
|
traitNameColumn.Add(traitNameText)
|
||||||
predictedOutcomeColumn.Add(predictionLabelCentered)
|
|
||||||
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
|
|
||||||
conflictExistsColumn.Add(conflictExistsLabel)
|
conflictExistsColumn.Add(conflictExistsLabel)
|
||||||
viewButtonsColumn.Add(viewDetailsButton)
|
viewButtonsColumn.Add(viewDetailsButton)
|
||||||
|
|
||||||
|
if (anyTraitRuleTested == false){
|
||||||
|
|
||||||
|
unknownTranslated := translate("Unknown")
|
||||||
|
unknownLabel := getBoldLabelCentered(unknownTranslated)
|
||||||
|
|
||||||
|
outcomeScoresColumn.Add(unknownLabel)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// We have to sort outcome names so they always show up in the same order
|
||||||
|
|
||||||
|
traitOutcomeNamesListSorted := helpers.CopyAndSortStringListToUnicodeOrder(traitOutcomeNamesList)
|
||||||
|
|
||||||
|
for index, outcomeName := range traitOutcomeNamesListSorted{
|
||||||
|
|
||||||
|
outcomeScore, exists := outcomeScoresMap[outcomeName]
|
||||||
|
if (exists == false){
|
||||||
|
return nil, errors.New("Outcome name not found in outcomeScoresMap: " + outcomeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
outcomeScoreString := helpers.ConvertIntToString(outcomeScore)
|
||||||
|
|
||||||
|
outcomeRow := getBoldLabelCentered(outcomeName + ": " + outcomeScoreString)
|
||||||
|
outcomeScoresColumn.Add(outcomeRow)
|
||||||
|
|
||||||
|
if (index > 0){
|
||||||
|
|
||||||
|
emptyLabelA := widget.NewLabel("")
|
||||||
|
emptyLabelB := widget.NewLabel("")
|
||||||
|
emptyLabelC := widget.NewLabel("")
|
||||||
|
|
||||||
|
traitNameColumn.Add(emptyLabelA)
|
||||||
|
conflictExistsColumn.Add(emptyLabelB)
|
||||||
|
viewButtonsColumn.Add(emptyLabelC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
traitNameColumn.Add(widget.NewSeparator())
|
traitNameColumn.Add(widget.NewSeparator())
|
||||||
predictedOutcomeColumn.Add(widget.NewSeparator())
|
outcomeScoresColumn.Add(widget.NewSeparator())
|
||||||
quantityOfLociKnownColumn.Add(widget.NewSeparator())
|
|
||||||
conflictExistsColumn.Add(widget.NewSeparator())
|
conflictExistsColumn.Add(widget.NewSeparator())
|
||||||
viewButtonsColumn.Add(widget.NewSeparator())
|
viewButtonsColumn.Add(widget.NewSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
outcomeScoresHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
//TODO
|
setTraitOutcomeScoresExplainerPage(window, currentPage)
|
||||||
showUnderConstructionDialog(window)
|
|
||||||
})
|
})
|
||||||
predictedOutcomeColumn.Add(predictedOutcomeHelpButton)
|
outcomeScoresColumn.Add(outcomeScoresHelpButton)
|
||||||
|
|
||||||
quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
traitsContainer := container.NewHBox(layout.NewSpacer(), traitNameColumn, outcomeScoresColumn)
|
||||||
//TODO
|
|
||||||
showUnderConstructionDialog(window)
|
|
||||||
})
|
|
||||||
quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton)
|
|
||||||
|
|
||||||
traitsContainer := container.NewHBox(layout.NewSpacer(), traitNameColumn, predictedOutcomeColumn, quantityOfLociKnownColumn)
|
|
||||||
|
|
||||||
if (multipleGenomesExist == true){
|
if (multipleGenomesExist == true){
|
||||||
|
|
||||||
|
@ -1977,15 +1923,16 @@ func setViewPersonGeneticAnalysisDiscreteTraitsPage(window fyne.Window, personId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, traitName string, previousPage func()){
|
|
||||||
|
|
||||||
currentPage := func(){setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window, personIdentifier, analysisObject, traitName, previousPage)}
|
func setViewPersonGeneticAnalysisTraitDetailsPage(window fyne.Window, personIdentifier string, analysisObject geneticAnalysis.PersonAnalysis, traitName string, previousPage func()){
|
||||||
|
|
||||||
|
currentPage := func(){setViewPersonGeneticAnalysisTraitDetailsPage(window, personIdentifier, analysisObject, traitName, previousPage)}
|
||||||
|
|
||||||
title := getPageTitleCentered("Viewing Genetic Analysis - " + traitName)
|
title := getPageTitleCentered("Viewing Genetic Analysis - " + traitName)
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
backButton := getBackButtonCentered(previousPage)
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
|
@ -2014,51 +1961,33 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe
|
||||||
traitInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
traitInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
||||||
setViewTraitDetailsPage(window, traitName, currentPage)
|
setViewTraitDetailsPage(window, traitName, currentPage)
|
||||||
})
|
})
|
||||||
traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitInfoButton, layout.NewSpacer())
|
traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitInfoButton, layout.NewSpacer())
|
||||||
|
|
||||||
neuralNetworkExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)
|
|
||||||
|
|
||||||
getGenomesContainer := func()(*fyne.Container, error){
|
getGenomesContainer := func()(*fyne.Container, error){
|
||||||
|
|
||||||
emptyLabel1 := widget.NewLabel("")
|
traitRulesMap, err := traits.GetTraitRulesMap(traitName)
|
||||||
|
if (err != nil){ return nil, err }
|
||||||
|
|
||||||
|
totalNumberOfRules := len(traitRulesMap)
|
||||||
|
totalNumberOfRulesString := helpers.ConvertIntToString(totalNumberOfRules)
|
||||||
|
|
||||||
|
emptyLabelA := widget.NewLabel("")
|
||||||
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
||||||
|
|
||||||
emptyLabel2 := widget.NewLabel("")
|
emptyLabelB := widget.NewLabel("")
|
||||||
predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome")
|
outcomeScoresLabel := getItalicLabelCentered("Outcome Scores")
|
||||||
|
|
||||||
emptyLabel3 := widget.NewLabel("")
|
numberOfLabel := getItalicLabelCentered("Number of")
|
||||||
predictionConfidenceLabel := getItalicLabelCentered("Prediction Confidence")
|
|
||||||
|
|
||||||
quantityOfLabel := getItalicLabelCentered("Quantity Of")
|
|
||||||
rulesTestedLabel := getItalicLabelCentered("Rules Tested")
|
rulesTestedLabel := getItalicLabelCentered("Rules Tested")
|
||||||
|
|
||||||
emptyLabel4 := widget.NewLabel("")
|
emptyLabelD := widget.NewLabel("")
|
||||||
emptyLabel5 := widget.NewLabel("")
|
emptyLabelE := widget.NewLabel("")
|
||||||
|
|
||||||
genomeNameColumn := container.NewVBox()
|
|
||||||
predictedOutcomeColumn := container.NewVBox()
|
|
||||||
neuralNetworkPredictionConfidenceColumn := container.NewVBox()
|
|
||||||
numberOfRulesTestedColumn := container.NewVBox(quantityOfLabel, rulesTestedLabel, widget.NewSeparator())
|
|
||||||
viewDetailsButtonsColumn := container.NewVBox()
|
|
||||||
|
|
||||||
if (neuralNetworkExists == false){
|
|
||||||
// We only need an extra header row if the numberOfRulesTested column is shown
|
|
||||||
genomeNameColumn.Add(emptyLabel1)
|
|
||||||
predictedOutcomeColumn.Add(emptyLabel2)
|
|
||||||
neuralNetworkPredictionConfidenceColumn.Add(emptyLabel3)
|
|
||||||
viewDetailsButtonsColumn.Add(emptyLabel4)
|
|
||||||
}
|
|
||||||
|
|
||||||
genomeNameColumn.Add(genomeNameLabel)
|
|
||||||
predictedOutcomeColumn.Add(predictedOutcomeLabel)
|
|
||||||
neuralNetworkPredictionConfidenceColumn.Add(predictionConfidenceLabel)
|
|
||||||
viewDetailsButtonsColumn.Add(emptyLabel5)
|
|
||||||
|
|
||||||
genomeNameColumn.Add(widget.NewSeparator())
|
|
||||||
predictedOutcomeColumn.Add(widget.NewSeparator())
|
|
||||||
neuralNetworkPredictionConfidenceColumn.Add(widget.NewSeparator())
|
|
||||||
viewDetailsButtonsColumn.Add(widget.NewSeparator())
|
|
||||||
|
|
||||||
|
genomeNameColumn := container.NewVBox(emptyLabelA, genomeNameLabel, widget.NewSeparator())
|
||||||
|
outcomeScoresColumn := container.NewVBox(emptyLabelB, outcomeScoresLabel, widget.NewSeparator())
|
||||||
|
numberOfRulesTestedColumn := container.NewVBox(numberOfLabel, rulesTestedLabel, widget.NewSeparator())
|
||||||
|
viewRulesButtonsColumn := container.NewVBox(emptyLabelD, emptyLabelE, widget.NewSeparator())
|
||||||
|
|
||||||
addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{
|
addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{
|
||||||
|
|
||||||
getGenomeNameCell := func()*fyne.Container{
|
getGenomeNameCell := func()*fyne.Container{
|
||||||
|
@ -2079,121 +2008,66 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe
|
||||||
|
|
||||||
genomeNameCell := getGenomeNameCell()
|
genomeNameCell := getGenomeNameCell()
|
||||||
|
|
||||||
neuralNetworkExists, neuralNetworkAnalysisExists, neuralNetworkPredictedOutcome, neuralNetworkPredictionConfidence, _, _, anyRulesExist, rulesAnalysisExists, _, rulesPredictedOutcomeExists, rulesPredictedOutcome, quantityOfRulesTested, _, _, err := readGeneticAnalysis.GetPersonDiscreteTraitInfoFromGeneticAnalysis(analysisObject, traitName, genomeIdentifier)
|
_, anyTraitRuleTested, outcomeScoresMap, numberOfRulesTested, _, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(analysisObject, traitName, genomeIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
if (neuralNetworkExists == false && anyRulesExist == false){
|
// We add all of the columns except for the trait rule column, which may be multiple rows high
|
||||||
// This trait is not analyzable
|
|
||||||
return errors.New("setViewPersonGeneticAnalysisTraitDetailsPage called with trait which cannot be analyzed via neural networks and traits.")
|
|
||||||
}
|
|
||||||
|
|
||||||
getPredictedOutcomeLabel := func()fyne.Widget{
|
genomeNumberOfRulesTestedString := helpers.ConvertIntToString(numberOfRulesTested)
|
||||||
|
numberOfRulesTestedLabel := getBoldLabelCentered(genomeNumberOfRulesTestedString + "/" + totalNumberOfRulesString)
|
||||||
|
|
||||||
if (neuralNetworkExists == true){
|
viewRulesButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
||||||
if (neuralNetworkAnalysisExists == false){
|
setViewPersonGenomeTraitRulesPage(window, analysisObject, traitName, genomeIdentifier, genomeName, currentPage)
|
||||||
|
|
||||||
predictedOutcomeLabel := getItalicLabel("Unknown")
|
|
||||||
|
|
||||||
return predictedOutcomeLabel
|
|
||||||
}
|
|
||||||
|
|
||||||
predictedOutcomeLabel := getBoldLabel(neuralNetworkPredictedOutcome)
|
|
||||||
|
|
||||||
return predictedOutcomeLabel
|
|
||||||
}
|
|
||||||
|
|
||||||
// anyRulesExist must be true
|
|
||||||
|
|
||||||
if (rulesAnalysisExists == false || rulesPredictedOutcomeExists == false){
|
|
||||||
|
|
||||||
predictedOutcomeLabel := getItalicLabel("Unknown")
|
|
||||||
return predictedOutcomeLabel
|
|
||||||
}
|
|
||||||
|
|
||||||
predictedOutcomeLabel := getBoldLabel(rulesPredictedOutcome)
|
|
||||||
|
|
||||||
return predictedOutcomeLabel
|
|
||||||
}
|
|
||||||
|
|
||||||
predictedOutcomeLabel := getPredictedOutcomeLabel()
|
|
||||||
|
|
||||||
predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel)
|
|
||||||
|
|
||||||
getNeuralNetworkConfidenceLabel := func()fyne.Widget{
|
|
||||||
|
|
||||||
if (neuralNetworkExists == false){
|
|
||||||
|
|
||||||
emptyLabel := widget.NewLabel("")
|
|
||||||
|
|
||||||
return emptyLabel
|
|
||||||
}
|
|
||||||
if (neuralNetworkAnalysisExists == false){
|
|
||||||
|
|
||||||
predictedOutcomeConfidenceLabel := getItalicLabel("Unknown")
|
|
||||||
|
|
||||||
return predictedOutcomeConfidenceLabel
|
|
||||||
}
|
|
||||||
|
|
||||||
neuralNetworkPredictionConfidenceString := helpers.ConvertIntToString(neuralNetworkPredictionConfidence)
|
|
||||||
predictedOutcomeConfidenceLabel := getBoldLabel(neuralNetworkPredictionConfidenceString + "%")
|
|
||||||
|
|
||||||
return predictedOutcomeConfidenceLabel
|
|
||||||
}
|
|
||||||
|
|
||||||
predictedOutcomeConfidenceLabel := getNeuralNetworkConfidenceLabel()
|
|
||||||
predictedOutcomeConfidenceLabelCentered := getWidgetCentered(predictedOutcomeConfidenceLabel)
|
|
||||||
|
|
||||||
getQuantityOfRulesTestedLabel := func()(fyne.Widget, error){
|
|
||||||
|
|
||||||
if (anyRulesExist == false){
|
|
||||||
|
|
||||||
emptyLabel := widget.NewLabel("")
|
|
||||||
return emptyLabel, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
traitRulesMap, err := traits.GetTraitRulesMap(traitName)
|
|
||||||
if (err != nil){ return nil, err }
|
|
||||||
|
|
||||||
totalNumberOfRules := len(traitRulesMap)
|
|
||||||
totalNumberOfRulesString := helpers.ConvertIntToString(totalNumberOfRules)
|
|
||||||
|
|
||||||
if (rulesAnalysisExists == false){
|
|
||||||
quantityOfRulesTestedLabel := getItalicLabel("0/" + totalNumberOfRulesString)
|
|
||||||
return quantityOfRulesTestedLabel, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
quantityOfRulesTestedString := helpers.ConvertIntToString(quantityOfRulesTested)
|
|
||||||
|
|
||||||
quantityOfRulesTestedLabel := getBoldLabel(quantityOfRulesTestedString + "/" + totalNumberOfRulesString)
|
|
||||||
|
|
||||||
return quantityOfRulesTestedLabel, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
quantityOfRulesTestedLabel, err := getQuantityOfRulesTestedLabel()
|
|
||||||
if (err != nil) { return err }
|
|
||||||
|
|
||||||
quantityOfRulesTestedLabelCentered := getWidgetCentered(quantityOfRulesTestedLabel)
|
|
||||||
|
|
||||||
viewDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
||||||
if (neuralNetworkExists == true){
|
|
||||||
//TODO
|
|
||||||
showUnderConstructionDialog(window)
|
|
||||||
} else {
|
|
||||||
setViewPersonGenomeDiscreteTraitRulesPage(window, analysisObject, traitName, genomeIdentifier, genomeName, currentPage)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
genomeNameColumn.Add(genomeNameCell)
|
genomeNameColumn.Add(genomeNameCell)
|
||||||
predictedOutcomeColumn.Add(predictedOutcomeLabelCentered)
|
numberOfRulesTestedColumn.Add(numberOfRulesTestedLabel)
|
||||||
neuralNetworkPredictionConfidenceColumn.Add(predictedOutcomeConfidenceLabelCentered)
|
viewRulesButtonsColumn.Add(viewRulesButton)
|
||||||
numberOfRulesTestedColumn.Add(quantityOfRulesTestedLabelCentered)
|
|
||||||
viewDetailsButtonsColumn.Add(viewDetailsButton)
|
|
||||||
|
|
||||||
|
if (anyTraitRuleTested == false){
|
||||||
|
|
||||||
|
unknownTranslated := translate("Unknown")
|
||||||
|
unknownLabel := getBoldLabelCentered(unknownTranslated)
|
||||||
|
|
||||||
|
outcomeScoresColumn.Add(unknownLabel)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// We have to sort the outcome names so they always show up in the same order
|
||||||
|
|
||||||
|
outcomeNamesList := helpers.GetListOfMapKeys(outcomeScoresMap)
|
||||||
|
|
||||||
|
helpers.SortStringListToUnicodeOrder(outcomeNamesList)
|
||||||
|
|
||||||
|
for index, outcomeName := range outcomeNamesList{
|
||||||
|
|
||||||
|
outcomeScore, exists := outcomeScoresMap[outcomeName]
|
||||||
|
if (exists == false){
|
||||||
|
return errors.New("Outcome name not found in outcome scores map after being found already: " + outcomeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
outcomeScoreString := helpers.ConvertIntToString(outcomeScore)
|
||||||
|
|
||||||
|
outcomeRow := getBoldLabelCentered(outcomeName + ": " + outcomeScoreString)
|
||||||
|
outcomeScoresColumn.Add(outcomeRow)
|
||||||
|
|
||||||
|
if (index > 0){
|
||||||
|
|
||||||
|
emptyLabelA := widget.NewLabel("")
|
||||||
|
emptyLabelB := widget.NewLabel("")
|
||||||
|
emptyLabelC := widget.NewLabel("")
|
||||||
|
|
||||||
|
genomeNameColumn.Add(emptyLabelA)
|
||||||
|
numberOfRulesTestedColumn.Add(emptyLabelB)
|
||||||
|
viewRulesButtonsColumn.Add(emptyLabelC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
genomeNameColumn.Add(widget.NewSeparator())
|
genomeNameColumn.Add(widget.NewSeparator())
|
||||||
predictedOutcomeColumn.Add(widget.NewSeparator())
|
outcomeScoresColumn.Add(widget.NewSeparator())
|
||||||
neuralNetworkPredictionConfidenceColumn.Add(widget.NewSeparator())
|
|
||||||
numberOfRulesTestedColumn.Add(widget.NewSeparator())
|
numberOfRulesTestedColumn.Add(widget.NewSeparator())
|
||||||
viewDetailsButtonsColumn.Add(widget.NewSeparator())
|
viewRulesButtonsColumn.Add(widget.NewSeparator())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -2238,41 +2112,17 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe
|
||||||
if (err != nil){ return nil, err }
|
if (err != nil){ return nil, err }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (neuralNetworkExists == true){
|
outcomeScoresHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
|
setTraitOutcomeScoresExplainerPage(window, currentPage)
|
||||||
neuralNetworksHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
|
||||||
setDiscreteTraitNeuralNetworkPredictionExplainerPage(window, currentPage)
|
|
||||||
})
|
|
||||||
predictedOutcomeColumn.Add(neuralNetworksHelpButton)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
rulesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
|
||||||
setDiscreteTraitRulesPredictionExplainerPage(window, currentPage)
|
|
||||||
})
|
|
||||||
predictedOutcomeColumn.Add(rulesHelpButton)
|
|
||||||
}
|
|
||||||
|
|
||||||
neuralNetworkConfidenceHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
|
||||||
showUnderConstructionDialog(window)
|
|
||||||
//TODO
|
|
||||||
})
|
})
|
||||||
neuralNetworkPredictionConfidenceColumn.Add(neuralNetworkConfidenceHelpButton)
|
outcomeScoresColumn.Add(outcomeScoresHelpButton)
|
||||||
|
|
||||||
numberOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
numberOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
|
setTraitNumberOfRulesTestedExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
numberOfRulesTestedColumn.Add(numberOfRulesTestedHelpButton)
|
numberOfRulesTestedColumn.Add(numberOfRulesTestedHelpButton)
|
||||||
|
|
||||||
genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, predictedOutcomeColumn)
|
genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, outcomeScoresColumn, numberOfRulesTestedColumn, viewRulesButtonsColumn, layout.NewSpacer())
|
||||||
|
|
||||||
if (neuralNetworkExists == true){
|
|
||||||
genomesContainer.Add(neuralNetworkPredictionConfidenceColumn)
|
|
||||||
} else {
|
|
||||||
genomesContainer.Add(numberOfRulesTestedColumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
genomesContainer.Add(viewDetailsButtonsColumn)
|
|
||||||
genomesContainer.Add(layout.NewSpacer())
|
|
||||||
|
|
||||||
return genomesContainer, nil
|
return genomesContainer, nil
|
||||||
}
|
}
|
||||||
|
@ -2290,12 +2140,12 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Ths function provides a page to view the discrete trait rules for a particular genome from a genetic analysis
|
// Ths function provides a page to view the trait rules for a particular genome from a genetic analysis
|
||||||
func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, genomeIdentifier [16]byte, genomeName string, previousPage func()){
|
func setViewPersonGenomeTraitRulesPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, genomeIdentifier [16]byte, genomeName string, previousPage func()){
|
||||||
|
|
||||||
setLoadingScreen(window, "Loading Trait Rules", "Loading trait rules...")
|
setLoadingScreen(window, "Loading Trait Rules", "Loading trait rules...")
|
||||||
|
|
||||||
currentPage := func(){setViewPersonGenomeDiscreteTraitRulesPage(window, geneticAnalysisObject, traitName, genomeIdentifier, genomeName, previousPage)}
|
currentPage := func(){setViewPersonGenomeTraitRulesPage(window, geneticAnalysisObject, traitName, genomeIdentifier, genomeName, previousPage)}
|
||||||
|
|
||||||
title := getPageTitleCentered("View Trait Rules - " + traitName)
|
title := getPageTitleCentered("View Trait Rules - " + traitName)
|
||||||
|
|
||||||
|
@ -2303,7 +2153,7 @@ func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalys
|
||||||
|
|
||||||
description1 := widget.NewLabel("Below are the trait rule results for this genome.")
|
description1 := widget.NewLabel("Below are the trait rule results for this genome.")
|
||||||
rulesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
rulesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setDiscreteTraitRulesExplainerPage(window, currentPage)
|
setTraitRulesExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
description1Row := container.NewHBox(layout.NewSpacer(), description1, rulesHelpButton, layout.NewSpacer())
|
description1Row := container.NewHBox(layout.NewSpacer(), description1, rulesHelpButton, layout.NewSpacer())
|
||||||
|
|
||||||
|
@ -2345,7 +2195,7 @@ func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalys
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleStatusIsKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
ruleStatusIsKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
||||||
if (err != nil){
|
if (err != nil){
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
|
@ -2371,7 +2221,7 @@ func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalys
|
||||||
rulesTestedLabel := widget.NewLabel("Rules Tested:")
|
rulesTestedLabel := widget.NewLabel("Rules Tested:")
|
||||||
rulesTestedText := getBoldLabel(numberOfRulesTestedString + "/" + totalNumberOfRulesString)
|
rulesTestedText := getBoldLabel(numberOfRulesTestedString + "/" + totalNumberOfRulesString)
|
||||||
rulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
rulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
|
setTraitNumberOfRulesTestedExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
rulesTestedRow := container.NewHBox(layout.NewSpacer(), rulesTestedLabel, rulesTestedText, rulesTestedHelpButton, layout.NewSpacer())
|
rulesTestedRow := container.NewHBox(layout.NewSpacer(), rulesTestedLabel, rulesTestedText, rulesTestedHelpButton, layout.NewSpacer())
|
||||||
|
@ -2395,7 +2245,7 @@ func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalys
|
||||||
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
|
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
|
||||||
if (err != nil){ return err }
|
if (err != nil){ return err }
|
||||||
|
|
||||||
ruleStatusIsKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
ruleStatusIsKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
getGenomePassesRuleText := func()string{
|
getGenomePassesRuleText := func()string{
|
||||||
|
@ -2417,7 +2267,7 @@ func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalys
|
||||||
// We do this because the rule effects column may be multiple rows tall
|
// We do this because the rule effects column may be multiple rows tall
|
||||||
|
|
||||||
viewRuleButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
viewRuleButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
||||||
setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window, geneticAnalysisObject, traitName, ruleIdentifier, currentPage)
|
setViewPersonGeneticAnalysisTraitRuleDetailsPage(window, geneticAnalysisObject, traitName, ruleIdentifier, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
ruleIdentifierColumn.Add(ruleIdentifierLabel)
|
ruleIdentifierColumn.Add(ruleIdentifierLabel)
|
||||||
|
@ -2502,12 +2352,12 @@ func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalys
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleEffectsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
ruleEffectsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setDiscreteTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
setTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
ruleEffectsColumn.Add(ruleEffectsHelpButton)
|
ruleEffectsColumn.Add(ruleEffectsHelpButton)
|
||||||
|
|
||||||
genomePassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
genomePassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setGenomePassesDiscreteTraitRuleExplainerPage(window, currentPage)
|
setGenomePassesTraitRuleExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
genomePassesRuleColumn.Add(genomePassesRuleHelpButton)
|
genomePassesRuleColumn.Add(genomePassesRuleHelpButton)
|
||||||
|
@ -2531,9 +2381,9 @@ func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalys
|
||||||
|
|
||||||
// This function provides a page to view the details of a specific trait rule from a person genetic analysis
|
// This function provides a page to view the details of a specific trait rule from a person genetic analysis
|
||||||
// The page will show the rule details for all of the person's genomes
|
// The page will show the rule details for all of the person's genomes
|
||||||
func setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, ruleIdentifier [3]byte, previousPage func()){
|
func setViewPersonGeneticAnalysisTraitRuleDetailsPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, ruleIdentifier [3]byte, previousPage func()){
|
||||||
|
|
||||||
currentPage := func(){setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window, geneticAnalysisObject, traitName, ruleIdentifier, previousPage)}
|
currentPage := func(){setViewPersonGeneticAnalysisTraitRuleDetailsPage(window, geneticAnalysisObject, traitName, ruleIdentifier, previousPage)}
|
||||||
|
|
||||||
title := getPageTitleCentered("Trait Rule Details - " + traitName)
|
title := getPageTitleCentered("Trait Rule Details - " + traitName)
|
||||||
|
|
||||||
|
@ -2546,13 +2396,13 @@ func setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window fyne.Window
|
||||||
ruleIdentifierLabel := widget.NewLabel("Rule Identifier:")
|
ruleIdentifierLabel := widget.NewLabel("Rule Identifier:")
|
||||||
ruleIdentifierText := getBoldLabel(ruleIdentifierHex)
|
ruleIdentifierText := getBoldLabel(ruleIdentifierHex)
|
||||||
ruleInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
ruleInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
||||||
setViewDiscreteTraitRuleDetailsPage(window, traitName, ruleIdentifierHex, currentPage)
|
setViewTraitRuleDetailsPage(window, traitName, ruleIdentifierHex, currentPage)
|
||||||
})
|
})
|
||||||
ruleIdentifierRow := container.NewHBox(layout.NewSpacer(), ruleIdentifierLabel, ruleIdentifierText, ruleInfoButton, layout.NewSpacer())
|
ruleIdentifierRow := container.NewHBox(layout.NewSpacer(), ruleIdentifierLabel, ruleIdentifierText, ruleInfoButton, layout.NewSpacer())
|
||||||
|
|
||||||
getGenomesRuleInfoGrid := func()(*fyne.Container, error){
|
getGenomesRuleInfoGrid := func()(*fyne.Container, error){
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(geneticAnalysisObject)
|
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(geneticAnalysisObject)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
||||||
|
@ -2563,7 +2413,7 @@ func setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window fyne.Window
|
||||||
|
|
||||||
addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{
|
addGenomeRow := func(genomeName string, genomeIdentifier [16]byte, isACombinedGenome bool)error{
|
||||||
|
|
||||||
genomeRuleStatusKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
genomeRuleStatusKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
getGenomePassesRuleText := func()string{
|
getGenomePassesRuleText := func()string{
|
||||||
|
@ -2651,7 +2501,7 @@ func setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window fyne.Window
|
||||||
}
|
}
|
||||||
|
|
||||||
genomePassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
genomePassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setGenomePassesDiscreteTraitRuleExplainerPage(window, currentPage)
|
setGenomePassesTraitRuleExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
genomePassesRuleColumn.Add(genomePassesRuleHelpButton)
|
genomePassesRuleColumn.Add(genomePassesRuleHelpButton)
|
||||||
|
|
||||||
|
|
|
@ -510,7 +510,7 @@ func setViewTraitDetailsPage(window fyne.Window, traitName string, previousPage
|
||||||
}
|
}
|
||||||
|
|
||||||
traitDescription := traitObject.TraitDescription
|
traitDescription := traitObject.TraitDescription
|
||||||
traitReferencesMap := traitObject.ReferencesMap
|
traitReferencesMap := traitObject.References
|
||||||
|
|
||||||
traitNameLabel := widget.NewLabel("Trait Name:")
|
traitNameLabel := widget.NewLabel("Trait Name:")
|
||||||
traitNameText := getBoldLabel(traitName)
|
traitNameText := getBoldLabel(traitName)
|
||||||
|
@ -538,9 +538,9 @@ func setViewTraitDetailsPage(window fyne.Window, traitName string, previousPage
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setViewDiscreteTraitRuleDetailsPage(window fyne.Window, traitName string, ruleIdentifier string, previousPage func()){
|
func setViewTraitRuleDetailsPage(window fyne.Window, traitName string, ruleIdentifier string, previousPage func()){
|
||||||
|
|
||||||
currentPage := func(){setViewDiscreteTraitRuleDetailsPage(window, traitName, ruleIdentifier, previousPage)}
|
currentPage := func(){setViewTraitRuleDetailsPage(window, traitName, ruleIdentifier, previousPage)}
|
||||||
|
|
||||||
title := getPageTitleCentered("Viewing Rule Details")
|
title := getPageTitleCentered("Viewing Rule Details")
|
||||||
|
|
||||||
|
@ -561,7 +561,7 @@ func setViewDiscreteTraitRuleDetailsPage(window fyne.Window, traitName string, r
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleOutcomePointsMap := traitRuleObject.OutcomePointsMap
|
ruleOutcomePointsMap := traitRuleObject.OutcomePointsMap
|
||||||
ruleReferencesMap := traitRuleObject.ReferencesMap
|
ruleReferencesMap := traitRuleObject.References
|
||||||
|
|
||||||
viewReferencesButton := getWidgetCentered(widget.NewButtonWithIcon("View References", theme.ListIcon(), func(){
|
viewReferencesButton := getWidgetCentered(widget.NewButtonWithIcon("View References", theme.ListIcon(), func(){
|
||||||
setViewGeneticAnalysisReferencesPage(window, "Rule", ruleReferencesMap, currentPage)
|
setViewGeneticAnalysisReferencesPage(window, "Rule", ruleReferencesMap, currentPage)
|
||||||
|
@ -605,7 +605,7 @@ func setViewDiscreteTraitRuleDetailsPage(window fyne.Window, traitName string, r
|
||||||
}
|
}
|
||||||
|
|
||||||
outcomeEffectHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
outcomeEffectHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setDiscreteTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
setTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
outcomeEffectColumn.Add(outcomeEffectHelpButton)
|
outcomeEffectColumn.Add(outcomeEffectHelpButton)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ import "fyne.io/fyne/v2/widget"
|
||||||
|
|
||||||
import "seekia/resources/worldLanguages"
|
import "seekia/resources/worldLanguages"
|
||||||
import "seekia/resources/worldLocations"
|
import "seekia/resources/worldLocations"
|
||||||
import "seekia/resources/geneticPredictionModels"
|
|
||||||
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"
|
||||||
|
@ -1271,7 +1270,7 @@ func setViewUserProfilePage_Category(window fyne.Window, profileIsMine bool, cat
|
||||||
})
|
})
|
||||||
|
|
||||||
geneticTraitsButton := widget.NewButton("Genetic Traits", func(){
|
geneticTraitsButton := widget.NewButton("Genetic Traits", func(){
|
||||||
setViewMateProfilePage_GeneticTraits(window, getAnyUserProfileAttributeFunction, currentPage)
|
setViewMateProfilePage_GeneticTraits(window, "Offspring", getAnyUserProfileAttributeFunction, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
buttonsGrid := getContainerCentered(container.NewGridWithColumns(2, racialSimilarityButton, totalDiseaseRiskButton, ancestryCompositionButton, monogenicDiseasesButton, haplogroupsButton, polygenicDiseasesButton, neanderthalVariantsButton, geneticTraitsButton))
|
buttonsGrid := getContainerCentered(container.NewGridWithColumns(2, racialSimilarityButton, totalDiseaseRiskButton, ancestryCompositionButton, monogenicDiseasesButton, haplogroupsButton, polygenicDiseasesButton, neanderthalVariantsButton, geneticTraitsButton))
|
||||||
|
@ -2098,9 +2097,9 @@ func setViewMateProfilePage_RacialSimilarity(window fyne.Window, getAnyUserProfi
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
traitLociList := traitObject.LociList
|
traitLociList := traitObject.LociList
|
||||||
quantityOfTraitLoci := len(traitLociList)
|
numberOfTraitLoci := len(traitLociList)
|
||||||
|
|
||||||
quantityOfTraitLociString := helpers.ConvertIntToString(quantityOfTraitLoci)
|
numberOfTraitLociString := helpers.ConvertIntToString(numberOfTraitLoci)
|
||||||
|
|
||||||
geneticSimilarityIsKnown, _, attributeValue, err := getAnyUserProfileAttributeFunction(geneticSimilarityAttributeName)
|
geneticSimilarityIsKnown, _, attributeValue, err := getAnyUserProfileAttributeFunction(geneticSimilarityAttributeName)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
@ -2109,11 +2108,11 @@ func setViewMateProfilePage_RacialSimilarity(window fyne.Window, getAnyUserProfi
|
||||||
|
|
||||||
geneticSimilarityColumn.Add(unknownLabel)
|
geneticSimilarityColumn.Add(unknownLabel)
|
||||||
|
|
||||||
quantityOfTestedLociText := "0/" + quantityOfTraitLociString
|
numberOfTestedLociText := "0/" + numberOfTraitLociString
|
||||||
|
|
||||||
quantityOfTestedLociLabel := getBoldLabelCentered(quantityOfTestedLociText)
|
numberOfTestedLociLabel := getBoldLabelCentered(numberOfTestedLociText)
|
||||||
|
|
||||||
numberOfTestedLociColumn.Add(quantityOfTestedLociLabel)
|
numberOfTestedLociColumn.Add(numberOfTestedLociLabel)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
similarityFormatted := attributeValue + "%"
|
similarityFormatted := attributeValue + "%"
|
||||||
|
@ -2148,7 +2147,7 @@ func setViewMateProfilePage_RacialSimilarity(window fyne.Window, getAnyUserProfi
|
||||||
|
|
||||||
numberOfTestedLociString := helpers.ConvertIntToString(numberOfTestedLoci)
|
numberOfTestedLociString := helpers.ConvertIntToString(numberOfTestedLoci)
|
||||||
|
|
||||||
numberOfTestedLociLabelText := numberOfTestedLociString + "/" + quantityOfTraitLociString
|
numberOfTestedLociLabelText := numberOfTestedLociString + "/" + numberOfTraitLociString
|
||||||
|
|
||||||
numberOfTestedLociLabel := getBoldLabelCentered(numberOfTestedLociLabelText)
|
numberOfTestedLociLabel := getBoldLabelCentered(numberOfTestedLociLabelText)
|
||||||
|
|
||||||
|
@ -2960,25 +2959,24 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -map[int64]locusValue.LocusValue
|
// -map[int64]locusValue.LocusValue
|
||||||
// -error
|
// -error
|
||||||
getMyGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
getMyDiseaseLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
||||||
|
|
||||||
if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){
|
if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){
|
||||||
emptyMap := make(map[int64]locusValue.LocusValue)
|
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||||
return emptyMap, nil
|
return emptyMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myAnalysisObject)
|
anyMyLociValuesExist, _, _, myDiseaseLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myAnalysisObject, diseaseName, myGenomeIdentifier)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
if (anyMyLociValuesExist == false){
|
||||||
myGenomeLocusValuesMap, exists := myGenomesMap[myGenomeIdentifier]
|
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||||
if (exists == false){
|
return emptyMap, nil
|
||||||
return nil, errors.New("GetMyChosenMateGeneticAnalysis returning analysis which is missing genome with myGenomeIdentifier.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return myGenomeLocusValuesMap, nil
|
return myDiseaseLocusValuesMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
myGenomeLocusValuesMap, err := getMyGenomeLocusValuesMap()
|
myDiseaseLocusValuesMap, err := getMyDiseaseLocusValuesMap()
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
// Map Structure: Locus rsID -> Locus Value
|
// Map Structure: Locus rsID -> Locus Value
|
||||||
|
@ -3033,7 +3031,7 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
||||||
userDiseaseRiskScoreString, err := getUserDiseaseRiskScoreString()
|
userDiseaseRiskScoreString, err := getUserDiseaseRiskScoreString()
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
anyOffspringLociTested, offspringDiseaseRiskScore, offspringNumberOfLociTested, _, offspringSampleRiskScoresList, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo(diseaseLociList, myGenomeLocusValuesMap, userDiseaseLocusValuesMap)
|
anyOffspringLociTested, offspringDiseaseRiskScore, offspringNumberOfLociTested, _, offspringSampleRiskScoresList, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo(diseaseLociList, myDiseaseLocusValuesMap, userDiseaseLocusValuesMap)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
getOffspringDiseaseRiskScoreFormatted := func()(string, error){
|
getOffspringDiseaseRiskScoreFormatted := func()(string, error){
|
||||||
|
@ -3174,7 +3172,7 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
||||||
// Outputs:
|
// Outputs:
|
||||||
// -map[int64]locusValue.LocusValue: Map Structure: Locus rsID -> Locus Value
|
// -map[int64]locusValue.LocusValue: Map Structure: Locus rsID -> Locus Value
|
||||||
// -error
|
// -error
|
||||||
getMyGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, 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 (err != nil) { return nil, err }
|
||||||
|
@ -3185,18 +3183,17 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
||||||
return emptyMap, nil
|
return emptyMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myAnalysisObject)
|
anyLocusValuesExist, _, _, myLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myAnalysisObject, diseaseName, myGenomeIdentifier)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
if (anyLocusValuesExist == false){
|
||||||
myGenomeLocusValuesMap, exists := myGenomesMap[myGenomeIdentifier]
|
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||||
if (exists == false){
|
return emptyMap, nil
|
||||||
return nil, errors.New("GetMyChosenMateGeneticAnalysis returning analysis which is missing genome with myGenomeIdentifier.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return myGenomeLocusValuesMap, nil
|
return myLocusValuesMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
myGenomeLocusValuesMap, err := getMyGenomeLocusValuesMap()
|
myDiseaseLocusValuesMap, err := getMyDiseaseLocusValuesMap()
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
|
@ -3251,7 +3248,7 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
anyOffspringLociTested, _, offspringNumberOfLociTested, offspringLociInfoMap, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo(diseaseLocusObjectsList, myGenomeLocusValuesMap, userDiseaseLocusValuesMap)
|
anyOffspringLociTested, _, offspringNumberOfLociTested, offspringLociInfoMap, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo(diseaseLocusObjectsList, myDiseaseLocusValuesMap, userDiseaseLocusValuesMap)
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
|
@ -3516,9 +3513,9 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setViewMateProfilePage_GeneticTraits(window fyne.Window, getAnyUserProfileAttributeFunction func(string)(bool, int, string, error), previousPage func()){
|
func setViewMateProfilePage_GeneticTraits(window fyne.Window, userOrOffspring string, getAnyUserProfileAttributeFunction func(string)(bool, int, string, error), previousPage func()){
|
||||||
|
|
||||||
currentPage := func(){setViewMateProfilePage_GeneticTraits(window, getAnyUserProfileAttributeFunction, previousPage)}
|
currentPage := func(){setViewMateProfilePage_GeneticTraits(window, userOrOffspring, getAnyUserProfileAttributeFunction, previousPage)}
|
||||||
|
|
||||||
title := getPageTitleCentered(translate("View Profile - Physical"))
|
title := getPageTitleCentered(translate("View Profile - Physical"))
|
||||||
|
|
||||||
|
@ -3526,46 +3523,7 @@ func setViewMateProfilePage_GeneticTraits(window fyne.Window, getAnyUserProfileA
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered(translate("Genetic Traits"))
|
subtitle := getPageSubtitleCentered(translate("Genetic Traits"))
|
||||||
|
|
||||||
description1 := getLabelCentered("Choose if you want to view Discrete traits or Numeric traits.")
|
description1 := getLabelCentered("Below is the genetic trait analysis for this user.")
|
||||||
description2 := getLabelCentered("Discrete traits are traits which have discrete outcomes, such as Eye Color")
|
|
||||||
description3 := getLabelCentered("Numeric traits are traits with numeric outcomes, such as Height.")
|
|
||||||
|
|
||||||
discreteTraitsButton := widget.NewButton("Discrete Traits", func(){
|
|
||||||
setViewMateProfilePage_DiscreteGeneticTraits(window, "Offspring", getAnyUserProfileAttributeFunction, currentPage)
|
|
||||||
})
|
|
||||||
|
|
||||||
numericTraitsButton := widget.NewButton("Numeric Traits", func(){
|
|
||||||
//TODO
|
|
||||||
showUnderConstructionDialog(window)
|
|
||||||
})
|
|
||||||
|
|
||||||
buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, discreteTraitsButton, numericTraitsButton))
|
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), buttonsGrid)
|
|
||||||
|
|
||||||
setPageContent(page, window)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffspring string, getAnyUserProfileAttributeFunction func(string)(bool, int, string, error), previousPage func()){
|
|
||||||
|
|
||||||
if (userOrOffspring != "User" && userOrOffspring != "Offspring"){
|
|
||||||
setErrorEncounteredPage(window, errors.New("setViewMateProfilePage_DiscreteGeneticTraits called with invalid userOrOffspring: " + userOrOffspring), previousPage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userOrOffspring == "Offspring"){
|
|
||||||
setLoadingScreen(window, "View Profile - Physical", "Computing Genetic Analysis...")
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPage := func(){setViewMateProfilePage_DiscreteGeneticTraits(window, userOrOffspring, getAnyUserProfileAttributeFunction, previousPage)}
|
|
||||||
|
|
||||||
title := getPageTitleCentered(translate("View Profile - Physical"))
|
|
||||||
|
|
||||||
backButton := getBackButtonCentered(previousPage)
|
|
||||||
|
|
||||||
subtitle := getPageSubtitleCentered(translate("Discrete Genetic Traits"))
|
|
||||||
|
|
||||||
description1 := getLabelCentered("Below is the discrete genetic trait analysis for this user.")
|
|
||||||
description2 := getLabelCentered("You can choose to view the analysis of the user or an offspring between you and the user.")
|
description2 := getLabelCentered("You can choose to view the analysis of the user or an offspring between you and the user.")
|
||||||
description3 := getLabelCentered("You must link your genome person in the Build Profile menu to see offspring information.")
|
description3 := getLabelCentered("You must link your genome person in the Build Profile menu to see offspring information.")
|
||||||
|
|
||||||
|
@ -3573,66 +3531,43 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs
|
||||||
if (userOrOffspring == newUserOrOffspring){
|
if (userOrOffspring == newUserOrOffspring){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setViewMateProfilePage_DiscreteGeneticTraits(window, newUserOrOffspring, getAnyUserProfileAttributeFunction, previousPage)
|
setViewMateProfilePage_GeneticTraits(window, newUserOrOffspring, getAnyUserProfileAttributeFunction, previousPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
userOrOffspringSelector := widget.NewSelect([]string{"User", "Offspring"}, handleSelectButton)
|
userOrOffspringSelector := widget.NewSelect([]string{"User", "Offspring"}, handleSelectButton)
|
||||||
userOrOffspringSelector.Selected = userOrOffspring
|
userOrOffspringSelector.Selected = userOrOffspring
|
||||||
|
|
||||||
userOrOffspringSelectorCentered := getWidgetCentered(userOrOffspringSelector)
|
userOrOffspringSelectorCentered := getWidgetCentered(userOrOffspringSelector)
|
||||||
|
|
||||||
getTraitsInfoGrid := func()(*fyne.Container, error){
|
getTraitsInfoGrid := func()(*fyne.Container, error){
|
||||||
|
|
||||||
myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis()
|
emptyLabelA := widget.NewLabel("")
|
||||||
if (err != nil) { return nil, err }
|
|
||||||
|
|
||||||
//Outputs:
|
|
||||||
// -map[int64]locusValue.LocusValue
|
|
||||||
// -error
|
|
||||||
getMyGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
|
||||||
|
|
||||||
if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){
|
|
||||||
emptyMap := make(map[int64]locusValue.LocusValue)
|
|
||||||
return emptyMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myAnalysisObject)
|
|
||||||
if (err != nil) { return nil, err }
|
|
||||||
|
|
||||||
myGenomeLocusValuesMap, exists := myGenomesMap[myGenomeIdentifier]
|
|
||||||
if (exists == false){
|
|
||||||
return nil, errors.New("GetMyChosenMateGeneticAnalysis returning analysis which is missing genome with myGenomeIdentifier.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return myGenomeLocusValuesMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
myGenomeLocusValuesMap, err := getMyGenomeLocusValuesMap()
|
|
||||||
if (err != nil) { return nil, err }
|
|
||||||
|
|
||||||
|
|
||||||
emptyLabel1 := widget.NewLabel("")
|
|
||||||
traitNameLabel := getItalicLabelCentered("Trait Name")
|
traitNameLabel := getItalicLabelCentered("Trait Name")
|
||||||
|
|
||||||
emptyLabel2 := widget.NewLabel("")
|
emptyLabelB := widget.NewLabel("")
|
||||||
userPredictedOutcomeTitle := getItalicLabelCentered("User Predicted Outcome")
|
userOutcomeScoresLabel := getItalicLabelCentered("User Outcome Scores")
|
||||||
|
|
||||||
emptyLabel3 := widget.NewLabel("")
|
emptyLabelC := widget.NewLabel("")
|
||||||
offspringOutcomeProbabilitiesLabel := getItalicLabelCentered("Offspring Outcome Probabilities")
|
offspringOutcomeScoresLabel := getItalicLabelCentered("Offspring Outcome Scores")
|
||||||
|
|
||||||
quantityOfLabel1 := getItalicLabelCentered("Quantity Of")
|
numberOfLabelA := getItalicLabelCentered("Number Of")
|
||||||
lociKnownLabel := getItalicLabelCentered("Loci Known")
|
rulesTestedLabelA := getItalicLabelCentered("Rules Tested")
|
||||||
|
|
||||||
emptyLabel4 := widget.NewLabel("")
|
numberOfLabelB := getItalicLabelCentered("Number Of")
|
||||||
emptyLabel5 := widget.NewLabel("")
|
rulesTestedLabelB := getItalicLabelCentered("Rules Tested")
|
||||||
|
|
||||||
traitNameColumn := container.NewVBox(emptyLabel1, traitNameLabel, widget.NewSeparator())
|
emptyLabelD := widget.NewLabel("")
|
||||||
userPredictedOutcomeColumn := container.NewVBox(emptyLabel2, userPredictedOutcomeTitle, widget.NewSeparator())
|
emptyLabelE := widget.NewLabel("")
|
||||||
|
|
||||||
offspringOutcomeProbabilitiesColumn := container.NewVBox(emptyLabel3, offspringOutcomeProbabilitiesLabel, widget.NewSeparator())
|
traitNameColumn := container.NewVBox(emptyLabelA, traitNameLabel, widget.NewSeparator())
|
||||||
|
userOutcomeScoresColumn := container.NewVBox(emptyLabelB, userOutcomeScoresLabel, widget.NewSeparator())
|
||||||
|
offspringOutcomeScoresColumn := container.NewVBox(emptyLabelC, offspringOutcomeScoresLabel, widget.NewSeparator())
|
||||||
|
userNumberOfRulesTestedColumn := container.NewVBox(numberOfLabelA, rulesTestedLabelA, widget.NewSeparator())
|
||||||
|
offspringNumberOfRulesTestedColumn := container.NewVBox(numberOfLabelB, rulesTestedLabelB, widget.NewSeparator())
|
||||||
|
viewTraitDetailsButtonsColumn := container.NewVBox(emptyLabelD, emptyLabelE, widget.NewSeparator())
|
||||||
|
|
||||||
quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel1, lociKnownLabel, widget.NewSeparator())
|
myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis()
|
||||||
viewTraitDetailsButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator())
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
traitObjectsList, err := traits.GetTraitObjectsList()
|
traitObjectsList, err := traits.GetTraitObjectsList()
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
@ -3640,39 +3575,29 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs
|
||||||
for _, traitObject := range traitObjectsList{
|
for _, traitObject := range traitObjectsList{
|
||||||
|
|
||||||
traitName := traitObject.TraitName
|
traitName := traitObject.TraitName
|
||||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
|
||||||
if (traitIsDiscreteOrNumeric != "Discrete"){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
traitRulesList := traitObject.RulesList
|
traitRulesList := traitObject.RulesList
|
||||||
totalNumberOfTraitRules := len(traitRulesList)
|
totalNumberOfTraitRules := len(traitRulesList)
|
||||||
|
|
||||||
traitLociList := traitObject.LociList
|
if (totalNumberOfTraitRules == 0){
|
||||||
|
|
||||||
numberOfTraitLoci := len(traitLociList)
|
|
||||||
|
|
||||||
if (totalNumberOfTraitRules == 0 && numberOfTraitLoci == 0){
|
|
||||||
// We are not able to analyze these traits yet
|
// We are not able to analyze these traits yet
|
||||||
|
// We will once we add neural network prediction
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
traitNeuralNetworkExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)
|
totalNumberOfTraitRulesString := helpers.ConvertIntToString(totalNumberOfTraitRules)
|
||||||
if (traitNeuralNetworkExists == false && totalNumberOfTraitRules == 0){
|
|
||||||
// We are not able to analyze these traits yet
|
traitOutcomeNamesList := traitObject.OutcomesList
|
||||||
continue
|
|
||||||
}
|
// We have to sort outcome names so they always show up in the same order
|
||||||
|
|
||||||
|
traitOutcomeNamesListSorted := helpers.CopyAndSortStringListToUnicodeOrder(traitOutcomeNamesList)
|
||||||
|
|
||||||
traitNameText := getBoldLabelCentered(translate(traitName))
|
traitNameText := getBoldLabelCentered(translate(traitName))
|
||||||
traitNameColumn.Add(traitNameText)
|
traitNameColumn.Add(traitNameText)
|
||||||
|
|
||||||
viewTraitDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
viewTraitDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
||||||
if (traitNeuralNetworkExists == true){
|
setViewMateProfilePage_TraitRules(window, traitName, userOrOffspring, getAnyUserProfileAttributeFunction, currentPage)
|
||||||
//TODO
|
|
||||||
showUnderConstructionDialog(window)
|
|
||||||
} else {
|
|
||||||
setViewMateProfilePage_DiscreteTraitRules(window, traitName, userOrOffspring, getAnyUserProfileAttributeFunction, currentPage)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
viewTraitDetailsButtonsColumn.Add(viewTraitDetailsButton)
|
viewTraitDetailsButtonsColumn.Add(viewTraitDetailsButton)
|
||||||
|
@ -3681,6 +3606,8 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs
|
||||||
// Map Structure: Locus rsID -> locusValue.LocusValue
|
// Map Structure: Locus rsID -> locusValue.LocusValue
|
||||||
userTraitLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
userTraitLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
|
||||||
|
traitLociList := traitObject.LociList
|
||||||
|
|
||||||
for _, rsID := range traitLociList{
|
for _, rsID := range traitLociList{
|
||||||
|
|
||||||
rsIDString := helpers.ConvertInt64ToString(rsID)
|
rsIDString := helpers.ConvertInt64ToString(rsID)
|
||||||
|
@ -3708,244 +3635,200 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs
|
||||||
userTraitLocusValuesMap[rsID] = userLocusValue
|
userTraitLocusValuesMap[rsID] = userLocusValue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userOrOffspring == "User"){
|
//Outputs:
|
||||||
|
// -bool: At least 1 rule is known
|
||||||
|
// -map[string]int: Outcome name -> Outcome score
|
||||||
|
// -int: Number of rules tested
|
||||||
|
// -error
|
||||||
|
getUserTraitOutcomeScoresMap := func()(bool, map[string]int, int, error){
|
||||||
|
|
||||||
if (traitNeuralNetworkExists == true){
|
userTraitOutcomeScoresMap := make(map[string]int)
|
||||||
|
userNumberOfRulesTested := 0
|
||||||
|
|
||||||
traitNeuralNetworkExists, anyLocusValuesAreKnown, predictedOutcome, _, quantityOfLociKnown, _, err := createPersonGeneticAnalysis.GetGenomeDiscreteTraitAnalysis_NeuralNetwork(traitObject, userTraitLocusValuesMap, true)
|
for _, traitRuleObject := range traitRulesList{
|
||||||
if (err != nil) { return nil, err }
|
|
||||||
if (traitNeuralNetworkExists == false){
|
ruleLociList := traitRuleObject.LociList
|
||||||
return nil, errors.New("GetGenomeTraitAnalysis_NeuralNetwork claims neural network doesn't exist for trait, but we already checked.")
|
|
||||||
}
|
userRuleStatusIsKnown, userPassesRule, err := createPersonGeneticAnalysis.GetGenomePassesTraitRuleStatus(ruleLociList, userTraitLocusValuesMap, true)
|
||||||
if (anyLocusValuesAreKnown == false){
|
if (err != nil) { return false, nil, 0, err }
|
||||||
unknownLabel := getItalicLabelCentered(translate("Unknown"))
|
if (userRuleStatusIsKnown == false){
|
||||||
userPredictedOutcomeColumn.Add(unknownLabel)
|
continue
|
||||||
} else {
|
|
||||||
predictedOutcomeLabel := getBoldLabelCentered(predictedOutcome)
|
|
||||||
userPredictedOutcomeColumn.Add(predictedOutcomeLabel)
|
|
||||||
}
|
}
|
||||||
|
userNumberOfRulesTested += 1
|
||||||
|
|
||||||
totalNumberOfLociString := helpers.ConvertIntToString(numberOfTraitLoci)
|
if (userPassesRule == true){
|
||||||
|
|
||||||
quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown)
|
ruleOutcomePointsMap := traitRuleObject.OutcomePointsMap
|
||||||
|
|
||||||
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalNumberOfLociString
|
for traitOutcome, pointsEffect := range ruleOutcomePointsMap{
|
||||||
|
|
||||||
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
|
userTraitOutcomeScoresMap[traitOutcome] += pointsEffect
|
||||||
|
|
||||||
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// We use the rules-based analysis
|
|
||||||
|
|
||||||
anyRulesExist, _, quantityOfLociKnown_Rules, _, predictedOutcomeIsKnown, predictedOutcome, err := createPersonGeneticAnalysis.GetGenomeDiscreteTraitAnalysis_Rules(traitObject, userTraitLocusValuesMap, true)
|
|
||||||
if (err != nil) { return nil, err }
|
|
||||||
if (anyRulesExist == false){
|
|
||||||
return nil, errors.New("GetGenomeTraitAnalysis_Rules claims no rules exist when we already checked.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (predictedOutcomeIsKnown == false){
|
|
||||||
unknownLabel := getItalicLabelCentered("Unknown")
|
|
||||||
userPredictedOutcomeColumn.Add(unknownLabel)
|
|
||||||
} else {
|
|
||||||
predictedOutcomeLabel := getBoldLabelCentered(predictedOutcome)
|
|
||||||
userPredictedOutcomeColumn.Add(predictedOutcomeLabel)
|
|
||||||
}
|
|
||||||
|
|
||||||
traitLociList_Rules := traitObject.LociList_Rules
|
|
||||||
|
|
||||||
totalQuantityOfLoci := len(traitLociList_Rules)
|
|
||||||
|
|
||||||
quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown_Rules)
|
|
||||||
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
|
|
||||||
|
|
||||||
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
|
|
||||||
|
|
||||||
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
|
|
||||||
|
|
||||||
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// userOrOffspring == "Offspring"
|
|
||||||
|
|
||||||
if (traitNeuralNetworkExists == true){
|
|
||||||
|
|
||||||
neuralNetworkExists, anyLociKnown, outcomeProbabilitiesMap, _, quantityOfLociKnown, _, err := createCoupleGeneticAnalysis.GetOffspringDiscreteTraitInfo_NeuralNetwork(traitObject, userTraitLocusValuesMap, myGenomeLocusValuesMap)
|
|
||||||
if (err != nil) { return nil, err }
|
|
||||||
if (neuralNetworkExists == false){
|
|
||||||
return nil, errors.New("GetOffspringTraitInfo_NeuralNetwork claiming that neural network doesn't exist when we already checked.")
|
|
||||||
}
|
|
||||||
|
|
||||||
totalNumberOfLociString := helpers.ConvertIntToString(numberOfTraitLoci)
|
|
||||||
|
|
||||||
quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown)
|
|
||||||
|
|
||||||
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalNumberOfLociString
|
|
||||||
|
|
||||||
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
|
|
||||||
|
|
||||||
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
|
|
||||||
|
|
||||||
if (anyLociKnown == false){
|
|
||||||
unknownLabel := getItalicLabelCentered("Unknown")
|
|
||||||
|
|
||||||
offspringOutcomeProbabilitiesColumn.Add(unknownLabel)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
outcomesList := helpers.GetListOfMapKeys(outcomeProbabilitiesMap)
|
|
||||||
|
|
||||||
// We sort the outcomes in alphabetical order so they show up the same way each time
|
|
||||||
slices.Sort(outcomesList)
|
|
||||||
|
|
||||||
quantityOfAddedItems := 0
|
|
||||||
|
|
||||||
for _, outcomeName := range outcomesList{
|
|
||||||
|
|
||||||
outcomeProbability, exists := outcomeProbabilitiesMap[outcomeName]
|
|
||||||
if (exists == false){
|
|
||||||
return nil, errors.New("GetListOfMapKeys returning element which doesn't exist in map.")
|
|
||||||
}
|
|
||||||
if (outcomeProbability == 0){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
outcomeProbabilityString := helpers.ConvertIntToString(outcomeProbability)
|
|
||||||
outcomeProbabilityLabelText := outcomeName + ": " + outcomeProbabilityString + "%"
|
|
||||||
|
|
||||||
outcomeProbabilityLabel := getBoldLabelCentered(outcomeProbabilityLabelText)
|
|
||||||
|
|
||||||
offspringOutcomeProbabilitiesColumn.Add(outcomeProbabilityLabel)
|
|
||||||
|
|
||||||
quantityOfAddedItems += 1
|
|
||||||
|
|
||||||
if (quantityOfAddedItems > 1){
|
|
||||||
// We add whitespace for the other columns
|
|
||||||
traitNameColumn.Add(widget.NewLabel(""))
|
|
||||||
quantityOfLociKnownColumn.Add(widget.NewLabel(""))
|
|
||||||
viewTraitDetailsButtonsColumn.Add(widget.NewLabel(""))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userNumberOfRulesTested == 0){
|
||||||
|
return false, nil, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
traitOutcomesList := traitObject.OutcomesList
|
||||||
|
|
||||||
|
// We add all outcomes for which there were no points
|
||||||
|
|
||||||
|
for _, traitOutcome := range traitOutcomesList{
|
||||||
|
|
||||||
|
_, exists := userTraitOutcomeScoresMap[traitOutcome]
|
||||||
|
if (exists == false){
|
||||||
|
userTraitOutcomeScoresMap[traitOutcome] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, userTraitOutcomeScoresMap, userNumberOfRulesTested, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//Outputs:
|
||||||
|
// -bool: At least 1 rule is known
|
||||||
|
// -map[string]float64: Outcome name -> Outcome score
|
||||||
|
// -int: Number of rules tested
|
||||||
|
// -error
|
||||||
|
getOffspringTraitOutcomeScoresMap := func()(bool, map[string]float64, int, error){
|
||||||
|
|
||||||
|
if (myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false){
|
||||||
|
// Without my genome person chosen, all offspring rules and outcome scores are unknown
|
||||||
|
return false, nil, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
myTraitLocusValuesMap, _, _, _, _, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(myAnalysisObject, traitName, myGenomeIdentifier)
|
||||||
|
if (err != nil) { return false, nil, 0, err }
|
||||||
|
|
||||||
|
anyRuleTested, offspringNumberOfRulesTested, _, offspringAverageOutcomeScoresMap, err := createCoupleGeneticAnalysis.GetOffspringTraitInfo(traitObject, myTraitLocusValuesMap, userTraitLocusValuesMap)
|
||||||
|
if (err != nil) { return false, nil, 0, err }
|
||||||
|
if (anyRuleTested == false){
|
||||||
|
return false, nil, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, offspringAverageOutcomeScoresMap, offspringNumberOfRulesTested, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userOrOffspring == "User"){
|
||||||
|
|
||||||
|
userTraitOutcomeScoresKnown, userTraitOutcomeScoresMap, userNumberOfRulesTested, err := getUserTraitOutcomeScoresMap()
|
||||||
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
|
numberOfRulesTestedString := helpers.ConvertIntToString(userNumberOfRulesTested)
|
||||||
|
numberOfRulesTestedFormatted := numberOfRulesTestedString + "/" + totalNumberOfTraitRulesString
|
||||||
|
numberOfRulesTestedLabel := getBoldLabelCentered(numberOfRulesTestedFormatted)
|
||||||
|
userNumberOfRulesTestedColumn.Add(numberOfRulesTestedLabel)
|
||||||
|
|
||||||
|
if (userTraitOutcomeScoresKnown == false){
|
||||||
|
unknownTranslated := translate("Unknown")
|
||||||
|
unknownLabel := getBoldLabelCentered(unknownTranslated)
|
||||||
|
|
||||||
|
userOutcomeScoresColumn.Add(unknownLabel)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// We use the rules-based analysis
|
for index, outcomeName := range traitOutcomeNamesListSorted{
|
||||||
|
|
||||||
anyRulesExist, rulesAnalysisExists, _, offspringQuantityOfLociKnown, _, outcomeProbabilitiesMap, err := createCoupleGeneticAnalysis.GetOffspringDiscreteTraitInfo_Rules(traitObject, myGenomeLocusValuesMap, userTraitLocusValuesMap)
|
outcomeScore, exists := userTraitOutcomeScoresMap[outcomeName]
|
||||||
if (err != nil) { return nil, err }
|
if (exists == false){
|
||||||
if (anyRulesExist == false){
|
return nil, errors.New("Outcome not found in userTraitOutcomeScoresMap.")
|
||||||
return nil, errors.New("GetOffspringDiscreteTraitInfo_Rules claiming that no rules exist when we already checked.")
|
}
|
||||||
|
|
||||||
|
outcomeScoreString := helpers.ConvertIntToString(outcomeScore)
|
||||||
|
|
||||||
|
outcomeRow := getBoldLabelCentered(outcomeName + ": " + outcomeScoreString)
|
||||||
|
userOutcomeScoresColumn.Add(outcomeRow)
|
||||||
|
|
||||||
|
if (index > 0){
|
||||||
|
|
||||||
|
emptyLabelA := widget.NewLabel("")
|
||||||
|
emptyLabelB := widget.NewLabel("")
|
||||||
|
emptyLabelC := widget.NewLabel("")
|
||||||
|
|
||||||
|
traitNameColumn.Add(emptyLabelA)
|
||||||
|
userNumberOfRulesTestedColumn.Add(emptyLabelB)
|
||||||
|
viewTraitDetailsButtonsColumn.Add(emptyLabelC)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else if (userOrOffspring == "Offspring"){
|
||||||
|
|
||||||
lociList_Rules := traitObject.LociList_Rules
|
offspringTraitOutcomeScoresKnown, offspringTraitOutcomeScoresMap, offspringNumberOfRulesTested, err := getOffspringTraitOutcomeScoresMap()
|
||||||
|
if (err != nil) { return nil, err }
|
||||||
|
|
||||||
totalQuantityOfLoci := len(lociList_Rules)
|
numberOfRulesTestedString := helpers.ConvertIntToString(offspringNumberOfRulesTested)
|
||||||
|
numberOfRulesTestedFormatted := numberOfRulesTestedString + "/" + totalNumberOfTraitRulesString
|
||||||
|
numberOfRulesTestedLabel := getBoldLabelCentered(numberOfRulesTestedFormatted)
|
||||||
|
offspringNumberOfRulesTestedColumn.Add(numberOfRulesTestedLabel)
|
||||||
|
|
||||||
quantityOfLociKnownString := helpers.ConvertIntToString(offspringQuantityOfLociKnown)
|
if (offspringTraitOutcomeScoresKnown == false){
|
||||||
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
|
unknownTranslated := translate("Unknown")
|
||||||
|
unknownLabel := getBoldLabelCentered(unknownTranslated)
|
||||||
|
|
||||||
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
|
offspringOutcomeScoresColumn.Add(unknownLabel)
|
||||||
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
|
} else {
|
||||||
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
|
|
||||||
|
|
||||||
if (rulesAnalysisExists == false){
|
for index, outcomeName := range traitOutcomeNamesListSorted{
|
||||||
unknownLabel := getItalicLabelCentered(translate("Unknown"))
|
|
||||||
|
|
||||||
offspringOutcomeProbabilitiesColumn.Add(unknownLabel)
|
outcomeScore, exists := offspringTraitOutcomeScoresMap[outcomeName]
|
||||||
} else {
|
if (exists == false){
|
||||||
|
return nil, errors.New("Outcome not found in offspringTraitOutcomeScoresMap.")
|
||||||
|
}
|
||||||
|
|
||||||
outcomesList := helpers.GetListOfMapKeys(outcomeProbabilitiesMap)
|
outcomeScoreString := helpers.ConvertFloat64ToStringRounded(outcomeScore, 2)
|
||||||
|
|
||||||
// We sort the outcomes in alphabetical order so they show up the same way each time
|
outcomeRow := getBoldLabelCentered(outcomeName + ": " + outcomeScoreString)
|
||||||
slices.Sort(outcomesList)
|
offspringOutcomeScoresColumn.Add(outcomeRow)
|
||||||
|
|
||||||
quantityOfAddedItems := 0
|
if (index > 0){
|
||||||
|
|
||||||
|
emptyLabelA := widget.NewLabel("")
|
||||||
|
emptyLabelB := widget.NewLabel("")
|
||||||
|
emptyLabelC := widget.NewLabel("")
|
||||||
|
|
||||||
for _, outcomeName := range outcomesList{
|
traitNameColumn.Add(emptyLabelA)
|
||||||
|
offspringNumberOfRulesTestedColumn.Add(emptyLabelB)
|
||||||
outcomeProbability, exists := outcomeProbabilitiesMap[outcomeName]
|
viewTraitDetailsButtonsColumn.Add(emptyLabelC)
|
||||||
if (exists == false){
|
|
||||||
return nil, errors.New("GetListOfMapKeys returning element which doesn't exist in map.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outcomeProbability == 0){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
outcomeProbabilityString := helpers.ConvertIntToString(outcomeProbability)
|
|
||||||
outcomeProbabilityLabelText := outcomeName + ": " + outcomeProbabilityString + "%"
|
|
||||||
|
|
||||||
outcomeProbabilityLabel := getBoldLabelCentered(outcomeProbabilityLabelText)
|
|
||||||
|
|
||||||
offspringOutcomeProbabilitiesColumn.Add(outcomeProbabilityLabel)
|
|
||||||
|
|
||||||
quantityOfAddedItems += 1
|
|
||||||
|
|
||||||
if (quantityOfAddedItems > 1){
|
|
||||||
// We add whitespace for the other columns
|
|
||||||
traitNameColumn.Add(widget.NewLabel(""))
|
|
||||||
quantityOfLociKnownColumn.Add(widget.NewLabel(""))
|
|
||||||
viewTraitDetailsButtonsColumn.Add(widget.NewLabel(""))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
traitNameColumn.Add(widget.NewSeparator())
|
traitNameColumn.Add(widget.NewSeparator())
|
||||||
userPredictedOutcomeColumn.Add(widget.NewSeparator())
|
userOutcomeScoresColumn.Add(widget.NewSeparator())
|
||||||
offspringOutcomeProbabilitiesColumn.Add(widget.NewSeparator())
|
offspringOutcomeScoresColumn.Add(widget.NewSeparator())
|
||||||
quantityOfLociKnownColumn.Add(widget.NewSeparator())
|
userNumberOfRulesTestedColumn.Add(widget.NewSeparator())
|
||||||
|
offspringNumberOfRulesTestedColumn.Add(widget.NewSeparator())
|
||||||
viewTraitDetailsButtonsColumn.Add(widget.NewSeparator())
|
viewTraitDetailsButtonsColumn.Add(widget.NewSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userOrOffspring == "User"){
|
userOutcomeScoresHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
|
setTraitOutcomeScoresExplainerPage(window, currentPage)
|
||||||
predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
|
||||||
|
|
||||||
//TODO
|
|
||||||
showUnderConstructionDialog(window)
|
|
||||||
})
|
|
||||||
|
|
||||||
userPredictedOutcomeColumn.Add(predictedOutcomeHelpButton)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// userOrOffspring == "Offspring"
|
|
||||||
|
|
||||||
outcomeProbabilitiesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
|
||||||
|
|
||||||
//TODO
|
|
||||||
showUnderConstructionDialog(window)
|
|
||||||
})
|
|
||||||
|
|
||||||
offspringOutcomeProbabilitiesColumn.Add(outcomeProbabilitiesHelpButton)
|
|
||||||
}
|
|
||||||
|
|
||||||
quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
|
||||||
//TODO
|
|
||||||
showUnderConstructionDialog(window)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton)
|
offspringOutcomeScoresHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
|
setOffspringTraitOutcomeScoresExplainerPage(window, currentPage)
|
||||||
|
})
|
||||||
|
|
||||||
traitsInfoGrid := container.NewHBox(layout.NewSpacer(), traitNameColumn)
|
userNumberOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
|
setTraitNumberOfRulesTestedExplainerPage(window, currentPage)
|
||||||
|
})
|
||||||
|
|
||||||
|
offspringNumberOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
|
setOffspringTraitNumberOfRulesTestedExplainerPage(window, currentPage)
|
||||||
|
})
|
||||||
|
|
||||||
|
userOutcomeScoresColumn.Add(userOutcomeScoresHelpButton)
|
||||||
|
offspringOutcomeScoresColumn.Add(offspringOutcomeScoresHelpButton)
|
||||||
|
userNumberOfRulesTestedColumn.Add(userNumberOfRulesTestedHelpButton)
|
||||||
|
offspringNumberOfRulesTestedColumn.Add(offspringNumberOfRulesTestedHelpButton)
|
||||||
|
|
||||||
if (userOrOffspring == "User"){
|
if (userOrOffspring == "User"){
|
||||||
|
traitsInfoGrid := container.NewHBox(layout.NewSpacer(), traitNameColumn, userOutcomeScoresColumn, userNumberOfRulesTestedColumn, viewTraitDetailsButtonsColumn, layout.NewSpacer())
|
||||||
traitsInfoGrid.Add(userPredictedOutcomeColumn)
|
|
||||||
|
|
||||||
} else {
|
return traitsInfoGrid, nil
|
||||||
|
|
||||||
// userOrOffspring == "Offspring"
|
|
||||||
|
|
||||||
traitsInfoGrid.Add(offspringOutcomeProbabilitiesColumn)
|
|
||||||
}
|
}
|
||||||
|
traitsInfoGrid := container.NewHBox(layout.NewSpacer(), traitNameColumn, offspringOutcomeScoresColumn, offspringNumberOfRulesTestedColumn, viewTraitDetailsButtonsColumn, layout.NewSpacer())
|
||||||
traitsInfoGrid.Add(quantityOfLociKnownColumn)
|
|
||||||
traitsInfoGrid.Add(viewTraitDetailsButtonsColumn)
|
|
||||||
traitsInfoGrid.Add(layout.NewSpacer())
|
|
||||||
|
|
||||||
return traitsInfoGrid, nil
|
return traitsInfoGrid, nil
|
||||||
}
|
}
|
||||||
|
@ -3961,9 +3844,9 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs
|
||||||
setPageContent(page, window)
|
setPageContent(page, window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName string, userOrOffspring string, getAnyUserProfileAttributeFunction func(string)(bool, int, string, error), previousPage func()){
|
func setViewMateProfilePage_TraitRules(window fyne.Window, traitName string, userOrOffspring string, getAnyUserProfileAttributeFunction func(string)(bool, int, string, error), previousPage func()){
|
||||||
|
|
||||||
currentPage := func(){setViewMateProfilePage_DiscreteTraitRules(window, traitName, userOrOffspring, getAnyUserProfileAttributeFunction, previousPage)}
|
currentPage := func(){setViewMateProfilePage_TraitRules(window, traitName, userOrOffspring, getAnyUserProfileAttributeFunction, previousPage)}
|
||||||
|
|
||||||
title := getPageTitleCentered("View Profile - Physical")
|
title := getPageTitleCentered("View Profile - Physical")
|
||||||
|
|
||||||
|
@ -3985,7 +3868,7 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
||||||
// -bool: Any trait locus value exists for this myself
|
// -bool: Any trait locus value exists for this myself
|
||||||
// -map[int64]locusValue.LocusValue: My locus values map
|
// -map[int64]locusValue.LocusValue: My locus values map
|
||||||
// -error
|
// -error
|
||||||
getMyGenomeLocusValuesMap := func()(bool, map[int64]locusValue.LocusValue, error){
|
getMyTraitLocusValuesMap := func()(bool, 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 false, nil, err }
|
if (err != nil) { return false, nil, err }
|
||||||
|
@ -3995,18 +3878,17 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myAnalysisObject)
|
myTraitLocusValuesMap, _, _, _, _, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(myAnalysisObject, traitName, myGenomeIdentifier)
|
||||||
if (err != nil){ return false, nil, err }
|
if (err != nil) { return false, nil, err }
|
||||||
|
|
||||||
myGenomeMap, exists := myGenomesMap[myGenomeIdentifier]
|
if (len(myTraitLocusValuesMap) == 0){
|
||||||
if (exists == false){
|
return false, nil, nil
|
||||||
return false, nil, errors.New("GetMyChosenMateGeneticAnalysis returning analysis which does not contain genome matching myGenomeIdentifier")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, myGenomeMap, nil
|
return true, myTraitLocusValuesMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
anyMyLocusValuesExist, myLocusValuesMap, err := getMyGenomeLocusValuesMap()
|
anyMyTraitLocusValuesExist, myTraitLocusValuesMap, err := getMyTraitLocusValuesMap()
|
||||||
if (err != nil){
|
if (err != nil){
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
|
@ -4018,14 +3900,9 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
traitLociList_Rules := traitObject.LociList_Rules
|
traitLociList := traitObject.LociList
|
||||||
traitRulesList := traitObject.RulesList
|
traitRulesList := traitObject.RulesList
|
||||||
|
|
||||||
if (len(traitRulesList) == 0){
|
|
||||||
setErrorEncounteredPage(window, errors.New("setViewMateProfilePage_DiscreteTraitRules called with trait which has no rules."), previousPage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: Any trait locus value exists for this user
|
// -bool: Any trait locus value exists for this user
|
||||||
// -map[int64]locusValue.LocusValue: User locus values map
|
// -map[int64]locusValue.LocusValue: User locus values map
|
||||||
|
@ -4036,7 +3913,7 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
||||||
// Map Structure: Locus rsID -> locusValue.LocusValue
|
// Map Structure: Locus rsID -> locusValue.LocusValue
|
||||||
userTraitLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
userTraitLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
|
||||||
for _, rsID := range traitLociList_Rules{
|
for _, rsID := range traitLociList{
|
||||||
|
|
||||||
rsIDString := helpers.ConvertInt64ToString(rsID)
|
rsIDString := helpers.ConvertInt64ToString(rsID)
|
||||||
|
|
||||||
|
@ -4082,15 +3959,12 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
||||||
// -error
|
// -error
|
||||||
getOffspringProbabilityOfPassingRulesMap := func()(bool, map[[3]byte]int, error){
|
getOffspringProbabilityOfPassingRulesMap := func()(bool, map[[3]byte]int, error){
|
||||||
|
|
||||||
if (anyMyLocusValuesExist == false || anyUserTraitLocusValueExists == false){
|
if (anyMyTraitLocusValuesExist == false || anyUserTraitLocusValueExists == false){
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
anyRulesExist, anyOffspringRulesTested, _, _, offspringProbabilityOfPassingRulesMap, _, err := createCoupleGeneticAnalysis.GetOffspringDiscreteTraitInfo_Rules(traitObject, myLocusValuesMap, userTraitLocusValuesMap)
|
anyOffspringRulesTested, _, offspringProbabilityOfPassingRulesMap, _, err := createCoupleGeneticAnalysis.GetOffspringTraitInfo(traitObject, myTraitLocusValuesMap, userTraitLocusValuesMap)
|
||||||
if (err != nil) { return false, nil, err }
|
if (err != nil) { return false, nil, err }
|
||||||
if (anyRulesExist == false){
|
|
||||||
return false, nil, errors.New("GetOffspringDiscreteTraitInfo claiming no trait rules exist when we already checked.")
|
|
||||||
}
|
|
||||||
if (anyOffspringRulesTested == false){
|
if (anyOffspringRulesTested == false){
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
|
@ -4126,7 +4000,7 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
||||||
|
|
||||||
ruleLociList := ruleObject.LociList
|
ruleLociList := ruleObject.LociList
|
||||||
|
|
||||||
ruleStatusIsKnown, _, err := createPersonGeneticAnalysis.GetGenomePassesDiscreteTraitRuleStatus(ruleLociList, userTraitLocusValuesMap, true)
|
ruleStatusIsKnown, _, err := createPersonGeneticAnalysis.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
|
||||||
|
@ -4153,9 +4027,9 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
||||||
|
|
||||||
numberOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
numberOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
if (userOrOffspring == "User"){
|
if (userOrOffspring == "User"){
|
||||||
setDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
|
setTraitNumberOfRulesTestedExplainerPage(window, currentPage)
|
||||||
} else {
|
} else {
|
||||||
setOffspringDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
|
setOffspringTraitNumberOfRulesTestedExplainerPage(window, currentPage)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -4219,7 +4093,7 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
||||||
|
|
||||||
getUserPassesRuleString := func()(string, error){
|
getUserPassesRuleString := func()(string, error){
|
||||||
|
|
||||||
userRuleStatusIsKnown, userPassesRule, err := createPersonGeneticAnalysis.GetGenomePassesDiscreteTraitRuleStatus(ruleLociList, userTraitLocusValuesMap, true)
|
userRuleStatusIsKnown, userPassesRule, err := createPersonGeneticAnalysis.GetGenomePassesTraitRuleStatus(ruleLociList, userTraitLocusValuesMap, true)
|
||||||
if (err != nil) { return "", err }
|
if (err != nil) { return "", err }
|
||||||
|
|
||||||
if (userRuleStatusIsKnown == false){
|
if (userRuleStatusIsKnown == false){
|
||||||
|
@ -4260,7 +4134,7 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
||||||
// We do this because the rule effects column may be multiple rows tall
|
// We do this because the rule effects column may be multiple rows tall
|
||||||
|
|
||||||
viewRuleInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
viewRuleInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
||||||
setViewDiscreteTraitRuleDetailsPage(window, traitName, ruleIdentifierHex, currentPage)
|
setViewTraitRuleDetailsPage(window, traitName, ruleIdentifierHex, currentPage)
|
||||||
})
|
})
|
||||||
ruleIdentifierLabel := getBoldLabelCentered(ruleIdentifierHex)
|
ruleIdentifierLabel := getBoldLabelCentered(ruleIdentifierHex)
|
||||||
userPassesRuleLabel := getBoldLabelCentered(userPassesRuleString)
|
userPassesRuleLabel := getBoldLabelCentered(userPassesRuleString)
|
||||||
|
@ -4326,11 +4200,11 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleEffectsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
ruleEffectsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setDiscreteTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
setTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
userPassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
userPassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
setPersonPassesDiscreteTraitRuleExplainerPage(window, currentPage)
|
setPersonPassesTraitRuleExplainerPage(window, currentPage)
|
||||||
})
|
})
|
||||||
|
|
||||||
offspringProbabilityOfPassingRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
offspringProbabilityOfPassingRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||||
|
@ -4617,29 +4491,29 @@ func get23andMeAncestryCompositionDisplay(inputContinentPercentagesMap map[strin
|
||||||
// We sort region subregions list
|
// We sort region subregions list
|
||||||
// We sort them from highest to lowest in percentage.
|
// We sort them from highest to lowest in percentage.
|
||||||
|
|
||||||
compareSubregionsFunction := func(subregion1Description string, subregion2Description string)int{
|
compareSubregionsFunction := func(subregionADescription string, subregionBDescription string)int{
|
||||||
|
|
||||||
if (subregion1Description == subregion2Description){
|
if (subregionADescription == subregionBDescription){
|
||||||
panic("compareSubregionsFunction called with identical subregion descriptions.")
|
panic("compareSubregionsFunction called with identical subregion descriptions.")
|
||||||
}
|
}
|
||||||
|
|
||||||
subregion1Percentage, exists := subregionDescriptionPercentagesMap[subregion1Description]
|
subregionAPercentage, exists := subregionDescriptionPercentagesMap[subregionADescription]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
panic("subregionPercentagesMap missing subregion during sort.")
|
panic("subregionPercentagesMap missing subregion during sort.")
|
||||||
}
|
}
|
||||||
|
|
||||||
subregion2Percentage, exists := subregionDescriptionPercentagesMap[subregion2Description]
|
subregionBPercentage, exists := subregionDescriptionPercentagesMap[subregionBDescription]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
panic("subregionPercentagesMap missing subregion during sort.")
|
panic("subregionPercentagesMap missing subregion during sort.")
|
||||||
}
|
}
|
||||||
if (subregion1Percentage == subregion2Percentage){
|
if (subregionAPercentage == subregionBPercentage){
|
||||||
// We sort subregions in unicode order
|
// We sort subregions in unicode order
|
||||||
if (subregion1Description < subregion2Description){
|
if (subregionADescription < subregionBDescription){
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if (subregion1Percentage > subregion2Percentage){
|
if (subregionAPercentage > subregionBPercentage){
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4653,33 +4527,32 @@ func get23andMeAncestryCompositionDisplay(inputContinentPercentagesMap map[strin
|
||||||
|
|
||||||
// We sort continent regions list by highest to lowest percentage.
|
// We sort continent regions list by highest to lowest percentage.
|
||||||
|
|
||||||
compareRegionsFunction := func(region1Description string, region2Description string)int{
|
compareRegionsFunction := func(regionADescription string, regionBDescription string)int{
|
||||||
|
|
||||||
if (region1Description == region2Description){
|
if (regionADescription == regionBDescription){
|
||||||
panic("compareRegionsFunction called with identical regions.")
|
panic("compareRegionsFunction called with identical regions.")
|
||||||
}
|
}
|
||||||
|
|
||||||
region1Percentage, exists := regionDescriptionPercentagesMap[region1Description]
|
regionAPercentage, exists := regionDescriptionPercentagesMap[regionADescription]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
panic("regionPercentagesMap missing subregion during sort.")
|
panic("regionPercentagesMap missing subregion during sort.")
|
||||||
}
|
}
|
||||||
|
|
||||||
region2Percentage, exists := regionDescriptionPercentagesMap[region2Description]
|
regionBPercentage, exists := regionDescriptionPercentagesMap[regionBDescription]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
panic("regionPercentagesMap missing subregion during sort.")
|
panic("regionPercentagesMap missing subregion during sort.")
|
||||||
}
|
}
|
||||||
if (region1Percentage == region2Percentage){
|
if (regionAPercentage == regionBPercentage){
|
||||||
// We sort regions in unicode order
|
// We sort regions in unicode order
|
||||||
if (region1Description < region2Description){
|
if (regionADescription < regionBDescription){
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region1Percentage > region2Percentage){
|
if (regionAPercentage > regionBPercentage){
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4690,29 +4563,29 @@ func get23andMeAncestryCompositionDisplay(inputContinentPercentagesMap map[strin
|
||||||
|
|
||||||
// We sort root list by highest to lowest proportions
|
// We sort root list by highest to lowest proportions
|
||||||
|
|
||||||
compareContinentsFunction := func(continent1Description string, continent2Description string)int{
|
compareContinentsFunction := func(continentADescription string, continentBDescription string)int{
|
||||||
|
|
||||||
if (continent1Description == continent2Description){
|
if (continentADescription == continentBDescription){
|
||||||
panic("compareContinentsFunction called with identical continents.")
|
panic("compareContinentsFunction called with identical continents.")
|
||||||
}
|
}
|
||||||
|
|
||||||
continent1Percentage, exists := continentDescriptionPercentagesMap[continent1Description]
|
continentAPercentage, exists := continentDescriptionPercentagesMap[continentADescription]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
panic("Continent percentage not found when sorting root list.")
|
panic("Continent percentage not found when sorting root list.")
|
||||||
}
|
}
|
||||||
|
|
||||||
continent2Percentage, exists := continentDescriptionPercentagesMap[continent2Description]
|
continentBPercentage, exists := continentDescriptionPercentagesMap[continentBDescription]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
panic("Continent percentage not found when sorting root list.")
|
panic("Continent percentage not found when sorting root list.")
|
||||||
}
|
}
|
||||||
if (continent1Percentage == continent2Percentage){
|
if (continentAPercentage == continentBPercentage){
|
||||||
// We sort continents in unicode order
|
// We sort continents in unicode order
|
||||||
if (continent1Description < continent2Description){
|
if (continentADescription < continentBDescription){
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if (continent1Percentage > continent2Percentage){
|
if (continentAPercentage > continentBPercentage){
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
|
|
|
@ -932,7 +932,7 @@ func GetFakeProfile(profileType string, identityPublicKey [32]byte, identityPriv
|
||||||
|
|
||||||
traitLociList := traitObject.LociList
|
traitLociList := traitObject.LociList
|
||||||
|
|
||||||
for _, rsID := range traitLociList{
|
for _, rsID := range traitLociList{
|
||||||
|
|
||||||
shareableRSIDsMap[rsID] = struct{}{}
|
shareableRSIDsMap[rsID] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,21 @@ package createCoupleGeneticAnalysis
|
||||||
|
|
||||||
// Disclaimer: I am a novice in the ways of genetics. This package could be flawed in numerous ways.
|
// Disclaimer: I am a novice in the ways of genetics. This package could be flawed in numerous ways.
|
||||||
|
|
||||||
// TODO: We want to eventually use neural nets for polygenic disease analysis (see geneticPrediction.go)
|
// TODO: We want to eventually use neural nets for both trait and polygenic disease analysis (see geneticPrediction.go)
|
||||||
|
// These will be trained on a set of genomes and will output a probability analysis for each trait/disease
|
||||||
// This is only possible once we get access to the necessary training data
|
// This is only possible once we get access to the necessary training data
|
||||||
|
//
|
||||||
|
// This is how offspring trait prediction could work with the neural net model:
|
||||||
|
// Both users will share all relevant SNPS base pairs that determine the trait on their profile.
|
||||||
|
// Each location has 4 possible outcomes, so for 1000 SNPs, there are 4^1000 possible offspring outcomes for a given couple. (this
|
||||||
|
// is actually too high because recombination break points do not occur at each locus, see genetic linkage)
|
||||||
|
// This is too many options for us to check all of them.
|
||||||
|
// Seekia will create 100 offspring that would be produced from both users, and run each offspring through the neural net.
|
||||||
|
// Each offspring would be different. The allele from each parent for each SNP would be randomly chosen.
|
||||||
|
// The user can choose how many prospective offspring to create in the settings.
|
||||||
|
// More offspring will take longer, but will yield a more accurate trait probability.
|
||||||
|
// Seekia will show the the average trait result and a chart showing the trait results for all created offspring.
|
||||||
|
|
||||||
import "seekia/resources/geneticPredictionModels"
|
|
||||||
import "seekia/resources/geneticReferences/locusMetadata"
|
import "seekia/resources/geneticReferences/locusMetadata"
|
||||||
import "seekia/resources/geneticReferences/monogenicDiseases"
|
import "seekia/resources/geneticReferences/monogenicDiseases"
|
||||||
import "seekia/resources/geneticReferences/polygenicDiseases"
|
import "seekia/resources/geneticReferences/polygenicDiseases"
|
||||||
|
@ -29,7 +40,6 @@ import "errors"
|
||||||
import mathRand "math/rand/v2"
|
import mathRand "math/rand/v2"
|
||||||
import "slices"
|
import "slices"
|
||||||
import "maps"
|
import "maps"
|
||||||
import "reflect"
|
|
||||||
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
|
@ -76,30 +86,6 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
return false, "", nil
|
return false, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// This map stores each genome's locus values
|
|
||||||
// Map Structure: Genome Identifier -> Genome locus values map (rsID -> Locus Value)
|
|
||||||
person1GenomesMap := make(map[[16]byte]map[int64]locusValue.LocusValue)
|
|
||||||
|
|
||||||
for _, genomeWithMetadata := range person1GenomesWithMetadataList{
|
|
||||||
|
|
||||||
genomeIdentifier := genomeWithMetadata.GenomeIdentifier
|
|
||||||
genomeMap := genomeWithMetadata.GenomeMap
|
|
||||||
|
|
||||||
person1GenomesMap[genomeIdentifier] = genomeMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// This map stores each genome's locus values
|
|
||||||
// Map Structure: Genome Identifier -> Genome locus values map (rsID -> Locus Value)
|
|
||||||
person2GenomesMap := make(map[[16]byte]map[int64]locusValue.LocusValue)
|
|
||||||
|
|
||||||
for _, genomeWithMetadata := range person2GenomesWithMetadataList{
|
|
||||||
|
|
||||||
genomeIdentifier := genomeWithMetadata.GenomeIdentifier
|
|
||||||
genomeMap := genomeWithMetadata.GenomeMap
|
|
||||||
|
|
||||||
person2GenomesMap[genomeIdentifier] = genomeMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// The analysis will analyze either 1 or 2 genome pairs
|
// The analysis will analyze either 1 or 2 genome pairs
|
||||||
// The gui will display the results from each pair
|
// The gui will display the results from each pair
|
||||||
//Outputs:
|
//Outputs:
|
||||||
|
@ -186,9 +172,9 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
person2DiseaseAnalysisObject, err := createPersonGeneticAnalysis.GetPersonMonogenicDiseaseAnalysis(person2GenomesWithMetadataList, diseaseObject)
|
person2DiseaseAnalysisObject, err := createPersonGeneticAnalysis.GetPersonMonogenicDiseaseAnalysis(person2GenomesWithMetadataList, diseaseObject)
|
||||||
if (err != nil) { return false, "", err }
|
if (err != nil) { return false, "", err }
|
||||||
|
|
||||||
// This map stores the quantity of variants tested in each person's genome
|
// This map stores the number of variants tested in each person's genome
|
||||||
// Map Structure: Genome Identifier -> Number of variants tested
|
// Map Structure: Genome Identifier -> Number of variants tested
|
||||||
quantityOfVariantsTestedMap := make(map[[16]byte]int)
|
numberOfVariantsTestedMap := make(map[[16]byte]int)
|
||||||
|
|
||||||
// This map stores the offspring disease probabilities for each genome pair.
|
// This map stores the offspring disease probabilities for each genome pair.
|
||||||
// A genome pair is a concatenation of two genome identifiers
|
// A genome pair is a concatenation of two genome identifiers
|
||||||
|
@ -198,7 +184,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
|
|
||||||
// This will calculate the probability of monogenic disease for the offspring from the two specified genomes
|
// This will calculate the probability of monogenic disease for the offspring from the two specified genomes
|
||||||
// It also calculates the probabilities for each monogenic disease variant for the offspring
|
// It also calculates the probabilities for each monogenic disease variant for the offspring
|
||||||
// It then adds the genome pair disease information to the offspringMonogenicDiseaseInfoMap and quantityOfVariantsTestedMap
|
// It then adds the genome pair disease information to the offspringMonogenicDiseaseInfoMap and numberOfVariantsTestedMap
|
||||||
addGenomePairInfoToDiseaseMaps := func(person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
addGenomePairInfoToDiseaseMaps := func(person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
|
@ -216,9 +202,9 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
|
|
||||||
personGenomeProbabilityOfPassingADiseaseVariant := personGenomeDiseaseInfoObject.ProbabilityOfPassingADiseaseVariant
|
personGenomeProbabilityOfPassingADiseaseVariant := personGenomeDiseaseInfoObject.ProbabilityOfPassingADiseaseVariant
|
||||||
|
|
||||||
personGenomeQuantityOfVariantsTested := personGenomeDiseaseInfoObject.QuantityOfVariantsTested
|
personGenomeNumberOfVariantsTested := personGenomeDiseaseInfoObject.NumberOfVariantsTested
|
||||||
|
|
||||||
return true, personGenomeProbabilityOfPassingADiseaseVariant, personGenomeQuantityOfVariantsTested
|
return true, personGenomeProbabilityOfPassingADiseaseVariant, personGenomeNumberOfVariantsTested
|
||||||
}
|
}
|
||||||
|
|
||||||
person1ProbabilityIsKnown, person1WillPassVariantProbability, person1NumberOfVariantsTested := getPersonWillPassDiseaseVariantProbability(person1DiseaseAnalysisObject, person1GenomeIdentifier)
|
person1ProbabilityIsKnown, person1WillPassVariantProbability, person1NumberOfVariantsTested := getPersonWillPassDiseaseVariantProbability(person1DiseaseAnalysisObject, person1GenomeIdentifier)
|
||||||
|
@ -376,8 +362,8 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
quantityOfVariantsTestedMap[person1GenomeIdentifier] = person1NumberOfVariantsTested
|
numberOfVariantsTestedMap[person1GenomeIdentifier] = person1NumberOfVariantsTested
|
||||||
quantityOfVariantsTestedMap[person2GenomeIdentifier] = person2NumberOfVariantsTested
|
numberOfVariantsTestedMap[person2GenomeIdentifier] = person2NumberOfVariantsTested
|
||||||
|
|
||||||
newOffspringGenomePairMonogenicDiseaseInfoObject := geneticAnalysis.OffspringGenomePairMonogenicDiseaseInfo{
|
newOffspringGenomePairMonogenicDiseaseInfoObject := geneticAnalysis.OffspringGenomePairMonogenicDiseaseInfo{
|
||||||
ProbabilityOffspringHasDiseaseIsKnown: offspringHasDiseaseProbabilityIsKnown,
|
ProbabilityOffspringHasDiseaseIsKnown: offspringHasDiseaseProbabilityIsKnown,
|
||||||
|
@ -404,7 +390,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
}
|
}
|
||||||
|
|
||||||
newOffspringMonogenicDiseaseInfoObject := geneticAnalysis.OffspringMonogenicDiseaseInfo{
|
newOffspringMonogenicDiseaseInfoObject := geneticAnalysis.OffspringMonogenicDiseaseInfo{
|
||||||
QuantityOfVariantsTestedMap: quantityOfVariantsTestedMap,
|
NumberOfVariantsTestedMap: numberOfVariantsTestedMap,
|
||||||
MonogenicDiseaseInfoMap: offspringMonogenicDiseaseInfoMap,
|
MonogenicDiseaseInfoMap: offspringMonogenicDiseaseInfoMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,6 +480,12 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
diseaseName := diseaseObject.DiseaseName
|
diseaseName := diseaseObject.DiseaseName
|
||||||
diseaseLociList := diseaseObject.LociList
|
diseaseLociList := diseaseObject.LociList
|
||||||
|
|
||||||
|
person1DiseaseAnalysisObject, err := createPersonGeneticAnalysis.GetPersonPolygenicDiseaseAnalysis(person1GenomesWithMetadataList, diseaseObject)
|
||||||
|
if (err != nil) { return false, "", err }
|
||||||
|
|
||||||
|
person2DiseaseAnalysisObject, err := createPersonGeneticAnalysis.GetPersonPolygenicDiseaseAnalysis(person2GenomesWithMetadataList, diseaseObject)
|
||||||
|
if (err != nil) { return false, "", err }
|
||||||
|
|
||||||
// This map stores the polygenic disease info for each genome pair
|
// This map stores the polygenic disease info for each genome pair
|
||||||
// Map Structure: Genome Pair Identifier -> OffspringGenomePairPolygenicDiseaseInfo
|
// Map Structure: Genome Pair Identifier -> OffspringGenomePairPolygenicDiseaseInfo
|
||||||
offspringPolygenicDiseaseInfoMap := make(map[[32]byte]geneticAnalysis.OffspringGenomePairPolygenicDiseaseInfo)
|
offspringPolygenicDiseaseInfoMap := make(map[[32]byte]geneticAnalysis.OffspringGenomePairPolygenicDiseaseInfo)
|
||||||
|
@ -502,17 +494,40 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
// It then adds the pair entry to the offspringPolygenicDiseaseInfoMap
|
// It then adds the pair entry to the offspringPolygenicDiseaseInfoMap
|
||||||
addGenomePairDiseaseInfoToDiseaseMap := func(person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
addGenomePairDiseaseInfoToDiseaseMap := func(person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
||||||
|
|
||||||
person1LocusValuesMap, exists := person1GenomesMap[person1GenomeIdentifier]
|
//Outputs:
|
||||||
if (exists == false){
|
// -bool: Any locus values exist
|
||||||
return errors.New("addGenomePairDiseaseInfoToDiseaseMap called with unknown person1GenomeIdentifier.")
|
// -map[int64]locusValue.LocusValue
|
||||||
|
// -error
|
||||||
|
getPersonGenomeDiseaseLocusValuesMap := func(personGenomeIdentifier [16]byte, personDiseaseAnalysisObject geneticAnalysis.PersonPolygenicDiseaseInfo)(bool, map[int64]locusValue.LocusValue, error){
|
||||||
|
|
||||||
|
personPolygenicDiseaseInfoMap := personDiseaseAnalysisObject.PolygenicDiseaseInfoMap
|
||||||
|
|
||||||
|
personGenomeDiseaseInfoObject, exists := personPolygenicDiseaseInfoMap[personGenomeIdentifier]
|
||||||
|
if (exists == false){
|
||||||
|
// This person's genome has no information about loci related to this disease
|
||||||
|
return false, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
personGenomeLocusValuesMap := personGenomeDiseaseInfoObject.LocusValuesMap
|
||||||
|
|
||||||
|
return true, personGenomeLocusValuesMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
person2LocusValuesMap, exists := person2GenomesMap[person2GenomeIdentifier]
|
anyPerson1LociValuesExist, person1LocusValuesMap, err := getPersonGenomeDiseaseLocusValuesMap(person1GenomeIdentifier, person1DiseaseAnalysisObject)
|
||||||
if (exists == false){
|
if (err != nil) { return err }
|
||||||
return errors.New("addGenomePairDiseaseInfoToDiseaseMap called with unknown person2GenomeIdentifier.")
|
if (anyPerson1LociValuesExist == false){
|
||||||
|
// Offspring's disease info for this locus on this genome pair is unknown
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
anyOffspringLocusTested, genomePairOffspringAverageRiskScore, quantityOfLociTested, genomePairOffspringDiseaseLociInfoMap, genomePairSampleOffspringRiskScoresList, err := GetOffspringPolygenicDiseaseInfo(diseaseLociList, person1LocusValuesMap, person2LocusValuesMap)
|
anyPerson2LociValuesExist, person2LocusValuesMap, err := getPersonGenomeDiseaseLocusValuesMap(person2GenomeIdentifier, person2DiseaseAnalysisObject)
|
||||||
|
if (err != nil) { return err }
|
||||||
|
if (anyPerson2LociValuesExist == false){
|
||||||
|
// Offspring's disease info for this locus on this genome pair is unknown
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
anyOffspringLocusTested, genomePairOffspringAverageRiskScore, numberOfLociTested, genomePairOffspringDiseaseLociInfoMap, genomePairSampleOffspringRiskScoresList, err := GetOffspringPolygenicDiseaseInfo(diseaseLociList, person1LocusValuesMap, person2LocusValuesMap)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
if (anyOffspringLocusTested == false){
|
if (anyOffspringLocusTested == false){
|
||||||
// We have no information about this genome pair's disease risk
|
// We have no information about this genome pair's disease risk
|
||||||
|
@ -522,7 +537,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
|
|
||||||
newOffspringGenomePairPolygenicDiseaseInfo := geneticAnalysis.OffspringGenomePairPolygenicDiseaseInfo{
|
newOffspringGenomePairPolygenicDiseaseInfo := geneticAnalysis.OffspringGenomePairPolygenicDiseaseInfo{
|
||||||
|
|
||||||
QuantityOfLociTested: quantityOfLociTested,
|
NumberOfLociTested: numberOfLociTested,
|
||||||
OffspringAverageRiskScore: genomePairOffspringAverageRiskScore,
|
OffspringAverageRiskScore: genomePairOffspringAverageRiskScore,
|
||||||
LociInfoMap: genomePairOffspringDiseaseLociInfoMap,
|
LociInfoMap: genomePairOffspringDiseaseLociInfoMap,
|
||||||
SampleOffspringRiskScoresList: genomePairSampleOffspringRiskScoresList,
|
SampleOffspringRiskScoresList: genomePairSampleOffspringRiskScoresList,
|
||||||
|
@ -555,20 +570,34 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
|
|
||||||
checkIfConflictExists := func()(bool, error){
|
checkIfConflictExists := func()(bool, error){
|
||||||
|
|
||||||
currentGenomePairPolygenicDiseaseInfo := geneticAnalysis.OffspringGenomePairPolygenicDiseaseInfo{}
|
numberOfLociTested := 0
|
||||||
|
offspringAverageRiskScore := 0
|
||||||
|
offspringLociInfoMap := make(map[[3]byte]geneticAnalysis.OffspringPolygenicDiseaseLocusInfo)
|
||||||
|
|
||||||
firstItemReached := false
|
firstItemReached := false
|
||||||
|
|
||||||
for _, genomePairDiseaseInfoObject := range offspringPolygenicDiseaseInfoMap{
|
for _, genomePairDiseaseInfoObject := range offspringPolygenicDiseaseInfoMap{
|
||||||
|
|
||||||
|
genomePairNumberOfLociTested := genomePairDiseaseInfoObject.NumberOfLociTested
|
||||||
|
genomePairOffspringAverageRiskScore := genomePairDiseaseInfoObject.OffspringAverageRiskScore
|
||||||
|
genomePairLociInfoMap := genomePairDiseaseInfoObject.LociInfoMap
|
||||||
|
|
||||||
if (firstItemReached == false){
|
if (firstItemReached == false){
|
||||||
currentGenomePairPolygenicDiseaseInfo = genomePairDiseaseInfoObject
|
numberOfLociTested = genomePairNumberOfLociTested
|
||||||
|
offspringAverageRiskScore = genomePairOffspringAverageRiskScore
|
||||||
|
offspringLociInfoMap = genomePairLociInfoMap
|
||||||
firstItemReached = true
|
firstItemReached = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if (numberOfLociTested != genomePairNumberOfLociTested){
|
||||||
areEqual := reflect.DeepEqual(genomePairDiseaseInfoObject, currentGenomePairPolygenicDiseaseInfo)
|
return true, nil
|
||||||
|
}
|
||||||
|
if (offspringAverageRiskScore != genomePairOffspringAverageRiskScore){
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
areEqual := maps.Equal(offspringLociInfoMap, genomePairLociInfoMap)
|
||||||
if (areEqual == false){
|
if (areEqual == false){
|
||||||
|
// A conflict exists
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -593,140 +622,128 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
||||||
if (err != nil) { return false, "", err }
|
if (err != nil) { return false, "", err }
|
||||||
|
|
||||||
// Map Structure: Trait Name -> Trait Info Object
|
// Map Structure: Trait Name -> Trait Info Object
|
||||||
offspringDiscreteTraitsMap := make(map[string]geneticAnalysis.OffspringDiscreteTraitInfo)
|
offspringTraitsMap := make(map[string]geneticAnalysis.OffspringTraitInfo)
|
||||||
|
|
||||||
// Map Structure: Trait Name -> Trait Info Object
|
|
||||||
offspringNumericTraitsMap := make(map[string]geneticAnalysis.OffspringNumericTraitInfo)
|
|
||||||
|
|
||||||
for _, traitObject := range traitObjectsList{
|
for _, traitObject := range traitObjectsList{
|
||||||
|
|
||||||
traitName := traitObject.TraitName
|
traitName := traitObject.TraitName
|
||||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
|
||||||
|
|
||||||
if (traitIsDiscreteOrNumeric == "Discrete"){
|
person1TraitAnalysisObject, err := createPersonGeneticAnalysis.GetPersonTraitAnalysis(person1GenomesWithMetadataList, traitObject)
|
||||||
|
if (err != nil) { return false, "", err }
|
||||||
|
|
||||||
// This map stores the trait info for each genome pair
|
person2TraitAnalysisObject, err := createPersonGeneticAnalysis.GetPersonTraitAnalysis(person2GenomesWithMetadataList, traitObject)
|
||||||
// Map Structure: Genome Pair Identifier -> OffspringGenomePairDiscreteTraitInfo
|
if (err != nil) { return false, "", err }
|
||||||
offspringTraitInfoMap := make(map[[32]byte]geneticAnalysis.OffspringGenomePairDiscreteTraitInfo)
|
|
||||||
|
|
||||||
// This will add the offspring trait information for the provided genome pair to the offspringTraitInfoMap
|
// This map stores the trait info for each genome pair
|
||||||
addGenomePairTraitInfoToOffspringMap := func(person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
// Map Structure: Genome Pair Identifier -> OffspringGenomePairTraitInfo
|
||||||
|
offspringTraitInfoMap := make(map[[32]byte]geneticAnalysis.OffspringGenomePairTraitInfo)
|
||||||
|
|
||||||
person1LocusValuesMap, exists := person1GenomesMap[person1GenomeIdentifier]
|
// This will add the offspring trait information for the provided genome pair to the offspringTraitInfoMap
|
||||||
if (exists == false){
|
addGenomePairTraitInfoToOffspringMap := func(person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
||||||
return errors.New("addGenomePairTraitInfoToOffspringMap called with unknown person1GenomeIdentifier.")
|
|
||||||
}
|
|
||||||
|
|
||||||
person2LocusValuesMap, exists := person2GenomesMap[person2GenomeIdentifier]
|
person1TraitInfoMap := person1TraitAnalysisObject.TraitInfoMap
|
||||||
if (exists == false){
|
person2TraitInfoMap := person2TraitAnalysisObject.TraitInfoMap
|
||||||
return errors.New("addGenomePairTraitInfoToOffspringMap called with unknown person2GenomeIdentifier.")
|
|
||||||
}
|
|
||||||
|
|
||||||
newOffspringGenomePairTraitInfo := geneticAnalysis.OffspringGenomePairDiscreteTraitInfo{}
|
|
||||||
|
|
||||||
neuralNetworkExists, neuralNetworkAnalysisExists, outcomeProbabilitiesMap, averagePredictionConfidence, quantityOfLociTested, quantityOfParentalPhasedLoci, err := GetOffspringDiscreteTraitInfo_NeuralNetwork(traitObject, person1LocusValuesMap, person2LocusValuesMap)
|
|
||||||
if (err != nil) { return err }
|
|
||||||
if (neuralNetworkExists == true){
|
|
||||||
|
|
||||||
newOffspringGenomePairTraitInfo.NeuralNetworkExists = true
|
|
||||||
|
|
||||||
if (neuralNetworkAnalysisExists == true){
|
|
||||||
newOffspringGenomePairTraitInfo.NeuralNetworkAnalysisExists = true
|
|
||||||
|
|
||||||
newOffspringGenomePairTraitInfo_NeuralNetwork := geneticAnalysis.OffspringGenomePairDiscreteTraitInfo_NeuralNetwork{
|
|
||||||
|
|
||||||
OffspringOutcomeProbabilitiesMap: outcomeProbabilitiesMap,
|
|
||||||
AverageConfidence: averagePredictionConfidence,
|
|
||||||
QuantityOfLociKnown: quantityOfLociTested,
|
|
||||||
QuantityOfParentalPhasedLoci: quantityOfParentalPhasedLoci,
|
|
||||||
}
|
|
||||||
|
|
||||||
newOffspringGenomePairTraitInfo.NeuralNetworkAnalysis = newOffspringGenomePairTraitInfo_NeuralNetwork
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anyRulesExist, rulesAnalysisExists, quantityOfRulesTested, quantityOfLociKnown, offspringProbabilityOfPassingRulesMap, offspringOutcomeProbabilitiesMap, err := GetOffspringDiscreteTraitInfo_Rules(traitObject, person1LocusValuesMap, person2LocusValuesMap)
|
|
||||||
if (err != nil) { return err }
|
|
||||||
if (anyRulesExist == true){
|
|
||||||
|
|
||||||
newOffspringGenomePairTraitInfo.RulesExist = true
|
|
||||||
|
|
||||||
if (rulesAnalysisExists == true){
|
|
||||||
newOffspringGenomePairTraitInfo.RulesAnalysisExists = true
|
|
||||||
|
|
||||||
newOffspringGenomePairTraitInfo_Rules := geneticAnalysis.OffspringGenomePairDiscreteTraitInfo_Rules{
|
|
||||||
QuantityOfRulesTested: quantityOfRulesTested,
|
|
||||||
QuantityOfLociKnown: quantityOfLociKnown,
|
|
||||||
ProbabilityOfPassingRulesMap: offspringProbabilityOfPassingRulesMap,
|
|
||||||
OffspringOutcomeProbabilitiesMap: offspringOutcomeProbabilitiesMap,
|
|
||||||
}
|
|
||||||
|
|
||||||
newOffspringGenomePairTraitInfo.RulesAnalysis = newOffspringGenomePairTraitInfo_Rules
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
genomePairIdentifier := helpers.JoinTwo16ByteArrays(person1GenomeIdentifier, person2GenomeIdentifier)
|
|
||||||
|
|
||||||
offspringTraitInfoMap[genomePairIdentifier] = newOffspringGenomePairTraitInfo
|
|
||||||
|
|
||||||
|
person1GenomeTraitInfoObject, exists := person1TraitInfoMap[person1GenomeIdentifier]
|
||||||
|
if (exists == false){
|
||||||
|
// This person has no genome values for any loci for this trait
|
||||||
|
// No predictions are possible
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
person2GenomeTraitInfoObject, exists := person2TraitInfoMap[person2GenomeIdentifier]
|
||||||
|
if (exists == false){
|
||||||
|
// This person has no genome values for any loci for this trait
|
||||||
|
// No predictions are possible
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addGenomePairTraitInfoToOffspringMap(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
|
person1LocusValuesMap := person1GenomeTraitInfoObject.LocusValuesMap
|
||||||
|
person2LocusValuesMap := person2GenomeTraitInfoObject.LocusValuesMap
|
||||||
|
|
||||||
|
anyRulesTested, numberOfRulesTested, offspringProbabilityOfPassingRulesMap, offspringAverageOutcomeScoresMap, err := GetOffspringTraitInfo(traitObject, person1LocusValuesMap, person2LocusValuesMap)
|
||||||
|
if (err != nil) { return err }
|
||||||
|
if (anyRulesTested == false){
|
||||||
|
// No rules were tested for this trait
|
||||||
|
// We will not add anything to the trait info map for this genome pair
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newOffspringGenomePairTraitInfoObject := geneticAnalysis.OffspringGenomePairTraitInfo{
|
||||||
|
NumberOfRulesTested: numberOfRulesTested,
|
||||||
|
OffspringAverageOutcomeScoresMap: offspringAverageOutcomeScoresMap,
|
||||||
|
ProbabilityOfPassingRulesMap: offspringProbabilityOfPassingRulesMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
genomePairIdentifier := helpers.JoinTwo16ByteArrays(person1GenomeIdentifier, person2GenomeIdentifier)
|
||||||
|
|
||||||
|
offspringTraitInfoMap[genomePairIdentifier] = newOffspringGenomePairTraitInfoObject
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = addGenomePairTraitInfoToOffspringMap(pair1Person1GenomeIdentifier, pair1Person2GenomeIdentifier)
|
||||||
|
if (err != nil) { return false, "", err }
|
||||||
|
|
||||||
|
if (genomePair2Exists == true){
|
||||||
|
|
||||||
|
err := addGenomePairTraitInfoToOffspringMap(pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier)
|
||||||
if (err != nil) { return false, "", err }
|
if (err != nil) { return false, "", err }
|
||||||
|
}
|
||||||
|
|
||||||
if (genomePair2Exists == true){
|
newOffspringTraitInfoObject := geneticAnalysis.OffspringTraitInfo{
|
||||||
|
TraitInfoMap: offspringTraitInfoMap,
|
||||||
|
}
|
||||||
|
|
||||||
err := addGenomePairTraitInfoToOffspringMap(pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier)
|
if (len(offspringTraitInfoMap) >= 2){
|
||||||
if (err != nil) { return false, "", err }
|
|
||||||
}
|
|
||||||
|
|
||||||
newOffspringTraitInfoObject := geneticAnalysis.OffspringDiscreteTraitInfo{
|
// We check for conflicts
|
||||||
TraitInfoMap: offspringTraitInfoMap,
|
// Conflicts are only possible if two genome pairs exist with information about the trait
|
||||||
}
|
|
||||||
|
|
||||||
if (len(offspringTraitInfoMap) >= 2){
|
checkIfConflictExists := func()(bool, error){
|
||||||
|
|
||||||
// We check for conflicts
|
// We check for conflicts between each genome pair's outcome scores and trait rules maps
|
||||||
// Conflicts are only possible if two genome pairs exist with information about the trait
|
|
||||||
|
|
||||||
checkIfConflictExists := func()(bool, error){
|
offspringAverageOutcomeScoresMap := make(map[string]float64)
|
||||||
|
offspringProbabilityOfPassingRulesMap := make(map[[3]byte]int)
|
||||||
|
|
||||||
// We check for conflicts between each genome pair's outcome scores and trait rules maps
|
firstItemReached := false
|
||||||
|
|
||||||
genomePairTraitInfoObject := geneticAnalysis.OffspringGenomePairDiscreteTraitInfo{}
|
for _, genomePairTraitInfoObject := range offspringTraitInfoMap{
|
||||||
|
|
||||||
firstItemReached := false
|
currentOffspringAverageOutcomeScoresMap := genomePairTraitInfoObject.OffspringAverageOutcomeScoresMap
|
||||||
|
currentProbabilityOfPassingRulesMap := genomePairTraitInfoObject.ProbabilityOfPassingRulesMap
|
||||||
|
|
||||||
for _, currentGenomePairTraitInfoObject := range offspringTraitInfoMap{
|
if (firstItemReached == false){
|
||||||
|
offspringAverageOutcomeScoresMap = currentOffspringAverageOutcomeScoresMap
|
||||||
|
offspringProbabilityOfPassingRulesMap = currentProbabilityOfPassingRulesMap
|
||||||
|
|
||||||
if (firstItemReached == false){
|
firstItemReached = true
|
||||||
genomePairTraitInfoObject = currentGenomePairTraitInfoObject
|
continue
|
||||||
firstItemReached = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
areEqual := reflect.DeepEqual(genomePairTraitInfoObject, currentGenomePairTraitInfoObject)
|
|
||||||
if (areEqual == false){
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
areEqual := maps.Equal(offspringAverageOutcomeScoresMap, currentOffspringAverageOutcomeScoresMap)
|
||||||
|
if (areEqual == false){
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
areEqual = maps.Equal(offspringProbabilityOfPassingRulesMap, currentProbabilityOfPassingRulesMap)
|
||||||
|
if (areEqual == false){
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conflictExists, err := checkIfConflictExists()
|
return false, nil
|
||||||
if (err != nil) { return false, "", err }
|
|
||||||
|
|
||||||
newOffspringTraitInfoObject.ConflictExists = conflictExists
|
|
||||||
}
|
}
|
||||||
|
|
||||||
offspringDiscreteTraitsMap[traitName] = newOffspringTraitInfoObject
|
conflictExists, err := checkIfConflictExists()
|
||||||
|
if (err != nil) { return false, "", err }
|
||||||
|
|
||||||
|
newOffspringTraitInfoObject.ConflictExists = conflictExists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offspringTraitsMap[traitName] = newOffspringTraitInfoObject
|
||||||
}
|
}
|
||||||
|
|
||||||
newCoupleAnalysis.DiscreteTraitsMap = offspringDiscreteTraitsMap
|
newCoupleAnalysis.TraitsMap = offspringTraitsMap
|
||||||
newCoupleAnalysis.NumericTraitsMap = offspringNumericTraitsMap
|
|
||||||
|
|
||||||
analysisBytes, err := encoding.EncodeMessagePackBytes(newCoupleAnalysis)
|
analysisBytes, err := encoding.EncodeMessagePackBytes(newCoupleAnalysis)
|
||||||
if (err != nil) { return false, "", err }
|
if (err != nil) { return false, "", err }
|
||||||
|
@ -1119,187 +1136,144 @@ func GetOffspringPolygenicDiseaseInfo(diseaseLociList []polygenicDiseases.Diseas
|
||||||
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: A neural network exists for this trait
|
// -bool: Any rules tested (if false, no offspring trait information is known)
|
||||||
// -bool: Analysis exists (at least 1 locus exists for this analysis from both people's genomes
|
// -int: Number of rules tested
|
||||||
// -map[string]int: Outcome probabilities map
|
|
||||||
// Map Structure: Outcome Name -> Offspring probability of outcome
|
|
||||||
// -int: Average prediction confidence (the average prediction confidence for all prospective offspring)
|
|
||||||
// -int: Quantity of loci tested
|
|
||||||
// -int: Quantity of parental phased loci
|
|
||||||
// -error
|
|
||||||
func GetOffspringDiscreteTraitInfo_NeuralNetwork(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, map[string]int, int, int, int, error){
|
|
||||||
|
|
||||||
traitName := traitObject.TraitName
|
|
||||||
|
|
||||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
|
||||||
if (traitIsDiscreteOrNumeric != "Discrete"){
|
|
||||||
return false, false, nil, 0, 0, 0, errors.New("GetOffspringDiscreteTraitInfo_NeuralNetwork called with non-discrete trait.")
|
|
||||||
}
|
|
||||||
|
|
||||||
modelExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)
|
|
||||||
if (modelExists == false){
|
|
||||||
// Neural network prediction is not possible for this trait
|
|
||||||
return false, false, nil, 0, 0, 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
traitLociList := traitObject.LociList
|
|
||||||
|
|
||||||
// First we count up the quantity of parental phased loci
|
|
||||||
// We only count the quantity of phased loci for loci which are known for both parents
|
|
||||||
|
|
||||||
quantityOfParentalPhasedLoci := 0
|
|
||||||
|
|
||||||
for _, rsID := range traitLociList{
|
|
||||||
|
|
||||||
person1LocusValue, exists := person1LocusValuesMap[rsID]
|
|
||||||
if (exists == false){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
person2LocusValue, exists := person2LocusValuesMap[rsID]
|
|
||||||
if (exists == false){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
person1LocusIsPhased := person1LocusValue.LocusIsPhased
|
|
||||||
if (person1LocusIsPhased == true){
|
|
||||||
quantityOfParentalPhasedLoci += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
person2LocusIsPhased := person2LocusValue.LocusIsPhased
|
|
||||||
if (person2LocusIsPhased == true){
|
|
||||||
quantityOfParentalPhasedLoci += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, we create 100 prospective offspring genomes.
|
|
||||||
|
|
||||||
anyLocusValueExists, prospectiveOffspringGenomesList, err := getProspectiveOffspringGenomesList(traitLociList, person1LocusValuesMap, person2LocusValuesMap)
|
|
||||||
if (err != nil) { return false, false, nil, 0, 0, 0, err }
|
|
||||||
if (anyLocusValueExists == false){
|
|
||||||
return true, false, nil, 0, 0, 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map Structure: Outcome Name -> Probability of outcome coming true
|
|
||||||
// Because we are summing from 100 offspring, the count of outcomes is the same as the probability of an offspring having the outcome
|
|
||||||
outcomeCountsMap := make(map[string]int)
|
|
||||||
|
|
||||||
// This is a sum of each prediction's confidence
|
|
||||||
predictionConfidencesSum := 0
|
|
||||||
|
|
||||||
quantityOfLociTested := 0
|
|
||||||
|
|
||||||
for index, offspringGenomeMap := range prospectiveOffspringGenomesList{
|
|
||||||
|
|
||||||
neuralNetworkExists, predictionIsKnown, predictedOutcome, predictionConfidence, currentQuantityOfLociTested, _, err := createPersonGeneticAnalysis.GetGenomeDiscreteTraitAnalysis_NeuralNetwork(traitObject, offspringGenomeMap, false)
|
|
||||||
if (err != nil){ return false, false, nil, 0, 0, 0, err }
|
|
||||||
if (neuralNetworkExists == false){
|
|
||||||
return false, false, nil, 0, 0, 0, errors.New("GetGenomeTraitAnalysis_NeuralNetwork claiming that neural network doesn't exist when we already checked.")
|
|
||||||
}
|
|
||||||
if (predictionIsKnown == false){
|
|
||||||
return false, false, nil, 0, 0, 0, errors.New("GetGenomeTraitAnalysis_NeuralNetwork claiming that prediction is impossible when we already know at least 1 locus value exists for trait.")
|
|
||||||
}
|
|
||||||
|
|
||||||
outcomeCountsMap[predictedOutcome] += 1
|
|
||||||
predictionConfidencesSum += predictionConfidence
|
|
||||||
|
|
||||||
if (index == 0){
|
|
||||||
// This value should be the same for each predicted offspring
|
|
||||||
quantityOfLociTested = currentQuantityOfLociTested
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
averagePredictionConfidence := predictionConfidencesSum/100
|
|
||||||
|
|
||||||
return true, true, outcomeCountsMap, averagePredictionConfidence, quantityOfLociTested, quantityOfParentalPhasedLoci, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//Outputs:
|
|
||||||
// -bool: Any rules exist (if false, rule-based prediction is not possible for this trait)
|
|
||||||
// -bool: Rule-based analysis exists (if false, no offspring trait information is known, or there is an outcome tie for one of the offspring)
|
|
||||||
// -int: Quantity of rules tested
|
|
||||||
// -int: Quantity of loci known
|
|
||||||
// -map[[3]byte]int: Offspring probability of passing rules map
|
// -map[[3]byte]int: Offspring probability of passing rules map
|
||||||
// Map Structure: Rule identifier -> Offspring probability of passing rule (1-100)
|
// Map Structure: Rule identifier -> Offspring probability of passing rule (1-100)
|
||||||
// If a rule entry doesn't exist, we don't know the passes-rule probability for any of the offspring
|
// -map[string]float64: Offspring average outcome scores map
|
||||||
// -map[string]int: Offspring outcome probabilities map
|
// Map Structure: Outcome Name -> Offspring average outcome score
|
||||||
// Map Structure: Outcome Name -> Offspring probability of outcome (0-100)
|
|
||||||
// -error
|
// -error
|
||||||
func GetOffspringDiscreteTraitInfo_Rules(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, bool, int, int, map[[3]byte]int, map[string]int, error){
|
func GetOffspringTraitInfo(traitObject traits.Trait, person1LocusValuesMap map[int64]locusValue.LocusValue, person2LocusValuesMap map[int64]locusValue.LocusValue)(bool, int, map[[3]byte]int, map[string]float64, error){
|
||||||
|
|
||||||
traitRulesList := traitObject.RulesList
|
|
||||||
|
|
||||||
if (len(traitRulesList) == 0){
|
|
||||||
return false, false, 0, 0, nil, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len(person1LocusValuesMap) == 0){
|
if (len(person1LocusValuesMap) == 0){
|
||||||
return true, false, 0, 0, nil, nil, nil
|
return false, 0, nil, nil, nil
|
||||||
}
|
}
|
||||||
if (len(person2LocusValuesMap) == 0){
|
if (len(person2LocusValuesMap) == 0){
|
||||||
return true, false, 0, 0, nil, nil, nil
|
return false, 0, nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, we create 100 prospective offspring genomes.
|
// First, we create 100 prospective offspring genomes.
|
||||||
|
|
||||||
traitLociList_Rules := traitObject.LociList_Rules
|
traitLociList := traitObject.LociList
|
||||||
|
|
||||||
anyLocusValueExists, prospectiveOffspringGenomesList, err := getProspectiveOffspringGenomesList(traitLociList_Rules, person1LocusValuesMap, person2LocusValuesMap)
|
anyLocusValueExists, prospectiveOffspringGenomesList, err := getProspectiveOffspringGenomesList(traitLociList, person1LocusValuesMap, person2LocusValuesMap)
|
||||||
if (err != nil) { return false, false, 0, 0, nil, nil, err }
|
if (err != nil) { return false, 0, nil, nil, err }
|
||||||
if (anyLocusValueExists == false){
|
if (anyLocusValueExists == false){
|
||||||
return true, false, 0, 0, nil, nil, nil
|
return false, 0, nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
traitRulesList := traitObject.RulesList
|
||||||
|
|
||||||
// Map Structure: Rule Identifier -> Number of offspring who pass the rule (out of 100 prospective offspring)
|
// Map Structure: Rule Identifier -> Number of offspring who pass the rule (out of 100 prospective offspring)
|
||||||
// Because there are 100 offspring, this also represents the percentage probability that an offspring will pass the rule
|
|
||||||
offspringPassesRulesCountMap := make(map[[3]byte]int)
|
offspringPassesRulesCountMap := make(map[[3]byte]int)
|
||||||
|
|
||||||
// This map stores the quantity of offspring who have each outcome
|
// We use this map to keep track of the rules for which we know every offspring's passes-rule status
|
||||||
// The probability an offspring will have this outcome is the same as the
|
// Map Structure: Rule Identifier -> Rule Object
|
||||||
// quantity of offspring who have this outcome in our set of 100 randomly generated offspring
|
offspringRulesWithKnownStatusMap := make(map[[3]byte]traits.TraitRule)
|
||||||
// Map structure: Outcome name -> quantity of offspring who have this outcome
|
|
||||||
outcomeCountsMap := make(map[string]int)
|
|
||||||
|
|
||||||
quantityOfLociKnown := 0
|
for offspringIndex, offspringGenomeMap := range prospectiveOffspringGenomesList{
|
||||||
|
|
||||||
for index, offspringGenomeMap := range prospectiveOffspringGenomesList{
|
// We iterate through rules to determine genome pair trait info
|
||||||
|
|
||||||
// Now we get outcome prediction for prospective offspring
|
for _, ruleObject := range traitRulesList{
|
||||||
|
|
||||||
anyRulesExist, quantityOfRulesTested, currentQuantityOfLociKnown, offspringPassesRulesMap, predictionOutcomeIsKnown, predictedOutcome, err := createPersonGeneticAnalysis.GetGenomeDiscreteTraitAnalysis_Rules(traitObject, offspringGenomeMap, false)
|
ruleIdentifierHex := ruleObject.RuleIdentifier
|
||||||
if (err != nil) { return false, false, 0, 0, nil, nil, err }
|
|
||||||
if (anyRulesExist == false){
|
|
||||||
return false, false, 0, 0, nil, nil, errors.New("GetGenomeTraitAnalysis_Rules returning noRulesExists when we already checked and trait rules do in-fact exist.")
|
|
||||||
}
|
|
||||||
if (quantityOfRulesTested == 0){
|
|
||||||
// This will be the same for each of the 100 generated offspring
|
|
||||||
// No analysis is possible.
|
|
||||||
return true, false, 0, currentQuantityOfLociKnown, nil, nil, nil
|
|
||||||
}
|
|
||||||
if (index == 0){
|
|
||||||
// currentQuantityOfLociKnown will be the same for each prospective offspring
|
|
||||||
quantityOfLociKnown = currentQuantityOfLociKnown
|
|
||||||
}
|
|
||||||
|
|
||||||
for ruleIdentifier, genomePassesRule := range offspringPassesRulesMap{
|
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
|
||||||
if (genomePassesRule == true){
|
if (err != nil) { return false, 0, nil, nil, err }
|
||||||
|
|
||||||
|
if (offspringIndex == 0){
|
||||||
|
|
||||||
|
offspringRulesWithKnownStatusMap[ruleIdentifier] = ruleObject
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_, exists := offspringRulesWithKnownStatusMap[ruleIdentifier]
|
||||||
|
if (exists == false){
|
||||||
|
// We already tried to check a previous offspring's passes-rule status for this rule
|
||||||
|
// We know that the offspring's passes-rule status will be unknown for every prospective offspring
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a list that describes the locus rsids and their values that must be fulfilled to pass the rule
|
||||||
|
ruleLocusObjectsList := ruleObject.LociList
|
||||||
|
|
||||||
|
offspringPassesRuleIsKnown, offspringPassesRule, err := createPersonGeneticAnalysis.GetGenomePassesTraitRuleStatus(ruleLocusObjectsList, offspringGenomeMap, false)
|
||||||
|
if (err != nil){ return false, 0, nil, nil, err }
|
||||||
|
if (offspringPassesRuleIsKnown == false){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offspringPassesRule == true){
|
||||||
offspringPassesRulesCountMap[ruleIdentifier] += 1
|
offspringPassesRulesCountMap[ruleIdentifier] += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (predictionOutcomeIsKnown == false){
|
|
||||||
// There was a tie between outcomes for this offspring
|
|
||||||
// We can't predict anything about this trait for this couple using rules
|
|
||||||
// This is why we need to create rules which make it unlikely for a tie between outcomes to occur.
|
|
||||||
return true, false, 0, 0, nil, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
outcomeCountsMap[predictedOutcome] += 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quantityOfRulesTested := len(offspringPassesRulesCountMap)
|
// Map Structure: Rule Identifier -> Offspring Probability Of Passing Rule
|
||||||
|
// The map value stores the probability that the offspring will pass the rule
|
||||||
|
// This is a number between 0-100%
|
||||||
|
offspringProbabilityOfPassingRulesMap := make(map[[3]byte]int)
|
||||||
|
|
||||||
return true, true, quantityOfRulesTested, quantityOfLociKnown, offspringPassesRulesCountMap, outcomeCountsMap, nil
|
// Map Structure: Outcome Name -> Outcome Score
|
||||||
|
// Example: "Intolerant" -> 2.5
|
||||||
|
offspringAverageOutcomeScoresMap := make(map[string]float64)
|
||||||
|
|
||||||
|
for ruleIdentifier, ruleObject := range offspringRulesWithKnownStatusMap{
|
||||||
|
|
||||||
|
//Output:
|
||||||
|
// -int: Offspring probability of passing rule (0-100%)
|
||||||
|
getOffspringPercentageProbabilityOfPassingRule := func()int{
|
||||||
|
|
||||||
|
numberOfOffspringWhoPassRule, exists := offspringPassesRulesCountMap[ruleIdentifier]
|
||||||
|
if (exists == false){
|
||||||
|
// None of the offspring passed the rule
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are 100 tested offspring
|
||||||
|
// Thus, the percentage of offspring who passed the rule is the same as the number of offspring who passed the rule
|
||||||
|
// The probability of the offspring passing the rule is the same as the percentage of offspring who passed the rule
|
||||||
|
|
||||||
|
return numberOfOffspringWhoPassRule
|
||||||
|
}
|
||||||
|
|
||||||
|
offspringPercentageProbabilityOfPassingRule := getOffspringPercentageProbabilityOfPassingRule()
|
||||||
|
|
||||||
|
offspringProbabilityOfPassingRulesMap[ruleIdentifier] = offspringPercentageProbabilityOfPassingRule
|
||||||
|
|
||||||
|
// This is the 0 - 1 probability value
|
||||||
|
offspringProbabilityOfPassingRule := float64(offspringPercentageProbabilityOfPassingRule)/100
|
||||||
|
|
||||||
|
ruleOutcomePointsMap := ruleObject.OutcomePointsMap
|
||||||
|
|
||||||
|
for outcomeName, outcomePointsEffect := range ruleOutcomePointsMap{
|
||||||
|
|
||||||
|
pointsToAdd := float64(outcomePointsEffect) * offspringProbabilityOfPassingRule
|
||||||
|
|
||||||
|
offspringAverageOutcomeScoresMap[outcomeName] += pointsToAdd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numberOfRulesTested := len(offspringProbabilityOfPassingRulesMap)
|
||||||
|
|
||||||
|
if (numberOfRulesTested == 0){
|
||||||
|
return false, 0, nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
traitOutcomesList := traitObject.OutcomesList
|
||||||
|
|
||||||
|
// We add all outcomes for which there were no points
|
||||||
|
|
||||||
|
for _, traitOutcome := range traitOutcomesList{
|
||||||
|
|
||||||
|
_, exists := offspringAverageOutcomeScoresMap[traitOutcome]
|
||||||
|
if (exists == false){
|
||||||
|
offspringAverageOutcomeScoresMap[traitOutcome] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, numberOfRulesTested, offspringProbabilityOfPassingRulesMap, offspringAverageOutcomeScoresMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1307,10 +1281,6 @@ func GetOffspringDiscreteTraitInfo_Rules(traitObject traits.Trait, person1LocusV
|
||||||
// Each genome represents an equal-probability offspring genome from both people's genomes
|
// Each genome represents an equal-probability offspring genome from both people's genomes
|
||||||
// This function takes into account the effects of genetic linkage
|
// This function takes into account the effects of genetic linkage
|
||||||
// Any locations which do not exist in both people's genomes will not be included
|
// Any locations which do not exist in both people's genomes will not be included
|
||||||
//
|
|
||||||
// TODO: The user should be able to choose how many prospective offspring to create in the settings.
|
|
||||||
// More offspring will take longer, but will yield a more accurate trait analysis.
|
|
||||||
//
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: Any locus value exists between both users
|
// -bool: Any locus value exists between both users
|
||||||
// -[]map[int64]locusValue.LocusValue
|
// -[]map[int64]locusValue.LocusValue
|
||||||
|
@ -1418,7 +1388,7 @@ func getProspectiveOffspringGenomesList(lociList []int64, person1LociMap map[int
|
||||||
|
|
||||||
// We step by 1,000,000 each time
|
// We step by 1,000,000 each time
|
||||||
// It would be more realistic if we did it in 1 integer increments, but it would be slower
|
// It would be more realistic if we did it in 1 integer increments, but it would be slower
|
||||||
for position := int64(0); position < chromosomeLength; position += 1_000_000{
|
for position := int64(0); position <= chromosomeLength; position += 1000000{
|
||||||
|
|
||||||
//From Wikipedia:
|
//From Wikipedia:
|
||||||
// A centimorgan (abbreviated cM) is a unit for measuring genetic linkage.
|
// A centimorgan (abbreviated cM) is a unit for measuring genetic linkage.
|
||||||
|
@ -1471,19 +1441,14 @@ func getProspectiveOffspringGenomesList(lociList []int64, person1LociMap map[int
|
||||||
}
|
}
|
||||||
|
|
||||||
personLocusBase1 := personLocusValue.Base1Value
|
personLocusBase1 := personLocusValue.Base1Value
|
||||||
personLocusBase2 := personLocusValue.Base2Value
|
personLocusBase2 := personLocusValue.Base1Value
|
||||||
personLocusIsPhased := personLocusValue.LocusIsPhased
|
personLocusIsPhased := personLocusValue.LocusIsPhased
|
||||||
|
|
||||||
if (personLocusBase1 == personLocusBase2){
|
|
||||||
// Phase doesn't matter
|
|
||||||
return true, personLocusBase1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if (personLocusIsPhased == false){
|
if (personLocusIsPhased == false){
|
||||||
// Breakpoints are unnecessary
|
// Breakpoints are unnecessary
|
||||||
// We either choose base 1 or 2
|
// We either choose base 1 or 2
|
||||||
randomInt := pseudorandomNumberGenerator.IntN(2)
|
randomBool := helpers.GetRandomBool()
|
||||||
if (randomInt == 1){
|
if (randomBool == true){
|
||||||
return true, personLocusBase1, nil
|
return true, personLocusBase1, nil
|
||||||
}
|
}
|
||||||
return true, personLocusBase2, nil
|
return true, personLocusBase2, nil
|
||||||
|
@ -1525,9 +1490,9 @@ func getProspectiveOffspringGenomesList(lociList []int64, person1LociMap map[int
|
||||||
|
|
||||||
getLocusListIndex := func()int{
|
getLocusListIndex := func()int{
|
||||||
|
|
||||||
for index, breakpointPosition := range personBreakpointsList{
|
for index, breakpoint := range personBreakpointsList{
|
||||||
|
|
||||||
if (int64(locusPosition) <= breakpointPosition){
|
if (int64(locusPosition) <= breakpoint){
|
||||||
|
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,13 @@ import "seekia/resources/geneticReferences/traits"
|
||||||
|
|
||||||
import "seekia/internal/encoding"
|
import "seekia/internal/encoding"
|
||||||
import "seekia/internal/genetics/geneticAnalysis"
|
import "seekia/internal/genetics/geneticAnalysis"
|
||||||
import "seekia/internal/genetics/geneticPrediction"
|
|
||||||
import "seekia/internal/genetics/locusValue"
|
import "seekia/internal/genetics/locusValue"
|
||||||
import "seekia/internal/genetics/prepareRawGenomes"
|
import "seekia/internal/genetics/prepareRawGenomes"
|
||||||
import "seekia/internal/helpers"
|
import "seekia/internal/helpers"
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
import "slices"
|
import "slices"
|
||||||
import "reflect"
|
import "maps"
|
||||||
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
|
@ -52,23 +51,10 @@ func CreatePersonGeneticAnalysis(genomesList []prepareRawGenomes.RawGenomeWithMe
|
||||||
genomesWithMetadataList, allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(genomesList, prepareRawGenomesUpdatePercentageCompleteFunction)
|
genomesWithMetadataList, allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(genomesList, prepareRawGenomesUpdatePercentageCompleteFunction)
|
||||||
if (err != nil) { return false, "", err }
|
if (err != nil) { return false, "", err }
|
||||||
|
|
||||||
// This map stores each genome's locus values
|
|
||||||
// Map Structure: Genome Identifier -> Genome locus values map (rsID -> Locus Value)
|
|
||||||
genomesMap := make(map[[16]byte]map[int64]locusValue.LocusValue)
|
|
||||||
|
|
||||||
for _, genomeWithMetadata := range genomesWithMetadataList{
|
|
||||||
|
|
||||||
genomeIdentifier := genomeWithMetadata.GenomeIdentifier
|
|
||||||
genomeMap := genomeWithMetadata.GenomeMap
|
|
||||||
|
|
||||||
genomesMap[genomeIdentifier] = genomeMap
|
|
||||||
}
|
|
||||||
|
|
||||||
newGeneticAnalysisObject := geneticAnalysis.PersonAnalysis{
|
newGeneticAnalysisObject := geneticAnalysis.PersonAnalysis{
|
||||||
AnalysisVersion: 1,
|
AnalysisVersion: 1,
|
||||||
CombinedGenomesExist: multipleGenomesExist,
|
CombinedGenomesExist: multipleGenomesExist,
|
||||||
AllRawGenomeIdentifiersList: allRawGenomeIdentifiersList,
|
AllRawGenomeIdentifiersList: allRawGenomeIdentifiersList,
|
||||||
GenomesMap: genomesMap,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multipleGenomesExist == true){
|
if (multipleGenomesExist == true){
|
||||||
|
@ -121,30 +107,20 @@ func CreatePersonGeneticAnalysis(genomesList []prepareRawGenomes.RawGenomeWithMe
|
||||||
traitObjectsList, err := traits.GetTraitObjectsList()
|
traitObjectsList, err := traits.GetTraitObjectsList()
|
||||||
if (err != nil) { return false, "", err }
|
if (err != nil) { return false, "", err }
|
||||||
|
|
||||||
// This map will always contain an entry for each discrete trait
|
// Map Structure: Trait Name -> PersonTraitInfo
|
||||||
// Map Structure: Trait Name -> PersonDiscreteTraitInfo
|
analysisTraitsMap := make(map[string]geneticAnalysis.PersonTraitInfo)
|
||||||
analysisDiscreteTraitsMap := make(map[string]geneticAnalysis.PersonDiscreteTraitInfo)
|
|
||||||
|
|
||||||
// This map will not contain entries for traits which this person's genome has no known loci
|
|
||||||
// Map Structure: Trait Name -> PersonNumericTraitInfo
|
|
||||||
analysisNumericTraitsMap := make(map[string]geneticAnalysis.PersonNumericTraitInfo)
|
|
||||||
|
|
||||||
for _, traitObject := range traitObjectsList{
|
for _, traitObject := range traitObjectsList{
|
||||||
|
|
||||||
|
personTraitAnalysisObject, err := GetPersonTraitAnalysis(genomesWithMetadataList, traitObject)
|
||||||
|
if (err != nil) { return false, "", err }
|
||||||
|
|
||||||
traitName := traitObject.TraitName
|
traitName := traitObject.TraitName
|
||||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
|
||||||
|
|
||||||
if (traitIsDiscreteOrNumeric == "Discrete"){
|
analysisTraitsMap[traitName] = personTraitAnalysisObject
|
||||||
|
|
||||||
personTraitAnalysisObject, err := GetPersonDiscreteTraitAnalysis(genomesWithMetadataList, traitObject)
|
|
||||||
if (err != nil) { return false, "", err }
|
|
||||||
|
|
||||||
analysisDiscreteTraitsMap[traitName] = personTraitAnalysisObject
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newGeneticAnalysisObject.DiscreteTraitsMap = analysisDiscreteTraitsMap
|
newGeneticAnalysisObject.TraitsMap = analysisTraitsMap
|
||||||
newGeneticAnalysisObject.NumericTraitsMap = analysisNumericTraitsMap
|
|
||||||
|
|
||||||
analysisBytes, err := encoding.EncodeMessagePackBytes(newGeneticAnalysisObject)
|
analysisBytes, err := encoding.EncodeMessagePackBytes(newGeneticAnalysisObject)
|
||||||
if (err != nil) { return false, "", err }
|
if (err != nil) { return false, "", err }
|
||||||
|
@ -529,9 +505,9 @@ func GetPersonMonogenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
|
||||||
|
|
||||||
diseaseAnalysisObject := geneticAnalysis.PersonGenomeMonogenicDiseaseInfo{
|
diseaseAnalysisObject := geneticAnalysis.PersonGenomeMonogenicDiseaseInfo{
|
||||||
PersonHasDisease: personHasDisease,
|
PersonHasDisease: personHasDisease,
|
||||||
QuantityOfVariantsTested: numberOfVariantsTested,
|
NumberOfVariantsTested: numberOfVariantsTested,
|
||||||
QuantityOfLociTested: numberOfLociTested,
|
NumberOfLociTested: numberOfLociTested,
|
||||||
QuantityOfPhasedLoci: numberOfPhasedLoci,
|
NumberOfPhasedLoci: numberOfPhasedLoci,
|
||||||
ProbabilityOfPassingADiseaseVariant: percentageProbabilityPersonWillPassADiseaseVariant,
|
ProbabilityOfPassingADiseaseVariant: percentageProbabilityPersonWillPassADiseaseVariant,
|
||||||
VariantsInfoMap: variantsInfoMap,
|
VariantsInfoMap: variantsInfoMap,
|
||||||
}
|
}
|
||||||
|
@ -761,15 +737,16 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
|
||||||
genomeLocusValuesMap[locusRSID] = locusValueObject
|
genomeLocusValuesMap[locusRSID] = locusValueObject
|
||||||
}
|
}
|
||||||
|
|
||||||
anyLociTested, personDiseaseRiskScore, genomeNumberOfLociTested, genomeLociInfoMap, err := GetPersonGenomePolygenicDiseaseInfo(diseaseLociList, genomeLocusValuesMap, true)
|
anyLociTested, personDiseaseRiskScore, genomeNumberOfLociTested, genomeLociInfoMap, err := GetPersonGenomePolygenicDiseaseInfo(diseaseLociList, genomeLocusValuesMap, false)
|
||||||
if (err != nil) { return emptyDiseaseInfoObject, err }
|
if (err != nil) { return emptyDiseaseInfoObject, err }
|
||||||
if (anyLociTested == false){
|
if (anyLociTested == false){
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
newDiseaseInfoObject := geneticAnalysis.PersonGenomePolygenicDiseaseInfo{
|
newDiseaseInfoObject := geneticAnalysis.PersonGenomePolygenicDiseaseInfo{
|
||||||
QuantityOfLociTested: genomeNumberOfLociTested,
|
NumberOfLociTested: genomeNumberOfLociTested,
|
||||||
RiskScore: personDiseaseRiskScore,
|
RiskScore: personDiseaseRiskScore,
|
||||||
|
LocusValuesMap: genomeLocusValuesMap,
|
||||||
LociInfoMap: genomeLociInfoMap,
|
LociInfoMap: genomeLociInfoMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -800,7 +777,7 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
|
||||||
for _, personGenomeDiseaseInfoObject := range personPolygenicDiseaseInfoMap{
|
for _, personGenomeDiseaseInfoObject := range personPolygenicDiseaseInfoMap{
|
||||||
|
|
||||||
currentGenomeRiskScore := personGenomeDiseaseInfoObject.RiskScore
|
currentGenomeRiskScore := personGenomeDiseaseInfoObject.RiskScore
|
||||||
currentGenomeNumberOfLociTested := personGenomeDiseaseInfoObject.QuantityOfLociTested
|
currentGenomeNumberOfLociTested := personGenomeDiseaseInfoObject.NumberOfLociTested
|
||||||
|
|
||||||
if (firstItemReached == false){
|
if (firstItemReached == false){
|
||||||
genomeRiskScore = currentGenomeRiskScore
|
genomeRiskScore = currentGenomeRiskScore
|
||||||
|
@ -878,68 +855,106 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
|
||||||
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -geneticAnalysis.PersonDiscreteTraitInfo: Trait analysis object
|
// -geneticAnalysis.PersonTraitInfo: Trait analysis object
|
||||||
// -error
|
// -error
|
||||||
func GetPersonDiscreteTraitAnalysis(inputGenomesWithMetadataList []prepareRawGenomes.GenomeWithMetadata, traitObject traits.Trait)(geneticAnalysis.PersonDiscreteTraitInfo, error){
|
func GetPersonTraitAnalysis(inputGenomesWithMetadataList []prepareRawGenomes.GenomeWithMetadata, traitObject traits.Trait)(geneticAnalysis.PersonTraitInfo, error){
|
||||||
|
|
||||||
// Map Structure: Genome Identifier -> PersonGenomeDiscreteTraitInfo
|
// We use this when returning errors
|
||||||
newPersonTraitInfoMap := make(map[[16]byte]geneticAnalysis.PersonGenomeDiscreteTraitInfo)
|
emptyPersonTraitInfo := geneticAnalysis.PersonTraitInfo{}
|
||||||
|
|
||||||
|
traitLociList := traitObject.LociList
|
||||||
|
traitRulesList := traitObject.RulesList
|
||||||
|
|
||||||
|
// Map Structure: Genome Identifier -> PersonGenomeTraitInfo
|
||||||
|
newPersonTraitInfoMap := make(map[[16]byte]geneticAnalysis.PersonGenomeTraitInfo)
|
||||||
|
|
||||||
for _, genomeWithMetadataObject := range inputGenomesWithMetadataList{
|
for _, genomeWithMetadataObject := range inputGenomesWithMetadataList{
|
||||||
|
|
||||||
genomeIdentifier := genomeWithMetadataObject.GenomeIdentifier
|
genomeIdentifier := genomeWithMetadataObject.GenomeIdentifier
|
||||||
genomeMap := genomeWithMetadataObject.GenomeMap
|
genomeMap := genomeWithMetadataObject.GenomeMap
|
||||||
|
|
||||||
newPersonGenomeTraitInfo := geneticAnalysis.PersonGenomeDiscreteTraitInfo{}
|
// This map contains the locus values for the genome
|
||||||
|
// If an locus's entry doesn't exist, its value is unknown
|
||||||
|
// Map Structure: Locus rsID -> Locus Value
|
||||||
|
genomeLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
|
||||||
neuralNetworkExists, neuralNetworkOutcomeIsKnown, predictedOutcome, predictionConfidence, quantityOfLociTested, quantityOfPhasedLoci, err := GetGenomeDiscreteTraitAnalysis_NeuralNetwork(traitObject, genomeMap, true)
|
for _, locusRSID := range traitLociList{
|
||||||
if (err != nil) { return geneticAnalysis.PersonDiscreteTraitInfo{}, err }
|
|
||||||
if (neuralNetworkExists == true){
|
|
||||||
|
|
||||||
newPersonGenomeTraitInfo.NeuralNetworkExists = true
|
locusBasePairKnown, _, _, _, locusValueObject, err := GetLocusValueFromGenomeMap(true, genomeMap, locusRSID)
|
||||||
|
if (err != nil) { return emptyPersonTraitInfo, err }
|
||||||
|
if (locusBasePairKnown == false){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (neuralNetworkOutcomeIsKnown == true){
|
genomeLocusValuesMap[locusRSID] = locusValueObject
|
||||||
|
}
|
||||||
|
|
||||||
newPersonGenomeTraitInfo.NeuralNetworkAnalysisExists = true
|
// This map contains the trait outcome scores for the genome
|
||||||
|
// Map Structure: Outcome Name -> Score
|
||||||
|
// Example: "Intolerant" -> 5
|
||||||
|
traitOutcomeScoresMap := make(map[string]int)
|
||||||
|
|
||||||
newPersonGenomeTraitInfo_NeuralNetwork := geneticAnalysis.PersonGenomeDiscreteTraitInfo_NeuralNetwork{
|
// Map Structure: Rule Identifier -> Genome Passes rule (true if the genome passes the rule)
|
||||||
|
personPassesRulesMap := make(map[[3]byte]bool)
|
||||||
|
|
||||||
PredictedOutcome: predictedOutcome,
|
if (len(traitRulesList) != 0){
|
||||||
PredictionConfidence: predictionConfidence,
|
|
||||||
QuantityOfLociKnown: quantityOfLociTested,
|
// At least 1 rule exists for this trait
|
||||||
QuantityOfPhasedLoci: quantityOfPhasedLoci,
|
|
||||||
|
for _, ruleObject := range traitRulesList{
|
||||||
|
|
||||||
|
ruleIdentifierHex := ruleObject.RuleIdentifier
|
||||||
|
|
||||||
|
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
|
||||||
|
if (err != nil) { return emptyPersonTraitInfo, err }
|
||||||
|
|
||||||
|
ruleLociList := ruleObject.LociList
|
||||||
|
|
||||||
|
genomePassesRuleIsKnown, genomePassesRule, err := GetGenomePassesTraitRuleStatus(ruleLociList, genomeMap, false)
|
||||||
|
if (err != nil) { return emptyPersonTraitInfo, err }
|
||||||
|
if (genomePassesRuleIsKnown == false){
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
newPersonGenomeTraitInfo.NeuralNetworkAnalysis = newPersonGenomeTraitInfo_NeuralNetwork
|
personPassesRulesMap[ruleIdentifier] = genomePassesRule
|
||||||
|
|
||||||
|
// The rule has been passed by this genome
|
||||||
|
// We add the outcome points for the rule to the traitOutcomeScoresMap
|
||||||
|
|
||||||
|
ruleOutcomePointsMap := ruleObject.OutcomePointsMap
|
||||||
|
|
||||||
|
for traitOutcome, pointsChange := range ruleOutcomePointsMap{
|
||||||
|
|
||||||
|
traitOutcomeScoresMap[traitOutcome] += pointsChange
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
anyRulesExist, quantityOfRulesTested, quantityOfLociKnown, genomePassesRulesMap, predictedOutcomeExists, predictedOutcome, err := GetGenomeDiscreteTraitAnalysis_Rules(traitObject, genomeMap, true)
|
traitOutcomesList := traitObject.OutcomesList
|
||||||
if (err != nil) { return geneticAnalysis.PersonDiscreteTraitInfo{}, err }
|
|
||||||
if (anyRulesExist == true){
|
|
||||||
newPersonGenomeTraitInfo.AnyRulesExist = true
|
|
||||||
|
|
||||||
if (quantityOfRulesTested != 0){
|
// We add all outcomes for which there were no points
|
||||||
|
|
||||||
newPersonGenomeTraitInfo.RulesAnalysisExists = true
|
for _, traitOutcome := range traitOutcomesList{
|
||||||
|
|
||||||
newPersonGenomeTraitInfo_Rules := geneticAnalysis.PersonGenomeDiscreteTraitInfo_Rules{
|
_, exists := traitOutcomeScoresMap[traitOutcome]
|
||||||
|
if (exists == false){
|
||||||
GenomePassesRulesMap: genomePassesRulesMap,
|
traitOutcomeScoresMap[traitOutcome] = 0
|
||||||
PredictedOutcomeExists: predictedOutcomeExists,
|
|
||||||
PredictedOutcome: predictedOutcome,
|
|
||||||
QuantityOfRulesTested: quantityOfRulesTested,
|
|
||||||
QuantityOfLociKnown: quantityOfLociKnown,
|
|
||||||
}
|
|
||||||
|
|
||||||
newPersonGenomeTraitInfo.RulesAnalysis = newPersonGenomeTraitInfo_Rules
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
numberOfRulesTested := len(personPassesRulesMap)
|
||||||
|
|
||||||
|
newPersonGenomeTraitInfo := geneticAnalysis.PersonGenomeTraitInfo{
|
||||||
|
NumberOfRulesTested: numberOfRulesTested,
|
||||||
|
LocusValuesMap: genomeLocusValuesMap,
|
||||||
|
OutcomeScoresMap: traitOutcomeScoresMap,
|
||||||
|
GenomePassesRulesMap: personPassesRulesMap,
|
||||||
|
}
|
||||||
|
|
||||||
newPersonTraitInfoMap[genomeIdentifier] = newPersonGenomeTraitInfo
|
newPersonTraitInfoMap[genomeIdentifier] = newPersonGenomeTraitInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
newPersonTraitInfoObject := geneticAnalysis.PersonDiscreteTraitInfo{
|
newPersonTraitInfoObject := geneticAnalysis.PersonTraitInfo{
|
||||||
TraitInfoMap: newPersonTraitInfoMap,
|
TraitInfoMap: newPersonTraitInfoMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -953,20 +968,40 @@ func GetPersonDiscreteTraitAnalysis(inputGenomesWithMetadataList []prepareRawGen
|
||||||
|
|
||||||
getConflictExistsBool := func()(bool, error){
|
getConflictExistsBool := func()(bool, error){
|
||||||
|
|
||||||
// We check to see if the analysis results are the same for all genomes
|
//TODO: Check for locus value conflicts once locus values are used in neural network prediction.
|
||||||
|
|
||||||
|
if (len(traitRulesList) == 0){
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We check to see if the outcome scores are the same for all genomes
|
||||||
|
// We also check each rule result
|
||||||
|
|
||||||
firstItemReached := false
|
firstItemReached := false
|
||||||
personGenomeTraitInfoObject := geneticAnalysis.PersonGenomeDiscreteTraitInfo{}
|
|
||||||
|
outcomeScoresMap := make(map[string]int)
|
||||||
|
passesRulesMap := make(map[[3]byte]bool)
|
||||||
|
|
||||||
for _, genomeTraitInfoObject := range newPersonTraitInfoMap{
|
for _, genomeTraitInfoObject := range newPersonTraitInfoMap{
|
||||||
|
|
||||||
|
currentGenomeOutcomeScoresMap := genomeTraitInfoObject.OutcomeScoresMap
|
||||||
|
currentGenomePassesRulesMap := genomeTraitInfoObject.GenomePassesRulesMap
|
||||||
|
|
||||||
if (firstItemReached == false){
|
if (firstItemReached == false){
|
||||||
personGenomeTraitInfoObject = genomeTraitInfoObject
|
outcomeScoresMap = currentGenomeOutcomeScoresMap
|
||||||
|
passesRulesMap = currentGenomePassesRulesMap
|
||||||
|
firstItemReached = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
areEqual := reflect.DeepEqual(personGenomeTraitInfoObject, genomeTraitInfoObject)
|
areEqual := maps.Equal(currentGenomeOutcomeScoresMap, outcomeScoresMap)
|
||||||
if (areEqual == false){
|
if (areEqual == false){
|
||||||
|
// A conflict exists
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
areEqual = maps.Equal(currentGenomePassesRulesMap, passesRulesMap)
|
||||||
|
if (areEqual == false){
|
||||||
|
// A conflict exists
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -975,7 +1010,7 @@ func GetPersonDiscreteTraitAnalysis(inputGenomesWithMetadataList []prepareRawGen
|
||||||
}
|
}
|
||||||
|
|
||||||
conflictExists, err := getConflictExistsBool()
|
conflictExists, err := getConflictExistsBool()
|
||||||
if (err != nil) { return geneticAnalysis.PersonDiscreteTraitInfo{}, err }
|
if (err != nil) { return emptyPersonTraitInfo, err }
|
||||||
|
|
||||||
newPersonTraitInfoObject.ConflictExists = conflictExists
|
newPersonTraitInfoObject.ConflictExists = conflictExists
|
||||||
|
|
||||||
|
@ -1011,205 +1046,12 @@ func GetGenomePolygenicDiseaseLocusRiskInfo(locusRiskWeightsMap map[string]int,
|
||||||
return riskWeight, true, oddsRatio, nil
|
return riskWeight, true, oddsRatio, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use this to generate trait predictions using a neural network
|
|
||||||
// The alternative prediction method is to use Rules (see GetGenomeTraitAnalysis_Rules)
|
|
||||||
//Outputs:
|
|
||||||
// -bool: Trait Neural network analysis available (if false, we can't predict this trait using a neural network)
|
|
||||||
// -bool: Neural network outcome is known (at least 1 locus value is known which is needed for the neural network
|
|
||||||
// -string: The predicted outcome (Example: "Blue")
|
|
||||||
// -int: Probability (0-100) that the outcome from neural network is true (confidence)
|
|
||||||
// -int: Quantity of loci tested
|
|
||||||
// -int: Quantity of phased loci
|
|
||||||
// -error
|
|
||||||
func GetGenomeDiscreteTraitAnalysis_NeuralNetwork(traitObject traits.Trait, genomeMap map[int64]locusValue.LocusValue, checkForAliases bool)(bool, bool, string, int, int, int, error){
|
|
||||||
|
|
||||||
getGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
|
||||||
|
|
||||||
if (checkForAliases == false){
|
|
||||||
// We don't need to check for rsID aliases.
|
|
||||||
return genomeMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
traitLociList := traitObject.LociList
|
|
||||||
|
|
||||||
// This map contains the locus values for the genome
|
|
||||||
// If a locus's entry doesn't exist, its value is unknown
|
|
||||||
// Map Structure: Locus rsID -> Locus Value
|
|
||||||
genomeLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
|
||||||
|
|
||||||
for _, locusRSID := range traitLociList{
|
|
||||||
|
|
||||||
locusBasePairKnown, _, _, _, locusValueObject, err := GetLocusValueFromGenomeMap(checkForAliases, genomeMap, locusRSID)
|
|
||||||
if (err != nil) { return nil, err }
|
|
||||||
if (locusBasePairKnown == false){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
genomeLocusValuesMap[locusRSID] = locusValueObject
|
|
||||||
}
|
|
||||||
|
|
||||||
return genomeLocusValuesMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
genomeLocusValuesMap, err := getGenomeLocusValuesMap()
|
|
||||||
if (err != nil) { return false, false, "", 0, 0, 0, err }
|
|
||||||
|
|
||||||
traitName := traitObject.TraitName
|
|
||||||
|
|
||||||
neuralNetworkModelExists, traitPredictionIsPossible, predictedOutcome, predictionConfidence, quantityOfLociKnown, quantityOfPhasedLoci, err := geneticPrediction.GetNeuralNetworkTraitPredictionFromGenomeMap(traitName, genomeLocusValuesMap)
|
|
||||||
if (err != nil) { return false, false, "", 0, 0, 0, err }
|
|
||||||
if (neuralNetworkModelExists == false){
|
|
||||||
return false, false, "", 0, 0, 0, nil
|
|
||||||
}
|
|
||||||
if (traitPredictionIsPossible == false){
|
|
||||||
return true, false, "", 0, 0, 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, true, predictedOutcome, predictionConfidence, quantityOfLociKnown, quantityOfPhasedLoci, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//Outputs:
|
|
||||||
// -bool: Rule-based trait prediction is available
|
|
||||||
// -int: Quantity of trait rules tested
|
|
||||||
// -int: Quantity of loci known
|
|
||||||
// -map[[3]byte]bool: Passed rules map (Rule Identifier -> Genome passes rule)
|
|
||||||
// -bool: Rule-based prediction outcome is known (at least 1 rule has been tested and there is no outcome tie)
|
|
||||||
// -string: The predicted outcome (Example: "Tolerant")
|
|
||||||
// -error
|
|
||||||
func GetGenomeDiscreteTraitAnalysis_Rules(traitObject traits.Trait, genomeMap map[int64]locusValue.LocusValue, checkForAliases bool)(bool, int, int, map[[3]byte]bool, bool, string, error){
|
|
||||||
|
|
||||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
|
||||||
if (traitIsDiscreteOrNumeric != "Discrete"){
|
|
||||||
return false, 0, 0, nil, false, "", errors.New("GetGenomeDiscreteTraitAnalysis_Rules called with non-discrete trait.")
|
|
||||||
}
|
|
||||||
|
|
||||||
traitRulesList := traitObject.RulesList
|
|
||||||
|
|
||||||
if (len(traitRulesList) == 0){
|
|
||||||
// We can't predict this trait using rules
|
|
||||||
// This means that neural network prediction is the only alternative potential way to predict this trait
|
|
||||||
return false, 0, 0, nil, false, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// This map contains the trait outcome scores for the genome
|
|
||||||
// Map Structure: Outcome Name -> Score
|
|
||||||
// Example: "Intolerant" -> 5
|
|
||||||
traitOutcomeScoresMap := make(map[string]int)
|
|
||||||
|
|
||||||
// Map Structure: Rule Identifier -> Genome Passes rule (true if the genome passes the rule)
|
|
||||||
personPassesRulesMap := make(map[[3]byte]bool)
|
|
||||||
|
|
||||||
// This map stores each known loci
|
|
||||||
// Multiple rules can use the same loci, so we need a map to avoid duplicates
|
|
||||||
// Map Structure: Locus RSID -> Locus is known
|
|
||||||
lociAreKnownMap := make(map[int64]bool)
|
|
||||||
|
|
||||||
for _, ruleObject := range traitRulesList{
|
|
||||||
|
|
||||||
ruleIdentifierHex := ruleObject.RuleIdentifier
|
|
||||||
|
|
||||||
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
|
|
||||||
if (err != nil) { return false, 0, 0, nil, false, "", err }
|
|
||||||
|
|
||||||
ruleLociList := ruleObject.LociList
|
|
||||||
|
|
||||||
for _, locusObject := range ruleLociList{
|
|
||||||
|
|
||||||
locusRSID := locusObject.LocusRSID
|
|
||||||
|
|
||||||
_, exists := lociAreKnownMap[locusRSID]
|
|
||||||
if (exists == true){
|
|
||||||
// We already know if this locus is known
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
locusIsKnown, _, _, _, _, err := GetLocusValueFromGenomeMap(checkForAliases, genomeMap, locusRSID)
|
|
||||||
if (err != nil) { return false, 0, 0, nil, false, "", err }
|
|
||||||
|
|
||||||
lociAreKnownMap[locusRSID] = locusIsKnown
|
|
||||||
}
|
|
||||||
|
|
||||||
genomePassesRuleIsKnown, genomePassesRule, err := GetGenomePassesDiscreteTraitRuleStatus(ruleLociList, genomeMap, checkForAliases)
|
|
||||||
if (err != nil) { return false, 0, 0, nil, false, "", err }
|
|
||||||
if (genomePassesRuleIsKnown == false){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
personPassesRulesMap[ruleIdentifier] = genomePassesRule
|
|
||||||
|
|
||||||
// The rule has been passed by this genome
|
|
||||||
// We add the outcome points for the rule to the traitOutcomeScoresMap
|
|
||||||
|
|
||||||
ruleOutcomePointsMap := ruleObject.OutcomePointsMap
|
|
||||||
|
|
||||||
for traitOutcome, pointsChange := range ruleOutcomePointsMap{
|
|
||||||
|
|
||||||
traitOutcomeScoresMap[traitOutcome] += pointsChange
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
quantityOfLociKnown := 0
|
|
||||||
|
|
||||||
for _, locusIsKnown := range lociAreKnownMap{
|
|
||||||
if (locusIsKnown == true){
|
|
||||||
quantityOfLociKnown += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
quantityOfRulesTested := len(personPassesRulesMap)
|
|
||||||
|
|
||||||
if (quantityOfRulesTested == 0){
|
|
||||||
return true, 0, quantityOfLociKnown, personPassesRulesMap, false, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// -bool: Outcome is known (will be false if there is a tie
|
|
||||||
// -string:
|
|
||||||
// -error
|
|
||||||
getOutcome := func()(bool, string, error){
|
|
||||||
|
|
||||||
largestOutcome := ""
|
|
||||||
largestOutcomePoints := 0
|
|
||||||
tieExists := false
|
|
||||||
|
|
||||||
for outcomeName, outcomePoints := range traitOutcomeScoresMap{
|
|
||||||
|
|
||||||
if (outcomePoints < 1){
|
|
||||||
// This should never happen, because outcomes points should only be increased by integers which are at least 1 or greater
|
|
||||||
return false, "", errors.New("traitOutcomeScoresMap contains outcomePoints < 1.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outcomePoints > largestOutcomePoints){
|
|
||||||
largestOutcome = outcomeName
|
|
||||||
largestOutcomePoints = outcomePoints
|
|
||||||
tieExists = false
|
|
||||||
continue
|
|
||||||
|
|
||||||
} else if (outcomePoints == largestOutcomePoints){
|
|
||||||
tieExists = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tieExists == true){
|
|
||||||
return false, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, largestOutcome, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
outcomeIsKnown, outcomeName, err := getOutcome()
|
|
||||||
if (err != nil) { return false, 0, 0, nil, false, "", err }
|
|
||||||
if (outcomeIsKnown == false){
|
|
||||||
return true, quantityOfRulesTested, quantityOfLociKnown, personPassesRulesMap, false, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, quantityOfRulesTested, quantityOfLociKnown, personPassesRulesMap, true, outcomeName, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function checks to see if a genome will pass a trait rule
|
// This function checks to see if a genome will pass a trait rule
|
||||||
// Outputs:
|
// Outputs:
|
||||||
// -bool: Genome passes trait rule status is known
|
// -bool: Genome passes trait rule status is known
|
||||||
// -bool: Genome passes trait rule
|
// -bool: Genome passes trait rule
|
||||||
// -error
|
// -error
|
||||||
func GetGenomePassesDiscreteTraitRuleStatus(ruleLociList []traits.RuleLocus, genomeMap map[int64]locusValue.LocusValue, checkForAliases bool)(bool, bool, error){
|
func GetGenomePassesTraitRuleStatus(ruleLociList []traits.RuleLocus, genomeMap map[int64]locusValue.LocusValue, checkForAliases bool)(bool, bool, error){
|
||||||
|
|
||||||
// We check to see if genome passes all rule loci
|
// We check to see if genome passes all rule loci
|
||||||
// To pass a rule, all of the rule's loci must be passed by the provided genome
|
// To pass a rule, all of the rule's loci must be passed by the provided genome
|
||||||
|
|
|
@ -22,27 +22,14 @@ type PersonAnalysis struct{
|
||||||
OnlyIncludeSharedGenomeIdentifier [16]byte
|
OnlyIncludeSharedGenomeIdentifier [16]byte
|
||||||
OnlyExcludeConflictsGenomeIdentifier [16]byte
|
OnlyExcludeConflictsGenomeIdentifier [16]byte
|
||||||
|
|
||||||
// This map stores each genome's locus values
|
|
||||||
// Only the loci that belong in the locusMetadata package are inside of this map
|
|
||||||
// This is necessary, otherwise genetic analyses would be too large by containing each analyzed raw genome.
|
|
||||||
// Map Structure: Genome Identifier -> Genome locus values map (rsID -> Locus Value)
|
|
||||||
GenomesMap map[[16]byte]map[int64]locusValue.LocusValue
|
|
||||||
|
|
||||||
// Map Structure: Disease Name -> PersonMonogenicDiseaseInfo
|
// Map Structure: Disease Name -> PersonMonogenicDiseaseInfo
|
||||||
MonogenicDiseasesMap map[string]PersonMonogenicDiseaseInfo
|
MonogenicDiseasesMap map[string]PersonMonogenicDiseaseInfo
|
||||||
|
|
||||||
// Map Structure: Disease Name -> PersonPolygenicDiseaseInfo
|
// Map Structure: Disease Name -> PersonPolygenicDiseaseInfo
|
||||||
PolygenicDiseasesMap map[string]PersonPolygenicDiseaseInfo
|
PolygenicDiseasesMap map[string]PersonPolygenicDiseaseInfo
|
||||||
|
|
||||||
// These are traits which have discrete outcomes, rather than numeric outcomes
|
|
||||||
// For example: Eye color
|
|
||||||
// Map Structure: Trait Name -> Trait Info Object
|
// Map Structure: Trait Name -> Trait Info Object
|
||||||
DiscreteTraitsMap map[string]PersonDiscreteTraitInfo
|
TraitsMap map[string]PersonTraitInfo
|
||||||
|
|
||||||
// These are traits which have numeric outcomes, rather than discrete outcomes
|
|
||||||
// For example: Height
|
|
||||||
// Map Structure: Trait Name -> Trait Info Object
|
|
||||||
NumericTraitsMap map[string]PersonNumericTraitInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,15 +50,15 @@ type PersonGenomeMonogenicDiseaseInfo struct{
|
||||||
PersonHasDisease bool
|
PersonHasDisease bool
|
||||||
|
|
||||||
// This describes the number of variants that were tested for this disease
|
// This describes the number of variants that were tested for this disease
|
||||||
QuantityOfVariantsTested int
|
NumberOfVariantsTested int
|
||||||
|
|
||||||
// This describes the number of loci that were tested for this disease
|
// This describes the number of loci that were tested for this disease
|
||||||
// 1 locus can have multiple potential variants
|
// 1 locus can have multiple potential variants
|
||||||
QuantityOfLociTested int
|
NumberOfLociTested int
|
||||||
|
|
||||||
// This describes the number of loci which are phased
|
// This describes the number of loci which are phased
|
||||||
// This number will always be <= QuantityOfLociTested
|
// This number will always be <= NumberOfLociTested
|
||||||
QuantityOfPhasedLoci int
|
NumberOfPhasedLoci int
|
||||||
|
|
||||||
// This describes the probability that the person will pass a disease variant
|
// This describes the probability that the person will pass a disease variant
|
||||||
// It is a value that represents a percentage between 0-100
|
// It is a value that represents a percentage between 0-100
|
||||||
|
@ -107,9 +94,14 @@ type PersonPolygenicDiseaseInfo struct{
|
||||||
|
|
||||||
type PersonGenomePolygenicDiseaseInfo struct{
|
type PersonGenomePolygenicDiseaseInfo struct{
|
||||||
|
|
||||||
// This describes the quantity of loci tested for this disease
|
// This describes the number of loci tested for this disease
|
||||||
// This should be len(LociInfoMap)
|
// This should be len(LociInfoList)
|
||||||
QuantityOfLociTested 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
|
||||||
|
@ -136,102 +128,34 @@ type PersonGenomePolygenicDiseaseLocusInfo struct{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type PersonDiscreteTraitInfo struct{
|
type PersonTraitInfo struct{
|
||||||
|
|
||||||
// This map contains the person's trait info for each genome
|
// This map contains the person's trait info for each genome
|
||||||
// If no map entries exist, then no trait info is known
|
// If no map entries exist, then no trait info is known
|
||||||
// Map Structure: Genome Identifier -> PersonGenomeDiscreteTraitInfo
|
// Map Structure: Genome Identifier -> PersonGenomeTraitInfo
|
||||||
TraitInfoMap map[[16]byte]PersonGenomeDiscreteTraitInfo
|
TraitInfoMap map[[16]byte]PersonGenomeTraitInfo
|
||||||
|
|
||||||
// This is true if there are multiple genomes and the results from each genome differ
|
// This is true if there are multiple genomes and the results from each genome differ
|
||||||
ConflictExists bool
|
ConflictExists bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// For a trait analysis, both analysis methods may exist in the results
|
type PersonGenomeTraitInfo struct{
|
||||||
// However, the GUI will only display the results from one of the methods.
|
|
||||||
// The neural network prediction is always prioritized over the rule-based prediction
|
|
||||||
type PersonGenomeDiscreteTraitInfo struct{
|
|
||||||
|
|
||||||
// This is true if it is possible to analyze this trait using a neural network
|
// This should be len(GenomePassesRulesMap)
|
||||||
NeuralNetworkExists bool
|
NumberOfRulesTested int
|
||||||
|
|
||||||
// This is true if a neural network analysis was performed for this genome
|
// This map contains the locus values for the genome for this trait
|
||||||
// This means that at least 1 locus for this trait was contained in the genome
|
// If an locus's entry doesn't exist, its value is unknown
|
||||||
NeuralNetworkAnalysisExists bool
|
// Map Structure: Locus rsID -> Locus Value
|
||||||
|
LocusValuesMap map[int64]locusValue.LocusValue
|
||||||
|
|
||||||
NeuralNetworkAnalysis PersonGenomeDiscreteTraitInfo_NeuralNetwork
|
// This map contains the outcome scores for the genome
|
||||||
|
// Map Structure: Outcome Name -> Score
|
||||||
// This is true if it is possible to analyze this trait using rules
|
// Example: "Intolerant" -> 5
|
||||||
AnyRulesExist bool
|
OutcomeScoresMap map[string]int
|
||||||
|
|
||||||
// This is true if a rules-based analysis was performed for this genome
|
|
||||||
// This means that all of the loci for at least 1 rule for this trait was contained in the genome
|
|
||||||
RulesAnalysisExists bool
|
|
||||||
|
|
||||||
RulesAnalysis PersonGenomeDiscreteTraitInfo_Rules
|
|
||||||
}
|
|
||||||
|
|
||||||
type PersonGenomeDiscreteTraitInfo_NeuralNetwork struct{
|
|
||||||
|
|
||||||
// The predicted outcome (Example: "Blue")
|
|
||||||
PredictedOutcome string
|
|
||||||
|
|
||||||
// Probability (0-100) that the outcome from the neural network is true
|
|
||||||
PredictionConfidence int
|
|
||||||
|
|
||||||
QuantityOfLociKnown int
|
|
||||||
|
|
||||||
QuantityOfPhasedLoci int
|
|
||||||
}
|
|
||||||
|
|
||||||
type PersonGenomeDiscreteTraitInfo_Rules struct{
|
|
||||||
|
|
||||||
// Map Structure: Rule Identifier -> Genome Passes rule (true if the genome passes the rule)
|
// Map Structure: Rule Identifier -> Genome Passes rule (true if the genome passes the rule)
|
||||||
GenomePassesRulesMap map[[3]byte]bool
|
GenomePassesRulesMap map[[3]byte]bool
|
||||||
|
|
||||||
// This is true if there was not a tie between summed rule outcome scores
|
|
||||||
// It is possible to have some tested rules without a known outcome
|
|
||||||
PredictedOutcomeExists bool
|
|
||||||
|
|
||||||
// This is the outcome that was predicted
|
|
||||||
// Example: "Intolerant"
|
|
||||||
PredictedOutcome string
|
|
||||||
|
|
||||||
// This should be len(GenomePassesRulesMap)
|
|
||||||
QuantityOfRulesTested int
|
|
||||||
|
|
||||||
// This only counts the loci which are used for rules
|
|
||||||
// For example, loci that are only used in neural-network-based prediction are not counted
|
|
||||||
QuantityOfLociKnown int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type PersonNumericTraitInfo struct{
|
|
||||||
|
|
||||||
// This map contains the person's trait info for each genome
|
|
||||||
// If no map entries exist, then no trait info is known
|
|
||||||
// Map Structure: Genome Identifier -> PersonGenomeNumericTraitInfo
|
|
||||||
TraitInfoMap map[[16]byte]PersonGenomeNumericTraitInfo
|
|
||||||
|
|
||||||
// This is true if there are multiple genomes and the results from each genome differ
|
|
||||||
ConflictExists bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type PersonGenomeNumericTraitInfo struct{
|
|
||||||
|
|
||||||
// The predicted outcome (Example: The predicted height for this person, in centimeters)
|
|
||||||
PredictedOutcome float64
|
|
||||||
|
|
||||||
// This map stores the confidence ranges for the predicted value
|
|
||||||
// If we want to know how accurate the prediction is with a X% accuracy, how far would we have to expand the
|
|
||||||
// predicted value's range to be accurate, X% of the time?
|
|
||||||
// For example: 50% accuracy requires a +/-5 point range, 80% accuracy requires a +-15 point range
|
|
||||||
// Map Structure: Accuracy probability (0-100) -> Amount to add to value in both +/- directions so prediction is that accurate
|
|
||||||
ConfidenceRangesMap map[int]float64
|
|
||||||
|
|
||||||
QuantityOfLociKnown int
|
|
||||||
|
|
||||||
QuantityOfPhasedLoci int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -266,21 +190,16 @@ type CoupleAnalysis struct{
|
||||||
// Map Structure: Disease Name -> OffspringPolygenicDiseaseInfo
|
// Map Structure: Disease Name -> OffspringPolygenicDiseaseInfo
|
||||||
PolygenicDiseasesMap map[string]OffspringPolygenicDiseaseInfo
|
PolygenicDiseasesMap map[string]OffspringPolygenicDiseaseInfo
|
||||||
|
|
||||||
// Discrete traits are traits with discrete outcomes, such as Eye Color
|
|
||||||
// Map Structure: Trait Name -> Trait Info Object
|
// Map Structure: Trait Name -> Trait Info Object
|
||||||
DiscreteTraitsMap map[string]OffspringDiscreteTraitInfo
|
TraitsMap map[string]OffspringTraitInfo
|
||||||
|
|
||||||
// Numeric traits are traits with numeric outcomes, such as Height
|
|
||||||
// Map Structure: Trait Name -> Trait Info Object
|
|
||||||
NumericTraitsMap map[string]OffspringNumericTraitInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type OffspringMonogenicDiseaseInfo struct{
|
type OffspringMonogenicDiseaseInfo struct{
|
||||||
|
|
||||||
// This map stores the quantity of variants tested in each person's genome
|
// This map stores the number of variants tested in each person's genome
|
||||||
// Map Structure: Genome Identifier -> Number of variants tested
|
// Map Structure: Genome Identifier -> Number of variants tested
|
||||||
QuantityOfVariantsTestedMap map[[16]byte]int
|
NumberOfVariantsTestedMap map[[16]byte]int
|
||||||
|
|
||||||
// This map stores the offspring disease probabilities for each genome pair.
|
// This map stores the offspring disease probabilities for each genome pair.
|
||||||
// A genome pair is a concatenation of two genome identifiers
|
// A genome pair is a concatenation of two genome identifiers
|
||||||
|
@ -296,6 +215,7 @@ type OffspringMonogenicDiseaseInfo struct{
|
||||||
type OffspringGenomePairMonogenicDiseaseInfo struct{
|
type OffspringGenomePairMonogenicDiseaseInfo struct{
|
||||||
|
|
||||||
// At least 1 variant's information is needed from either person to include the diseaseInfo object in the MonogenicDiseaseInfoMap
|
// At least 1 variant's information is needed from either person to include the diseaseInfo object in the MonogenicDiseaseInfoMap
|
||||||
|
|
||||||
ProbabilityOffspringHasDiseaseIsKnown bool
|
ProbabilityOffspringHasDiseaseIsKnown bool
|
||||||
|
|
||||||
// This is the probability that the offspring will have the disease
|
// This is the probability that the offspring will have the disease
|
||||||
|
@ -339,8 +259,8 @@ type OffspringPolygenicDiseaseInfo struct{
|
||||||
|
|
||||||
type OffspringGenomePairPolygenicDiseaseInfo struct{
|
type OffspringGenomePairPolygenicDiseaseInfo struct{
|
||||||
|
|
||||||
// This should be len(LociInfoMap)
|
// This should be len(DiseaseLociList)
|
||||||
QuantityOfLociTested int
|
NumberOfLociTested int
|
||||||
|
|
||||||
// A number between 1-10 representing the offspring's average risk score
|
// A number between 1-10 representing the offspring's average risk score
|
||||||
// 1 == lowest risk, 10 == highest risk
|
// 1 == lowest risk, 10 == highest risk
|
||||||
|
@ -377,110 +297,27 @@ type OffspringPolygenicDiseaseLocusInfo struct{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type OffspringDiscreteTraitInfo struct{
|
type OffspringTraitInfo struct{
|
||||||
|
|
||||||
// This map stores the trait info for each genome pair
|
// This map stores the trait info for each genome pair
|
||||||
// Map Structure: Genome Pair Identifier -> OffspringGenomePairTraitInfo
|
// Map Structure: Genome Pair Identifier -> OffspringGenomePairTraitInfo
|
||||||
TraitInfoMap map[[32]byte]OffspringGenomePairDiscreteTraitInfo
|
TraitInfoMap map[[32]byte]OffspringGenomePairTraitInfo
|
||||||
|
|
||||||
ConflictExists bool
|
ConflictExists bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// For a trait analysis, both analysis methods may exist in the results
|
type OffspringGenomePairTraitInfo struct{
|
||||||
// However, the GUI will only display the results from one of the methods.
|
|
||||||
// The neural network prediction is always prioritized over the rule-based prediction
|
|
||||||
type OffspringGenomePairDiscreteTraitInfo struct{
|
|
||||||
|
|
||||||
// This is true if it is possible to analyze this trait using a neural network
|
// This should be len(TraitRulesList)
|
||||||
NeuralNetworkExists bool
|
NumberOfRulesTested int
|
||||||
|
|
||||||
// This is true if a neural network analysis was performed for this genome
|
// Map Structure: Outcome Name -> Outcome Score
|
||||||
// This means that at least 1 locus for this trait was contained in both of the genomes in the pair
|
// Example: "Intolerant" -> 2.5
|
||||||
NeuralNetworkAnalysisExists bool
|
OffspringAverageOutcomeScoresMap map[string]float64
|
||||||
|
|
||||||
NeuralNetworkAnalysis OffspringGenomePairDiscreteTraitInfo_NeuralNetwork
|
|
||||||
|
|
||||||
// This is true if it is possible to analyze this trait using rules
|
|
||||||
RulesExist bool
|
|
||||||
|
|
||||||
// This is true if a rules-based analysis was performed for this genome
|
|
||||||
// This means that all of the loci for at least 1 rule for this trait was contained in both of the genomes in the pair
|
|
||||||
// Also, none of the offspring have an unknown outcome caused by an outcome score tie
|
|
||||||
RulesAnalysisExists bool
|
|
||||||
|
|
||||||
RulesAnalysis OffspringGenomePairDiscreteTraitInfo_Rules
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type OffspringGenomePairDiscreteTraitInfo_NeuralNetwork struct{
|
|
||||||
|
|
||||||
// Map Structure: Outcome Name -> Outcome Probability (0-100)
|
|
||||||
// Example: "Intolerant" -> 5
|
|
||||||
OffspringOutcomeProbabilitiesMap map[string]int
|
|
||||||
|
|
||||||
// Probability (0-100) that each outcome from the neural network is true
|
|
||||||
// This is an average of the confidence for each of the calculated 100 outcome probabilities
|
|
||||||
AverageConfidence int
|
|
||||||
|
|
||||||
QuantityOfLociKnown int
|
|
||||||
|
|
||||||
// This describes the quantity of loci from both parents that are phased
|
|
||||||
// For example, if there are 10 loci for this trait, and one parent has 10 phased loci and the other has 5,
|
|
||||||
// this variable will have a value of 15
|
|
||||||
QuantityOfParentalPhasedLoci int
|
|
||||||
}
|
|
||||||
|
|
||||||
type OffspringGenomePairDiscreteTraitInfo_Rules struct{
|
|
||||||
|
|
||||||
// Map Structure: Outcome Name -> Outcome Probability (0-100)
|
|
||||||
// Example: "Intolerant" -> 5
|
|
||||||
OffspringOutcomeProbabilitiesMap map[string]int
|
|
||||||
|
|
||||||
// Map Structure: Rule Identifier -> Offspring Probability Of Passing Rule
|
// Map Structure: Rule Identifier -> Offspring Probability Of Passing Rule
|
||||||
// The value stores the probability that the offspring will pass the rule
|
// The value stores the probability that the offspring will pass the rule
|
||||||
// This is a number between 0-100%
|
// This is a number between 0-100%
|
||||||
ProbabilityOfPassingRulesMap map[[3]byte]int
|
ProbabilityOfPassingRulesMap map[[3]byte]int
|
||||||
|
|
||||||
// This should be len(ProbabilityOfPassingRulesMap)
|
|
||||||
QuantityOfRulesTested int
|
|
||||||
|
|
||||||
// This only counts the loci which are used for rules
|
|
||||||
// For example, loci that are only used in neural-network-based prediction are not counted
|
|
||||||
QuantityOfLociKnown int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type OffspringNumericTraitInfo struct{
|
|
||||||
|
|
||||||
// This map stores the trait info for each genome pair
|
|
||||||
// Map Structure: Genome Pair Identifier -> OffspringGenomePairNumericTraitInfo
|
|
||||||
TraitInfoMap map[[32]byte]OffspringGenomePairNumericTraitInfo
|
|
||||||
|
|
||||||
ConflictExists bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type OffspringGenomePairNumericTraitInfo struct{
|
|
||||||
|
|
||||||
// The average outcome for the offspring
|
|
||||||
// For example, the average height for an offspring between these 2 people
|
|
||||||
OffspringAverageOutcome float64
|
|
||||||
|
|
||||||
// This map stores the confidence ranges for the predicted value
|
|
||||||
// If we want to know how accurate the prediction is with a X% accuracy, how far would we have to expand the
|
|
||||||
// predicted value's range to be accurate, X% of the time?
|
|
||||||
// For example: 50% accuracy requires a +/-5 point range, 80% accuracy requires a +-15 point range
|
|
||||||
// Map Structure: Accuracy probability (0-100) -> Amount to add to value in both +/- directions so prediction is that accurate
|
|
||||||
AverageConfidenceRangesMap map[int]float64
|
|
||||||
|
|
||||||
// This describes the quantity of loci from both parents that are phased
|
|
||||||
// For example, if there are 10 loci for this trait, and one parent has 10 phased loci and the other has 5,
|
|
||||||
// this variable will have a value of 15
|
|
||||||
QuantityOfParentalPhasedLoci int
|
|
||||||
|
|
||||||
QuantityOfLociKnown int
|
|
||||||
|
|
||||||
// A list of 100 offspring outcomes for 100 prospective offspring from the genome pair
|
|
||||||
// Example: A list of heights for 100 prospective offspring
|
|
||||||
SampleOffspringOutcomesList []float64
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ package geneticPrediction
|
||||||
// We could create slower models that provide more accurate predictions
|
// We could create slower models that provide more accurate predictions
|
||||||
|
|
||||||
import "seekia/resources/geneticReferences/traits"
|
import "seekia/resources/geneticReferences/traits"
|
||||||
import "seekia/resources/geneticPredictionModels"
|
|
||||||
|
|
||||||
import "seekia/internal/genetics/locusValue"
|
import "seekia/internal/genetics/locusValue"
|
||||||
import "seekia/internal/genetics/readBiobankData"
|
import "seekia/internal/genetics/readBiobankData"
|
||||||
|
@ -212,252 +211,6 @@ func DecodeBytesToNeuralNetworkObject(inputNeuralNetwork []byte)(NeuralNetwork,
|
||||||
return newNeuralNetworkObject, nil
|
return newNeuralNetworkObject, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// This map is used to store information about how accurate genetic prediction models are
|
|
||||||
// Map Structure: Trait Outcome Info -> Trait Prediction Accuracy Info
|
|
||||||
type TraitPredictionAccuracyInfoMap map[TraitOutcomeInfo]TraitPredictionAccuracyInfo
|
|
||||||
|
|
||||||
type TraitOutcomeInfo struct{
|
|
||||||
|
|
||||||
// This is the outcome which was found
|
|
||||||
// Example: "Blue"
|
|
||||||
OutcomeName string
|
|
||||||
|
|
||||||
// This is a value between 0-100 which describes the percentage of the loci which were tested for the input for the prediction
|
|
||||||
PercentageOfLociTested int
|
|
||||||
|
|
||||||
// This is a value between 0-100 which describes the percentage of the tested loci which were phased for the input for the prediction
|
|
||||||
PercentageOfPhasedLoci int
|
|
||||||
}
|
|
||||||
|
|
||||||
type TraitPredictionAccuracyInfo struct{
|
|
||||||
|
|
||||||
// This contains the quantity of examples for the outcome with the specified percentageOfLociTested and percentageOfPhasedLoci
|
|
||||||
QuantityOfExamples int
|
|
||||||
|
|
||||||
// This contains the quantity of predictions for the outcome with the specified percentageOfLociTested and percentageOfPhasedLoci
|
|
||||||
// Prediction = our model predicted this outcome
|
|
||||||
QuantityOfPredictions int
|
|
||||||
|
|
||||||
// This stores the probability (0-100) that our model will accurately predict this outcome for a genome which has
|
|
||||||
// the specified percentageOfLociTested and percentageOfPhasedLoci
|
|
||||||
// In other words: What is the probability that if you give Seekia a blue-eyed genome, it will give you a correct Blue prediction?
|
|
||||||
// This value is only accurate is QuantityOfExamples > 0
|
|
||||||
ProbabilityOfCorrectGenomePrediction int
|
|
||||||
|
|
||||||
// This stores the probability (0-100) that our model is correct if our model predicts that a genome
|
|
||||||
// with the specified percentageOfLociTested and percentageOfPhasedLoci has this outcome
|
|
||||||
// In other words: What is the probability that if Seekia says a genome will have blue eyes, it is correct?
|
|
||||||
// This value is only accurate is QuantityOfPredictions > 0
|
|
||||||
ProbabilityOfCorrectOutcomePrediction int
|
|
||||||
}
|
|
||||||
|
|
||||||
func EncodeTraitPredictionAccuracyInfoMapToBytes(inputMap TraitPredictionAccuracyInfoMap)([]byte, error){
|
|
||||||
|
|
||||||
buffer := new(bytes.Buffer)
|
|
||||||
|
|
||||||
encoder := gob.NewEncoder(buffer)
|
|
||||||
|
|
||||||
err := encoder.Encode(inputMap)
|
|
||||||
if (err != nil) { return nil, err }
|
|
||||||
|
|
||||||
inputMapBytes := buffer.Bytes()
|
|
||||||
|
|
||||||
return inputMapBytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeBytesToTraitPredictionAccuracyInfoMap(inputBytes []byte)(TraitPredictionAccuracyInfoMap, error){
|
|
||||||
|
|
||||||
if (inputBytes == nil){
|
|
||||||
return nil, errors.New("DecodeBytesToTraitPredictionAccuracyInfoMap called with nil inputBytes.")
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer := bytes.NewBuffer(inputBytes)
|
|
||||||
|
|
||||||
decoder := gob.NewDecoder(buffer)
|
|
||||||
|
|
||||||
var newTraitPredictionAccuracyInfoMap TraitPredictionAccuracyInfoMap
|
|
||||||
|
|
||||||
err := decoder.Decode(&newTraitPredictionAccuracyInfoMap)
|
|
||||||
if (err != nil){ return nil, err }
|
|
||||||
|
|
||||||
return newTraitPredictionAccuracyInfoMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//Outputs:
|
|
||||||
// -bool: Neural network model exists for this trait (trait prediction is possible for this trait)
|
|
||||||
// -bool: Trait prediction is possible for this user (User has at least 1 known trait locus value)
|
|
||||||
// -string: Predicted trait outcome (Example: "Blue")
|
|
||||||
// -int: Confidence: Probability (0-100) that the prediction is accurate
|
|
||||||
// -int: Quantity of loci known
|
|
||||||
// -int: Quantity of phased loci
|
|
||||||
// -error
|
|
||||||
func GetNeuralNetworkTraitPredictionFromGenomeMap(traitName string, genomeMap map[int64]locusValue.LocusValue)(bool, bool, string, int, int, int, error){
|
|
||||||
|
|
||||||
traitObject, err := traits.GetTraitObject(traitName)
|
|
||||||
if (err != nil) { return false, false, "", 0, 0, 0, err }
|
|
||||||
|
|
||||||
// This is a map of rsIDs which influence this trait
|
|
||||||
traitRSIDsList := traitObject.LociList
|
|
||||||
|
|
||||||
if (len(traitRSIDsList) == 0){
|
|
||||||
// Neural network trait prediction is not possible for this trait
|
|
||||||
return false, false, "", 0, 0, 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
predictionModelExists, predictionModelBytes := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)
|
|
||||||
if (predictionModelExists == false){
|
|
||||||
// Neural network trait prediction is not possible for this trait
|
|
||||||
return false, false, "", 0, 0, 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
traitRSIDsListCopy := slices.Clone(traitRSIDsList)
|
|
||||||
slices.Sort(traitRSIDsListCopy)
|
|
||||||
|
|
||||||
// In the inputLayer, each locus value is represented by 3 neurons:
|
|
||||||
// 1. LocusExists/LocusIsPhased
|
|
||||||
// -0 = Locus value is unknown
|
|
||||||
// -0.5 = Locus Is known, phase is unknown
|
|
||||||
// -1 = Locus Is Known, phase is known
|
|
||||||
// 2. Allele1 Locus Value (Value between 0-1)
|
|
||||||
// -0 = Value is unknown
|
|
||||||
// 3. Allele2 Locus Value (Value between 0-1)
|
|
||||||
// -0 = Value is unknown
|
|
||||||
//
|
|
||||||
neuralNetworkInput := make([]float32, 0)
|
|
||||||
|
|
||||||
quantityOfLociKnown := 0
|
|
||||||
quantityOfPhasedLoci := 0
|
|
||||||
|
|
||||||
for _, rsID := range traitRSIDsListCopy{
|
|
||||||
|
|
||||||
userLocusValue, exists := genomeMap[rsID]
|
|
||||||
if (exists == false){
|
|
||||||
neuralNetworkInput = append(neuralNetworkInput, 0, 0, 0)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
quantityOfLociKnown += 1
|
|
||||||
|
|
||||||
locusAllele1 := userLocusValue.Base1Value
|
|
||||||
locusAllele2 := userLocusValue.Base2Value
|
|
||||||
locusIsPhased := userLocusValue.LocusIsPhased
|
|
||||||
|
|
||||||
getNeuron1 := func()float32{
|
|
||||||
if (locusIsPhased == false){
|
|
||||||
return 0.5
|
|
||||||
}
|
|
||||||
|
|
||||||
quantityOfPhasedLoci += 1
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
neuron1 := getNeuron1()
|
|
||||||
|
|
||||||
neuron2, err := convertAlleleToNeuron(locusAllele1)
|
|
||||||
if (err != nil) { return false, false, "", 0, 0, 0, err }
|
|
||||||
|
|
||||||
neuron3, err := convertAlleleToNeuron(locusAllele2)
|
|
||||||
if (err != nil) { return false, false, "", 0, 0, 0, err }
|
|
||||||
|
|
||||||
neuralNetworkInput = append(neuralNetworkInput, neuron1, neuron2, neuron3)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quantityOfLociKnown == 0){
|
|
||||||
// We can't predict anything about this trait for this genome
|
|
||||||
return true, false, "", 0, 0, 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
neuralNetworkObject, err := DecodeBytesToNeuralNetworkObject(predictionModelBytes)
|
|
||||||
if (err != nil) { return false, false, "", 0, 0, 0, err }
|
|
||||||
|
|
||||||
outputLayer, err := GetNeuralNetworkRawPrediction(&neuralNetworkObject, neuralNetworkInput)
|
|
||||||
if (err != nil) { return false, false, "", 0, 0, 0, err }
|
|
||||||
|
|
||||||
predictedOutcomeName, err := GetOutcomeNameFromOutputLayer(traitName, false, outputLayer)
|
|
||||||
if (err != nil) { return false, false, "", 0, 0, 0, err }
|
|
||||||
|
|
||||||
modelTraitAccuracyInfoFile, err := geneticPredictionModels.GetPredictionModelTraitAccuracyInfoBytes(traitName)
|
|
||||||
if (err != nil) { return false, false, "", 0, 0, 0, err }
|
|
||||||
|
|
||||||
modelTraitAccuracyInfoMap, err := DecodeBytesToTraitPredictionAccuracyInfoMap(modelTraitAccuracyInfoFile)
|
|
||||||
if (err != nil) { return false, false, "", 0, 0, 0, err }
|
|
||||||
|
|
||||||
// We find the model trait accuracy info object that is the most similar to our predicted outcome
|
|
||||||
|
|
||||||
getPredictionAccuracy := func()int{
|
|
||||||
|
|
||||||
totalNumberOfTraitLoci := len(traitRSIDsList)
|
|
||||||
|
|
||||||
proportionOfLociTested := float64(quantityOfLociKnown)/float64(totalNumberOfTraitLoci)
|
|
||||||
percentageOfLociTested := int(proportionOfLociTested * 100)
|
|
||||||
|
|
||||||
proportionOfPhasedLoci := float64(quantityOfPhasedLoci)/float64(totalNumberOfTraitLoci)
|
|
||||||
percentageOfPhasedLoci := int(proportionOfPhasedLoci * 100)
|
|
||||||
|
|
||||||
// This is a value between 0 and 100 that represents the most likely accuracy probability for this prediction
|
|
||||||
closestPredictionAccuracy := 0
|
|
||||||
|
|
||||||
// This is a value that represents the distance our closest prediction accuracy has from the current prediction
|
|
||||||
// Consider each prediction accuracy value on an (X,Y) coordinate plane
|
|
||||||
// X = Number of loci tested
|
|
||||||
// Y = Number of phased loci
|
|
||||||
closestPredictionAccuracyDistance := float64(0)
|
|
||||||
|
|
||||||
anyOutcomeAccuracyFound := false
|
|
||||||
|
|
||||||
for traitOutcomeInfo, traitPredictionAccuracyInfo := range modelTraitAccuracyInfoMap{
|
|
||||||
|
|
||||||
outcomeName := traitOutcomeInfo.OutcomeName
|
|
||||||
if (outcomeName != predictedOutcomeName){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
probabilityOfCorrectOutcomePrediction := traitPredictionAccuracyInfo.ProbabilityOfCorrectOutcomePrediction
|
|
||||||
|
|
||||||
currentPercentageOfLociTested := traitOutcomeInfo.PercentageOfLociTested
|
|
||||||
currentPercentageOfPhasedLoci := traitOutcomeInfo.PercentageOfPhasedLoci
|
|
||||||
|
|
||||||
// Distance Formula for 2 coordinates (x1, y1) and (x2, y2):
|
|
||||||
// distance = √((x2 - x1)^2 + (y2 - y1)^2)
|
|
||||||
|
|
||||||
differenceInX := float64(currentPercentageOfLociTested - percentageOfLociTested)
|
|
||||||
differenceInY := float64(currentPercentageOfPhasedLoci - percentageOfPhasedLoci)
|
|
||||||
|
|
||||||
distance := math.Sqrt(math.Pow(differenceInX, 2) + math.Pow(differenceInY, 2))
|
|
||||||
|
|
||||||
if (distance == 0){
|
|
||||||
// We found the exact prediction accuracy
|
|
||||||
return probabilityOfCorrectOutcomePrediction
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anyOutcomeAccuracyFound == false){
|
|
||||||
closestPredictionAccuracyDistance = distance
|
|
||||||
closestPredictionAccuracy = probabilityOfCorrectOutcomePrediction
|
|
||||||
anyOutcomeAccuracyFound = true
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
if (distance < closestPredictionAccuracyDistance){
|
|
||||||
closestPredictionAccuracyDistance = distance
|
|
||||||
closestPredictionAccuracy = probabilityOfCorrectOutcomePrediction
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anyOutcomeAccuracyFound == false){
|
|
||||||
// This means that our model has never actually predicted this outcome
|
|
||||||
// This shouldn't happen unless our model is really bad, or our training set has very few people with this outcome.
|
|
||||||
// We return a 0% accuracy rating
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return closestPredictionAccuracy
|
|
||||||
}
|
|
||||||
|
|
||||||
predictionAccuracy := getPredictionAccuracy()
|
|
||||||
|
|
||||||
return true, true, predictedOutcomeName, predictionAccuracy, quantityOfLociKnown, quantityOfPhasedLoci, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -int: Number of loci values that are known
|
// -int: Number of loci values that are known
|
||||||
// -int: Number of loci values that are known and phased
|
// -int: Number of loci values that are known and phased
|
||||||
|
@ -684,9 +437,9 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
|
||||||
if (err != nil) { return false, nil, err }
|
if (err != nil) { return false, nil, err }
|
||||||
|
|
||||||
// This is a list of rsIDs which influence this trait
|
// This is a list of rsIDs which influence this trait
|
||||||
traitRSIDsList := traitObject.LociList
|
traitRSIDs := traitObject.LociList
|
||||||
|
|
||||||
if (len(traitRSIDsList) == 0){
|
if (len(traitRSIDs) == 0){
|
||||||
return false, nil, errors.New("traitObject contains no rsIDs.")
|
return false, nil, errors.New("traitObject contains no rsIDs.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,7 +457,7 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
|
||||||
// -0 = Locus value is unknown
|
// -0 = Locus value is unknown
|
||||||
// -0.5 = Locus Is known, phase is unknown
|
// -0.5 = Locus Is known, phase is unknown
|
||||||
// -1 = Locus Is Known, phase is known
|
// -1 = Locus Is Known, phase is known
|
||||||
expectedNumberOfInputLayerRows := len(traitRSIDsList) * 3
|
expectedNumberOfInputLayerRows := len(traitRSIDs) * 3
|
||||||
|
|
||||||
if (numberOfInputLayerRows != expectedNumberOfInputLayerRows){
|
if (numberOfInputLayerRows != expectedNumberOfInputLayerRows){
|
||||||
|
|
||||||
|
@ -715,7 +468,7 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
|
||||||
|
|
||||||
checkIfAnyTraitLocusValuesExist := func()bool{
|
checkIfAnyTraitLocusValuesExist := func()bool{
|
||||||
|
|
||||||
for _, rsID := range traitRSIDsList{
|
for _, rsID := range traitRSIDs{
|
||||||
|
|
||||||
_, exists := userLocusValuesMap[rsID]
|
_, exists := userLocusValuesMap[rsID]
|
||||||
if (exists == true){
|
if (exists == true){
|
||||||
|
@ -734,9 +487,11 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
|
||||||
}
|
}
|
||||||
|
|
||||||
// We sort rsIDs in ascending order
|
// We sort rsIDs in ascending order
|
||||||
|
// We copy list so we don't change the original
|
||||||
|
|
||||||
traitRSIDsListCopy := slices.Clone(traitRSIDsList)
|
traitRSIDsList := slices.Clone(traitRSIDs)
|
||||||
slices.Sort(traitRSIDsListCopy)
|
|
||||||
|
slices.Sort(traitRSIDsList)
|
||||||
|
|
||||||
// This function returns the outputLayer for all trainingDatas for this user
|
// This function returns the outputLayer for all trainingDatas for this user
|
||||||
// Each outputLayer represents the user's trait value (Example: "Blue" for Eye Color)
|
// Each outputLayer represents the user's trait value (Example: "Blue" for Eye Color)
|
||||||
|
@ -882,11 +637,11 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
|
||||||
|
|
||||||
anyLocusExists := false
|
anyLocusExists := false
|
||||||
|
|
||||||
inputLayerLength := len(traitRSIDsListCopy) * 3
|
inputLayerLength := len(traitRSIDsList) * 3
|
||||||
|
|
||||||
inputLayer := make([]float32, 0, inputLayerLength)
|
inputLayer := make([]float32, 0, inputLayerLength)
|
||||||
|
|
||||||
for _, rsID := range traitRSIDsListCopy{
|
for _, rsID := range traitRSIDsList{
|
||||||
|
|
||||||
randomFloat := pseudorandomNumberGenerator.Float64()
|
randomFloat := pseudorandomNumberGenerator.Float64()
|
||||||
if (randomFloat > probabilityOfUsingLoci){
|
if (randomFloat > probabilityOfUsingLoci){
|
||||||
|
@ -1241,7 +996,7 @@ func (inputNetwork *NeuralNetwork)buildNeuralNetwork(inputLayer *gorgonia.Node)e
|
||||||
|
|
||||||
inputLayerCopy := inputLayer
|
inputLayerCopy := inputLayer
|
||||||
|
|
||||||
// We multiply weights at each layer and perform ReLU (Rectification) after each multiplication
|
// We multiply weights at each layer and perform sigmoid after each multiplication
|
||||||
|
|
||||||
weights1 := inputNetwork.weights1
|
weights1 := inputNetwork.weights1
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ var myCacheChosenGeneticAnalysisIdentifier string
|
||||||
|
|
||||||
// We use this variable to store the analysis in memory
|
// We use this variable to store the analysis in memory
|
||||||
// This prevents us from having to read and unmarshal the messagepack file each time we want to retrieve the analysis
|
// This prevents us from having to read and unmarshal the messagepack file each time we want to retrieve the analysis
|
||||||
|
// TODO: Read attributes from the analysis into maps for faster retrieval
|
||||||
var myCacheChosenGeneticAnalysis geneticAnalysis.PersonAnalysis
|
var myCacheChosenGeneticAnalysis geneticAnalysis.PersonAnalysis
|
||||||
|
|
||||||
// These variables store metadata about the cache genetic analysis
|
// These variables store metadata about the cache genetic analysis
|
||||||
|
@ -35,7 +36,6 @@ var myCacheChosenGeneticAnalysis_GenomeIdentifierToUse [16]byte
|
||||||
// This variable tells us if the current cache chosen genetic analysis contains multiple genomes
|
// This variable tells us if the current cache chosen genetic analysis contains multiple genomes
|
||||||
var myCacheChosenGeneticAnalysis_MultipleGenomesExist bool
|
var myCacheChosenGeneticAnalysis_MultipleGenomesExist bool
|
||||||
|
|
||||||
|
|
||||||
// This function is used to retrieve the user's chosen person genetic analysis
|
// This function is used to retrieve the user's chosen person genetic analysis
|
||||||
// The user must choose a person to link to their mate profile/identity
|
// The user must choose a person to link to their mate profile/identity
|
||||||
// This genetic analysis is not shared on the person's profile publicly.
|
// This genetic analysis is not shared on the person's profile publicly.
|
||||||
|
@ -101,7 +101,7 @@ func GetMyChosenMateGeneticAnalysis()(bool, bool, bool, geneticAnalysis.PersonAn
|
||||||
return false, false, false, emptyPersonAnalysis, [16]byte{}, false, errors.New("CheckIfPersonAnalysisIsReady returning missing genetic analysis.")
|
return false, false, false, emptyPersonAnalysis, [16]byte{}, false, errors.New("CheckIfPersonAnalysisIsReady returning missing genetic analysis.")
|
||||||
}
|
}
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myGeneticAnalysisObject)
|
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myGeneticAnalysisObject)
|
||||||
if (err != nil) { return false, false, false, emptyPersonAnalysis, [16]byte{}, false, err }
|
if (err != nil) { return false, false, false, emptyPersonAnalysis, [16]byte{}, false, err }
|
||||||
|
|
||||||
getGenomeIdentifierToUse := func()([16]byte, error){
|
getGenomeIdentifierToUse := func()([16]byte, error){
|
||||||
|
|
|
@ -6,7 +6,6 @@ package myGenomes
|
||||||
|
|
||||||
import "seekia/internal/cryptography/blake3"
|
import "seekia/internal/cryptography/blake3"
|
||||||
import "seekia/internal/encoding"
|
import "seekia/internal/encoding"
|
||||||
import "seekia/internal/genetics/prepareRawGenomes"
|
|
||||||
import "seekia/internal/genetics/readRawGenomes"
|
import "seekia/internal/genetics/readRawGenomes"
|
||||||
import "seekia/internal/helpers"
|
import "seekia/internal/helpers"
|
||||||
import "seekia/internal/localFilesystem"
|
import "seekia/internal/localFilesystem"
|
||||||
|
@ -107,18 +106,11 @@ func AddRawGenome(personIdentifier string, rawGenomeString string)(bool, bool, e
|
||||||
|
|
||||||
rawGenomeReader := strings.NewReader(rawGenomeString)
|
rawGenomeReader := strings.NewReader(rawGenomeString)
|
||||||
|
|
||||||
companyName, importVersion, timeFileWasGenerated, snpCount, genomeIsPhased, rawGenomeMap, err := readRawGenomes.ReadRawGenomeFile(rawGenomeReader)
|
companyName, importVersion, timeFileWasGenerated, snpCount, genomeIsPhased, _, err := readRawGenomes.ReadRawGenomeFile(rawGenomeReader)
|
||||||
if (err != nil){
|
if (err != nil){
|
||||||
return false, false, nil
|
return false, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
genomeHasUsefulLocations, _, err := prepareRawGenomes.ConvertRawGenomeToGenomeMap(rawGenomeMap, genomeIsPhased)
|
|
||||||
if (err != nil) { return false, false, err }
|
|
||||||
if (genomeHasUsefulLocations == false){
|
|
||||||
//TODO: Explain this to the user rather than just telling the user that the file is invalid
|
|
||||||
return false, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
genomeIdentifier, err := helpers.GetNewRandomHexString(16)
|
genomeIdentifier, err := helpers.GetNewRandomHexString(16)
|
||||||
if (err != nil) { return false, false, err }
|
if (err != nil) { return false, false, err }
|
||||||
|
|
||||||
|
|
|
@ -76,10 +76,6 @@ func CreateRawGenomeWithMetadataObject(genomeIdentifier [16]byte, rawGenomeStrin
|
||||||
// -error
|
// -error
|
||||||
func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWithMetadata, updatePercentageCompleteFunction func(int)error)([]GenomeWithMetadata, [][16]byte, bool, [16]byte, [16]byte, error){
|
func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWithMetadata, updatePercentageCompleteFunction func(int)error)([]GenomeWithMetadata, [][16]byte, bool, [16]byte, [16]byte, error){
|
||||||
|
|
||||||
if (len(inputGenomesList) == 0){
|
|
||||||
return nil, nil, false, [16]byte{}, [16]byte{}, errors.New("GetGenomesWithMetadataListFromRawGenomesList called with empty inputGenomesList")
|
|
||||||
}
|
|
||||||
|
|
||||||
// The reading of genomes will take up the first 20% of the percentage range
|
// The reading of genomes will take up the first 20% of the percentage range
|
||||||
// The creation of multiple genomes will take up the last 80% of the percentage range
|
// The creation of multiple genomes will take up the last 80% of the percentage range
|
||||||
|
|
||||||
|
@ -106,13 +102,103 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
|
||||||
|
|
||||||
// Now we convert rawGenomeMap to a genomeMap
|
// Now we convert rawGenomeMap to a genomeMap
|
||||||
|
|
||||||
anyValuesExist, genomeMap, err := ConvertRawGenomeToGenomeMap(rawGenomeMap, genomeIsPhased)
|
// Map Structure: RSID -> Locus Value
|
||||||
if (err != nil) { return nil, nil, false, [16]byte{}, [16]byte{}, err }
|
genomeMap := make(map[int64]locusValue.LocusValue)
|
||||||
if (anyValuesExist == false){
|
|
||||||
// We have to make sure this never happens so the user isn't confused as to why genomes
|
// We use this list to check for alias collisions later
|
||||||
// that were imported were not included in the analysis
|
allRSIDsList := make([]int64, 0)
|
||||||
// We make sure this doesn't happen by verifying the genome at the time of importing
|
|
||||||
return nil, nil, false, [16]byte{}, [16]byte{}, errors.New("Genome supplied to GetGenomesWithMetadataListFromRawGenomesList has no valid locations.")
|
for rsID, locusBasePairValue := range rawGenomeMap{
|
||||||
|
|
||||||
|
locusAllele2Exists := locusBasePairValue.Allele2Exists
|
||||||
|
if (locusAllele2Exists == false){
|
||||||
|
// This SNP contains less than 2 bases
|
||||||
|
// We don't support reading these kinds of SNP values yet
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
locusAllele1 := locusBasePairValue.Allele1
|
||||||
|
locusAllele2 := locusBasePairValue.Allele2
|
||||||
|
|
||||||
|
getLocusIsPhasedBool := func()bool{
|
||||||
|
|
||||||
|
if (locusAllele1 == locusAllele2){
|
||||||
|
// Locus has to be phased, because phase flip does not change value
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return genomeIsPhased
|
||||||
|
}
|
||||||
|
|
||||||
|
locusIsPhased := getLocusIsPhasedBool()
|
||||||
|
|
||||||
|
locusValueObject := locusValue.LocusValue{
|
||||||
|
LocusIsPhased: locusIsPhased,
|
||||||
|
Base1Value: locusAllele1,
|
||||||
|
Base2Value: locusAllele2,
|
||||||
|
}
|
||||||
|
|
||||||
|
genomeMap[rsID] = locusValueObject
|
||||||
|
|
||||||
|
allRSIDsList = append(allRSIDsList, rsID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we check for rsID aliases
|
||||||
|
// rsID aliases are multiple rsids that refer to the same location
|
||||||
|
// If a single genome file contained two identical rsids whose value conflicted, the company must have made an error in reporting
|
||||||
|
|
||||||
|
for _, rsID := range allRSIDsList{
|
||||||
|
|
||||||
|
rsidLocusValue, exists := genomeMap[rsID]
|
||||||
|
if (exists == false){
|
||||||
|
// This must have been an alias that was deleted
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
aliasExists, rsidAliasesList, err := locusMetadata.GetRSIDAliases(rsID)
|
||||||
|
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err }
|
||||||
|
if (aliasExists == false){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
checkIfRSIDCollisionExists := func()bool{
|
||||||
|
|
||||||
|
for _, rsidAlias := range rsidAliasesList{
|
||||||
|
|
||||||
|
aliasLocusValue, exists := genomeMap[rsidAlias]
|
||||||
|
if (exists == false){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aliasLocusValue != rsidLocusValue){
|
||||||
|
// A collision exists with an alias rsID
|
||||||
|
// The company must be creating invalid results, or our alias list is invalid
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
rsidCollisionExists := checkIfRSIDCollisionExists()
|
||||||
|
if (rsidCollisionExists == true){
|
||||||
|
// We will delete this rsID
|
||||||
|
// We cannot trust any of the results
|
||||||
|
|
||||||
|
delete(genomeMap, rsID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We delete all aliases from the genome map
|
||||||
|
// We do this to save space
|
||||||
|
|
||||||
|
for _, rsidAlias := range rsidAliasesList{
|
||||||
|
delete(genomeMap, rsidAlias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len(genomeMap) == 0){
|
||||||
|
// No valid locations exist
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
genomeWithMetadataObject := GenomeWithMetadata{
|
genomeWithMetadataObject := GenomeWithMetadata{
|
||||||
|
@ -135,9 +221,9 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
|
||||||
err := updatePercentageCompleteFunction(20)
|
err := updatePercentageCompleteFunction(20)
|
||||||
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err }
|
if (err != nil){ return nil, nil, false, [16]byte{}, [16]byte{}, err }
|
||||||
|
|
||||||
if (len(genomesWithMetadataList) <= 1){
|
if (len(genomesWithMetadataList) == 1){
|
||||||
|
|
||||||
// <=1 genome exists.
|
// Only 1 genome exists.
|
||||||
// No genome combining is needed.
|
// No genome combining is needed.
|
||||||
|
|
||||||
err = updatePercentageCompleteFunction(100)
|
err = updatePercentageCompleteFunction(100)
|
||||||
|
@ -461,112 +547,4 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
|
||||||
return genomesWithMetadataList, allRawGenomeIdentifiersList, true, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, nil
|
return genomesWithMetadataList, allRawGenomeIdentifiersList, true, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Outputs:
|
|
||||||
// -bool: Genome has any useful locations
|
|
||||||
// -map[int64]locusValue.LocusValue
|
|
||||||
// -error
|
|
||||||
func ConvertRawGenomeToGenomeMap(rawGenomeMap map[int64]readRawGenomes.RawGenomeLocusValue, genomeIsPhased bool)(bool, map[int64]locusValue.LocusValue, error){
|
|
||||||
|
|
||||||
// Map Structure: RSID -> Locus Value
|
|
||||||
genomeMap := make(map[int64]locusValue.LocusValue)
|
|
||||||
|
|
||||||
// We use this list to check for alias collisions later
|
|
||||||
allRSIDsList := make([]int64, 0)
|
|
||||||
|
|
||||||
for rsID, locusBasePairValue := range rawGenomeMap{
|
|
||||||
|
|
||||||
locusAllele2Exists := locusBasePairValue.Allele2Exists
|
|
||||||
if (locusAllele2Exists == false){
|
|
||||||
// This SNP contains less than 2 bases
|
|
||||||
// We don't support reading these kinds of SNP values yet
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
locusAllele1 := locusBasePairValue.Allele1
|
|
||||||
locusAllele2 := locusBasePairValue.Allele2
|
|
||||||
|
|
||||||
getLocusIsPhasedBool := func()bool{
|
|
||||||
|
|
||||||
if (locusAllele1 == locusAllele2){
|
|
||||||
// Locus has to be phased, because phase flip does not change value
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return genomeIsPhased
|
|
||||||
}
|
|
||||||
|
|
||||||
locusIsPhased := getLocusIsPhasedBool()
|
|
||||||
|
|
||||||
locusValueObject := locusValue.LocusValue{
|
|
||||||
Base1Value: locusAllele1,
|
|
||||||
Base2Value: locusAllele2,
|
|
||||||
LocusIsPhased: locusIsPhased,
|
|
||||||
}
|
|
||||||
|
|
||||||
genomeMap[rsID] = locusValueObject
|
|
||||||
|
|
||||||
allRSIDsList = append(allRSIDsList, rsID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we check for rsID aliases
|
|
||||||
// rsID aliases are multiple rsids that refer to the same location
|
|
||||||
// If a single genome file contained two identical rsids whose value conflicted, the company must have made an error in reporting
|
|
||||||
|
|
||||||
for _, rsID := range allRSIDsList{
|
|
||||||
|
|
||||||
rsidLocusValue, exists := genomeMap[rsID]
|
|
||||||
if (exists == false){
|
|
||||||
// This must have been an alias that was deleted
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
aliasExists, rsidAliasesList, err := locusMetadata.GetRSIDAliases(rsID)
|
|
||||||
if (err != nil){ return false, nil, err }
|
|
||||||
if (aliasExists == false){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
checkIfRSIDCollisionExists := func()bool{
|
|
||||||
|
|
||||||
for _, rsidAlias := range rsidAliasesList{
|
|
||||||
|
|
||||||
aliasLocusValue, exists := genomeMap[rsidAlias]
|
|
||||||
if (exists == false){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aliasLocusValue != rsidLocusValue){
|
|
||||||
// A collision exists with an alias rsID
|
|
||||||
// The company must be creating invalid results, or our alias list is invalid
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
rsidCollisionExists := checkIfRSIDCollisionExists()
|
|
||||||
if (rsidCollisionExists == true){
|
|
||||||
// We will delete this rsID
|
|
||||||
// We cannot trust any of the results
|
|
||||||
|
|
||||||
delete(genomeMap, rsID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We delete all aliases from the genome map
|
|
||||||
// We do this to save space
|
|
||||||
|
|
||||||
for _, rsidAlias := range rsidAliasesList{
|
|
||||||
|
|
||||||
delete(genomeMap, rsidAlias)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len(genomeMap) == 0){
|
|
||||||
// No valid locations exist
|
|
||||||
return false, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, genomeMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -47,30 +47,27 @@ func ReadCoupleGeneticAnalysisString(inputAnalysisString string)(geneticAnalysis
|
||||||
// -bool: Multiple genomes exist
|
// -bool: Multiple genomes exist
|
||||||
// -[16]byte: OnlyExcludeConflicts GenomeIdentifier
|
// -[16]byte: OnlyExcludeConflicts GenomeIdentifier
|
||||||
// -[16]byte: OnlyIncludeShared GenomeIdentifier
|
// -[16]byte: OnlyIncludeShared GenomeIdentifier
|
||||||
// -map[[16]byte]map[int64]locusValue.LocusValue: Genomes locus values map
|
|
||||||
// -error
|
// -error
|
||||||
func GetMetadataFromPersonGeneticAnalysis(inputGeneticAnalysis geneticAnalysis.PersonAnalysis)([][16]byte, bool, [16]byte, [16]byte, map[[16]byte]map[int64]locusValue.LocusValue, error){
|
func GetMetadataFromPersonGeneticAnalysis(inputGeneticAnalysis geneticAnalysis.PersonAnalysis)([][16]byte, bool, [16]byte, [16]byte, error){
|
||||||
|
|
||||||
analysisVersion := inputGeneticAnalysis.AnalysisVersion
|
analysisVersion := inputGeneticAnalysis.AnalysisVersion
|
||||||
if (analysisVersion != 1){
|
if (analysisVersion != 1){
|
||||||
// This analysis must have been created by a newer version of Seekia
|
// This analysis must have been created by a newer version of Seekia
|
||||||
// We cannot read it
|
// We cannot read it
|
||||||
return nil, false, [16]byte{}, [16]byte{}, nil, errors.New("Cannot read analysis: Is a newer analysis version.")
|
return nil, false, [16]byte{}, [16]byte{}, errors.New("Cannot read analysis: Is a newer analysis version.")
|
||||||
}
|
}
|
||||||
|
|
||||||
allRawGenomeIdentifiersList := inputGeneticAnalysis.AllRawGenomeIdentifiersList
|
allRawGenomeIdentifiersList := inputGeneticAnalysis.AllRawGenomeIdentifiersList
|
||||||
|
|
||||||
genomesMap := inputGeneticAnalysis.GenomesMap
|
|
||||||
|
|
||||||
combinedGenomesExist := inputGeneticAnalysis.CombinedGenomesExist
|
combinedGenomesExist := inputGeneticAnalysis.CombinedGenomesExist
|
||||||
if (combinedGenomesExist == false){
|
if (combinedGenomesExist == false){
|
||||||
return allRawGenomeIdentifiersList, false, [16]byte{}, [16]byte{}, genomesMap, nil
|
return allRawGenomeIdentifiersList, false, [16]byte{}, [16]byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
onlyExcludeConflictsGenomeIdentifier := inputGeneticAnalysis.OnlyExcludeConflictsGenomeIdentifier
|
onlyExcludeConflictsGenomeIdentifier := inputGeneticAnalysis.OnlyExcludeConflictsGenomeIdentifier
|
||||||
onlyIncludeSharedGenomeIdentifier := inputGeneticAnalysis.OnlyIncludeSharedGenomeIdentifier
|
onlyIncludeSharedGenomeIdentifier := inputGeneticAnalysis.OnlyIncludeSharedGenomeIdentifier
|
||||||
|
|
||||||
return allRawGenomeIdentifiersList, true, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, genomesMap, nil
|
return allRawGenomeIdentifiersList, true, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
|
@ -181,7 +178,7 @@ func GetMatchingPersonAnalysisGenomeIdentifierFromCoupleAnalysis(isPerson1 bool,
|
||||||
return inputGenomeIdentifier, true, false, "", nil
|
return inputGenomeIdentifier, true, false, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := GetMetadataFromPersonGeneticAnalysis(person1AnalysisObject)
|
_, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := GetMetadataFromPersonGeneticAnalysis(person1AnalysisObject)
|
||||||
if (err != nil) { return [16]byte{}, false, false, "", err }
|
if (err != nil) { return [16]byte{}, false, false, "", err }
|
||||||
if (multipleGenomesExist == false){
|
if (multipleGenomesExist == false){
|
||||||
return [16]byte{}, false, false, "", errors.New("Couple analysis says person has multiple genomes, person analysis does not.")
|
return [16]byte{}, false, false, "", errors.New("Couple analysis says person has multiple genomes, person analysis does not.")
|
||||||
|
@ -207,7 +204,7 @@ func GetMatchingPersonAnalysisGenomeIdentifierFromCoupleAnalysis(isPerson1 bool,
|
||||||
return inputGenomeIdentifier, true, false, "", nil
|
return inputGenomeIdentifier, true, false, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := GetMetadataFromPersonGeneticAnalysis(person2AnalysisObject)
|
_, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := GetMetadataFromPersonGeneticAnalysis(person2AnalysisObject)
|
||||||
if (err != nil) { return [16]byte{}, false, false, "", err }
|
if (err != nil) { return [16]byte{}, false, false, "", err }
|
||||||
if (multipleGenomesExist == false){
|
if (multipleGenomesExist == false){
|
||||||
return [16]byte{}, false, false, "", errors.New("Couple analysis says person has multiple genomes, person analysis does not.")
|
return [16]byte{}, false, false, "", errors.New("Couple analysis says person has multiple genomes, person analysis does not.")
|
||||||
|
@ -229,9 +226,9 @@ func GetMatchingPersonAnalysisGenomeIdentifierFromCoupleAnalysis(isPerson1 bool,
|
||||||
// -bool: Person has disease
|
// -bool: Person has disease
|
||||||
// -int: Probability of passing a disease variant
|
// -int: Probability of passing a disease variant
|
||||||
// -string: Probability of passing a disease variant formatted (with % suffix)
|
// -string: Probability of passing a disease variant formatted (with % suffix)
|
||||||
// -int: Quantity of variants tested
|
// -int: Number of variants tested
|
||||||
// -int: Quantity of loci tested
|
// -int: Number of loci tested
|
||||||
// -int: Quantity of phased loci
|
// -int: Number of phased loci
|
||||||
// -bool: Conflict exists
|
// -bool: Conflict exists
|
||||||
// -error
|
// -error
|
||||||
func GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, genomeIdentifier [16]byte)(bool, bool, int, string, int, int, int, bool, error){
|
func GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, diseaseName string, genomeIdentifier [16]byte)(bool, bool, int, string, int, int, int, bool, error){
|
||||||
|
@ -253,16 +250,16 @@ func GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject genet
|
||||||
conflictExists := personMonogenicDiseaseInfo.ConflictExists
|
conflictExists := personMonogenicDiseaseInfo.ConflictExists
|
||||||
|
|
||||||
personHasDisease := genomeMonogenicDiseaseInfo.PersonHasDisease
|
personHasDisease := genomeMonogenicDiseaseInfo.PersonHasDisease
|
||||||
quantityOfVariantsTested := genomeMonogenicDiseaseInfo.QuantityOfVariantsTested
|
numberOfVariantsTested := genomeMonogenicDiseaseInfo.NumberOfVariantsTested
|
||||||
quantityOfLociTested := genomeMonogenicDiseaseInfo.QuantityOfLociTested
|
numberOfLociTested := genomeMonogenicDiseaseInfo.NumberOfLociTested
|
||||||
quantityOfPhasedLoci := genomeMonogenicDiseaseInfo.QuantityOfPhasedLoci
|
numberOfPhasedLoci := genomeMonogenicDiseaseInfo.NumberOfPhasedLoci
|
||||||
probabilityOfPassingAVariant := genomeMonogenicDiseaseInfo.ProbabilityOfPassingADiseaseVariant
|
probabilityOfPassingAVariant := genomeMonogenicDiseaseInfo.ProbabilityOfPassingADiseaseVariant
|
||||||
|
|
||||||
probabilityOfPassingAVariantString := helpers.ConvertIntToString(probabilityOfPassingAVariant)
|
probabilityOfPassingAVariantString := helpers.ConvertIntToString(probabilityOfPassingAVariant)
|
||||||
|
|
||||||
probabilityOfPassingAVariantFormatted := probabilityOfPassingAVariantString + "%"
|
probabilityOfPassingAVariantFormatted := probabilityOfPassingAVariantString + "%"
|
||||||
|
|
||||||
return true, personHasDisease, probabilityOfPassingAVariant, probabilityOfPassingAVariantFormatted, quantityOfVariantsTested, quantityOfLociTested, quantityOfPhasedLoci, conflictExists, nil
|
return true, personHasDisease, probabilityOfPassingAVariant, probabilityOfPassingAVariantFormatted, numberOfVariantsTested, numberOfLociTested, numberOfPhasedLoci, conflictExists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -488,23 +485,24 @@ func GetOffspringMonogenicDiseaseVariantInfoFromGeneticAnalysis(coupleAnalysisOb
|
||||||
// -bool: Polygenic Disease Risk Score known (any loci values exist)
|
// -bool: Polygenic Disease Risk Score known (any loci values exist)
|
||||||
// -int: Person Disease risk score
|
// -int: Person Disease risk score
|
||||||
// -string: Person Disease risk score formatted (has "/10" suffix)
|
// -string: Person Disease risk score formatted (has "/10" suffix)
|
||||||
// -int: Quantity of loci tested
|
// -map[int]locusValue.LocusValue: Person locus values map
|
||||||
|
// -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
|
||||||
|
@ -515,9 +513,11 @@ func GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject genet
|
||||||
|
|
||||||
personDiseaseRiskScoreFormatted := personDiseaseRiskScoreString + "/10"
|
personDiseaseRiskScoreFormatted := personDiseaseRiskScoreString + "/10"
|
||||||
|
|
||||||
quantityOfLociTested := genomePolygenicDiseaseInfo.QuantityOfLociTested
|
personLocusValuesMap := genomePolygenicDiseaseInfo.LocusValuesMap
|
||||||
|
|
||||||
return true, personDiseaseRiskScore, personDiseaseRiskScoreFormatted, quantityOfLociTested, conflictExists, nil
|
numberOfLociTested := genomePolygenicDiseaseInfo.NumberOfLociTested
|
||||||
|
|
||||||
|
return true, personDiseaseRiskScore, personDiseaseRiskScoreFormatted, personLocusValuesMap, numberOfLociTested, conflictExists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -526,7 +526,7 @@ func GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject genet
|
||||||
// -int: Offspring average disease risk score
|
// -int: Offspring average disease risk score
|
||||||
// -string: Offspring Disease average risk score formatted (has "/10" suffix)
|
// -string: Offspring Disease average risk score formatted (has "/10" suffix)
|
||||||
// -[]int: Sample Offspring Risk Scores List
|
// -[]int: Sample Offspring Risk Scores List
|
||||||
// -int: Quantity 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, int, bool, error){
|
func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, diseaseName string, genomePairIdentifier [32]byte)(bool, int, string, []int, int, bool, error){
|
||||||
|
@ -547,7 +547,7 @@ func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject ge
|
||||||
|
|
||||||
conflictExists := couplePolygenicDiseaseInfo.ConflictExists
|
conflictExists := couplePolygenicDiseaseInfo.ConflictExists
|
||||||
|
|
||||||
quantityOfLociTested := genomePairPolygenicDiseaseInfo.QuantityOfLociTested
|
numberOfLociTested := genomePairPolygenicDiseaseInfo.NumberOfLociTested
|
||||||
|
|
||||||
offspringAverageRiskScore := genomePairPolygenicDiseaseInfo.OffspringAverageRiskScore
|
offspringAverageRiskScore := genomePairPolygenicDiseaseInfo.OffspringAverageRiskScore
|
||||||
|
|
||||||
|
@ -557,7 +557,7 @@ func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject ge
|
||||||
|
|
||||||
sampleOffspringRiskScoresList := genomePairPolygenicDiseaseInfo.SampleOffspringRiskScoresList
|
sampleOffspringRiskScoresList := genomePairPolygenicDiseaseInfo.SampleOffspringRiskScoresList
|
||||||
|
|
||||||
return true, offspringAverageRiskScore, offspringAverageRiskScoreFormatted, sampleOffspringRiskScoresList, quantityOfLociTested, conflictExists, nil
|
return true, offspringAverageRiskScore, offspringAverageRiskScoreFormatted, sampleOffspringRiskScoresList, numberOfLociTested, conflictExists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
|
@ -673,169 +673,71 @@ func GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisObje
|
||||||
}
|
}
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: Neural network exists
|
// -map[int64]locusValue.LocusValue (rsID -> Base pair) (missing rsIDs represent unknown values)
|
||||||
// -bool: Any neural network analysis exists
|
|
||||||
// -string: Neural network predicted outcome
|
|
||||||
// -int: Prediction confidence
|
|
||||||
// -int: Quantity of loci known (Neural network)
|
|
||||||
// -int: Quantity of phased loci (Neural network)
|
|
||||||
// -bool: Any trait rules exist (Rule-based analysis is possible)
|
|
||||||
// -bool: Any Trait Rule known/tested
|
// -bool: Any Trait Rule known/tested
|
||||||
// -map[[3]byte]bool: Rule Identifier -> Person passes rule
|
// -map[string]int: Trait outcomes scores map (Outcome -> Number of points)
|
||||||
// -bool: Predicted outcome exists
|
// -int: Number of rules tested
|
||||||
// -string: Predicted outcome
|
// -bool: Conflict exists
|
||||||
// -int: Quantity of rules tested
|
|
||||||
// -int: Quantity Of Loci Known (Rules)
|
|
||||||
// -bool: Conflict exists (between any of these results for each genome)
|
|
||||||
// -error
|
// -error
|
||||||
func GetPersonDiscreteTraitInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, genomeIdentifier [16]byte)(bool, bool, string, int, int, int, bool, bool, map[[3]byte]bool, bool, string, int, int, bool, error){
|
func GetPersonTraitInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, genomeIdentifier [16]byte)(map[int64]locusValue.LocusValue, bool, map[string]int, int, bool, error){
|
||||||
|
|
||||||
personTraitsMap := personAnalysisObject.DiscreteTraitsMap
|
personTraitsMap := personAnalysisObject.TraitsMap
|
||||||
|
|
||||||
personTraitInfoObject, exists := personTraitsMap[traitName]
|
personTraitInfoObject, exists := personTraitsMap[traitName]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, false, "", 0, 0, 0, false, false, nil, false, "", 0, 0, false, errors.New("Person trait analysis is missing trait: " + traitName)
|
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
return emptyMap, false, nil, 0, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
personTraitInfoMap := personTraitInfoObject.TraitInfoMap
|
personTraitInfoMap := personTraitInfoObject.TraitInfoMap
|
||||||
conflictExists := personTraitInfoObject.ConflictExists
|
|
||||||
|
|
||||||
personGenomeTraitInfoObject, exists := personTraitInfoMap[genomeIdentifier]
|
personGenomeTraitInfoObject, exists := personTraitInfoMap[genomeIdentifier]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, false, "", 0, 0, 0, false, false, nil, false, "", 0, 0, false, errors.New("personTraitInfoMap in Person analysis is missing map for genome identifier.")
|
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
return emptyMap, false, nil, 0, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
neuralNetworkExists := personGenomeTraitInfoObject.NeuralNetworkExists
|
conflictExists := personTraitInfoObject.ConflictExists
|
||||||
neuralNetworkAnalysisExists := personGenomeTraitInfoObject.NeuralNetworkAnalysisExists
|
|
||||||
|
|
||||||
getNeuralNetworkAnalysisInfo := func()(string, int, int, int){
|
genomeNumberOfRulesTested := personGenomeTraitInfoObject.NumberOfRulesTested
|
||||||
|
|
||||||
if (neuralNetworkExists == false || neuralNetworkAnalysisExists == false){
|
genomeLocusValuesMap := personGenomeTraitInfoObject.LocusValuesMap
|
||||||
return "", 0, 0, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
neuralNetworkAnalysis := personGenomeTraitInfoObject.NeuralNetworkAnalysis
|
genomeOutcomeScoresMap := personGenomeTraitInfoObject.OutcomeScoresMap
|
||||||
|
|
||||||
predictedOutcome := neuralNetworkAnalysis.PredictedOutcome
|
return genomeLocusValuesMap, true, genomeOutcomeScoresMap, genomeNumberOfRulesTested, conflictExists, nil
|
||||||
predictionConfidence := neuralNetworkAnalysis.PredictionConfidence
|
|
||||||
quantityOfLociKnown := neuralNetworkAnalysis.QuantityOfLociKnown
|
|
||||||
quantityOfPhasedLoci := neuralNetworkAnalysis.QuantityOfPhasedLoci
|
|
||||||
|
|
||||||
return predictedOutcome, predictionConfidence, quantityOfLociKnown, quantityOfPhasedLoci
|
|
||||||
}
|
|
||||||
|
|
||||||
neuralNetworkPredictedOutcome, neuralNetworkPredictionConfidence, quantityOfLociKnown_NeuralNetwork, quantityOfPhasedLoci_NeuralNetwork :=
|
|
||||||
getNeuralNetworkAnalysisInfo()
|
|
||||||
|
|
||||||
anyRulesExist := personGenomeTraitInfoObject.AnyRulesExist
|
|
||||||
rulesAnalysisExists := personGenomeTraitInfoObject.RulesAnalysisExists
|
|
||||||
|
|
||||||
getTraitAnalysisInfo := func()(map[[3]byte]bool, bool, string, int, int){
|
|
||||||
|
|
||||||
if (anyRulesExist == false || rulesAnalysisExists == false){
|
|
||||||
return nil, false, "", 0, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
rulesAnalysisObject := personGenomeTraitInfoObject.RulesAnalysis
|
|
||||||
|
|
||||||
genomePassesRulesMap := rulesAnalysisObject.GenomePassesRulesMap
|
|
||||||
|
|
||||||
predictedOutcomeExists := rulesAnalysisObject.PredictedOutcomeExists
|
|
||||||
|
|
||||||
predictedOutcome := rulesAnalysisObject.PredictedOutcome
|
|
||||||
|
|
||||||
quantityOfRulesTested := rulesAnalysisObject.QuantityOfRulesTested
|
|
||||||
|
|
||||||
quantityOfLociKnown := rulesAnalysisObject.QuantityOfLociKnown
|
|
||||||
|
|
||||||
return genomePassesRulesMap, predictedOutcomeExists, predictedOutcome, quantityOfRulesTested, quantityOfLociKnown
|
|
||||||
}
|
|
||||||
|
|
||||||
genomePassesRulesMap, rulesPredictedOutcomeExists, rulesPredictedOutcome, quantityOfRulesTested, quantityOfLociKnown_Rules := getTraitAnalysisInfo()
|
|
||||||
|
|
||||||
return neuralNetworkExists, neuralNetworkAnalysisExists, neuralNetworkPredictedOutcome, neuralNetworkPredictionConfidence, quantityOfLociKnown_NeuralNetwork, quantityOfPhasedLoci_NeuralNetwork, anyRulesExist, rulesAnalysisExists, genomePassesRulesMap, rulesPredictedOutcomeExists, rulesPredictedOutcome, quantityOfRulesTested, quantityOfLociKnown_Rules, conflictExists, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Outputs:
|
|
||||||
// -bool: Neural network exists
|
|
||||||
// -bool: Neural network analysis exists
|
|
||||||
// -map[string]int: Offspring outcome probabilities map for neural network prediction
|
|
||||||
// -Map Structure: Outcome name -> Probability of outcome (0-100)
|
|
||||||
// -int: Average confidence (for neural network prediction)
|
|
||||||
// -int: Quantity of loci known (for neural network)
|
|
||||||
// -int: Quantity of Parental phased loci
|
|
||||||
// -bool: Any Rules exist
|
|
||||||
// -bool: Rules analysis exists
|
|
||||||
// -map[string]int: Offspring outcome probabilities map for rules-based prediction
|
|
||||||
// -Map Structure: Outcome name -> Probability of outcome (0-100)
|
|
||||||
// -map[[3]byte]int: Offspring probability of passing rules map
|
|
||||||
// -Map Structure: Rule Identifier -> Probability of passing rule (0-100)
|
|
||||||
// -int: Quantity of rules tested
|
|
||||||
// -int: Quantity of loci known (For Rules)
|
|
||||||
// -bool: Conflict exists (Between this genome pair and other genome pairs)
|
|
||||||
// -error
|
|
||||||
func GetOffspringDiscreteTraitInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, traitName string, genomePairIdentifier [32]byte)(bool, bool, map[string]int, int, int, int, bool, bool, map[string]int, map[[3]byte]int, int, int, bool, error){
|
|
||||||
|
|
||||||
offspringTraitsMap := coupleAnalysisObject.DiscreteTraitsMap
|
|
||||||
|
//Outputs:
|
||||||
|
// -bool: Trait Outcome Scores known
|
||||||
|
// -map[string]float64: Trait average outcome scores map (OutcomeName -> AverageScore)
|
||||||
|
// -int: Number of rules tested
|
||||||
|
// -bool: Conflict exists
|
||||||
|
// -error
|
||||||
|
func GetOffspringTraitInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, traitName string, genomePairIdentifier [32]byte)(bool, map[string]float64, int, bool, error){
|
||||||
|
|
||||||
|
offspringTraitsMap := coupleAnalysisObject.TraitsMap
|
||||||
|
|
||||||
traitInfoObject, exists := offspringTraitsMap[traitName]
|
traitInfoObject, exists := offspringTraitsMap[traitName]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, false, nil, 0, 0, 0, false, false, nil, nil, 0, 0, false, errors.New("offspringTraitsMap missing trait when reading couple genetic analysis: " + traitName)
|
return false, nil, 0, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
traitInfoMap := traitInfoObject.TraitInfoMap
|
traitInfoMap := traitInfoObject.TraitInfoMap
|
||||||
conflictExists := traitInfoObject.ConflictExists
|
|
||||||
|
|
||||||
genomePairTraitInfoObject, exists := traitInfoMap[genomePairIdentifier]
|
genomePairTraitInfoObject, exists := traitInfoMap[genomePairIdentifier]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, false, nil, 0, 0, 0, false, false, nil, nil, 0, 0, false, errors.New("traitInfoMap missing trait info for genome pair when reading from genetic analysis.")
|
return false, nil, 0, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
neuralNetworkExists := genomePairTraitInfoObject.NeuralNetworkExists
|
conflictExists := traitInfoObject.ConflictExists
|
||||||
|
|
||||||
neuralNetworkAnalysisExists := genomePairTraitInfoObject.NeuralNetworkAnalysisExists
|
numberOfRulesTested := genomePairTraitInfoObject.NumberOfRulesTested
|
||||||
|
offspringAverageOutcomeScoresMap := genomePairTraitInfoObject.OffspringAverageOutcomeScoresMap
|
||||||
|
|
||||||
getGenomePairTraitNeuralNetworkAnalysisInfo := func()(map[string]int, int, int, int){
|
return true, offspringAverageOutcomeScoresMap, numberOfRulesTested, conflictExists, nil
|
||||||
|
|
||||||
if (neuralNetworkExists == false || neuralNetworkAnalysisExists == false){
|
|
||||||
return nil, 0, 0, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
genomePairTraitNeuralNetworkInfo := genomePairTraitInfoObject.NeuralNetworkAnalysis
|
|
||||||
|
|
||||||
offspringOutcomeProbabilitiesMap := genomePairTraitNeuralNetworkInfo.OffspringOutcomeProbabilitiesMap
|
|
||||||
averageConfidence := genomePairTraitNeuralNetworkInfo.AverageConfidence
|
|
||||||
quantityOfLociKnown := genomePairTraitNeuralNetworkInfo.QuantityOfLociKnown
|
|
||||||
quantityOfParentalPhasedLoci := genomePairTraitNeuralNetworkInfo.QuantityOfParentalPhasedLoci
|
|
||||||
|
|
||||||
return offspringOutcomeProbabilitiesMap, averageConfidence, quantityOfLociKnown, quantityOfParentalPhasedLoci
|
|
||||||
}
|
|
||||||
|
|
||||||
offspringOutcomeProbabilitiesMap_NeuralNetwork, averageConfidence_NeuralNetwork, quantityOfLociKnown_NeuralNetwork, quantityOfParentalPhasedLoci_NeuralNetwork := getGenomePairTraitNeuralNetworkAnalysisInfo()
|
|
||||||
|
|
||||||
anyRulesExist := genomePairTraitInfoObject.RulesExist
|
|
||||||
|
|
||||||
rulesAnalysisExists := genomePairTraitInfoObject.RulesAnalysisExists
|
|
||||||
|
|
||||||
getGenomePairTraitRulesAnalysisInfo := func()(map[string]int, map[[3]byte]int, int, int){
|
|
||||||
|
|
||||||
if (anyRulesExist == false || rulesAnalysisExists == false){
|
|
||||||
return nil, nil, 0, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
genomePairTraitInfo_Rules := genomePairTraitInfoObject.RulesAnalysis
|
|
||||||
|
|
||||||
offspringOutcomeProbabilitiesMap := genomePairTraitInfo_Rules.OffspringOutcomeProbabilitiesMap
|
|
||||||
probabilityOfPassingRulesMap := genomePairTraitInfo_Rules.ProbabilityOfPassingRulesMap
|
|
||||||
quantityOfRulesTested := genomePairTraitInfo_Rules.QuantityOfRulesTested
|
|
||||||
quantityOfLociKnown := genomePairTraitInfo_Rules.QuantityOfLociKnown
|
|
||||||
|
|
||||||
return offspringOutcomeProbabilitiesMap, probabilityOfPassingRulesMap, quantityOfRulesTested, quantityOfLociKnown
|
|
||||||
}
|
|
||||||
|
|
||||||
offspringOutcomeProbabilitiesMap_Rules, probabilityOfPassingRulesMap, quantityOfRulesTested, quantityOfLociKnown_Rules := getGenomePairTraitRulesAnalysisInfo()
|
|
||||||
|
|
||||||
return neuralNetworkExists, neuralNetworkAnalysisExists, offspringOutcomeProbabilitiesMap_NeuralNetwork, averageConfidence_NeuralNetwork, quantityOfLociKnown_NeuralNetwork, quantityOfParentalPhasedLoci_NeuralNetwork, anyRulesExist, rulesAnalysisExists, offspringOutcomeProbabilitiesMap_Rules, probabilityOfPassingRulesMap, quantityOfRulesTested, quantityOfLociKnown_Rules, conflictExists, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -843,17 +745,24 @@ func GetOffspringDiscreteTraitInfoFromGeneticAnalysis(coupleAnalysisObject genet
|
||||||
// -bool: Rule status is known (we know if the rule is passed or not)
|
// -bool: Rule status is known (we know if the rule is passed or not)
|
||||||
// -bool: Genome passes rule
|
// -bool: Genome passes rule
|
||||||
// -error
|
// -error
|
||||||
func GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, ruleIdentifier [3]byte, genomeIdentifier [16]byte)(bool, bool, error){
|
func GetPersonTraitRuleInfoFromGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, ruleIdentifier [3]byte, genomeIdentifier [16]byte)(bool, bool, error){
|
||||||
|
|
||||||
_, _, _, _, _, _, anyRulesExist, rulesAnalysisExists, genomePassesRulesMap, _, _, _, _, _, err := GetPersonDiscreteTraitInfoFromGeneticAnalysis(personAnalysisObject, traitName, genomeIdentifier)
|
personTraitsMap := personAnalysisObject.TraitsMap
|
||||||
if (err != nil) { return false, false, err }
|
|
||||||
if (anyRulesExist == false){
|
traitInfoObject, exists := personTraitsMap[traitName]
|
||||||
return false, false, errors.New("GetPersonTraitRuleInfoFromGeneticAnalysis called when no trait rules exist.")
|
if (exists == false){
|
||||||
}
|
|
||||||
if (rulesAnalysisExists == false){
|
|
||||||
return false, false, nil
|
return false, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
personTraitInfoMap := traitInfoObject.TraitInfoMap
|
||||||
|
|
||||||
|
genomeTraitInfoObject, exists := personTraitInfoMap[genomeIdentifier]
|
||||||
|
if (exists == false){
|
||||||
|
return false, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
genomePassesRulesMap := genomeTraitInfoObject.GenomePassesRulesMap
|
||||||
|
|
||||||
genomePassesRule, statusIsKnown := genomePassesRulesMap[ruleIdentifier]
|
genomePassesRule, statusIsKnown := genomePassesRulesMap[ruleIdentifier]
|
||||||
if (statusIsKnown == false){
|
if (statusIsKnown == false){
|
||||||
return false, false, nil
|
return false, false, nil
|
||||||
|
@ -868,17 +777,24 @@ func GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(personAnalysisObject gene
|
||||||
// -int: Offspring probability of passing rule (0 - 100)
|
// -int: Offspring probability of passing rule (0 - 100)
|
||||||
// -string: Offspring probability of passing rule formatted (with % suffix)
|
// -string: Offspring probability of passing rule formatted (with % suffix)
|
||||||
// -error
|
// -error
|
||||||
func GetOffspringDiscreteTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, traitName string, ruleIdentifier [3]byte, genomePairIdentifier [32]byte)(bool, int, string, error){
|
func GetOffspringTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnalysis, traitName string, ruleIdentifier [3]byte, genomePairIdentifier [32]byte)(bool, int, string, error){
|
||||||
|
|
||||||
_, _, _, _, _, _, anyRulesExist, rulesAnalysisExists, _, offspringProbabilityOfPassingRulesMap, _, _, _, err := GetOffspringDiscreteTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, genomePairIdentifier)
|
offspringTraitsMap := coupleAnalysisObject.TraitsMap
|
||||||
if (err != nil) { return false, 0, "", err }
|
|
||||||
if (anyRulesExist == false){
|
offspringTraitInfo, exists := offspringTraitsMap[traitName]
|
||||||
return false, 0, "", errors.New("GetOffspringTraitRuleInfoFromGeneticAnalysis called for trait which has no rules: " + traitName)
|
if (exists == false){
|
||||||
}
|
|
||||||
if (rulesAnalysisExists == false){
|
|
||||||
return false, 0, "", nil
|
return false, 0, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offspringTraitInfoMap := offspringTraitInfo.TraitInfoMap
|
||||||
|
|
||||||
|
offspringTraitInfoObject, exists := offspringTraitInfoMap[genomePairIdentifier]
|
||||||
|
if (exists == false){
|
||||||
|
return false, 0, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
offspringProbabilityOfPassingRulesMap := offspringTraitInfoObject.ProbabilityOfPassingRulesMap
|
||||||
|
|
||||||
offspringProbabilityOfPassingRule, exists := offspringProbabilityOfPassingRulesMap[ruleIdentifier]
|
offspringProbabilityOfPassingRule, exists := offspringProbabilityOfPassingRulesMap[ruleIdentifier]
|
||||||
if (exists == false){
|
if (exists == false){
|
||||||
return false, 0, "", nil
|
return false, 0, "", nil
|
||||||
|
@ -896,7 +812,7 @@ func GetOffspringDiscreteTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject g
|
||||||
//TODO: Perform sanity checks on data
|
//TODO: Perform sanity checks on data
|
||||||
func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis)error{
|
func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnalysis)error{
|
||||||
|
|
||||||
allRawGenomeIdentifiersList, personHasMultipleGenomes, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := GetMetadataFromPersonGeneticAnalysis(personAnalysisObject)
|
allRawGenomeIdentifiersList, personHasMultipleGenomes, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := GetMetadataFromPersonGeneticAnalysis(personAnalysisObject)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
allGenomeIdentifiersList := allRawGenomeIdentifiersList
|
allGenomeIdentifiersList := allRawGenomeIdentifiersList
|
||||||
|
@ -943,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 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -970,31 +886,27 @@ func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnal
|
||||||
for _, traitObject := range traitObjectsList{
|
for _, traitObject := range traitObjectsList{
|
||||||
|
|
||||||
traitName := traitObject.TraitName
|
traitName := traitObject.TraitName
|
||||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
|
||||||
|
|
||||||
if (traitIsDiscreteOrNumeric == "Discrete"){
|
for _, genomeIdentifier := range allGenomeIdentifiersList{
|
||||||
|
|
||||||
|
_, _, _, _, _, err := GetPersonTraitInfoFromGeneticAnalysis(personAnalysisObject, traitName, genomeIdentifier)
|
||||||
|
if (err != nil) { return err }
|
||||||
|
}
|
||||||
|
|
||||||
|
traitRulesList := traitObject.RulesList
|
||||||
|
|
||||||
|
for _, traitRuleObject := range traitRulesList{
|
||||||
|
|
||||||
|
ruleIdentifierHex := traitRuleObject.RuleIdentifier
|
||||||
|
|
||||||
|
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
|
||||||
|
if (err != nil) { return err }
|
||||||
|
|
||||||
for _, genomeIdentifier := range allGenomeIdentifiersList{
|
for _, genomeIdentifier := range allGenomeIdentifiersList{
|
||||||
|
|
||||||
_, _, _, _, _, _, _, _, _, _, _, _, _, _, err := GetPersonDiscreteTraitInfoFromGeneticAnalysis(personAnalysisObject, traitName, genomeIdentifier)
|
_, _, err := GetPersonTraitRuleInfoFromGeneticAnalysis(personAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
}
|
}
|
||||||
|
|
||||||
traitRulesList := traitObject.RulesList
|
|
||||||
|
|
||||||
for _, traitRuleObject := range traitRulesList{
|
|
||||||
|
|
||||||
ruleIdentifierHex := traitRuleObject.RuleIdentifier
|
|
||||||
|
|
||||||
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
|
|
||||||
if (err != nil) { return err }
|
|
||||||
|
|
||||||
for _, genomeIdentifier := range allGenomeIdentifiersList{
|
|
||||||
|
|
||||||
_, _, err := GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(personAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
|
||||||
if (err != nil) { return err }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1086,31 +998,27 @@ func VerifyCoupleGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnal
|
||||||
for _, traitObject := range traitObjectsList{
|
for _, traitObject := range traitObjectsList{
|
||||||
|
|
||||||
traitName := traitObject.TraitName
|
traitName := traitObject.TraitName
|
||||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
|
||||||
|
|
||||||
if (traitIsDiscreteOrNumeric == "Discrete"){
|
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
|
||||||
|
|
||||||
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
|
_, _, _, _, err := GetOffspringTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, genomePairIdentifier)
|
||||||
|
if (err != nil) { return err }
|
||||||
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, _, _, _, _, _, _, _, err := GetOffspringDiscreteTraitInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, genomePairIdentifier)
|
traitRulesList := traitObject.RulesList
|
||||||
|
|
||||||
|
for _, traitRuleObject := range traitRulesList{
|
||||||
|
|
||||||
|
ruleIdentifierHex := traitRuleObject.RuleIdentifier
|
||||||
|
|
||||||
|
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
|
||||||
|
if (err != nil) { return err }
|
||||||
|
|
||||||
|
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
|
||||||
|
|
||||||
|
_, _, _, err := GetOffspringTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, ruleIdentifier, genomePairIdentifier)
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
}
|
}
|
||||||
|
|
||||||
traitRulesList := traitObject.RulesList
|
|
||||||
|
|
||||||
for _, traitRuleObject := range traitRulesList{
|
|
||||||
|
|
||||||
ruleIdentifierHex := traitRuleObject.RuleIdentifier
|
|
||||||
|
|
||||||
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
|
|
||||||
if (err != nil) { return err }
|
|
||||||
|
|
||||||
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
|
|
||||||
|
|
||||||
_, _, _, err := GetOffspringDiscreteTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject, traitName, ruleIdentifier, genomePairIdentifier)
|
|
||||||
if (err != nil) { return err }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,44 +128,41 @@ func ReadRawGenomeFile(fileReader io.Reader) (string, int, int64, int64, bool, m
|
||||||
}
|
}
|
||||||
|
|
||||||
getMonthObject := func()(time.Month, error){
|
getMonthObject := func()(time.Month, error){
|
||||||
|
if (monthString == "01"){
|
||||||
switch monthString{
|
return time.January, nil
|
||||||
case "01":{
|
}
|
||||||
return time.January, nil
|
if (monthString == "02"){
|
||||||
}
|
return time.February, nil
|
||||||
case "02":{
|
}
|
||||||
return time.February, nil
|
if (monthString == "03"){
|
||||||
}
|
return time.March, nil
|
||||||
case "03":{
|
}
|
||||||
return time.March, nil
|
if (monthString == "04"){
|
||||||
}
|
return time.April, nil
|
||||||
case "04":{
|
}
|
||||||
return time.April, nil
|
if (monthString == "05"){
|
||||||
}
|
return time.May, nil
|
||||||
case "05":{
|
}
|
||||||
return time.May, nil
|
if (monthString == "06"){
|
||||||
}
|
return time.June, nil
|
||||||
case "06":{
|
}
|
||||||
return time.June, nil
|
if (monthString == "07"){
|
||||||
}
|
return time.July, nil
|
||||||
case "07":{
|
}
|
||||||
return time.July, nil
|
if (monthString == "08"){
|
||||||
}
|
return time.August, nil
|
||||||
case "08":{
|
}
|
||||||
return time.August, nil
|
if (monthString == "09"){
|
||||||
}
|
return time.September, nil
|
||||||
case "09":{
|
}
|
||||||
return time.September, nil
|
if (monthString == "10"){
|
||||||
}
|
return time.October, nil
|
||||||
case "10":{
|
}
|
||||||
return time.October, nil
|
if (monthString == "11"){
|
||||||
}
|
return time.November, nil
|
||||||
case "11":{
|
}
|
||||||
return time.November, nil
|
if (monthString == "12"){
|
||||||
}
|
return time.December, nil
|
||||||
case "12":{
|
|
||||||
return time.December, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return time.January, errors.New("Malformed AncestryDNA genome file: Invalid month: " + monthString)
|
return time.January, errors.New("Malformed AncestryDNA genome file: Invalid month: " + monthString)
|
||||||
}
|
}
|
||||||
|
@ -441,22 +438,15 @@ func ReadRawGenomeFile(fileReader io.Reader) (string, int, int64, int64, bool, m
|
||||||
snpIdentifier := rowSlice[0]
|
snpIdentifier := rowSlice[0]
|
||||||
snpValueRaw := rowSlice[3]
|
snpValueRaw := rowSlice[3]
|
||||||
|
|
||||||
if (len(snpValueRaw) < 2){
|
if (snpValueRaw[0] != byte('-')){
|
||||||
return "", 0, 0, 0, false, nil, errors.New("Malformed 23andMe genome data: Invalid SNP row snp value: " + fileLineString)
|
// Locus value is not "--"
|
||||||
|
// Locus value exists
|
||||||
|
numberOfLoci += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snpValueRaw[0] == '-'){
|
|
||||||
// Locus value is "--"
|
|
||||||
// Locus value does not exist
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
numberOfLoci += 1
|
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: rsID found
|
// -bool: rsID found
|
||||||
// -int64: rsID value
|
// -int64: rsID value
|
||||||
// -error
|
|
||||||
getRSIDIdentifier := func()(bool, int64, error){
|
getRSIDIdentifier := func()(bool, int64, error){
|
||||||
|
|
||||||
isRSID, rsidInt64 := readRSIDString(snpIdentifier)
|
isRSID, rsidInt64 := readRSIDString(snpIdentifier)
|
||||||
|
@ -491,50 +481,75 @@ func ReadRawGenomeFile(fileReader io.Reader) (string, int, int64, int64, bool, m
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
getLocusBasesList := func()([]rune, error){
|
// This will return either a base pair or a single base
|
||||||
|
// Base pair can be "--"
|
||||||
|
getLocusValueString := func()(string, error){
|
||||||
|
|
||||||
locusBasesList := make([]rune, 0)
|
// This value has a control character suffix
|
||||||
|
// Final index is always a control character
|
||||||
|
// We remove the control character suffix
|
||||||
|
|
||||||
finalIndex := len(snpValueRaw) - 1
|
if (len(snpValueRaw) == 2){
|
||||||
|
|
||||||
for index, character := range snpValueRaw{
|
singleBase := string(snpValueRaw[0])
|
||||||
|
return singleBase, nil
|
||||||
baseIsValid := verifyBase(string(character))
|
|
||||||
if (baseIsValid == false){
|
|
||||||
|
|
||||||
if (index == finalIndex){
|
|
||||||
// The final index of snpValueRaw is sometimes a control character
|
|
||||||
|
|
||||||
return locusBasesList, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("Malformed 23andMe genome file: Invalid SNP base: " + string(character))
|
|
||||||
}
|
|
||||||
|
|
||||||
locusBasesList = append(locusBasesList, character)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return locusBasesList, nil
|
if (len(snpValueRaw) == 3){
|
||||||
|
|
||||||
|
basePair := snpValueRaw[:2]
|
||||||
|
return basePair, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("Malformed 23andMe genome file: Invalid SNP value: " + snpValueRaw)
|
||||||
}
|
}
|
||||||
|
|
||||||
locusBasesList, err := getLocusBasesList()
|
basesString, err := getLocusValueString()
|
||||||
if (err != nil){ return "", 0, 0, 0, false, nil, err }
|
if (err != nil) { return "", 0, 0, 0, false, nil, err }
|
||||||
|
|
||||||
allele1 := string(locusBasesList[0])
|
if (basesString == "--"){
|
||||||
|
// No data exists, skip.
|
||||||
locusValueObject := RawGenomeLocusValue{
|
continue
|
||||||
Allele1: allele1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(locusBasesList) > 1){
|
for _, baseRune := range basesString{
|
||||||
|
|
||||||
allele2 := string(locusBasesList[1])
|
baseIsValid := verifyBase(string(baseRune))
|
||||||
|
if (baseIsValid == false){
|
||||||
locusValueObject.Allele2Exists = true
|
return "", 0, 0, 0, false, nil, errors.New("Malformed 23andMe genome file: Invalid SNP base: " + string(baseRune))
|
||||||
locusValueObject.Allele2 = allele2
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
genomeMap[locusRSID] = locusValueObject
|
getMapEntryValue := func()RawGenomeLocusValue{
|
||||||
|
|
||||||
|
if (len(basesString) == 1){
|
||||||
|
|
||||||
|
locusValueObject := RawGenomeLocusValue{
|
||||||
|
|
||||||
|
Allele1: basesString,
|
||||||
|
Allele2Exists: false,
|
||||||
|
Allele2: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
return locusValueObject
|
||||||
|
}
|
||||||
|
|
||||||
|
baseAString := string(basesString[0])
|
||||||
|
baseBString := string(basesString[1])
|
||||||
|
|
||||||
|
locusValueObject := RawGenomeLocusValue{
|
||||||
|
|
||||||
|
Allele1: baseAString,
|
||||||
|
Allele2Exists: true,
|
||||||
|
Allele2: baseBString,
|
||||||
|
}
|
||||||
|
|
||||||
|
return locusValueObject
|
||||||
|
}
|
||||||
|
|
||||||
|
mapEntryValue := getMapEntryValue()
|
||||||
|
|
||||||
|
genomeMap[locusRSID] = mapEntryValue
|
||||||
}
|
}
|
||||||
|
|
||||||
return "23andMe", 1, fileTimeUnix, numberOfLoci, false, genomeMap, nil
|
return "23andMe", 1, fileTimeUnix, numberOfLoci, false, genomeMap, nil
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -769,14 +769,6 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
||||||
return false, profileVersion, "", nil
|
return false, profileVersion, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myGeneticAnalysisObject)
|
|
||||||
if (err != nil) { return false, 0, "", err }
|
|
||||||
|
|
||||||
myGenomeLocusValuesMap, exists := myGenomesMap[myGenomeIdentifier]
|
|
||||||
if (exists == false){
|
|
||||||
return false, 0, "", errors.New("GetMyChosenMateGeneticAnalysis returning genetic analysis which has GenomesMap which is missing my genome identifier.")
|
|
||||||
}
|
|
||||||
|
|
||||||
polygenicDiseaseObjectsList, err := polygenicDiseases.GetPolygenicDiseaseObjectsList()
|
polygenicDiseaseObjectsList, err := polygenicDiseases.GetPolygenicDiseaseObjectsList()
|
||||||
if (err != nil) { return false, 0, "", err }
|
if (err != nil) { return false, 0, "", err }
|
||||||
|
|
||||||
|
@ -788,8 +780,12 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
||||||
|
|
||||||
for _, diseaseObject := range polygenicDiseaseObjectsList{
|
for _, diseaseObject := range polygenicDiseaseObjectsList{
|
||||||
|
|
||||||
|
diseaseName := diseaseObject.DiseaseName
|
||||||
diseaseLociList := diseaseObject.LociList
|
diseaseLociList := diseaseObject.LociList
|
||||||
|
|
||||||
|
_, _, _, myDiseaseLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myGeneticAnalysisObject, diseaseName, myGenomeIdentifier)
|
||||||
|
if (err != nil) { return false, 0, "", err }
|
||||||
|
|
||||||
// Map Structure: rsID -> Locus Value
|
// Map Structure: rsID -> Locus Value
|
||||||
userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||||
|
|
||||||
|
@ -822,7 +818,7 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
||||||
userDiseaseLocusValuesMap[locusRSID] = newLocusValue
|
userDiseaseLocusValuesMap[locusRSID] = newLocusValue
|
||||||
}
|
}
|
||||||
|
|
||||||
anyLocusValuesTested, offspringAverageRiskScore, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo_Fast(diseaseLociList, myGenomeLocusValuesMap, userDiseaseLocusValuesMap)
|
anyLocusValuesTested, offspringAverageRiskScore, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo_Fast(diseaseLociList, myDiseaseLocusValuesMap, userDiseaseLocusValuesMap)
|
||||||
if (err != nil) { return false, 0, "", err }
|
if (err != nil) { return false, 0, "", err }
|
||||||
if (anyLocusValuesTested == false){
|
if (anyLocusValuesTested == false){
|
||||||
continue
|
continue
|
||||||
|
@ -1403,14 +1399,9 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
||||||
|
|
||||||
traitName := getTraitName()
|
traitName := getTraitName()
|
||||||
|
|
||||||
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myGeneticAnalysisObject)
|
myTraitLociMap, _, _, _, _, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(myGeneticAnalysisObject, traitName, myGenomeIdentifier)
|
||||||
if (err != nil) { return false, 0, "", err }
|
if (err != nil) { return false, 0, "", err }
|
||||||
|
|
||||||
myGenomeLocusValuesMap, exists := myGenomesMap[myGenomeIdentifier]
|
|
||||||
if (exists == false){
|
|
||||||
return false, 0, "", errors.New("GetMyChosenMateGeneticAnalysis returning genetic analysis with a GenomesMap which is missing my genome identifier.")
|
|
||||||
}
|
|
||||||
|
|
||||||
traitObject, err := traits.GetTraitObject(traitName)
|
traitObject, err := traits.GetTraitObject(traitName)
|
||||||
if (err != nil) { return false, 0, "", err }
|
if (err != nil) { return false, 0, "", err }
|
||||||
|
|
||||||
|
@ -1424,7 +1415,7 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
||||||
|
|
||||||
for _, rsID := range traitLociList{
|
for _, rsID := range traitLociList{
|
||||||
|
|
||||||
myLocusValue, myLocusValueExists := myGenomeLocusValuesMap[rsID]
|
myLocusValue, myLocusValueExists := myTraitLociMap[rsID]
|
||||||
if (myLocusValueExists == false){
|
if (myLocusValueExists == false){
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,14 +150,6 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{
|
||||||
return errors.New("UpdateMyExportedProfile called when profile genetic analysis is not ready.")
|
return errors.New("UpdateMyExportedProfile called when profile genetic analysis is not ready.")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myGeneticAnalysisObject)
|
|
||||||
if (err != nil) { return err }
|
|
||||||
|
|
||||||
myGenomeLocusValuesMap, exists := myGenomesMap[genomeIdentifierToShare]
|
|
||||||
if (exists == false){
|
|
||||||
return errors.New("GetMyChosenMateGeneticAnalysis returning genetic analysis which has GenomesMap which is missing my genome identifier.")
|
|
||||||
}
|
|
||||||
|
|
||||||
monogenicDiseaseNamesList, err := monogenicDiseases.GetMonogenicDiseaseNamesList()
|
monogenicDiseaseNamesList, err := monogenicDiseases.GetMonogenicDiseaseNamesList()
|
||||||
if (err != nil) { return err }
|
if (err != nil) { return err }
|
||||||
|
|
||||||
|
@ -213,24 +205,19 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
lociList := diseaseObject.LociList
|
_, _, _, myDiseaseLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myGeneticAnalysisObject, diseaseName, genomeIdentifierToShare)
|
||||||
|
if (err != nil) { return err }
|
||||||
|
|
||||||
for _, locusObject := range lociList{
|
for rsID, locusValueObject := range myDiseaseLocusValuesMap{
|
||||||
|
|
||||||
locusRSID := locusObject.LocusRSID
|
rsIDString := helpers.ConvertInt64ToString(rsID)
|
||||||
|
|
||||||
locusValueObject, exists := myGenomeLocusValuesMap[locusRSID]
|
locusBase1 := locusValueObject.Base1Value
|
||||||
if (exists == true){
|
locusBase2 := locusValueObject.Base2Value
|
||||||
|
|
||||||
rsIDString := helpers.ConvertInt64ToString(locusRSID)
|
basePairValue := locusBase1 + ";" + locusBase2
|
||||||
|
|
||||||
locusBase1 := locusValueObject.Base1Value
|
profileMap["LocusValue_rs" + rsIDString] = basePairValue
|
||||||
locusBase2 := locusValueObject.Base2Value
|
|
||||||
|
|
||||||
basePairValue := locusBase1 + ";" + locusBase2
|
|
||||||
|
|
||||||
profileMap["LocusValue_rs" + rsIDString] = basePairValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,22 +239,19 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
lociList := traitObject.LociList
|
myTraitLocusValuesMap, _, _, _, _, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(myGeneticAnalysisObject, traitName, genomeIdentifierToShare)
|
||||||
|
if (err != nil) { return err }
|
||||||
|
|
||||||
for _, rsID := range lociList{
|
for rsID, locusValueObject := range myTraitLocusValuesMap{
|
||||||
|
|
||||||
locusValueObject, exists := myGenomeLocusValuesMap[rsID]
|
rsIDString := helpers.ConvertInt64ToString(rsID)
|
||||||
if (exists == true){
|
|
||||||
|
|
||||||
rsIDString := helpers.ConvertInt64ToString(rsID)
|
locusBase1 := locusValueObject.Base1Value
|
||||||
|
locusBase2 := locusValueObject.Base2Value
|
||||||
|
|
||||||
locusBase1 := locusValueObject.Base1Value
|
basePairValue := locusBase1 + ";" + locusBase2
|
||||||
locusBase2 := locusValueObject.Base2Value
|
|
||||||
|
|
||||||
basePairValue := locusBase1 + ";" + locusBase2
|
profileMap["LocusValue_rs" + rsIDString] = basePairValue
|
||||||
|
|
||||||
profileMap["LocusValue_rs" + rsIDString] = basePairValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
// geneticPredictionModels contains genetic prediction neural network models for predicting genetic traits
|
|
||||||
// These are .gob encoded files of []float32 weights
|
|
||||||
// This package also contains prediction accuracy information for each model
|
|
||||||
// Prediction accuracy models describe information about how accurate the predictions made by the models are
|
|
||||||
// All of the files in this package are created by the Create Genetic Models utility.
|
|
||||||
// This utility is located in /utilities/createGeneticModels/createGeneticModels.go
|
|
||||||
|
|
||||||
package geneticPredictionModels
|
|
||||||
|
|
||||||
import _ "embed"
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
//Outputs:
|
|
||||||
// -bool: Model exists
|
|
||||||
// -[]byte
|
|
||||||
func GetGeneticPredictionModelBytes(traitName string)(bool, []byte){
|
|
||||||
|
|
||||||
switch traitName{
|
|
||||||
|
|
||||||
case "Eye Color":{
|
|
||||||
return true, predictionModel_EyeColor
|
|
||||||
}
|
|
||||||
case "Lactose Tolerance":{
|
|
||||||
return true, predictionModel_LactoseTolerance
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:embed predictionModels/EyeColorModel.gob
|
|
||||||
var predictionModel_EyeColor []byte
|
|
||||||
|
|
||||||
//go:embed predictionModels/LactoseToleranceModel.gob
|
|
||||||
var predictionModel_LactoseTolerance []byte
|
|
||||||
|
|
||||||
// The files returned by this function are .gob encoded geneticPrediction.TraitPredictionAccuracyInfoMap objects
|
|
||||||
func GetPredictionModelTraitAccuracyInfoBytes(traitName string)([]byte, error){
|
|
||||||
|
|
||||||
switch traitName{
|
|
||||||
case "Eye Color":{
|
|
||||||
return predictionAccuracy_EyeColor, nil
|
|
||||||
}
|
|
||||||
case "Lactose Tolerance":{
|
|
||||||
return predictionAccuracy_LactoseTolerance, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("GetPredictionModelTraitAccuracyInfoFile called with unknown traitName: " + traitName)
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:embed predictionModelAccuracies/EyeColorModelAccuracy.gob
|
|
||||||
var predictionAccuracy_EyeColor []byte
|
|
||||||
|
|
||||||
//go:embed predictionModelAccuracies/LactoseToleranceModelAccuracy.gob
|
|
||||||
var predictionAccuracy_LactoseTolerance []byte
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
package geneticPredictionModels_test
|
|
||||||
|
|
||||||
import "seekia/resources/geneticPredictionModels"
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
import "seekia/internal/genetics/geneticPrediction"
|
|
||||||
|
|
||||||
|
|
||||||
func TestGeneticPredictionModels(t *testing.T){
|
|
||||||
|
|
||||||
traitNamesList := []string{"Eye Color", "Lactose Tolerance"}
|
|
||||||
|
|
||||||
for _, traitName := range traitNamesList{
|
|
||||||
|
|
||||||
modelFound, modelBytes := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)
|
|
||||||
if (modelFound == false){
|
|
||||||
t.Fatalf("GetGeneticPredictionModelBytes failed to find model for trait: " + traitName)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := geneticPrediction.DecodeBytesToNeuralNetworkObject(modelBytes)
|
|
||||||
if (err != nil){
|
|
||||||
t.Fatalf("DecodeBytesToNeuralNetworkObject failed: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func TestGeneticPredictionModelAccuracies(t *testing.T){
|
|
||||||
|
|
||||||
traitNamesList := []string{"Eye Color", "Lactose Tolerance"}
|
|
||||||
|
|
||||||
for _, traitName := range traitNamesList{
|
|
||||||
|
|
||||||
accuracyInfoBytes, err := geneticPredictionModels.GetPredictionModelTraitAccuracyInfoBytes(traitName)
|
|
||||||
if (err != nil){
|
|
||||||
t.Fatalf("GetGeneticPredictionModelBytes failed: " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = geneticPrediction.DecodeBytesToTraitPredictionAccuracyInfoMap(accuracyInfoBytes)
|
|
||||||
if (err != nil){
|
|
||||||
t.Fatalf("DecodeBytesToTraitPredictionAccuracyInfoMap failed: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -309,13 +309,10 @@ func TestGeneticReferences(t *testing.T){
|
||||||
|
|
||||||
traitName := traitObject.TraitName
|
traitName := traitObject.TraitName
|
||||||
traitDescription := traitObject.TraitDescription
|
traitDescription := traitObject.TraitDescription
|
||||||
traitDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
|
||||||
traitLocusReferencesMap := traitObject.LocusReferencesMap
|
|
||||||
traitLociList := traitObject.LociList
|
traitLociList := traitObject.LociList
|
||||||
traitLociList_Rules := traitObject.LociList_Rules
|
|
||||||
traitRulesList := traitObject.RulesList
|
traitRulesList := traitObject.RulesList
|
||||||
traitOutcomesList := traitObject.OutcomesList
|
traitOutcomesList := traitObject.OutcomesList
|
||||||
traitReferencesMap := traitObject.ReferencesMap
|
traitReferencesMap := traitObject.References
|
||||||
|
|
||||||
if (traitName == ""){
|
if (traitName == ""){
|
||||||
t.Fatalf("Empty trait name exists.")
|
t.Fatalf("Empty trait name exists.")
|
||||||
|
@ -329,9 +326,6 @@ func TestGeneticReferences(t *testing.T){
|
||||||
if (traitDescription == ""){
|
if (traitDescription == ""){
|
||||||
t.Fatalf("Empty trait description exists for trait: " + traitName)
|
t.Fatalf("Empty trait description exists for trait: " + traitName)
|
||||||
}
|
}
|
||||||
if (traitDiscreteOrNumeric != "Discrete" && traitDiscreteOrNumeric != "Numeric"){
|
|
||||||
t.Fatalf("Invalid DiscreteOrNumeric for trait: " + traitDiscreteOrNumeric)
|
|
||||||
}
|
|
||||||
if (len(traitOutcomesList) != 0){
|
if (len(traitOutcomesList) != 0){
|
||||||
|
|
||||||
if (len(traitOutcomesList) < 2){
|
if (len(traitOutcomesList) < 2){
|
||||||
|
@ -355,41 +349,18 @@ func TestGeneticReferences(t *testing.T){
|
||||||
t.Fatalf("Invalid references exist for trait: " + traitName)
|
t.Fatalf("Invalid references exist for trait: " + traitName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(traitLocusReferencesMap) == 0){
|
|
||||||
t.Fatalf("No trait locus references exist for trait: " + traitName)
|
|
||||||
}
|
|
||||||
|
|
||||||
for locusRSID, locusReferences := range traitLocusReferencesMap{
|
|
||||||
|
|
||||||
allRSIDsMap[locusRSID] = struct{}{}
|
|
||||||
|
|
||||||
if (locusReferences == nil){
|
|
||||||
t.Fatalf("A trait locus has no references map: " + traitName)
|
|
||||||
}
|
|
||||||
if (len(locusReferences) == 0){
|
|
||||||
t.Fatalf("A trait locus has no references: " + traitName)
|
|
||||||
}
|
|
||||||
|
|
||||||
locusExists := slices.Contains(traitLociList, locusRSID)
|
|
||||||
if (locusExists == false){
|
|
||||||
t.Fatalf("traitLocusReferencesMap contains rsID which does not exist in traitLociList")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len(traitLociList) == 0){
|
if (len(traitLociList) == 0){
|
||||||
t.Fatalf("No trait loci exist for trait: " + traitName)
|
t.Fatalf("No trait loci exist for trait: " + traitName)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rsID := range traitLociList{
|
for _, locusRSID := range traitLociList{
|
||||||
allRSIDsMap[rsID] = struct{}{}
|
allRSIDsMap[locusRSID] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rsID := range traitLociList_Rules{
|
containsDuplicates, duplicateLocus := helpers.CheckIfListContainsDuplicates(traitLociList)
|
||||||
|
if (containsDuplicates == true){
|
||||||
locusExists := slices.Contains(traitLociList, rsID)
|
duplicateLocusString := helpers.ConvertInt64ToString(duplicateLocus)
|
||||||
if (locusExists == false){
|
t.Fatalf("traitLociList contains duplicates for trait: " + traitName + ". RSID: " + duplicateLocusString)
|
||||||
t.Fatalf("traitLociList_Rules contains locus not present in traitLociList")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(traitRulesList) == 0){
|
if (len(traitRulesList) == 0){
|
||||||
|
@ -402,7 +373,7 @@ func TestGeneticReferences(t *testing.T){
|
||||||
ruleIdentifier := ruleObject.RuleIdentifier
|
ruleIdentifier := ruleObject.RuleIdentifier
|
||||||
ruleLociList := ruleObject.LociList
|
ruleLociList := ruleObject.LociList
|
||||||
ruleOutcomePointsMap := ruleObject.OutcomePointsMap
|
ruleOutcomePointsMap := ruleObject.OutcomePointsMap
|
||||||
ruleReferencesMap := ruleObject.ReferencesMap
|
ruleReferences := ruleObject.References
|
||||||
|
|
||||||
identifierIsValid := verifyIdentifier(ruleIdentifier)
|
identifierIsValid := verifyIdentifier(ruleIdentifier)
|
||||||
if (identifierIsValid == false){
|
if (identifierIsValid == false){
|
||||||
|
@ -442,21 +413,11 @@ func TestGeneticReferences(t *testing.T){
|
||||||
t.Fatalf("Trait rule Locus identifier is invalid: " + locusIdentifier)
|
t.Fatalf("Trait rule Locus identifier is invalid: " + locusIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, mapContainsItem := traitLocusReferencesMap[locusRSID]
|
listContainsItem := slices.Contains(traitLociList, locusRSID)
|
||||||
if (mapContainsItem == false){
|
if (listContainsItem == false){
|
||||||
t.Fatalf("Rule locus contains rsid which is not contained within LocusReferencesMap.")
|
|
||||||
}
|
|
||||||
|
|
||||||
sliceContainsItem := slices.Contains(traitLociList, locusRSID)
|
|
||||||
if (sliceContainsItem == false){
|
|
||||||
t.Fatalf("Rule locus contains rsid which is not contained within traitLociList.")
|
t.Fatalf("Rule locus contains rsid which is not contained within traitLociList.")
|
||||||
}
|
}
|
||||||
|
|
||||||
sliceContainsItem = slices.Contains(traitLociList_Rules, locusRSID)
|
|
||||||
if (sliceContainsItem == false){
|
|
||||||
t.Fatalf("Rule locus contains rsid which is not contained within traitLociList_Rules.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len(locusBasePairsList) == 0){
|
if (len(locusBasePairsList) == 0){
|
||||||
t.Fatalf("Trait rule locus base pairs list is empty: " + locusIdentifier)
|
t.Fatalf("Trait rule locus base pairs list is empty: " + locusIdentifier)
|
||||||
}
|
}
|
||||||
|
@ -469,7 +430,7 @@ func TestGeneticReferences(t *testing.T){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
referencesAreValid := verifyReferencesMap(ruleReferencesMap)
|
referencesAreValid := verifyReferencesMap(ruleReferences)
|
||||||
if (referencesAreValid == false){
|
if (referencesAreValid == false){
|
||||||
t.Fatalf("Invalid references map for trait rule locus: " + ruleIdentifier)
|
t.Fatalf("Invalid references map for trait rule locus: " + ruleIdentifier)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,9 @@ package polygenicDiseases
|
||||||
// Polygenic disease probabilities are less accurate, because individual base pair changes only cause comparatively small changes in the disease risk.
|
// Polygenic disease probabilities are less accurate, because individual base pair changes only cause comparatively small changes in the disease risk.
|
||||||
// Polygenic diseases are also more influenced by environmental factors, further decreasing risk accuracy.
|
// Polygenic diseases are also more influenced by environmental factors, further decreasing risk accuracy.
|
||||||
|
|
||||||
//TODO: Eventually we want to use neural networks for polygenic disease prediction.
|
//TODO: Eventually we want to use neural networks for both polygenic disease and trait prediction.
|
||||||
// This package is currently a less accurate solution until we get access to the necessary training data.
|
// This package is currently a temporary, less accurate solution until we get access to the necessary training data.
|
||||||
|
// It may still be worth keeping this method in place for polygenic diseases and using neural networks in tandem.
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
package traits
|
package traits
|
||||||
|
|
||||||
import "seekia/internal/helpers"
|
|
||||||
|
|
||||||
import "maps"
|
|
||||||
|
|
||||||
func getEyeColorTraitObject()Trait{
|
func getEyeColorTraitObject()Trait{
|
||||||
|
|
||||||
// Map Structure: rsID -> References Map
|
eyeColorLociList := []int64{
|
||||||
locusReferencesMap := make(map[int64]map[string]string)
|
|
||||||
|
|
||||||
referencesMap_List1 := make(map[string]string)
|
//TODO: Add more SNPs.
|
||||||
referencesMap_List1["SNPedia.com - Eye Color"] = "https://www.snpedia.com/index.php/Eye_color"
|
|
||||||
|
|
||||||
// These SNPs are taken from https://www.snpedia.com/index.php/Eye_color
|
// These SNPs are taken from https://www.snpedia.com/index.php/Eye_color
|
||||||
|
|
||||||
lociList_1 := []int64{
|
|
||||||
2733832,
|
2733832,
|
||||||
1800401,
|
1800401,
|
||||||
1800407,
|
1800407,
|
||||||
|
@ -57,39 +51,16 @@ func getEyeColorTraitObject()Trait{
|
||||||
989869,
|
989869,
|
||||||
4778138,
|
4778138,
|
||||||
12906280,
|
12906280,
|
||||||
}
|
|
||||||
|
|
||||||
for _, rsID := range lociList_1{
|
// These SNPs are taken from https://pubmed.ncbi.nlm.nih.gov/20546537/
|
||||||
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List1)
|
|
||||||
}
|
|
||||||
|
|
||||||
referencesMap_List2 := make(map[string]string)
|
|
||||||
referencesMap_List2["Genome-wide association studies of pigmentation and skin cancer: a review and meta-analysis"] = "https://pubmed.ncbi.nlm.nih.gov/20546537/"
|
|
||||||
|
|
||||||
// These SNPs are taken from https://pubmed.ncbi.nlm.nih.gov/20546537/
|
|
||||||
|
|
||||||
lociList_2 := []int64{
|
|
||||||
12203592,
|
12203592,
|
||||||
1408799,
|
1408799,
|
||||||
1126809,
|
1126809,
|
||||||
12896399,
|
12896399,
|
||||||
7495174,
|
7495174,
|
||||||
1667394,
|
1667394,
|
||||||
}
|
|
||||||
|
|
||||||
for _, rsID := range lociList_2{
|
// These SNPs are taken from https://pubmed.ncbi.nlm.nih.gov/33692100/
|
||||||
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List2)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
referencesMap_List3 := make(map[string]string)
|
|
||||||
referencesMap_List3["Genome-wide association study in almost 195,000 individuals identifies 50 previously unidentified genetic loci for eye color."] = "https://pubmed.ncbi.nlm.nih.gov/33692100/"
|
|
||||||
|
|
||||||
// These SNPs are taken from https://pubmed.ncbi.nlm.nih.gov/33692100/
|
|
||||||
|
|
||||||
lociList_3 := []int64{
|
|
||||||
6693258,
|
6693258,
|
||||||
351385,
|
351385,
|
||||||
2385028,
|
2385028,
|
||||||
|
@ -144,12 +115,6 @@ func getEyeColorTraitObject()Trait{
|
||||||
// 5957354,
|
// 5957354,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rsID := range lociList_3{
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List3)
|
|
||||||
}
|
|
||||||
|
|
||||||
eyeColorLociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
|
||||||
|
|
||||||
referencesMap := make(map[string]string)
|
referencesMap := make(map[string]string)
|
||||||
referencesMap["SNPedia.com - Eye Color"] = "https://www.snpedia.com/index.php/Eye_color"
|
referencesMap["SNPedia.com - Eye Color"] = "https://www.snpedia.com/index.php/Eye_color"
|
||||||
referencesMap["Genome-wide association studies of pigmentation and skin cancer: a review and meta-analysis"] = "https://pubmed.ncbi.nlm.nih.gov/20546537/"
|
referencesMap["Genome-wide association studies of pigmentation and skin cancer: a review and meta-analysis"] = "https://pubmed.ncbi.nlm.nih.gov/20546537/"
|
||||||
|
@ -158,13 +123,10 @@ func getEyeColorTraitObject()Trait{
|
||||||
eyeColorObject := Trait{
|
eyeColorObject := Trait{
|
||||||
TraitName: "Eye Color",
|
TraitName: "Eye Color",
|
||||||
TraitDescription: "The color of a person's eyes.",
|
TraitDescription: "The color of a person's eyes.",
|
||||||
DiscreteOrNumeric: "Discrete",
|
|
||||||
LocusReferencesMap: locusReferencesMap,
|
|
||||||
LociList: eyeColorLociList,
|
LociList: eyeColorLociList,
|
||||||
LociList_Rules: []int64{},
|
|
||||||
RulesList: []TraitRule{},
|
RulesList: []TraitRule{},
|
||||||
OutcomesList: []string{"Blue", "Green", "Hazel", "Brown"},
|
OutcomesList: []string{"Blue", "Green", "Hazel", "Brown"},
|
||||||
ReferencesMap: referencesMap,
|
References: referencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
return eyeColorObject
|
return eyeColorObject
|
||||||
|
|
|
@ -1,19 +1,9 @@
|
||||||
package traits
|
package traits
|
||||||
|
|
||||||
import "seekia/internal/helpers"
|
|
||||||
|
|
||||||
import "maps"
|
|
||||||
|
|
||||||
func getFacialStructureTraitObject()Trait{
|
func getFacialStructureTraitObject()Trait{
|
||||||
|
|
||||||
// Map Structure: rsID -> References Map
|
facialStructureLociList := []int64{
|
||||||
locusReferencesMap := make(map[int64]map[string]string)
|
|
||||||
|
|
||||||
referencesMap_List1 := make(map[string]string)
|
|
||||||
referencesMap_List1["SNPedia.com - Appearance"] = "https://www.snpedia.com/index.php/Appearance"
|
|
||||||
referencesMap_List1["A Genome-Wide Association Study Identifies Five Loci Influencing Facial Morphology in Europeans"] = "https://journals.plos.org/plosgenetics/article?id=10.1371/journal.pgen.1002932"
|
|
||||||
|
|
||||||
lociList_1 := []int64{
|
|
||||||
|
|
||||||
//TODO: Add more SNPs.
|
//TODO: Add more SNPs.
|
||||||
|
|
||||||
|
@ -122,13 +112,6 @@ func getFacialStructureTraitObject()Trait{
|
||||||
397723,
|
397723,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rsID := range lociList_1{
|
|
||||||
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List1)
|
|
||||||
}
|
|
||||||
|
|
||||||
facialStructureLociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
|
||||||
|
|
||||||
referencesMap := make(map[string]string)
|
referencesMap := make(map[string]string)
|
||||||
referencesMap["SNPedia.com - Appearance"] = "https://www.snpedia.com/index.php/Appearance"
|
referencesMap["SNPedia.com - Appearance"] = "https://www.snpedia.com/index.php/Appearance"
|
||||||
referencesMap["A Genome-Wide Association Study Identifies Five Loci Influencing Facial Morphology in Europeans"] = "https://journals.plos.org/plosgenetics/article?id=10.1371/journal.pgen.1002932"
|
referencesMap["A Genome-Wide Association Study Identifies Five Loci Influencing Facial Morphology in Europeans"] = "https://journals.plos.org/plosgenetics/article?id=10.1371/journal.pgen.1002932"
|
||||||
|
@ -136,13 +119,10 @@ func getFacialStructureTraitObject()Trait{
|
||||||
facialStructureObject := Trait{
|
facialStructureObject := Trait{
|
||||||
TraitName: "Facial Structure",
|
TraitName: "Facial Structure",
|
||||||
TraitDescription: "The structure of a person's face.",
|
TraitDescription: "The structure of a person's face.",
|
||||||
DiscreteOrNumeric: "Discrete",
|
|
||||||
LocusReferencesMap: locusReferencesMap,
|
|
||||||
LociList: facialStructureLociList,
|
LociList: facialStructureLociList,
|
||||||
LociList_Rules: []int64{},
|
|
||||||
RulesList: []TraitRule{},
|
RulesList: []TraitRule{},
|
||||||
OutcomesList: []string{},
|
OutcomesList: []string{},
|
||||||
ReferencesMap: referencesMap,
|
References: referencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
return facialStructureObject
|
return facialStructureObject
|
||||||
|
|
|
@ -3,20 +3,10 @@ package traits
|
||||||
// Hair color is influenced by thousands of genes
|
// Hair color is influenced by thousands of genes
|
||||||
// We only have a few listed here
|
// We only have a few listed here
|
||||||
|
|
||||||
import "seekia/internal/helpers"
|
|
||||||
|
|
||||||
import "maps"
|
|
||||||
|
|
||||||
func getHairColorTraitObject()Trait{
|
func getHairColorTraitObject()Trait{
|
||||||
|
|
||||||
// Map Structure: rsID -> References Map
|
hairColorLociList := []int64{
|
||||||
locusReferencesMap := make(map[int64]map[string]string)
|
|
||||||
|
|
||||||
referencesMap_List1 := make(map[string]string)
|
|
||||||
referencesMap_List1["SNPedia.com - Appearance"] = "https://www.snpedia.com/index.php/Appearance"
|
|
||||||
referencesMap_List1["Genome-wide association studies of pigmentation and skin cancer: a review and meta-analysis"] = "https://pubmed.ncbi.nlm.nih.gov/20546537/"
|
|
||||||
|
|
||||||
lociList_1 := []int64{
|
|
||||||
|
|
||||||
//These loci were taken from https://pubmed.ncbi.nlm.nih.gov/20546537/
|
//These loci were taken from https://pubmed.ncbi.nlm.nih.gov/20546537/
|
||||||
|
|
||||||
|
@ -42,13 +32,6 @@ func getHairColorTraitObject()Trait{
|
||||||
1805008,
|
1805008,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rsID := range lociList_1{
|
|
||||||
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List1)
|
|
||||||
}
|
|
||||||
|
|
||||||
hairColorLociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
|
||||||
|
|
||||||
referencesMap := make(map[string]string)
|
referencesMap := make(map[string]string)
|
||||||
referencesMap["SNPedia.com - Appearance"] = "https://www.snpedia.com/index.php/Appearance"
|
referencesMap["SNPedia.com - Appearance"] = "https://www.snpedia.com/index.php/Appearance"
|
||||||
referencesMap["Genome-wide association studies of pigmentation and skin cancer: a review and meta-analysis"] = "https://pubmed.ncbi.nlm.nih.gov/20546537/"
|
referencesMap["Genome-wide association studies of pigmentation and skin cancer: a review and meta-analysis"] = "https://pubmed.ncbi.nlm.nih.gov/20546537/"
|
||||||
|
@ -56,13 +39,10 @@ func getHairColorTraitObject()Trait{
|
||||||
hairColorObject := Trait{
|
hairColorObject := Trait{
|
||||||
TraitName: "Hair Color",
|
TraitName: "Hair Color",
|
||||||
TraitDescription: "The color of a person's hair.",
|
TraitDescription: "The color of a person's hair.",
|
||||||
DiscreteOrNumeric: "Discrete",
|
|
||||||
LocusReferencesMap: locusReferencesMap,
|
|
||||||
LociList: hairColorLociList,
|
LociList: hairColorLociList,
|
||||||
LociList_Rules: []int64{},
|
|
||||||
RulesList: []TraitRule{},
|
RulesList: []TraitRule{},
|
||||||
OutcomesList: []string{},
|
OutcomesList: []string{},
|
||||||
ReferencesMap: referencesMap,
|
References: referencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
return hairColorObject
|
return hairColorObject
|
||||||
|
|
|
@ -1,53 +1,11 @@
|
||||||
package traits
|
package traits
|
||||||
|
|
||||||
import "seekia/internal/helpers"
|
|
||||||
|
|
||||||
import "maps"
|
|
||||||
|
|
||||||
func getHairTextureTraitObject()Trait{
|
func getHairTextureTraitObject()Trait{
|
||||||
|
|
||||||
// Map Structure: rsID -> References Map
|
rule1_ReferencesMap := make(map[string]string)
|
||||||
locusReferencesMap := make(map[int64]map[string]string)
|
rule1_ReferencesMap["SNPedia.com - rs7349332"] = "https://www.snpedia.com/index.php/Rs7349332"
|
||||||
|
|
||||||
referencesMap_List1 := make(map[string]string)
|
|
||||||
referencesMap_List1["SNPedia.com - rs7349332"] = "https://www.snpedia.com/index.php/Rs7349332"
|
|
||||||
|
|
||||||
lociList_1 := []int64{
|
|
||||||
7349332,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rsID := range lociList_1{
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List1)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
referencesMap_List2 := make(map[string]string)
|
|
||||||
referencesMap_List2["SNPedia.com - rs11803731"] = "https://www.snpedia.com/index.php/Rs11803731"
|
|
||||||
|
|
||||||
lociList_2 := []int64{
|
|
||||||
11803731,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rsID := range lociList_2{
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List2)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
referencesMap_List3 := make(map[string]string)
|
|
||||||
referencesMap_List3["SNPedia.com - rs17646946"] = "https://www.snpedia.com/index.php/Rs17646946"
|
|
||||||
|
|
||||||
lociList_3 := []int64{
|
|
||||||
17646946,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rsID := range lociList_3{
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List3)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
referencesMap_rs7349332 := make(map[string]string)
|
|
||||||
referencesMap_rs7349332["SNPedia.com - rs7349332"] = "https://www.snpedia.com/index.php/Rs7349332"
|
|
||||||
|
|
||||||
rule1_Locus1Object := RuleLocus{
|
rule1_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
|
@ -64,10 +22,12 @@ func getHairTextureTraitObject()Trait{
|
||||||
RuleIdentifier: "fde405",
|
RuleIdentifier: "fde405",
|
||||||
LociList: rule1_LociList,
|
LociList: rule1_LociList,
|
||||||
OutcomePointsMap: rule1_OutcomePointsMap,
|
OutcomePointsMap: rule1_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs7349332),
|
References: rule1_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Make sure this is true, that a heterozygote has a higher likelihood of curly hair
|
//TODO: Make sure this is true, that a heterozygote has a higher likelihood of curly hair
|
||||||
|
rule2_ReferencesMap := make(map[string]string)
|
||||||
|
rule2_ReferencesMap["SNPedia.com - rs7349332"] = "https://www.snpedia.com/index.php/Rs7349332"
|
||||||
|
|
||||||
rule2_Locus1Object := RuleLocus{
|
rule2_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
|
@ -84,8 +44,11 @@ func getHairTextureTraitObject()Trait{
|
||||||
RuleIdentifier: "6bd1da",
|
RuleIdentifier: "6bd1da",
|
||||||
LociList: rule2_LociList,
|
LociList: rule2_LociList,
|
||||||
OutcomePointsMap: rule2_OutcomePointsMap,
|
OutcomePointsMap: rule2_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs7349332),
|
References: rule2_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule3_ReferencesMap := make(map[string]string)
|
||||||
|
rule3_ReferencesMap["SNPedia.com - rs7349332"] = "https://www.snpedia.com/index.php/Rs7349332"
|
||||||
|
|
||||||
rule3_Locus1Object := RuleLocus{
|
rule3_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
|
@ -102,13 +65,11 @@ func getHairTextureTraitObject()Trait{
|
||||||
RuleIdentifier: "32e377",
|
RuleIdentifier: "32e377",
|
||||||
LociList: rule3_LociList,
|
LociList: rule3_LociList,
|
||||||
OutcomePointsMap: rule3_OutcomePointsMap,
|
OutcomePointsMap: rule3_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs7349332),
|
References: rule3_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule4_ReferencesMap := make(map[string]string)
|
||||||
|
rule4_ReferencesMap["SNPedia.com - rs11803731"] = "https://www.snpedia.com/index.php/Rs11803731"
|
||||||
referencesMap_rs11803731 := make(map[string]string)
|
|
||||||
referencesMap_rs11803731["SNPedia.com - rs11803731"] = "https://www.snpedia.com/index.php/Rs11803731"
|
|
||||||
|
|
||||||
rule4_Locus1Object := RuleLocus{
|
rule4_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
|
@ -125,10 +86,12 @@ func getHairTextureTraitObject()Trait{
|
||||||
RuleIdentifier: "34e6d2",
|
RuleIdentifier: "34e6d2",
|
||||||
LociList: rule4_LociList,
|
LociList: rule4_LociList,
|
||||||
OutcomePointsMap: rule4_OutcomePointsMap,
|
OutcomePointsMap: rule4_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs11803731),
|
References: rule4_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Make sure this is true, that a heterozygote has a higher likelihood of curly hair
|
//TODO: Make sure this is true, that a heterozygote has a higher likelihood of curly hair
|
||||||
|
rule5_ReferencesMap := make(map[string]string)
|
||||||
|
rule5_ReferencesMap["SNPedia.com - rs11803731"] = "https://www.snpedia.com/index.php/Rs11803731"
|
||||||
|
|
||||||
rule5_Locus1Object := RuleLocus{
|
rule5_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
|
@ -145,8 +108,11 @@ func getHairTextureTraitObject()Trait{
|
||||||
RuleIdentifier: "cf6cb5",
|
RuleIdentifier: "cf6cb5",
|
||||||
LociList: rule5_LociList,
|
LociList: rule5_LociList,
|
||||||
OutcomePointsMap: rule5_OutcomePointsMap,
|
OutcomePointsMap: rule5_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs11803731),
|
References: rule5_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule6_ReferencesMap := make(map[string]string)
|
||||||
|
rule6_ReferencesMap["SNPedia.com - rs11803731"] = "https://www.snpedia.com/index.php/Rs11803731"
|
||||||
|
|
||||||
rule6_Locus1Object := RuleLocus{
|
rule6_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
|
@ -163,11 +129,11 @@ func getHairTextureTraitObject()Trait{
|
||||||
RuleIdentifier: "2ba65b",
|
RuleIdentifier: "2ba65b",
|
||||||
LociList: rule6_LociList,
|
LociList: rule6_LociList,
|
||||||
OutcomePointsMap: rule6_OutcomePointsMap,
|
OutcomePointsMap: rule6_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs11803731),
|
References: rule6_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
referencesMap_rs17646946 := make(map[string]string)
|
rule7_ReferencesMap := make(map[string]string)
|
||||||
referencesMap_rs17646946["SNPedia.com - rs17646946"] = "https://www.snpedia.com/index.php/Rs17646946"
|
rule7_ReferencesMap["SNPedia.com - rs17646946"] = "https://www.snpedia.com/index.php/Rs17646946"
|
||||||
|
|
||||||
rule7_Locus1Object := RuleLocus{
|
rule7_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
|
@ -184,9 +150,12 @@ func getHairTextureTraitObject()Trait{
|
||||||
RuleIdentifier: "ae3274",
|
RuleIdentifier: "ae3274",
|
||||||
LociList: rule7_LociList,
|
LociList: rule7_LociList,
|
||||||
OutcomePointsMap: rule7_OutcomePointsMap,
|
OutcomePointsMap: rule7_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs17646946),
|
References: rule7_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule8_ReferencesMap := make(map[string]string)
|
||||||
|
rule8_ReferencesMap["SNPedia.com - rs17646946"] = "https://www.snpedia.com/index.php/Rs17646946"
|
||||||
|
|
||||||
rule8_Locus1Object := RuleLocus{
|
rule8_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
LocusIdentifier: "f1144a",
|
LocusIdentifier: "f1144a",
|
||||||
|
@ -202,9 +171,12 @@ func getHairTextureTraitObject()Trait{
|
||||||
RuleIdentifier: "a546bf",
|
RuleIdentifier: "a546bf",
|
||||||
LociList: rule8_LociList,
|
LociList: rule8_LociList,
|
||||||
OutcomePointsMap: rule8_OutcomePointsMap,
|
OutcomePointsMap: rule8_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs17646946),
|
References: rule8_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule9_ReferencesMap := make(map[string]string)
|
||||||
|
rule9_ReferencesMap["SNPedia.com - rs17646946"] = "https://www.snpedia.com/index.php/Rs17646946"
|
||||||
|
|
||||||
rule9_Locus1Object := RuleLocus{
|
rule9_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
LocusIdentifier: "468bb3",
|
LocusIdentifier: "468bb3",
|
||||||
|
@ -220,32 +192,26 @@ func getHairTextureTraitObject()Trait{
|
||||||
RuleIdentifier: "b8dc0a",
|
RuleIdentifier: "b8dc0a",
|
||||||
LociList: rule9_LociList,
|
LociList: rule9_LociList,
|
||||||
OutcomePointsMap: rule9_OutcomePointsMap,
|
OutcomePointsMap: rule9_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs17646946),
|
References: rule9_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
hairTextureRulesList := []TraitRule{rule1_Object, rule2_Object, rule3_Object, rule4_Object, rule5_Object, rule6_Object, rule7_Object, rule8_Object, rule9_Object}
|
hairTextureRulesList := []TraitRule{rule1_Object, rule2_Object, rule3_Object, rule4_Object, rule5_Object, rule6_Object, rule7_Object, rule8_Object, rule9_Object}
|
||||||
|
|
||||||
|
hairTextureLociList := []int64{17646946, 11803731, 7349332}
|
||||||
lociList_Rules := []int64{7349332, 11803731, 17646946}
|
|
||||||
|
|
||||||
referencesMap := make(map[string]string)
|
referencesMap := make(map[string]string)
|
||||||
referencesMap["SNPedia.com - Hair Curliness"] = "https://www.snpedia.com/index.php/Hair_curliness"
|
referencesMap["SNPedia.com - Hair Curliness"] = "https://www.snpedia.com/index.php/Hair_curliness"
|
||||||
|
|
||||||
outcomesList := []string{"Straight", "Curly"}
|
outcomesList := []string{"Straight", "Curly"}
|
||||||
|
|
||||||
hairTextureLociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
|
||||||
|
|
||||||
hairTextureObject := Trait{
|
hairTextureObject := Trait{
|
||||||
|
|
||||||
TraitName: "Hair Texture",
|
TraitName: "Hair Texture",
|
||||||
TraitDescription: "The texture of a person's head hair.",
|
TraitDescription: "The texture of a person's head hair.",
|
||||||
DiscreteOrNumeric: "Discrete",
|
|
||||||
LocusReferencesMap: locusReferencesMap,
|
|
||||||
LociList: hairTextureLociList,
|
LociList: hairTextureLociList,
|
||||||
LociList_Rules: lociList_Rules,
|
|
||||||
RulesList: hairTextureRulesList,
|
RulesList: hairTextureRulesList,
|
||||||
OutcomesList: outcomesList,
|
OutcomesList: outcomesList,
|
||||||
ReferencesMap: referencesMap,
|
References: referencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
return hairTextureObject
|
return hairTextureObject
|
||||||
|
|
|
@ -1,30 +1,11 @@
|
||||||
package traits
|
package traits
|
||||||
|
|
||||||
import "seekia/internal/helpers"
|
|
||||||
|
|
||||||
import "maps"
|
|
||||||
|
|
||||||
|
|
||||||
func getLactoseToleranceTraitObject()Trait{
|
func getLactoseToleranceTraitObject()Trait{
|
||||||
|
|
||||||
// Map Structure: rsID -> References Map
|
rule1_ReferencesMap := make(map[string]string)
|
||||||
locusReferencesMap := make(map[int64]map[string]string)
|
rule1_ReferencesMap["SNPedia.com - rs182549"] = "https://www.snpedia.com/index.php/Rs182549"
|
||||||
|
|
||||||
referencesMap_1 := make(map[string]string)
|
|
||||||
referencesMap_1["SNPedia.com - rs182549"] = "https://www.snpedia.com/index.php/Rs182549"
|
|
||||||
|
|
||||||
locusReferencesMap[182549] = referencesMap_1
|
|
||||||
|
|
||||||
|
|
||||||
referencesMap_2 := make(map[string]string)
|
|
||||||
referencesMap_2["SNPedia.com - rs4988235"] = "https://www.snpedia.com/index.php/Rs4988235"
|
|
||||||
|
|
||||||
locusReferencesMap[4988235] = referencesMap_2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
referencesMap_rs182549 := make(map[string]string)
|
|
||||||
referencesMap_rs182549["SNPedia.com - rs182549"] = "https://www.snpedia.com/index.php/Rs182549"
|
|
||||||
|
|
||||||
rule1_Locus1Object := RuleLocus{
|
rule1_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
|
@ -41,9 +22,12 @@ func getLactoseToleranceTraitObject()Trait{
|
||||||
RuleIdentifier: "f4e02c",
|
RuleIdentifier: "f4e02c",
|
||||||
LociList: rule1_LociList,
|
LociList: rule1_LociList,
|
||||||
OutcomePointsMap: rule1_OutcomePointsMap,
|
OutcomePointsMap: rule1_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs182549),
|
References: rule1_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule2_ReferencesMap := make(map[string]string)
|
||||||
|
rule2_ReferencesMap["SNPedia.com - rs182549"] = "https://www.snpedia.com/index.php/Rs182549"
|
||||||
|
|
||||||
rule2_Locus1Object := RuleLocus{
|
rule2_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
LocusIdentifier: "a7feff",
|
LocusIdentifier: "a7feff",
|
||||||
|
@ -59,11 +43,11 @@ func getLactoseToleranceTraitObject()Trait{
|
||||||
RuleIdentifier: "cc3df0",
|
RuleIdentifier: "cc3df0",
|
||||||
LociList: rule2_LociList,
|
LociList: rule2_LociList,
|
||||||
OutcomePointsMap: rule2_OutcomePointsMap,
|
OutcomePointsMap: rule2_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs182549),
|
References: rule2_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
referencesMap_rs4988235 := make(map[string]string)
|
rule3_ReferencesMap := make(map[string]string)
|
||||||
referencesMap_rs4988235["SNPedia.com - rs4988235"] = "https://www.snpedia.com/index.php/Rs4988235"
|
rule3_ReferencesMap["SNPedia.com - rs4988235"] = "https://www.snpedia.com/index.php/Rs4988235"
|
||||||
|
|
||||||
rule3_Locus1Object := RuleLocus{
|
rule3_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
|
@ -80,9 +64,12 @@ func getLactoseToleranceTraitObject()Trait{
|
||||||
RuleIdentifier: "8170ee",
|
RuleIdentifier: "8170ee",
|
||||||
LociList: rule3_LociList,
|
LociList: rule3_LociList,
|
||||||
OutcomePointsMap: rule3_OutcomePointsMap,
|
OutcomePointsMap: rule3_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs4988235),
|
References: rule3_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule4_ReferencesMap := make(map[string]string)
|
||||||
|
rule4_ReferencesMap["SNPedia.com - rs4988235"] = "https://www.snpedia.com/index.php/Rs4988235"
|
||||||
|
|
||||||
rule4_Locus1Object := RuleLocus{
|
rule4_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
LocusIdentifier: "176dde",
|
LocusIdentifier: "176dde",
|
||||||
|
@ -98,9 +85,12 @@ func getLactoseToleranceTraitObject()Trait{
|
||||||
RuleIdentifier: "52425f",
|
RuleIdentifier: "52425f",
|
||||||
LociList: rule4_LociList,
|
LociList: rule4_LociList,
|
||||||
OutcomePointsMap: rule4_OutcomePointsMap,
|
OutcomePointsMap: rule4_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs4988235),
|
References: rule4_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule5_ReferencesMap := make(map[string]string)
|
||||||
|
rule5_ReferencesMap["SNPedia.com - rs4988235"] = "https://www.snpedia.com/index.php/Rs4988235"
|
||||||
|
|
||||||
rule5_Locus1Object := RuleLocus{
|
rule5_Locus1Object := RuleLocus{
|
||||||
|
|
||||||
LocusIdentifier: "164acb",
|
LocusIdentifier: "164acb",
|
||||||
|
@ -116,31 +106,25 @@ func getLactoseToleranceTraitObject()Trait{
|
||||||
RuleIdentifier: "4b5c35",
|
RuleIdentifier: "4b5c35",
|
||||||
LociList: rule5_LociList,
|
LociList: rule5_LociList,
|
||||||
OutcomePointsMap: rule5_OutcomePointsMap,
|
OutcomePointsMap: rule5_OutcomePointsMap,
|
||||||
ReferencesMap: maps.Clone(referencesMap_rs4988235),
|
References: rule5_ReferencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
lactoseToleranceRulesList := []TraitRule{rule1_Object, rule2_Object, rule3_Object, rule4_Object, rule5_Object}
|
lactoseToleranceRulesList := []TraitRule{rule1_Object, rule2_Object, rule3_Object, rule4_Object, rule5_Object}
|
||||||
|
|
||||||
|
lactoseToleranceLociList := []int64{4988235, 182549}
|
||||||
|
|
||||||
referencesMap := make(map[string]string)
|
referencesMap := make(map[string]string)
|
||||||
referencesMap["SNPedia.com - Lactose Intolerance"] = "https://www.snpedia.com/index.php/Lactose_intolerance"
|
referencesMap["SNPedia.com - Lactose Intolerance"] = "https://www.snpedia.com/index.php/Lactose_intolerance"
|
||||||
|
|
||||||
outcomesList := []string{"Tolerant", "Intolerant"}
|
outcomesList := []string{"Tolerant", "Intolerant"}
|
||||||
|
|
||||||
lactoseToleranceLociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
|
||||||
|
|
||||||
lociList_Rules := []int64{182549, 4988235}
|
|
||||||
|
|
||||||
lactoseToleranceObject := Trait{
|
lactoseToleranceObject := Trait{
|
||||||
TraitName: "Lactose Tolerance",
|
TraitName: "Lactose Tolerance",
|
||||||
TraitDescription: "The ability to tolerate lactose.",
|
TraitDescription: "The ability to tolerate lactose.",
|
||||||
DiscreteOrNumeric: "Discrete",
|
|
||||||
LocusReferencesMap: locusReferencesMap,
|
|
||||||
LociList: lactoseToleranceLociList,
|
LociList: lactoseToleranceLociList,
|
||||||
LociList_Rules: lociList_Rules,
|
|
||||||
RulesList: lactoseToleranceRulesList,
|
RulesList: lactoseToleranceRulesList,
|
||||||
OutcomesList: outcomesList,
|
OutcomesList: outcomesList,
|
||||||
ReferencesMap: referencesMap,
|
References: referencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
return lactoseToleranceObject
|
return lactoseToleranceObject
|
||||||
|
|
|
@ -1,18 +1,10 @@
|
||||||
package traits
|
package traits
|
||||||
|
|
||||||
import "seekia/internal/helpers"
|
|
||||||
|
|
||||||
import "maps"
|
|
||||||
|
|
||||||
func getSkinColorTraitObject()Trait{
|
func getSkinColorTraitObject()Trait{
|
||||||
|
|
||||||
// Map Structure: rsID -> References Map
|
skinColorLociList := []int64{
|
||||||
locusReferencesMap := make(map[int64]map[string]string)
|
|
||||||
|
|
||||||
referencesMap_List1 := make(map[string]string)
|
|
||||||
referencesMap_List1["SNPedia.com - Appearance"] = "https://www.snpedia.com/index.php/Appearance"
|
|
||||||
|
|
||||||
lociList_1 := []int64{
|
|
||||||
|
|
||||||
//TODO: Add more SNPs.
|
//TODO: Add more SNPs.
|
||||||
|
|
||||||
|
@ -22,32 +14,12 @@ func getSkinColorTraitObject()Trait{
|
||||||
26722,
|
26722,
|
||||||
1426654,
|
1426654,
|
||||||
642742,
|
642742,
|
||||||
}
|
|
||||||
|
|
||||||
for _, rsID := range lociList_1{
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List1)
|
|
||||||
}
|
|
||||||
|
|
||||||
referencesMap_List2 := make(map[string]string)
|
|
||||||
referencesMap_List2["Genome-wide association studies of pigmentation and skin cancer: a review and meta-analysis"] = "https://pubmed.ncbi.nlm.nih.gov/20546537/"
|
|
||||||
|
|
||||||
lociList_2 := []int64{
|
|
||||||
|
|
||||||
// These SNPs are from https://pubmed.ncbi.nlm.nih.gov/20546537/
|
// These SNPs are from https://pubmed.ncbi.nlm.nih.gov/20546537/
|
||||||
16891982,
|
16891982,
|
||||||
12203592,
|
12203592,
|
||||||
1042602,
|
1042602,
|
||||||
1834640,
|
1834640,
|
||||||
}
|
|
||||||
|
|
||||||
for _, rsID := range lociList_2{
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List2)
|
|
||||||
}
|
|
||||||
|
|
||||||
referencesMap_List3 := make(map[string]string)
|
|
||||||
referencesMap_List3["Meta-analysis and prioritization of human skin pigmentation-associated GWAS-SNPs using ENCODE data-based web-tools"] = "https://link.springer.com/article/10.1007/s00403-019-01891-3"
|
|
||||||
|
|
||||||
lociList_3 := []int64{
|
|
||||||
|
|
||||||
// These SNPs are from https://link.springer.com/article/10.1007/s00403-019-01891-3
|
// These SNPs are from https://link.springer.com/article/10.1007/s00403-019-01891-3
|
||||||
7182710,
|
7182710,
|
||||||
|
@ -61,28 +33,18 @@ func getSkinColorTraitObject()Trait{
|
||||||
3212368,
|
3212368,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rsID := range lociList_3{
|
|
||||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List3)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
referencesMap := make(map[string]string)
|
referencesMap := make(map[string]string)
|
||||||
referencesMap["SNPedia.com - Appearance"] = "https://www.snpedia.com/index.php/Appearance"
|
referencesMap["SNPedia.com - Appearance"] = "https://www.snpedia.com/index.php/Appearance"
|
||||||
referencesMap["Genome-wide association studies of pigmentation and skin cancer: a review and meta-analysis"] = "https://pubmed.ncbi.nlm.nih.gov/20546537/"
|
referencesMap["Genome-wide association studies of pigmentation and skin cancer: a review and meta-analysis"] = "https://pubmed.ncbi.nlm.nih.gov/20546537/"
|
||||||
referencesMap["Meta-analysis and prioritization of human skin pigmentation-associated GWAS-SNPs using ENCODE data-based web-tools"] = "https://link.springer.com/article/10.1007/s00403-019-01891-3"
|
referencesMap["Meta-analysis and prioritization of human skin pigmentation-associated GWAS-SNPs using ENCODE data-based web-tools"] = "https://link.springer.com/article/10.1007/s00403-019-01891-3"
|
||||||
|
|
||||||
lociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
|
||||||
|
|
||||||
skinColorObject := Trait{
|
skinColorObject := Trait{
|
||||||
TraitName: "Skin Color",
|
TraitName: "Skin Color",
|
||||||
TraitDescription: "The color of a person's skin.",
|
TraitDescription: "The color of a person's skin.",
|
||||||
DiscreteOrNumeric: "Discrete",
|
LociList: skinColorLociList,
|
||||||
LocusReferencesMap: locusReferencesMap,
|
|
||||||
LociList: lociList,
|
|
||||||
LociList_Rules: []int64{},
|
|
||||||
RulesList: []TraitRule{},
|
RulesList: []TraitRule{},
|
||||||
OutcomesList: []string{},
|
OutcomesList: []string{},
|
||||||
ReferencesMap: referencesMap,
|
References: referencesMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
return skinColorObject
|
return skinColorObject
|
||||||
|
|
|
@ -3,51 +3,30 @@
|
||||||
|
|
||||||
package traits
|
package traits
|
||||||
|
|
||||||
|
// TODO: We want to eventually use neural nets for both trait and polygenic disease analysis
|
||||||
|
// These will be trained on a set of genomes and will output a probability analysis for each trait
|
||||||
|
// This is only possible once we get access to the necessary training data
|
||||||
|
//
|
||||||
|
// See geneticPrediction.go for a non-working attempt to predict traits with neural nets
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
type Trait struct{
|
type RuleLocus struct{
|
||||||
|
|
||||||
// Example: "Eye Color"
|
// 3 byte hex encoded string
|
||||||
TraitName string
|
LocusIdentifier string
|
||||||
|
|
||||||
TraitDescription string
|
// RSID that represents this locus
|
||||||
|
// If multiple RSIDs represent the same locus, use the first rsid for the locus in the locusMetadata package
|
||||||
|
LocusRSID int64
|
||||||
|
|
||||||
// This describes if the trait is discrete or numeric
|
// List of base pair values that this RSID must fulfill to pass the rule
|
||||||
// Discrete traits have a set of outcomes (Example: Eye Color: Blue, Green...)
|
// As long as the value matches any base pair value in the list, the genome has passed this rule locus
|
||||||
// Numeric traits have a numeric outcome (Example: Height)
|
// The genome must pass every rule locus within a rule to pass the rule
|
||||||
// The value of this variable is either "Discrete" or "Numeric"
|
BasePairsList []string
|
||||||
DiscreteOrNumeric string
|
|
||||||
|
|
||||||
// This is a list of rsIDs which are known to have an effect on this trait
|
|
||||||
// These loci may not have any associated rules
|
|
||||||
// We use these loci to predict trait outcomes with neural networks.
|
|
||||||
// We also use these loci to calculate Racial Similarity.
|
|
||||||
// Map Structure: rsID -> (map[ReferenceName]Reference Link)
|
|
||||||
LocusReferencesMap map[int64]map[string]string
|
|
||||||
|
|
||||||
// This is a list of all loci used to predict this trait
|
|
||||||
// If a neural network exists, all of these will be used as input into the network for prediction
|
|
||||||
LociList []int64
|
|
||||||
|
|
||||||
// This is a list of all loci used to predict this trait using rules
|
|
||||||
// It is sometimes a subset of LociList
|
|
||||||
LociList_Rules []int64
|
|
||||||
|
|
||||||
// This list can be empty if no rules exist
|
|
||||||
// An empty list means we are relying on LociList and neural networks for trait prediction.
|
|
||||||
RulesList []TraitRule
|
|
||||||
|
|
||||||
// List of outcomes
|
|
||||||
// Example: "Lactose Intolerant", "Lactore Tolerant"
|
|
||||||
// This list can be empty if outcomes are not text descriptions (Example: Facial structure)
|
|
||||||
// If the trait is Numeric, or their or no rules nor a neural network, then this list will be empty.
|
|
||||||
OutcomesList []string
|
|
||||||
|
|
||||||
// This map contains scientific resources about this trait
|
|
||||||
// Map structure: Reference name -> Reference link
|
|
||||||
ReferencesMap map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type TraitRule struct{
|
type TraitRule struct{
|
||||||
|
|
||||||
// 3 byte identifier encoded hex
|
// 3 byte identifier encoded hex
|
||||||
|
@ -65,26 +44,36 @@ type TraitRule struct{
|
||||||
OutcomePointsMap map[string]int
|
OutcomePointsMap map[string]int
|
||||||
|
|
||||||
// Map structure: Reference name -> Reference link
|
// Map structure: Reference name -> Reference link
|
||||||
ReferencesMap map[string]string
|
References map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type RuleLocus struct{
|
type Trait struct{
|
||||||
|
|
||||||
// 3 byte hex encoded string
|
TraitName string
|
||||||
LocusIdentifier string
|
|
||||||
|
|
||||||
// RSID that represents this locus
|
TraitDescription string
|
||||||
// If multiple RSIDs represent the same locus, use the first rsid for the locus in the locusMetadata package
|
|
||||||
LocusRSID int64
|
|
||||||
|
|
||||||
// List of base pair values that this RSID must fulfill to pass the rule
|
// This is a list of rsIDs which are known to have an effect on this trait
|
||||||
// As long as the value matches any base pair value in the list, the genome has passed this rule locus
|
// These loci may not have any associated rules
|
||||||
// The genome must pass every rule locus within a rule to pass the rule
|
// We use these loci to calculate Racial Similarity.
|
||||||
BasePairsList []string
|
// We will also use neural networks to predict trait outcome scores using these loci
|
||||||
|
LociList []int64
|
||||||
|
|
||||||
|
// This list can be empty if no rules exist
|
||||||
|
// An empty list means we are relying on LociList and neural networks for trait prediction.
|
||||||
|
RulesList []TraitRule
|
||||||
|
|
||||||
|
// List of outcomes
|
||||||
|
// Example: "Lactose Intolerant", "Lactore Tolerant"
|
||||||
|
// This list can be empty if outcomes are not text descriptions (Example: Facial structure)
|
||||||
|
// If there are no outcomes, then no rules can exist
|
||||||
|
OutcomesList []string
|
||||||
|
|
||||||
|
// Map structure: Reference name -> Reference link
|
||||||
|
References map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var traitNamesList []string
|
var traitNamesList []string
|
||||||
var traitObjectsList []Trait
|
var traitObjectsList []Trait
|
||||||
|
|
||||||
|
|
3
utilities/createGeneticModels/.gitignore
vendored
3
utilities/createGeneticModels/.gitignore
vendored
|
@ -1,4 +1,3 @@
|
||||||
OpenSNPDataArchiveFolderpath.txt
|
OpenSNPDataArchiveFolderpath.txt
|
||||||
TrainingData
|
TrainingData
|
||||||
TrainedModels
|
TrainedModels
|
||||||
ModelAccuracies
|
|
|
@ -3,7 +3,6 @@
|
||||||
// These are neural networks which predict traits such as eye color from raw genome files
|
// These are neural networks which predict traits such as eye color from raw genome files
|
||||||
// The OpenSNP.org dataset is used, and more datasets will be added in the future.
|
// The OpenSNP.org dataset is used, and more datasets will be added in the future.
|
||||||
// You must download the dataset and extract it. The instructions are described in the utility.
|
// You must download the dataset and extract it. The instructions are described in the utility.
|
||||||
// The trained models are saved in the /resources/geneticPredictionModels package for use in the Seekia app.
|
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
@ -1137,16 +1136,10 @@ func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, prev
|
||||||
_, err := localFilesystem.CreateFolder("./TrainedModels")
|
_, err := localFilesystem.CreateFolder("./TrainedModels")
|
||||||
if (err != nil) { return false, err }
|
if (err != nil) { return false, err }
|
||||||
|
|
||||||
|
|
||||||
trainingSetFilepathsList, _, err := getTrainingAndTestingDataFilepathLists(traitName)
|
trainingSetFilepathsList, _, err := getTrainingAndTestingDataFilepathLists(traitName)
|
||||||
if (err != nil) { return false, err }
|
if (err != nil) { return false, err }
|
||||||
|
|
||||||
// Now we deterministically randomize the order of the trainingSetFilepathsList
|
|
||||||
pseudorandomNumberGenerator := mathRand.New(mathRand.NewPCG(1, 2))
|
|
||||||
|
|
||||||
pseudorandomNumberGenerator.Shuffle(len(trainingSetFilepathsList), func(i int, j int){
|
|
||||||
trainingSetFilepathsList[i], trainingSetFilepathsList[j] = trainingSetFilepathsList[j], trainingSetFilepathsList[i]
|
|
||||||
})
|
|
||||||
|
|
||||||
// We create a new neural network object to train
|
// We create a new neural network object to train
|
||||||
neuralNetworkObject, err := geneticPrediction.GetNewUntrainedNeuralNetworkObject(traitName)
|
neuralNetworkObject, err := geneticPrediction.GetNewUntrainedNeuralNetworkObject(traitName)
|
||||||
if (err != nil) { return false, err }
|
if (err != nil) { return false, err }
|
||||||
|
@ -1284,8 +1277,7 @@ func setTestModelsPage(window fyne.Window, previousPage func()){
|
||||||
description2 := getLabelCentered("This will test each neural network using user training data examples.")
|
description2 := getLabelCentered("This will test each neural network using user training data examples.")
|
||||||
description3 := getLabelCentered("The testing data is not used to train the models.")
|
description3 := getLabelCentered("The testing data is not used to train the models.")
|
||||||
description4 := getLabelCentered("The results of the testing will be displayed at the end.")
|
description4 := getLabelCentered("The results of the testing will be displayed at the end.")
|
||||||
description5 := getLabelCentered("The results will also be saved in the ModelAccuracies folder.")
|
description5 := getLabelCentered("You must select a trait model to test.")
|
||||||
description6 := getLabelCentered("You must select a trait model to test.")
|
|
||||||
|
|
||||||
traitNamesList := []string{"Eye Color", "Lactose Tolerance"}
|
traitNamesList := []string{"Eye Color", "Lactose Tolerance"}
|
||||||
|
|
||||||
|
@ -1309,12 +1301,50 @@ func setTestModelsPage(window fyne.Window, previousPage func()){
|
||||||
|
|
||||||
traitNameSelectorCentered := getWidgetCentered(traitNameSelector)
|
traitNameSelectorCentered := getWidgetCentered(traitNameSelector)
|
||||||
|
|
||||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, widget.NewSeparator(), traitNameSelectorCentered, widget.NewSeparator(), beginTestingButton)
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, widget.NewSeparator(), traitNameSelectorCentered, widget.NewSeparator(), beginTestingButton)
|
||||||
|
|
||||||
window.SetContent(page)
|
window.SetContent(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type TraitOutcomeInfo struct{
|
||||||
|
|
||||||
|
// This is the outcome which was found
|
||||||
|
// Example: "Blue"
|
||||||
|
OutcomeName string
|
||||||
|
|
||||||
|
// This is a value between 0-100 which describes the percentage of the loci which were tested for the input for the prediction
|
||||||
|
PercentageOfLociTested int
|
||||||
|
|
||||||
|
// This is a value between 0-100 which describes the percentage of the tested loci which were phased for the input for the prediction
|
||||||
|
PercentageOfPhasedLoci int
|
||||||
|
}
|
||||||
|
|
||||||
|
type TraitPredictionAccuracyInfo struct{
|
||||||
|
|
||||||
|
// This contains the quantity of examples for the outcome with the specified percentageOfLociTested and percentageOfPhasedLoci
|
||||||
|
QuantityOfExamples int
|
||||||
|
|
||||||
|
// This contains the quantity of predictions for the outcome with the specified percentageOfLociTested and percentageOfPhasedLoci
|
||||||
|
// Prediction = our model predicted this outcome
|
||||||
|
QuantityOfPredictions int
|
||||||
|
|
||||||
|
// This stores the probability (0-100) that our model will accurately predict this outcome for a genome which has
|
||||||
|
// the specified percentageOfLociTested and percentageOfPhasedLoci
|
||||||
|
// In other words: What is the probability that if you give Seekia a blue-eyed genome, it will give you a correct Blue prediction?
|
||||||
|
// This value is only accurate is QuantityOfExamples > 0
|
||||||
|
ProbabilityOfCorrectGenomePrediction int
|
||||||
|
|
||||||
|
// This stores the probability (0-100) that our model is correct if our model predicts that a genome
|
||||||
|
// with the specified percentageOfLociTested and percentageOfPhasedLoci has this outcome
|
||||||
|
// In other words: What is the probability that if Seekia says a genome will have blue eyes, it is correct?
|
||||||
|
// This value is only accurate is QuantityOfPredictions > 0
|
||||||
|
ProbabilityOfCorrectOutcomePrediction int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map Structure: Trait Outcome Info -> Trait Prediction Accuracy Info
|
||||||
|
type TraitAccuracyInfoMap map[TraitOutcomeInfo]TraitPredictionAccuracyInfo
|
||||||
|
|
||||||
func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previousPage func()){
|
func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previousPage func()){
|
||||||
|
|
||||||
title := getBoldLabelCentered("Testing Model")
|
title := getBoldLabelCentered("Testing Model")
|
||||||
|
@ -1356,9 +1386,9 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
||||||
|
|
||||||
//Outputs:
|
//Outputs:
|
||||||
// -bool: Process completed (true == was not stopped mid-way)
|
// -bool: Process completed (true == was not stopped mid-way)
|
||||||
// -geneticPrediction.TraitPredictionAccuracyInfoMap
|
// -TraitAccuracyInfoMap
|
||||||
// -error
|
// -error
|
||||||
testModel := func()(bool, geneticPrediction.TraitPredictionAccuracyInfoMap, error){
|
testModel := func()(bool, TraitAccuracyInfoMap, error){
|
||||||
|
|
||||||
type TraitAccuracyStatisticsValue struct{
|
type TraitAccuracyStatisticsValue struct{
|
||||||
|
|
||||||
|
@ -1378,7 +1408,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
||||||
|
|
||||||
// We use this map to count up the information about predictions
|
// We use this map to count up the information about predictions
|
||||||
// We use information from this map to construct the final accuracy information map
|
// We use information from this map to construct the final accuracy information map
|
||||||
traitPredictionInfoMap := make(map[geneticPrediction.TraitOutcomeInfo]TraitAccuracyStatisticsValue)
|
traitPredictionInfoMap := make(map[TraitOutcomeInfo]TraitAccuracyStatisticsValue)
|
||||||
|
|
||||||
|
|
||||||
_, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(traitName)
|
_, testingSetFilepathsList, err := getTrainingAndTestingDataFilepathLists(traitName)
|
||||||
|
@ -1464,7 +1494,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
||||||
{
|
{
|
||||||
// We first add the information to the map for the correct outcome
|
// We first add the information to the map for the correct outcome
|
||||||
|
|
||||||
newTraitOutcomeInfo_CorrectOutcome := geneticPrediction.TraitOutcomeInfo{
|
newTraitOutcomeInfo_CorrectOutcome := TraitOutcomeInfo{
|
||||||
|
|
||||||
OutcomeName: correctOutcomeName,
|
OutcomeName: correctOutcomeName,
|
||||||
PercentageOfLociTested: percentageOfLociTested,
|
PercentageOfLociTested: percentageOfLociTested,
|
||||||
|
@ -1495,7 +1525,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
||||||
{
|
{
|
||||||
// We now add the information to the map for the predicted outcome
|
// We now add the information to the map for the predicted outcome
|
||||||
|
|
||||||
newTraitOutcomeInfo_PredictedOutcome := geneticPrediction.TraitOutcomeInfo{
|
newTraitOutcomeInfo_PredictedOutcome := TraitOutcomeInfo{
|
||||||
|
|
||||||
OutcomeName: predictedOutcomeName,
|
OutcomeName: predictedOutcomeName,
|
||||||
PercentageOfLociTested: percentageOfLociTested,
|
PercentageOfLociTested: percentageOfLociTested,
|
||||||
|
@ -1536,7 +1566,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
||||||
// Now we construct the TraitAccuracyInfoMap
|
// Now we construct the TraitAccuracyInfoMap
|
||||||
|
|
||||||
// This map stores the accuracy for each outcome
|
// This map stores the accuracy for each outcome
|
||||||
traitPredictionAccuracyInfoMap := make(map[geneticPrediction.TraitOutcomeInfo]geneticPrediction.TraitPredictionAccuracyInfo)
|
traitAccuracyInfoMap := make(map[TraitOutcomeInfo]TraitPredictionAccuracyInfo)
|
||||||
|
|
||||||
for traitAccuracyData, value := range traitPredictionInfoMap{
|
for traitAccuracyData, value := range traitPredictionInfoMap{
|
||||||
|
|
||||||
|
@ -1553,7 +1583,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
||||||
return false, nil, errors.New("traitPredictionInfoMap contains quantityOfCorrectOutcomePredictions > quantityOfPredictions")
|
return false, nil, errors.New("traitPredictionInfoMap contains quantityOfCorrectOutcomePredictions > quantityOfPredictions")
|
||||||
}
|
}
|
||||||
|
|
||||||
newTraitPredictionAccuracyInfo := geneticPrediction.TraitPredictionAccuracyInfo{
|
newTraitPredictionAccuracyInfo := TraitPredictionAccuracyInfo{
|
||||||
QuantityOfExamples: quantityOfExamples,
|
QuantityOfExamples: quantityOfExamples,
|
||||||
QuantityOfPredictions: quantityOfPredictions,
|
QuantityOfPredictions: quantityOfPredictions,
|
||||||
}
|
}
|
||||||
|
@ -1574,30 +1604,17 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
||||||
newTraitPredictionAccuracyInfo.ProbabilityOfCorrectOutcomePrediction = percentageOfCorrectOutcomePredictions
|
newTraitPredictionAccuracyInfo.ProbabilityOfCorrectOutcomePrediction = percentageOfCorrectOutcomePredictions
|
||||||
}
|
}
|
||||||
|
|
||||||
traitPredictionAccuracyInfoMap[traitAccuracyData] = newTraitPredictionAccuracyInfo
|
traitAccuracyInfoMap[traitAccuracyData] = newTraitPredictionAccuracyInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testing is complete.
|
// Testing is complete.
|
||||||
|
|
||||||
// We save the info map as a file in the ModelAccuracies folder
|
|
||||||
|
|
||||||
fileBytes, err := geneticPrediction.EncodeTraitPredictionAccuracyInfoMapToBytes(traitPredictionAccuracyInfoMap)
|
|
||||||
if (err != nil) { return false, nil, err }
|
|
||||||
|
|
||||||
_, err = localFilesystem.CreateFolder("./ModelAccuracies")
|
|
||||||
if (err != nil) { return false, nil, err }
|
|
||||||
|
|
||||||
modelAccuracyFilename := traitNameWithoutWhitespaces + "ModelAccuracy.gob"
|
|
||||||
|
|
||||||
err = localFilesystem.CreateOrOverwriteFile(fileBytes, "./ModelAccuracies/", modelAccuracyFilename)
|
|
||||||
if (err != nil) { return false, nil, err }
|
|
||||||
|
|
||||||
progressPercentageBinding.Set(1)
|
progressPercentageBinding.Set(1)
|
||||||
|
|
||||||
return true, traitPredictionAccuracyInfoMap, nil
|
return true, traitAccuracyInfoMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
processIsComplete, traitPredictionAccuracyInfoMap, err := testModel()
|
processIsComplete, traitAccuracyInfoMap, err := testModel()
|
||||||
if (err != nil){
|
if (err != nil){
|
||||||
setErrorEncounteredPage(window, err, previousPage)
|
setErrorEncounteredPage(window, err, previousPage)
|
||||||
return
|
return
|
||||||
|
@ -1607,14 +1624,14 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setViewModelTestingTraitResultsPage(window, traitName, traitPredictionAccuracyInfoMap, previousPage)
|
setViewModelTestingTraitResultsPage(window, traitName, traitAccuracyInfoMap, previousPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
go testModelFunction()
|
go testModelFunction()
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a page to view the details of testing for a specific trait's model
|
// This is a page to view the details of testing for a specific trait's model
|
||||||
func setViewModelTestingTraitResultsPage(window fyne.Window, traitName string, traitAccuracyInfoMap geneticPrediction.TraitPredictionAccuracyInfoMap, exitPage func()){
|
func setViewModelTestingTraitResultsPage(window fyne.Window, traitName string, traitAccuracyInfoMap TraitAccuracyInfoMap, exitPage func()){
|
||||||
|
|
||||||
title := getBoldLabelCentered("Trait Prediction Accuracy Details")
|
title := getBoldLabelCentered("Trait Prediction Accuracy Details")
|
||||||
|
|
||||||
|
@ -1644,10 +1661,14 @@ func setViewModelTestingTraitResultsPage(window fyne.Window, traitName string, t
|
||||||
predictionAccuracyTitle3 := getItalicLabelCentered("Prediction Accuracy")
|
predictionAccuracyTitle3 := getItalicLabelCentered("Prediction Accuracy")
|
||||||
knownLociLabel_67to100 := getItalicLabelCentered("67-100% Known Loci")
|
knownLociLabel_67to100 := getItalicLabelCentered("67-100% Known Loci")
|
||||||
|
|
||||||
|
emptyLabel2 := widget.NewLabel("")
|
||||||
|
emptyLabel3 := widget.NewLabel("")
|
||||||
|
|
||||||
outcomeNameColumn := container.NewVBox(outcomeNameTitle, emptyLabel1, widget.NewSeparator())
|
outcomeNameColumn := container.NewVBox(outcomeNameTitle, emptyLabel1, widget.NewSeparator())
|
||||||
predictionAccuracyColumn_0to33 := container.NewVBox(predictionAccuracyTitle1, knownLociLabel_0to33, widget.NewSeparator())
|
predictionAccuracyColumn_0to33 := container.NewVBox(predictionAccuracyTitle1, knownLociLabel_0to33, widget.NewSeparator())
|
||||||
predictionAccuracyColumn_34to66 := container.NewVBox(predictionAccuracyTitle2, knownLociLabel_34to66, widget.NewSeparator())
|
predictionAccuracyColumn_34to66 := container.NewVBox(predictionAccuracyTitle2, knownLociLabel_34to66, widget.NewSeparator())
|
||||||
predictionAccuracyColumn_67to100 := container.NewVBox(predictionAccuracyTitle3, knownLociLabel_67to100, widget.NewSeparator())
|
predictionAccuracyColumn_67to100 := container.NewVBox(predictionAccuracyTitle3, knownLociLabel_67to100, widget.NewSeparator())
|
||||||
|
viewTraitAccuracyDetailsColumn := container.NewVBox(emptyLabel2, emptyLabel3, widget.NewSeparator())
|
||||||
|
|
||||||
traitObject, err := traits.GetTraitObject(traitName)
|
traitObject, err := traits.GetTraitObject(traitName)
|
||||||
if (err != nil) { return nil, err }
|
if (err != nil) { return nil, err }
|
||||||
|
@ -1756,7 +1777,7 @@ func setViewModelTestingTraitResultsPage(window fyne.Window, traitName string, t
|
||||||
predictionAccuracyColumn_67to100.Add(widget.NewSeparator())
|
predictionAccuracyColumn_67to100.Add(widget.NewSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
resultsGrid := container.NewHBox(layout.NewSpacer(), outcomeNameColumn, predictionAccuracyColumn_0to33, predictionAccuracyColumn_34to66, predictionAccuracyColumn_67to100, layout.NewSpacer())
|
resultsGrid := container.NewHBox(layout.NewSpacer(), outcomeNameColumn, predictionAccuracyColumn_0to33, predictionAccuracyColumn_34to66, predictionAccuracyColumn_67to100, viewTraitAccuracyDetailsColumn, layout.NewSpacer())
|
||||||
|
|
||||||
return resultsGrid, nil
|
return resultsGrid, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue