progeny-selector 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- progeny_selector-0.1.0/.gitattributes +11 -0
- progeny_selector-0.1.0/.gitignore +45 -0
- progeny_selector-0.1.0/CHANGELOG.md +126 -0
- progeny_selector-0.1.0/CITATION.cff +27 -0
- progeny_selector-0.1.0/CODE_OF_CONDUCT.md +132 -0
- progeny_selector-0.1.0/CONTRIBUTING.md +45 -0
- progeny_selector-0.1.0/LICENSE +21 -0
- progeny_selector-0.1.0/PKG-INFO +147 -0
- progeny_selector-0.1.0/README.md +108 -0
- progeny_selector-0.1.0/SECURITY.md +13 -0
- progeny_selector-0.1.0/contract/MANIFEST.sha256 +360 -0
- progeny_selector-0.1.0/contract/README.md +20 -0
- progeny_selector-0.1.0/contract/VERSION +1 -0
- progeny_selector-0.1.0/contract/cases/chrom-natural-order/expected.json +169 -0
- progeny_selector-0.1.0/contract/cases/chrom-natural-order/genotypes.csv +9 -0
- progeny_selector-0.1.0/contract/cases/chrom-natural-order/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/chrom-spellings/expected.json +187 -0
- progeny_selector-0.1.0/contract/cases/chrom-spellings/genotypes.csv +10 -0
- progeny_selector-0.1.0/contract/cases/chrom-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-barley-spellings/expected.json +96 -0
- progeny_selector-0.1.0/contract/cases/crop-barley-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-barley-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-barley-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-common-bean-spellings/expected.json +96 -0
- progeny_selector-0.1.0/contract/cases/crop-common-bean-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-common-bean-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-common-bean-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-cotton-spellings/expected.json +96 -0
- progeny_selector-0.1.0/contract/cases/crop-cotton-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-cotton-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-cotton-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-cowpea-spellings/expected.json +97 -0
- progeny_selector-0.1.0/contract/cases/crop-cowpea-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-cowpea-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-cowpea-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-maize-spellings/expected.json +96 -0
- progeny_selector-0.1.0/contract/cases/crop-maize-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-maize-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-maize-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-oat-spellings/expected.json +97 -0
- progeny_selector-0.1.0/contract/cases/crop-oat-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-oat-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-oat-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-pea-spellings/expected.json +97 -0
- progeny_selector-0.1.0/contract/cases/crop-pea-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-pea-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-pea-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-peanut-spellings/expected.json +97 -0
- progeny_selector-0.1.0/contract/cases/crop-peanut-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-peanut-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-peanut-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-rice-spellings/expected.json +96 -0
- progeny_selector-0.1.0/contract/cases/crop-rice-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-rice-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-rice-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-sorghum-spellings/expected.json +96 -0
- progeny_selector-0.1.0/contract/cases/crop-sorghum-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-sorghum-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-sorghum-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-soybean-data-store-spellings/expected.json +96 -0
- progeny_selector-0.1.0/contract/cases/crop-soybean-data-store-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-soybean-data-store-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-soybean-data-store-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-soybean-spellings/expected.json +96 -0
- progeny_selector-0.1.0/contract/cases/crop-soybean-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-soybean-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-soybean-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-sunflower-spellings/expected.json +173 -0
- progeny_selector-0.1.0/contract/cases/crop-sunflower-spellings/genotypes.csv +9 -0
- progeny_selector-0.1.0/contract/cases/crop-sunflower-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-sunflower-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/crop-wheat-spellings/expected.json +96 -0
- progeny_selector-0.1.0/contract/cases/crop-wheat-spellings/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/crop-wheat-spellings/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/crop-wheat-spellings/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-coded-unknown-cell/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-coded-unknown-cell/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-coded-unknown-cell/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/err-duplicate-marker/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-duplicate-marker/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-duplicate-marker/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-hash-before-header/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-hash-before-header/genotypes.hmp.txt +3 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-hash-before-header/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-latin1-byte/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-latin1-byte/genotypes.hmp.txt +3 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-latin1-byte/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-nbsp-line-before-header/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-nbsp-line-before-header/genotypes.hmp.txt +3 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-nbsp-line-before-header/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-plus/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-plus/genotypes.hmp.txt +2 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-plus/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-single-b/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-single-b/genotypes.hmp.txt +2 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-single-b/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-unknown-cell/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-unknown-cell/genotypes.hmp.txt +2 -0
- progeny_selector-0.1.0/contract/cases/err-hapmap-unknown-cell/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-markers-latin1-byte/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-markers-latin1-byte/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-markers-latin1-byte/markers.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-markers-latin1-byte/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-markers-unterminated-quote/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-markers-unterminated-quote/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-markers-unterminated-quote/markers.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-markers-unterminated-quote/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-pair-stray/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-pair-stray/genotypes.csv +2 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-pair-stray/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-single-h/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-single-h/genotypes.csv +2 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-single-h/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-unknown-cell/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-unknown-cell/genotypes.csv +2 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-unknown-cell/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-xx/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-xx/genotypes.csv +2 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-xx/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-zero/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-zero/genotypes.csv +2 -0
- progeny_selector-0.1.0/contract/cases/err-nucleotide-zero/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-position-fraction/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-position-fraction/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-position-fraction/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-profile-ambiguous-het/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-profile-ambiguous-het/genotypes.csv +2 -0
- progeny_selector-0.1.0/contract/cases/err-profile-ambiguous-het/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/err-profile-ambiguous-het/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-profile-none-half-missing-pair/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-profile-none-half-missing-pair/genotypes.csv +2 -0
- progeny_selector-0.1.0/contract/cases/err-profile-none-half-missing-pair/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/err-profile-none-half-missing-pair/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-profile-none-two-missing-pair/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-profile-none-two-missing-pair/genotypes.csv +2 -0
- progeny_selector-0.1.0/contract/cases/err-profile-none-two-missing-pair/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/err-profile-none-two-missing-pair/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-profile-nucleotide-on-coded/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-profile-nucleotide-on-coded/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-profile-nucleotide-on-coded/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/err-profile-nucleotide-on-coded/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-profile-with-vcf/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-profile-with-vcf/genotypes.vcf +7 -0
- progeny_selector-0.1.0/contract/cases/err-profile-with-vcf/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/err-profile-with-vcf/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-sample-missing/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-sample-missing/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-sample-missing/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/err-samples-hash-row/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-samples-hash-row/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-samples-hash-row/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-samples-latin1-byte/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-samples-latin1-byte/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-samples-latin1-byte/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-two-recurrent-parents/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-two-recurrent-parents/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-two-recurrent-parents/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-unknown-role/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-unknown-role/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-unknown-role/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-empty-side/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-empty-side/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-empty-side/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-exceeds-alt/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-exceeds-alt/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-exceeds-alt/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-exponent/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-exponent/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-exponent/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-leading-phase/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-leading-phase/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-leading-phase/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-leading-zero/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-leading-zero/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-leading-zero/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-negative/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-negative/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-negative/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-triploid/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-triploid/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-triploid/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-underscore/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-underscore/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gt-underscore/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gzip-latin1-byte/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gzip-latin1-byte/genotypes.vcf.gz +0 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-gzip-latin1-byte/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-hash-line-after-header/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-hash-line-after-header/genotypes.vcf +5 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-hash-line-after-header/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-latin1-byte/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-latin1-byte/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-latin1-byte/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-overlong-byte/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-overlong-byte/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-overlong-byte/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-position-float/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-position-float/genotypes.vcf +3 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-position-float/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-second-header/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-second-header/genotypes.vcf +5 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-second-header/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-surrogate-byte/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-surrogate-byte/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-surrogate-byte/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-truncated-sequence-at-eof/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-truncated-sequence-at-eof/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/err-vcf-truncated-sequence-at-eof/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/err-wide-latin1-byte/expected-error.json +4 -0
- progeny_selector-0.1.0/contract/cases/err-wide-latin1-byte/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/err-wide-latin1-byte/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/hapmap-blank-lines-skipped/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/hapmap-blank-lines-skipped/genotypes.hmp.txt +6 -0
- progeny_selector-0.1.0/contract/cases/hapmap-blank-lines-skipped/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/hapmap-half-missing-pair/expected.json +89 -0
- progeny_selector-0.1.0/contract/cases/hapmap-half-missing-pair/genotypes.hmp.txt +5 -0
- progeny_selector-0.1.0/contract/cases/hapmap-half-missing-pair/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/hapmap-iupac/expected.json +166 -0
- progeny_selector-0.1.0/contract/cases/hapmap-iupac/genotypes.hmp.txt +7 -0
- progeny_selector-0.1.0/contract/cases/hapmap-iupac/samples.csv +6 -0
- progeny_selector-0.1.0/contract/cases/hapmap-missing-na-dot/expected.json +102 -0
- progeny_selector-0.1.0/contract/cases/hapmap-missing-na-dot/genotypes.hmp.txt +6 -0
- progeny_selector-0.1.0/contract/cases/hapmap-missing-na-dot/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/hapmap-position-whole-float/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/hapmap-position-whole-float/genotypes.hmp.txt +3 -0
- progeny_selector-0.1.0/contract/cases/hapmap-position-whole-float/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/hapmap-two-missing-pair/expected.json +73 -0
- progeny_selector-0.1.0/contract/cases/hapmap-two-missing-pair/genotypes.hmp.txt +4 -0
- progeny_selector-0.1.0/contract/cases/hapmap-two-missing-pair/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/markers-blank-rows-skipped/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/markers-blank-rows-skipped/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/markers-blank-rows-skipped/markers.csv +5 -0
- progeny_selector-0.1.0/contract/cases/markers-blank-rows-skipped/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/markers-override-partial-cm/expected.json +94 -0
- progeny_selector-0.1.0/contract/cases/markers-override-partial-cm/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/markers-override-partial-cm/markers.csv +4 -0
- progeny_selector-0.1.0/contract/cases/markers-override-partial-cm/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/profile-axiom-wide/expected.json +55 -0
- progeny_selector-0.1.0/contract/cases/profile-axiom-wide/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/profile-axiom-wide/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/profile-axiom-wide/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/profile-dart-wide/expected.json +55 -0
- progeny_selector-0.1.0/contract/cases/profile-dart-wide/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/profile-dart-wide/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/profile-dart-wide/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/profile-kasp-wide/expected.json +55 -0
- progeny_selector-0.1.0/contract/cases/profile-kasp-wide/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/profile-kasp-wide/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/profile-kasp-wide/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/profile-soybase-report-hapmap/expected.json +73 -0
- progeny_selector-0.1.0/contract/cases/profile-soybase-report-hapmap/genotypes.hmp.txt +4 -0
- progeny_selector-0.1.0/contract/cases/profile-soybase-report-hapmap/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/profile-soybase-report-hapmap/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/profile-soybase-report-wide/expected.json +55 -0
- progeny_selector-0.1.0/contract/cases/profile-soybase-report-wide/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/profile-soybase-report-wide/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/profile-soybase-report-wide/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-half-missing-pair/expected.json +57 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-half-missing-pair/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-half-missing-pair/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-half-missing-pair/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-two-missing-pair/expected.json +57 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-two-missing-pair/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-two-missing-pair/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-two-missing-pair/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-wide/expected.json +52 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-wide/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-wide/options.json +3 -0
- progeny_selector-0.1.0/contract/cases/profile-tassel-wide/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/samples-blank-rows-skipped/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/samples-blank-rows-skipped/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/samples-blank-rows-skipped/samples.csv +7 -0
- progeny_selector-0.1.0/contract/cases/samples-manifest-defaults/expected.json +69 -0
- progeny_selector-0.1.0/contract/cases/samples-manifest-defaults/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/samples-manifest-defaults/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/samples-midfield-quote-literal/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/samples-midfield-quote-literal/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/samples-midfield-quote-literal/markers.csv +3 -0
- progeny_selector-0.1.0/contract/cases/samples-midfield-quote-literal/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/samples-quoted-fields/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/samples-quoted-fields/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/samples-quoted-fields/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/samples-quoted-newline/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/samples-quoted-newline/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/samples-quoted-newline/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/vcf-basic/expected.json +104 -0
- progeny_selector-0.1.0/contract/cases/vcf-basic/genotypes.vcf +7 -0
- progeny_selector-0.1.0/contract/cases/vcf-basic/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/vcf-bgzip-two-members-eof/expected.json +73 -0
- progeny_selector-0.1.0/contract/cases/vcf-bgzip-two-members-eof/genotypes.vcf.gz +0 -0
- progeny_selector-0.1.0/contract/cases/vcf-bgzip-two-members-eof/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/vcf-bgzip-utf8-split-across-members/expected.json +73 -0
- progeny_selector-0.1.0/contract/cases/vcf-bgzip-utf8-split-across-members/genotypes.vcf.gz +0 -0
- progeny_selector-0.1.0/contract/cases/vcf-bgzip-utf8-split-across-members/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/vcf-blank-lines-skipped/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/vcf-blank-lines-skipped/genotypes.vcf +8 -0
- progeny_selector-0.1.0/contract/cases/vcf-blank-lines-skipped/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/vcf-gt-haploid-and-missing/expected.json +133 -0
- progeny_selector-0.1.0/contract/cases/vcf-gt-haploid-and-missing/genotypes.vcf +9 -0
- progeny_selector-0.1.0/contract/cases/vcf-gt-haploid-and-missing/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/vcf-gt-multiallelic-index/expected.json +40 -0
- progeny_selector-0.1.0/contract/cases/vcf-gt-multiallelic-index/genotypes.vcf +3 -0
- progeny_selector-0.1.0/contract/cases/vcf-gt-multiallelic-index/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/vcf-gzip-one-member/expected.json +73 -0
- progeny_selector-0.1.0/contract/cases/vcf-gzip-one-member/genotypes.vcf.gz +0 -0
- progeny_selector-0.1.0/contract/cases/vcf-gzip-one-member/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/vcf-id-dot-crlf/expected.json +76 -0
- progeny_selector-0.1.0/contract/cases/vcf-id-dot-crlf/genotypes.vcf +5 -0
- progeny_selector-0.1.0/contract/cases/vcf-id-dot-crlf/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/vcf-position-digits-id/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/vcf-position-digits-id/genotypes.vcf +4 -0
- progeny_selector-0.1.0/contract/cases/vcf-position-digits-id/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/wide-blank-lines-skipped/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/wide-blank-lines-skipped/genotypes.csv +6 -0
- progeny_selector-0.1.0/contract/cases/wide-blank-lines-skipped/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/wide-coded-blank-line-before-header/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/wide-coded-blank-line-before-header/genotypes.csv +4 -0
- progeny_selector-0.1.0/contract/cases/wide-coded-blank-line-before-header/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/wide-coded-parents-absent/expected.json +85 -0
- progeny_selector-0.1.0/contract/cases/wide-coded-parents-absent/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/wide-coded-parents-absent/samples.csv +6 -0
- progeny_selector-0.1.0/contract/cases/wide-empty-row-skipped/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/wide-empty-row-skipped/genotypes.csv +4 -0
- progeny_selector-0.1.0/contract/cases/wide-empty-row-skipped/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/wide-half-missing-pair/expected.json +89 -0
- progeny_selector-0.1.0/contract/cases/wide-half-missing-pair/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/wide-half-missing-pair/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/wide-hash-row-is-data/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/wide-hash-row-is-data/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/wide-hash-row-is-data/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/wide-nucleotide-comma/expected.json +117 -0
- progeny_selector-0.1.0/contract/cases/wide-nucleotide-comma/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/wide-nucleotide-comma/samples.csv +6 -0
- progeny_selector-0.1.0/contract/cases/wide-nucleotide-iupac/expected.json +154 -0
- progeny_selector-0.1.0/contract/cases/wide-nucleotide-iupac/genotypes.csv +7 -0
- progeny_selector-0.1.0/contract/cases/wide-nucleotide-iupac/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/wide-nucleotide-tab-crlf-bom/expected.json +98 -0
- progeny_selector-0.1.0/contract/cases/wide-nucleotide-tab-crlf-bom/genotypes.tsv +5 -0
- progeny_selector-0.1.0/contract/cases/wide-nucleotide-tab-crlf-bom/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/wide-position-whole-float/expected.json +94 -0
- progeny_selector-0.1.0/contract/cases/wide-position-whole-float/genotypes.csv +5 -0
- progeny_selector-0.1.0/contract/cases/wide-position-whole-float/markers.csv +5 -0
- progeny_selector-0.1.0/contract/cases/wide-position-whole-float/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/wide-tab-blank-line-before-header/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/wide-tab-blank-line-before-header/genotypes.csv +6 -0
- progeny_selector-0.1.0/contract/cases/wide-tab-blank-line-before-header/samples.csv +4 -0
- progeny_selector-0.1.0/contract/cases/wide-two-missing-pair/expected.json +73 -0
- progeny_selector-0.1.0/contract/cases/wide-two-missing-pair/genotypes.csv +4 -0
- progeny_selector-0.1.0/contract/cases/wide-two-missing-pair/samples.csv +5 -0
- progeny_selector-0.1.0/contract/cases/wide-utf8-non-ascii-ids/expected.json +58 -0
- progeny_selector-0.1.0/contract/cases/wide-utf8-non-ascii-ids/genotypes.csv +3 -0
- progeny_selector-0.1.0/contract/cases/wide-utf8-non-ascii-ids/samples.csv +4 -0
- progeny_selector-0.1.0/contract/crops/barley.json +29 -0
- progeny_selector-0.1.0/contract/crops/common-bean.json +39 -0
- progeny_selector-0.1.0/contract/crops/cotton.json +67 -0
- progeny_selector-0.1.0/contract/crops/cowpea.json +43 -0
- progeny_selector-0.1.0/contract/crops/maize.json +36 -0
- progeny_selector-0.1.0/contract/crops/oat.json +57 -0
- progeny_selector-0.1.0/contract/crops/pea.json +34 -0
- progeny_selector-0.1.0/contract/crops/peanut.json +62 -0
- progeny_selector-0.1.0/contract/crops/rice.json +41 -0
- progeny_selector-0.1.0/contract/crops/sorghum.json +35 -0
- progeny_selector-0.1.0/contract/crops/soybean.json +57 -0
- progeny_selector-0.1.0/contract/crops/sunflower.json +54 -0
- progeny_selector-0.1.0/contract/crops/wheat.json +57 -0
- progeny_selector-0.1.0/contract/data-contract.md +97 -0
- progeny_selector-0.1.0/contract/profiles/axiom.json +10 -0
- progeny_selector-0.1.0/contract/profiles/dart.json +10 -0
- progeny_selector-0.1.0/contract/profiles/kasp.json +12 -0
- progeny_selector-0.1.0/contract/profiles/soybase-report.json +12 -0
- progeny_selector-0.1.0/contract/profiles/tassel.json +12 -0
- progeny_selector-0.1.0/docs/README.md +13 -0
- progeny_selector-0.1.0/docs/accessibility.md +81 -0
- progeny_selector-0.1.0/docs/adr/0001-python-core-shiny-ui-shinylive.md +36 -0
- progeny_selector-0.1.0/docs/adr/0002-input-data-contract.md +27 -0
- progeny_selector-0.1.0/docs/adr/0003-hosting-local-shiny-and-shinylive-pages.md +30 -0
- progeny_selector-0.1.0/docs/adr/0004-mit-license.md +19 -0
- progeny_selector-0.1.0/docs/adr/0005-criteria-file-yaml.md +25 -0
- progeny_selector-0.1.0/docs/adr/0006-parent-of-origin-and-rpp-definitions.md +33 -0
- progeny_selector-0.1.0/docs/adr/0007-hard-filters-before-composite-score.md +29 -0
- progeny_selector-0.1.0/docs/adr/0008-screen-testing-and-extras.md +21 -0
- progeny_selector-0.1.0/docs/adr/0009-shinylive-export-staging.md +25 -0
- progeny_selector-0.1.0/docs/adr/0010-contract-1.1-alignment.md +25 -0
- progeny_selector-0.1.0/docs/adr/0011-foreground-run-rule.md +35 -0
- progeny_selector-0.1.0/docs/adr/0012-family-donor-outlier.md +40 -0
- progeny_selector-0.1.0/docs/adr/0013-contract-1.3-lines-and-rows.md +27 -0
- progeny_selector-0.1.0/docs/adr/0014-contract-1.4-token-profiles.md +30 -0
- progeny_selector-0.1.0/docs/adr/0015-assembly-selector-and-map-warnings.md +43 -0
- progeny_selector-0.1.0/docs/adr/0016-results-schema-freeze.md +45 -0
- progeny_selector-0.1.0/docs/adr/0017-duplicate-flag.md +62 -0
- progeny_selector-0.1.0/docs/adr/0018-two-generation-round-trip.md +34 -0
- progeny_selector-0.1.0/docs/adr/0019-soybean-input-tooling.md +53 -0
- progeny_selector-0.1.0/docs/adr/0020-contract-1.5-crop-schemes.md +29 -0
- progeny_selector-0.1.0/docs/adr/0021-measured-limits.md +63 -0
- progeny_selector-0.1.0/docs/adr/0022-streaming-vcf-parse.md +148 -0
- progeny_selector-0.1.0/docs/adr/0023-accessibility-baseline.md +90 -0
- progeny_selector-0.1.0/docs/adr/0024-brapi-allele-matrix-loader.md +154 -0
- progeny_selector-0.1.0/docs/adr/0025-core-sample-chunking.md +140 -0
- progeny_selector-0.1.0/docs/adr/0026-contract-1.6-half-missing-pair.md +29 -0
- progeny_selector-0.1.0/docs/adr/0027-contract-1.7-crop-schemes.md +29 -0
- progeny_selector-0.1.0/docs/adr/0028-contract-1.8-two-missing-pair.md +25 -0
- progeny_selector-0.1.0/docs/adr/0029-contract-1.9-sunflower-scheme.md +25 -0
- progeny_selector-0.1.0/docs/adr/0030-contract-1.10-vcf-gt-grammar.md +43 -0
- progeny_selector-0.1.0/docs/adr/0031-contract-1.11-utf8-text.md +51 -0
- progeny_selector-0.1.0/docs/adr/0032-contract-1.12-soybean-data-store-names.md +27 -0
- progeny_selector-0.1.0/docs/adr/0033-results-schema-1.2-cap-and-end-rule.md +46 -0
- progeny_selector-0.1.0/docs/adr/0034-purdy-generation-labels.md +28 -0
- progeny_selector-0.1.0/docs/adr/0035-release-decisions-and-provenance.md +52 -0
- progeny_selector-0.1.0/docs/adr/0036-first-public-release-packaging.md +34 -0
- progeny_selector-0.1.0/docs/data-formats.md +208 -0
- progeny_selector-0.1.0/docs/glossary.md +120 -0
- progeny_selector-0.1.0/docs/handoffs/2026-09-21-m3-planning.md +135 -0
- progeny_selector-0.1.0/docs/keyboard-walkthrough.md +75 -0
- progeny_selector-0.1.0/docs/legacy-readme.md +50 -0
- progeny_selector-0.1.0/docs/limits.md +86 -0
- progeny_selector-0.1.0/docs/reference-repos.md +63 -0
- progeny_selector-0.1.0/docs/soybean-inputs.md +63 -0
- progeny_selector-0.1.0/docs/tutorial.md +191 -0
- progeny_selector-0.1.0/pyproject.toml +84 -0
- progeny_selector-0.1.0/scripts/bench_pipeline.py +320 -0
- progeny_selector-0.1.0/scripts/bench_shinylive.py +163 -0
- progeny_selector-0.1.0/scripts/build_shinylive.py +113 -0
- progeny_selector-0.1.0/scripts/changelog_section.py +86 -0
- progeny_selector-0.1.0/scripts/check_contract.py +118 -0
- progeny_selector-0.1.0/scripts/kasp_to_wide.py +289 -0
- progeny_selector-0.1.0/scripts/make_fixture.py +998 -0
- progeny_selector-0.1.0/scripts/read_results.R +181 -0
- progeny_selector-0.1.0/scripts/song2016_map.py +308 -0
- progeny_selector-0.1.0/scripts/soysnp50k_nils.py +236 -0
- progeny_selector-0.1.0/scripts/soysnp_positions.py +266 -0
- progeny_selector-0.1.0/src/progeny_selector/__init__.py +11 -0
- progeny_selector-0.1.0/src/progeny_selector/__main__.py +6 -0
- progeny_selector-0.1.0/src/progeny_selector/_version.py +6 -0
- progeny_selector-0.1.0/src/progeny_selector/app/__init__.py +6 -0
- progeny_selector-0.1.0/src/progeny_selector/app/app.py +57 -0
- progeny_selector-0.1.0/src/progeny_selector/app/present.py +201 -0
- progeny_selector-0.1.0/src/progeny_selector/app/screens/__init__.py +1 -0
- progeny_selector-0.1.0/src/progeny_selector/app/screens/compare.py +285 -0
- progeny_selector-0.1.0/src/progeny_selector/app/screens/export.py +112 -0
- progeny_selector-0.1.0/src/progeny_selector/app/screens/load.py +293 -0
- progeny_selector-0.1.0/src/progeny_selector/app/screens/navigate.py +132 -0
- progeny_selector-0.1.0/src/progeny_selector/app/screens/qc.py +125 -0
- progeny_selector-0.1.0/src/progeny_selector/app/screens/rank.py +111 -0
- progeny_selector-0.1.0/src/progeny_selector/app/screens/select.py +97 -0
- progeny_selector-0.1.0/src/progeny_selector/cli.py +369 -0
- progeny_selector-0.1.0/src/progeny_selector/config.py +39 -0
- progeny_selector-0.1.0/src/progeny_selector/constants.py +219 -0
- progeny_selector-0.1.0/src/progeny_selector/core/__init__.py +5 -0
- progeny_selector-0.1.0/src/progeny_selector/core/avoid.py +27 -0
- progeny_selector-0.1.0/src/progeny_selector/core/background.py +117 -0
- progeny_selector-0.1.0/src/progeny_selector/core/chrom.py +141 -0
- progeny_selector-0.1.0/src/progeny_selector/core/classify.py +113 -0
- progeny_selector-0.1.0/src/progeny_selector/core/drag.py +120 -0
- progeny_selector-0.1.0/src/progeny_selector/core/foreground.py +209 -0
- progeny_selector-0.1.0/src/progeny_selector/core/generation.py +124 -0
- progeny_selector-0.1.0/src/progeny_selector/core/genetic_map.py +79 -0
- progeny_selector-0.1.0/src/progeny_selector/core/navigation.py +84 -0
- progeny_selector-0.1.0/src/progeny_selector/core/pipeline.py +384 -0
- progeny_selector-0.1.0/src/progeny_selector/core/qc.py +327 -0
- progeny_selector-0.1.0/src/progeny_selector/core/score.py +179 -0
- progeny_selector-0.1.0/src/progeny_selector/core/selection.py +71 -0
- progeny_selector-0.1.0/src/progeny_selector/core/similarity.py +126 -0
- progeny_selector-0.1.0/src/progeny_selector/core/strip.py +95 -0
- progeny_selector-0.1.0/src/progeny_selector/examples/__init__.py +87 -0
- progeny_selector-0.1.0/src/progeny_selector/examples/synthetic_bc2f1/criteria.yaml +23 -0
- progeny_selector-0.1.0/src/progeny_selector/examples/synthetic_bc2f1/genotypes.vcf +504 -0
- progeny_selector-0.1.0/src/progeny_selector/examples/synthetic_bc2f1/markers.csv +501 -0
- progeny_selector-0.1.0/src/progeny_selector/examples/synthetic_bc2f1/samples.csv +43 -0
- progeny_selector-0.1.0/src/progeny_selector/examples/synthetic_bc3f1/genotypes.vcf +504 -0
- progeny_selector-0.1.0/src/progeny_selector/examples/synthetic_bc3f1/samples.csv +43 -0
- progeny_selector-0.1.0/src/progeny_selector/io/__init__.py +93 -0
- progeny_selector-0.1.0/src/progeny_selector/io/brapi.py +630 -0
- progeny_selector-0.1.0/src/progeny_selector/io/calls.py +167 -0
- progeny_selector-0.1.0/src/progeny_selector/io/criteria.py +305 -0
- progeny_selector-0.1.0/src/progeny_selector/io/crops.py +450 -0
- progeny_selector-0.1.0/src/progeny_selector/io/delimited.py +164 -0
- progeny_selector-0.1.0/src/progeny_selector/io/export.py +302 -0
- progeny_selector-0.1.0/src/progeny_selector/io/hapmap.py +96 -0
- progeny_selector-0.1.0/src/progeny_selector/io/manifest.py +149 -0
- progeny_selector-0.1.0/src/progeny_selector/io/position.py +58 -0
- progeny_selector-0.1.0/src/progeny_selector/io/profiles.py +243 -0
- progeny_selector-0.1.0/src/progeny_selector/io/vcf.py +215 -0
- progeny_selector-0.1.0/src/progeny_selector/io/wide_csv.py +102 -0
- progeny_selector-0.1.0/src/progeny_selector/model/__init__.py +29 -0
- progeny_selector-0.1.0/src/progeny_selector/model/criteria.py +217 -0
- progeny_selector-0.1.0/src/progeny_selector/model/dataset.py +213 -0
- progeny_selector-0.1.0/src/progeny_selector/provenance.py +100 -0
- progeny_selector-0.1.0/tests/__init__.py +0 -0
- progeny_selector-0.1.0/tests/conftest.py +45 -0
- progeny_selector-0.1.0/tests/e2e/__init__.py +0 -0
- progeny_selector-0.1.0/tests/e2e/conftest.py +39 -0
- progeny_selector-0.1.0/tests/e2e/helpers.py +26 -0
- progeny_selector-0.1.0/tests/e2e/test_a11y.py +129 -0
- progeny_selector-0.1.0/tests/e2e/test_criteria_editor.py +140 -0
- progeny_selector-0.1.0/tests/e2e/test_export_manifest.py +110 -0
- progeny_selector-0.1.0/tests/e2e/test_focus_order.py +52 -0
- progeny_selector-0.1.0/tests/e2e/test_keyboard_walkthrough.py +81 -0
- progeny_selector-0.1.0/tests/e2e/test_load_screen.py +26 -0
- progeny_selector-0.1.0/tests/e2e/test_load_upload_names.py +81 -0
- progeny_selector-0.1.0/tests/e2e/test_navigate_gaps.py +106 -0
- progeny_selector-0.1.0/tests/e2e/test_navigate_rank.py +163 -0
- progeny_selector-0.1.0/tests/e2e/test_qc_compare.py +159 -0
- progeny_selector-0.1.0/tests/e2e/test_reload.py +57 -0
- progeny_selector-0.1.0/tests/e2e/test_select_top_n.py +43 -0
- progeny_selector-0.1.0/tests/e2e/test_selection_notes.py +85 -0
- progeny_selector-0.1.0/tests/e2e/test_shinylive_export.py +162 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/README.md +24 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/allelematrix.v0.c0.json +149 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/allelematrix.v0.c1.json +121 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/allelematrix.v1.c0.json +141 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/allelematrix.v1.c1.json +115 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/callsets.p0.json +59 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/callsets.p1.json +41 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/criteria.yaml +20 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/samples.csv +9 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/variants-nopos.p0.json +315 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/variants.p0.json +197 -0
- progeny_selector-0.1.0/tests/fixtures/brapi/variants.p1.json +183 -0
- progeny_selector-0.1.0/tests/fixtures/synthetic_bc2f1/README.md +5 -0
- progeny_selector-0.1.0/tests/fixtures/synthetic_bc2f1/criteria.yaml +23 -0
- progeny_selector-0.1.0/tests/fixtures/synthetic_bc2f1/expected_results.csv +41 -0
- progeny_selector-0.1.0/tests/fixtures/synthetic_bc2f1/genotypes.vcf +504 -0
- progeny_selector-0.1.0/tests/fixtures/synthetic_bc2f1/markers.csv +501 -0
- progeny_selector-0.1.0/tests/fixtures/synthetic_bc2f1/samples.csv +43 -0
- progeny_selector-0.1.0/tests/fixtures/synthetic_bc3f1/README.md +35 -0
- progeny_selector-0.1.0/tests/fixtures/synthetic_bc3f1/expected_results.csv +41 -0
- progeny_selector-0.1.0/tests/fixtures/synthetic_bc3f1/genotypes.vcf +504 -0
- progeny_selector-0.1.0/tests/fixtures/synthetic_bc3f1/samples.csv +43 -0
- progeny_selector-0.1.0/tests/test_assembly_resolution.py +93 -0
- progeny_selector-0.1.0/tests/test_bench_generator.py +55 -0
- progeny_selector-0.1.0/tests/test_brapi.py +618 -0
- progeny_selector-0.1.0/tests/test_changelog_section.py +144 -0
- progeny_selector-0.1.0/tests/test_check_contract.py +73 -0
- progeny_selector-0.1.0/tests/test_chrom_assembly.py +55 -0
- progeny_selector-0.1.0/tests/test_classify.py +67 -0
- progeny_selector-0.1.0/tests/test_cli_app.py +33 -0
- progeny_selector-0.1.0/tests/test_cli_select_top.py +52 -0
- progeny_selector-0.1.0/tests/test_compare_view.py +115 -0
- progeny_selector-0.1.0/tests/test_contract_cases.py +131 -0
- progeny_selector-0.1.0/tests/test_core_memory.py +277 -0
- progeny_selector-0.1.0/tests/test_criteria_hardening.py +151 -0
- progeny_selector-0.1.0/tests/test_criteria_roundtrip.py +177 -0
- progeny_selector-0.1.0/tests/test_crops.py +741 -0
- progeny_selector-0.1.0/tests/test_docs_commands.py +34 -0
- progeny_selector-0.1.0/tests/test_duplicates.py +240 -0
- progeny_selector-0.1.0/tests/test_examples.py +97 -0
- progeny_selector-0.1.0/tests/test_export_text.py +94 -0
- progeny_selector-0.1.0/tests/test_generation_purdy.py +76 -0
- progeny_selector-0.1.0/tests/test_genetic_map.py +55 -0
- progeny_selector-0.1.0/tests/test_github_templates.py +50 -0
- progeny_selector-0.1.0/tests/test_io.py +700 -0
- progeny_selector-0.1.0/tests/test_kasp_to_wide.py +241 -0
- progeny_selector-0.1.0/tests/test_map_warnings.py +153 -0
- progeny_selector-0.1.0/tests/test_navigation.py +82 -0
- progeny_selector-0.1.0/tests/test_next_generation.py +153 -0
- progeny_selector-0.1.0/tests/test_present.py +144 -0
- progeny_selector-0.1.0/tests/test_profiles.py +293 -0
- progeny_selector-0.1.0/tests/test_provenance.py +144 -0
- progeny_selector-0.1.0/tests/test_qc_family_outlier.py +191 -0
- progeny_selector-0.1.0/tests/test_qc_table.py +86 -0
- progeny_selector-0.1.0/tests/test_ranking_staged.py +103 -0
- progeny_selector-0.1.0/tests/test_ranking_staged_pipeline.py +72 -0
- progeny_selector-0.1.0/tests/test_readme_links.py +41 -0
- progeny_selector-0.1.0/tests/test_results_schema.py +337 -0
- progeny_selector-0.1.0/tests/test_round_trip.py +238 -0
- progeny_selector-0.1.0/tests/test_run_rule.py +334 -0
- progeny_selector-0.1.0/tests/test_smoke_pipeline.py +207 -0
- progeny_selector-0.1.0/tests/test_song2016_map.py +259 -0
- progeny_selector-0.1.0/tests/test_soysnp50k_nils.py +231 -0
- progeny_selector-0.1.0/tests/test_soysnp_positions.py +113 -0
- progeny_selector-0.1.0/tests/test_status_metrics.py +195 -0
- progeny_selector-0.1.0/tests/test_strip.py +176 -0
- progeny_selector-0.1.0/tests/test_utf8.py +194 -0
- progeny_selector-0.1.0/tests/test_vcf_streaming.py +247 -0
- progeny_selector-0.1.0/tests/test_version.py +45 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Normalise line endings: the repository is LF everywhere, so a regenerated
|
|
2
|
+
# fixture on Windows matches the committed files.
|
|
3
|
+
* text=auto eol=lf
|
|
4
|
+
|
|
5
|
+
# The data contract (contract/) is mirrored byte for byte from backcross and hashed
|
|
6
|
+
# in MANIFEST.sha256; its text is LF on every checkout, its case files are the generator's
|
|
7
|
+
# bytes verbatim (some are CRLF by design), and its gzip and bgzip cases are never normalised.
|
|
8
|
+
contract/** text eol=lf
|
|
9
|
+
contract/cases/** -text
|
|
10
|
+
*.gz binary
|
|
11
|
+
*.bgz binary
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
.mypy_cache/
|
|
11
|
+
.ruff_cache/
|
|
12
|
+
.coverage
|
|
13
|
+
htmlcov/
|
|
14
|
+
|
|
15
|
+
# shinylive export
|
|
16
|
+
site/
|
|
17
|
+
# written only into the staged copy by scripts/build_shinylive.py (docs/adr/0035)
|
|
18
|
+
src/progeny_selector/_build_commit.txt
|
|
19
|
+
|
|
20
|
+
# local environment
|
|
21
|
+
.env
|
|
22
|
+
.env.local
|
|
23
|
+
|
|
24
|
+
# local Claude Code tooling (token-economy kit hooks), never committed
|
|
25
|
+
.claude/
|
|
26
|
+
|
|
27
|
+
# editors and OS
|
|
28
|
+
.vscode/
|
|
29
|
+
.idea/
|
|
30
|
+
.DS_Store
|
|
31
|
+
|
|
32
|
+
# genotype data is never committed; the synthetic fixture is the only exception
|
|
33
|
+
data/
|
|
34
|
+
*.vcf
|
|
35
|
+
*.vcf.gz
|
|
36
|
+
*.hmp.txt
|
|
37
|
+
results*.csv
|
|
38
|
+
selected*.csv
|
|
39
|
+
!tests/fixtures/**
|
|
40
|
+
!contract/**
|
|
41
|
+
# the shipped examples (package data, written by scripts/make_fixture.py): *.vcf is ignored
|
|
42
|
+
# globally, and hatchling excludes VCS-ignored files from the sdist and wheel by default, so
|
|
43
|
+
# without this line the package data would be missing from both git and the wheel
|
|
44
|
+
!src/progeny_selector/examples/**
|
|
45
|
+
src/progeny_selector/examples/**/__pycache__/
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file. The format follows Keep a Changelog 1.1.0 (https://keepachangelog.com/en/1.1.0/) and the project uses Semantic Versioning (https://semver.org/spec/v2.0.0.html).
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
Nothing yet.
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-09-29
|
|
10
|
+
|
|
11
|
+
The first public release. It implements input data contract 1.12.0, shared with backcross, and writes results.csv and selected.csv under results_schema 1.2.0. The sibling backcross v0.1.0 was released the same day (https://github.com/piercetaylor/backcross/releases/tag/v0.1.0; docs/adr/0035 Q6).
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Continuous integration covers Python 3.11, 3.12 and 3.13, plus Windows and macOS. A `package` job validates CITATION.cff, builds the sdist and wheel, runs `twine check`, and runs the example end to end from the installed wheel in a fresh environment. A tag-triggered release workflow publishes to PyPI by trusted publishing and creates the GitHub release from this file's section.
|
|
16
|
+
- `progeny-selector app [--host] [--port] [--no-browser]` starts the browser interface from an installed package, and the Load screen has a "Load example (synthetic BC2F1)" button, which also works in the Shinylive site.
|
|
17
|
+
- `progeny-selector example [--out DIR] [--name synthetic_bc2f1|synthetic_bc3f1|all] [--force]` writes the synthetic BC2F1 and BC3F1 example datasets, which now ship inside the package, so the quickstart runs without a checkout. The command refuses to overwrite existing files unless given `--force`.
|
|
18
|
+
- `progeny-selector --version` prints the installed version, read from one source (`src/progeny_selector/_version.py`).
|
|
19
|
+
- Single-cross Purdy generation labels are read for the backcross count: `RP*3/DONOR`, `3*RP/DONOR`, `DONOR/RP*3` and `DONOR/3*RP` (a recurrent-parent dose n of 2 or more is BC(n-1), n = 1 the F1). Such a line gets an expected RPP and no longer carries `generation_unparsed`; its `expected_het` is `NA` and `het_rate_deviates` and `possible_self_or_outcross` are not evaluated, since the label states no filial generation. Write the BCnFm label (`BC2F1`) to keep those checks (docs/adr/0034).
|
|
20
|
+
- `scripts/kasp_to_wide.py` names up to five distinct unrecognised call strings, with their counts, in its stderr summary, so a vendor token the converter does not know is visible rather than only counted. `?`, `NTC` and empty are documented as the missing tokens seen in real exports; `Uncallable`, `Missing`, `Bad` and `Dupe` stay accepted as assumed aliases (docs/soybean-inputs.md).
|
|
21
|
+
|
|
22
|
+
- The shared input contract mirror is version 1.12.0: the soybean scheme also reads the SoyBase / LIS Data Store names of Williams 82 (`glyma.Wm82.gnmN.Gm01`, `glyma.Wm82.gnm5.Chr01`) and the V1.1 spelling `GLYMAchr_01` (canonical record: backcross docs/adr/0027; mirror record docs/adr/0032).
|
|
23
|
+
- The shared input contract mirror is version 1.11.0: every text input is UTF-8 (canonical record: backcross docs/adr/0026; mirror record docs/adr/0031). A byte sequence that is not well-formed UTF-8 in the genotype file (plain, gzip or bgzip), samples.csv or markers.csv now raises `DataContractError` naming the file, the physical line and the byte position (`{path}: line N: not valid UTF-8 (byte 0xHH at position P)`), where a raw `UnicodeDecodeError` escaped before; criteria.yaml raises `CriteriaError`, and the results.csv read by `select` a `DataContractError`, with the same message. A byte-order mark stays ignored.
|
|
24
|
+
- The shared input contract mirror is version 1.10.0: a VCF GT outside the grammar (a sign, an exponent, an underscore, whitespace, a leading zero, an empty side, three alleles, the VCF 4.4 leading phase indicator, or an allele index above 127 or outside REF,ALT) is the error `genotypes.invalid_gt`, naming the line and the value, where before it was misread or raised a raw Python exception; an empty GT, which raised a ValueError, and a sample field that ends before its GT sub-field, which raised an IndexError, are now read as missing (canonical record: backcross docs/adr/0025; mirror record docs/adr/0030).
|
|
25
|
+
- Accessibility review against WCAG 2.2 AA: axe-core runs on every screen in the browser tests, a Tab walk from the Load screen never lands focus on an element with no layout box, statuses carry text as well as colour; docs/accessibility.md records the method and the known exceptions (docs/adr/0023).
|
|
26
|
+
|
|
27
|
+
- Load a variant set from a BrAPI v2.1 server on the command line (`rank` and `validate` with `--brapi-url` and `--variant-set`, token from the environment variable named by `--brapi-token-env`); `brapi-callsets` writes the call-set table so samples.csv is built from the server's own ids; roles still come from samples.csv (docs/adr/0024).
|
|
28
|
+
|
|
29
|
+
- The shared input contract mirror is version 1.6.0: a genotype cell pairing one of A, C, G, T with one of `N`, `-`, `.`, in either order and in all three spellings, is read as missing in HapMap and in nucleotide-mode wide CSV, which `io.calls` already did and does not change (canonical record: backcross docs/adr/0021). A pair of two missing characters (`N/N`, `..`) was left undefined by 1.6.0 and is defined by 1.8.0 below.
|
|
30
|
+
|
|
31
|
+
- The shared input contract mirror is version 1.7.0: `--crop` and the Load screen add cowpea, pea and peanut chromosome schemes (canonical record: backcross docs/adr/0022; mirror record docs/adr/0027). Pea needs a `chr` or `chromosome` prefix or a matching `LG` suffix and keeps a bare `1`-`7` as written, because published pea tables use bare digits for two numberings; peanut's `A01`/`B01`, `Aradu.` and `Araip.` spellings are kept as written. Sunflower stayed deferred then and followed as contract 1.9.0 below.
|
|
32
|
+
|
|
33
|
+
- The shared input contract mirror is version 1.8.0: a genotype cell pairing two of `N`, `-`, `.`, in any order and in all three spellings (`N/N`, `N-`, `./N`, `..`, `-|N`), is read as missing in HapMap and in nucleotide-mode wide CSV, which `io.calls` already did and does not change (canonical record: backcross docs/adr/0023; mirror record docs/adr/0028). A pair with `X` that is not itself a missing token (`X/X`, `XN`) stays an error; under a `base: none` token profile (`dart`, `axiom`, `kasp`) such a cell is an error unless the profile lists it, as `axiom` lists `--`; and a wide CSV holding such a cell that is not itself a missing token is read as nucleotide by `auto` detection.
|
|
34
|
+
|
|
35
|
+
- The shared input contract mirror is version 1.9.0: `--crop` and the Load screen add a sunflower chromosome scheme (canonical record: backcross docs/adr/0024; mirror record docs/adr/0029). Its canonical names are bare `1`-`17`, and `Ha412HOChr01` (HA412-HOv2.0), `HanXRQChr01` (HanXRQr2.0-SUNRISE), `chr1`, `chromosome-1`, `01` and `1` are all read as `1`, because the two assemblies share the LG1-LG17 numbering (XRQ and HA412-HO v1 by their map anchoring, HA412-HOv2 by a whole-genome alignment against XRQ; backcross docs/adr/0024 gives the evidence and its weakest link); unplaced scaffolds (`HanXRQChr00c001`), organelles, accessions (`NC_035433.2`, `CM007890.2`), the `LG` prefix and HA412-HO v1.1 names (`Ha1`) are kept as written.
|
|
36
|
+
|
|
37
|
+
- Navigate offers a "(no generation)" choice for individuals without a generation; the Rank caption names an unassigned family or generation; the Navigate reload guard has a browser test.
|
|
38
|
+
- `scripts/bench_pipeline.py` and `scripts/bench_shinylive.py` measure wall-clock and peak memory on generated datasets; `docs/limits.md` records the measured limits for CPython and Shinylive (docs/adr/0021).
|
|
39
|
+
|
|
40
|
+
- Crop selector (contract 1.5.0, docs/adr/0020): soybean (default), maize, rice, sorghum, wheat, barley, oat, common bean and cotton chromosome schemes; a chosen crop normalizes and orders chromosome names, resolves target regions and selects chromosome lengths by that crop's convention, so a maize `chr1` is no longer read as `Gm01` and a maize target `chr7` resolves. `--crop ID` on the CLI and a Crop select on the Load screen.
|
|
41
|
+
|
|
42
|
+
- `scripts/soysnp_positions.py` builds a SoySNP50K/6K position table across Wm82 assemblies from SoyBase GFF3s; `scripts/kasp_to_wide.py` converts an LGC long-format KASP export to the wide CSV contract.
|
|
43
|
+
- Selection list: editable notes written to selected.csv. Validate: background model, units, assembly, rank mode and duplicate pairs. Export: placeholder rows per selected individual. docs/keyboard-walkthrough.md.
|
|
44
|
+
- `select --per-selected N`; a synthetic BC3F1 fixture generated from the BC2F1 selection proves next_samples.csv loads unchanged as the next generation (docs/adr/0018).
|
|
45
|
+
- Advisory QC flag `possible_duplicate` and duplicate pairs in `validate` (docs/adr/0017). IBS is measured over the informative markers called in both individuals, and a pair is reported only when they share calls at half or more of the markers used, so a sample with almost no calls is no longer a duplicate of everyone it overlaps. The fixture pins weighted RPP and staged ranks computed independently.
|
|
46
|
+
- `ranking: {mode: staged}` orders survivors lexicographically (docs/adr/0007); `assembly` selects the chromosome-length table (Wm82.a1, a2, a4 or none; docs/adr/0015). Warnings now report a cM request the map cannot honour, chromosomes without an assembly length, and marker positions beyond the assembly length.
|
|
47
|
+
- `scripts/read_results.R` reads results.csv with readr and explicit column types; CI verifies it on the fixture and on an empty results file.
|
|
48
|
+
- Token profiles (contract 1.4.0 mirrored, docs/adr/0014; backcross docs/adr/0019): the Load screen, the CLI (`--profile`) and backcross read HapMap and wide-CSV cells under a named vocabulary, `tassel`, `soybase-report` (H heterozygous, U missing), `dart` (0/1/2/-), `axiom` (AA/AB/BB, NoCall, or 0/1/2) or `kasp` (X:X/X:Y/?), or a JSON file of the same shape. results.csv and selected.csv gain a trailing `token_profile` column; readers by position keep their columns. A profile with a VCF, or with a wide CSV or HapMap read as A/B/H, is an error, as is an `H` at a marker with an indel allele; a profile file is always recorded as `custom:<id>`; the Load screen's custom profile can be cleared and disables the select while set; error kinds `genotypes.ambiguous_heterozygote` and `genotypes.profile_format`.
|
|
49
|
+
- Package scaffold with a pure compute core, boundary parsers, CLI and a Shiny for Python screen shell.
|
|
50
|
+
- Parsers for VCF 4.2+ (plain, gzip, bgzip), HapMap, wide CSV (nucleotide and A/B/H), samples.csv, markers.csv and criteria.yaml, with boundary validation.
|
|
51
|
+
- Parent-of-origin classification; foreground status for marker, region and flanking-marker loci; avoid-locus status; recurrent-parent proportion (count and map-weighted, per chromosome, carrier and non-carrier); donor-segment bounds and flank recombinant flags; identity-by-state to each parent; QC metrics and flags; hard filters, composite score, ranking with fixed tie-breaks; top-N selection and next-generation projection.
|
|
52
|
+
- results.csv, selected.csv and next-round manifest writers; `progeny-selector validate | rank | select` commands.
|
|
53
|
+
- Synthetic BC2F1 fixture (2 parents, 40 progeny in 2 families, 500 markers, planted target, avoid locus, contaminant, high-missing individual) with generator and expected results; unit and smoke tests.
|
|
54
|
+
- PLAN.md, data-format and reference-repository documents, MADR decision records, CI workflow.
|
|
55
|
+
- Navigate screen: family and generation tree with breadcrumbs that filter the Rank grid. Rank grid shows pass, fail and unknown chips and recombinant flags per locus.
|
|
56
|
+
- Validate screen: QC table with flagged rows highlighted and the reasons markers were uninformative. Compare screen: side-by-side statuses, per-chromosome RPP, drag bounds and Okabe-Ito chromosome strips.
|
|
57
|
+
- Criteria can be edited on the Load screen, re-applied without reloading genotypes, and downloaded as criteria.yaml. Downloads no longer write temporary files.
|
|
58
|
+
- The Shinylive static export includes the package and is smoke-tested in CI with the fixture; it deploys to GitHub Pages when ENABLE_PAGES is set.
|
|
59
|
+
- `scripts/soysnp50k_nils.py` converts one backcross-derived NIL family from the SoyBase SoySNP50K VCF and PATRIOT's pedigree file into a genotype file and samples.csv for this tool. It streams the 144 MB VCF, strips SoyBase's chromosome prefix, and drops scaffold and malformed records.
|
|
60
|
+
- The shared input contract, version 1.1.0, mirrored byte for byte from isoline-browser under `contract/` and checked by `tests/test_contract_cases.py`, which loads every case through `load_dataset` and verifies the manifest hashes (docs/adr/0010).
|
|
61
|
+
- Foreground `rule: run` for region targets, with `min_run`, `anchor_bp` and `tolerate_isolated`: a target passes only on a contiguous run of donor calls through the anchor, so scattered array calls no longer pass a wide window (docs/adr/0011).
|
|
62
|
+
- Advisory QC flag `family_donor_outlier`: an individual whose donor fraction (count model) lies above its family median by more than 2.5 robust scales (1.4826 x MAD, floor 0.01), in families of at least 6; it does not exclude (docs/adr/0012).
|
|
63
|
+
- `scripts/check_contract.py`, a per-commit gate that recomputes `contract/MANIFEST.sha256` and, given `../isoline-browser`, byte-compares the mirror with the canonical copy.
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- shiny and pandas are core dependencies, and the `app` extra is gone: `pip install progeny-selector` installs everything the browser interface needs. The `select --top N` help now says it keeps up to N per family, and that `--overall` keeps the N best overall.
|
|
68
|
+
- results.csv and selected.csv are schema 1.2.0 (docs/adr/0033, docs/adr/0035). results.csv gains six columns directly after `crop`, before the per-target, per-avoid and per-chromosome columns: `call_set_db_id`, `sample_db_id`, `background_max_marker_coverage`, `tool`, `tool_version`, `tool_commit`, so its fixed prefix is 41 names (42 in the header of an empty file). selected.csv gains five after `crop`: `call_set_db_id`, `sample_db_id`, `tool`, `tool_version`, `tool_commit`. `call_set_db_id` and `sample_db_id` are the BrAPI ids a line was loaded from and an empty cell for data loaded from files. `background_max_marker_coverage` is the coverage cap the weighted model applied, in `background_unit`, and `NA` under `model: count`. `tool` is `progeny-selector`, `tool_version` the version that wrote the file, and `tool_commit` the commit it was built from (`g` and seven hex digits, `-dirty` when tracked files differ from that commit; untracked files do not count), `NA` when the commit is unknown, as for an installed wheel. A script that reads the per-chromosome columns by position after `crop` must move to the new position or select them by name; `scripts/read_results.R` reads the new columns, and `select` still reads a results.csv written before 1.2.0.
|
|
69
|
+
- Weighted RPP changes for runs in bp: the first marker's outer side on a chromosome is min(position, cap/2) whether or not an assembly length is known (it was cap/2 when no length was known), and the default bp cap is 2,000,000 (was 4,000,000). `rpp_total`, `rpp_carrier`, `rpp_noncarrier` and every `rpp_<chrom>` move on existing bp datasets under `model: weighted`; re-rank before comparing with earlier results, or set `background.max_marker_coverage: 4000000` to keep the old cap. Values in cM are unchanged (docs/adr/0033).
|
|
70
|
+
- Duplicate pairs carry `n_overlap`, the number of markers called in both lines that the IBS was measured over; `validate` and the Validate screen print it beside the IBS. When the most advanced parsed generation is BC6 or later, the run warns that `possible_duplicate` cannot separate duplicates from siblings, whose expected IBS is then within 0.005 of the 0.995 threshold (docs/adr/0017, amendment 2026-09-27).
|
|
71
|
+
|
|
72
|
+
- Classification, RPP and IBS to a parent compute in blocks of 64 sample columns, so analysis temporaries are set by the marker count alone: 83 MB for `rpp` at 50,000 markers, measured the same at 100 individuals and at 2,000, where before the cost scaled with the call count and reaches about 3.2 GB at 50,000 x 2,000 by arithmetic from the measured per-call figure (docs/adr/0025). Results are bit-identical.
|
|
73
|
+
|
|
74
|
+
- `read_vcf` reads the file in two passes and fills a preallocated matrix instead of stacking a list of rows, so the parse peak falls from 3.6x to 2.0x the genotype matrix on a file of 50,000 markers by 200 individuals (68.4 MiB to 38.4 MiB, measured on the reference machine); what remains beyond the matrix is the marker and allele tables, about 450 bytes a record, so the saving is largest on the sample-heavy files where the matrix dominates (docs/adr/0022). A truncated `.gz` is now a contract error naming the file, reported ahead of any row error in the same file. Results are unchanged.
|
|
75
|
+
|
|
76
|
+
- results.csv schema 1.1.0: a fixed `crop` column after `results_schema` and before `token_profile`, which stays last (docs/adr/0016); selected.csv gains it in the same position and `scripts/read_results.R` reads it. Under any crop but soybean a chromosome ends at its last marker, because the chromosome length tables are Williams 82's; the per-chromosome "assembly gives no length" warning says so.
|
|
77
|
+
|
|
78
|
+
- **BREAKING CHANGE:** results.csv schema 1.0.0: missing cells are `NA`, the header is written with no results, new columns `background_model`, `background_unit`, `rank_mode`, `assembly`, `results_schema`; `het_rate`, `expected_het` and `expected_rpp` never print `nan`. selected.csv gains `results_schema` and writes `NA` for missing family or generation (docs/adr/0016). next_samples.csv is unchanged: empty cells, no schema column. A chromosome whose name would collide with `rpp_total`, `rpp_carrier` or `rpp_noncarrier` is now an error naming the chromosome.
|
|
79
|
+
- Contract 1.3.0 mirrored (docs/adr/0013): a blank line before the header is skipped in HapMap, wide CSV, samples.csv and markers.csv; the delimiter is sniffed from the first non-blank line; a blank line holds only spaces and tabs; a quoted field left open at the end of a delimited file, a `#` line after a VCF `#CHROM` line and an unparseable markers.csv `cm` are errors naming the line; line breaks inside quoted fields are read as LF; error kinds `genotypes.column_count` and `delimited.unterminated_quote`.
|
|
80
|
+
- Data contract 1.2.1 (wording only): the sibling browser tool is now called Backcross.
|
|
81
|
+
|
|
82
|
+
- Contract 1.2.0, a minor version (docs/adr/0010, amended 2026-09-14): VCF POS must be decimal digits; a VCF record with ID `.` is named from the parsed POS. A position written as a whole-valued float or in exponent notation (`1000.0`, `1e3`, `1.9E+07`) is read as that integer in HapMap, wide CSV and markers.csv; a fractional `pos_bp` in wide CSV or markers.csv is now an error naming the line and value instead of being truncated, a non-integer VCF `POS` is a `DataContractError` instead of an uncaught `ValueError`, an empty `marker_id` in a wide CSV is an error, and wide-CSV and markers.csv errors name the physical line even after skipped rows.
|
|
83
|
+
- Loaders aligned with contract 1.1.0 (docs/adr/0010): samples.csv, markers.csv and wide CSV may be tab-delimited and quoted; `line_name` is optional; genotype columns not in samples.csv are dropped and samples load in manifest order; a VCF record with ID `.` is named from CHROM as written (`chr13_19000000`, not `Gm13_19000000`); chromosome names accept the `LG` prefix and space or `-` separators, no longer accept `ch6`, and non-soybean names order naturally (`scaffold_2` before `scaffold_10`); `?` is no longer a missing token anywhere, and in HapMap and nucleotide wide CSV a single character outside A, C, G, T and the IUPAC codes (`?`, `B`, `H`, `0`, `+`) is an error naming the line and cell rather than a missing call; the HapMap missing tokens are exactly the contract's eleven (`X`, `XX` added, `?` removed); A/B/H auto-detection reads the whole file instead of its first 200 rows; a leading byte-order mark is accepted on every input.
|
|
84
|
+
|
|
85
|
+
### Fixed
|
|
86
|
+
|
|
87
|
+
- `scripts/kasp_to_wide.py` reads a sectioned KASP service-lab export (`Statistics`, `SNPs`, then `Data`) from the first row carrying `SubjectID`, `SNPID` and `Call`; it took the first row as the header, so a real export failed as an undetectable grid (docs/adr/0019, amendment of 2026-09-27).
|
|
88
|
+
- `validate` reports how many duplicate-pair candidates it skipped because the two lines share too few called markers ("N pairs skipped: fewer than M markers called in both lines"), where it dropped them silently before (Q14, the silent-skip half). The reload-guard end-to-end test now waits for the breadcrumb's settled state and fails on an empty mutation history, so it can no longer pass vacuously.
|
|
89
|
+
- The Load screen reads a genotype upload named `.vcf.gz`, `.vcf.bgz`, `.hmp.txt` or `.hmp.gz`. Shiny stores an upload under its last suffix only, so such a file reached the reader as `0.gz` or `0.txt` and failed with "cannot infer genotype format" or a wide-CSV header error; the screen now restores the upload's own name before reading it, and errors in samples.csv, markers.csv and criteria.yaml name the user's file.
|
|
90
|
+
|
|
91
|
+
- The next-round manifest refuses an empty next-generation label in `io.export`, so `select --next-generation ""` is a usage error and the Export screen shows the refusal and writes no file, where both previously wrote ids like `BC2F1-F1-001--001` and a blank `generation` column; a padded label is trimmed, and a refused write no longer leaves an empty file behind.
|
|
92
|
+
- results.csv and the Validate screen record the chromosome-length table the run used, and not the criteria.yaml text. A maize run with an unset `assembly` recorded `Wm82.a4` while using no length table at all, and now records `none` (docs/adr/0015, amendment 2026-09-22).
|
|
93
|
+
- An unset criteria.yaml `assembly` means whatever the crop implies: `Wm82.a4` under soybean, `none` under every other crop. An explicit `Wm82.*` under a non-soybean crop is refused naming the key, and an explicit `none` is accepted under any crop. A downloaded criteria.yaml writes an unset key as `assembly: null` and stays reusable across crops.
|
|
94
|
+
|
|
95
|
+
- Weighted RPP: a chromosome whose markers run past the assembly length now weighs its terminal markers like a chromosome with no recorded length at all, instead of giving the terminal marker zero outer weight (docs/adr/0015, amendment 2026-09-21).
|
|
96
|
+
- `scripts/kasp_to_wide.py` accepts `A:G` and `G:A` for the same sample and SNP as one call instead of a conflict.
|
|
97
|
+
- Clearing a numeric field no longer breaks the screen: Export still downloads next_samples.csv and the Selection list's "Add top N per family" adds nothing instead of failing.
|
|
98
|
+
- The next-round manifest refuses a placeholder-row count below 1 in `io.export` rather than only in the CLI, so the Export screen shows the refusal and writes no file where it previously downloaded a manifest holding the two parents and no progeny.
|
|
99
|
+
|
|
100
|
+
- Genotype files named `.vcf.bgz` now load, as documented; `.bcf`, which was never documented and was read as text, is rejected.
|
|
101
|
+
|
|
102
|
+
### Removed
|
|
103
|
+
|
|
104
|
+
- The unused `core.classify.rpp_contribution`, a second copy of the table `constants.RPP_LOOKUP` carries (the follow-up docs/adr/0025 recorded).
|
|
105
|
+
|
|
106
|
+
### Documentation
|
|
107
|
+
|
|
108
|
+
- The README is rewritten for breeders: install with pip or pipx, run the shipped example, launch the interface, what each output means, what `--top` keeps, and the known limitations. docs/tutorial.md walks through one run of the example on the command line and in the interface, docs/glossary.md defines the terms (RPP, carrier chromosome, linkage drag, the six genotype states, ranking modes, possible_duplicate), and docs/README.md indexes the documentation. CITATION.cff says how to cite the software.
|
|
109
|
+
- Replace the milestone-heavy landing page with a concise workflow and fixture example; preserve the previous README in `docs/legacy-readme.md`.
|
|
110
|
+
|
|
111
|
+
### Known limitations
|
|
112
|
+
|
|
113
|
+
1. `possible_duplicate` is raw pairwise identity by state of at least 0.995 over informative markers, and it does not consider family. It is advisory only ([ADR 0017](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0017-duplicate-flag.md)).
|
|
114
|
+
2. The two-generation round trip is verified on synthetic data only. No real linked BC(n) to BC(n+1) dataset has been run.
|
|
115
|
+
3. The browser site has no BrAPI source. BrAPI is command-line only until a server sends CORS headers for the site's origin ([ADR 0024](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0024-brapi-allele-matrix-loader.md)).
|
|
116
|
+
4. One donor per analysis. An intercross or pyramiding population is not ranked ([contract](https://github.com/piercetaylor/progeny-selector/blob/main/contract/data-contract.md), [ADR 0002](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0002-input-data-contract.md)).
|
|
117
|
+
5. Chromosome-length tables exist for soybean only (Wm82.a1, Wm82.a2 and Wm82.a4). Under any other crop a chromosome ends at its last marker ([ADR 0020](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0020-contract-1.5-crop-schemes.md)).
|
|
118
|
+
6. The default cap of 2 Mb on base-pair coverage is a soybean translation of 10 cM. Set `background.max_marker_coverage` for other crops ([ADR 0033](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0033-results-schema-1.2-cap-and-end-rule.md)).
|
|
119
|
+
7. A VCF 4.4 leading phase indicator in GT is rejected as `genotypes.invalid_gt` (contract 1.10.0).
|
|
120
|
+
8. Accessibility: selecting several rows in the Rank grid needs a mouse; three axe rules are recorded exceptions; there is no screen-reader, Firefox, Safari or 320 px reflow testing ([accessibility review](https://github.com/piercetaylor/progeny-selector/blob/main/docs/accessibility.md)).
|
|
121
|
+
9. Purdy labels: single crosses only, and no heterozygosity checks, because the label carries no filial generation ([ADR 0034](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0034-purdy-generation-labels.md)).
|
|
122
|
+
10. The long-format KASP header names are unconfirmed against a real LGC export ([ADR 0019](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0019-soybean-input-tooling.md)).
|
|
123
|
+
11. CI runs the browser tests on Linux only; Windows and macOS run the unit tests.
|
|
124
|
+
|
|
125
|
+
[Unreleased]: https://github.com/piercetaylor/progeny-selector/compare/v0.1.0...HEAD
|
|
126
|
+
[0.1.0]: https://github.com/piercetaylor/progeny-selector/releases/tag/v0.1.0
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it as below."
|
|
3
|
+
type: software
|
|
4
|
+
title: "progeny-selector: marker-assisted backcross progeny ranking and selection"
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: Taylor
|
|
7
|
+
given-names: Pierce
|
|
8
|
+
license: MIT
|
|
9
|
+
repository-code: "https://github.com/piercetaylor/progeny-selector"
|
|
10
|
+
url: "https://piercetaylor.github.io/progeny-selector/"
|
|
11
|
+
version: 0.1.0
|
|
12
|
+
date-released: '2026-09-29'
|
|
13
|
+
keywords:
|
|
14
|
+
- plant breeding
|
|
15
|
+
- marker-assisted backcrossing
|
|
16
|
+
- progeny selection
|
|
17
|
+
- recurrent parent genome
|
|
18
|
+
- soybean
|
|
19
|
+
references:
|
|
20
|
+
- type: software
|
|
21
|
+
title: Backcross
|
|
22
|
+
authors:
|
|
23
|
+
- family-names: Taylor
|
|
24
|
+
given-names: Pierce
|
|
25
|
+
repository-code: "https://github.com/piercetaylor/backcross"
|
|
26
|
+
url: "https://piercetaylor.github.io/backcross/"
|
|
27
|
+
notes: "Sibling tool; both read input data contract 1.12.0"
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, caste, color, religion, or sexual
|
|
10
|
+
identity and orientation.
|
|
11
|
+
|
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
13
|
+
diverse, inclusive, and healthy community.
|
|
14
|
+
|
|
15
|
+
## Our Standards
|
|
16
|
+
|
|
17
|
+
Examples of behavior that contributes to a positive environment for our
|
|
18
|
+
community include:
|
|
19
|
+
|
|
20
|
+
* Demonstrating empathy and kindness toward other people
|
|
21
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
|
22
|
+
* Giving and gracefully accepting constructive feedback
|
|
23
|
+
* Accepting responsibility and apologizing to those affected by our mistakes,
|
|
24
|
+
and learning from the experience
|
|
25
|
+
* Focusing on what is best not just for us as individuals, but for the overall
|
|
26
|
+
community
|
|
27
|
+
|
|
28
|
+
Examples of unacceptable behavior include:
|
|
29
|
+
|
|
30
|
+
* The use of sexualized language or imagery, and sexual attention or advances of
|
|
31
|
+
any kind
|
|
32
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
33
|
+
* Public or private harassment
|
|
34
|
+
* Publishing others' private information, such as a physical or email address,
|
|
35
|
+
without their explicit permission
|
|
36
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
|
37
|
+
professional setting
|
|
38
|
+
|
|
39
|
+
## Enforcement Responsibilities
|
|
40
|
+
|
|
41
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
|
42
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
|
43
|
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
44
|
+
or harmful.
|
|
45
|
+
|
|
46
|
+
Community leaders have the right and responsibility to remove, edit, or reject
|
|
47
|
+
comments, commits, code, wiki edits, issues, and other contributions that are
|
|
48
|
+
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
|
49
|
+
decisions when appropriate.
|
|
50
|
+
|
|
51
|
+
## Scope
|
|
52
|
+
|
|
53
|
+
This Code of Conduct applies within all community spaces, and also applies when
|
|
54
|
+
an individual is officially representing the community in public spaces.
|
|
55
|
+
Examples of representing our community include using an official e-mail address,
|
|
56
|
+
posting via an official social media account, or acting as an appointed
|
|
57
|
+
representative at an online or offline event.
|
|
58
|
+
|
|
59
|
+
## Enforcement
|
|
60
|
+
|
|
61
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
62
|
+
reported to the community leaders responsible for enforcement at
|
|
63
|
+
the maintainer, through a GitHub issue or the repository's private reporting form.
|
|
64
|
+
All complaints will be reviewed and investigated promptly and fairly.
|
|
65
|
+
|
|
66
|
+
All community leaders are obligated to respect the privacy and security of the
|
|
67
|
+
reporter of any incident.
|
|
68
|
+
|
|
69
|
+
## Enforcement Guidelines
|
|
70
|
+
|
|
71
|
+
Community leaders will follow these Community Impact Guidelines in determining
|
|
72
|
+
the consequences for any action they deem in violation of this Code of Conduct:
|
|
73
|
+
|
|
74
|
+
### 1. Correction
|
|
75
|
+
|
|
76
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed
|
|
77
|
+
unprofessional or unwelcome in the community.
|
|
78
|
+
|
|
79
|
+
**Consequence**: A private, written warning from community leaders, providing
|
|
80
|
+
clarity around the nature of the violation and an explanation of why the
|
|
81
|
+
behavior was inappropriate. A public apology may be requested.
|
|
82
|
+
|
|
83
|
+
### 2. Warning
|
|
84
|
+
|
|
85
|
+
**Community Impact**: A violation through a single incident or series of
|
|
86
|
+
actions.
|
|
87
|
+
|
|
88
|
+
**Consequence**: A warning with consequences for continued behavior. No
|
|
89
|
+
interaction with the people involved, including unsolicited interaction with
|
|
90
|
+
those enforcing the Code of Conduct, for a specified period of time. This
|
|
91
|
+
includes avoiding interactions in community spaces as well as external channels
|
|
92
|
+
like social media. Violating these terms may lead to a temporary or permanent
|
|
93
|
+
ban.
|
|
94
|
+
|
|
95
|
+
### 3. Temporary Ban
|
|
96
|
+
|
|
97
|
+
**Community Impact**: A serious violation of community standards, including
|
|
98
|
+
sustained inappropriate behavior.
|
|
99
|
+
|
|
100
|
+
**Consequence**: A temporary ban from any sort of interaction or public
|
|
101
|
+
communication with the community for a specified period of time. No public or
|
|
102
|
+
private interaction with the people involved, including unsolicited interaction
|
|
103
|
+
with those enforcing the Code of Conduct, is allowed during this period.
|
|
104
|
+
Violating these terms may lead to a permanent ban.
|
|
105
|
+
|
|
106
|
+
### 4. Permanent Ban
|
|
107
|
+
|
|
108
|
+
**Community Impact**: Demonstrating a pattern of violation of community
|
|
109
|
+
standards, including sustained inappropriate behavior, harassment of an
|
|
110
|
+
individual, or aggression toward or disparagement of classes of individuals.
|
|
111
|
+
|
|
112
|
+
**Consequence**: A permanent ban from any sort of public interaction within the
|
|
113
|
+
community.
|
|
114
|
+
|
|
115
|
+
## Attribution
|
|
116
|
+
|
|
117
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
118
|
+
version 2.1, available at
|
|
119
|
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct/][v2.1].
|
|
120
|
+
|
|
121
|
+
Community Impact Guidelines were inspired by
|
|
122
|
+
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
|
123
|
+
|
|
124
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
|
125
|
+
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
|
126
|
+
[https://www.contributor-covenant.org/translations][translations].
|
|
127
|
+
|
|
128
|
+
[homepage]: https://www.contributor-covenant.org
|
|
129
|
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct/
|
|
130
|
+
[Mozilla CoC]: https://github.com/mozilla/diversity
|
|
131
|
+
[FAQ]: https://www.contributor-covenant.org/faq
|
|
132
|
+
[translations]: https://www.contributor-covenant.org/translations
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Setup
|
|
4
|
+
|
|
5
|
+
Python 3.11 or later. The package installs shiny and pandas; the extras are `dev` (pytest, pytest-cov, ruff, mypy), `e2e` (pytest-playwright and axe-playwright-python) and `export` (shinylive).
|
|
6
|
+
|
|
7
|
+
- `dev`: `pip install -e ".[dev]"` is enough for the per-commit gates below. A pull request must pass them.
|
|
8
|
+
- `e2e`: the browser tests under `tests/e2e/`. Install with `pip install -e ".[dev,e2e]"`, run `playwright install chromium` once, then `pytest -m e2e`. Plain `pytest` excludes these tests.
|
|
9
|
+
- `export`: shinylive, for the static Shinylive export. No per-commit gate needs it.
|
|
10
|
+
|
|
11
|
+
Local venv recipe (Windows): `py -3.12 -m venv .venv`, then `.venv\Scripts\python -m pip install -e ".[dev,export,e2e]"` and `.venv\Scripts\python -m playwright install chromium`.
|
|
12
|
+
|
|
13
|
+
After changing `src/progeny_selector/_version.py`, re-run `pip install -e .` so `tests/test_version.py` sees the new metadata.
|
|
14
|
+
|
|
15
|
+
## Gates
|
|
16
|
+
|
|
17
|
+
All must pass before a pull request:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
ruff check .
|
|
21
|
+
ruff format --check .
|
|
22
|
+
mypy
|
|
23
|
+
pytest
|
|
24
|
+
python scripts/check_contract.py
|
|
25
|
+
python scripts/make_fixture.py
|
|
26
|
+
git diff --exit-code -- tests/fixtures src/progeny_selector/examples
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The generator is deterministic, so regenerating the fixture must leave `tests/fixtures` and `src/progeny_selector/examples` unchanged. Edit the generator, never the generated files.
|
|
30
|
+
|
|
31
|
+
## Conventions
|
|
32
|
+
|
|
33
|
+
Commits follow Conventional Commits 1.0.0 (`feat(core): ...`, `fix(io): ...`, `docs: ...`, `test: ...`, `chore: ...`; `!` or a `BREAKING CHANGE:` footer for changes to the data contract or the results columns). Versions follow SemVer 2.0.0; docs/data-formats.md is part of the public interface. CHANGELOG.md follows Keep a Changelog 1.1.0; add a line under Unreleased with every user-visible change. Decisions are MADR files in docs/adr/, numbered sequentially; supersede rather than edit an accepted record.
|
|
34
|
+
|
|
35
|
+
## Code rules
|
|
36
|
+
|
|
37
|
+
Everything in src/progeny_selector/core is pure: numpy arrays and dataclasses in, arrays and dataclasses out; no file I/O, no Shiny, no pandas. Validation happens once at the boundary (src/progeny_selector/io) and raises DataContractError or CriteriaError with the file, line and column. The UI (src/progeny_selector/app) calls `run_analysis` and renders rows; it computes nothing. Colours come only from `constants.STATE_COLORS` and `STATUS_COLORS` (Okabe-Ito). Every module starts with a docstring stating its responsibility and interface.
|
|
38
|
+
|
|
39
|
+
## Data
|
|
40
|
+
|
|
41
|
+
Never commit genotype data other than the synthetic fixture; .gitignore excludes *.vcf, *.vcf.gz and *.hmp.txt outside tests/fixtures/.
|
|
42
|
+
|
|
43
|
+
## Releasing
|
|
44
|
+
|
|
45
|
+
Releases are made by the maintainer only: set the version in `src/progeny_selector/_version.py`, CHANGELOG.md and CITATION.cff, push a `v<version>` tag, and `.github/workflows/release.yml` builds, publishes to PyPI by trusted publishing and creates the GitHub release with the CHANGELOG section as notes.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pierce Taylor
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: progeny-selector
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Marker-assisted backcross progeny ranking and selection: foreground, background, linkage drag, avoid loci, composite scores.
|
|
5
|
+
Project-URL: Homepage, https://github.com/piercetaylor/progeny-selector
|
|
6
|
+
Project-URL: Documentation, https://github.com/piercetaylor/progeny-selector/blob/main/docs/README.md
|
|
7
|
+
Project-URL: Repository, https://github.com/piercetaylor/progeny-selector
|
|
8
|
+
Project-URL: Issues, https://github.com/piercetaylor/progeny-selector/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/piercetaylor/progeny-selector/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Browser app, https://piercetaylor.github.io/progeny-selector/
|
|
11
|
+
Author: Pierce Taylor
|
|
12
|
+
License-Expression: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: genotype,marker-assisted backcrossing,plant breeding,selection,soybean
|
|
15
|
+
Classifier: Development Status :: 3 - Alpha
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Requires-Dist: numpy>=1.26
|
|
25
|
+
Requires-Dist: pandas>=2.2
|
|
26
|
+
Requires-Dist: pyyaml>=6.0
|
|
27
|
+
Requires-Dist: shiny>=1.4
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
33
|
+
Provides-Extra: e2e
|
|
34
|
+
Requires-Dist: axe-playwright-python>=0.1; extra == 'e2e'
|
|
35
|
+
Requires-Dist: pytest-playwright>=0.5; extra == 'e2e'
|
|
36
|
+
Provides-Extra: export
|
|
37
|
+
Requires-Dist: shinylive>=0.8; extra == 'export'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# progeny-selector
|
|
41
|
+
|
|
42
|
+
progeny-selector ranks candidates in marker-assisted backcross breeding. It checks target and avoid loci, estimates recurrent-parent recovery and donor-segment bounds, applies quality flags and selection criteria, and exports ranked results, selections, and a manifest for the next generation. The analysis runs as a Python package and command-line tool, with a Shiny interface for local use or a browser-hosted site.
|
|
43
|
+
|
|
44
|
+
Status: version 0.1.0; see [CHANGELOG.md](https://github.com/piercetaylor/progeny-selector/blob/main/CHANGELOG.md) and [Known limitations](#known-limitations).
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
Python 3.11 or newer is required.
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
python -m pip install progeny-selector
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
or, to keep it out of your other Python projects:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
pipx install progeny-selector
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
On Windows, use `py -3 -m pip install progeny-selector`. If the `progeny-selector` command is not found afterwards, run `py -3 -m progeny_selector ...` instead, or install with pipx (`py -3 -m pip install --user pipx && py -3 -m pipx ensurepath`).
|
|
61
|
+
|
|
62
|
+
## Open the interface
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
progeny-selector app
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This opens a browser tab at http://127.0.0.1:8000/. Options: `--port`, `--host` and `--no-browser`. Press Ctrl+C in the terminal to stop it.
|
|
69
|
+
|
|
70
|
+
Or use the [browser site](https://piercetaylor.github.io/progeny-selector/): files are processed in the tab and never uploaded. Both offer **Load example (synthetic BC2F1)** on the Load screen.
|
|
71
|
+
|
|
72
|
+
## Run the example
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
progeny-selector example --out example
|
|
76
|
+
progeny-selector validate --genotypes example/synthetic_bc2f1/genotypes.vcf --samples example/synthetic_bc2f1/samples.csv --markers example/synthetic_bc2f1/markers.csv --criteria example/synthetic_bc2f1/criteria.yaml
|
|
77
|
+
progeny-selector rank --genotypes example/synthetic_bc2f1/genotypes.vcf --samples example/synthetic_bc2f1/samples.csv --markers example/synthetic_bc2f1/markers.csv --criteria example/synthetic_bc2f1/criteria.yaml --out results.csv
|
|
78
|
+
progeny-selector select --results results.csv --top 3 --out selected.csv --next-manifest next_samples.csv --next-generation BC3F1 --samples example/synthetic_bc2f1/samples.csv
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The example has 500 markers, 2 parents and 40 BC2F1 progeny in 2 families; 11 of the 40 pass the hard filters. It is synthetic, and its rankings are test cases, not breeding recommendations.
|
|
82
|
+
|
|
83
|
+
For a step-by-step walk through the same data, see the [tutorial](https://github.com/piercetaylor/progeny-selector/blob/main/docs/tutorial.md).
|
|
84
|
+
|
|
85
|
+
## What the outputs mean
|
|
86
|
+
|
|
87
|
+
`results.csv` has one row per individual:
|
|
88
|
+
|
|
89
|
+
- `rank_overall` and `rank_in_family`, `passes_filters` and `exclusion_reason`, and `composite_score`.
|
|
90
|
+
- `rpp_total`, `rpp_carrier` and `rpp_noncarrier`: recurrent-parent recovery overall, on chromosomes that carry a target locus, and on those that do not.
|
|
91
|
+
- `drag_total_est` and `drag_total_max`, with `drag_unit` naming the unit of both.
|
|
92
|
+
- `missing_rate` and `qc_flags`.
|
|
93
|
+
- One status column per target and avoid locus, and one `rpp_<chromosome>` column per chromosome.
|
|
94
|
+
- `results_schema` names the column layout. `background_model`, `background_unit`, `background_max_marker_coverage`, `assembly` and `crop` record how the numbers were computed.
|
|
95
|
+
|
|
96
|
+
`selected.csv` holds the chosen individuals, with a `notes` column. `next_samples.csv` is a `samples.csv` for the next genotyping round.
|
|
97
|
+
|
|
98
|
+
Further reading: the [tutorial](https://github.com/piercetaylor/progeny-selector/blob/main/docs/tutorial.md), the [glossary](https://github.com/piercetaylor/progeny-selector/blob/main/docs/glossary.md), and [selection and output formats](https://github.com/piercetaylor/progeny-selector/blob/main/docs/data-formats.md).
|
|
99
|
+
|
|
100
|
+
### What `--top N` selects
|
|
101
|
+
|
|
102
|
+
`select --top N` keeps every passing individual ranked N or better within its family, so up to N per family. With `--overall` it keeps the N best overall instead. Ranks are dense (tied individuals share a rank and the next rank follows without a gap), so ties can return more than N.
|
|
103
|
+
|
|
104
|
+
On the example, `--top 3` writes 6 rows: 3 in family F1 and 3 in F2. `--top 3 --overall` writes 3. The Selection screen's "add top N per family" does the same as `--top N`.
|
|
105
|
+
|
|
106
|
+
## Your own data
|
|
107
|
+
|
|
108
|
+
- Genotypes: VCF, HapMap or wide CSV, each optionally gzip- or bgzip-compressed (`.gz`, `.bgz`); the file extension selects the format. Every call is diploid. On the command line, a BrAPI v2.1 server can be the source instead (`--brapi-url`, `--variant-set`, `--brapi-token-env`).
|
|
109
|
+
- `samples.csv`: columns `sample_id` and `role` are required; `line_name`, `generation`, `family_id` and `notes` are optional. `role` is `recurrent_parent`, `donor_parent`, `candidate` or `progeny`. The file needs exactly one recurrent parent, exactly one donor parent, and at least one candidate or progeny.
|
|
110
|
+
- `criteria.yaml`: the top-level keys are `name`, `targets`, `avoid`, `flank_window`, `flank_unit`, `assembly`, `background`, `ranking`, `weights` and `filters`. Unknown keys are an error.
|
|
111
|
+
- `markers.csv` (optional): `marker_id`, `chrom` and `pos_bp` are required; `cm` is optional and enables cM-weighted recovery and cM segment bounds. Positions here override those in the genotype file.
|
|
112
|
+
- Crop: `--crop` selects one of 13 chromosome-naming schemes (soybean, maize, rice, sorghum, wheat, barley, oat, common bean, cotton, cowpea, pea, peanut, sunflower). Soybean is the default. The `assembly` key in `criteria.yaml` (`Wm82.a1`, `Wm82.a2`, `Wm82.a4` or `none`) sets the chromosome-length table used for chromosome ends.
|
|
113
|
+
- `--profile` chooses how HapMap and wide CSV cell values are read: one of the built-in token profiles (`tassel`, `soybase-report`, `dart`, `axiom`, `kasp`) or your own JSON file.
|
|
114
|
+
|
|
115
|
+
Details: the [input contract](https://github.com/piercetaylor/progeny-selector/blob/main/contract/data-contract.md), [selection and output formats](https://github.com/piercetaylor/progeny-selector/blob/main/docs/data-formats.md), and [soybean inputs](https://github.com/piercetaylor/progeny-selector/blob/main/docs/soybean-inputs.md).
|
|
116
|
+
|
|
117
|
+
## Known limitations
|
|
118
|
+
|
|
119
|
+
1. `possible_duplicate` is raw pairwise identity by state of at least 0.995 over informative markers, and it does not consider family. It is advisory only ([ADR 0017](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0017-duplicate-flag.md)).
|
|
120
|
+
2. The two-generation round trip is verified on synthetic data only. No real linked BC(n) to BC(n+1) dataset has been run.
|
|
121
|
+
3. The browser site has no BrAPI source. BrAPI is command-line only until a server sends CORS headers for the site's origin ([ADR 0024](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0024-brapi-allele-matrix-loader.md)).
|
|
122
|
+
4. One donor per analysis. An intercross or pyramiding population is not ranked ([contract](https://github.com/piercetaylor/progeny-selector/blob/main/contract/data-contract.md), [ADR 0002](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0002-input-data-contract.md)).
|
|
123
|
+
5. Chromosome-length tables exist for soybean only (Wm82.a1, Wm82.a2 and Wm82.a4). Under any other crop a chromosome ends at its last marker ([ADR 0020](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0020-contract-1.5-crop-schemes.md)).
|
|
124
|
+
6. The default cap of 2 Mb on base-pair coverage is a soybean translation of 10 cM. Set `background.max_marker_coverage` for other crops ([ADR 0033](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0033-results-schema-1.2-cap-and-end-rule.md)).
|
|
125
|
+
7. A VCF 4.4 leading phase indicator in GT is rejected as `genotypes.invalid_gt` (contract 1.10.0).
|
|
126
|
+
8. Accessibility: selecting several rows in the Rank grid needs a mouse; three axe rules are recorded exceptions; there is no screen-reader, Firefox, Safari or 320 px reflow testing ([accessibility review](https://github.com/piercetaylor/progeny-selector/blob/main/docs/accessibility.md)).
|
|
127
|
+
9. Purdy labels: single crosses only, and no heterozygosity checks, because the label carries no filial generation ([ADR 0034](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0034-purdy-generation-labels.md)).
|
|
128
|
+
10. The long-format KASP header names are unconfirmed against a real LGC export ([ADR 0019](https://github.com/piercetaylor/progeny-selector/blob/main/docs/adr/0019-soybean-input-tooling.md)).
|
|
129
|
+
11. CI runs the browser tests on Linux only; Windows and macOS run the unit tests.
|
|
130
|
+
|
|
131
|
+
## Verification
|
|
132
|
+
|
|
133
|
+
From a source checkout, `ruff check .`, `ruff format --check .`, `mypy` and `pytest -q` check the package. Browser and static-export checks, and the real-data verification with its limits, are described in [the plan](https://github.com/piercetaylor/progeny-selector/blob/main/PLAN.md). Measured run time and memory at several dataset sizes: [limits](https://github.com/piercetaylor/progeny-selector/blob/main/docs/limits.md). The WCAG 2.2 AA review is in the [accessibility review](https://github.com/piercetaylor/progeny-selector/blob/main/docs/accessibility.md). Design decisions are in [docs/adr](https://github.com/piercetaylor/progeny-selector/tree/main/docs/adr).
|
|
134
|
+
|
|
135
|
+
## Related tool
|
|
136
|
+
|
|
137
|
+
[backcross](https://github.com/piercetaylor/backcross) is the sibling browser-based tool. backcross characterises finished near-isogenic lines; progeny-selector ranks progeny during the programme. Both read input data contract 1.12.0, so genotype, samples.csv and markers.csv files move between them unchanged. The two tools release v0.1.0 on the same day, and each release note links the other's.
|
|
138
|
+
|
|
139
|
+
## Citing
|
|
140
|
+
|
|
141
|
+
Cite the software with [CITATION.cff](https://github.com/piercetaylor/progeny-selector/blob/main/CITATION.cff). GitHub shows a Cite this repository button for it. A Zenodo DOI is added after the first release. In plain text:
|
|
142
|
+
|
|
143
|
+
Taylor, P. (2026). progeny-selector (version 0.1.0) [Computer software]. https://github.com/piercetaylor/progeny-selector
|
|
144
|
+
|
|
145
|
+
## Licence
|
|
146
|
+
|
|
147
|
+
MIT. See [LICENSE](https://github.com/piercetaylor/progeny-selector/blob/main/LICENSE).
|