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
|
||||
|
||||
* 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 ReadMe.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
|
||||
--- | --- | ---
|
||||
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
|
||||
|
||||
require (
|
||||
fyne.io/fyne/v2 v2.5.0
|
||||
fyne.io/fyne/v2 v2.4.5
|
||||
github.com/chai2010/webp v1.1.1
|
||||
github.com/cloudflare/circl v1.3.9
|
||||
github.com/dgraph-io/badger/v4 v4.2.0
|
||||
|
@ -15,15 +15,14 @@ require (
|
|||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.1
|
||||
github.com/zeebo/blake3 v0.2.3
|
||||
golang.org/x/crypto v0.23.0
|
||||
golang.org/x/image v0.18.0
|
||||
golang.org/x/crypto v0.21.0
|
||||
golang.org/x/image v0.15.0
|
||||
gorgonia.org/gorgonia v0.9.18
|
||||
gorgonia.org/tensor v0.9.24
|
||||
)
|
||||
|
||||
require (
|
||||
fyne.io/systray v1.11.0 // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e // indirect
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 // indirect
|
||||
github.com/awalterschulze/gographviz v2.0.3+incompatible // 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/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/fredbi/uri v1.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fredbi/uri v1.0.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/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/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/typesetting v0.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/uuid v1.5.0 // 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/klauspost/compress v1.13.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 // 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/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/tevino/abool v1.2.0 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.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
|
||||
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/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
gonum.org/v1/gonum v0.14.0 // indirect
|
||||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
|
@ -79,4 +76,5 @@ require (
|
|||
gorgonia.org/dawson v1.2.0 // indirect
|
||||
gorgonia.org/vecf32 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.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=
|
||||
fyne.io/fyne/v2 v2.5.0 h1:lEjEIso0Vi4sJXYngIMoXOM6aUjqnPjK7pBpxRxG9aI=
|
||||
fyne.io/fyne/v2 v2.5.0/go.mod h1:9D4oT3NWeG+MLi/lP7ItZZyujHC/qqMJpoGTAYX5Uqc=
|
||||
fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg=
|
||||
fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
|
||||
fyne.io/fyne/v2 v2.4.5 h1:W6jpAEmLoBbKyBB+EXqI7GMJ7kLgHQWCa0wZHUV2VfQ=
|
||||
fyne.io/fyne/v2 v2.4.5/go.mod h1:SlOgbca0y80cRObu/JOhxIJdIgtoW7aCyqUVlTMgs0Y=
|
||||
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e h1:Hvs+kW2VwCzNToF3FmnIAzmivNgrclwPgoUdVSrjkP8=
|
||||
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=
|
||||
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 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/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=
|
||||
|
@ -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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
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.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.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4=
|
||||
github.com/fredbi/uri v1.0.0 h1:s4QwUAZ8fz+mbTsukND+4V5f+mJ/wjaTokwstGUAemg=
|
||||
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.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
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/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-20240101223322-6e1efdc71b7a/go.mod h1:gsGA2dotD4v0SR6PmPCYvS9JuOeMwAtmfvDE7mbYXMY=
|
||||
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-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/go.mod h1:eO7W361vmlPOrykIg+Rsh1SZ3tQBaOsfzZhsIOb/Lm0=
|
||||
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/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-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0=
|
||||
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-20211213063430-748e38ca8aec/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-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=
|
||||
|
@ -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-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-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/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=
|
||||
|
@ -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-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/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/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=
|
||||
|
@ -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-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
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/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=
|
||||
|
@ -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/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
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/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
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/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/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/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
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-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=
|
||||
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/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=
|
||||
|
@ -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/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||
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.2.0/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.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.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/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
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/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||
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.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.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U=
|
||||
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.5.5 h1:IJznPe8wOzfIKETmMkd06F8nXkmlhaHqFRM9l1hAGsU=
|
||||
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/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
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-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.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
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-20180807140117-3d87b88a115f/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-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.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
|
||||
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||
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-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
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-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-20231127183840-76ac6878050a h1:sYbmY3FwUWCBTodZL1S3JUuOvaW6kM2o+clDzzDNBWg=
|
||||
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a/go.mod h1:Ede7gF0KGoHlj822RtphAHK1jLdrcuRBZg0sF1Q+SPc=
|
||||
golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda h1:O+EUvnBNPwI4eLthn8W5K+cS8zQZfgTABPLNm6Bna34=
|
||||
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.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
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-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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
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-20190226205417-e64efc72b421/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-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-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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
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.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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
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-20190308202827-9d24e82272b4/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=
|
||||
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-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
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.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
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.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.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
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-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.9.0 h1:bgZDP5x0OzBF64PjMGC3EvTdOoMEcmfAh1VCUnZFm1A=
|
||||
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-20190106161140-3f1c8253044a/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(){
|
||||
setWealthIsLowerBoundExplainerPage(window, currentPage)
|
||||
setWealthOrIncomeIsLowerBoundExplainerPage(window, currentPage)
|
||||
})
|
||||
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)
|
||||
|
||||
subtitle := getPageSubtitleCentered("Discrete Trait Neural Network Prediction")
|
||||
subtitle := getPageSubtitleCentered("Trait Outcome Scores")
|
||||
|
||||
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("Neural network prediction is calculated by inputing a genome's loci into a neural network.")
|
||||
description5 := getLabelCentered("Each trait has multiple outcomes, and the neural network predicts a single outcome.")
|
||||
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.")
|
||||
description1 := getLabelCentered("Person genetic analyses contain trait analyses.")
|
||||
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||
description3 := getLabelCentered("Points are added to an outcome to represent a higher probability.")
|
||||
description4 := getLabelCentered("Points are subtracted from an outcome to represent a lower probability.")
|
||||
description5 := 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)
|
||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5)
|
||||
|
||||
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)
|
||||
|
||||
subtitle := getPageSubtitleCentered("Offspring Discrete Trait Neural Network Prediction")
|
||||
subtitle := getPageSubtitleCentered("Offspring Trait Outcome Scores")
|
||||
|
||||
description1 := getLabelCentered("Couple 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("Neural network prediction is calculated by inputing a genome's loci into a neural network.")
|
||||
description5 := getLabelCentered("Each trait has multiple outcomes, and the neural network predicts the probability of each outcome.")
|
||||
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.")
|
||||
description1 := getLabelCentered("Couple genetic analyses contain trait analyses for the offspring.")
|
||||
description2 := getLabelCentered("Each trait has multiple outcomes, and each outcome has an associated score.")
|
||||
description3 := getLabelCentered("Points are added to an outcome to represent a higher probability.")
|
||||
description4 := getLabelCentered("Points are subtracted from an outcome to represent a lower probability.")
|
||||
description5 := 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)
|
||||
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5)
|
||||
|
||||
setPageContent(page, window)
|
||||
}
|
||||
|
||||
func setDiscreteTraitRulesPredictionExplainerPage(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()){
|
||||
func setTraitRulesExplainerPage(window fyne.Window, previousPage func()){
|
||||
|
||||
title := getPageTitleCentered("Help - Trait Rules")
|
||||
|
||||
|
@ -770,8 +720,8 @@ func setDiscreteTraitRulesExplainerPage(window fyne.Window, previousPage func())
|
|||
|
||||
subtitle := getPageSubtitleCentered("Trait Rules")
|
||||
|
||||
description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.")
|
||||
description2 := getLabelCentered("Discrete traits has multiple outcomes, and each outcome has an associated score.")
|
||||
description1 := getLabelCentered("Person genetic analyses contain trait analyses.")
|
||||
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.")
|
||||
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
||||
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)
|
||||
}
|
||||
|
||||
func setOffspringDiscreteTraitRulesExplainerPage(window fyne.Window, previousPage func()){
|
||||
func setOffspringTraitRulesExplainerPage(window fyne.Window, previousPage func()){
|
||||
|
||||
title := getPageTitleCentered("Help - Trait Rules")
|
||||
|
||||
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.")
|
||||
description2 := getLabelCentered("Each discrete trait has multiple outcomes, and each outcome has an associated score.")
|
||||
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.")
|
||||
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.")
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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.")
|
||||
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.")
|
||||
|
@ -825,13 +775,13 @@ func setDiscreteTraitQuantityOfRulesTestedExplainerPage(window fyne.Window, prev
|
|||
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)
|
||||
|
||||
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.")
|
||||
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")
|
||||
|
||||
description1 := getLabelCentered("Offspring genetic analyses contain discrete trait analyses for a couple's offspring.")
|
||||
description2 := getLabelCentered("Each discrete trait has multiple outcomes, and each outcome has an associated score.")
|
||||
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.")
|
||||
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.")
|
||||
description5 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
||||
|
@ -871,7 +821,8 @@ func setOffspringProbabilityOfPassingTraitRuleExplainerPage(window fyne.Window,
|
|||
setPageContent(page, window)
|
||||
}
|
||||
|
||||
func setPersonPassesDiscreteTraitRuleExplainerPage(window fyne.Window, previousPage func()){
|
||||
|
||||
func setPersonPassesTraitRuleExplainerPage(window fyne.Window, previousPage func()){
|
||||
|
||||
title := getPageTitleCentered("Help - Trait Rules")
|
||||
|
||||
|
@ -879,8 +830,8 @@ func setPersonPassesDiscreteTraitRuleExplainerPage(window fyne.Window, previousP
|
|||
|
||||
subtitle := getPageSubtitleCentered("Person Passes Trait Rule")
|
||||
|
||||
description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.")
|
||||
description2 := getLabelCentered("Each discrete trait has multiple outcomes, and each outcome has an associated score.")
|
||||
description1 := getLabelCentered("Person genetic analyses contain trait analyses.")
|
||||
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.")
|
||||
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
||||
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)
|
||||
}
|
||||
|
||||
func setGenomePassesDiscreteTraitRuleExplainerPage(window fyne.Window, previousPage func()){
|
||||
func setGenomePassesTraitRuleExplainerPage(window fyne.Window, previousPage func()){
|
||||
|
||||
title := getPageTitleCentered("Help - Genome Passes Rule")
|
||||
|
||||
|
@ -899,23 +850,22 @@ func setGenomePassesDiscreteTraitRuleExplainerPage(window fyne.Window, previousP
|
|||
|
||||
subtitle := getPageSubtitleCentered("Genome Passes Trait Rule")
|
||||
|
||||
description1 := getLabelCentered("Person genetic analyses contain discrete trait analyses.")
|
||||
description2 := getLabelCentered("There are 2 discrete trait analysis methods: Rules and Neural Networks.")
|
||||
description3 := getLabelCentered("For rule-based analyses, each trait's outcome has an associated score.")
|
||||
description4 := getLabelCentered("A higher score represents a higher probability, and a lower score represents the opposite.")
|
||||
description5 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
||||
description6 := getLabelCentered("A trait rule will add/subtract values to outcome(s).")
|
||||
description7 := getLabelCentered("If a person passes a rule, its effects will be applied to their outcome(s).")
|
||||
description8 := getLabelCentered("If a person has imported multiple genomes, each genome may or may not pass the rule.")
|
||||
description9 := getLabelCentered("If one genome passes and another does not, it means that one genome has an invalid value.")
|
||||
description10 := getLabelCentered("This happens because genome sequencing technology is not perfectly accurate.")
|
||||
description1 := getLabelCentered("Person genetic analyses contain trait analyses.")
|
||||
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.")
|
||||
description4 := getLabelCentered("Each outcome's score is determined by trait rules.")
|
||||
description5 := 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 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("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)
|
||||
}
|
||||
|
||||
func setDiscreteTraitRuleOutcomeEffectsExplainerPage(window fyne.Window, previousPage func()){
|
||||
func setTraitRuleOutcomeEffectsExplainerPage(window fyne.Window, previousPage func()){
|
||||
|
||||
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")
|
||||
|
||||
|
@ -955,7 +905,7 @@ func setWealthIsLowerBoundExplainerPage(window fyne.Window, previousPage func())
|
|||
|
||||
|
||||
func setMemoExplainerPage(window fyne.Window, previousPage func()){
|
||||
|
||||
|
||||
title := getPageTitleCentered("Help - Memo")
|
||||
|
||||
backButton := getBackButtonCentered(previousPage)
|
||||
|
@ -1076,7 +1026,7 @@ func setHostingHelpPage(window fyne.Window, previousPage func()){
|
|||
description1 := getLabelCentered("Be a Seekia host.")
|
||||
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.")
|
||||
|
||||
|
||||
//TODO: Add buttons to show more help
|
||||
//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/widget"
|
||||
|
||||
import "seekia/resources/geneticPredictionModels"
|
||||
import "seekia/resources/geneticReferences/monogenicDiseases"
|
||||
import "seekia/resources/geneticReferences/polygenicDiseases"
|
||||
import "seekia/resources/geneticReferences/traits"
|
||||
|
@ -71,15 +70,11 @@ func setViewPersonGeneticAnalysisPage(window fyne.Window, personIdentifier strin
|
|||
polygenicDiseasesButton := widget.NewButton("Polygenic Diseases", func(){
|
||||
setViewPersonGeneticAnalysisPolygenicDiseasesPage(window, personIdentifier, analysisObject, currentPage)
|
||||
})
|
||||
discreteTraitsButton := widget.NewButton("Discrete Traits", func(){
|
||||
setViewPersonGeneticAnalysisDiscreteTraitsPage(window, personIdentifier, analysisObject, currentPage)
|
||||
})
|
||||
numericTraitsButton := widget.NewButton("Numeric Traits", func(){
|
||||
//TODO
|
||||
showUnderConstructionDialog(window)
|
||||
traitsButton := widget.NewButton("Traits", func(){
|
||||
setViewPersonGeneticAnalysisTraitsPage(window, personIdentifier, analysisObject, currentPage)
|
||||
})
|
||||
|
||||
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)
|
||||
|
||||
|
@ -99,7 +94,7 @@ func setViewPersonGeneticAnalysisMonogenicDiseasesPage(window fyne.Window, analy
|
|||
|
||||
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 }
|
||||
|
||||
// Outputs:
|
||||
|
@ -245,8 +240,8 @@ func setViewPersonGeneticAnalysisMonogenicDiseaseDetailsPage(window fyne.Window,
|
|||
title := getPageTitleCentered("Viewing Genetic Analysis - " + diseaseName)
|
||||
|
||||
backButton := getBackButtonCentered(previousPage)
|
||||
|
||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||
|
||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||
if (err != nil) {
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
|
@ -285,6 +280,8 @@ func setViewPersonGeneticAnalysisMonogenicDiseaseDetailsPage(window fyne.Window,
|
|||
totalNumberOfVariants := len(diseaseVariantsMap)
|
||||
totalNumberOfVariantsString := helpers.ConvertIntToString(totalNumberOfVariants)
|
||||
|
||||
|
||||
|
||||
emptyLabelA := widget.NewLabel("")
|
||||
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
||||
|
||||
|
@ -739,7 +736,7 @@ func setViewPersonGeneticAnalysisMonogenicDiseaseVariantDetailsPage(window fyne.
|
|||
|
||||
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 }
|
||||
|
||||
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
||||
|
@ -897,7 +894,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso
|
|||
|
||||
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 }
|
||||
|
||||
// Outputs:
|
||||
|
@ -938,7 +935,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseasesPage(window fyne.Window, perso
|
|||
|
||||
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 }
|
||||
|
||||
getPersonRiskScoreLabelText := func()string{
|
||||
|
@ -1018,7 +1015,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
|||
|
||||
backButton := getBackButtonCentered(previousPage)
|
||||
|
||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||
if (err != nil) {
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
|
@ -1057,6 +1054,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
|||
totalNumberOfLoci := len(diseaseLociMap)
|
||||
totalNumberOfLociString := helpers.ConvertIntToString(totalNumberOfLoci)
|
||||
|
||||
|
||||
emptyLabelA := widget.NewLabel("")
|
||||
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
||||
|
||||
|
@ -1089,7 +1087,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
|||
viewHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setCombinedGenomesExplainerPage(window, currentPage)
|
||||
})
|
||||
|
||||
|
||||
genomeNameLabel := getBoldLabel(genomeName)
|
||||
genomeNameCell := container.NewHBox(layout.NewSpacer(), viewHelpButton, genomeNameLabel, layout.NewSpacer())
|
||||
|
||||
|
@ -1098,7 +1096,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseDetailsPage(window fyne.Window,
|
|||
|
||||
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 }
|
||||
|
||||
getRiskScoreLabelText := func()string{
|
||||
|
@ -1624,7 +1622,7 @@ func setViewPersonGeneticAnalysisPolygenicDiseaseLocusDetailsPage(window fyne.Wi
|
|||
|
||||
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 }
|
||||
|
||||
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)
|
||||
|
||||
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){
|
||||
|
||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||
if (err != nil){ return nil, err }
|
||||
|
||||
// Outputs:
|
||||
|
@ -1800,154 +1798,102 @@ func setViewPersonGeneticAnalysisDiscreteTraitsPage(window fyne.Window, personId
|
|||
mainGenomeIdentifier, err := getMainGenomeIdentifier()
|
||||
if (err != nil){ return nil, err }
|
||||
|
||||
emptyLabel1 := widget.NewLabel("")
|
||||
traitNameLabel := getItalicLabelCentered("Trait Name")
|
||||
|
||||
emptyLabel2 := widget.NewLabel("")
|
||||
predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome")
|
||||
outcomeScoresLabel := getItalicLabelCentered("Outcome Scores")
|
||||
|
||||
quantityOfLabel := getItalicLabelCentered("Quantity Of")
|
||||
lociKnownLabel := getItalicLabelCentered("Loci Known")
|
||||
|
||||
emptyLabel3 := widget.NewLabel("")
|
||||
conflictExistsLabel := getItalicLabelCentered("Conflict Exists?")
|
||||
|
||||
emptyLabel4 := widget.NewLabel("")
|
||||
emptyLabel5 := widget.NewLabel("")
|
||||
emptyLabel := widget.NewLabel("")
|
||||
|
||||
traitNameColumn := container.NewVBox(emptyLabel1, traitNameLabel, widget.NewSeparator())
|
||||
predictedOutcomeColumn := container.NewVBox(emptyLabel2, predictedOutcomeLabel, widget.NewSeparator())
|
||||
quantityOfLociKnownColumn := container.NewVBox(quantityOfLabel, lociKnownLabel, widget.NewSeparator())
|
||||
conflictExistsColumn := container.NewVBox(emptyLabel3, conflictExistsLabel, widget.NewSeparator())
|
||||
viewButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator())
|
||||
traitNameColumn := container.NewVBox(traitNameLabel, widget.NewSeparator())
|
||||
outcomeScoresColumn := container.NewVBox(outcomeScoresLabel, widget.NewSeparator())
|
||||
conflictExistsColumn := container.NewVBox(conflictExistsLabel, widget.NewSeparator())
|
||||
viewButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator())
|
||||
|
||||
traitObjectsList, err := traits.GetTraitObjectsList()
|
||||
if (err != nil) { return nil, err }
|
||||
|
||||
for _, traitObject := range traitObjectsList{
|
||||
|
||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
||||
if (traitIsDiscreteOrNumeric != "Discrete"){
|
||||
continue
|
||||
}
|
||||
|
||||
traitName := traitObject.TraitName
|
||||
traitLociList := traitObject.LociList
|
||||
traitRulesList := traitObject.RulesList
|
||||
|
||||
if (len(traitLociList) == 0 && len(traitRulesList) == 0){
|
||||
// This trait does not have any rules or loci to analyze
|
||||
if (len(traitRulesList) == 0){
|
||||
// This trait does not have any rules
|
||||
// We cannot analyze it yet
|
||||
// We will add neural network prediction so we can predict these traits
|
||||
continue
|
||||
}
|
||||
traitOutcomeNamesList := traitObject.OutcomesList
|
||||
|
||||
traitNameText := getBoldLabelCentered(traitName)
|
||||
|
||||
neuralNetworkExists, neuralNetworkAnalysisExists, neuralNetworkPredictedOutcome, _, quantityOfLociKnown_NeuralNetwork, _, anyRulesExist, rulesAnalysisExists, _, rulesPredictedOutcomeExists, rulesPredictedOutcome, _, quantityOfLociKnown_Rules, conflictExists, err := readGeneticAnalysis.GetPersonDiscreteTraitInfoFromGeneticAnalysis(analysisObject, traitName, mainGenomeIdentifier)
|
||||
_, anyTraitRuleTested, outcomeScoresMap, _, conflictExists, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(analysisObject, traitName, mainGenomeIdentifier)
|
||||
if (err != nil) { return nil, err }
|
||||
if (neuralNetworkExists == false && anyRulesExist == false){
|
||||
// We can't analyze this trait
|
||||
continue
|
||||
}
|
||||
|
||||
getPredictionLabel := func()fyne.Widget{
|
||||
|
||||
if (neuralNetworkExists == true){
|
||||
|
||||
if (neuralNetworkAnalysisExists == false){
|
||||
result := getItalicLabel("Unknown")
|
||||
return result
|
||||
}
|
||||
|
||||
result := getBoldLabel(neuralNetworkPredictedOutcome)
|
||||
|
||||
return result
|
||||
}
|
||||
// anyRulesExist must be true
|
||||
|
||||
if (rulesAnalysisExists == false || rulesPredictedOutcomeExists == false){
|
||||
result := getItalicLabel("Unknown")
|
||||
return result
|
||||
}
|
||||
|
||||
result := getBoldLabel(rulesPredictedOutcome)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
predictionLabel := getPredictionLabel()
|
||||
|
||||
predictionLabelCentered := getWidgetCentered(predictionLabel)
|
||||
|
||||
getQuantityOfLociKnown := func()int{
|
||||
|
||||
if (neuralNetworkExists == true){
|
||||
|
||||
return quantityOfLociKnown_NeuralNetwork
|
||||
}
|
||||
return quantityOfLociKnown_Rules
|
||||
}
|
||||
|
||||
quantityOfLociKnown := getQuantityOfLociKnown()
|
||||
|
||||
getTotalQuantityOfLoci := func()int{
|
||||
|
||||
if (neuralNetworkExists == true){
|
||||
|
||||
totalQuantityOfLoci := len(traitLociList)
|
||||
|
||||
return totalQuantityOfLoci
|
||||
}
|
||||
|
||||
traitLociList_Rules := traitObject.LociList_Rules
|
||||
|
||||
totalQuantityOfLoci := len(traitLociList_Rules)
|
||||
|
||||
return totalQuantityOfLoci
|
||||
}
|
||||
|
||||
totalQuantityOfLoci := getTotalQuantityOfLoci()
|
||||
|
||||
quantityOfLociKnownString := helpers.ConvertIntToString(quantityOfLociKnown)
|
||||
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
|
||||
|
||||
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
|
||||
|
||||
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
|
||||
// We add all of the columns except for the trait outcomes column, which may be multiple rows high
|
||||
|
||||
conflictExistsString := helpers.ConvertBoolToYesOrNoString(conflictExists)
|
||||
conflictExistsLabel := getBoldLabelCentered(conflictExistsString)
|
||||
|
||||
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)
|
||||
predictedOutcomeColumn.Add(predictionLabelCentered)
|
||||
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
|
||||
conflictExistsColumn.Add(conflictExistsLabel)
|
||||
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())
|
||||
predictedOutcomeColumn.Add(widget.NewSeparator())
|
||||
quantityOfLociKnownColumn.Add(widget.NewSeparator())
|
||||
outcomeScoresColumn.Add(widget.NewSeparator())
|
||||
conflictExistsColumn.Add(widget.NewSeparator())
|
||||
viewButtonsColumn.Add(widget.NewSeparator())
|
||||
}
|
||||
|
||||
predictedOutcomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
//TODO
|
||||
showUnderConstructionDialog(window)
|
||||
outcomeScoresHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setTraitOutcomeScoresExplainerPage(window, currentPage)
|
||||
})
|
||||
predictedOutcomeColumn.Add(predictedOutcomeHelpButton)
|
||||
outcomeScoresColumn.Add(outcomeScoresHelpButton)
|
||||
|
||||
quantityOfLociKnownHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
//TODO
|
||||
showUnderConstructionDialog(window)
|
||||
})
|
||||
quantityOfLociKnownColumn.Add(quantityOfLociKnownHelpButton)
|
||||
|
||||
traitsContainer := container.NewHBox(layout.NewSpacer(), traitNameColumn, predictedOutcomeColumn, quantityOfLociKnownColumn)
|
||||
traitsContainer := container.NewHBox(layout.NewSpacer(), traitNameColumn, outcomeScoresColumn)
|
||||
|
||||
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)
|
||||
|
||||
backButton := getBackButtonCentered(previousPage)
|
||||
|
||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||
allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(analysisObject)
|
||||
if (err != nil) {
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
|
@ -2014,51 +1961,33 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe
|
|||
traitInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
||||
setViewTraitDetailsPage(window, traitName, currentPage)
|
||||
})
|
||||
traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitInfoButton, layout.NewSpacer())
|
||||
|
||||
neuralNetworkExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)
|
||||
traitNameRow := container.NewHBox(layout.NewSpacer(), traitNameLabel, traitNameText, traitInfoButton, layout.NewSpacer())
|
||||
|
||||
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")
|
||||
|
||||
emptyLabel2 := widget.NewLabel("")
|
||||
predictedOutcomeLabel := getItalicLabelCentered("Predicted Outcome")
|
||||
|
||||
emptyLabel3 := widget.NewLabel("")
|
||||
predictionConfidenceLabel := getItalicLabelCentered("Prediction Confidence")
|
||||
|
||||
quantityOfLabel := getItalicLabelCentered("Quantity Of")
|
||||
|
||||
emptyLabelB := widget.NewLabel("")
|
||||
outcomeScoresLabel := getItalicLabelCentered("Outcome Scores")
|
||||
|
||||
numberOfLabel := getItalicLabelCentered("Number of")
|
||||
rulesTestedLabel := getItalicLabelCentered("Rules Tested")
|
||||
|
||||
emptyLabel4 := widget.NewLabel("")
|
||||
emptyLabel5 := 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())
|
||||
emptyLabelD := widget.NewLabel("")
|
||||
emptyLabelE := widget.NewLabel("")
|
||||
|
||||
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{
|
||||
|
||||
getGenomeNameCell := func()*fyne.Container{
|
||||
|
@ -2079,121 +2008,66 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe
|
|||
|
||||
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 (neuralNetworkExists == false && anyRulesExist == false){
|
||||
// This trait is not analyzable
|
||||
return errors.New("setViewPersonGeneticAnalysisTraitDetailsPage called with trait which cannot be analyzed via neural networks and traits.")
|
||||
}
|
||||
// We add all of the columns except for the trait rule column, which may be multiple rows high
|
||||
|
||||
getPredictedOutcomeLabel := func()fyne.Widget{
|
||||
genomeNumberOfRulesTestedString := helpers.ConvertIntToString(numberOfRulesTested)
|
||||
numberOfRulesTestedLabel := getBoldLabelCentered(genomeNumberOfRulesTestedString + "/" + totalNumberOfRulesString)
|
||||
|
||||
if (neuralNetworkExists == true){
|
||||
if (neuralNetworkAnalysisExists == false){
|
||||
|
||||
predictedOutcomeLabel := getItalicLabel("Unknown")
|
||||
|
||||
return predictedOutcomeLabel
|
||||
}
|
||||
|
||||
predictedOutcomeLabel := getBoldLabel(neuralNetworkPredictedOutcome)
|
||||
|
||||
return predictedOutcomeLabel
|
||||
}
|
||||
|
||||
// anyRulesExist must be true
|
||||
|
||||
if (rulesAnalysisExists == false || rulesPredictedOutcomeExists == false){
|
||||
|
||||
predictedOutcomeLabel := getItalicLabel("Unknown")
|
||||
return predictedOutcomeLabel
|
||||
}
|
||||
|
||||
predictedOutcomeLabel := getBoldLabel(rulesPredictedOutcome)
|
||||
|
||||
return predictedOutcomeLabel
|
||||
}
|
||||
|
||||
predictedOutcomeLabel := getPredictedOutcomeLabel()
|
||||
|
||||
predictedOutcomeLabelCentered := getWidgetCentered(predictedOutcomeLabel)
|
||||
|
||||
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)
|
||||
}
|
||||
viewRulesButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
||||
setViewPersonGenomeTraitRulesPage(window, analysisObject, traitName, genomeIdentifier, genomeName, currentPage)
|
||||
})
|
||||
|
||||
genomeNameColumn.Add(genomeNameCell)
|
||||
predictedOutcomeColumn.Add(predictedOutcomeLabelCentered)
|
||||
neuralNetworkPredictionConfidenceColumn.Add(predictedOutcomeConfidenceLabelCentered)
|
||||
numberOfRulesTestedColumn.Add(quantityOfRulesTestedLabelCentered)
|
||||
viewDetailsButtonsColumn.Add(viewDetailsButton)
|
||||
numberOfRulesTestedColumn.Add(numberOfRulesTestedLabel)
|
||||
viewRulesButtonsColumn.Add(viewRulesButton)
|
||||
|
||||
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())
|
||||
predictedOutcomeColumn.Add(widget.NewSeparator())
|
||||
neuralNetworkPredictionConfidenceColumn.Add(widget.NewSeparator())
|
||||
outcomeScoresColumn.Add(widget.NewSeparator())
|
||||
numberOfRulesTestedColumn.Add(widget.NewSeparator())
|
||||
viewDetailsButtonsColumn.Add(widget.NewSeparator())
|
||||
viewRulesButtonsColumn.Add(widget.NewSeparator())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -2238,41 +2112,17 @@ func setViewPersonGeneticAnalysisDiscreteTraitDetailsPage(window fyne.Window, pe
|
|||
if (err != nil){ return nil, err }
|
||||
}
|
||||
|
||||
if (neuralNetworkExists == true){
|
||||
|
||||
neuralNetworksHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setDiscreteTraitNeuralNetworkPredictionExplainerPage(window, currentPage)
|
||||
})
|
||||
predictedOutcomeColumn.Add(neuralNetworksHelpButton)
|
||||
} else {
|
||||
|
||||
rulesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setDiscreteTraitRulesPredictionExplainerPage(window, currentPage)
|
||||
})
|
||||
predictedOutcomeColumn.Add(rulesHelpButton)
|
||||
}
|
||||
|
||||
neuralNetworkConfidenceHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
showUnderConstructionDialog(window)
|
||||
//TODO
|
||||
outcomeScoresHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setTraitOutcomeScoresExplainerPage(window, currentPage)
|
||||
})
|
||||
neuralNetworkPredictionConfidenceColumn.Add(neuralNetworkConfidenceHelpButton)
|
||||
outcomeScoresColumn.Add(outcomeScoresHelpButton)
|
||||
|
||||
numberOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
|
||||
setTraitNumberOfRulesTestedExplainerPage(window, currentPage)
|
||||
})
|
||||
numberOfRulesTestedColumn.Add(numberOfRulesTestedHelpButton)
|
||||
|
||||
genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, predictedOutcomeColumn)
|
||||
|
||||
if (neuralNetworkExists == true){
|
||||
genomesContainer.Add(neuralNetworkPredictionConfidenceColumn)
|
||||
} else {
|
||||
genomesContainer.Add(numberOfRulesTestedColumn)
|
||||
}
|
||||
|
||||
genomesContainer.Add(viewDetailsButtonsColumn)
|
||||
genomesContainer.Add(layout.NewSpacer())
|
||||
genomesContainer := container.NewHBox(layout.NewSpacer(), genomeNameColumn, outcomeScoresColumn, numberOfRulesTestedColumn, viewRulesButtonsColumn, layout.NewSpacer())
|
||||
|
||||
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
|
||||
func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalysisObject geneticAnalysis.PersonAnalysis, traitName string, genomeIdentifier [16]byte, genomeName string, previousPage func()){
|
||||
// Ths function provides a page to view the trait rules for a particular genome from a genetic analysis
|
||||
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...")
|
||||
|
||||
currentPage := func(){setViewPersonGenomeDiscreteTraitRulesPage(window, geneticAnalysisObject, traitName, genomeIdentifier, genomeName, previousPage)}
|
||||
currentPage := func(){setViewPersonGenomeTraitRulesPage(window, geneticAnalysisObject, traitName, genomeIdentifier, genomeName, previousPage)}
|
||||
|
||||
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.")
|
||||
rulesHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setDiscreteTraitRulesExplainerPage(window, currentPage)
|
||||
setTraitRulesExplainerPage(window, currentPage)
|
||||
})
|
||||
description1Row := container.NewHBox(layout.NewSpacer(), description1, rulesHelpButton, layout.NewSpacer())
|
||||
|
||||
|
@ -2345,7 +2195,7 @@ func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalys
|
|||
return
|
||||
}
|
||||
|
||||
ruleStatusIsKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
||||
ruleStatusIsKnown, genomePassesRule, err := readGeneticAnalysis.GetPersonTraitRuleInfoFromGeneticAnalysis(geneticAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
||||
if (err != nil){
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
|
@ -2371,7 +2221,7 @@ func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalys
|
|||
rulesTestedLabel := widget.NewLabel("Rules Tested:")
|
||||
rulesTestedText := getBoldLabel(numberOfRulesTestedString + "/" + totalNumberOfRulesString)
|
||||
rulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
|
||||
setTraitNumberOfRulesTestedExplainerPage(window, currentPage)
|
||||
})
|
||||
|
||||
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)
|
||||
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 }
|
||||
|
||||
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
|
||||
|
||||
viewRuleButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
||||
setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window, geneticAnalysisObject, traitName, ruleIdentifier, currentPage)
|
||||
setViewPersonGeneticAnalysisTraitRuleDetailsPage(window, geneticAnalysisObject, traitName, ruleIdentifier, currentPage)
|
||||
})
|
||||
|
||||
ruleIdentifierColumn.Add(ruleIdentifierLabel)
|
||||
|
@ -2502,12 +2352,12 @@ func setViewPersonGenomeDiscreteTraitRulesPage(window fyne.Window, geneticAnalys
|
|||
}
|
||||
|
||||
ruleEffectsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setDiscreteTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
||||
setTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
||||
})
|
||||
ruleEffectsColumn.Add(ruleEffectsHelpButton)
|
||||
|
||||
genomePassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setGenomePassesDiscreteTraitRuleExplainerPage(window, currentPage)
|
||||
setGenomePassesTraitRuleExplainerPage(window, currentPage)
|
||||
})
|
||||
|
||||
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
|
||||
// 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)
|
||||
|
||||
|
@ -2546,13 +2396,13 @@ func setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window fyne.Window
|
|||
ruleIdentifierLabel := widget.NewLabel("Rule Identifier:")
|
||||
ruleIdentifierText := getBoldLabel(ruleIdentifierHex)
|
||||
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())
|
||||
|
||||
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 }
|
||||
|
||||
genomeNameLabel := getItalicLabelCentered("Genome Name")
|
||||
|
@ -2563,7 +2413,7 @@ func setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window fyne.Window
|
|||
|
||||
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 }
|
||||
|
||||
getGenomePassesRuleText := func()string{
|
||||
|
@ -2651,7 +2501,7 @@ func setViewPersonGeneticAnalysisDiscreteTraitRuleDetailsPage(window fyne.Window
|
|||
}
|
||||
|
||||
genomePassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setGenomePassesDiscreteTraitRuleExplainerPage(window, currentPage)
|
||||
setGenomePassesTraitRuleExplainerPage(window, currentPage)
|
||||
})
|
||||
genomePassesRuleColumn.Add(genomePassesRuleHelpButton)
|
||||
|
||||
|
|
|
@ -510,7 +510,7 @@ func setViewTraitDetailsPage(window fyne.Window, traitName string, previousPage
|
|||
}
|
||||
|
||||
traitDescription := traitObject.TraitDescription
|
||||
traitReferencesMap := traitObject.ReferencesMap
|
||||
traitReferencesMap := traitObject.References
|
||||
|
||||
traitNameLabel := widget.NewLabel("Trait Name:")
|
||||
traitNameText := getBoldLabel(traitName)
|
||||
|
@ -538,9 +538,9 @@ func setViewTraitDetailsPage(window fyne.Window, traitName string, previousPage
|
|||
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")
|
||||
|
||||
|
@ -561,7 +561,7 @@ func setViewDiscreteTraitRuleDetailsPage(window fyne.Window, traitName string, r
|
|||
}
|
||||
|
||||
ruleOutcomePointsMap := traitRuleObject.OutcomePointsMap
|
||||
ruleReferencesMap := traitRuleObject.ReferencesMap
|
||||
ruleReferencesMap := traitRuleObject.References
|
||||
|
||||
viewReferencesButton := getWidgetCentered(widget.NewButtonWithIcon("View References", theme.ListIcon(), func(){
|
||||
setViewGeneticAnalysisReferencesPage(window, "Rule", ruleReferencesMap, currentPage)
|
||||
|
@ -605,7 +605,7 @@ func setViewDiscreteTraitRuleDetailsPage(window fyne.Window, traitName string, r
|
|||
}
|
||||
|
||||
outcomeEffectHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setDiscreteTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
||||
setTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
||||
})
|
||||
outcomeEffectColumn.Add(outcomeEffectHelpButton)
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ import "fyne.io/fyne/v2/widget"
|
|||
|
||||
import "seekia/resources/worldLanguages"
|
||||
import "seekia/resources/worldLocations"
|
||||
import "seekia/resources/geneticPredictionModels"
|
||||
import "seekia/resources/geneticReferences/monogenicDiseases"
|
||||
import "seekia/resources/geneticReferences/polygenicDiseases"
|
||||
import "seekia/resources/geneticReferences/traits"
|
||||
|
@ -1271,7 +1270,7 @@ func setViewUserProfilePage_Category(window fyne.Window, profileIsMine bool, cat
|
|||
})
|
||||
|
||||
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))
|
||||
|
@ -2098,9 +2097,9 @@ func setViewMateProfilePage_RacialSimilarity(window fyne.Window, getAnyUserProfi
|
|||
if (err != nil) { return err }
|
||||
|
||||
traitLociList := traitObject.LociList
|
||||
quantityOfTraitLoci := len(traitLociList)
|
||||
numberOfTraitLoci := len(traitLociList)
|
||||
|
||||
quantityOfTraitLociString := helpers.ConvertIntToString(quantityOfTraitLoci)
|
||||
numberOfTraitLociString := helpers.ConvertIntToString(numberOfTraitLoci)
|
||||
|
||||
geneticSimilarityIsKnown, _, attributeValue, err := getAnyUserProfileAttributeFunction(geneticSimilarityAttributeName)
|
||||
if (err != nil) { return err }
|
||||
|
@ -2109,11 +2108,11 @@ func setViewMateProfilePage_RacialSimilarity(window fyne.Window, getAnyUserProfi
|
|||
|
||||
geneticSimilarityColumn.Add(unknownLabel)
|
||||
|
||||
quantityOfTestedLociText := "0/" + quantityOfTraitLociString
|
||||
numberOfTestedLociText := "0/" + numberOfTraitLociString
|
||||
|
||||
quantityOfTestedLociLabel := getBoldLabelCentered(quantityOfTestedLociText)
|
||||
numberOfTestedLociLabel := getBoldLabelCentered(numberOfTestedLociText)
|
||||
|
||||
numberOfTestedLociColumn.Add(quantityOfTestedLociLabel)
|
||||
numberOfTestedLociColumn.Add(numberOfTestedLociLabel)
|
||||
} else {
|
||||
|
||||
similarityFormatted := attributeValue + "%"
|
||||
|
@ -2148,7 +2147,7 @@ func setViewMateProfilePage_RacialSimilarity(window fyne.Window, getAnyUserProfi
|
|||
|
||||
numberOfTestedLociString := helpers.ConvertIntToString(numberOfTestedLoci)
|
||||
|
||||
numberOfTestedLociLabelText := numberOfTestedLociString + "/" + quantityOfTraitLociString
|
||||
numberOfTestedLociLabelText := numberOfTestedLociString + "/" + numberOfTraitLociString
|
||||
|
||||
numberOfTestedLociLabel := getBoldLabelCentered(numberOfTestedLociLabelText)
|
||||
|
||||
|
@ -2960,25 +2959,24 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
|||
//Outputs:
|
||||
// -map[int64]locusValue.LocusValue
|
||||
// -error
|
||||
getMyGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
||||
getMyDiseaseLocusValuesMap := 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)
|
||||
anyMyLociValuesExist, _, _, myDiseaseLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myAnalysisObject, diseaseName, myGenomeIdentifier)
|
||||
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.")
|
||||
if (anyMyLociValuesExist == false){
|
||||
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||
return emptyMap, nil
|
||||
}
|
||||
|
||||
return myGenomeLocusValuesMap, nil
|
||||
return myDiseaseLocusValuesMap, nil
|
||||
}
|
||||
|
||||
myGenomeLocusValuesMap, err := getMyGenomeLocusValuesMap()
|
||||
myDiseaseLocusValuesMap, err := getMyDiseaseLocusValuesMap()
|
||||
if (err != nil) { return nil, err }
|
||||
|
||||
// Map Structure: Locus rsID -> Locus Value
|
||||
|
@ -3033,7 +3031,7 @@ func setViewMateProfilePage_PolygenicDiseases(window fyne.Window, userOrOffsprin
|
|||
userDiseaseRiskScoreString, err := getUserDiseaseRiskScoreString()
|
||||
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 }
|
||||
|
||||
getOffspringDiseaseRiskScoreFormatted := func()(string, error){
|
||||
|
@ -3174,7 +3172,7 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
|||
// Outputs:
|
||||
// -map[int64]locusValue.LocusValue: Map Structure: Locus rsID -> Locus Value
|
||||
// -error
|
||||
getMyGenomeLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
||||
getMyDiseaseLocusValuesMap := func()(map[int64]locusValue.LocusValue, error){
|
||||
|
||||
myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis()
|
||||
if (err != nil) { return nil, err }
|
||||
|
@ -3185,18 +3183,17 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
|||
return emptyMap, nil
|
||||
}
|
||||
|
||||
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myAnalysisObject)
|
||||
anyLocusValuesExist, _, _, myLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myAnalysisObject, diseaseName, myGenomeIdentifier)
|
||||
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.")
|
||||
if (anyLocusValuesExist == false){
|
||||
emptyMap := make(map[int64]locusValue.LocusValue)
|
||||
return emptyMap, nil
|
||||
}
|
||||
|
||||
return myGenomeLocusValuesMap, nil
|
||||
return myLocusValuesMap, nil
|
||||
}
|
||||
|
||||
myGenomeLocusValuesMap, err := getMyGenomeLocusValuesMap()
|
||||
myDiseaseLocusValuesMap, err := getMyDiseaseLocusValuesMap()
|
||||
if (err != nil) {
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
|
@ -3251,7 +3248,7 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
|||
return
|
||||
}
|
||||
|
||||
anyOffspringLociTested, _, offspringNumberOfLociTested, offspringLociInfoMap, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo(diseaseLocusObjectsList, myGenomeLocusValuesMap, userDiseaseLocusValuesMap)
|
||||
anyOffspringLociTested, _, offspringNumberOfLociTested, offspringLociInfoMap, _, err := createCoupleGeneticAnalysis.GetOffspringPolygenicDiseaseInfo(diseaseLocusObjectsList, myDiseaseLocusValuesMap, userDiseaseLocusValuesMap)
|
||||
if (err != nil) {
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
|
@ -3516,9 +3513,9 @@ func setViewMateProfilePage_PolygenicDiseaseLoci(window fyne.Window, diseaseName
|
|||
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"))
|
||||
|
||||
|
@ -3526,46 +3523,7 @@ func setViewMateProfilePage_GeneticTraits(window fyne.Window, getAnyUserProfileA
|
|||
|
||||
subtitle := getPageSubtitleCentered(translate("Genetic Traits"))
|
||||
|
||||
description1 := getLabelCentered("Choose if you want to view Discrete traits or Numeric traits.")
|
||||
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.")
|
||||
description1 := getLabelCentered("Below is the 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.")
|
||||
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){
|
||||
return
|
||||
}
|
||||
setViewMateProfilePage_DiscreteGeneticTraits(window, newUserOrOffspring, getAnyUserProfileAttributeFunction, previousPage)
|
||||
setViewMateProfilePage_GeneticTraits(window, newUserOrOffspring, getAnyUserProfileAttributeFunction, previousPage)
|
||||
}
|
||||
|
||||
userOrOffspringSelector := widget.NewSelect([]string{"User", "Offspring"}, handleSelectButton)
|
||||
userOrOffspringSelector.Selected = userOrOffspring
|
||||
userOrOffspringSelector.Selected = userOrOffspring
|
||||
|
||||
userOrOffspringSelectorCentered := getWidgetCentered(userOrOffspringSelector)
|
||||
|
||||
getTraitsInfoGrid := func()(*fyne.Container, error){
|
||||
|
||||
myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis()
|
||||
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("")
|
||||
emptyLabelA := widget.NewLabel("")
|
||||
traitNameLabel := getItalicLabelCentered("Trait Name")
|
||||
|
||||
emptyLabel2 := widget.NewLabel("")
|
||||
userPredictedOutcomeTitle := getItalicLabelCentered("User Predicted Outcome")
|
||||
emptyLabelB := widget.NewLabel("")
|
||||
userOutcomeScoresLabel := getItalicLabelCentered("User Outcome Scores")
|
||||
|
||||
emptyLabel3 := widget.NewLabel("")
|
||||
offspringOutcomeProbabilitiesLabel := getItalicLabelCentered("Offspring Outcome Probabilities")
|
||||
emptyLabelC := widget.NewLabel("")
|
||||
offspringOutcomeScoresLabel := getItalicLabelCentered("Offspring Outcome Scores")
|
||||
|
||||
quantityOfLabel1 := getItalicLabelCentered("Quantity Of")
|
||||
lociKnownLabel := getItalicLabelCentered("Loci Known")
|
||||
numberOfLabelA := getItalicLabelCentered("Number Of")
|
||||
rulesTestedLabelA := getItalicLabelCentered("Rules Tested")
|
||||
|
||||
emptyLabel4 := widget.NewLabel("")
|
||||
emptyLabel5 := widget.NewLabel("")
|
||||
numberOfLabelB := getItalicLabelCentered("Number Of")
|
||||
rulesTestedLabelB := getItalicLabelCentered("Rules Tested")
|
||||
|
||||
traitNameColumn := container.NewVBox(emptyLabel1, traitNameLabel, widget.NewSeparator())
|
||||
userPredictedOutcomeColumn := container.NewVBox(emptyLabel2, userPredictedOutcomeTitle, widget.NewSeparator())
|
||||
emptyLabelD := widget.NewLabel("")
|
||||
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())
|
||||
viewTraitDetailsButtonsColumn := container.NewVBox(emptyLabel4, emptyLabel5, widget.NewSeparator())
|
||||
myPersonChosen, myGenomesExist, myAnalysisIsReady, myAnalysisObject, myGenomeIdentifier, _, err := myChosenAnalysis.GetMyChosenMateGeneticAnalysis()
|
||||
if (err != nil) { return nil, err }
|
||||
|
||||
traitObjectsList, err := traits.GetTraitObjectsList()
|
||||
if (err != nil) { return nil, err }
|
||||
|
@ -3640,39 +3575,29 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs
|
|||
for _, traitObject := range traitObjectsList{
|
||||
|
||||
traitName := traitObject.TraitName
|
||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
||||
if (traitIsDiscreteOrNumeric != "Discrete"){
|
||||
continue
|
||||
}
|
||||
|
||||
traitRulesList := traitObject.RulesList
|
||||
totalNumberOfTraitRules := len(traitRulesList)
|
||||
|
||||
traitLociList := traitObject.LociList
|
||||
|
||||
numberOfTraitLoci := len(traitLociList)
|
||||
|
||||
if (totalNumberOfTraitRules == 0 && numberOfTraitLoci == 0){
|
||||
if (totalNumberOfTraitRules == 0){
|
||||
// We are not able to analyze these traits yet
|
||||
// We will once we add neural network prediction
|
||||
continue
|
||||
}
|
||||
|
||||
traitNeuralNetworkExists, _ := geneticPredictionModels.GetGeneticPredictionModelBytes(traitName)
|
||||
if (traitNeuralNetworkExists == false && totalNumberOfTraitRules == 0){
|
||||
// We are not able to analyze these traits yet
|
||||
continue
|
||||
}
|
||||
totalNumberOfTraitRulesString := helpers.ConvertIntToString(totalNumberOfTraitRules)
|
||||
|
||||
traitOutcomeNamesList := traitObject.OutcomesList
|
||||
|
||||
// We have to sort outcome names so they always show up in the same order
|
||||
|
||||
traitOutcomeNamesListSorted := helpers.CopyAndSortStringListToUnicodeOrder(traitOutcomeNamesList)
|
||||
|
||||
traitNameText := getBoldLabelCentered(translate(traitName))
|
||||
traitNameColumn.Add(traitNameText)
|
||||
|
||||
viewTraitDetailsButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
||||
if (traitNeuralNetworkExists == true){
|
||||
//TODO
|
||||
showUnderConstructionDialog(window)
|
||||
} else {
|
||||
setViewMateProfilePage_DiscreteTraitRules(window, traitName, userOrOffspring, getAnyUserProfileAttributeFunction, currentPage)
|
||||
}
|
||||
setViewMateProfilePage_TraitRules(window, traitName, userOrOffspring, getAnyUserProfileAttributeFunction, currentPage)
|
||||
})
|
||||
|
||||
viewTraitDetailsButtonsColumn.Add(viewTraitDetailsButton)
|
||||
|
@ -3681,6 +3606,8 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs
|
|||
// Map Structure: Locus rsID -> locusValue.LocusValue
|
||||
userTraitLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||
|
||||
traitLociList := traitObject.LociList
|
||||
|
||||
for _, rsID := range traitLociList{
|
||||
|
||||
rsIDString := helpers.ConvertInt64ToString(rsID)
|
||||
|
@ -3708,244 +3635,200 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs
|
|||
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)
|
||||
if (err != nil) { return nil, err }
|
||||
if (traitNeuralNetworkExists == false){
|
||||
return nil, errors.New("GetGenomeTraitAnalysis_NeuralNetwork claims neural network doesn't exist for trait, but we already checked.")
|
||||
}
|
||||
if (anyLocusValuesAreKnown == false){
|
||||
unknownLabel := getItalicLabelCentered(translate("Unknown"))
|
||||
userPredictedOutcomeColumn.Add(unknownLabel)
|
||||
} else {
|
||||
predictedOutcomeLabel := getBoldLabelCentered(predictedOutcome)
|
||||
userPredictedOutcomeColumn.Add(predictedOutcomeLabel)
|
||||
for _, traitRuleObject := range traitRulesList{
|
||||
|
||||
ruleLociList := traitRuleObject.LociList
|
||||
|
||||
userRuleStatusIsKnown, userPassesRule, err := createPersonGeneticAnalysis.GetGenomePassesTraitRuleStatus(ruleLociList, userTraitLocusValuesMap, true)
|
||||
if (err != nil) { return false, nil, 0, err }
|
||||
if (userRuleStatusIsKnown == false){
|
||||
continue
|
||||
}
|
||||
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)
|
||||
|
||||
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(""))
|
||||
}
|
||||
userTraitOutcomeScoresMap[traitOutcome] += pointsEffect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
// We use the rules-based analysis
|
||||
for index, outcomeName := range traitOutcomeNamesListSorted{
|
||||
|
||||
anyRulesExist, rulesAnalysisExists, _, offspringQuantityOfLociKnown, _, outcomeProbabilitiesMap, err := createCoupleGeneticAnalysis.GetOffspringDiscreteTraitInfo_Rules(traitObject, myGenomeLocusValuesMap, userTraitLocusValuesMap)
|
||||
if (err != nil) { return nil, err }
|
||||
if (anyRulesExist == false){
|
||||
return nil, errors.New("GetOffspringDiscreteTraitInfo_Rules claiming that no rules exist when we already checked.")
|
||||
outcomeScore, exists := userTraitOutcomeScoresMap[outcomeName]
|
||||
if (exists == false){
|
||||
return nil, errors.New("Outcome not found in userTraitOutcomeScoresMap.")
|
||||
}
|
||||
|
||||
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)
|
||||
totalQuantityOfLociString := helpers.ConvertIntToString(totalQuantityOfLoci)
|
||||
if (offspringTraitOutcomeScoresKnown == false){
|
||||
unknownTranslated := translate("Unknown")
|
||||
unknownLabel := getBoldLabelCentered(unknownTranslated)
|
||||
|
||||
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
|
||||
quantityOfLociKnownLabel := getBoldLabelCentered(quantityOfLociKnownFormatted)
|
||||
quantityOfLociKnownColumn.Add(quantityOfLociKnownLabel)
|
||||
offspringOutcomeScoresColumn.Add(unknownLabel)
|
||||
} else {
|
||||
|
||||
if (rulesAnalysisExists == false){
|
||||
unknownLabel := getItalicLabelCentered(translate("Unknown"))
|
||||
for index, outcomeName := range traitOutcomeNamesListSorted{
|
||||
|
||||
offspringOutcomeProbabilitiesColumn.Add(unknownLabel)
|
||||
} else {
|
||||
outcomeScore, exists := offspringTraitOutcomeScoresMap[outcomeName]
|
||||
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
|
||||
slices.Sort(outcomesList)
|
||||
outcomeRow := getBoldLabelCentered(outcomeName + ": " + outcomeScoreString)
|
||||
offspringOutcomeScoresColumn.Add(outcomeRow)
|
||||
|
||||
quantityOfAddedItems := 0
|
||||
if (index > 0){
|
||||
|
||||
emptyLabelA := widget.NewLabel("")
|
||||
emptyLabelB := widget.NewLabel("")
|
||||
emptyLabelC := widget.NewLabel("")
|
||||
|
||||
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(""))
|
||||
}
|
||||
traitNameColumn.Add(emptyLabelA)
|
||||
offspringNumberOfRulesTestedColumn.Add(emptyLabelB)
|
||||
viewTraitDetailsButtonsColumn.Add(emptyLabelC)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traitNameColumn.Add(widget.NewSeparator())
|
||||
userPredictedOutcomeColumn.Add(widget.NewSeparator())
|
||||
offspringOutcomeProbabilitiesColumn.Add(widget.NewSeparator())
|
||||
quantityOfLociKnownColumn.Add(widget.NewSeparator())
|
||||
userOutcomeScoresColumn.Add(widget.NewSeparator())
|
||||
offspringOutcomeScoresColumn.Add(widget.NewSeparator())
|
||||
userNumberOfRulesTestedColumn.Add(widget.NewSeparator())
|
||||
offspringNumberOfRulesTestedColumn.Add(widget.NewSeparator())
|
||||
viewTraitDetailsButtonsColumn.Add(widget.NewSeparator())
|
||||
}
|
||||
|
||||
if (userOrOffspring == "User"){
|
||||
|
||||
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)
|
||||
userOutcomeScoresHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setTraitOutcomeScoresExplainerPage(window, currentPage)
|
||||
})
|
||||
|
||||
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"){
|
||||
|
||||
traitsInfoGrid.Add(userPredictedOutcomeColumn)
|
||||
traitsInfoGrid := container.NewHBox(layout.NewSpacer(), traitNameColumn, userOutcomeScoresColumn, userNumberOfRulesTestedColumn, viewTraitDetailsButtonsColumn, layout.NewSpacer())
|
||||
|
||||
} else {
|
||||
|
||||
// userOrOffspring == "Offspring"
|
||||
|
||||
traitsInfoGrid.Add(offspringOutcomeProbabilitiesColumn)
|
||||
return traitsInfoGrid, nil
|
||||
}
|
||||
|
||||
traitsInfoGrid.Add(quantityOfLociKnownColumn)
|
||||
traitsInfoGrid.Add(viewTraitDetailsButtonsColumn)
|
||||
traitsInfoGrid.Add(layout.NewSpacer())
|
||||
traitsInfoGrid := container.NewHBox(layout.NewSpacer(), traitNameColumn, offspringOutcomeScoresColumn, offspringNumberOfRulesTestedColumn, viewTraitDetailsButtonsColumn, layout.NewSpacer())
|
||||
|
||||
return traitsInfoGrid, nil
|
||||
}
|
||||
|
@ -3961,9 +3844,9 @@ func setViewMateProfilePage_DiscreteGeneticTraits(window fyne.Window, userOrOffs
|
|||
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")
|
||||
|
||||
|
@ -3985,7 +3868,7 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
|||
// -bool: Any trait locus value exists for this myself
|
||||
// -map[int64]locusValue.LocusValue: My locus values map
|
||||
// -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()
|
||||
if (err != nil) { return false, nil, err }
|
||||
|
@ -3995,18 +3878,17 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
|||
return false, nil, nil
|
||||
}
|
||||
|
||||
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myAnalysisObject)
|
||||
if (err != nil){ return false, nil, err }
|
||||
myTraitLocusValuesMap, _, _, _, _, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(myAnalysisObject, traitName, myGenomeIdentifier)
|
||||
if (err != nil) { return false, nil, err }
|
||||
|
||||
myGenomeMap, exists := myGenomesMap[myGenomeIdentifier]
|
||||
if (exists == false){
|
||||
return false, nil, errors.New("GetMyChosenMateGeneticAnalysis returning analysis which does not contain genome matching myGenomeIdentifier")
|
||||
if (len(myTraitLocusValuesMap) == 0){
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
return true, myGenomeMap, nil
|
||||
return true, myTraitLocusValuesMap, nil
|
||||
}
|
||||
|
||||
anyMyLocusValuesExist, myLocusValuesMap, err := getMyGenomeLocusValuesMap()
|
||||
anyMyTraitLocusValuesExist, myTraitLocusValuesMap, err := getMyTraitLocusValuesMap()
|
||||
if (err != nil){
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
|
@ -4018,14 +3900,9 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
|||
return
|
||||
}
|
||||
|
||||
traitLociList_Rules := traitObject.LociList_Rules
|
||||
traitLociList := traitObject.LociList
|
||||
traitRulesList := traitObject.RulesList
|
||||
|
||||
if (len(traitRulesList) == 0){
|
||||
setErrorEncounteredPage(window, errors.New("setViewMateProfilePage_DiscreteTraitRules called with trait which has no rules."), previousPage)
|
||||
return
|
||||
}
|
||||
|
||||
//Outputs:
|
||||
// -bool: Any trait locus value exists for this user
|
||||
// -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
|
||||
userTraitLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||
|
||||
for _, rsID := range traitLociList_Rules{
|
||||
for _, rsID := range traitLociList{
|
||||
|
||||
rsIDString := helpers.ConvertInt64ToString(rsID)
|
||||
|
||||
|
@ -4082,15 +3959,12 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
|||
// -error
|
||||
getOffspringProbabilityOfPassingRulesMap := func()(bool, map[[3]byte]int, error){
|
||||
|
||||
if (anyMyLocusValuesExist == false || anyUserTraitLocusValueExists == false){
|
||||
if (anyMyTraitLocusValuesExist == false || anyUserTraitLocusValueExists == false){
|
||||
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 (anyRulesExist == false){
|
||||
return false, nil, errors.New("GetOffspringDiscreteTraitInfo claiming no trait rules exist when we already checked.")
|
||||
}
|
||||
if (anyOffspringRulesTested == false){
|
||||
return false, nil, nil
|
||||
}
|
||||
|
@ -4126,7 +4000,7 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
|||
|
||||
ruleLociList := ruleObject.LociList
|
||||
|
||||
ruleStatusIsKnown, _, err := createPersonGeneticAnalysis.GetGenomePassesDiscreteTraitRuleStatus(ruleLociList, userTraitLocusValuesMap, true)
|
||||
ruleStatusIsKnown, _, err := createPersonGeneticAnalysis.GetGenomePassesTraitRuleStatus(ruleLociList, userTraitLocusValuesMap, true)
|
||||
if (err != nil) { return 0, err }
|
||||
if (ruleStatusIsKnown == true){
|
||||
numberOfRulesTested += 1
|
||||
|
@ -4153,9 +4027,9 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
|||
|
||||
numberOfRulesTestedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
if (userOrOffspring == "User"){
|
||||
setDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
|
||||
setTraitNumberOfRulesTestedExplainerPage(window, currentPage)
|
||||
} else {
|
||||
setOffspringDiscreteTraitQuantityOfRulesTestedExplainerPage(window, currentPage)
|
||||
setOffspringTraitNumberOfRulesTestedExplainerPage(window, currentPage)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -4219,7 +4093,7 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
|||
|
||||
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 (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
|
||||
|
||||
viewRuleInfoButton := widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
||||
setViewDiscreteTraitRuleDetailsPage(window, traitName, ruleIdentifierHex, currentPage)
|
||||
setViewTraitRuleDetailsPage(window, traitName, ruleIdentifierHex, currentPage)
|
||||
})
|
||||
ruleIdentifierLabel := getBoldLabelCentered(ruleIdentifierHex)
|
||||
userPassesRuleLabel := getBoldLabelCentered(userPassesRuleString)
|
||||
|
@ -4326,11 +4200,11 @@ func setViewMateProfilePage_DiscreteTraitRules(window fyne.Window, traitName str
|
|||
}
|
||||
|
||||
ruleEffectsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setDiscreteTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
||||
setTraitRuleOutcomeEffectsExplainerPage(window, currentPage)
|
||||
})
|
||||
|
||||
userPassesRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
setPersonPassesDiscreteTraitRuleExplainerPage(window, currentPage)
|
||||
setPersonPassesTraitRuleExplainerPage(window, currentPage)
|
||||
})
|
||||
|
||||
offspringProbabilityOfPassingRuleHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||||
|
@ -4617,29 +4491,29 @@ func get23andMeAncestryCompositionDisplay(inputContinentPercentagesMap map[strin
|
|||
// We sort region subregions list
|
||||
// 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.")
|
||||
}
|
||||
|
||||
subregion1Percentage, exists := subregionDescriptionPercentagesMap[subregion1Description]
|
||||
subregionAPercentage, exists := subregionDescriptionPercentagesMap[subregionADescription]
|
||||
if (exists == false){
|
||||
panic("subregionPercentagesMap missing subregion during sort.")
|
||||
}
|
||||
|
||||
subregion2Percentage, exists := subregionDescriptionPercentagesMap[subregion2Description]
|
||||
subregionBPercentage, exists := subregionDescriptionPercentagesMap[subregionBDescription]
|
||||
if (exists == false){
|
||||
panic("subregionPercentagesMap missing subregion during sort.")
|
||||
}
|
||||
if (subregion1Percentage == subregion2Percentage){
|
||||
if (subregionAPercentage == subregionBPercentage){
|
||||
// We sort subregions in unicode order
|
||||
if (subregion1Description < subregion2Description){
|
||||
if (subregionADescription < subregionBDescription){
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
if (subregion1Percentage > subregion2Percentage){
|
||||
if (subregionAPercentage > subregionBPercentage){
|
||||
return -1
|
||||
}
|
||||
|
||||
|
@ -4653,33 +4527,32 @@ func get23andMeAncestryCompositionDisplay(inputContinentPercentagesMap map[strin
|
|||
|
||||
// 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.")
|
||||
}
|
||||
|
||||
region1Percentage, exists := regionDescriptionPercentagesMap[region1Description]
|
||||
regionAPercentage, exists := regionDescriptionPercentagesMap[regionADescription]
|
||||
if (exists == false){
|
||||
panic("regionPercentagesMap missing subregion during sort.")
|
||||
}
|
||||
|
||||
region2Percentage, exists := regionDescriptionPercentagesMap[region2Description]
|
||||
|
||||
regionBPercentage, exists := regionDescriptionPercentagesMap[regionBDescription]
|
||||
if (exists == false){
|
||||
panic("regionPercentagesMap missing subregion during sort.")
|
||||
}
|
||||
if (region1Percentage == region2Percentage){
|
||||
if (regionAPercentage == regionBPercentage){
|
||||
// We sort regions in unicode order
|
||||
if (region1Description < region2Description){
|
||||
if (regionADescription < regionBDescription){
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
if (region1Percentage > region2Percentage){
|
||||
if (regionAPercentage > regionBPercentage){
|
||||
return -1
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
|
@ -4690,29 +4563,29 @@ func get23andMeAncestryCompositionDisplay(inputContinentPercentagesMap map[strin
|
|||
|
||||
// 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.")
|
||||
}
|
||||
|
||||
continent1Percentage, exists := continentDescriptionPercentagesMap[continent1Description]
|
||||
continentAPercentage, exists := continentDescriptionPercentagesMap[continentADescription]
|
||||
if (exists == false){
|
||||
panic("Continent percentage not found when sorting root list.")
|
||||
}
|
||||
|
||||
continent2Percentage, exists := continentDescriptionPercentagesMap[continent2Description]
|
||||
continentBPercentage, exists := continentDescriptionPercentagesMap[continentBDescription]
|
||||
if (exists == false){
|
||||
panic("Continent percentage not found when sorting root list.")
|
||||
}
|
||||
if (continent1Percentage == continent2Percentage){
|
||||
if (continentAPercentage == continentBPercentage){
|
||||
// We sort continents in unicode order
|
||||
if (continent1Description < continent2Description){
|
||||
if (continentADescription < continentBDescription){
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
if (continent1Percentage > continent2Percentage){
|
||||
if (continentAPercentage > continentBPercentage){
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
|
|
|
@ -932,7 +932,7 @@ func GetFakeProfile(profileType string, identityPublicKey [32]byte, identityPriv
|
|||
|
||||
traitLociList := traitObject.LociList
|
||||
|
||||
for _, rsID := range traitLociList{
|
||||
for _, rsID := range traitLociList{
|
||||
|
||||
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.
|
||||
|
||||
// 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 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/monogenicDiseases"
|
||||
import "seekia/resources/geneticReferences/polygenicDiseases"
|
||||
|
@ -29,7 +40,6 @@ import "errors"
|
|||
import mathRand "math/rand/v2"
|
||||
import "slices"
|
||||
import "maps"
|
||||
import "reflect"
|
||||
|
||||
|
||||
//Outputs:
|
||||
|
@ -76,30 +86,6 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
|||
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 gui will display the results from each pair
|
||||
//Outputs:
|
||||
|
@ -186,9 +172,9 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
|||
person2DiseaseAnalysisObject, err := createPersonGeneticAnalysis.GetPersonMonogenicDiseaseAnalysis(person2GenomesWithMetadataList, diseaseObject)
|
||||
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
|
||||
quantityOfVariantsTestedMap := make(map[[16]byte]int)
|
||||
numberOfVariantsTestedMap := make(map[[16]byte]int)
|
||||
|
||||
// This map stores the offspring disease probabilities for each genome pair.
|
||||
// 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
|
||||
// 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{
|
||||
|
||||
//Outputs:
|
||||
|
@ -216,9 +202,9 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
|||
|
||||
personGenomeProbabilityOfPassingADiseaseVariant := personGenomeDiseaseInfoObject.ProbabilityOfPassingADiseaseVariant
|
||||
|
||||
personGenomeQuantityOfVariantsTested := personGenomeDiseaseInfoObject.QuantityOfVariantsTested
|
||||
personGenomeNumberOfVariantsTested := personGenomeDiseaseInfoObject.NumberOfVariantsTested
|
||||
|
||||
return true, personGenomeProbabilityOfPassingADiseaseVariant, personGenomeQuantityOfVariantsTested
|
||||
return true, personGenomeProbabilityOfPassingADiseaseVariant, personGenomeNumberOfVariantsTested
|
||||
}
|
||||
|
||||
person1ProbabilityIsKnown, person1WillPassVariantProbability, person1NumberOfVariantsTested := getPersonWillPassDiseaseVariantProbability(person1DiseaseAnalysisObject, person1GenomeIdentifier)
|
||||
|
@ -376,8 +362,8 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
|||
return nil
|
||||
}
|
||||
|
||||
quantityOfVariantsTestedMap[person1GenomeIdentifier] = person1NumberOfVariantsTested
|
||||
quantityOfVariantsTestedMap[person2GenomeIdentifier] = person2NumberOfVariantsTested
|
||||
numberOfVariantsTestedMap[person1GenomeIdentifier] = person1NumberOfVariantsTested
|
||||
numberOfVariantsTestedMap[person2GenomeIdentifier] = person2NumberOfVariantsTested
|
||||
|
||||
newOffspringGenomePairMonogenicDiseaseInfoObject := geneticAnalysis.OffspringGenomePairMonogenicDiseaseInfo{
|
||||
ProbabilityOffspringHasDiseaseIsKnown: offspringHasDiseaseProbabilityIsKnown,
|
||||
|
@ -404,7 +390,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
|||
}
|
||||
|
||||
newOffspringMonogenicDiseaseInfoObject := geneticAnalysis.OffspringMonogenicDiseaseInfo{
|
||||
QuantityOfVariantsTestedMap: quantityOfVariantsTestedMap,
|
||||
NumberOfVariantsTestedMap: numberOfVariantsTestedMap,
|
||||
MonogenicDiseaseInfoMap: offspringMonogenicDiseaseInfoMap,
|
||||
}
|
||||
|
||||
|
@ -494,6 +480,12 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
|||
diseaseName := diseaseObject.DiseaseName
|
||||
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
|
||||
// Map Structure: Genome Pair Identifier -> 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
|
||||
addGenomePairDiseaseInfoToDiseaseMap := func(person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
||||
|
||||
person1LocusValuesMap, exists := person1GenomesMap[person1GenomeIdentifier]
|
||||
if (exists == false){
|
||||
return errors.New("addGenomePairDiseaseInfoToDiseaseMap called with unknown person1GenomeIdentifier.")
|
||||
//Outputs:
|
||||
// -bool: Any locus values exist
|
||||
// -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]
|
||||
if (exists == false){
|
||||
return errors.New("addGenomePairDiseaseInfoToDiseaseMap called with unknown person2GenomeIdentifier.")
|
||||
anyPerson1LociValuesExist, person1LocusValuesMap, err := getPersonGenomeDiseaseLocusValuesMap(person1GenomeIdentifier, person1DiseaseAnalysisObject)
|
||||
if (err != nil) { return err }
|
||||
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 (anyOffspringLocusTested == false){
|
||||
// We have no information about this genome pair's disease risk
|
||||
|
@ -522,7 +537,7 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
|||
|
||||
newOffspringGenomePairPolygenicDiseaseInfo := geneticAnalysis.OffspringGenomePairPolygenicDiseaseInfo{
|
||||
|
||||
QuantityOfLociTested: quantityOfLociTested,
|
||||
NumberOfLociTested: numberOfLociTested,
|
||||
OffspringAverageRiskScore: genomePairOffspringAverageRiskScore,
|
||||
LociInfoMap: genomePairOffspringDiseaseLociInfoMap,
|
||||
SampleOffspringRiskScoresList: genomePairSampleOffspringRiskScoresList,
|
||||
|
@ -555,20 +570,34 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
|||
|
||||
checkIfConflictExists := func()(bool, error){
|
||||
|
||||
currentGenomePairPolygenicDiseaseInfo := geneticAnalysis.OffspringGenomePairPolygenicDiseaseInfo{}
|
||||
numberOfLociTested := 0
|
||||
offspringAverageRiskScore := 0
|
||||
offspringLociInfoMap := make(map[[3]byte]geneticAnalysis.OffspringPolygenicDiseaseLocusInfo)
|
||||
|
||||
firstItemReached := false
|
||||
|
||||
for _, genomePairDiseaseInfoObject := range offspringPolygenicDiseaseInfoMap{
|
||||
|
||||
genomePairNumberOfLociTested := genomePairDiseaseInfoObject.NumberOfLociTested
|
||||
genomePairOffspringAverageRiskScore := genomePairDiseaseInfoObject.OffspringAverageRiskScore
|
||||
genomePairLociInfoMap := genomePairDiseaseInfoObject.LociInfoMap
|
||||
|
||||
if (firstItemReached == false){
|
||||
currentGenomePairPolygenicDiseaseInfo = genomePairDiseaseInfoObject
|
||||
numberOfLociTested = genomePairNumberOfLociTested
|
||||
offspringAverageRiskScore = genomePairOffspringAverageRiskScore
|
||||
offspringLociInfoMap = genomePairLociInfoMap
|
||||
firstItemReached = true
|
||||
continue
|
||||
}
|
||||
|
||||
areEqual := reflect.DeepEqual(genomePairDiseaseInfoObject, currentGenomePairPolygenicDiseaseInfo)
|
||||
if (numberOfLociTested != genomePairNumberOfLociTested){
|
||||
return true, nil
|
||||
}
|
||||
if (offspringAverageRiskScore != genomePairOffspringAverageRiskScore){
|
||||
return true, nil
|
||||
}
|
||||
areEqual := maps.Equal(offspringLociInfoMap, genomePairLociInfoMap)
|
||||
if (areEqual == false){
|
||||
// A conflict exists
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
@ -593,140 +622,128 @@ func CreateCoupleGeneticAnalysis(person1GenomesList []prepareRawGenomes.RawGenom
|
|||
if (err != nil) { return false, "", err }
|
||||
|
||||
// Map Structure: Trait Name -> Trait Info Object
|
||||
offspringDiscreteTraitsMap := make(map[string]geneticAnalysis.OffspringDiscreteTraitInfo)
|
||||
|
||||
// Map Structure: Trait Name -> Trait Info Object
|
||||
offspringNumericTraitsMap := make(map[string]geneticAnalysis.OffspringNumericTraitInfo)
|
||||
offspringTraitsMap := make(map[string]geneticAnalysis.OffspringTraitInfo)
|
||||
|
||||
for _, traitObject := range traitObjectsList{
|
||||
|
||||
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
|
||||
// Map Structure: Genome Pair Identifier -> OffspringGenomePairDiscreteTraitInfo
|
||||
offspringTraitInfoMap := make(map[[32]byte]geneticAnalysis.OffspringGenomePairDiscreteTraitInfo)
|
||||
person2TraitAnalysisObject, err := createPersonGeneticAnalysis.GetPersonTraitAnalysis(person2GenomesWithMetadataList, traitObject)
|
||||
if (err != nil) { return false, "", err }
|
||||
|
||||
// This will add the offspring trait information for the provided genome pair to the offspringTraitInfoMap
|
||||
addGenomePairTraitInfoToOffspringMap := func(person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
||||
// This map stores the trait info for each genome pair
|
||||
// Map Structure: Genome Pair Identifier -> OffspringGenomePairTraitInfo
|
||||
offspringTraitInfoMap := make(map[[32]byte]geneticAnalysis.OffspringGenomePairTraitInfo)
|
||||
|
||||
person1LocusValuesMap, exists := person1GenomesMap[person1GenomeIdentifier]
|
||||
if (exists == false){
|
||||
return errors.New("addGenomePairTraitInfoToOffspringMap called with unknown person1GenomeIdentifier.")
|
||||
}
|
||||
// This will add the offspring trait information for the provided genome pair to the offspringTraitInfoMap
|
||||
addGenomePairTraitInfoToOffspringMap := func(person1GenomeIdentifier [16]byte, person2GenomeIdentifier [16]byte)error{
|
||||
|
||||
person2LocusValuesMap, exists := person2GenomesMap[person2GenomeIdentifier]
|
||||
if (exists == false){
|
||||
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
|
||||
person1TraitInfoMap := person1TraitAnalysisObject.TraitInfoMap
|
||||
person2TraitInfoMap := person2TraitAnalysisObject.TraitInfoMap
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 (genomePair2Exists == true){
|
||||
newOffspringTraitInfoObject := geneticAnalysis.OffspringTraitInfo{
|
||||
TraitInfoMap: offspringTraitInfoMap,
|
||||
}
|
||||
|
||||
err := addGenomePairTraitInfoToOffspringMap(pair2Person1GenomeIdentifier, pair2Person2GenomeIdentifier)
|
||||
if (err != nil) { return false, "", err }
|
||||
}
|
||||
if (len(offspringTraitInfoMap) >= 2){
|
||||
|
||||
newOffspringTraitInfoObject := geneticAnalysis.OffspringDiscreteTraitInfo{
|
||||
TraitInfoMap: offspringTraitInfoMap,
|
||||
}
|
||||
// We check for conflicts
|
||||
// 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
|
||||
// Conflicts are only possible if two genome pairs exist with information about the trait
|
||||
// We check for conflicts between each genome pair's outcome scores and trait rules maps
|
||||
|
||||
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){
|
||||
genomePairTraitInfoObject = currentGenomePairTraitInfoObject
|
||||
firstItemReached = true
|
||||
continue
|
||||
}
|
||||
|
||||
areEqual := reflect.DeepEqual(genomePairTraitInfoObject, currentGenomePairTraitInfoObject)
|
||||
if (areEqual == false){
|
||||
return true, nil
|
||||
}
|
||||
firstItemReached = true
|
||||
continue
|
||||
}
|
||||
|
||||
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()
|
||||
if (err != nil) { return false, "", err }
|
||||
|
||||
newOffspringTraitInfoObject.ConflictExists = conflictExists
|
||||
return false, nil
|
||||
}
|
||||
|
||||
offspringDiscreteTraitsMap[traitName] = newOffspringTraitInfoObject
|
||||
conflictExists, err := checkIfConflictExists()
|
||||
if (err != nil) { return false, "", err }
|
||||
|
||||
newOffspringTraitInfoObject.ConflictExists = conflictExists
|
||||
}
|
||||
|
||||
offspringTraitsMap[traitName] = newOffspringTraitInfoObject
|
||||
}
|
||||
|
||||
newCoupleAnalysis.DiscreteTraitsMap = offspringDiscreteTraitsMap
|
||||
newCoupleAnalysis.NumericTraitsMap = offspringNumericTraitsMap
|
||||
newCoupleAnalysis.TraitsMap = offspringTraitsMap
|
||||
|
||||
analysisBytes, err := encoding.EncodeMessagePackBytes(newCoupleAnalysis)
|
||||
if (err != nil) { return false, "", err }
|
||||
|
@ -1119,187 +1136,144 @@ func GetOffspringPolygenicDiseaseInfo(diseaseLociList []polygenicDiseases.Diseas
|
|||
|
||||
|
||||
//Outputs:
|
||||
// -bool: A neural network exists for this trait
|
||||
// -bool: Analysis exists (at least 1 locus exists for this analysis from both people's genomes
|
||||
// -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
|
||||
// -bool: Any rules tested (if false, no offspring trait information is known)
|
||||
// -int: Number of rules tested
|
||||
// -map[[3]byte]int: Offspring probability of passing rules map
|
||||
// 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]int: Offspring outcome probabilities map
|
||||
// Map Structure: Outcome Name -> Offspring probability of outcome (0-100)
|
||||
// -map[string]float64: Offspring average outcome scores map
|
||||
// Map Structure: Outcome Name -> Offspring average outcome score
|
||||
// -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){
|
||||
|
||||
traitRulesList := traitObject.RulesList
|
||||
|
||||
if (len(traitRulesList) == 0){
|
||||
return false, false, 0, 0, nil, nil, nil
|
||||
}
|
||||
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){
|
||||
|
||||
if (len(person1LocusValuesMap) == 0){
|
||||
return true, false, 0, 0, nil, nil, nil
|
||||
return false, 0, nil, nil, nil
|
||||
}
|
||||
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.
|
||||
|
||||
traitLociList_Rules := traitObject.LociList_Rules
|
||||
traitLociList := traitObject.LociList
|
||||
|
||||
anyLocusValueExists, prospectiveOffspringGenomesList, err := getProspectiveOffspringGenomesList(traitLociList_Rules, person1LocusValuesMap, person2LocusValuesMap)
|
||||
if (err != nil) { return false, false, 0, 0, nil, nil, err }
|
||||
anyLocusValueExists, prospectiveOffspringGenomesList, err := getProspectiveOffspringGenomesList(traitLociList, person1LocusValuesMap, person2LocusValuesMap)
|
||||
if (err != nil) { return false, 0, nil, nil, err }
|
||||
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)
|
||||
// Because there are 100 offspring, this also represents the percentage probability that an offspring will pass the rule
|
||||
offspringPassesRulesCountMap := make(map[[3]byte]int)
|
||||
|
||||
// This map stores the quantity of offspring who have each outcome
|
||||
// The probability an offspring will have this outcome is the same as the
|
||||
// quantity of offspring who have this outcome in our set of 100 randomly generated offspring
|
||||
// Map structure: Outcome name -> quantity of offspring who have this outcome
|
||||
outcomeCountsMap := make(map[string]int)
|
||||
// We use this map to keep track of the rules for which we know every offspring's passes-rule status
|
||||
// Map Structure: Rule Identifier -> Rule Object
|
||||
offspringRulesWithKnownStatusMap := make(map[[3]byte]traits.TraitRule)
|
||||
|
||||
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)
|
||||
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
|
||||
}
|
||||
ruleIdentifierHex := ruleObject.RuleIdentifier
|
||||
|
||||
for ruleIdentifier, genomePassesRule := range offspringPassesRulesMap{
|
||||
if (genomePassesRule == true){
|
||||
ruleIdentifier, err := encoding.DecodeHexStringTo3ByteArray(ruleIdentifierHex)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
//
|
||||
// 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:
|
||||
// -bool: Any locus value exists between both users
|
||||
// -[]map[int64]locusValue.LocusValue
|
||||
|
@ -1418,7 +1388,7 @@ func getProspectiveOffspringGenomesList(lociList []int64, person1LociMap map[int
|
|||
|
||||
// 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
|
||||
for position := int64(0); position < chromosomeLength; position += 1_000_000{
|
||||
for position := int64(0); position <= chromosomeLength; position += 1000000{
|
||||
|
||||
//From Wikipedia:
|
||||
// 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
|
||||
personLocusBase2 := personLocusValue.Base2Value
|
||||
personLocusBase2 := personLocusValue.Base1Value
|
||||
personLocusIsPhased := personLocusValue.LocusIsPhased
|
||||
|
||||
if (personLocusBase1 == personLocusBase2){
|
||||
// Phase doesn't matter
|
||||
return true, personLocusBase1, nil
|
||||
}
|
||||
|
||||
if (personLocusIsPhased == false){
|
||||
// Breakpoints are unnecessary
|
||||
// We either choose base 1 or 2
|
||||
randomInt := pseudorandomNumberGenerator.IntN(2)
|
||||
if (randomInt == 1){
|
||||
randomBool := helpers.GetRandomBool()
|
||||
if (randomBool == true){
|
||||
return true, personLocusBase1, nil
|
||||
}
|
||||
return true, personLocusBase2, nil
|
||||
|
@ -1525,9 +1490,9 @@ func getProspectiveOffspringGenomesList(lociList []int64, person1LociMap map[int
|
|||
|
||||
getLocusListIndex := func()int{
|
||||
|
||||
for index, breakpointPosition := range personBreakpointsList{
|
||||
for index, breakpoint := range personBreakpointsList{
|
||||
|
||||
if (int64(locusPosition) <= breakpointPosition){
|
||||
if (int64(locusPosition) <= breakpoint){
|
||||
|
||||
return index
|
||||
}
|
||||
|
|
|
@ -22,14 +22,13 @@ import "seekia/resources/geneticReferences/traits"
|
|||
|
||||
import "seekia/internal/encoding"
|
||||
import "seekia/internal/genetics/geneticAnalysis"
|
||||
import "seekia/internal/genetics/geneticPrediction"
|
||||
import "seekia/internal/genetics/locusValue"
|
||||
import "seekia/internal/genetics/prepareRawGenomes"
|
||||
import "seekia/internal/helpers"
|
||||
|
||||
import "errors"
|
||||
import "slices"
|
||||
import "reflect"
|
||||
import "maps"
|
||||
|
||||
|
||||
//Outputs:
|
||||
|
@ -52,23 +51,10 @@ func CreatePersonGeneticAnalysis(genomesList []prepareRawGenomes.RawGenomeWithMe
|
|||
genomesWithMetadataList, allRawGenomeIdentifiersList, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := prepareRawGenomes.GetGenomesWithMetadataListFromRawGenomesList(genomesList, prepareRawGenomesUpdatePercentageCompleteFunction)
|
||||
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{
|
||||
AnalysisVersion: 1,
|
||||
CombinedGenomesExist: multipleGenomesExist,
|
||||
AllRawGenomeIdentifiersList: allRawGenomeIdentifiersList,
|
||||
GenomesMap: genomesMap,
|
||||
}
|
||||
|
||||
if (multipleGenomesExist == true){
|
||||
|
@ -121,30 +107,20 @@ func CreatePersonGeneticAnalysis(genomesList []prepareRawGenomes.RawGenomeWithMe
|
|||
traitObjectsList, err := traits.GetTraitObjectsList()
|
||||
if (err != nil) { return false, "", err }
|
||||
|
||||
// This map will always contain an entry for each discrete trait
|
||||
// Map Structure: Trait Name -> PersonDiscreteTraitInfo
|
||||
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)
|
||||
// Map Structure: Trait Name -> PersonTraitInfo
|
||||
analysisTraitsMap := make(map[string]geneticAnalysis.PersonTraitInfo)
|
||||
|
||||
for _, traitObject := range traitObjectsList{
|
||||
|
||||
personTraitAnalysisObject, err := GetPersonTraitAnalysis(genomesWithMetadataList, traitObject)
|
||||
if (err != nil) { return false, "", err }
|
||||
|
||||
traitName := traitObject.TraitName
|
||||
traitIsDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
||||
|
||||
if (traitIsDiscreteOrNumeric == "Discrete"){
|
||||
|
||||
personTraitAnalysisObject, err := GetPersonDiscreteTraitAnalysis(genomesWithMetadataList, traitObject)
|
||||
if (err != nil) { return false, "", err }
|
||||
|
||||
analysisDiscreteTraitsMap[traitName] = personTraitAnalysisObject
|
||||
}
|
||||
analysisTraitsMap[traitName] = personTraitAnalysisObject
|
||||
}
|
||||
|
||||
newGeneticAnalysisObject.DiscreteTraitsMap = analysisDiscreteTraitsMap
|
||||
newGeneticAnalysisObject.NumericTraitsMap = analysisNumericTraitsMap
|
||||
newGeneticAnalysisObject.TraitsMap = analysisTraitsMap
|
||||
|
||||
analysisBytes, err := encoding.EncodeMessagePackBytes(newGeneticAnalysisObject)
|
||||
if (err != nil) { return false, "", err }
|
||||
|
@ -529,9 +505,9 @@ func GetPersonMonogenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
|
|||
|
||||
diseaseAnalysisObject := geneticAnalysis.PersonGenomeMonogenicDiseaseInfo{
|
||||
PersonHasDisease: personHasDisease,
|
||||
QuantityOfVariantsTested: numberOfVariantsTested,
|
||||
QuantityOfLociTested: numberOfLociTested,
|
||||
QuantityOfPhasedLoci: numberOfPhasedLoci,
|
||||
NumberOfVariantsTested: numberOfVariantsTested,
|
||||
NumberOfLociTested: numberOfLociTested,
|
||||
NumberOfPhasedLoci: numberOfPhasedLoci,
|
||||
ProbabilityOfPassingADiseaseVariant: percentageProbabilityPersonWillPassADiseaseVariant,
|
||||
VariantsInfoMap: variantsInfoMap,
|
||||
}
|
||||
|
@ -761,15 +737,16 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
|
|||
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 (anyLociTested == false){
|
||||
continue
|
||||
}
|
||||
|
||||
newDiseaseInfoObject := geneticAnalysis.PersonGenomePolygenicDiseaseInfo{
|
||||
QuantityOfLociTested: genomeNumberOfLociTested,
|
||||
NumberOfLociTested: genomeNumberOfLociTested,
|
||||
RiskScore: personDiseaseRiskScore,
|
||||
LocusValuesMap: genomeLocusValuesMap,
|
||||
LociInfoMap: genomeLociInfoMap,
|
||||
}
|
||||
|
||||
|
@ -800,7 +777,7 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
|
|||
for _, personGenomeDiseaseInfoObject := range personPolygenicDiseaseInfoMap{
|
||||
|
||||
currentGenomeRiskScore := personGenomeDiseaseInfoObject.RiskScore
|
||||
currentGenomeNumberOfLociTested := personGenomeDiseaseInfoObject.QuantityOfLociTested
|
||||
currentGenomeNumberOfLociTested := personGenomeDiseaseInfoObject.NumberOfLociTested
|
||||
|
||||
if (firstItemReached == false){
|
||||
genomeRiskScore = currentGenomeRiskScore
|
||||
|
@ -878,68 +855,106 @@ func GetPersonPolygenicDiseaseAnalysis(inputGenomesWithMetadataList []prepareRaw
|
|||
|
||||
|
||||
//Outputs:
|
||||
// -geneticAnalysis.PersonDiscreteTraitInfo: Trait analysis object
|
||||
// -geneticAnalysis.PersonTraitInfo: Trait analysis object
|
||||
// -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
|
||||
newPersonTraitInfoMap := make(map[[16]byte]geneticAnalysis.PersonGenomeDiscreteTraitInfo)
|
||||
// We use this when returning errors
|
||||
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{
|
||||
|
||||
genomeIdentifier := genomeWithMetadataObject.GenomeIdentifier
|
||||
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)
|
||||
if (err != nil) { return geneticAnalysis.PersonDiscreteTraitInfo{}, err }
|
||||
if (neuralNetworkExists == true){
|
||||
for _, locusRSID := range traitLociList{
|
||||
|
||||
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,
|
||||
PredictionConfidence: predictionConfidence,
|
||||
QuantityOfLociKnown: quantityOfLociTested,
|
||||
QuantityOfPhasedLoci: quantityOfPhasedLoci,
|
||||
if (len(traitRulesList) != 0){
|
||||
|
||||
// At least 1 rule exists for this trait
|
||||
|
||||
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)
|
||||
if (err != nil) { return geneticAnalysis.PersonDiscreteTraitInfo{}, err }
|
||||
if (anyRulesExist == true){
|
||||
newPersonGenomeTraitInfo.AnyRulesExist = true
|
||||
traitOutcomesList := traitObject.OutcomesList
|
||||
|
||||
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{
|
||||
|
||||
GenomePassesRulesMap: genomePassesRulesMap,
|
||||
PredictedOutcomeExists: predictedOutcomeExists,
|
||||
PredictedOutcome: predictedOutcome,
|
||||
QuantityOfRulesTested: quantityOfRulesTested,
|
||||
QuantityOfLociKnown: quantityOfLociKnown,
|
||||
}
|
||||
|
||||
newPersonGenomeTraitInfo.RulesAnalysis = newPersonGenomeTraitInfo_Rules
|
||||
_, exists := traitOutcomeScoresMap[traitOutcome]
|
||||
if (exists == false){
|
||||
traitOutcomeScoresMap[traitOutcome] = 0
|
||||
}
|
||||
}
|
||||
|
||||
numberOfRulesTested := len(personPassesRulesMap)
|
||||
|
||||
newPersonGenomeTraitInfo := geneticAnalysis.PersonGenomeTraitInfo{
|
||||
NumberOfRulesTested: numberOfRulesTested,
|
||||
LocusValuesMap: genomeLocusValuesMap,
|
||||
OutcomeScoresMap: traitOutcomeScoresMap,
|
||||
GenomePassesRulesMap: personPassesRulesMap,
|
||||
}
|
||||
|
||||
newPersonTraitInfoMap[genomeIdentifier] = newPersonGenomeTraitInfo
|
||||
}
|
||||
|
||||
newPersonTraitInfoObject := geneticAnalysis.PersonDiscreteTraitInfo{
|
||||
newPersonTraitInfoObject := geneticAnalysis.PersonTraitInfo{
|
||||
TraitInfoMap: newPersonTraitInfoMap,
|
||||
}
|
||||
|
||||
|
@ -953,20 +968,40 @@ func GetPersonDiscreteTraitAnalysis(inputGenomesWithMetadataList []prepareRawGen
|
|||
|
||||
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
|
||||
personGenomeTraitInfoObject := geneticAnalysis.PersonGenomeDiscreteTraitInfo{}
|
||||
|
||||
outcomeScoresMap := make(map[string]int)
|
||||
passesRulesMap := make(map[[3]byte]bool)
|
||||
|
||||
for _, genomeTraitInfoObject := range newPersonTraitInfoMap{
|
||||
|
||||
currentGenomeOutcomeScoresMap := genomeTraitInfoObject.OutcomeScoresMap
|
||||
currentGenomePassesRulesMap := genomeTraitInfoObject.GenomePassesRulesMap
|
||||
|
||||
if (firstItemReached == false){
|
||||
personGenomeTraitInfoObject = genomeTraitInfoObject
|
||||
outcomeScoresMap = currentGenomeOutcomeScoresMap
|
||||
passesRulesMap = currentGenomePassesRulesMap
|
||||
firstItemReached = true
|
||||
continue
|
||||
}
|
||||
|
||||
areEqual := reflect.DeepEqual(personGenomeTraitInfoObject, genomeTraitInfoObject)
|
||||
areEqual := maps.Equal(currentGenomeOutcomeScoresMap, outcomeScoresMap)
|
||||
if (areEqual == false){
|
||||
// A conflict exists
|
||||
return true, nil
|
||||
}
|
||||
areEqual = maps.Equal(currentGenomePassesRulesMap, passesRulesMap)
|
||||
if (areEqual == false){
|
||||
// A conflict exists
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
@ -975,7 +1010,7 @@ func GetPersonDiscreteTraitAnalysis(inputGenomesWithMetadataList []prepareRawGen
|
|||
}
|
||||
|
||||
conflictExists, err := getConflictExistsBool()
|
||||
if (err != nil) { return geneticAnalysis.PersonDiscreteTraitInfo{}, err }
|
||||
if (err != nil) { return emptyPersonTraitInfo, err }
|
||||
|
||||
newPersonTraitInfoObject.ConflictExists = conflictExists
|
||||
|
||||
|
@ -1011,205 +1046,12 @@ func GetGenomePolygenicDiseaseLocusRiskInfo(locusRiskWeightsMap map[string]int,
|
|||
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
|
||||
// Outputs:
|
||||
// -bool: Genome passes trait rule status is known
|
||||
// -bool: Genome passes trait rule
|
||||
// -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
|
||||
// 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
|
||||
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
|
||||
MonogenicDiseasesMap map[string]PersonMonogenicDiseaseInfo
|
||||
|
||||
// Map Structure: Disease Name -> 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
|
||||
DiscreteTraitsMap map[string]PersonDiscreteTraitInfo
|
||||
|
||||
// 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
|
||||
TraitsMap map[string]PersonTraitInfo
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,15 +50,15 @@ type PersonGenomeMonogenicDiseaseInfo struct{
|
|||
PersonHasDisease bool
|
||||
|
||||
// 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
|
||||
// 1 locus can have multiple potential variants
|
||||
QuantityOfLociTested int
|
||||
NumberOfLociTested int
|
||||
|
||||
// This describes the number of loci which are phased
|
||||
// This number will always be <= QuantityOfLociTested
|
||||
QuantityOfPhasedLoci int
|
||||
// This number will always be <= NumberOfLociTested
|
||||
NumberOfPhasedLoci int
|
||||
|
||||
// This describes the probability that the person will pass a disease variant
|
||||
// It is a value that represents a percentage between 0-100
|
||||
|
@ -107,9 +94,14 @@ type PersonPolygenicDiseaseInfo struct{
|
|||
|
||||
type PersonGenomePolygenicDiseaseInfo struct{
|
||||
|
||||
// This describes the quantity of loci tested for this disease
|
||||
// This should be len(LociInfoMap)
|
||||
QuantityOfLociTested int
|
||||
// This describes the number of loci tested for this disease
|
||||
// This should be len(LociInfoList)
|
||||
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 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
|
||||
// If no map entries exist, then no trait info is known
|
||||
// Map Structure: Genome Identifier -> PersonGenomeDiscreteTraitInfo
|
||||
TraitInfoMap map[[16]byte]PersonGenomeDiscreteTraitInfo
|
||||
// Map Structure: Genome Identifier -> PersonGenomeTraitInfo
|
||||
TraitInfoMap map[[16]byte]PersonGenomeTraitInfo
|
||||
|
||||
// This is true if there are multiple genomes and the results from each genome differ
|
||||
ConflictExists bool
|
||||
}
|
||||
|
||||
// For a trait analysis, both analysis methods may exist in the results
|
||||
// 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{
|
||||
type PersonGenomeTraitInfo struct{
|
||||
|
||||
// This is true if it is possible to analyze this trait using a neural network
|
||||
NeuralNetworkExists bool
|
||||
// This should be len(GenomePassesRulesMap)
|
||||
NumberOfRulesTested int
|
||||
|
||||
// This is true if a neural network analysis was performed for this genome
|
||||
// This means that at least 1 locus for this trait was contained in the genome
|
||||
NeuralNetworkAnalysisExists bool
|
||||
// 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
|
||||
|
||||
NeuralNetworkAnalysis PersonGenomeDiscreteTraitInfo_NeuralNetwork
|
||||
|
||||
// This is true if it is possible to analyze this trait using rules
|
||||
AnyRulesExist 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 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{
|
||||
// This map contains the outcome scores for the genome
|
||||
// Map Structure: Outcome Name -> Score
|
||||
// Example: "Intolerant" -> 5
|
||||
OutcomeScoresMap map[string]int
|
||||
|
||||
// Map Structure: Rule Identifier -> Genome Passes rule (true if the genome passes the rule)
|
||||
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
|
||||
PolygenicDiseasesMap map[string]OffspringPolygenicDiseaseInfo
|
||||
|
||||
// Discrete traits are traits with discrete outcomes, such as Eye Color
|
||||
// Map Structure: Trait Name -> Trait Info Object
|
||||
DiscreteTraitsMap map[string]OffspringDiscreteTraitInfo
|
||||
|
||||
// Numeric traits are traits with numeric outcomes, such as Height
|
||||
// Map Structure: Trait Name -> Trait Info Object
|
||||
NumericTraitsMap map[string]OffspringNumericTraitInfo
|
||||
TraitsMap map[string]OffspringTraitInfo
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
QuantityOfVariantsTestedMap map[[16]byte]int
|
||||
NumberOfVariantsTestedMap map[[16]byte]int
|
||||
|
||||
// This map stores the offspring disease probabilities for each genome pair.
|
||||
// A genome pair is a concatenation of two genome identifiers
|
||||
|
@ -296,6 +215,7 @@ type OffspringMonogenicDiseaseInfo struct{
|
|||
type OffspringGenomePairMonogenicDiseaseInfo struct{
|
||||
|
||||
// At least 1 variant's information is needed from either person to include the diseaseInfo object in the MonogenicDiseaseInfoMap
|
||||
|
||||
ProbabilityOffspringHasDiseaseIsKnown bool
|
||||
|
||||
// This is the probability that the offspring will have the disease
|
||||
|
@ -339,8 +259,8 @@ type OffspringPolygenicDiseaseInfo struct{
|
|||
|
||||
type OffspringGenomePairPolygenicDiseaseInfo struct{
|
||||
|
||||
// This should be len(LociInfoMap)
|
||||
QuantityOfLociTested int
|
||||
// This should be len(DiseaseLociList)
|
||||
NumberOfLociTested int
|
||||
|
||||
// A number between 1-10 representing the offspring's average risk score
|
||||
// 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
|
||||
// Map Structure: Genome Pair Identifier -> OffspringGenomePairTraitInfo
|
||||
TraitInfoMap map[[32]byte]OffspringGenomePairDiscreteTraitInfo
|
||||
TraitInfoMap map[[32]byte]OffspringGenomePairTraitInfo
|
||||
|
||||
ConflictExists bool
|
||||
}
|
||||
|
||||
// For a trait analysis, both analysis methods may exist in the results
|
||||
// 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{
|
||||
type OffspringGenomePairTraitInfo struct{
|
||||
|
||||
// This is true if it is possible to analyze this trait using a neural network
|
||||
NeuralNetworkExists bool
|
||||
// This should be len(TraitRulesList)
|
||||
NumberOfRulesTested int
|
||||
|
||||
// This is true if a neural network analysis was performed for this genome
|
||||
// This means that at least 1 locus for this trait was contained in both of the genomes in the pair
|
||||
NeuralNetworkAnalysisExists bool
|
||||
|
||||
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: Outcome Name -> Outcome Score
|
||||
// Example: "Intolerant" -> 2.5
|
||||
OffspringAverageOutcomeScoresMap map[string]float64
|
||||
|
||||
// Map Structure: Rule Identifier -> Offspring Probability Of Passing Rule
|
||||
// The value stores the probability that the offspring will pass the rule
|
||||
// This is a number between 0-100%
|
||||
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
|
||||
|
||||
import "seekia/resources/geneticReferences/traits"
|
||||
import "seekia/resources/geneticPredictionModels"
|
||||
|
||||
import "seekia/internal/genetics/locusValue"
|
||||
import "seekia/internal/genetics/readBiobankData"
|
||||
|
@ -212,252 +211,6 @@ func DecodeBytesToNeuralNetworkObject(inputNeuralNetwork []byte)(NeuralNetwork,
|
|||
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:
|
||||
// -int: Number of loci values that are known
|
||||
// -int: Number of loci values that are known and phased
|
||||
|
@ -684,9 +437,9 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
|
|||
if (err != nil) { return false, nil, err }
|
||||
|
||||
// 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.")
|
||||
}
|
||||
|
||||
|
@ -704,7 +457,7 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
|
|||
// -0 = Locus value is unknown
|
||||
// -0.5 = Locus Is known, phase is unknown
|
||||
// -1 = Locus Is Known, phase is known
|
||||
expectedNumberOfInputLayerRows := len(traitRSIDsList) * 3
|
||||
expectedNumberOfInputLayerRows := len(traitRSIDs) * 3
|
||||
|
||||
if (numberOfInputLayerRows != expectedNumberOfInputLayerRows){
|
||||
|
||||
|
@ -715,7 +468,7 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
|
|||
|
||||
checkIfAnyTraitLocusValuesExist := func()bool{
|
||||
|
||||
for _, rsID := range traitRSIDsList{
|
||||
for _, rsID := range traitRSIDs{
|
||||
|
||||
_, exists := userLocusValuesMap[rsID]
|
||||
if (exists == true){
|
||||
|
@ -734,9 +487,11 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
|
|||
}
|
||||
|
||||
// We sort rsIDs in ascending order
|
||||
// We copy list so we don't change the original
|
||||
|
||||
traitRSIDsListCopy := slices.Clone(traitRSIDsList)
|
||||
slices.Sort(traitRSIDsListCopy)
|
||||
traitRSIDsList := slices.Clone(traitRSIDs)
|
||||
|
||||
slices.Sort(traitRSIDsList)
|
||||
|
||||
// This function returns the outputLayer for all trainingDatas for this user
|
||||
// Each outputLayer represents the user's trait value (Example: "Blue" for Eye Color)
|
||||
|
@ -882,11 +637,11 @@ func CreateGeneticPredictionTrainingData_OpenSNP(
|
|||
|
||||
anyLocusExists := false
|
||||
|
||||
inputLayerLength := len(traitRSIDsListCopy) * 3
|
||||
inputLayerLength := len(traitRSIDsList) * 3
|
||||
|
||||
inputLayer := make([]float32, 0, inputLayerLength)
|
||||
|
||||
for _, rsID := range traitRSIDsListCopy{
|
||||
for _, rsID := range traitRSIDsList{
|
||||
|
||||
randomFloat := pseudorandomNumberGenerator.Float64()
|
||||
if (randomFloat > probabilityOfUsingLoci){
|
||||
|
@ -1241,7 +996,7 @@ func (inputNetwork *NeuralNetwork)buildNeuralNetwork(inputLayer *gorgonia.Node)e
|
|||
|
||||
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
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ var myCacheChosenGeneticAnalysisIdentifier string
|
|||
|
||||
// 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
|
||||
// TODO: Read attributes from the analysis into maps for faster retrieval
|
||||
var myCacheChosenGeneticAnalysis geneticAnalysis.PersonAnalysis
|
||||
|
||||
// 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
|
||||
var myCacheChosenGeneticAnalysis_MultipleGenomesExist bool
|
||||
|
||||
|
||||
// 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
|
||||
// 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.")
|
||||
}
|
||||
|
||||
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 }
|
||||
|
||||
getGenomeIdentifierToUse := func()([16]byte, error){
|
||||
|
|
|
@ -6,7 +6,6 @@ package myGenomes
|
|||
|
||||
import "seekia/internal/cryptography/blake3"
|
||||
import "seekia/internal/encoding"
|
||||
import "seekia/internal/genetics/prepareRawGenomes"
|
||||
import "seekia/internal/genetics/readRawGenomes"
|
||||
import "seekia/internal/helpers"
|
||||
import "seekia/internal/localFilesystem"
|
||||
|
@ -107,18 +106,11 @@ func AddRawGenome(personIdentifier string, rawGenomeString string)(bool, bool, e
|
|||
|
||||
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){
|
||||
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)
|
||||
if (err != nil) { return false, false, err }
|
||||
|
||||
|
|
|
@ -76,10 +76,6 @@ func CreateRawGenomeWithMetadataObject(genomeIdentifier [16]byte, rawGenomeStrin
|
|||
// -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 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
|
||||
|
||||
anyValuesExist, genomeMap, err := ConvertRawGenomeToGenomeMap(rawGenomeMap, genomeIsPhased)
|
||||
if (err != nil) { return nil, nil, false, [16]byte{}, [16]byte{}, err }
|
||||
if (anyValuesExist == false){
|
||||
// We have to make sure this never happens so the user isn't confused as to why genomes
|
||||
// that were imported were not included in the analysis
|
||||
// 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.")
|
||||
// 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{
|
||||
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{
|
||||
|
@ -135,9 +221,9 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
|
|||
err := updatePercentageCompleteFunction(20)
|
||||
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.
|
||||
|
||||
err = updatePercentageCompleteFunction(100)
|
||||
|
@ -461,112 +547,4 @@ func GetGenomesWithMetadataListFromRawGenomesList(inputGenomesList []RawGenomeWi
|
|||
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
|
||||
// -[16]byte: OnlyExcludeConflicts GenomeIdentifier
|
||||
// -[16]byte: OnlyIncludeShared GenomeIdentifier
|
||||
// -map[[16]byte]map[int64]locusValue.LocusValue: Genomes locus values map
|
||||
// -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
|
||||
if (analysisVersion != 1){
|
||||
// This analysis must have been created by a newer version of Seekia
|
||||
// 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
|
||||
|
||||
genomesMap := inputGeneticAnalysis.GenomesMap
|
||||
|
||||
combinedGenomesExist := inputGeneticAnalysis.CombinedGenomesExist
|
||||
if (combinedGenomesExist == false){
|
||||
return allRawGenomeIdentifiersList, false, [16]byte{}, [16]byte{}, genomesMap, nil
|
||||
return allRawGenomeIdentifiersList, false, [16]byte{}, [16]byte{}, nil
|
||||
}
|
||||
|
||||
onlyExcludeConflictsGenomeIdentifier := inputGeneticAnalysis.OnlyExcludeConflictsGenomeIdentifier
|
||||
onlyIncludeSharedGenomeIdentifier := inputGeneticAnalysis.OnlyIncludeSharedGenomeIdentifier
|
||||
|
||||
return allRawGenomeIdentifiersList, true, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, genomesMap, nil
|
||||
return allRawGenomeIdentifiersList, true, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, nil
|
||||
}
|
||||
|
||||
//Outputs:
|
||||
|
@ -181,7 +178,7 @@ func GetMatchingPersonAnalysisGenomeIdentifierFromCoupleAnalysis(isPerson1 bool,
|
|||
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 (multipleGenomesExist == false){
|
||||
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
|
||||
}
|
||||
|
||||
_, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, _, err := GetMetadataFromPersonGeneticAnalysis(person2AnalysisObject)
|
||||
_, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := GetMetadataFromPersonGeneticAnalysis(person2AnalysisObject)
|
||||
if (err != nil) { return [16]byte{}, false, false, "", err }
|
||||
if (multipleGenomesExist == false){
|
||||
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
|
||||
// -int: Probability of passing a disease variant
|
||||
// -string: Probability of passing a disease variant formatted (with % suffix)
|
||||
// -int: Quantity of variants tested
|
||||
// -int: Quantity of loci tested
|
||||
// -int: Quantity of phased loci
|
||||
// -int: Number of variants tested
|
||||
// -int: Number of loci tested
|
||||
// -int: Number of phased loci
|
||||
// -bool: Conflict exists
|
||||
// -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
|
||||
|
||||
personHasDisease := genomeMonogenicDiseaseInfo.PersonHasDisease
|
||||
quantityOfVariantsTested := genomeMonogenicDiseaseInfo.QuantityOfVariantsTested
|
||||
quantityOfLociTested := genomeMonogenicDiseaseInfo.QuantityOfLociTested
|
||||
quantityOfPhasedLoci := genomeMonogenicDiseaseInfo.QuantityOfPhasedLoci
|
||||
numberOfVariantsTested := genomeMonogenicDiseaseInfo.NumberOfVariantsTested
|
||||
numberOfLociTested := genomeMonogenicDiseaseInfo.NumberOfLociTested
|
||||
numberOfPhasedLoci := genomeMonogenicDiseaseInfo.NumberOfPhasedLoci
|
||||
probabilityOfPassingAVariant := genomeMonogenicDiseaseInfo.ProbabilityOfPassingADiseaseVariant
|
||||
|
||||
probabilityOfPassingAVariantString := helpers.ConvertIntToString(probabilityOfPassingAVariant)
|
||||
|
||||
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)
|
||||
// -int: Person Disease risk score
|
||||
// -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
|
||||
// -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
|
||||
|
||||
personPolygenicDiseaseInfo, exists := personPolygenicDiseasesMap[diseaseName]
|
||||
if (exists == false){
|
||||
return false, 0, "", 0, false, nil
|
||||
return false, 0, "", nil, 0, false, nil
|
||||
}
|
||||
|
||||
personPolygenicDiseaseInfoMap := personPolygenicDiseaseInfo.PolygenicDiseaseInfoMap
|
||||
|
||||
genomePolygenicDiseaseInfo, exists := personPolygenicDiseaseInfoMap[genomeIdentifier]
|
||||
if (exists == false){
|
||||
return false, 0, "", 0, false, nil
|
||||
return false, 0, "", nil, 0, false, nil
|
||||
}
|
||||
|
||||
conflictExists := personPolygenicDiseaseInfo.ConflictExists
|
||||
|
@ -515,9 +513,11 @@ func GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject genet
|
|||
|
||||
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
|
||||
// -string: Offspring Disease average risk score formatted (has "/10" suffix)
|
||||
// -[]int: Sample Offspring Risk Scores List
|
||||
// -int: Quantity of loci tested
|
||||
// -int: Number of loci tested
|
||||
// -bool: Conflict exists
|
||||
// -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
|
||||
|
||||
quantityOfLociTested := genomePairPolygenicDiseaseInfo.QuantityOfLociTested
|
||||
numberOfLociTested := genomePairPolygenicDiseaseInfo.NumberOfLociTested
|
||||
|
||||
offspringAverageRiskScore := genomePairPolygenicDiseaseInfo.OffspringAverageRiskScore
|
||||
|
||||
|
@ -557,7 +557,7 @@ func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisObject ge
|
|||
|
||||
sampleOffspringRiskScoresList := genomePairPolygenicDiseaseInfo.SampleOffspringRiskScoresList
|
||||
|
||||
return true, offspringAverageRiskScore, offspringAverageRiskScoreFormatted, sampleOffspringRiskScoresList, quantityOfLociTested, conflictExists, nil
|
||||
return true, offspringAverageRiskScore, offspringAverageRiskScoreFormatted, sampleOffspringRiskScoresList, numberOfLociTested, conflictExists, nil
|
||||
}
|
||||
|
||||
//Outputs:
|
||||
|
@ -673,169 +673,71 @@ func GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisObje
|
|||
}
|
||||
|
||||
//Outputs:
|
||||
// -bool: Neural network exists
|
||||
// -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)
|
||||
// -map[int64]locusValue.LocusValue (rsID -> Base pair) (missing rsIDs represent unknown values)
|
||||
// -bool: Any Trait Rule known/tested
|
||||
// -map[[3]byte]bool: Rule Identifier -> Person passes rule
|
||||
// -bool: Predicted outcome exists
|
||||
// -string: Predicted outcome
|
||||
// -int: Quantity of rules tested
|
||||
// -int: Quantity Of Loci Known (Rules)
|
||||
// -bool: Conflict exists (between any of these results for each genome)
|
||||
// -map[string]int: Trait outcomes scores map (Outcome -> Number of points)
|
||||
// -int: Number of rules tested
|
||||
// -bool: Conflict exists
|
||||
// -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]
|
||||
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
|
||||
conflictExists := personTraitInfoObject.ConflictExists
|
||||
|
||||
personGenomeTraitInfoObject, exists := personTraitInfoMap[genomeIdentifier]
|
||||
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
|
||||
neuralNetworkAnalysisExists := personGenomeTraitInfoObject.NeuralNetworkAnalysisExists
|
||||
conflictExists := personTraitInfoObject.ConflictExists
|
||||
|
||||
getNeuralNetworkAnalysisInfo := func()(string, int, int, int){
|
||||
genomeNumberOfRulesTested := personGenomeTraitInfoObject.NumberOfRulesTested
|
||||
|
||||
if (neuralNetworkExists == false || neuralNetworkAnalysisExists == false){
|
||||
return "", 0, 0, 0
|
||||
}
|
||||
genomeLocusValuesMap := personGenomeTraitInfoObject.LocusValuesMap
|
||||
|
||||
neuralNetworkAnalysis := personGenomeTraitInfoObject.NeuralNetworkAnalysis
|
||||
genomeOutcomeScoresMap := personGenomeTraitInfoObject.OutcomeScoresMap
|
||||
|
||||
predictedOutcome := neuralNetworkAnalysis.PredictedOutcome
|
||||
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
|
||||
return genomeLocusValuesMap, true, genomeOutcomeScoresMap, genomeNumberOfRulesTested, 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]
|
||||
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
|
||||
conflictExists := traitInfoObject.ConflictExists
|
||||
|
||||
genomePairTraitInfoObject, exists := traitInfoMap[genomePairIdentifier]
|
||||
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){
|
||||
|
||||
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
|
||||
return true, offspringAverageOutcomeScoresMap, numberOfRulesTested, 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: Genome passes rule
|
||||
// -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)
|
||||
if (err != nil) { return false, false, err }
|
||||
if (anyRulesExist == false){
|
||||
return false, false, errors.New("GetPersonTraitRuleInfoFromGeneticAnalysis called when no trait rules exist.")
|
||||
}
|
||||
if (rulesAnalysisExists == false){
|
||||
personTraitsMap := personAnalysisObject.TraitsMap
|
||||
|
||||
traitInfoObject, exists := personTraitsMap[traitName]
|
||||
if (exists == false){
|
||||
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]
|
||||
if (statusIsKnown == false){
|
||||
return false, false, nil
|
||||
|
@ -868,17 +777,24 @@ func GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(personAnalysisObject gene
|
|||
// -int: Offspring probability of passing rule (0 - 100)
|
||||
// -string: Offspring probability of passing rule formatted (with % suffix)
|
||||
// -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)
|
||||
if (err != nil) { return false, 0, "", err }
|
||||
if (anyRulesExist == false){
|
||||
return false, 0, "", errors.New("GetOffspringTraitRuleInfoFromGeneticAnalysis called for trait which has no rules: " + traitName)
|
||||
}
|
||||
if (rulesAnalysisExists == false){
|
||||
offspringTraitsMap := coupleAnalysisObject.TraitsMap
|
||||
|
||||
offspringTraitInfo, exists := offspringTraitsMap[traitName]
|
||||
if (exists == false){
|
||||
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]
|
||||
if (exists == false){
|
||||
return false, 0, "", nil
|
||||
|
@ -896,7 +812,7 @@ func GetOffspringDiscreteTraitRuleInfoFromGeneticAnalysis(coupleAnalysisObject g
|
|||
//TODO: Perform sanity checks on data
|
||||
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 }
|
||||
|
||||
allGenomeIdentifiersList := allRawGenomeIdentifiersList
|
||||
|
@ -943,7 +859,7 @@ func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnal
|
|||
|
||||
for _, genomeIdentifier := range allGenomeIdentifiersList{
|
||||
|
||||
_, _, _, _, _, err := GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, genomeIdentifier)
|
||||
_, _, _, _, _, _, err := GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisObject, diseaseName, genomeIdentifier)
|
||||
if (err != nil) { return err }
|
||||
}
|
||||
|
||||
|
@ -970,31 +886,27 @@ func VerifyPersonGeneticAnalysis(personAnalysisObject geneticAnalysis.PersonAnal
|
|||
for _, traitObject := range traitObjectsList{
|
||||
|
||||
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{
|
||||
|
||||
_, _, _, _, _, _, _, _, _, _, _, _, _, _, err := GetPersonDiscreteTraitInfoFromGeneticAnalysis(personAnalysisObject, traitName, genomeIdentifier)
|
||||
_, _, err := GetPersonTraitRuleInfoFromGeneticAnalysis(personAnalysisObject, traitName, ruleIdentifier, 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{
|
||||
|
||||
_, _, err := GetPersonDiscreteTraitRuleInfoFromGeneticAnalysis(personAnalysisObject, traitName, ruleIdentifier, genomeIdentifier)
|
||||
if (err != nil) { return err }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1086,31 +998,27 @@ func VerifyCoupleGeneticAnalysis(coupleAnalysisObject geneticAnalysis.CoupleAnal
|
|||
for _, traitObject := range traitObjectsList{
|
||||
|
||||
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 }
|
||||
}
|
||||
|
||||
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){
|
||||
|
||||
switch monthString{
|
||||
case "01":{
|
||||
return time.January, nil
|
||||
}
|
||||
case "02":{
|
||||
return time.February, nil
|
||||
}
|
||||
case "03":{
|
||||
return time.March, nil
|
||||
}
|
||||
case "04":{
|
||||
return time.April, nil
|
||||
}
|
||||
case "05":{
|
||||
return time.May, nil
|
||||
}
|
||||
case "06":{
|
||||
return time.June, nil
|
||||
}
|
||||
case "07":{
|
||||
return time.July, nil
|
||||
}
|
||||
case "08":{
|
||||
return time.August, nil
|
||||
}
|
||||
case "09":{
|
||||
return time.September, nil
|
||||
}
|
||||
case "10":{
|
||||
return time.October, nil
|
||||
}
|
||||
case "11":{
|
||||
return time.November, nil
|
||||
}
|
||||
case "12":{
|
||||
return time.December, nil
|
||||
}
|
||||
if (monthString == "01"){
|
||||
return time.January, nil
|
||||
}
|
||||
if (monthString == "02"){
|
||||
return time.February, nil
|
||||
}
|
||||
if (monthString == "03"){
|
||||
return time.March, nil
|
||||
}
|
||||
if (monthString == "04"){
|
||||
return time.April, nil
|
||||
}
|
||||
if (monthString == "05"){
|
||||
return time.May, nil
|
||||
}
|
||||
if (monthString == "06"){
|
||||
return time.June, nil
|
||||
}
|
||||
if (monthString == "07"){
|
||||
return time.July, nil
|
||||
}
|
||||
if (monthString == "08"){
|
||||
return time.August, nil
|
||||
}
|
||||
if (monthString == "09"){
|
||||
return time.September, nil
|
||||
}
|
||||
if (monthString == "10"){
|
||||
return time.October, nil
|
||||
}
|
||||
if (monthString == "11"){
|
||||
return time.November, nil
|
||||
}
|
||||
if (monthString == "12"){
|
||||
return time.December, nil
|
||||
}
|
||||
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]
|
||||
snpValueRaw := rowSlice[3]
|
||||
|
||||
if (len(snpValueRaw) < 2){
|
||||
return "", 0, 0, 0, false, nil, errors.New("Malformed 23andMe genome data: Invalid SNP row snp value: " + fileLineString)
|
||||
if (snpValueRaw[0] != byte('-')){
|
||||
// Locus value is not "--"
|
||||
// Locus value exists
|
||||
numberOfLoci += 1
|
||||
}
|
||||
|
||||
if (snpValueRaw[0] == '-'){
|
||||
// Locus value is "--"
|
||||
// Locus value does not exist
|
||||
continue
|
||||
}
|
||||
|
||||
numberOfLoci += 1
|
||||
|
||||
//Outputs:
|
||||
// -bool: rsID found
|
||||
// -int64: rsID value
|
||||
// -error
|
||||
getRSIDIdentifier := func()(bool, int64, error){
|
||||
|
||||
isRSID, rsidInt64 := readRSIDString(snpIdentifier)
|
||||
|
@ -491,50 +481,75 @@ func ReadRawGenomeFile(fileReader io.Reader) (string, int, int64, int64, bool, m
|
|||
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{
|
||||
|
||||
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)
|
||||
singleBase := string(snpValueRaw[0])
|
||||
return singleBase, nil
|
||||
}
|
||||
|
||||
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()
|
||||
if (err != nil){ return "", 0, 0, 0, false, nil, err }
|
||||
basesString, err := getLocusValueString()
|
||||
if (err != nil) { return "", 0, 0, 0, false, nil, err }
|
||||
|
||||
allele1 := string(locusBasesList[0])
|
||||
|
||||
locusValueObject := RawGenomeLocusValue{
|
||||
Allele1: allele1,
|
||||
if (basesString == "--"){
|
||||
// No data exists, skip.
|
||||
continue
|
||||
}
|
||||
|
||||
if (len(locusBasesList) > 1){
|
||||
for _, baseRune := range basesString{
|
||||
|
||||
allele2 := string(locusBasesList[1])
|
||||
|
||||
locusValueObject.Allele2Exists = true
|
||||
locusValueObject.Allele2 = allele2
|
||||
baseIsValid := verifyBase(string(baseRune))
|
||||
if (baseIsValid == false){
|
||||
return "", 0, 0, 0, false, nil, errors.New("Malformed 23andMe genome file: Invalid SNP base: " + string(baseRune))
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
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
|
||||
}
|
||||
|
||||
_, _, _, _, 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()
|
||||
if (err != nil) { return false, 0, "", err }
|
||||
|
||||
|
@ -788,8 +780,12 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
|||
|
||||
for _, diseaseObject := range polygenicDiseaseObjectsList{
|
||||
|
||||
diseaseName := diseaseObject.DiseaseName
|
||||
diseaseLociList := diseaseObject.LociList
|
||||
|
||||
_, _, _, myDiseaseLocusValuesMap, _, _, err := readGeneticAnalysis.GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(myGeneticAnalysisObject, diseaseName, myGenomeIdentifier)
|
||||
if (err != nil) { return false, 0, "", err }
|
||||
|
||||
// Map Structure: rsID -> Locus Value
|
||||
userDiseaseLocusValuesMap := make(map[int64]locusValue.LocusValue)
|
||||
|
||||
|
@ -822,7 +818,7 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
|||
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 (anyLocusValuesTested == false){
|
||||
continue
|
||||
|
@ -1403,14 +1399,9 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
|||
|
||||
traitName := getTraitName()
|
||||
|
||||
_, _, _, _, myGenomesMap, err := readGeneticAnalysis.GetMetadataFromPersonGeneticAnalysis(myGeneticAnalysisObject)
|
||||
myTraitLociMap, _, _, _, _, err := readGeneticAnalysis.GetPersonTraitInfoFromGeneticAnalysis(myGeneticAnalysisObject, traitName, myGenomeIdentifier)
|
||||
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)
|
||||
if (err != nil) { return false, 0, "", err }
|
||||
|
||||
|
@ -1424,7 +1415,7 @@ func GetAnyProfileAttributeIncludingCalculated(attributeName string, getProfileA
|
|||
|
||||
for _, rsID := range traitLociList{
|
||||
|
||||
myLocusValue, myLocusValueExists := myGenomeLocusValuesMap[rsID]
|
||||
myLocusValue, myLocusValueExists := myTraitLociMap[rsID]
|
||||
if (myLocusValueExists == false){
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -150,14 +150,6 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{
|
|||
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()
|
||||
if (err != nil) { return err }
|
||||
|
||||
|
@ -213,24 +205,19 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{
|
|||
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]
|
||||
if (exists == true){
|
||||
locusBase1 := locusValueObject.Base1Value
|
||||
locusBase2 := locusValueObject.Base2Value
|
||||
|
||||
rsIDString := helpers.ConvertInt64ToString(locusRSID)
|
||||
basePairValue := locusBase1 + ";" + locusBase2
|
||||
|
||||
locusBase1 := locusValueObject.Base1Value
|
||||
locusBase2 := locusValueObject.Base2Value
|
||||
|
||||
basePairValue := locusBase1 + ";" + locusBase2
|
||||
|
||||
profileMap["LocusValue_rs" + rsIDString] = basePairValue
|
||||
}
|
||||
profileMap["LocusValue_rs" + rsIDString] = basePairValue
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,22 +239,19 @@ func UpdateMyExportedProfile(myProfileType string, networkType byte)error{
|
|||
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]
|
||||
if (exists == true){
|
||||
rsIDString := helpers.ConvertInt64ToString(rsID)
|
||||
|
||||
rsIDString := helpers.ConvertInt64ToString(rsID)
|
||||
locusBase1 := locusValueObject.Base1Value
|
||||
locusBase2 := locusValueObject.Base2Value
|
||||
|
||||
locusBase1 := locusValueObject.Base1Value
|
||||
locusBase2 := locusValueObject.Base2Value
|
||||
basePairValue := locusBase1 + ";" + locusBase2
|
||||
|
||||
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
|
||||
traitDescription := traitObject.TraitDescription
|
||||
traitDiscreteOrNumeric := traitObject.DiscreteOrNumeric
|
||||
traitLocusReferencesMap := traitObject.LocusReferencesMap
|
||||
traitLociList := traitObject.LociList
|
||||
traitLociList_Rules := traitObject.LociList_Rules
|
||||
traitRulesList := traitObject.RulesList
|
||||
traitOutcomesList := traitObject.OutcomesList
|
||||
traitReferencesMap := traitObject.ReferencesMap
|
||||
traitReferencesMap := traitObject.References
|
||||
|
||||
if (traitName == ""){
|
||||
t.Fatalf("Empty trait name exists.")
|
||||
|
@ -329,9 +326,6 @@ func TestGeneticReferences(t *testing.T){
|
|||
if (traitDescription == ""){
|
||||
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) < 2){
|
||||
|
@ -355,41 +349,18 @@ func TestGeneticReferences(t *testing.T){
|
|||
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){
|
||||
t.Fatalf("No trait loci exist for trait: " + traitName)
|
||||
}
|
||||
|
||||
for _, rsID := range traitLociList{
|
||||
allRSIDsMap[rsID] = struct{}{}
|
||||
for _, locusRSID := range traitLociList{
|
||||
allRSIDsMap[locusRSID] = struct{}{}
|
||||
}
|
||||
|
||||
for _, rsID := range traitLociList_Rules{
|
||||
|
||||
locusExists := slices.Contains(traitLociList, rsID)
|
||||
if (locusExists == false){
|
||||
t.Fatalf("traitLociList_Rules contains locus not present in traitLociList")
|
||||
}
|
||||
containsDuplicates, duplicateLocus := helpers.CheckIfListContainsDuplicates(traitLociList)
|
||||
if (containsDuplicates == true){
|
||||
duplicateLocusString := helpers.ConvertInt64ToString(duplicateLocus)
|
||||
t.Fatalf("traitLociList contains duplicates for trait: " + traitName + ". RSID: " + duplicateLocusString)
|
||||
}
|
||||
|
||||
if (len(traitRulesList) == 0){
|
||||
|
@ -402,7 +373,7 @@ func TestGeneticReferences(t *testing.T){
|
|||
ruleIdentifier := ruleObject.RuleIdentifier
|
||||
ruleLociList := ruleObject.LociList
|
||||
ruleOutcomePointsMap := ruleObject.OutcomePointsMap
|
||||
ruleReferencesMap := ruleObject.ReferencesMap
|
||||
ruleReferences := ruleObject.References
|
||||
|
||||
identifierIsValid := verifyIdentifier(ruleIdentifier)
|
||||
if (identifierIsValid == false){
|
||||
|
@ -442,21 +413,11 @@ func TestGeneticReferences(t *testing.T){
|
|||
t.Fatalf("Trait rule Locus identifier is invalid: " + locusIdentifier)
|
||||
}
|
||||
|
||||
_, mapContainsItem := traitLocusReferencesMap[locusRSID]
|
||||
if (mapContainsItem == false){
|
||||
t.Fatalf("Rule locus contains rsid which is not contained within LocusReferencesMap.")
|
||||
}
|
||||
|
||||
sliceContainsItem := slices.Contains(traitLociList, locusRSID)
|
||||
if (sliceContainsItem == false){
|
||||
listContainsItem := slices.Contains(traitLociList, locusRSID)
|
||||
if (listContainsItem == false){
|
||||
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){
|
||||
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){
|
||||
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 diseases are also more influenced by environmental factors, further decreasing risk accuracy.
|
||||
|
||||
//TODO: Eventually we want to use neural networks for polygenic disease prediction.
|
||||
// This package is currently a less accurate solution until we get access to the necessary training data.
|
||||
//TODO: Eventually we want to use neural networks for both polygenic disease and trait prediction.
|
||||
// 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"
|
||||
|
||||
|
|
|
@ -1,20 +1,14 @@
|
|||
package traits
|
||||
|
||||
import "seekia/internal/helpers"
|
||||
|
||||
import "maps"
|
||||
|
||||
func getEyeColorTraitObject()Trait{
|
||||
|
||||
// Map Structure: rsID -> References Map
|
||||
locusReferencesMap := make(map[int64]map[string]string)
|
||||
eyeColorLociList := []int64{
|
||||
|
||||
referencesMap_List1 := make(map[string]string)
|
||||
referencesMap_List1["SNPedia.com - Eye Color"] = "https://www.snpedia.com/index.php/Eye_color"
|
||||
//TODO: Add more SNPs.
|
||||
|
||||
// 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,
|
||||
1800401,
|
||||
1800407,
|
||||
|
@ -57,39 +51,16 @@ func getEyeColorTraitObject()Trait{
|
|||
989869,
|
||||
4778138,
|
||||
12906280,
|
||||
}
|
||||
|
||||
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/"
|
||||
|
||||
// These SNPs are taken from https://pubmed.ncbi.nlm.nih.gov/20546537/
|
||||
|
||||
lociList_2 := []int64{
|
||||
// These SNPs are taken from https://pubmed.ncbi.nlm.nih.gov/20546537/
|
||||
12203592,
|
||||
1408799,
|
||||
1126809,
|
||||
12896399,
|
||||
7495174,
|
||||
1667394,
|
||||
}
|
||||
|
||||
for _, rsID := range lociList_2{
|
||||
|
||||
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{
|
||||
// These SNPs are taken from https://pubmed.ncbi.nlm.nih.gov/33692100/
|
||||
6693258,
|
||||
351385,
|
||||
2385028,
|
||||
|
@ -144,12 +115,6 @@ func getEyeColorTraitObject()Trait{
|
|||
// 5957354,
|
||||
}
|
||||
|
||||
for _, rsID := range lociList_3{
|
||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List3)
|
||||
}
|
||||
|
||||
eyeColorLociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
||||
|
||||
referencesMap := make(map[string]string)
|
||||
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/"
|
||||
|
@ -158,13 +123,10 @@ func getEyeColorTraitObject()Trait{
|
|||
eyeColorObject := Trait{
|
||||
TraitName: "Eye Color",
|
||||
TraitDescription: "The color of a person's eyes.",
|
||||
DiscreteOrNumeric: "Discrete",
|
||||
LocusReferencesMap: locusReferencesMap,
|
||||
LociList: eyeColorLociList,
|
||||
LociList_Rules: []int64{},
|
||||
RulesList: []TraitRule{},
|
||||
OutcomesList: []string{"Blue", "Green", "Hazel", "Brown"},
|
||||
ReferencesMap: referencesMap,
|
||||
References: referencesMap,
|
||||
}
|
||||
|
||||
return eyeColorObject
|
||||
|
|
|
@ -1,19 +1,9 @@
|
|||
package traits
|
||||
|
||||
import "seekia/internal/helpers"
|
||||
|
||||
import "maps"
|
||||
|
||||
func getFacialStructureTraitObject()Trait{
|
||||
|
||||
// Map Structure: rsID -> References Map
|
||||
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{
|
||||
facialStructureLociList := []int64{
|
||||
|
||||
//TODO: Add more SNPs.
|
||||
|
||||
|
@ -122,13 +112,6 @@ func getFacialStructureTraitObject()Trait{
|
|||
397723,
|
||||
}
|
||||
|
||||
for _, rsID := range lociList_1{
|
||||
|
||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List1)
|
||||
}
|
||||
|
||||
facialStructureLociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
||||
|
||||
referencesMap := make(map[string]string)
|
||||
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"
|
||||
|
@ -136,13 +119,10 @@ func getFacialStructureTraitObject()Trait{
|
|||
facialStructureObject := Trait{
|
||||
TraitName: "Facial Structure",
|
||||
TraitDescription: "The structure of a person's face.",
|
||||
DiscreteOrNumeric: "Discrete",
|
||||
LocusReferencesMap: locusReferencesMap,
|
||||
LociList: facialStructureLociList,
|
||||
LociList_Rules: []int64{},
|
||||
RulesList: []TraitRule{},
|
||||
OutcomesList: []string{},
|
||||
ReferencesMap: referencesMap,
|
||||
References: referencesMap,
|
||||
}
|
||||
|
||||
return facialStructureObject
|
||||
|
|
|
@ -3,20 +3,10 @@ package traits
|
|||
// Hair color is influenced by thousands of genes
|
||||
// We only have a few listed here
|
||||
|
||||
import "seekia/internal/helpers"
|
||||
|
||||
import "maps"
|
||||
|
||||
func getHairColorTraitObject()Trait{
|
||||
|
||||
// Map Structure: rsID -> References Map
|
||||
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{
|
||||
hairColorLociList := []int64{
|
||||
|
||||
//These loci were taken from https://pubmed.ncbi.nlm.nih.gov/20546537/
|
||||
|
||||
|
@ -42,13 +32,6 @@ func getHairColorTraitObject()Trait{
|
|||
1805008,
|
||||
}
|
||||
|
||||
for _, rsID := range lociList_1{
|
||||
|
||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List1)
|
||||
}
|
||||
|
||||
hairColorLociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
||||
|
||||
referencesMap := make(map[string]string)
|
||||
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/"
|
||||
|
@ -56,13 +39,10 @@ func getHairColorTraitObject()Trait{
|
|||
hairColorObject := Trait{
|
||||
TraitName: "Hair Color",
|
||||
TraitDescription: "The color of a person's hair.",
|
||||
DiscreteOrNumeric: "Discrete",
|
||||
LocusReferencesMap: locusReferencesMap,
|
||||
LociList: hairColorLociList,
|
||||
LociList_Rules: []int64{},
|
||||
RulesList: []TraitRule{},
|
||||
OutcomesList: []string{},
|
||||
ReferencesMap: referencesMap,
|
||||
References: referencesMap,
|
||||
}
|
||||
|
||||
return hairColorObject
|
||||
|
|
|
@ -1,53 +1,11 @@
|
|||
package traits
|
||||
|
||||
import "seekia/internal/helpers"
|
||||
|
||||
import "maps"
|
||||
|
||||
func getHairTextureTraitObject()Trait{
|
||||
|
||||
// Map Structure: rsID -> References Map
|
||||
locusReferencesMap := make(map[int64]map[string]string)
|
||||
|
||||
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_ReferencesMap := make(map[string]string)
|
||||
rule1_ReferencesMap["SNPedia.com - rs7349332"] = "https://www.snpedia.com/index.php/Rs7349332"
|
||||
|
||||
rule1_Locus1Object := RuleLocus{
|
||||
|
||||
|
@ -64,10 +22,12 @@ func getHairTextureTraitObject()Trait{
|
|||
RuleIdentifier: "fde405",
|
||||
LociList: rule1_LociList,
|
||||
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
|
||||
rule2_ReferencesMap := make(map[string]string)
|
||||
rule2_ReferencesMap["SNPedia.com - rs7349332"] = "https://www.snpedia.com/index.php/Rs7349332"
|
||||
|
||||
rule2_Locus1Object := RuleLocus{
|
||||
|
||||
|
@ -84,8 +44,11 @@ func getHairTextureTraitObject()Trait{
|
|||
RuleIdentifier: "6bd1da",
|
||||
LociList: rule2_LociList,
|
||||
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{
|
||||
|
||||
|
@ -102,13 +65,11 @@ func getHairTextureTraitObject()Trait{
|
|||
RuleIdentifier: "32e377",
|
||||
LociList: rule3_LociList,
|
||||
OutcomePointsMap: rule3_OutcomePointsMap,
|
||||
ReferencesMap: maps.Clone(referencesMap_rs7349332),
|
||||
References: rule3_ReferencesMap,
|
||||
}
|
||||
|
||||
|
||||
|
||||
referencesMap_rs11803731 := make(map[string]string)
|
||||
referencesMap_rs11803731["SNPedia.com - rs11803731"] = "https://www.snpedia.com/index.php/Rs11803731"
|
||||
rule4_ReferencesMap := make(map[string]string)
|
||||
rule4_ReferencesMap["SNPedia.com - rs11803731"] = "https://www.snpedia.com/index.php/Rs11803731"
|
||||
|
||||
rule4_Locus1Object := RuleLocus{
|
||||
|
||||
|
@ -125,10 +86,12 @@ func getHairTextureTraitObject()Trait{
|
|||
RuleIdentifier: "34e6d2",
|
||||
LociList: rule4_LociList,
|
||||
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
|
||||
rule5_ReferencesMap := make(map[string]string)
|
||||
rule5_ReferencesMap["SNPedia.com - rs11803731"] = "https://www.snpedia.com/index.php/Rs11803731"
|
||||
|
||||
rule5_Locus1Object := RuleLocus{
|
||||
|
||||
|
@ -145,8 +108,11 @@ func getHairTextureTraitObject()Trait{
|
|||
RuleIdentifier: "cf6cb5",
|
||||
LociList: rule5_LociList,
|
||||
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{
|
||||
|
||||
|
@ -163,11 +129,11 @@ func getHairTextureTraitObject()Trait{
|
|||
RuleIdentifier: "2ba65b",
|
||||
LociList: rule6_LociList,
|
||||
OutcomePointsMap: rule6_OutcomePointsMap,
|
||||
ReferencesMap: maps.Clone(referencesMap_rs11803731),
|
||||
References: rule6_ReferencesMap,
|
||||
}
|
||||
|
||||
referencesMap_rs17646946 := make(map[string]string)
|
||||
referencesMap_rs17646946["SNPedia.com - rs17646946"] = "https://www.snpedia.com/index.php/Rs17646946"
|
||||
rule7_ReferencesMap := make(map[string]string)
|
||||
rule7_ReferencesMap["SNPedia.com - rs17646946"] = "https://www.snpedia.com/index.php/Rs17646946"
|
||||
|
||||
rule7_Locus1Object := RuleLocus{
|
||||
|
||||
|
@ -184,9 +150,12 @@ func getHairTextureTraitObject()Trait{
|
|||
RuleIdentifier: "ae3274",
|
||||
LociList: rule7_LociList,
|
||||
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{
|
||||
|
||||
LocusIdentifier: "f1144a",
|
||||
|
@ -202,9 +171,12 @@ func getHairTextureTraitObject()Trait{
|
|||
RuleIdentifier: "a546bf",
|
||||
LociList: rule8_LociList,
|
||||
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{
|
||||
|
||||
LocusIdentifier: "468bb3",
|
||||
|
@ -220,32 +192,26 @@ func getHairTextureTraitObject()Trait{
|
|||
RuleIdentifier: "b8dc0a",
|
||||
LociList: rule9_LociList,
|
||||
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}
|
||||
|
||||
|
||||
lociList_Rules := []int64{7349332, 11803731, 17646946}
|
||||
hairTextureLociList := []int64{17646946, 11803731, 7349332}
|
||||
|
||||
referencesMap := make(map[string]string)
|
||||
referencesMap["SNPedia.com - Hair Curliness"] = "https://www.snpedia.com/index.php/Hair_curliness"
|
||||
|
||||
outcomesList := []string{"Straight", "Curly"}
|
||||
|
||||
hairTextureLociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
||||
|
||||
hairTextureObject := Trait{
|
||||
|
||||
TraitName: "Hair Texture",
|
||||
TraitDescription: "The texture of a person's head hair.",
|
||||
DiscreteOrNumeric: "Discrete",
|
||||
LocusReferencesMap: locusReferencesMap,
|
||||
LociList: hairTextureLociList,
|
||||
LociList_Rules: lociList_Rules,
|
||||
RulesList: hairTextureRulesList,
|
||||
OutcomesList: outcomesList,
|
||||
ReferencesMap: referencesMap,
|
||||
References: referencesMap,
|
||||
}
|
||||
|
||||
return hairTextureObject
|
||||
|
|
|
@ -1,30 +1,11 @@
|
|||
package traits
|
||||
|
||||
import "seekia/internal/helpers"
|
||||
|
||||
import "maps"
|
||||
|
||||
|
||||
func getLactoseToleranceTraitObject()Trait{
|
||||
|
||||
// Map Structure: rsID -> References Map
|
||||
locusReferencesMap := make(map[int64]map[string]string)
|
||||
|
||||
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_ReferencesMap := make(map[string]string)
|
||||
rule1_ReferencesMap["SNPedia.com - rs182549"] = "https://www.snpedia.com/index.php/Rs182549"
|
||||
|
||||
rule1_Locus1Object := RuleLocus{
|
||||
|
||||
|
@ -41,9 +22,12 @@ func getLactoseToleranceTraitObject()Trait{
|
|||
RuleIdentifier: "f4e02c",
|
||||
LociList: rule1_LociList,
|
||||
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{
|
||||
|
||||
LocusIdentifier: "a7feff",
|
||||
|
@ -59,11 +43,11 @@ func getLactoseToleranceTraitObject()Trait{
|
|||
RuleIdentifier: "cc3df0",
|
||||
LociList: rule2_LociList,
|
||||
OutcomePointsMap: rule2_OutcomePointsMap,
|
||||
ReferencesMap: maps.Clone(referencesMap_rs182549),
|
||||
References: rule2_ReferencesMap,
|
||||
}
|
||||
|
||||
referencesMap_rs4988235 := make(map[string]string)
|
||||
referencesMap_rs4988235["SNPedia.com - rs4988235"] = "https://www.snpedia.com/index.php/Rs4988235"
|
||||
rule3_ReferencesMap := make(map[string]string)
|
||||
rule3_ReferencesMap["SNPedia.com - rs4988235"] = "https://www.snpedia.com/index.php/Rs4988235"
|
||||
|
||||
rule3_Locus1Object := RuleLocus{
|
||||
|
||||
|
@ -80,9 +64,12 @@ func getLactoseToleranceTraitObject()Trait{
|
|||
RuleIdentifier: "8170ee",
|
||||
LociList: rule3_LociList,
|
||||
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{
|
||||
|
||||
LocusIdentifier: "176dde",
|
||||
|
@ -98,9 +85,12 @@ func getLactoseToleranceTraitObject()Trait{
|
|||
RuleIdentifier: "52425f",
|
||||
LociList: rule4_LociList,
|
||||
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{
|
||||
|
||||
LocusIdentifier: "164acb",
|
||||
|
@ -116,31 +106,25 @@ func getLactoseToleranceTraitObject()Trait{
|
|||
RuleIdentifier: "4b5c35",
|
||||
LociList: rule5_LociList,
|
||||
OutcomePointsMap: rule5_OutcomePointsMap,
|
||||
ReferencesMap: maps.Clone(referencesMap_rs4988235),
|
||||
References: rule5_ReferencesMap,
|
||||
}
|
||||
|
||||
lactoseToleranceRulesList := []TraitRule{rule1_Object, rule2_Object, rule3_Object, rule4_Object, rule5_Object}
|
||||
|
||||
lactoseToleranceLociList := []int64{4988235, 182549}
|
||||
|
||||
referencesMap := make(map[string]string)
|
||||
referencesMap["SNPedia.com - Lactose Intolerance"] = "https://www.snpedia.com/index.php/Lactose_intolerance"
|
||||
|
||||
outcomesList := []string{"Tolerant", "Intolerant"}
|
||||
|
||||
lactoseToleranceLociList := helpers.GetListOfMapKeys(locusReferencesMap)
|
||||
|
||||
lociList_Rules := []int64{182549, 4988235}
|
||||
|
||||
lactoseToleranceObject := Trait{
|
||||
TraitName: "Lactose Tolerance",
|
||||
TraitDescription: "The ability to tolerate lactose.",
|
||||
DiscreteOrNumeric: "Discrete",
|
||||
LocusReferencesMap: locusReferencesMap,
|
||||
LociList: lactoseToleranceLociList,
|
||||
LociList_Rules: lociList_Rules,
|
||||
RulesList: lactoseToleranceRulesList,
|
||||
OutcomesList: outcomesList,
|
||||
ReferencesMap: referencesMap,
|
||||
References: referencesMap,
|
||||
}
|
||||
|
||||
return lactoseToleranceObject
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
package traits
|
||||
|
||||
import "seekia/internal/helpers"
|
||||
|
||||
import "maps"
|
||||
|
||||
func getSkinColorTraitObject()Trait{
|
||||
|
||||
// Map Structure: rsID -> References Map
|
||||
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{
|
||||
skinColorLociList := []int64{
|
||||
|
||||
//TODO: Add more SNPs.
|
||||
|
||||
|
@ -22,32 +14,12 @@ func getSkinColorTraitObject()Trait{
|
|||
26722,
|
||||
1426654,
|
||||
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/
|
||||
16891982,
|
||||
12203592,
|
||||
1042602,
|
||||
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
|
||||
7182710,
|
||||
|
@ -61,28 +33,18 @@ func getSkinColorTraitObject()Trait{
|
|||
3212368,
|
||||
}
|
||||
|
||||
for _, rsID := range lociList_3{
|
||||
locusReferencesMap[rsID] = maps.Clone(referencesMap_List3)
|
||||
}
|
||||
|
||||
|
||||
referencesMap := make(map[string]string)
|
||||
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["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{
|
||||
TraitName: "Skin Color",
|
||||
TraitDescription: "The color of a person's skin.",
|
||||
DiscreteOrNumeric: "Discrete",
|
||||
LocusReferencesMap: locusReferencesMap,
|
||||
LociList: lociList,
|
||||
LociList_Rules: []int64{},
|
||||
LociList: skinColorLociList,
|
||||
RulesList: []TraitRule{},
|
||||
OutcomesList: []string{},
|
||||
ReferencesMap: referencesMap,
|
||||
References: referencesMap,
|
||||
}
|
||||
|
||||
return skinColorObject
|
||||
|
|
|
@ -3,51 +3,30 @@
|
|||
|
||||
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"
|
||||
|
||||
type Trait struct{
|
||||
type RuleLocus struct{
|
||||
|
||||
// Example: "Eye Color"
|
||||
TraitName string
|
||||
// 3 byte hex encoded 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
|
||||
// Discrete traits have a set of outcomes (Example: Eye Color: Blue, Green...)
|
||||
// Numeric traits have a numeric outcome (Example: Height)
|
||||
// The value of this variable is either "Discrete" or "Numeric"
|
||||
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
|
||||
// List of base pair values that this RSID must fulfill to pass the rule
|
||||
// As long as the value matches any base pair value in the list, the genome has passed this rule locus
|
||||
// The genome must pass every rule locus within a rule to pass the rule
|
||||
BasePairsList []string
|
||||
}
|
||||
|
||||
|
||||
type TraitRule struct{
|
||||
|
||||
// 3 byte identifier encoded hex
|
||||
|
@ -65,26 +44,36 @@ type TraitRule struct{
|
|||
OutcomePointsMap map[string]int
|
||||
|
||||
// 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
|
||||
LocusIdentifier string
|
||||
TraitName 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
|
||||
TraitDescription string
|
||||
|
||||
// List of base pair values that this RSID must fulfill to pass the rule
|
||||
// As long as the value matches any base pair value in the list, the genome has passed this rule locus
|
||||
// The genome must pass every rule locus within a rule to pass the rule
|
||||
BasePairsList []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 calculate Racial Similarity.
|
||||
// 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 traitObjectsList []Trait
|
||||
|
||||
|
|
3
utilities/createGeneticModels/.gitignore
vendored
3
utilities/createGeneticModels/.gitignore
vendored
|
@ -1,4 +1,3 @@
|
|||
OpenSNPDataArchiveFolderpath.txt
|
||||
TrainingData
|
||||
TrainedModels
|
||||
ModelAccuracies
|
||||
TrainedModels
|
|
@ -3,7 +3,6 @@
|
|||
// 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.
|
||||
// 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
|
||||
|
||||
|
@ -1137,16 +1136,10 @@ func setStartAndMonitorTrainModelPage(window fyne.Window, traitName string, prev
|
|||
_, err := localFilesystem.CreateFolder("./TrainedModels")
|
||||
if (err != nil) { return false, err }
|
||||
|
||||
|
||||
trainingSetFilepathsList, _, err := getTrainingAndTestingDataFilepathLists(traitName)
|
||||
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
|
||||
neuralNetworkObject, err := geneticPrediction.GetNewUntrainedNeuralNetworkObject(traitName)
|
||||
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.")
|
||||
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.")
|
||||
description5 := getLabelCentered("The results will also be saved in the ModelAccuracies folder.")
|
||||
description6 := getLabelCentered("You must select a trait model to test.")
|
||||
description5 := getLabelCentered("You must select a trait model to test.")
|
||||
|
||||
traitNamesList := []string{"Eye Color", "Lactose Tolerance"}
|
||||
|
||||
|
@ -1309,12 +1301,50 @@ func setTestModelsPage(window fyne.Window, previousPage func()){
|
|||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
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()){
|
||||
|
||||
title := getBoldLabelCentered("Testing Model")
|
||||
|
@ -1356,9 +1386,9 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
|||
|
||||
//Outputs:
|
||||
// -bool: Process completed (true == was not stopped mid-way)
|
||||
// -geneticPrediction.TraitPredictionAccuracyInfoMap
|
||||
// -TraitAccuracyInfoMap
|
||||
// -error
|
||||
testModel := func()(bool, geneticPrediction.TraitPredictionAccuracyInfoMap, error){
|
||||
testModel := func()(bool, TraitAccuracyInfoMap, error){
|
||||
|
||||
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 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)
|
||||
|
@ -1464,7 +1494,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
|||
{
|
||||
// We first add the information to the map for the correct outcome
|
||||
|
||||
newTraitOutcomeInfo_CorrectOutcome := geneticPrediction.TraitOutcomeInfo{
|
||||
newTraitOutcomeInfo_CorrectOutcome := TraitOutcomeInfo{
|
||||
|
||||
OutcomeName: correctOutcomeName,
|
||||
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
|
||||
|
||||
newTraitOutcomeInfo_PredictedOutcome := geneticPrediction.TraitOutcomeInfo{
|
||||
newTraitOutcomeInfo_PredictedOutcome := TraitOutcomeInfo{
|
||||
|
||||
OutcomeName: predictedOutcomeName,
|
||||
PercentageOfLociTested: percentageOfLociTested,
|
||||
|
@ -1536,7 +1566,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
|||
// Now we construct the TraitAccuracyInfoMap
|
||||
|
||||
// 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{
|
||||
|
||||
|
@ -1553,7 +1583,7 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
|||
return false, nil, errors.New("traitPredictionInfoMap contains quantityOfCorrectOutcomePredictions > quantityOfPredictions")
|
||||
}
|
||||
|
||||
newTraitPredictionAccuracyInfo := geneticPrediction.TraitPredictionAccuracyInfo{
|
||||
newTraitPredictionAccuracyInfo := TraitPredictionAccuracyInfo{
|
||||
QuantityOfExamples: quantityOfExamples,
|
||||
QuantityOfPredictions: quantityOfPredictions,
|
||||
}
|
||||
|
@ -1574,30 +1604,17 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
|||
newTraitPredictionAccuracyInfo.ProbabilityOfCorrectOutcomePrediction = percentageOfCorrectOutcomePredictions
|
||||
}
|
||||
|
||||
traitPredictionAccuracyInfoMap[traitAccuracyData] = newTraitPredictionAccuracyInfo
|
||||
traitAccuracyInfoMap[traitAccuracyData] = newTraitPredictionAccuracyInfo
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
return true, traitPredictionAccuracyInfoMap, nil
|
||||
return true, traitAccuracyInfoMap, nil
|
||||
}
|
||||
|
||||
processIsComplete, traitPredictionAccuracyInfoMap, err := testModel()
|
||||
processIsComplete, traitAccuracyInfoMap, err := testModel()
|
||||
if (err != nil){
|
||||
setErrorEncounteredPage(window, err, previousPage)
|
||||
return
|
||||
|
@ -1607,14 +1624,14 @@ func setStartAndMonitorTestModelPage(window fyne.Window, traitName string, previ
|
|||
return
|
||||
}
|
||||
|
||||
setViewModelTestingTraitResultsPage(window, traitName, traitPredictionAccuracyInfoMap, previousPage)
|
||||
setViewModelTestingTraitResultsPage(window, traitName, traitAccuracyInfoMap, previousPage)
|
||||
}
|
||||
|
||||
go testModelFunction()
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
|
@ -1644,10 +1661,14 @@ func setViewModelTestingTraitResultsPage(window fyne.Window, traitName string, t
|
|||
predictionAccuracyTitle3 := getItalicLabelCentered("Prediction Accuracy")
|
||||
knownLociLabel_67to100 := getItalicLabelCentered("67-100% Known Loci")
|
||||
|
||||
emptyLabel2 := widget.NewLabel("")
|
||||
emptyLabel3 := widget.NewLabel("")
|
||||
|
||||
outcomeNameColumn := container.NewVBox(outcomeNameTitle, emptyLabel1, widget.NewSeparator())
|
||||
predictionAccuracyColumn_0to33 := container.NewVBox(predictionAccuracyTitle1, knownLociLabel_0to33, widget.NewSeparator())
|
||||
predictionAccuracyColumn_34to66 := container.NewVBox(predictionAccuracyTitle2, knownLociLabel_34to66, widget.NewSeparator())
|
||||
predictionAccuracyColumn_67to100 := container.NewVBox(predictionAccuracyTitle3, knownLociLabel_67to100, widget.NewSeparator())
|
||||
viewTraitAccuracyDetailsColumn := container.NewVBox(emptyLabel2, emptyLabel3, widget.NewSeparator())
|
||||
|
||||
traitObject, err := traits.GetTraitObject(traitName)
|
||||
if (err != nil) { return nil, err }
|
||||
|
@ -1756,7 +1777,7 @@ func setViewModelTestingTraitResultsPage(window fyne.Window, traitName string, t
|
|||
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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue