├── .classpath ├── .github └── workflows │ ├── create-release.yml │ └── maven.yml ├── .gitignore ├── .project ├── .settings ├── org.eclipse.core.resources.prefs └── org.eclipse.jdt.core.prefs ├── LICENSE ├── README.md ├── files ├── chains │ ├── hg19ToHg38.over.chain.gz │ └── hg38ToHg19.over.chain.gz └── pgs-calc ├── pom.xml ├── src ├── main │ ├── assembly │ │ └── assembly.xml │ ├── java │ │ └── genepi │ │ │ └── riskscore │ │ │ ├── App.java │ │ │ ├── commands │ │ │ ├── ApplyScoreCommand.java │ │ │ ├── ClearCacheCommand.java │ │ │ ├── CreateChunksCommand.java │ │ │ ├── CreateCollectionCommand.java │ │ │ ├── CreateHtmlReportCommand.java │ │ │ ├── DownloadMetaCommand.java │ │ │ ├── DownloadScoreCommand.java │ │ │ ├── FilterMetaCommand.java │ │ │ ├── LiftOverScoreCommand.java │ │ │ ├── MergeEffectsCommand.java │ │ │ ├── MergeInfoCommand.java │ │ │ ├── MergeScoreCommand.java │ │ │ ├── MergeVariantsCommand.java │ │ │ ├── ProcessHaploRegCommand.java │ │ │ ├── ResolveScoreCommand.java │ │ │ ├── ValidateScoreCommand.java │ │ │ └── VariantReadingException.java │ │ │ ├── io │ │ │ ├── Chunk.java │ │ │ ├── MetaFile.java │ │ │ ├── OutputFile.java │ │ │ ├── OutputFileReader.java │ │ │ ├── OutputFileWriter.java │ │ │ ├── PGSCatalog.java │ │ │ ├── PGSCatalogIDFile.java │ │ │ ├── ReportFile.java │ │ │ ├── RiskScoreFile.java │ │ │ ├── SamplesFile.java │ │ │ ├── ScoresFile.java │ │ │ ├── VariantFile.java │ │ │ ├── csv │ │ │ │ ├── CsvWithHeaderTableReader.java │ │ │ │ ├── CsvWithHeaderTableWriter.java │ │ │ │ └── TabixTableReader.java │ │ │ ├── dbsnp │ │ │ │ └── DbSnpReader.java │ │ │ ├── formats │ │ │ │ ├── PGSCatalogFormat.java │ │ │ │ ├── PGSCatalogHarmonizedFormat.java │ │ │ │ ├── PGSCatalogVariantsFormat.java │ │ │ │ ├── PRSwebFormat.java │ │ │ │ ├── RiskScoreFormatFactory.java │ │ │ │ └── RiskScoreFormatImpl.java │ │ │ ├── meta │ │ │ │ ├── JsonMetaFileReader.java │ │ │ │ ├── PGSCatalogCategoryFile.java │ │ │ │ ├── PGSCatalogMetaFile.java │ │ │ │ └── TabMetaFileReader.java │ │ │ ├── proxy │ │ │ │ └── ProxyReader.java │ │ │ ├── scores │ │ │ │ ├── IRiskScoreCollection.java │ │ │ │ ├── MergedRiskScoreCollection.java │ │ │ │ └── RiskScoreCollection.java │ │ │ └── vcf │ │ │ │ ├── FastVCFFileReader.java │ │ │ │ ├── MinimalVariantContext.java │ │ │ │ └── VCFLineParser.java │ │ │ ├── model │ │ │ ├── Population.java │ │ │ ├── PopulationMap.java │ │ │ ├── ReferenceVariant.java │ │ │ ├── RiskScore.java │ │ │ ├── RiskScoreSummary.java │ │ │ ├── Sample.java │ │ │ └── ScorePopulationMap.java │ │ │ └── tasks │ │ │ ├── ApplyScoreTask.java │ │ │ ├── CreateHtmlReportTask.java │ │ │ ├── LiftOverScoreTask.java │ │ │ ├── MergeEffectsTask.java │ │ │ ├── MergeReportTask.java │ │ │ ├── MergeScoreTask.java │ │ │ ├── MergeVariantsTask.java │ │ │ └── ResolveScoreTask.java │ └── resources │ │ └── templates │ │ ├── default │ │ ├── components │ │ │ ├── distribution.html │ │ │ ├── samples.html │ │ │ ├── score_details.html │ │ │ └── score_list.html │ │ ├── images │ │ │ └── logo.svg │ │ ├── index.html │ │ ├── report.css │ │ ├── report.js │ │ └── report.json │ │ ├── multi-page │ │ ├── components │ │ │ ├── score_list.html │ │ │ └── score_list.js │ │ ├── index.html │ │ ├── report.json │ │ ├── samples.html │ │ └── score.html │ │ └── txt │ │ └── index.html └── test │ └── java │ └── genepi │ └── riskscore │ ├── commands │ ├── ApplyScoreCommandTest.java │ ├── CreateHtmlReportCommandTest.java │ ├── MergeEffectsCommandTest.java │ ├── MergeVariantsCommandTest.java │ └── ResolveScoreCommandTest.java │ ├── io │ ├── RiskScoreFileTest.java │ ├── dbsnp │ │ └── DbSnpReaderTest.java │ └── proxy │ │ └── ProxyReaderTest.java │ └── tasks │ ├── ApplyScoreTaskTest.java │ ├── CreateHtmlReportTaskTest.java │ ├── MergeEffectsTaskTest.java │ ├── MergeScoreTaskTest.java │ └── MergeVariantsTaskTest.java └── test-data ├── .gitignore ├── PGS000001.txt.gz ├── PGS000018.txt.gz ├── PGS000781.txt.gz ├── PGS000899.txt.gz ├── PGS000957.txt.gz ├── PGS000958.txt.gz ├── PRSWEB_PHECODE153_CRC-Huyghe_PT_UKB_20200608.txt ├── cancer-prsweb.tab ├── chains ├── hg19ToHg38.over.chain.gz └── hg38ToHg19.over.chain.gz ├── chr20.dose.vcf.gz ├── chr20.scores.2.csv ├── chr20.scores.2.csv.format ├── chr20.scores.2.flips.csv ├── chr20.scores.csv ├── chr20.scores.csv.format ├── chr20.scores.csv.gz ├── chr20.scores.csv.gz.format ├── dbsnp-index.small.txt.gz ├── dbsnp-index.small.txt.gz.tbi ├── effects.chunk1.txt ├── effects.chunk2.txt ├── effects.expected.txt ├── lpa.snps.sorted.txt.gz ├── lpa.snps.sorted.txt.gz.tbi ├── merged.expected.txt ├── output.csv ├── pgs-catalog-small.json ├── pgs-ids.txt ├── report.json ├── samples-population.txt ├── samples.txt ├── scores.chunk1.txt ├── scores.chunk2.txt ├── single.hg38.vcf ├── single.vcf ├── single.wrong_chr.vcf ├── small.vcf ├── test.chr1.vcf ├── test.chr2.vcf ├── test.chr2.wrong.vcf ├── test.scores.csv ├── test.scores.csv.format ├── test.scores2.csv ├── test.scores2.csv.format ├── two.vcf └── variants.txt /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: Create Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | 16 | - name: Install JDK 11 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11 20 | 21 | - name: Build 22 | run: mvn install 23 | 24 | - uses: ncipollo/release-action@v1 25 | with: 26 | allowUpdates: true 27 | artifacts: "target/pgs-calc-*.tar.gz" 28 | token: ${{ secrets.GITHUB_TOKEN }} 29 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Java CI with Maven 5 | 6 | on: [push] 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Set up JDK 11 16 | uses: actions/setup-java@v2 17 | with: 18 | java-version: '11' 19 | distribution: 'adopt' 20 | - name: Build with Maven 21 | run: mvn -B package --file pom.xml 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /output.csv 3 | /.DS_Store 4 | /variants.txt 5 | /test-data-output/ 6 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | pgs-calc 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/test/java=UTF-8 4 | encoding/=UTF-8 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 3 | org.eclipse.jdt.core.compiler.compliance=1.8 4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 5 | org.eclipse.jdt.core.compiler.release=disabled 6 | org.eclipse.jdt.core.compiler.source=1.8 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Lukas Forer 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. 22 | -------------------------------------------------------------------------------- /files/chains/hg19ToHg38.over.chain.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/files/chains/hg19ToHg38.over.chain.gz -------------------------------------------------------------------------------- /files/chains/hg38ToHg19.over.chain.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/files/chains/hg38ToHg19.over.chain.gz -------------------------------------------------------------------------------- /files/pgs-calc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export JAVA_PROGRAM_ARGS=`echo "$@"` 3 | FILE_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 4 | java -Xmx10G -jar "$FILE_PATH/pgs-calc.jar" "$@" -------------------------------------------------------------------------------- /src/main/assembly/assembly.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | assembly 7 | 8 | 9 | tar.gz 10 | dir 11 | 12 | 13 | false 14 | 15 | 16 | 17 | / 18 | ${project.build.directory}/${project.artifactId}.jar 19 | ${project.artifactId}.jar 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | / 28 | files 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/App.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore; 2 | 3 | import static lukfor.progress.Components.PROGRESS_BAR; 4 | import static lukfor.progress.Components.SPACE; 5 | import static lukfor.progress.Components.SPINNER; 6 | import static lukfor.progress.Components.TASK_NAME; 7 | import static lukfor.progress.Components.TIME; 8 | 9 | import java.util.concurrent.Callable; 10 | 11 | import genepi.riskscore.commands.*; 12 | import lukfor.progress.renderer.ProgressIndicatorGroup; 13 | import picocli.CommandLine; 14 | import picocli.CommandLine.Command; 15 | 16 | public class App { 17 | 18 | public static final String APP = "pgs-calc"; 19 | 20 | public static final String VERSION = "1.6.1"; 21 | 22 | public static final String URL = "https://github.com/lukfor/pgs-calc"; 23 | 24 | public static final String COPYRIGHT = "(c) 2020 - 2023 Lukas Forer"; 25 | 26 | public static String[] ARGS = new String[0]; 27 | 28 | public static void main(String[] args) { 29 | 30 | System.out.println(); 31 | System.out.println(APP + " " + VERSION); 32 | if (URL != null && !URL.isEmpty()) { 33 | System.out.println(URL); 34 | } 35 | if (COPYRIGHT != null && !COPYRIGHT.isEmpty()) { 36 | System.out.println(COPYRIGHT); 37 | } 38 | System.out.println(); 39 | 40 | ARGS = args; 41 | 42 | int exitCode = new CommandLine(new DefaultCommand()).execute(args); 43 | System.exit(exitCode); 44 | 45 | } 46 | 47 | @Command(name = App.APP, version = App.VERSION, subcommands = { ApplyScoreCommand.class, MergeScoreCommand.class, 48 | MergeInfoCommand.class, MergeVariantsCommand.class, MergeEffectsCommand.class, ResolveScoreCommand.class, 49 | CreateHtmlReportCommand.class, DownloadMetaCommand.class, LiftOverScoreCommand.class, 50 | DownloadScoreCommand.class, ClearCacheCommand.class, ValidateScoreCommand.class, 51 | ProcessHaploRegCommand.class, CreateChunksCommand.class, CreateCollectionCommand.class, FilterMetaCommand.class }) 52 | public static class DefaultCommand implements Callable { 53 | 54 | @Override 55 | public Integer call() throws Exception { 56 | // TODO Auto-generated method stub 57 | return null; 58 | } 59 | 60 | } 61 | 62 | public static ProgressIndicatorGroup STYLE_LONG_TASK = new ProgressIndicatorGroup(SPACE, SPINNER, SPACE, TASK_NAME, 63 | PROGRESS_BAR, TIME); 64 | 65 | public static ProgressIndicatorGroup STYLE_SHORT_TASK = new ProgressIndicatorGroup(SPACE, SPINNER, SPACE, 66 | TASK_NAME); 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/ClearCacheCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | import genepi.riskscore.App; 6 | import genepi.riskscore.io.PGSCatalog; 7 | import picocli.CommandLine.Command; 8 | 9 | @Command(name = "clear-cache", version = App.VERSION) 10 | public class ClearCacheCommand implements Callable { 11 | 12 | public Integer call() throws Exception { 13 | 14 | PGSCatalog.VERBOSE = true; 15 | PGSCatalog.clearCache(); 16 | 17 | return 0; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/CreateChunksCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.concurrent.Callable; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | import genepi.io.table.writer.CsvTableWriter; 9 | import genepi.riskscore.App; 10 | import genepi.riskscore.io.vcf.FastVCFFileReader; 11 | import genepi.riskscore.io.vcf.MinimalVariantContext; 12 | import picocli.CommandLine.Command; 13 | import picocli.CommandLine.Help.Visibility; 14 | import picocli.CommandLine.Option; 15 | import picocli.CommandLine.Parameters; 16 | 17 | @Command(name = "create-chunks", version = App.VERSION) 18 | public class CreateChunksCommand implements Callable { 19 | 20 | @Parameters(description = "VCF files") 21 | List vcfs; 22 | 23 | @Option(names = { "--size" }, description = "Chunk Size", required = true, showDefaultValue = Visibility.ALWAYS) 24 | int chunkSize = 0; 25 | 26 | @Option(names = { 27 | "--out" }, description = "Output Chunk Filename)", required = true, showDefaultValue = Visibility.ALWAYS) 28 | String output = ""; 29 | 30 | public Integer call() throws Exception { 31 | 32 | CsvTableWriter writer = new CsvTableWriter(output); 33 | writer.setColumns(new String[] { "CONTIG", "START", "END", "VARIANTS", "FILENAME" }); 34 | 35 | int countChunks = 0; 36 | 37 | for (String vcf : vcfs) { 38 | 39 | System.out.println("Reading file '" + vcf + "'..."); 40 | 41 | FastVCFFileReader reader = new FastVCFFileReader(vcf); 42 | String contig = null; 43 | 44 | Map chunks = new ConcurrentHashMap(); 45 | 46 | while (reader.next()) { 47 | MinimalVariantContext variant = reader.get(); 48 | 49 | if (contig != null && !variant.getContig().equals(contig)) { 50 | System.out.println("Error: Multiple contigs in file " + vcf + ". Found contigs '" + contig 51 | + "' and '" + variant.getContig() + "'"); 52 | return 1; 53 | } 54 | contig = variant.getContig(); 55 | 56 | int chunkNumber = variant.getStart() / chunkSize; 57 | if (variant.getStart() % chunkSize == 0) { 58 | chunkNumber = chunkNumber - 1; 59 | } 60 | VcfChunk chunk = chunks.get(chunkNumber); 61 | if (chunk == null) { 62 | int chunkStart = chunkNumber * chunkSize + 1; 63 | int chunkEnd = chunkStart + chunkSize - 1; 64 | chunk = new VcfChunk(contig, chunkStart, chunkEnd); 65 | chunks.put(chunkNumber, chunk); 66 | } 67 | 68 | chunk.incVariants(); 69 | 70 | } 71 | reader.close(); 72 | for (VcfChunk chunk : chunks.values()) { 73 | writer.setString("CONTIG", chunk.getContig()); 74 | writer.setInteger("START", chunk.getStart()); 75 | writer.setInteger("END", chunk.getEnd()); 76 | writer.setInteger("VARIANTS", chunk.getVariants()); 77 | writer.setString("FILENAME", vcf); 78 | writer.next(); 79 | countChunks++; 80 | } 81 | } 82 | 83 | writer.close(); 84 | 85 | System.out.println("Done. Wrote " + countChunks + " to file '" + output + "'."); 86 | 87 | return 0; 88 | } 89 | 90 | class VcfChunk { 91 | 92 | private String contig; 93 | 94 | private int start; 95 | 96 | private int end; 97 | 98 | private int variants = 0; 99 | 100 | public VcfChunk(String contig, int start, int end) { 101 | super(); 102 | this.contig = contig; 103 | this.start = start; 104 | this.end = end; 105 | } 106 | 107 | public String getContig() { 108 | return contig; 109 | } 110 | 111 | public void setContig(String contig) { 112 | this.contig = contig; 113 | } 114 | 115 | public int getStart() { 116 | return start; 117 | } 118 | 119 | public void setStart(int start) { 120 | this.start = start; 121 | } 122 | 123 | public int getEnd() { 124 | return end; 125 | } 126 | 127 | public void setEnd(int end) { 128 | this.end = end; 129 | } 130 | 131 | public int getVariants() { 132 | return variants; 133 | } 134 | 135 | public void setVariants(int variants) { 136 | this.variants = variants; 137 | } 138 | 139 | public void incVariants() { 140 | this.variants++; 141 | } 142 | 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/CreateHtmlReportCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Callable; 5 | 6 | import genepi.riskscore.App; 7 | import genepi.riskscore.io.MetaFile; 8 | import genepi.riskscore.io.OutputFile; 9 | import genepi.riskscore.io.ReportFile; 10 | import genepi.riskscore.io.SamplesFile; 11 | import genepi.riskscore.tasks.CreateHtmlReportTask; 12 | import lukfor.progress.TaskService; 13 | import lukfor.progress.tasks.Task; 14 | import picocli.CommandLine.Command; 15 | import picocli.CommandLine.Option; 16 | 17 | @Command(name = "report", version = App.VERSION) 18 | public class CreateHtmlReportCommand implements Callable { 19 | 20 | @Option(names = { "--data" }, description = "JSON file with meta data about scores", required = false) 21 | String data = null; 22 | 23 | @Option(names = { "--info" }, description = "JSON file with meta data about scores", required = true) 24 | String info = null; 25 | 26 | @Option(names = { "--meta" }, description = "JSON file with meta data about scores", required = false) 27 | String meta = null; 28 | 29 | @Option(names = { "--out" }, description = "Output filename", required = true) 30 | String out; 31 | 32 | @Option(names = { "--template" }, description = "template to create html report", required = false) 33 | String template = null; 34 | 35 | @Option(names = { "--samples" }, description = "csv file with ancestry information for each sample", required = false) 36 | String samples = null; 37 | 38 | public Integer call() throws Exception { 39 | 40 | ReportFile infoFile = ReportFile.loadFromFile(info); 41 | 42 | if (meta != null) { 43 | MetaFile metaFile = MetaFile.load(meta); 44 | infoFile.mergeWithMeta(metaFile); 45 | } 46 | 47 | CreateHtmlReportTask htmlReportTask = new CreateHtmlReportTask(); 48 | htmlReportTask.setReport(infoFile); 49 | if (data != null) { 50 | OutputFile outputFile = new OutputFile(data); 51 | htmlReportTask.setData(outputFile); 52 | } 53 | if (samples != null) { 54 | SamplesFile samplesFile = new SamplesFile(samples); 55 | samplesFile.buildIndex(); 56 | htmlReportTask.setSamples(samplesFile); 57 | } 58 | if (template != null) { 59 | htmlReportTask.setTemplate(template); 60 | } 61 | htmlReportTask.setOutput(out); 62 | 63 | if (isFailed(TaskService.monitor(App.STYLE_SHORT_TASK).run(htmlReportTask))) { 64 | return 1; 65 | } else { 66 | return 0; 67 | } 68 | 69 | } 70 | 71 | private boolean isFailed(List tasks) { 72 | for (Task result : tasks) { 73 | if (!result.getStatus().isSuccess()) { 74 | return true; 75 | } 76 | } 77 | return false; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/DownloadMetaCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.net.URL; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | import java.nio.file.StandardCopyOption; 9 | import java.util.concurrent.Callable; 10 | 11 | import genepi.io.FileUtil; 12 | import genepi.riskscore.App; 13 | import genepi.riskscore.io.meta.PGSCatalogCategoryFile; 14 | import genepi.riskscore.io.meta.PGSCatalogMetaFile; 15 | import picocli.CommandLine.Command; 16 | import picocli.CommandLine.Option; 17 | 18 | @Command(name = "download-meta", version = App.VERSION) 19 | public class DownloadMetaCommand implements Callable { 20 | 21 | @Option(names = { "--url-scores" }, description = "PGS-Catalog Url", required = false) 22 | String urlScores = "https://www.pgscatalog.org/rest/score/all?format=json&limit=250"; 23 | 24 | @Option(names = { "--url-trait-catgefory" }, description = "PGS-Catalog Url for category", required = false) 25 | String urlTraits = "https://www.pgscatalog.org/rest/trait_category/all?format=json&limit=250"; 26 | 27 | @Option(names = { "--out" }, description = "Output filename", required = true) 28 | String out; 29 | 30 | public Integer call() throws Exception { 31 | 32 | String traitsFilename = "pgs_catalog_categories.json"; 33 | download(urlTraits, traitsFilename); 34 | PGSCatalogCategoryFile categoryFile = PGSCatalogCategoryFile.load(traitsFilename); 35 | //categoryFile.getCategories(); 36 | 37 | String next = urlScores; 38 | 39 | String chunkFilename = "pgs_catalog_chunk.json"; 40 | 41 | PGSCatalogMetaFile file = null; 42 | while (next != null) { 43 | 44 | System.out.println("Download " + next); 45 | download(next, chunkFilename); 46 | 47 | PGSCatalogMetaFile file1 = PGSCatalogMetaFile.load(chunkFilename, categoryFile); 48 | if (file == null) { 49 | file = file1; 50 | } else { 51 | file.merge(file1); 52 | } 53 | next = file1.getNext(); 54 | } 55 | file.save(out); 56 | 57 | FileUtil.deleteFile(chunkFilename); 58 | 59 | System.out.println("Downloaded meta data from PGS-Catalog to file '" + out + "'."); 60 | 61 | return 0; 62 | } 63 | 64 | private void download(String url, String filename) throws IOException { 65 | InputStream in2 = new URL(url).openStream(); 66 | Files.copy(in2, Paths.get(filename), StandardCopyOption.REPLACE_EXISTING); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/DownloadScoreCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.io.InputStream; 4 | import java.net.URL; 5 | import java.nio.file.Files; 6 | import java.nio.file.Paths; 7 | import java.nio.file.StandardCopyOption; 8 | import java.util.List; 9 | import java.util.concurrent.Callable; 10 | 11 | import genepi.io.FileUtil; 12 | import genepi.riskscore.App; 13 | import genepi.riskscore.io.PGSCatalog; 14 | import picocli.CommandLine.Command; 15 | import picocli.CommandLine.Option; 16 | import picocli.CommandLine.Parameters; 17 | 18 | @Command(name = "download", version = App.VERSION) 19 | public class DownloadScoreCommand implements Callable { 20 | 21 | @Parameters(description = "PGS IDs") 22 | List scores; 23 | 24 | @Option(names = { "--out" }, description = "Output filename or folder when mutiple IDs", required = false) 25 | String out = null; 26 | 27 | public Integer call() throws Exception { 28 | 29 | for (String score : scores) { 30 | 31 | String url = PGSCatalog.getUrl(score); 32 | 33 | String filename = ""; 34 | if (out == null) { 35 | filename = score + ".txt.gz"; 36 | } else { 37 | if (scores.size() == 1) { 38 | filename = out; 39 | } else { 40 | FileUtil.createDirectory(out); 41 | filename = FileUtil.path(out, score + ".txt.gz"); 42 | } 43 | } 44 | 45 | System.out.println("Downloading score " + score + " from " + url + "..."); 46 | 47 | InputStream in = new URL(url).openStream(); 48 | Files.copy(in, Paths.get(filename), StandardCopyOption.REPLACE_EXISTING); 49 | 50 | System.out.println("Downloaded score from PGS-Catalog to file '" + filename + "'."); 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/FilterMetaCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import genepi.io.text.LineWriter; 4 | import genepi.riskscore.App; 5 | import genepi.riskscore.io.MetaFile; 6 | import genepi.riskscore.io.OutputFile; 7 | import genepi.riskscore.io.ReportFile; 8 | import genepi.riskscore.io.SamplesFile; 9 | import genepi.riskscore.tasks.CreateHtmlReportTask; 10 | import lukfor.progress.TaskService; 11 | import lukfor.progress.tasks.Task; 12 | import picocli.CommandLine.Command; 13 | import picocli.CommandLine.Option; 14 | 15 | import java.util.List; 16 | import java.util.concurrent.Callable; 17 | 18 | @Command(name = "filter", version = App.VERSION) 19 | public class FilterMetaCommand implements Callable { 20 | 21 | @Option(names = { "--meta" }, description = "JSON file with meta data about scores", required = true) 22 | String meta = null; 23 | 24 | @Option(names = { "--category" }, description = "category", required = true, split = "") 25 | String category; 26 | 27 | @Option(names = { "--population" }, description = "population", required = false, split = "") 28 | String population; 29 | 30 | @Option(names = { "--out" }, description = "Output filename", required = true) 31 | String out; 32 | 33 | public Integer call() throws Exception { 34 | 35 | LineWriter writer = new LineWriter(out); 36 | 37 | int accepted= 0 ; 38 | MetaFile metaFile = MetaFile.load(meta); 39 | for (MetaFile.MetaScore score: metaFile.getAll()){ 40 | if (accept(score, category, population)){ 41 | writer.write(score.getId()); 42 | accepted++; 43 | } 44 | } 45 | 46 | writer.close(); 47 | 48 | System.out.println("Done. Wrote " + accepted + " scores to file '" + out + "'."); 49 | 50 | return 0; 51 | 52 | } 53 | 54 | private boolean accept(MetaFile.MetaScore score, String category, String population) { 55 | if (category != null) { 56 | if (!score.getCategories().contains(category)){ 57 | return false; 58 | } 59 | } 60 | 61 | if (population != null){ 62 | if ( score.getPopulations() == null){ 63 | return false; 64 | } 65 | if (!score.getPopulations().supports(population)){ 66 | return false; 67 | } 68 | } 69 | 70 | return true; 71 | } 72 | 73 | public void setMeta(String meta) { 74 | this.meta = meta; 75 | } 76 | 77 | public void setCategory(String category) { 78 | this.category = category; 79 | } 80 | 81 | public void setPopulation(String population) { 82 | this.population = population; 83 | } 84 | 85 | public void setOut(String out) { 86 | this.out = out; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/LiftOverScoreCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Callable; 5 | 6 | import genepi.io.FileUtil; 7 | import genepi.io.text.GzipLineWriter; 8 | import genepi.io.text.LineReader; 9 | import genepi.riskscore.App; 10 | import genepi.riskscore.tasks.LiftOverScoreTask; 11 | import lukfor.progress.TaskService; 12 | import lukfor.progress.tasks.Task; 13 | import picocli.CommandLine.Command; 14 | import picocli.CommandLine.Option; 15 | 16 | @Command(name = "liftover", version = App.VERSION) 17 | public class LiftOverScoreCommand implements Callable { 18 | 19 | @Option(names = "--in", description = "input score file", required = true) 20 | private String input; 21 | 22 | @Option(names = "--out", description = "output score file", required = true) 23 | private String output; 24 | 25 | @Option(names = "--chain", description = "chain file", required = true) 26 | private String chain; 27 | 28 | @Override 29 | public Integer call() throws Exception { 30 | 31 | LiftOverScoreTask.VERBOSE = true; 32 | 33 | LiftOverScoreTask task = new LiftOverScoreTask(input, output + ".raw", chain); 34 | TaskService.setAnsiSupport(false); 35 | TaskService.setAnimated(false); 36 | List result = TaskService.run(task); 37 | if (!result.get(0).getStatus().isSuccess()) { 38 | result.get(0).getStatus().getThrowable().printStackTrace(); 39 | System.out.println("*** ERROR *** " + result.get(0).getStatus().getThrowable()); 40 | return 1; 41 | } 42 | 43 | System.out.println("Number Variants Input: " + task.getTotal()); 44 | System.out.println("Number Variants lifted: " + task.getResolved()); 45 | System.out.println("Ignored Variants: " + task.getFailed()); 46 | 47 | LineReader reader = new LineReader(output + ".raw"); 48 | GzipLineWriter writer = new GzipLineWriter(output); 49 | while (reader.next()) { 50 | writer.write(reader.get()); 51 | } 52 | writer.close(); 53 | reader.close(); 54 | 55 | FileUtil.deleteFile(output + ".raw"); 56 | 57 | return 0; 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/MergeEffectsCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Callable; 5 | 6 | import genepi.riskscore.App; 7 | import genepi.riskscore.tasks.MergeEffectsTask; 8 | import lukfor.progress.TaskService; 9 | import lukfor.progress.tasks.Task; 10 | import picocli.CommandLine.Command; 11 | import picocli.CommandLine.Option; 12 | import picocli.CommandLine.Parameters; 13 | 14 | @Command(name = "merge-effects", version = App.VERSION) 15 | public class MergeEffectsCommand implements Callable { 16 | 17 | @Parameters(description = "effects files") 18 | String[] chunkFiles; 19 | 20 | @Option(names = { "--out" }, description = "Output filename", required = true) 21 | String out; 22 | 23 | public Integer call() throws Exception { 24 | 25 | MergeEffectsTask task = new MergeEffectsTask(); 26 | task.setInputs(chunkFiles); 27 | task.setOutput(out); 28 | List results = TaskService.monitor(App.STYLE_LONG_TASK).run(task); 29 | 30 | if (isFailed(results)) { 31 | results.get(0).getStatus().getThrowable().printStackTrace(); 32 | return 1; 33 | } else { 34 | return 0; 35 | } 36 | 37 | } 38 | 39 | private boolean isFailed(List tasks) { 40 | for (Task result : tasks) { 41 | if (!result.getStatus().isSuccess()) { 42 | return true; 43 | } 44 | } 45 | return false; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/MergeInfoCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Callable; 5 | 6 | import genepi.riskscore.App; 7 | import genepi.riskscore.tasks.MergeReportTask; 8 | import lukfor.progress.TaskService; 9 | import lukfor.progress.tasks.Task; 10 | import picocli.CommandLine.Command; 11 | import picocli.CommandLine.Option; 12 | import picocli.CommandLine.Parameters; 13 | 14 | @Command(name = "merge-info", version = App.VERSION) 15 | public class MergeInfoCommand implements Callable { 16 | 17 | @Parameters(description = "info files") 18 | String[] chunkFiles; 19 | 20 | @Option(names = { "--out" }, description = "Output filename", required = true) 21 | String out; 22 | 23 | public Integer call() throws Exception { 24 | 25 | MergeReportTask task = new MergeReportTask(); 26 | task.setInputs(chunkFiles); 27 | task.setOutput(out); 28 | 29 | List results = TaskService.monitor(App.STYLE_LONG_TASK).run(task); 30 | 31 | if (isFailed(results)) { 32 | results.get(0).getStatus().getThrowable().printStackTrace(); 33 | return 1; 34 | } else { 35 | return 0; 36 | } 37 | 38 | } 39 | 40 | private boolean isFailed(List tasks) { 41 | for (Task result : tasks) { 42 | if (!result.getStatus().isSuccess()) { 43 | return true; 44 | } 45 | } 46 | return false; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/MergeScoreCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Callable; 5 | 6 | import genepi.riskscore.App; 7 | import genepi.riskscore.tasks.MergeScoreTask; 8 | import lukfor.progress.TaskService; 9 | import lukfor.progress.tasks.Task; 10 | import picocli.CommandLine.Command; 11 | import picocli.CommandLine.Option; 12 | import picocli.CommandLine.Parameters; 13 | 14 | @Command(name = "merge-score", version = App.VERSION) 15 | public class MergeScoreCommand implements Callable { 16 | 17 | @Parameters(description = "score files") 18 | String[] chunkFiles; 19 | 20 | @Option(names = { "--out" }, description = "Output filename", required = true) 21 | String out; 22 | 23 | public Integer call() throws Exception { 24 | 25 | MergeScoreTask task = new MergeScoreTask(); 26 | task.setInputs(chunkFiles); 27 | task.setOutput(out); 28 | List results = TaskService.monitor(App.STYLE_LONG_TASK).run(task); 29 | 30 | if (isFailed(results)) { 31 | results.get(0).getStatus().getThrowable().printStackTrace(); 32 | return 1; 33 | } else { 34 | return 0; 35 | } 36 | 37 | } 38 | 39 | private boolean isFailed(List tasks) { 40 | for (Task result : tasks) { 41 | if (!result.getStatus().isSuccess()) { 42 | return true; 43 | } 44 | } 45 | return false; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/MergeVariantsCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Callable; 5 | 6 | import genepi.riskscore.App; 7 | import genepi.riskscore.tasks.MergeVariantsTask; 8 | import lukfor.progress.TaskService; 9 | import lukfor.progress.tasks.Task; 10 | import picocli.CommandLine.Command; 11 | import picocli.CommandLine.Option; 12 | import picocli.CommandLine.Parameters; 13 | 14 | @Command(name = "merge-variants", version = App.VERSION) 15 | public class MergeVariantsCommand implements Callable { 16 | 17 | @Parameters(description = "variant files") 18 | String[] chunkFiles; 19 | 20 | @Option(names = { "--out" }, description = "Output filename", required = true) 21 | String out; 22 | 23 | public Integer call() throws Exception { 24 | 25 | MergeVariantsTask task = new MergeVariantsTask(); 26 | task.setInputs(chunkFiles); 27 | task.setOutput(out); 28 | List results = TaskService.monitor(App.STYLE_LONG_TASK).run(task); 29 | 30 | if (isFailed(results)) { 31 | results.get(0).getStatus().getThrowable().printStackTrace(); 32 | return 1; 33 | } else { 34 | return 0; 35 | } 36 | 37 | } 38 | 39 | private boolean isFailed(List tasks) { 40 | for (Task result : tasks) { 41 | if (!result.getStatus().isSuccess()) { 42 | return true; 43 | } 44 | } 45 | return false; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/ProcessHaploRegCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.io.DataInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.util.HashSet; 7 | import java.util.List; 8 | import java.util.Set; 9 | import java.util.Vector; 10 | import java.util.concurrent.Callable; 11 | 12 | import genepi.io.text.LineReader; 13 | import genepi.io.text.LineWriter; 14 | import genepi.riskscore.App; 15 | import genepi.riskscore.io.dbsnp.DbSnpReader; 16 | import genepi.riskscore.io.dbsnp.DbSnpReader.Snp; 17 | import lukfor.progress.TaskService; 18 | import lukfor.progress.tasks.ITaskRunnable; 19 | import lukfor.progress.tasks.monitors.ITaskMonitor; 20 | import lukfor.progress.util.CountingInputStream; 21 | import picocli.CommandLine.Command; 22 | import picocli.CommandLine.Option; 23 | import picocli.CommandLine.Help.Visibility; 24 | 25 | @Command(name = "proxy", version = App.VERSION) 26 | public class ProcessHaploRegCommand implements Callable { 27 | 28 | @Option(names = { "--in" }, description = "Input filename", required = true) 29 | String input; 30 | 31 | @Option(names = { "--out" }, description = "Output filename", required = true) 32 | String output; 33 | 34 | @Option(names = { "--r2" }, description = "LD threshold", required = false) 35 | double r2 = 0.95; 36 | 37 | @Option(names = { "--dbsnp" }, description = "dbsnp index", required = true) 38 | String dbsnp = ""; 39 | 40 | @Option(names = { 41 | "--no-ansi" }, description = "Disable ANSI output", required = false, showDefaultValue = Visibility.ALWAYS) 42 | boolean noAnsi = false; 43 | 44 | @Option(names = { "--ids" }, description = "rsIds of snps used in index", required = false) 45 | String ids = null; 46 | 47 | 48 | @Override 49 | public Integer call() throws Exception { 50 | 51 | if (noAnsi) { 52 | TaskService.setAnimated(false); 53 | TaskService.setAnsiColors(false); 54 | } 55 | 56 | ProcessHaploRegTask task = new ProcessHaploRegTask(); 57 | TaskService.monitor(App.STYLE_LONG_TASK).run(task); 58 | 59 | return 0; 60 | 61 | } 62 | 63 | public static String join(List alleles) { 64 | String result = ""; 65 | for (int i = 0; i < alleles.size(); i++) { 66 | if (i > 0) { 67 | result += ";"; 68 | } 69 | result += alleles.get(i); 70 | } 71 | return result; 72 | } 73 | 74 | class ProcessHaploRegTask implements ITaskRunnable { 75 | 76 | @Override 77 | public void run(ITaskMonitor monitor) throws Exception { 78 | 79 | monitor.begin("Parse file", new File(input).length()); 80 | 81 | CountingInputStream countingStream = new CountingInputStream(new FileInputStream(input), monitor); 82 | 83 | DbSnpReader dbSnpReader = new DbSnpReader(dbsnp); 84 | 85 | LineWriter writer = new LineWriter(output); 86 | 87 | LineReader reader = new LineReader(new DataInputStream(countingStream)); 88 | 89 | Set rsIds = new HashSet(); 90 | if (ids != null) { 91 | LineReader rsIdsReader = new LineReader(ids); 92 | while(rsIdsReader.next()) { 93 | String id = rsIdsReader.get(); 94 | if (!id.trim().isEmpty()) { 95 | rsIds.add(id.trim()); 96 | } 97 | } 98 | rsIdsReader.close(); 99 | } 100 | 101 | while (reader.next()) { 102 | if (monitor.isCanceled()) { 103 | writer.close(); 104 | reader.close(); 105 | return; 106 | } 107 | 108 | List finalProxies = new Vector(); 109 | 110 | String line = reader.get(); 111 | String[] tiles = line.split("\t"); 112 | String id = tiles[0]; 113 | 114 | if (!rsIds.isEmpty()) { 115 | if (!rsIds.contains(id)) { 116 | continue; 117 | } 118 | } 119 | 120 | Snp snp = dbSnpReader.getByRsId(id); 121 | if (snp != null) { 122 | // Ignore multi allelic 123 | if (!snp.getAlternate().contains(",")) { 124 | String[] proxies = tiles[1].split(";"); 125 | for (String proxy : proxies) { 126 | String[] proxyDetails = proxy.split(","); 127 | double proxyR2 = Double.parseDouble(proxyDetails[1]); 128 | if (proxyR2 >= r2) { 129 | Snp proxySnp = dbSnpReader.getByRsId(proxyDetails[0]); 130 | if (proxySnp != null) { 131 | // Remove multi allelic 132 | if (!proxySnp.getAlternate().contains(",")) { 133 | finalProxies.add(proxySnp.getChromosome() + ":" + proxySnp.getPosition() + ":" 134 | + proxySnp.getReference() + ":" + proxySnp.getAlternate()); 135 | } 136 | } 137 | } 138 | } 139 | 140 | if (!finalProxies.isEmpty()) { 141 | writer.write(snp.getChromosome() + "\t" + snp.getPosition() + "\t" + snp.getReference() 142 | + "\t" + snp.getAlternate() + "\t" + join(finalProxies)); 143 | } 144 | } 145 | } 146 | 147 | } 148 | reader.close(); 149 | writer.close(); 150 | 151 | } 152 | 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/ValidateScoreCommand.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Callable; 5 | 6 | import genepi.io.table.writer.CsvTableWriter; 7 | import genepi.riskscore.App; 8 | import genepi.riskscore.io.PGSCatalog; 9 | import genepi.riskscore.io.RiskScoreFile; 10 | import genepi.riskscore.tasks.ApplyScoreTask; 11 | import genepi.riskscore.tasks.LiftOverScoreTask; 12 | import genepi.riskscore.tasks.ResolveScoreTask; 13 | import picocli.CommandLine.Command; 14 | import picocli.CommandLine.Help.Visibility; 15 | import picocli.CommandLine.Option; 16 | import picocli.CommandLine.Parameters; 17 | 18 | @Command(name = "validate", version = App.VERSION) 19 | public class ValidateScoreCommand implements Callable { 20 | 21 | @Parameters(description = "Score files") 22 | List scores; 23 | 24 | @Option(names = { "--out" }, description = "Output filename", required = false) 25 | String out; 26 | 27 | @Option(names = { 28 | "--verbose" }, description = "Show debug messages", required = false, showDefaultValue = Visibility.ALWAYS) 29 | boolean verbose = false; 30 | 31 | @Override 32 | public Integer call() throws Exception { 33 | 34 | if (verbose) { 35 | RiskScoreFile.VERBOSE = true; 36 | ResolveScoreTask.VERBOSE = true; 37 | ApplyScoreTask.VERBOSE = true; 38 | LiftOverScoreTask.VERBOSE = true; 39 | PGSCatalog.VERBOSE = true; 40 | } 41 | 42 | CsvTableWriter writer = null; 43 | if (out != null) { 44 | writer = new CsvTableWriter(out); 45 | writer.setColumns(new String[] { "score", "coverage", "variants", "original_variants", }); 46 | } 47 | 48 | for (String input : scores) { 49 | 50 | try { 51 | // test file format 52 | RiskScoreFile score = null; 53 | int loaded = 0; 54 | for (int i = 1; i <= 22; i++) { 55 | System.out.println("Validate chromosome " + i + "..."); 56 | score = new RiskScoreFile(input, null, null); 57 | score.buildIndex(i + ""); 58 | loaded += score.getLoadedVariants(); 59 | } 60 | 61 | // chr X 62 | System.out.println("Validate chromosome X..."); 63 | score = new RiskScoreFile(input, null, null); 64 | score.buildIndex("X"); 65 | loaded += score.getLoadedVariants(); 66 | 67 | String name = RiskScoreFile.getName(input); 68 | System.out.println("--------------------------------------"); 69 | System.out.println("Score File: " + input); 70 | System.out.println("Score Name: " + name); 71 | System.out.println("Output File Format: " + score.getFormat()); 72 | System.out.println("Number Variants Output: " + loaded + "/" + score.getTotalVariants()); 73 | System.out.println("--------------------------------------"); 74 | 75 | if (writer != null) { 76 | writer.setString("score", name); 77 | writer.setDouble("coverage", (double) loaded / (double) score.getTotalVariants()); 78 | writer.setInteger("variants", loaded); 79 | writer.setInteger("original_variants", score.getTotalVariants()); 80 | writer.next(); 81 | } 82 | 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | System.out.println("*** ERROR *** " + e); 86 | return 1; 87 | } 88 | } 89 | 90 | if (writer != null) { 91 | writer.close(); 92 | } 93 | 94 | return 0; 95 | 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/commands/VariantReadingException.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | public class VariantReadingException extends Exception { 4 | public VariantReadingException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/Chunk.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import picocli.CommandLine.Option; 4 | 5 | public class Chunk { 6 | 7 | @Option(names = "--start", required = true) 8 | int start = 0; 9 | @Option(names = "--end", required = true) 10 | int end = Integer.MAX_VALUE; 11 | 12 | public int getStart() { 13 | return start; 14 | } 15 | 16 | public void setStart(int start) { 17 | this.start = start; 18 | } 19 | 20 | public int getEnd() { 21 | return end; 22 | } 23 | 24 | public void setEnd(int end) { 25 | this.end = end; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/MetaFile.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import java.io.IOException; 4 | import java.util.Collection; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Vector; 8 | 9 | import com.google.gson.Gson; 10 | import com.google.gson.JsonIOException; 11 | import com.google.gson.JsonSyntaxException; 12 | 13 | import genepi.io.text.LineWriter; 14 | import genepi.riskscore.io.meta.JsonMetaFileReader; 15 | import genepi.riskscore.io.meta.TabMetaFileReader; 16 | import genepi.riskscore.model.ScorePopulationMap; 17 | 18 | public class MetaFile { 19 | 20 | protected Map index; 21 | 22 | public MetaFile(Map index) { 23 | this.index = index; 24 | } 25 | 26 | public static MetaFile load(String filename) throws JsonIOException, JsonSyntaxException, IOException { 27 | 28 | if (filename.endsWith(".json")) { 29 | return JsonMetaFileReader.load(filename); 30 | } else if (filename.endsWith(".csv") || filename.endsWith(".txt") || filename.endsWith("tab")) { 31 | return TabMetaFileReader.load(filename); 32 | } else { 33 | throw new IOException("Unsupported file format"); 34 | } 35 | 36 | } 37 | 38 | public MetaScore getById(String id) { 39 | return index.get(id); 40 | } 41 | 42 | public Collection getAll(){ 43 | return index.values(); 44 | } 45 | 46 | public void save(String filename) throws IOException { 47 | Gson gson = new Gson(); 48 | String json = gson.toJson(index); 49 | LineWriter writer = new LineWriter(filename); 50 | writer.write(json); 51 | writer.close(); 52 | } 53 | 54 | public static class MetaScore { 55 | 56 | private String id; 57 | 58 | private String trait; 59 | 60 | private List> efo; 61 | 62 | private String traitAdditional; 63 | 64 | private ScorePopulationMap populations; 65 | 66 | private Map publication; 67 | 68 | private List categories = new Vector(); 69 | 70 | private int variants; 71 | 72 | private String repository; 73 | 74 | private String link; 75 | 76 | private int samples; 77 | 78 | public String getId() { 79 | return id; 80 | } 81 | 82 | public void setId(String id) { 83 | this.id = id; 84 | } 85 | 86 | public String getTrait() { 87 | return trait; 88 | } 89 | 90 | public void setTrait(String trait) { 91 | this.trait = trait; 92 | } 93 | 94 | public String getTraitAdditional() { 95 | return traitAdditional; 96 | } 97 | 98 | public void setTraitAdditional(String traitAdditional) { 99 | this.traitAdditional = traitAdditional; 100 | } 101 | 102 | public List> getEfo() { 103 | return efo; 104 | } 105 | 106 | public void setEfo(List> efo) { 107 | this.efo = efo; 108 | } 109 | 110 | public ScorePopulationMap getPopulations() { 111 | return populations; 112 | } 113 | 114 | public void setPopulations(ScorePopulationMap populations) { 115 | this.populations = populations; 116 | } 117 | 118 | public Map getPublication() { 119 | return publication; 120 | } 121 | 122 | public void setPublication(Map publication) { 123 | this.publication = publication; 124 | } 125 | 126 | public int getVariants() { 127 | return variants; 128 | } 129 | 130 | public void setVariants(int variants) { 131 | this.variants = variants; 132 | } 133 | 134 | public String getRepository() { 135 | return repository; 136 | } 137 | 138 | public void setRepository(String repository) { 139 | this.repository = repository; 140 | } 141 | 142 | public String getLink() { 143 | return link; 144 | } 145 | 146 | public void setLink(String link) { 147 | this.link = link; 148 | } 149 | 150 | public int getSamples() { 151 | return samples; 152 | } 153 | 154 | public void setSamples(int samples) { 155 | this.samples = samples; 156 | } 157 | 158 | public List getCategories() { 159 | return categories; 160 | } 161 | 162 | public void addCategory(String category){ 163 | if (categories.contains(category)){ 164 | return; 165 | } 166 | this.categories.add(category); 167 | } 168 | 169 | public void setCategories(List categories) { 170 | this.categories = categories; 171 | } 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/OutputFile.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import java.io.IOException; 4 | import java.util.Arrays; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Vector; 9 | 10 | public class OutputFile { 11 | 12 | private List samples; 13 | 14 | private List data; 15 | 16 | private List scores; 17 | 18 | private Map scoresIndex = new HashMap(); 19 | 20 | public OutputFile(String filename) throws IOException { 21 | 22 | OutputFileReader outputFile = new OutputFileReader(filename); 23 | 24 | scores = outputFile.getScores(); 25 | int index = 0; 26 | for (String score: scores) { 27 | scoresIndex.put(score, index); 28 | index++; 29 | } 30 | 31 | samples = new Vector(); 32 | data = new Vector(); 33 | while (outputFile.next()) { 34 | samples.add(outputFile.getSample()); 35 | double[] values = Arrays.copyOf(outputFile.getValues(), outputFile.getValues().length); 36 | data.add(values); 37 | } 38 | outputFile.close(); 39 | 40 | } 41 | 42 | public int getCountSamples() { 43 | return samples.size(); 44 | } 45 | 46 | public List getSamples() { 47 | return samples; 48 | } 49 | 50 | public int getCountScores() { 51 | return scores.size(); 52 | } 53 | 54 | public List getScores() { 55 | return scores; 56 | } 57 | 58 | public double getValue(int score, int sample) { 59 | return data.get(sample)[score]; 60 | } 61 | 62 | public double[] getValuesByScore(String score) { 63 | int scoreIndex = scoresIndex.get(score); 64 | double[] values = new double[samples.size()]; 65 | for (int i = 0; i < values.length; i++) { 66 | values[i] = getValue(scoreIndex, i); 67 | } 68 | return values; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/OutputFileReader.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | import java.util.Vector; 6 | 7 | import genepi.io.table.reader.CsvTableReader; 8 | import genepi.io.table.reader.ITableReader; 9 | 10 | public class OutputFileReader { 11 | 12 | public static final String COLUMN_SAMPLE = "sample"; 13 | 14 | public static final char SEPARATOR = ','; 15 | 16 | private double[] data; 17 | 18 | private List scores; 19 | 20 | private ITableReader reader; 21 | 22 | public OutputFileReader(String filename) { 23 | init(filename); 24 | } 25 | 26 | public void init(String filename) { 27 | 28 | reader = new CsvTableReader(filename, SEPARATOR); 29 | 30 | scores = new Vector(); 31 | String[] columns = reader.getColumns(); 32 | for (String column : columns) { 33 | if (!column.equals(COLUMN_SAMPLE)) { 34 | scores.add(column); 35 | } 36 | } 37 | 38 | data = new double[scores.size()]; 39 | 40 | } 41 | 42 | public boolean next() { 43 | return reader.next(); 44 | } 45 | 46 | public double[] getValues() { 47 | for (int i = 0; i < scores.size(); i++) { 48 | data[i] = reader.getDouble(scores.get(i)); 49 | } 50 | return data; 51 | } 52 | 53 | public String getSample() throws IOException { 54 | return reader.getString(COLUMN_SAMPLE); 55 | } 56 | 57 | public void close() { 58 | reader.close(); 59 | } 60 | 61 | public List getScores() { 62 | return scores; 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return "scores: " + scores.size(); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/OutputFileWriter.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | import java.util.Vector; 6 | 7 | import genepi.io.table.reader.CsvTableReader; 8 | import genepi.io.table.reader.ITableReader; 9 | import genepi.io.table.writer.CsvTableWriter; 10 | import genepi.io.table.writer.ITableWriter; 11 | import genepi.riskscore.model.RiskScore; 12 | import genepi.riskscore.model.RiskScoreSummary; 13 | 14 | public class OutputFileWriter { 15 | 16 | public static final String COLUMN_SAMPLE = "sample"; 17 | 18 | public static final char SEPARATOR = ','; 19 | 20 | private List samples; 21 | 22 | private List[] data; 23 | 24 | private List scores; 25 | 26 | public OutputFileWriter() { 27 | 28 | } 29 | 30 | public OutputFileWriter(List finalScores, RiskScoreSummary[] summaries) { 31 | 32 | scores = new Vector(); 33 | for (RiskScoreSummary summary : summaries) { 34 | scores.add(summary.getName()); 35 | } 36 | 37 | samples = new Vector(); 38 | data = new Vector[scores.size()]; 39 | for (int i = 0; i < scores.size(); i++) { 40 | data[i] = new Vector(); 41 | } 42 | 43 | for (RiskScore riskScore : finalScores) { 44 | samples.add(riskScore.getSample()); 45 | for (int i = 0; i < scores.size(); i++) { 46 | data[i].add(riskScore.getScore(i)); 47 | } 48 | } 49 | 50 | } 51 | 52 | public void save(String filename) { 53 | 54 | String[] columns = new String[scores.size() + 1]; 55 | columns[0] = COLUMN_SAMPLE; 56 | for (int i = 0; i < scores.size(); i++) { 57 | columns[i + 1] = scores.get(i); 58 | } 59 | 60 | ITableWriter writer = new CsvTableWriter(filename, SEPARATOR); 61 | writer.setColumns(columns); 62 | 63 | for (int i = 0; i < samples.size(); i++) { 64 | writer.setString(COLUMN_SAMPLE, samples.get(i)); 65 | for (int j = 0; j < scores.size(); j++) { 66 | writer.setDouble(scores.get(j), data[j].get(i)); 67 | } 68 | writer.next(); 69 | } 70 | 71 | writer.close(); 72 | 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/PGSCatalog.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.net.URL; 7 | import java.nio.file.Files; 8 | import java.nio.file.Paths; 9 | import java.nio.file.StandardCopyOption; 10 | import java.text.MessageFormat; 11 | 12 | import genepi.io.FileUtil; 13 | 14 | public class PGSCatalog { 15 | 16 | public static String USER_HOME = System.getProperty("user.home"); 17 | 18 | public static boolean ENABLE_CACHE = true; 19 | 20 | public static String CACHE_DIR = FileUtil.path(USER_HOME, ".pgs-calc", "pgs-catalog"); 21 | 22 | public static String FILE_URL = "http://ftp.ebi.ac.uk/pub/databases/spot/pgs/scores/{0}/ScoringFiles/{0}.txt.gz"; 23 | 24 | public static boolean VERBOSE = false; 25 | 26 | public static String getFilenameById(String id) throws IOException { 27 | 28 | String filename = FileUtil.path(CACHE_DIR, id + ".txt.gz"); 29 | 30 | if ((new File(filename)).exists()) { 31 | debug("Score '" + id + "' found in local cache " + filename); 32 | if (ENABLE_CACHE) { 33 | return filename; 34 | } else 35 | new File(filename).delete(); 36 | } 37 | 38 | FileUtil.createDirectory(CACHE_DIR); 39 | 40 | String url = getUrl(id); 41 | 42 | debug("Downloading score '" + id + "' from " + url + "..."); 43 | 44 | InputStream in = new URL(url).openStream(); 45 | Files.copy(in, Paths.get(filename), StandardCopyOption.REPLACE_EXISTING); 46 | 47 | debug("Score '" + id + "' downloaded and cached in file '" + filename + "'."); 48 | 49 | 50 | return filename; 51 | 52 | } 53 | 54 | public static void clearCache() { 55 | FileUtil.deleteDirectory(CACHE_DIR); 56 | debug("Deleted cache directory '" + CACHE_DIR + "'"); 57 | } 58 | 59 | public static boolean isValidId(String id) { 60 | return (id.startsWith("PGS") && id.length() == 9 && !id.endsWith(".txt.gz")); 61 | } 62 | 63 | public static String getUrl(String id) { 64 | MessageFormat format = new MessageFormat(FILE_URL); 65 | return format.format(new Object[] { id }); 66 | 67 | } 68 | 69 | public static void debug(String message) { 70 | if (VERBOSE) { 71 | System.out.println(message); 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/PGSCatalogIDFile.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | import java.util.Vector; 6 | 7 | import genepi.io.text.LineReader; 8 | 9 | public class PGSCatalogIDFile { 10 | 11 | private String filename; 12 | 13 | public static final String COLUMN_ID = "PGSID"; 14 | 15 | public PGSCatalogIDFile(String filename) { 16 | 17 | this.filename = filename; 18 | 19 | } 20 | 21 | public String[] getIds() throws Exception { 22 | 23 | if (!new File(filename).exists()) { 24 | throw new Exception("File '" + filename + "' not found."); 25 | } 26 | 27 | LineReader reader = new LineReader(filename); 28 | if (!reader.next()) { 29 | throw new Exception("File '" + filename + "' is empty."); 30 | } 31 | 32 | String header = reader.get(); 33 | if (!header.equalsIgnoreCase(COLUMN_ID)) { 34 | throw new Exception("Column '" + COLUMN_ID + "' not found in '" + filename + "'"); 35 | } 36 | 37 | List ids = new Vector(); 38 | while (reader.next()) { 39 | String id = reader.get(); 40 | if (!id.trim().isEmpty() && !ids.contains(id)) { 41 | ids.add(id); 42 | } 43 | } 44 | reader.close(); 45 | 46 | String[] result = new String[ids.size()]; 47 | return ids.toArray(result); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/ReportFile.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import java.io.FileReader; 4 | import java.io.FileWriter; 5 | import java.io.IOException; 6 | import java.lang.reflect.Type; 7 | import java.util.Comparator; 8 | import java.util.List; 9 | import java.util.Vector; 10 | 11 | import com.google.gson.Gson; 12 | import com.google.gson.JsonIOException; 13 | import com.google.gson.reflect.TypeToken; 14 | 15 | import genepi.riskscore.io.MetaFile.MetaScore; 16 | import genepi.riskscore.model.RiskScoreSummary; 17 | 18 | public class ReportFile { 19 | 20 | private List summaries; 21 | 22 | public ReportFile() { 23 | this.summaries = new Vector(); 24 | } 25 | 26 | public ReportFile(RiskScoreSummary[] summaries) { 27 | this.summaries = new Vector(); 28 | for (RiskScoreSummary summary : summaries) { 29 | this.summaries.add(summary); 30 | } 31 | } 32 | 33 | public void save(String filename) throws JsonIOException, IOException { 34 | 35 | Gson gson = new Gson(); 36 | Type type = new TypeToken>() { 37 | }.getType(); 38 | FileWriter writer = new FileWriter(filename); 39 | gson.toJson(summaries, type, writer); 40 | writer.close(); 41 | 42 | } 43 | 44 | public static ReportFile loadFromFile(String filename) throws IOException { 45 | ReportFile reportFile = new ReportFile(); 46 | reportFile.load(filename); 47 | return reportFile; 48 | } 49 | 50 | public void load(String filename) throws IOException { 51 | 52 | Gson gson = new Gson(); 53 | Type type = new TypeToken>() { 54 | }.getType(); 55 | this.summaries = gson.fromJson(new FileReader(filename), type); 56 | 57 | } 58 | 59 | public void merge(ReportFile file) throws Exception { 60 | 61 | summaries.size(); 62 | file.summaries.size(); 63 | 64 | if (summaries.size() != file.summaries.size()) { 65 | throw new Exception("Different number of scores. Expected " + summaries.size() + " samples but found " 66 | + file.summaries.size() + " scores."); 67 | } 68 | 69 | // sum up all statistics 70 | for (int i = 0; i < summaries.size(); i++) { 71 | summaries.get(i).merge(file.summaries.get(i)); 72 | } 73 | 74 | } 75 | 76 | public void mergeWithMeta(MetaFile meta) { 77 | for (RiskScoreSummary summary : summaries) { 78 | MetaScore data = meta.getById(summary.getName()); 79 | if (data != null) { 80 | summary.setMeta(data); 81 | } 82 | } 83 | } 84 | 85 | public void mergeWithData(OutputFile data) { 86 | for (int i = 0; i < getSummaries().size(); i++) { 87 | // ignore empty scores 88 | if (getSummaries().get(i).getVariantsUsed() > 0) { 89 | if (data != null) { 90 | getSummaries().get(i).setData(data.getValuesByScore(getSummaries().get(i).getName())); 91 | } 92 | } 93 | getSummaries().get(i).updateStatistics(); 94 | getSummaries().get(i).updateColorAndLabel(); 95 | } 96 | 97 | // sort summaries by pgs name 98 | getSummaries().sort(new Comparator() { 99 | @Override 100 | public int compare(RiskScoreSummary o1, RiskScoreSummary o2) { 101 | return o1.getName().compareTo(o2.getName()); 102 | } 103 | }); 104 | } 105 | 106 | public void checkPopulations(SamplesFile samples, OutputFile data) { 107 | 108 | if (samples != null && data != null) { 109 | for (RiskScoreSummary score : getSummaries()) { 110 | score.checkPopulation(data.getSamples(), samples); 111 | } 112 | } else { 113 | for (RiskScoreSummary score : getSummaries()) { 114 | score.setPopulationCheckStatus(true); 115 | } 116 | } 117 | 118 | } 119 | 120 | public List getSummaries() { 121 | return summaries; 122 | } 123 | 124 | @Override 125 | public String toString() { 126 | return "scores: " + summaries.size(); 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/SamplesFile.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Vector; 9 | 10 | import genepi.io.table.reader.CsvTableReader; 11 | import genepi.io.table.reader.ITableReader; 12 | import genepi.riskscore.model.Population; 13 | import genepi.riskscore.model.PopulationMap; 14 | import genepi.riskscore.model.Sample; 15 | 16 | public class SamplesFile { 17 | 18 | private String filename; 19 | 20 | private Map samples; 21 | 22 | private int totalSamples = 0; 23 | 24 | public static final char SEPARATOR = '\t'; 25 | 26 | public static final String COLUMN_POPULATION = "population"; 27 | 28 | public SamplesFile(String filename) throws Exception { 29 | 30 | this.filename = filename; 31 | samples = new HashMap(); 32 | 33 | if (!new File(filename).exists()) { 34 | throw new Exception("File '" + filename + "' not found."); 35 | } 36 | 37 | ITableReader reader = new CsvTableReader(filename, SEPARATOR); 38 | checkFileFormat(reader, filename); 39 | reader.close(); 40 | } 41 | 42 | private void checkFileFormat(ITableReader reader, String filename) throws Exception { 43 | if (!reader.hasColumn(OutputFileWriter.COLUMN_SAMPLE)) { 44 | throw new Exception("Column '" + OutputFileWriter.COLUMN_SAMPLE + "' not found in '" + filename + "'"); 45 | } 46 | } 47 | 48 | public void buildIndex() throws IOException { 49 | ITableReader reader = new CsvTableReader(filename, SEPARATOR); 50 | while (reader.next()) { 51 | String sample = reader.getString(OutputFileWriter.COLUMN_SAMPLE); 52 | String population = Sample.UNKNOWN_POPULATION; 53 | if (reader.hasColumn(COLUMN_POPULATION)) { 54 | population = reader.getString(COLUMN_POPULATION); 55 | } 56 | samples.put(sample, new Sample(sample, population)); 57 | totalSamples++; 58 | } 59 | reader.close(); 60 | } 61 | 62 | public boolean contains(String sample) { 63 | return samples.containsKey(sample); 64 | } 65 | 66 | public int getTotalSamples() { 67 | return totalSamples; 68 | } 69 | 70 | public PopulationMap getPopulations() { 71 | PopulationMap populations = new PopulationMap(); 72 | for (Sample sample : samples.values()) { 73 | populations.addSample(sample.getPopulation()); 74 | } 75 | return populations; 76 | } 77 | 78 | public List getSamples(Population population) { 79 | List result = new Vector(); 80 | for (Sample sample : samples.values()) { 81 | if (sample.getPopulation().equals(population.getName())) { 82 | result.add(sample.getId()); 83 | } 84 | } 85 | return result; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/ScoresFile.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | import java.util.Vector; 6 | 7 | import genepi.io.FileUtil; 8 | import genepi.io.text.LineReader; 9 | 10 | public class ScoresFile { 11 | 12 | private String filename; 13 | 14 | public static final String COLUMN_ID = "SCORES"; 15 | 16 | public ScoresFile(String filename) { 17 | 18 | this.filename = filename; 19 | 20 | } 21 | 22 | public String[] getFilenames() throws Exception { 23 | 24 | if (!new File(filename).exists()) { 25 | throw new Exception("File '" + filename + "' not found."); 26 | } 27 | 28 | LineReader reader = new LineReader(filename); 29 | if (!reader.next()) { 30 | throw new Exception("File '" + filename + "' is empty."); 31 | } 32 | 33 | String header = reader.get(); 34 | if (!header.equalsIgnoreCase(COLUMN_ID)) { 35 | throw new Exception("Column '" + COLUMN_ID + "' not found in '" + filename + "'"); 36 | } 37 | 38 | String path = new File(filename).getAbsoluteFile().getParent(); 39 | 40 | List ids = new Vector(); 41 | while (reader.next()) { 42 | String id = reader.get(); 43 | if (!id.trim().isEmpty() && !ids.contains(id)) { 44 | if (id.startsWith("/")){ 45 | ids.add(id); 46 | }else { 47 | ids.add(FileUtil.path(path, id)); 48 | } 49 | } 50 | } 51 | reader.close(); 52 | 53 | String[] result = new String[ids.size()]; 54 | return ids.toArray(result); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/VariantFile.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | import genepi.io.table.reader.CsvTableReader; 11 | import genepi.io.table.reader.ITableReader; 12 | 13 | public class VariantFile { 14 | 15 | private String filename; 16 | 17 | private Map> variants; 18 | 19 | private int totalVariants = 0; 20 | 21 | public static final char SEPARATOR = '\t'; 22 | 23 | public static final String SCORE = "score"; 24 | 25 | public static final String CHROMOSOME = "chr_name"; 26 | 27 | public static final String POSITION = "chr_position"; 28 | 29 | public static final String R2 = "r2"; 30 | 31 | public static final String INCLUDE = "INCLUDE"; 32 | 33 | public static final String WEIGHT = "effect_weight"; 34 | 35 | public VariantFile(String filename) throws Exception { 36 | 37 | this.filename = filename; 38 | variants = new HashMap>(); 39 | 40 | if (!new File(filename).exists()) { 41 | throw new Exception("File '" + filename + "' not found."); 42 | } 43 | 44 | ITableReader reader = new CsvTableReader(filename, SEPARATOR); 45 | checkFileFormat(reader, filename); 46 | reader.close(); 47 | } 48 | 49 | private void checkFileFormat(ITableReader reader, String filename) throws Exception { 50 | if (!reader.hasColumn(SCORE)) { 51 | throw new Exception("Column '" + SCORE + "' not found in '" + filename + "'"); 52 | } 53 | if (!reader.hasColumn(CHROMOSOME)) { 54 | throw new Exception("Column '" + CHROMOSOME + "' not found in '" + filename + "'"); 55 | } 56 | if (!reader.hasColumn(POSITION)) { 57 | throw new Exception("Column '" + POSITION + "' not found in '" + filename + "'"); 58 | } 59 | if (!reader.hasColumn(INCLUDE)) { 60 | throw new Exception("Column '" + INCLUDE + "' not found in '" + filename + "'"); 61 | } 62 | } 63 | 64 | public void buildIndex(String chromosome) throws IOException { 65 | ITableReader reader = new CsvTableReader(filename, SEPARATOR); 66 | while (reader.next()) { 67 | String chromsomeVariant = reader.getString(CHROMOSOME); 68 | if (chromsomeVariant.equals(chromosome)) { 69 | int include = reader.getInteger(INCLUDE); 70 | if (include == 1) { 71 | String score = reader.getString(SCORE); 72 | int position = reader.getInteger(POSITION); 73 | Set variantsScore = variants.get(score); 74 | if (variantsScore == null) { 75 | variantsScore = new HashSet(); 76 | variants.put(score, variantsScore); 77 | } 78 | variantsScore.add(position); 79 | } 80 | } 81 | totalVariants++; 82 | } 83 | reader.close(); 84 | } 85 | 86 | public boolean contains(String score, int position) { 87 | Set variantsScore = variants.get(score); 88 | if (variantsScore != null) { 89 | return variantsScore.contains(position); 90 | } else { 91 | return false; 92 | } 93 | 94 | } 95 | 96 | public int getCacheSize() { 97 | return variants.size(); 98 | } 99 | 100 | public int getTotalVariants() { 101 | return totalVariants; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/csv/CsvWithHeaderTableReader.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.csv; 2 | 3 | import java.io.DataInputStream; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.util.List; 8 | import java.util.Vector; 9 | 10 | import genepi.io.FileUtil; 11 | import genepi.io.table.reader.CsvTableReader; 12 | import genepi.io.text.LineReader; 13 | 14 | public class CsvWithHeaderTableReader extends CsvTableReader { 15 | 16 | private List headerLines = new Vector(); 17 | 18 | public CsvWithHeaderTableReader(String filename, char seperator) throws IOException { 19 | super(filename, seperator); 20 | LineReader reader = new LineReader(openTxtOrGzipStream(filename)); 21 | while(reader.next()) { 22 | if (reader.get().startsWith("#")) { 23 | headerLines.add(reader.get()); 24 | } else{ 25 | break; 26 | } 27 | } 28 | reader.close(); 29 | } 30 | 31 | public List getHeader() { 32 | return headerLines; 33 | } 34 | 35 | 36 | private static DataInputStream openTxtOrGzipStream(String filename) throws IOException { 37 | FileInputStream inputStream = new FileInputStream(filename); 38 | InputStream in2 = FileUtil.decompressStream(inputStream); 39 | return new DataInputStream(in2); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/csv/CsvWithHeaderTableWriter.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.csv; 2 | 3 | import java.io.FileWriter; 4 | import java.io.IOException; 5 | import java.io.OutputStreamWriter; 6 | import java.io.Writer; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | import au.com.bytecode.opencsv.CSVWriter; 12 | import genepi.io.table.writer.AbstractTableWriter; 13 | import genepi.io.text.LineWriter; 14 | import genepi.riskscore.App; 15 | 16 | public class CsvWithHeaderTableWriter extends AbstractTableWriter { 17 | 18 | private CSVWriter writer; 19 | public String[] currentLine; 20 | private Map columns2Index = new HashMap(); 21 | 22 | public CsvWithHeaderTableWriter(String filename, char separator, List header) { 23 | try { 24 | LineWriter lineWriter = new LineWriter(filename); 25 | for (String line : header) { 26 | lineWriter.write(line.replace("\n", "").replace("\r", "")); 27 | } 28 | if (!header.isEmpty()) { 29 | lineWriter.write("# Updated by " + App.APP + " " + App.VERSION + "\n"); 30 | } 31 | lineWriter.close(); 32 | writer = new CSVWriter(new FileWriter(filename, true), separator, CSVWriter.NO_QUOTE_CHARACTER, 33 | CSVWriter.NO_ESCAPE_CHARACTER); 34 | } catch (IOException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | public CsvWithHeaderTableWriter( char separator, List header) { 40 | for (String line : header) { 41 | System.out.println(line.replace("\n", "").replace("\r", "")); 42 | } 43 | if (!header.isEmpty()) { 44 | System.out.println("# Updated by " + App.APP + " " + App.VERSION + "\n"); 45 | } 46 | writer = new CSVWriter(new OutputStreamWriter(System.out), separator, CSVWriter.NO_QUOTE_CHARACTER, 47 | CSVWriter.NO_ESCAPE_CHARACTER); 48 | } 49 | 50 | public CsvWithHeaderTableWriter(Writer stream, char separator, List header) throws IOException { 51 | for (String line : header) { 52 | stream.write(line.replace("\n", "").replace("\r", "")); 53 | stream.write(System.lineSeparator()); 54 | } 55 | stream.write("# Created by " + App.APP + " " + App.VERSION); 56 | stream.write(System.lineSeparator()); 57 | writer = new CSVWriter(stream, separator, CSVWriter.NO_QUOTE_CHARACTER, 58 | CSVWriter.NO_ESCAPE_CHARACTER); 59 | } 60 | 61 | @Override 62 | public void close() { 63 | try { 64 | writer.close(); 65 | } catch (IOException e) { 66 | e.printStackTrace(); 67 | } 68 | } 69 | 70 | @Override 71 | public int getColumnIndex(String column) { 72 | return columns2Index.get(column); 73 | } 74 | 75 | @Override 76 | public boolean next() { 77 | writer.writeNext(currentLine); 78 | for (int i = 0; i < currentLine.length; i++) { 79 | currentLine[i] = ""; 80 | } 81 | return true; 82 | } 83 | 84 | @Override 85 | public void setColumns(String[] columns) { 86 | currentLine = new String[columns.length]; 87 | for (int i = 0; i < columns.length; i++) { 88 | columns2Index.put(columns[i], i); 89 | currentLine[i] = ""; 90 | } 91 | writer.writeNext(columns); 92 | } 93 | 94 | @Override 95 | public void setDouble(int column, double value) { 96 | currentLine[column] = value + ""; 97 | } 98 | 99 | @Override 100 | public void setInteger(int column, int value) { 101 | currentLine[column] = value + ""; 102 | } 103 | 104 | @Override 105 | public void setString(int column, String value) { 106 | currentLine[column] = value; 107 | } 108 | 109 | @Override 110 | public void setRow(String[] row) { 111 | currentLine = row; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/csv/TabixTableReader.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.csv; 2 | 3 | import genepi.io.FileUtil; 4 | import genepi.io.table.reader.AbstractTableReader; 5 | import genepi.io.table.reader.CsvTableReader; 6 | import genepi.io.text.LineReader; 7 | import genepi.riskscore.io.dbsnp.DbSnpReader; 8 | import htsjdk.tribble.readers.TabixReader; 9 | 10 | import java.io.DataInputStream; 11 | import java.io.FileInputStream; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | import java.util.Vector; 18 | 19 | public class TabixTableReader extends AbstractTableReader { 20 | 21 | private List headerLines = new Vector(); 22 | 23 | private String[] columns = null; 24 | 25 | private Map index = new HashMap(); 26 | 27 | private String[] row = null; 28 | 29 | private TabixReader tabixReader; 30 | 31 | private TabixReader.Iterator iterator; 32 | 33 | private int lineNumber = 0; 34 | 35 | public TabixTableReader(String filename, String chromosome) throws IOException { 36 | this(filename, chromosome, 0, Integer.MAX_VALUE); 37 | } 38 | 39 | 40 | public TabixTableReader(String filename, String chromosome, int start, int end) throws IOException { 41 | LineReader reader = new LineReader(openTxtOrGzipStream(filename)); 42 | while(reader.next()) { 43 | if (reader.get().startsWith("#")) { 44 | headerLines.add(reader.get()); 45 | } else{ 46 | columns = reader.get().split("\t"); 47 | for (int i = 0 ; i < columns.length; i++){ 48 | index.put(columns[i], i); 49 | } 50 | break; 51 | } 52 | } 53 | reader.close(); 54 | 55 | tabixReader = new TabixReader(filename); 56 | iterator = tabixReader.query(chromosome, start, end); 57 | } 58 | 59 | public List getHeader() { 60 | return headerLines; 61 | } 62 | 63 | @Override 64 | public String[] getColumns() { 65 | return columns; 66 | } 67 | 68 | @Override 69 | public boolean next() { 70 | String line = null; 71 | try { 72 | line = iterator.next(); 73 | } catch (IOException e) { 74 | throw new RuntimeException(e); 75 | } 76 | if (line == null) { 77 | row = null; 78 | return false; 79 | } 80 | row = line.split("\t", -1); 81 | lineNumber++; 82 | if (row.length != columns.length){ 83 | throw new RuntimeException("Different number of columns in line " + lineNumber + ": " + line); 84 | } 85 | return true; 86 | } 87 | 88 | @Override 89 | public int getColumnIndex(String column) { 90 | return index.get(column); 91 | } 92 | 93 | @Override 94 | public String[] getRow() { 95 | return row; 96 | } 97 | 98 | @Override 99 | public void close() { 100 | tabixReader.close(); 101 | } 102 | 103 | @Override 104 | public boolean hasColumn(String column) { 105 | return index.containsKey(column); 106 | } 107 | 108 | private static DataInputStream openTxtOrGzipStream(String filename) throws IOException { 109 | FileInputStream inputStream = new FileInputStream(filename); 110 | InputStream in2 = FileUtil.decompressStream(inputStream); 111 | return new DataInputStream(in2); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/dbsnp/DbSnpReader.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.dbsnp; 2 | 3 | import java.io.IOException; 4 | 5 | import genepi.io.text.LineReader; 6 | import htsjdk.tribble.readers.TabixReader; 7 | import htsjdk.tribble.readers.TabixReader.Iterator; 8 | 9 | public class DbSnpReader { 10 | 11 | private TabixReader reader; 12 | 13 | private int size = 3; 14 | 15 | public DbSnpReader(String input) throws IOException { 16 | 17 | // read header 18 | LineReader headerReader = new LineReader(input); 19 | while (headerReader.next()) { 20 | String line = headerReader.get(); 21 | if (!line.startsWith("#")) { 22 | break; 23 | } 24 | String[] tiles = line.split("="); 25 | if (tiles.length == 2) { 26 | String key = tiles[0]; 27 | String value = tiles[1]; 28 | if (key.equalsIgnoreCase("#size")) { 29 | size = Integer.parseInt(value); 30 | } 31 | } 32 | } 33 | headerReader.close(); 34 | 35 | reader = new TabixReader(input); 36 | 37 | } 38 | 39 | public Snp getByRsId(String rs) throws IOException { 40 | 41 | Iterator result = reader.query(DbSnpReader.getContig(rs, size), DbSnpReader.getPosition(rs, size) - 1, 42 | DbSnpReader.getPosition(rs, size)); 43 | 44 | String line = result.next(); 45 | 46 | if (line != null) { 47 | String[] tiles = line.split("\t"); 48 | if (tiles.length == 6) { 49 | Snp snp = new Snp(); 50 | snp.setChromosome(tiles[2]); 51 | snp.setPosition(Integer.parseInt(tiles[3])); 52 | snp.setReference(tiles[4].replaceAll("\\*", "")); 53 | snp.setAlternate(tiles[5]); 54 | return snp; 55 | } else { 56 | throw new IOException("Index has not 6 columns."); 57 | } 58 | 59 | } else { 60 | return null; 61 | } 62 | } 63 | 64 | public class Snp { 65 | 66 | private String chromosome; 67 | 68 | private long position; 69 | 70 | private String reference; 71 | 72 | private String alternate; 73 | 74 | public String getChromosome() { 75 | return chromosome; 76 | } 77 | 78 | public void setChromosome(String chromosome) { 79 | this.chromosome = chromosome; 80 | } 81 | 82 | public long getPosition() { 83 | return position; 84 | } 85 | 86 | public void setPosition(long position) { 87 | this.position = position; 88 | } 89 | 90 | public void setReference(String reference) { 91 | this.reference = reference; 92 | } 93 | 94 | public String getReference() { 95 | return reference; 96 | } 97 | 98 | public void setAlternate(String alternate) { 99 | this.alternate = alternate; 100 | } 101 | 102 | public String getAlternate() { 103 | return alternate; 104 | } 105 | 106 | @Override 107 | public String toString() { 108 | return chromosome + ":" + position + ":" + reference; 109 | } 110 | 111 | } 112 | 113 | public void close() { 114 | reader.close(); 115 | } 116 | 117 | public static String getContig(String rsID, int size) { 118 | if (rsID.length() > 10) { 119 | // count zeros --> rs1, rs10, ... 120 | String position = rsID.substring(size); 121 | int count = countCharacter(position, '0'); 122 | return rsID.substring(0, size) + sequence('0', count); 123 | } else { 124 | String position = rsID.substring(2); 125 | int count = countCharacter(position, '0'); 126 | return "rs" + sequence('0', count); 127 | } 128 | } 129 | 130 | public static int getPosition(String rsID, int size) { 131 | if (rsID.length() > 10) { 132 | return Integer.parseInt(rsID.substring(size)); 133 | } else { 134 | return Integer.parseInt(rsID.substring(2)); 135 | } 136 | } 137 | 138 | public static int countCharacter(String string, char character) { 139 | int count = 0; 140 | for (int i = 0; i < string.length(); i++) { 141 | if (string.charAt(i) != character) { 142 | break; 143 | } 144 | count++; 145 | } 146 | return count; 147 | } 148 | 149 | public static String sequence(char character, int count) { 150 | String result = ""; 151 | for (int i = 0; i < count; i++) { 152 | result += character; 153 | } 154 | return result; 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/formats/PGSCatalogFormat.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.formats; 2 | 3 | import java.io.DataInputStream; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | 8 | import genepi.io.FileUtil; 9 | import genepi.io.table.reader.CsvTableReader; 10 | import genepi.io.table.reader.ITableReader; 11 | 12 | public class PGSCatalogFormat extends RiskScoreFormatImpl { 13 | 14 | public int VERSION_1 = 1; 15 | 16 | public int VERSION_2 = 2; 17 | 18 | private int version = VERSION_1; 19 | 20 | private PGSCatalogVariantsFormat format; 21 | 22 | public PGSCatalogFormat(String filename, boolean forecRsIds) throws IOException { 23 | this.format = detectVersionAndFormat(filename, forecRsIds); 24 | // format unknown or rsIds --> let try version two --> maybe we find coordinates 25 | if (format == PGSCatalogVariantsFormat.UNKNOWN || format == PGSCatalogVariantsFormat.RS_ID) { 26 | this.version = VERSION_2; 27 | this.format = detectVersionAndFormat(filename, forecRsIds); 28 | } 29 | } 30 | 31 | @Override 32 | public String getChromosome() { 33 | return "chr_name"; 34 | } 35 | 36 | @Override 37 | public String getPosition() { 38 | return "chr_position"; 39 | } 40 | 41 | @Override 42 | public String getEffectAllele() { 43 | return "effect_allele"; 44 | } 45 | 46 | @Override 47 | public String getEffectWeight() { 48 | return "effect_weight"; 49 | } 50 | 51 | @Override 52 | public String getOtherAllele() { 53 | if (version == VERSION_2) { 54 | return "other_allele"; 55 | } else { 56 | return "reference_allele"; 57 | } 58 | } 59 | 60 | protected PGSCatalogVariantsFormat detectVersionAndFormat(String filename, boolean forceRsId) throws IOException { 61 | DataInputStream in = openTxtOrGzipStream(filename); 62 | ITableReader reader = new CsvTableReader(in, getSeparator()); 63 | PGSCatalogVariantsFormat format = detectVersionAndFormat(reader, forceRsId); 64 | reader.close(); 65 | return format; 66 | } 67 | 68 | private PGSCatalogVariantsFormat detectVersionAndFormat(ITableReader reader, boolean forceRsId) { 69 | if (!reader.hasColumn("rsID")) { 70 | 71 | if (!reader.hasColumn(getChromosome())) { 72 | return PGSCatalogVariantsFormat.UNKNOWN; 73 | } 74 | if (!reader.hasColumn(getPosition())) { 75 | return PGSCatalogVariantsFormat.UNKNOWN; 76 | } 77 | 78 | if (!reader.hasColumn(getOtherAllele())) { 79 | return PGSCatalogVariantsFormat.UNKNOWN; 80 | } 81 | return PGSCatalogVariantsFormat.COORDINATES; 82 | } 83 | 84 | if (!reader.hasColumn(getEffectWeight())) { 85 | return PGSCatalogVariantsFormat.UNKNOWN; 86 | } 87 | if (!reader.hasColumn(getEffectAllele())) { 88 | return PGSCatalogVariantsFormat.UNKNOWN; 89 | } 90 | 91 | if (!forceRsId && reader.hasColumn(getChromosome()) && reader.hasColumn(getPosition()) 92 | && reader.hasColumn(getOtherAllele())) { 93 | return PGSCatalogVariantsFormat.COORDINATES; 94 | } 95 | 96 | // check if all rsIds are nor empty 97 | boolean empty = false; 98 | while (!empty && reader.next()) { 99 | empty = !reader.getString("rsID").startsWith("rs"); 100 | } 101 | reader.close(); 102 | 103 | //if one rsId is empty check if positions are available 104 | if (empty && reader.hasColumn(getChromosome()) && reader.hasColumn(getPosition()) 105 | && reader.hasColumn(getOtherAllele())) { 106 | return PGSCatalogVariantsFormat.COORDINATES; 107 | } 108 | 109 | return PGSCatalogVariantsFormat.RS_ID; 110 | 111 | } 112 | 113 | public PGSCatalogVariantsFormat getFormat() { 114 | return format; 115 | } 116 | 117 | public String toString() { 118 | return "PGS-Catalog v" + version + " (" + format + ")"; 119 | } 120 | 121 | private static DataInputStream openTxtOrGzipStream(String filename) throws IOException { 122 | FileInputStream inputStream = new FileInputStream(filename); 123 | InputStream in2 = FileUtil.decompressStream(inputStream); 124 | return new DataInputStream(in2); 125 | } 126 | 127 | @Override 128 | public boolean hasRsIds() { 129 | return format == PGSCatalogVariantsFormat.RS_ID; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/formats/PGSCatalogHarmonizedFormat.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.formats; 2 | 3 | import genepi.io.FileUtil; 4 | import genepi.io.table.reader.CsvTableReader; 5 | import genepi.io.table.reader.ITableReader; 6 | 7 | import java.io.DataInputStream; 8 | import java.io.FileInputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | 12 | public class PGSCatalogHarmonizedFormat extends RiskScoreFormatImpl { 13 | 14 | @Override 15 | public String getChromosome() { 16 | return "hm_chr"; 17 | } 18 | 19 | @Override 20 | public String getPosition() { 21 | return "hm_pos"; 22 | } 23 | 24 | @Override 25 | public String getEffectAllele() { 26 | return "effect_allele"; 27 | } 28 | 29 | @Override 30 | public String getEffectWeight() { 31 | return "effect_weight"; 32 | } 33 | 34 | @Override 35 | public String getOtherAllele() { 36 | return "other_allele"; 37 | } 38 | 39 | @Override 40 | public boolean hasRsIds() { 41 | return false; 42 | } 43 | 44 | public String toString() { 45 | return "PGS Catalog Harmonized format"; 46 | } 47 | 48 | protected static boolean acceptFile(String filename) throws IOException { 49 | DataInputStream in = openTxtOrGzipStream(filename); 50 | ITableReader reader = new CsvTableReader(in, '\t'); 51 | reader.close(); 52 | return reader.hasColumn("hm_chr"); 53 | } 54 | 55 | private static DataInputStream openTxtOrGzipStream(String filename) throws IOException { 56 | FileInputStream inputStream = new FileInputStream(filename); 57 | InputStream in2 = FileUtil.decompressStream(inputStream); 58 | return new DataInputStream(in2); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/formats/PGSCatalogVariantsFormat.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.formats; 2 | 3 | public enum PGSCatalogVariantsFormat { 4 | 5 | COORDINATES, RS_ID, UNKNOWN 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/formats/PRSwebFormat.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.formats; 2 | 3 | public class PRSwebFormat extends RiskScoreFormatImpl { 4 | 5 | @Override 6 | public String getChromosome() { 7 | return "CHROM"; 8 | } 9 | 10 | @Override 11 | public String getPosition() { 12 | return "POS"; 13 | } 14 | 15 | @Override 16 | public String getEffectAllele() { 17 | return "EA"; 18 | } 19 | 20 | @Override 21 | public String getEffectWeight() { 22 | return "WEIGHT"; 23 | } 24 | 25 | @Override 26 | public String getOtherAllele() { 27 | return "OA"; 28 | } 29 | 30 | @Override 31 | public boolean hasRsIds() { 32 | return false; 33 | } 34 | 35 | public String toString() { 36 | return "PRSweb format"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/formats/RiskScoreFormatFactory.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.formats; 2 | 3 | import java.io.DataInputStream; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | 8 | import genepi.io.FileUtil; 9 | import genepi.io.table.reader.CsvTableReader; 10 | import genepi.io.table.reader.ITableReader; 11 | 12 | public class RiskScoreFormatFactory { 13 | 14 | public enum RiskScoreFormat { 15 | DEFAULT, AUTO_DETECT, MAPPING_FILE 16 | } 17 | 18 | public static RiskScoreFormatImpl buildFormat(String filename, RiskScoreFormat format) throws IOException { 19 | switch (format) { 20 | case AUTO_DETECT: 21 | 22 | if (PGSCatalogHarmonizedFormat.acceptFile(filename)){ 23 | return new PGSCatalogHarmonizedFormat(); 24 | } 25 | 26 | String headerLine = readHeader(filename); 27 | if (headerLine.startsWith("## PRSweb")) { 28 | return new PRSwebFormat(); 29 | } else { 30 | // PGSCatalog as default 31 | return new PGSCatalogFormat(filename, false); 32 | } 33 | 34 | case DEFAULT: 35 | return new RiskScoreFormatImpl(); 36 | case MAPPING_FILE: 37 | return RiskScoreFormatImpl.load(filename + ".format"); 38 | default: 39 | return new RiskScoreFormatImpl(); 40 | } 41 | } 42 | 43 | 44 | public static String readHeader(String filename) throws IOException { 45 | DataInputStream in = openTxtOrGzipStream(filename); 46 | String line = in.readLine(); 47 | in.close(); 48 | return line; 49 | } 50 | 51 | private static DataInputStream openTxtOrGzipStream(String filename) throws IOException { 52 | FileInputStream inputStream = new FileInputStream(filename); 53 | InputStream in2 = FileUtil.decompressStream(inputStream); 54 | return new DataInputStream(in2); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/formats/RiskScoreFormatImpl.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.formats; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.FileReader; 5 | 6 | import com.google.gson.Gson; 7 | import com.google.gson.JsonIOException; 8 | import com.google.gson.JsonSyntaxException; 9 | 10 | public class RiskScoreFormatImpl { 11 | 12 | private static final char SEPARATOR = '\t'; 13 | 14 | private static final String CHROMOSOME = "chr"; 15 | 16 | private static final String POSITION = "position_hg19"; 17 | 18 | private static final String EFFECT_WEIGHT = "effect_weight"; 19 | 20 | private static final String OTHER_ALLELE = "A2"; 21 | 22 | private static final String EFFECT_ALLELE = "effect_allele"; 23 | 24 | private String chromosome = CHROMOSOME; 25 | 26 | private String position = POSITION; 27 | 28 | private String effect_weight = EFFECT_WEIGHT; 29 | 30 | private String otherAllele = OTHER_ALLELE; 31 | 32 | private String effectAllele = EFFECT_ALLELE; 33 | 34 | private char separator = SEPARATOR; 35 | 36 | public String getChromosome() { 37 | return chromosome; 38 | } 39 | 40 | public void setChromosome(String chromosome) { 41 | this.chromosome = chromosome; 42 | } 43 | 44 | public String getPosition() { 45 | return position; 46 | } 47 | 48 | public void setPosition(String position) { 49 | this.position = position; 50 | } 51 | 52 | public String getEffectWeight() { 53 | return effect_weight; 54 | } 55 | 56 | public void setEffectWeight(String effect_weight) { 57 | this.effect_weight = effect_weight; 58 | } 59 | 60 | public void setOtherAllele(String otherAllele) { 61 | this.otherAllele = otherAllele; 62 | } 63 | 64 | public String getOtherAllele() { 65 | return otherAllele; 66 | } 67 | 68 | public void setEffectAllele(String effectAllele) { 69 | this.effectAllele = effectAllele; 70 | } 71 | 72 | public String getEffectAllele() { 73 | return effectAllele; 74 | } 75 | 76 | public void setSeparator(char separator) { 77 | this.separator = separator; 78 | } 79 | 80 | public char getSeparator() { 81 | return separator; 82 | } 83 | 84 | public static RiskScoreFormatImpl load(String filename) 85 | throws JsonSyntaxException, JsonIOException, FileNotFoundException { 86 | 87 | Gson gson = new Gson(); 88 | RiskScoreFormatImpl format = gson.fromJson(new FileReader(filename), RiskScoreFormatImpl.class); 89 | return format; 90 | } 91 | 92 | public boolean hasRsIds() { 93 | return false; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/meta/JsonMetaFileReader.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.meta; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.FileReader; 5 | import java.lang.reflect.Type; 6 | import java.util.Map; 7 | 8 | import com.google.gson.Gson; 9 | import com.google.gson.JsonIOException; 10 | import com.google.gson.JsonSyntaxException; 11 | import com.google.gson.reflect.TypeToken; 12 | 13 | import genepi.riskscore.io.MetaFile; 14 | import genepi.riskscore.io.MetaFile.MetaScore; 15 | 16 | public class JsonMetaFileReader { 17 | 18 | private JsonMetaFileReader() { 19 | 20 | } 21 | 22 | public static MetaFile load(String filename) throws JsonIOException, JsonSyntaxException, FileNotFoundException { 23 | 24 | Gson gson = new Gson(); 25 | Type type = new TypeToken>() { 26 | }.getType(); 27 | 28 | Map index = gson.fromJson(new FileReader(filename), type); 29 | MetaFile metaFile = new MetaFile(index); 30 | return metaFile; 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/meta/PGSCatalogCategoryFile.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.meta; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonIOException; 5 | import com.google.gson.JsonSyntaxException; 6 | import com.google.gson.reflect.TypeToken; 7 | import genepi.io.text.LineWriter; 8 | import genepi.riskscore.io.MetaFile.MetaScore; 9 | import genepi.riskscore.model.ScorePopulationMap; 10 | 11 | import java.io.FileNotFoundException; 12 | import java.io.FileReader; 13 | import java.io.IOException; 14 | import java.lang.reflect.Type; 15 | import java.util.*; 16 | 17 | public class PGSCatalogCategoryFile { 18 | 19 | protected Map> traits; 20 | 21 | protected String next; 22 | 23 | private PGSCatalogCategoryFile() { 24 | 25 | } 26 | 27 | public static PGSCatalogCategoryFile load(String filename) 28 | throws JsonIOException, JsonSyntaxException, FileNotFoundException { 29 | PGSCatalogCategoryFile file = new PGSCatalogCategoryFile(); 30 | // file.data 31 | Gson gson = new Gson(); 32 | Type type = new TypeToken>() { 33 | }.getType(); 34 | Object data = gson.fromJson(new FileReader(filename), Object.class); 35 | 36 | Object results = ((AbstractMap) data).get("results"); 37 | if (((AbstractMap) data).get("next") != null) { 38 | file.next = ((AbstractMap) data).get("next").toString(); 39 | } else { 40 | file.next = null; 41 | } 42 | List list = (List) results; 43 | 44 | file.traits = new HashMap>(); 45 | for (Object score : list) { 46 | Category category = parsePGSCatalog((AbstractMap) score); 47 | System.out.println("Process " + category.getLabel()); 48 | for (String trait: category.getTraits()){ 49 | List categories = file.traits.get(trait); 50 | if (categories == null){ 51 | categories = new Vector(); 52 | file.traits.put(trait, categories); 53 | } 54 | if (!categories.contains(category.label)) { 55 | categories.add(category.label); 56 | } 57 | } 58 | } 59 | System.out.println("Loaded categories for " + file.traits.size() + " traits."); 60 | return file; 61 | } 62 | 63 | public void merge(PGSCatalogCategoryFile metaFile) { 64 | traits.putAll(metaFile.traits); 65 | } 66 | 67 | public List getCategories(String trait){ 68 | return traits.get(trait); 69 | } 70 | 71 | public int getTraits() { 72 | return traits.size(); 73 | } 74 | 75 | public String getNext() { 76 | return next; 77 | } 78 | 79 | 80 | protected static Category parsePGSCatalog(AbstractMap data) { 81 | Category category = new Category(); 82 | String label = data.get("label").toString(); 83 | category.setLabel(label); 84 | 85 | Object efos = data.get("efotraits"); 86 | if (efos != null) { 87 | List> efoTraits = (List>) efos; 88 | for (Map efo: efoTraits){ 89 | category.addTrait(efo.get("id")); 90 | } 91 | } 92 | 93 | return category; 94 | } 95 | 96 | 97 | public static class Category { 98 | 99 | public String label; 100 | 101 | private List traits = new Vector(); 102 | 103 | public String getLabel() { 104 | return label; 105 | } 106 | 107 | public void setLabel(String label) { 108 | this.label = label; 109 | } 110 | 111 | public void addTrait(String trait){ 112 | traits.add(trait); 113 | } 114 | 115 | public List getTraits() { 116 | return traits; 117 | } 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/meta/PGSCatalogMetaFile.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.meta; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.FileReader; 5 | import java.io.IOException; 6 | import java.lang.reflect.Type; 7 | import java.util.AbstractMap; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | import com.google.gson.Gson; 13 | import com.google.gson.JsonIOException; 14 | import com.google.gson.JsonSyntaxException; 15 | import com.google.gson.reflect.TypeToken; 16 | 17 | import genepi.io.text.LineWriter; 18 | import genepi.riskscore.io.MetaFile.MetaScore; 19 | import genepi.riskscore.model.ScorePopulationMap; 20 | 21 | public class PGSCatalogMetaFile { 22 | 23 | protected Map index; 24 | 25 | protected String next; 26 | 27 | private PGSCatalogMetaFile() { 28 | 29 | } 30 | 31 | public static PGSCatalogMetaFile load(String filename, PGSCatalogCategoryFile categoryFile) 32 | throws JsonIOException, JsonSyntaxException, FileNotFoundException { 33 | PGSCatalogMetaFile file = new PGSCatalogMetaFile(); 34 | // file.data 35 | Gson gson = new Gson(); 36 | Type type = new TypeToken>() { 37 | }.getType(); 38 | Object data = gson.fromJson(new FileReader(filename), Object.class); 39 | 40 | Object results = ((AbstractMap) data).get("results"); 41 | if (((AbstractMap) data).get("next") != null) { 42 | file.next = ((AbstractMap) data).get("next").toString(); 43 | } else { 44 | file.next = null; 45 | } 46 | List list = (List) results; 47 | 48 | file.index = new HashMap(); 49 | for (Object score : list) { 50 | MetaScore metaScore = parsePGSCatalog((AbstractMap) score); 51 | for (Map efo: metaScore.getEfo()){ 52 | String id = efo.get("id"); 53 | List categories = categoryFile.getCategories(id); 54 | for (String category: categories){ 55 | metaScore.addCategory(category); 56 | } 57 | } 58 | file.index.put(metaScore.getId(), metaScore); 59 | } 60 | return file; 61 | } 62 | 63 | public void merge(PGSCatalogMetaFile metaFile) { 64 | index.putAll(metaFile.index); 65 | } 66 | 67 | public int getScores() { 68 | return index.size(); 69 | } 70 | 71 | public String getNext() { 72 | return next; 73 | } 74 | 75 | public void save(String filename) throws IOException { 76 | Gson gson = new Gson(); 77 | Type type = new TypeToken>() { 78 | }.getType(); 79 | String json = gson.toJson(index); 80 | LineWriter writer = new LineWriter(filename); 81 | writer.write(json); 82 | writer.close(); 83 | 84 | } 85 | 86 | protected static MetaScore parsePGSCatalog(AbstractMap data) { 87 | MetaScore score = new MetaScore(); 88 | String id = data.get("id").toString(); 89 | String trait = data.get("trait_reported").toString(); 90 | score.setId(id); 91 | score.setTrait(trait); 92 | 93 | Object ancestry_distribution = data.get("ancestry_distribution"); 94 | if (ancestry_distribution != null) { 95 | Object gwas = ((Map) ancestry_distribution).get("gwas"); 96 | if (gwas != null) { 97 | Object samplesVariants = ((Map) gwas).get("dist"); 98 | 99 | if (samplesVariants != null) { 100 | ScorePopulationMap populationMap = new ScorePopulationMap(); 101 | Map items = (Map) samplesVariants; 102 | for (String key : items.keySet()) { 103 | populationMap.addSamples(key, items.get(key).floatValue() / 100.0f); 104 | } 105 | score.setPopulations(populationMap); 106 | Double samples = (Double) ((Map) gwas).get("count"); 107 | populationMap.total = samples.intValue(); 108 | score.setSamples(samples.intValue()); 109 | } 110 | 111 | } 112 | } 113 | 114 | Object publication = data.get("publication"); 115 | if (publication != null) { 116 | Map publicationMap = (Map) publication; 117 | Map map = new HashMap(); 118 | map.put("doi", publicationMap.get("doi")); 119 | map.put("firstauthor", publicationMap.get("firstauthor")); 120 | map.put("journal", publicationMap.get("journal")); 121 | map.put("date", publicationMap.get("date_publication")); 122 | score.setPublication(map); 123 | } 124 | 125 | Object efos = data.get("trait_efo"); 126 | if (efos != null) { 127 | score.setEfo((List>) efos); 128 | } 129 | 130 | score.setVariants(((Double) data.get("variants_number")).intValue()); 131 | score.setRepository("PGS-Catalog"); 132 | score.setLink("https://www.pgscatalog.org/score/" + id); 133 | 134 | return score; 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/meta/TabMetaFileReader.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.meta; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import com.google.gson.JsonIOException; 8 | import com.google.gson.JsonSyntaxException; 9 | 10 | import genepi.io.table.reader.CsvTableReader; 11 | import genepi.riskscore.io.MetaFile; 12 | import genepi.riskscore.io.MetaFile.MetaScore; 13 | import genepi.riskscore.model.ScorePopulationMap; 14 | 15 | public class TabMetaFileReader { 16 | 17 | public static String COLUMN_ID = "id"; 18 | 19 | public static String COLUMN_TRAIT = "trait"; 20 | 21 | public static String COLUMN_TRAIT_EFO = "trait_efo"; 22 | 23 | public static String COLUMN_ANCESTRY_DISTRIBUTION = "ancestry_distribution"; 24 | 25 | public static String COLUMN_VARIANTS = "variants"; 26 | 27 | public static String COLUMN_SAMPLES = "samples"; 28 | 29 | public static String COLUMN_LINK = "url.details"; 30 | 31 | public static String COLUMN_REPOSITORY = "repository"; 32 | 33 | public static String COLUMN_PUBLICATION_DOI = "publication.doi"; 34 | 35 | public static String COLUMN_PUBLICATION_FIRSTAUTHOR = "publication.firstauthor"; 36 | 37 | public static String COLUMN_PUBLICATION_JOURNAL = "publication.journal"; 38 | 39 | public static String COLUMN_PUBLICATION_DATE = "publication.date"; 40 | 41 | private TabMetaFileReader() { 42 | 43 | } 44 | 45 | public static MetaFile load(String filename) throws JsonIOException, JsonSyntaxException, FileNotFoundException { 46 | 47 | Map index = new HashMap(); 48 | 49 | CsvTableReader reader = new CsvTableReader(filename, '\t'); 50 | while (reader.next()) { 51 | MetaScore score = parseCsvRecord(reader); 52 | index.put(score.getId(), score); 53 | } 54 | reader.close(); 55 | 56 | MetaFile metaFile = new MetaFile(index); 57 | return metaFile; 58 | 59 | } 60 | 61 | private static MetaScore parseCsvRecord(CsvTableReader reader) { 62 | 63 | MetaScore score = new MetaScore(); 64 | String id = reader.getString(COLUMN_ID); 65 | String trait = reader.getString(COLUMN_TRAIT); 66 | score.setId(id); 67 | score.setTrait(trait); 68 | if (!reader.getString(COLUMN_SAMPLES).trim().isEmpty()) { 69 | score.setSamples(reader.getInteger(COLUMN_SAMPLES)); 70 | } 71 | if (!reader.getString(COLUMN_VARIANTS).trim().isEmpty()) { 72 | score.setVariants(reader.getInteger(COLUMN_VARIANTS)); 73 | } 74 | score.setRepository(reader.getString(COLUMN_REPOSITORY)); 75 | score.setLink(reader.getString(COLUMN_LINK)); 76 | 77 | String ancestry_distribution = reader.getString(COLUMN_ANCESTRY_DISTRIBUTION); 78 | if (!ancestry_distribution.trim().isEmpty()) { 79 | 80 | ScorePopulationMap populationMap = new ScorePopulationMap(); 81 | String[] populations = ancestry_distribution.split(","); 82 | for (String population : populations) { 83 | String[] tiles = population.split("="); 84 | populationMap.addSamples(tiles[0], Float.parseFloat(tiles[1]) / 100.0f); 85 | } 86 | populationMap.total = score.getSamples(); 87 | score.setPopulations(populationMap); 88 | } 89 | 90 | String doi = reader.getString(COLUMN_PUBLICATION_DOI); 91 | if (!doi.trim().isEmpty()) { 92 | Map publication = new HashMap(); 93 | publication.put("doi", doi); 94 | publication.put("firstauthor", reader.getString(COLUMN_PUBLICATION_FIRSTAUTHOR)); 95 | publication.put("journal", reader.getString(COLUMN_PUBLICATION_JOURNAL)); 96 | publication.put("date", reader.getString(COLUMN_PUBLICATION_DATE)); 97 | score.setPublication(publication); 98 | } 99 | 100 | // Object efos = data.get("trait_efo"); 101 | // if (efos != null) { 102 | // score.setEfo((List>) efos); 103 | // } 104 | 105 | return score; 106 | 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/proxy/ProxyReader.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.proxy; 2 | 3 | import java.io.IOException; 4 | 5 | import htsjdk.tribble.readers.TabixReader; 6 | import htsjdk.tribble.readers.TabixReader.Iterator; 7 | 8 | public class ProxyReader { 9 | 10 | private TabixReader reader; 11 | 12 | public ProxyReader(String input) throws IOException { 13 | reader = new TabixReader(input); 14 | } 15 | 16 | public ProxySnp[] getByPosition(String chromosome, int position, String alleleA, String alleleB) 17 | throws IOException { 18 | 19 | Iterator result = reader.query(chromosome, position - 1, position); 20 | 21 | String line = result.next(); 22 | 23 | if (line != null) { 24 | String[] tiles = line.split("\t"); 25 | if (tiles.length >= 5) { 26 | String[] proxiesDetails = tiles[4].split(";"); 27 | if ((tiles[2].equals(alleleA) && tiles[3].equals(alleleB)) 28 | || (tiles[2].equals(alleleB) && tiles[3].equals(alleleA))) { 29 | ProxySnp[] proxies = new ProxySnp[proxiesDetails.length]; 30 | for (int i = 0; i < proxiesDetails.length; i++) { 31 | String proxyDetails = proxiesDetails[i]; 32 | String tiles2[] = proxyDetails.split(":"); 33 | proxies[i] = new ProxySnp(); 34 | proxies[i].setChromosome(tiles2[0]); 35 | proxies[i].setPosition(Integer.parseInt(tiles2[1])); 36 | proxies[i].setReference(tiles2[2]); 37 | proxies[i].setAlternate(tiles2[3]); 38 | proxies[i].setProxyReference(tiles[2]); 39 | proxies[i].setProxyAlternate(tiles[3]); 40 | } 41 | return proxies; 42 | } else { 43 | return new ProxySnp[0]; 44 | } 45 | } else { 46 | throw new IOException("Index has not 5 columns:\n" + line); 47 | } 48 | 49 | } else { 50 | return new ProxySnp[0]; 51 | } 52 | } 53 | 54 | public class ProxySnp { 55 | 56 | private String chromosome; 57 | 58 | private int position; 59 | 60 | private String reference; 61 | 62 | private String alternate; 63 | 64 | private String proxyReference; 65 | 66 | private String proxyAlternate; 67 | 68 | public String getChromosome() { 69 | return chromosome; 70 | } 71 | 72 | public void setChromosome(String chromosome) { 73 | this.chromosome = chromosome; 74 | } 75 | 76 | public int getPosition() { 77 | return position; 78 | } 79 | 80 | public void setPosition(int position) { 81 | this.position = position; 82 | } 83 | 84 | public void setReference(String reference) { 85 | this.reference = reference; 86 | } 87 | 88 | public String getReference() { 89 | return reference; 90 | } 91 | 92 | public void setAlternate(String alternate) { 93 | this.alternate = alternate; 94 | } 95 | 96 | public String getAlternate() { 97 | return alternate; 98 | } 99 | 100 | public void setProxyAlternate(String proxyAlternate) { 101 | this.proxyAlternate = proxyAlternate; 102 | } 103 | 104 | public void setProxyReference(String proxyReference) { 105 | this.proxyReference = proxyReference; 106 | } 107 | 108 | public String mapAllele(String allele) throws IOException { 109 | if (allele.equals(proxyReference)) { 110 | return reference; 111 | } 112 | if (allele.equals(proxyAlternate)) { 113 | return alternate; 114 | } 115 | throw new IOException("No mapping entry for allele '" + allele + "' (Supported alleles: " + proxyReference +" and " + proxyAlternate+")"); 116 | } 117 | 118 | @Override 119 | public String toString() { 120 | return chromosome + ":" + position + ":" + reference; 121 | } 122 | 123 | } 124 | 125 | public void close() { 126 | reader.close(); 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/scores/IRiskScoreCollection.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.scores; 2 | 3 | import java.util.Map.Entry; 4 | import java.util.Set; 5 | import java.util.SortedSet; 6 | 7 | import genepi.riskscore.io.Chunk; 8 | import genepi.riskscore.model.ReferenceVariant; 9 | import genepi.riskscore.model.RiskScoreSummary; 10 | 11 | public interface IRiskScoreCollection { 12 | 13 | public String getBuild(); 14 | 15 | public String getName(); 16 | 17 | public String getVersion(); 18 | 19 | public void buildIndex(String chromosome, Chunk chunk, String dbsnp, String proxies) throws Exception; 20 | 21 | public RiskScoreSummary getSummary(int index); 22 | 23 | public boolean contains(int position, String alleleA, String alleleB); 24 | 25 | public boolean contains(int index, int position, String alleleA, String alleleB); 26 | 27 | public Set> getAllVariants(int index); 28 | 29 | public ReferenceVariant getVariant(int index, int position, String alleleA, String alleleB); 30 | 31 | public int getSize(); 32 | 33 | public boolean isEmpty(); 34 | 35 | public RiskScoreSummary[] getSummaries(); 36 | 37 | public void clearIndex(); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/scores/RiskScoreCollection.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.scores; 2 | 3 | import java.io.File; 4 | import java.util.*; 5 | 6 | import genepi.riskscore.io.Chunk; 7 | import genepi.riskscore.io.RiskScoreFile; 8 | import genepi.riskscore.io.formats.RiskScoreFormatFactory.RiskScoreFormat; 9 | import genepi.riskscore.model.ReferenceVariant; 10 | import genepi.riskscore.model.RiskScoreSummary; 11 | 12 | public class RiskScoreCollection implements IRiskScoreCollection { 13 | 14 | private String build; 15 | 16 | private String name; 17 | 18 | private String version; 19 | 20 | private RiskScoreFile[] riskscores; 21 | 22 | private RiskScoreSummary[] summaries; 23 | 24 | private int numberRiskScores; 25 | 26 | private String[] filenames; 27 | 28 | private boolean verbose = false; 29 | 30 | private Map formats; 31 | 32 | public RiskScoreCollection(String[] filenames, Map formats) { 33 | this.filenames = filenames; 34 | this.formats = formats; 35 | } 36 | 37 | @Override 38 | public String getBuild() { 39 | return build; 40 | } 41 | 42 | @Override 43 | public String getName() { 44 | return name; 45 | } 46 | 47 | @Override 48 | public String getVersion() { 49 | return version; 50 | } 51 | 52 | @Override 53 | public void buildIndex(String chromosome, Chunk chunk, String dbsnp, String proxies) throws Exception { 54 | 55 | numberRiskScores = filenames.length; 56 | 57 | summaries = new RiskScoreSummary[numberRiskScores]; 58 | for (int i = 0; i < numberRiskScores; i++) { 59 | String name = RiskScoreFile.getName(filenames[i]); 60 | summaries[i] = new RiskScoreSummary(name); 61 | } 62 | 63 | int total = 0; 64 | 65 | riskscores = new RiskScoreFile[numberRiskScores]; 66 | for (int i = 0; i < numberRiskScores; i++) { 67 | 68 | if (verbose) { 69 | System.out.println("Loading file " + filenames[i] + "..."); 70 | } 71 | 72 | RiskScoreFormat format = formats.get(filenames[i]); 73 | RiskScoreFile riskscore = new RiskScoreFile(filenames[i], format, dbsnp, proxies); 74 | 75 | if (chunk != null) { 76 | riskscore.buildIndex(chromosome, chunk); 77 | } else { 78 | riskscore.buildIndex(chromosome); 79 | } 80 | 81 | summaries[i].setVariants(riskscore.getTotalVariants()); 82 | summaries[i].setVariantsIgnored(riskscore.getIgnoredVariants()); 83 | 84 | if (verbose) { 85 | System.out.println("Loaded " + riskscore.getLoadedVariants() + " weights for chromosome " + chromosome); 86 | } 87 | total += riskscore.getLoadedVariants(); 88 | riskscores[i] = riskscore; 89 | 90 | } 91 | 92 | if (verbose) { 93 | System.out.println(); 94 | System.out.println("Collection contains " + total + " weights for chromosome " + chromosome); 95 | System.out.println(); 96 | } 97 | } 98 | 99 | @Override 100 | public RiskScoreSummary getSummary(int index) { 101 | return summaries[index]; 102 | } 103 | 104 | @Override 105 | public boolean contains( int position, String alleleA, String alleleB) { 106 | return true; 107 | } 108 | 109 | @Override 110 | public boolean contains(int index, int position, String alleleA, String alleleB) { 111 | return riskscores[index].contains(position); 112 | } 113 | 114 | @Override 115 | public ReferenceVariant getVariant(int index, int position, String alleleA, String alleleB) { 116 | return riskscores[index].getVariant(position); 117 | } 118 | 119 | @Override 120 | public Set> getAllVariants(int index) { 121 | return riskscores[index].getVariants().entrySet(); 122 | } 123 | 124 | @Override 125 | public int getSize() { 126 | return numberRiskScores; 127 | } 128 | 129 | @Override 130 | public void clearIndex() { 131 | for (RiskScoreFile riskscore: riskscores) { 132 | riskscore.clearIndex(); 133 | } 134 | } 135 | 136 | @Override 137 | public boolean isEmpty() { 138 | for (RiskScoreFile riskscore : riskscores) { 139 | if (riskscore.getLoadedVariants() > 0) { 140 | return false; 141 | } 142 | } 143 | return true; 144 | } 145 | 146 | @Override 147 | public RiskScoreSummary[] getSummaries() { 148 | return summaries; 149 | } 150 | 151 | public void setVerbose(boolean verbose) { 152 | this.verbose = verbose; 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/vcf/FastVCFFileReader.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.vcf; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | import java.util.Iterator; 10 | import java.util.List; 11 | 12 | import genepi.io.FileUtil; 13 | import genepi.io.reader.IReader; 14 | import htsjdk.variant.vcf.VCFFileReader; 15 | import htsjdk.variant.vcf.VCFHeader; 16 | 17 | public class FastVCFFileReader implements IReader { 18 | 19 | private List samples; 20 | 21 | private int snpsCount = 0; 22 | 23 | private int samplesCount = 0; 24 | 25 | private MinimalVariantContext variantContext; 26 | 27 | private VCFLineParser parser; 28 | 29 | private String filename; 30 | 31 | protected BufferedReader in; 32 | 33 | private int lineNumber = 0; 34 | 35 | public FastVCFFileReader(InputStream inputStream, String vcfFilename) throws IOException { 36 | 37 | // load header 38 | VCFFileReader reader = new VCFFileReader(new File(vcfFilename), false); 39 | VCFHeader header = reader.getFileHeader(); 40 | samples = header.getGenotypeSamples(); 41 | samplesCount = samples.size(); 42 | variantContext = new MinimalVariantContext(samplesCount); 43 | reader.close(); 44 | 45 | filename = vcfFilename; 46 | InputStream in2 = FileUtil.decompressStream(inputStream); 47 | in = new BufferedReader(new InputStreamReader(in2)); 48 | 49 | parser = new VCFLineParser(samplesCount); 50 | 51 | } 52 | 53 | public FastVCFFileReader(String vcfFilename) throws IOException { 54 | this(new FileInputStream(vcfFilename), vcfFilename); 55 | } 56 | 57 | public List getGenotypedSamples() { 58 | return samples; 59 | } 60 | 61 | public MinimalVariantContext get() { 62 | return variantContext; 63 | } 64 | 65 | public int getSnpsCount() { 66 | return snpsCount; 67 | } 68 | 69 | public int getSamplesCount() { 70 | return samplesCount; 71 | } 72 | 73 | public boolean next() throws IOException { 74 | String line; 75 | while ((line = in.readLine()) != null) { 76 | try { 77 | lineNumber++; 78 | if (!line.trim().isEmpty() && line.charAt(0) != '#') { 79 | parseLine(line); 80 | return true; 81 | } 82 | } catch (Exception e) { 83 | throw new IOException(filename + ": Line " + lineNumber + ": " + e.getMessage()); 84 | } 85 | } 86 | return false; 87 | } 88 | 89 | protected void parseLine(String line) throws IOException { 90 | 91 | variantContext = parser.parseLine(line); 92 | 93 | if (variantContext.getNSamples() != samplesCount) { 94 | throw new IOException("Line " + lineNumber + ": different number of samples."); 95 | } 96 | 97 | snpsCount++; 98 | 99 | } 100 | 101 | public void close() { 102 | try { 103 | in.close(); 104 | } catch (IOException e) { 105 | e.printStackTrace(); 106 | } 107 | } 108 | 109 | public String getFilename() { 110 | return filename; 111 | } 112 | 113 | @Override 114 | public Iterator iterator() { 115 | return null; 116 | } 117 | 118 | @Override 119 | public void reset() { 120 | 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/io/vcf/VCFLineParser.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.vcf; 2 | 3 | import java.io.IOException; 4 | 5 | public class VCFLineParser { 6 | 7 | private int samplesInLineCount = 0; 8 | 9 | private int noCallCount = 0; 10 | 11 | private int hetCount = 0; 12 | 13 | private int homRefCount = 0; 14 | 15 | private int homVarCount = 0; 16 | 17 | private int i = 0; 18 | 19 | private int countR = 0; 20 | 21 | private int countV = 0; 22 | 23 | private int countNo = 0; 24 | 25 | private int tile = 0; 26 | 27 | private int tileGT = 0; 28 | 29 | private int j = 0; 30 | 31 | private int k = 0; 32 | 33 | private MinimalVariantContext variantContext; 34 | 35 | private int samples; 36 | 37 | public VCFLineParser(int samples) { 38 | variantContext = new MinimalVariantContext(samples); 39 | this.samples=samples; 40 | } 41 | 42 | public MinimalVariantContext parseLine(String line) throws IOException { 43 | 44 | String tiles[] = line.split("\t", 10); 45 | 46 | if (tiles.length < 10) { 47 | throw new IOException("The provided VCF file is not correct tab-delimited"); 48 | } 49 | 50 | String chromosome = tiles[0]; 51 | int position = Integer.parseInt(tiles[1]); 52 | String ref = tiles[3]; 53 | String alt = tiles[4]; 54 | 55 | /*i = 0; 56 | countR = 0; 57 | countV = 0; 58 | 59 | homRefCount = 0; 60 | homVarCount = 0; 61 | hetCount = 0; 62 | noCallCount = 0; 63 | 64 | samplesInLineCount = 0; 65 | 66 | tileGT = 0; 67 | k = tiles[8].indexOf("GT"); 68 | 69 | if (k == -1){ 70 | throw new IOException("No GT field found in FORMAT column."); 71 | } 72 | 73 | j = 0; 74 | while (j < k){ 75 | if (tiles[8].charAt(j) == ':'){ 76 | tileGT++; 77 | } 78 | j++; 79 | } 80 | 81 | while (i < tiles[9].length()) { 82 | countR = 0; 83 | countV = 0; 84 | countNo = 0; 85 | // count genotypes for one sample 86 | tile = 0; 87 | while (i < tiles[9].length() && tiles[9].charAt(i) != '\t') { 88 | 89 | //count format values 90 | if (tiles[9].charAt(i) == ':') { 91 | tile++; 92 | } else { 93 | //find right position 94 | if (tile == tileGT) { 95 | 96 | if (tiles[9].charAt(i) == '1') { 97 | countV++; 98 | } else if (tiles[9].charAt(i) == '0') { 99 | countR++; 100 | } else if (tiles[9].charAt(i) == '.') { 101 | countNo++; 102 | } 103 | } 104 | } 105 | i++; 106 | } 107 | // check if it is hom or het 108 | if (countR == 2 || (countR == 1 && countV == 0)) { 109 | homRefCount++; 110 | } else if (countV == 2 || (countV == 1 && countR == 0)) { 111 | homVarCount++; 112 | } else 113 | 114 | if (countV == 1 && countR == 1) { 115 | hetCount++; 116 | } 117 | i++; 118 | 119 | if (countNo == 2 || (countNo == 1 && countV == 0 && countR == 0)) { 120 | noCallCount++; 121 | variantContext.setCalled(samplesInLineCount, false); 122 | } else { 123 | variantContext.setCalled(samplesInLineCount, true); 124 | } 125 | 126 | samplesInLineCount++; 127 | }*/ 128 | //variantContext.setNSamples(samplesInLineCount); 129 | 130 | // update variant context 131 | variantContext.setContig(chromosome); 132 | variantContext.setStart(position); 133 | variantContext.setReferenceAllele(ref); 134 | variantContext.setAlternateAllele(alt); 135 | variantContext.setHetCount(hetCount); 136 | variantContext.setHomRefCount(homRefCount); 137 | variantContext.setHomVarCount(homVarCount); 138 | variantContext.setNoCallCount(noCallCount); 139 | variantContext.setNSamples(samples); 140 | variantContext.setRawLine(line); 141 | 142 | if (!tiles[6].equals("PASS") && !tiles[6].equals(".")) { 143 | variantContext.setFilters(tiles[6]); 144 | } else { 145 | variantContext.setFilters(null); 146 | } 147 | 148 | //info 149 | variantContext.setInfo(tiles[7]); 150 | 151 | return variantContext; 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/model/Population.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.model; 2 | 3 | public class Population implements Comparable { 4 | 5 | private String name; 6 | 7 | public int count = 0; 8 | 9 | public float percentage = 0; 10 | 11 | public String color; 12 | 13 | public String label; 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public void setName(String name) { 20 | this.name = name; 21 | color = getColor(); 22 | label = getLabel(); 23 | } 24 | 25 | public int getCount() { 26 | return count; 27 | } 28 | 29 | public void setCount(int count) { 30 | this.count = count; 31 | } 32 | 33 | public void incCount() { 34 | this.count++; 35 | } 36 | 37 | public float getPercentage() { 38 | return percentage; 39 | } 40 | 41 | public void setPercentage(float percentage) { 42 | this.percentage = percentage; 43 | } 44 | 45 | public void updateColorAndLabel() { 46 | color = getColor(); 47 | label = getLabel(); 48 | } 49 | 50 | public void setColor(String color) { 51 | this.color = color; 52 | } 53 | 54 | public String getColor() { 55 | 56 | switch (name) { 57 | 58 | case "AFR": 59 | return "#FF6600"; 60 | 61 | case "ASN": 62 | //TODO: update 63 | return "#999999"; 64 | 65 | case "EUR": 66 | return "#0099E6"; 67 | 68 | case "GME": 69 | return "#DBEE06"; 70 | 71 | case "SAS": 72 | return "#F90026"; 73 | 74 | case "EAS": 75 | return "#FF99E6"; 76 | 77 | case "OTH": 78 | return "#339933"; 79 | 80 | case "AMR": 81 | return "#800080"; 82 | 83 | // TODO: udpate colors 84 | case "MAE": 85 | return "eeeeee"; 86 | 87 | case "MAO": 88 | return "333333"; 89 | 90 | } 91 | 92 | return "#B5B5B5"; 93 | } 94 | 95 | public void setLabel(String label) { 96 | this.label = label; 97 | } 98 | 99 | public String getLabel() { 100 | switch (name) { 101 | 102 | case "AFR": 103 | return "African"; 104 | 105 | case "ASN": 106 | return "Additional Asian Ancestries"; 107 | 108 | case "EUR": 109 | return "European"; 110 | 111 | case "GME": 112 | return "Greater Middle Eastern"; 113 | 114 | case "SAS": 115 | return "South Asian"; 116 | 117 | case "EAS": 118 | return "East Asian"; 119 | 120 | case "OTH": 121 | return "Additional Diverse Ancestries"; 122 | 123 | case "AMR": 124 | return "Hispanic or Latin American"; 125 | 126 | case "MAE": 127 | return "Multi-Ancestry (including Europeans)"; 128 | 129 | case "MAO": 130 | return "Multi-Ancestry (excluding Europeans)"; 131 | 132 | 133 | } 134 | 135 | return "Unknown"; 136 | 137 | } 138 | 139 | @Override 140 | public int compareTo(Population o) { 141 | return -Float.compare(percentage, o.getPercentage()); 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/model/PopulationMap.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.model; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Vector; 8 | 9 | public class PopulationMap { 10 | 11 | private Map items = new HashMap(); 12 | 13 | public int total = 0; 14 | 15 | public void addSample(String population) { 16 | addSamples(population, 1); 17 | } 18 | 19 | public void addSamples(String population, int count) { 20 | Population item = items.get(population); 21 | if (item == null) { 22 | item = new Population(); 23 | item.setName(population); 24 | item.setCount(0); 25 | items.put(population, item); 26 | } 27 | item.setCount(item.getCount() + count); 28 | this.total += count; 29 | for ( Population _item: items.values()) { 30 | _item.setPercentage(_item.getCount() / (float) total); 31 | } 32 | } 33 | 34 | public List getPopulations() { 35 | List result = new Vector(); 36 | for ( Population item: items.values()) { 37 | result.add(item); 38 | } 39 | Collections.sort(result); 40 | return result; 41 | } 42 | 43 | public int getTotal() { 44 | return total; 45 | } 46 | 47 | public boolean supports(String population) { 48 | return items.containsKey(population); 49 | } 50 | 51 | public boolean supports(Population population) { 52 | return items.containsKey(population.getName()); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/model/ReferenceVariant.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.model; 2 | 3 | public class ReferenceVariant { 4 | 5 | private float effectWeight; 6 | 7 | private String otherAllele; 8 | 9 | private String effectAllele; 10 | 11 | private boolean used = false; 12 | 13 | private ReferenceVariant parent; 14 | 15 | public ReferenceVariant(String otherAllele, String effectAllele, float effectWeight) { 16 | this.otherAllele = otherAllele; 17 | this.effectAllele = effectAllele; 18 | this.effectWeight = effectWeight; 19 | } 20 | 21 | public ReferenceVariant(){ 22 | 23 | } 24 | 25 | public void setEffectWeight(float effectWeight) { 26 | this.effectWeight = effectWeight; 27 | } 28 | 29 | public void setOtherAllele(String otherAllele) { 30 | this.otherAllele = otherAllele; 31 | } 32 | 33 | public void setEffectAllele(String effectAllele) { 34 | this.effectAllele = effectAllele; 35 | } 36 | 37 | public float getEffectWeight() { 38 | return effectWeight; 39 | } 40 | 41 | public String getOtherAllele() { 42 | return otherAllele; 43 | } 44 | 45 | public String getEffectAllele() { 46 | return effectAllele; 47 | } 48 | 49 | public boolean isEffectAllele(String allele) { 50 | return (effectAllele.equals(allele)); 51 | } 52 | 53 | public boolean hasAllele(String allele) { 54 | return ((otherAllele.equals(allele)) || (effectAllele.equals(allele))); 55 | } 56 | 57 | public void setUsed(boolean used) { 58 | if (parent != null) { 59 | parent.setUsed(used); 60 | } else { 61 | this.used = used; 62 | } 63 | } 64 | 65 | public boolean isUsed() { 66 | if (parent != null) { 67 | return parent.isUsed(); 68 | } else { 69 | return used; 70 | } 71 | } 72 | 73 | public void setParent(ReferenceVariant parent) { 74 | this.parent = parent; 75 | } 76 | 77 | public ReferenceVariant getParent() { 78 | return parent; 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | return effectAllele + "_" + otherAllele + ":" + effectWeight; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/model/RiskScore.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.model; 2 | 3 | public class RiskScore { 4 | 5 | private String sample; 6 | 7 | private String chromosome; 8 | 9 | private double[] scores; 10 | 11 | public RiskScore(String chromosome, String sample, int numberOfScores) { 12 | this.chromosome = chromosome; 13 | this.sample = sample; 14 | this.scores = new double[numberOfScores]; 15 | for (int i = 0; i < scores.length; i++) { 16 | this.scores[i] = 0; 17 | } 18 | } 19 | 20 | public void setScore(int index, double score) { 21 | this.scores[index] = score; 22 | } 23 | 24 | public void incScore(int index, double score) { 25 | this.scores[index] += score; 26 | } 27 | 28 | public double getScore(int index) { 29 | return scores[index]; 30 | } 31 | 32 | public String getSample() { 33 | return sample; 34 | } 35 | 36 | public String getChromosome() { 37 | return chromosome; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return sample + ": " + scores; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/model/Sample.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.model; 2 | 3 | public class Sample { 4 | 5 | private String id; 6 | 7 | private String population; 8 | 9 | public static String UNKNOWN_POPULATION = "Not Reported"; 10 | 11 | public Sample(String id, String population) { 12 | this.id = id; 13 | this.population = population; 14 | } 15 | 16 | public String getId() { 17 | return id; 18 | } 19 | 20 | public void setId(String id) { 21 | this.id = id; 22 | } 23 | 24 | public String getPopulation() { 25 | return population; 26 | } 27 | 28 | public void setPopulation(String population) { 29 | this.population = population; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/model/ScorePopulationMap.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.model; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Vector; 8 | 9 | public class ScorePopulationMap { 10 | 11 | private Map items = new HashMap(); 12 | 13 | public int total = 0; 14 | 15 | public void addSample(String population) { 16 | addSamples(population, 1); 17 | } 18 | 19 | public void addSamples(String population, float percentage) { 20 | Population item = items.get(population); 21 | item = new Population(); 22 | item.setName(population); 23 | item.setCount(-1); 24 | item.setPercentage(percentage); 25 | items.put(population, item); 26 | 27 | } 28 | 29 | public List getPopulations() { 30 | List result = new Vector(); 31 | for (Population item : items.values()) { 32 | result.add(item); 33 | } 34 | Collections.sort(result); 35 | return result; 36 | } 37 | 38 | public int getTotal() { 39 | return total; 40 | } 41 | 42 | public boolean supports(String population) { 43 | return items.containsKey(population); 44 | } 45 | 46 | public boolean supports(Population population) { 47 | return items.containsKey(population.getName()); 48 | } 49 | 50 | public void updateColorAndLabel() { 51 | for (Population item: items.values()) { 52 | item.updateColorAndLabel(); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/tasks/MergeEffectsTask.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.tasks; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.List; 6 | import java.util.Vector; 7 | 8 | import genepi.io.table.reader.CsvTableReader; 9 | import genepi.io.table.writer.CsvTableWriter; 10 | import lukfor.progress.tasks.ITaskRunnable; 11 | import lukfor.progress.tasks.monitors.ITaskMonitor; 12 | 13 | public class MergeEffectsTask implements ITaskRunnable { 14 | 15 | public static final char EFFECTS_FILE_SEPARATOR = ','; 16 | 17 | private String output; 18 | 19 | private List inputs = new Vector<>(); 20 | 21 | public void setOutput(String output) { 22 | this.output = output; 23 | } 24 | 25 | public void setInputs(String... filenames) throws IOException { 26 | for (String filename : filenames) { 27 | if (new File(filename).exists()) { 28 | inputs.add(filename); 29 | } 30 | } 31 | } 32 | 33 | public void setInputs(List tasks) { 34 | for (int i = 0; i < tasks.size(); i++) { 35 | ApplyScoreTask task = tasks.get(i); 36 | String filename = task.getOutputEffectsFilename(); 37 | if (new File(filename).exists()) { 38 | inputs.add(filename); 39 | } 40 | } 41 | } 42 | 43 | @Override 44 | public void run(ITaskMonitor monitor) throws Exception { 45 | 46 | monitor.begin("Merge effect files"); 47 | 48 | assert (output != null); 49 | 50 | if (inputs.isEmpty()) { 51 | throw new Exception("No chunks found to merge."); 52 | } 53 | 54 | CsvTableReader reader = new CsvTableReader(inputs.get(0), EFFECTS_FILE_SEPARATOR); 55 | 56 | CsvTableWriter writer = new CsvTableWriter(output, EFFECTS_FILE_SEPARATOR); 57 | writer.setColumns(reader.getColumns()); 58 | reader.close(); 59 | 60 | for (int i = 0; i < inputs.size(); i++) { 61 | reader = new CsvTableReader(inputs.get(i), EFFECTS_FILE_SEPARATOR); 62 | while (reader.next()) { 63 | writer.setRow(reader.getRow()); 64 | writer.next(); 65 | } 66 | reader.close(); 67 | } 68 | 69 | writer.close(); 70 | 71 | monitor.done(); 72 | 73 | inputs = null; 74 | 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/tasks/MergeReportTask.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.tasks; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.List; 6 | import java.util.Vector; 7 | 8 | import genepi.riskscore.io.ReportFile; 9 | import genepi.riskscore.model.RiskScoreSummary; 10 | import lukfor.progress.tasks.ITaskRunnable; 11 | import lukfor.progress.tasks.monitors.ITaskMonitor; 12 | 13 | public class MergeReportTask implements ITaskRunnable { 14 | 15 | private String output; 16 | 17 | private List inputs = new Vector(); 18 | 19 | private ReportFile result; 20 | 21 | public void setOutput(String output) { 22 | this.output = output; 23 | } 24 | 25 | public void setInputs(String... filenames) throws IOException { 26 | for (String filename : filenames) { 27 | if (new File(filename).exists()) { 28 | inputs.add(ReportFile.loadFromFile(filename)); 29 | } 30 | } 31 | } 32 | 33 | public void setInputs(List tasks) { 34 | for (int i = 0; i < tasks.size(); i++) { 35 | ApplyScoreTask task = tasks.get(i); 36 | String filename = task.getOutput(); 37 | if (new File(filename).exists()) { 38 | inputs.add(new ReportFile(task.getSummaries())); 39 | } 40 | } 41 | } 42 | 43 | @Override 44 | public void run(ITaskMonitor monitor) throws Exception { 45 | 46 | monitor.begin("Merge report files"); 47 | 48 | if (inputs.isEmpty()) { 49 | throw new Exception("No chunks found to merge."); 50 | } 51 | result = inputs.get(0); 52 | 53 | for (int i = 1; i < inputs.size(); i++) { 54 | result.merge(inputs.get(i)); 55 | } 56 | 57 | // update statistics 58 | for (RiskScoreSummary summary : result.getSummaries()) { 59 | summary.updateStatistics(); 60 | } 61 | 62 | if (output != null) { 63 | result.save(output); 64 | monitor.update("Report files merged and written to '" + output + "'"); 65 | } else { 66 | monitor.update("Report files merged"); 67 | } 68 | monitor.done(); 69 | 70 | inputs = null; 71 | 72 | } 73 | 74 | public ReportFile getResult() { 75 | return result; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/tasks/MergeScoreTask.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.tasks; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.List; 6 | import java.util.Vector; 7 | 8 | import genepi.io.table.writer.CsvTableWriter; 9 | import genepi.io.table.writer.ITableWriter; 10 | import genepi.riskscore.io.OutputFileReader; 11 | import genepi.riskscore.io.OutputFileWriter; 12 | import lukfor.progress.tasks.ITaskRunnable; 13 | import lukfor.progress.tasks.monitors.ITaskMonitor; 14 | 15 | public class MergeScoreTask implements ITaskRunnable { 16 | 17 | private String output; 18 | 19 | private List inputs = new Vector<>(); 20 | 21 | public void setOutput(String output) { 22 | this.output = output; 23 | } 24 | 25 | public void setInputs(String... filenames) throws IOException { 26 | for (String filename : filenames) { 27 | if (new File(filename).exists()) { 28 | inputs.add(filename); 29 | } 30 | } 31 | } 32 | 33 | public void setInputs(List tasks) { 34 | for (int i = 0; i < tasks.size(); i++) { 35 | ApplyScoreTask task = tasks.get(i); 36 | String filename = task.getOutput(); 37 | if (new File(filename).exists()) { 38 | inputs.add(filename); 39 | } 40 | } 41 | } 42 | 43 | @Override 44 | public void run(ITaskMonitor monitor) throws Exception { 45 | 46 | monitor.begin("Merge score files"); 47 | 48 | assert (output != null); 49 | 50 | if (inputs.isEmpty()) { 51 | throw new Exception("No chunks found to merge."); 52 | } 53 | 54 | OutputFileReader[] files = new OutputFileReader[inputs.size()]; 55 | 56 | for (int i = 0; i < inputs.size(); i++) { 57 | files[i] = new OutputFileReader(inputs.get(i)); 58 | } 59 | 60 | List scores = files[0].getScores(); 61 | 62 | String[] columns = new String[scores.size() + 1]; 63 | columns[0] = OutputFileWriter.COLUMN_SAMPLE; 64 | for (int i = 0; i < scores.size(); i++) { 65 | columns[i + 1] = scores.get(i); 66 | } 67 | 68 | ITableWriter writer = new CsvTableWriter(output, OutputFileWriter.SEPARATOR); 69 | writer.setColumns(columns); 70 | 71 | while (files[0].next()) { 72 | 73 | double[] values = files[0].getValues(); 74 | for (int i = 1; i < files.length; i++) { 75 | if (!files[i].next()) { 76 | throw new Exception("Not all vcf files have the same number of samples."); 77 | } 78 | double[] data = files[i].getValues(); 79 | for (int j = 0; j < data.length; j++) { 80 | values[j] += data[j]; 81 | } 82 | } 83 | 84 | writer.setString(OutputFileWriter.COLUMN_SAMPLE, files[0].getSample()); 85 | for (int i = 0; i < scores.size(); i++) { 86 | writer.setDouble(scores.get(i), values[i]); 87 | } 88 | writer.next(); 89 | 90 | } 91 | 92 | for (int i = 1; i < files.length; i++) { 93 | if (files[i].next()) { 94 | throw new Exception("Not all vcf files have the same number of samples."); 95 | } 96 | files[i].close(); 97 | } 98 | 99 | writer.close(); 100 | 101 | monitor.done(); 102 | 103 | inputs = null; 104 | 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/genepi/riskscore/tasks/MergeVariantsTask.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.tasks; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.List; 6 | import java.util.Vector; 7 | 8 | import genepi.io.table.reader.CsvTableReader; 9 | import genepi.io.table.writer.CsvTableWriter; 10 | import genepi.riskscore.io.VariantFile; 11 | import lukfor.progress.tasks.ITaskRunnable; 12 | import lukfor.progress.tasks.monitors.ITaskMonitor; 13 | 14 | public class MergeVariantsTask implements ITaskRunnable { 15 | 16 | private String output; 17 | 18 | private List inputs = new Vector<>(); 19 | 20 | public void setOutput(String output) { 21 | this.output = output; 22 | } 23 | 24 | public void setInputs(String... filenames) throws IOException { 25 | for (String filename : filenames) { 26 | if (new File(filename).exists()) { 27 | inputs.add(filename); 28 | } 29 | } 30 | } 31 | 32 | public void setInputs(List tasks) { 33 | for (int i = 0; i < tasks.size(); i++) { 34 | ApplyScoreTask task = tasks.get(i); 35 | String filename = task.getOutputVariantFilename(); 36 | if (new File(filename).exists()) { 37 | inputs.add(filename); 38 | } 39 | } 40 | } 41 | 42 | @Override 43 | public void run(ITaskMonitor monitor) throws Exception { 44 | 45 | monitor.begin("Merge variants files"); 46 | 47 | assert (output != null); 48 | 49 | if (inputs.isEmpty()) { 50 | throw new Exception("No chunks found to merge."); 51 | } 52 | 53 | CsvTableReader reader = new CsvTableReader(inputs.get(0), VariantFile.SEPARATOR); 54 | 55 | CsvTableWriter writer = new CsvTableWriter(output, VariantFile.SEPARATOR); 56 | writer.setColumns(reader.getColumns()); 57 | reader.close(); 58 | 59 | for (int i = 0; i < inputs.size(); i++) { 60 | reader = new CsvTableReader(inputs.get(i), VariantFile.SEPARATOR); 61 | while (reader.next()) { 62 | writer.setRow(reader.getRow()); 63 | writer.next(); 64 | } 65 | reader.close(); 66 | } 67 | 68 | writer.close(); 69 | 70 | monitor.done(); 71 | 72 | inputs = null; 73 | 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/resources/templates/default/components/distribution.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | Distribution 6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 14 |
15 |
16 |
17 | Selection (0) 18 |
19 | 22 | 26 |
27 |
28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
SampleScore
40 |
41 |
42 |
43 | 44 |
45 |
46 | -------------------------------------------------------------------------------- /src/main/resources/templates/default/components/samples.html: -------------------------------------------------------------------------------- 1 |

Samples

2 |
3 |
General
4 |
    5 | {{if (show_samples)}} 6 |
  • Samples: {{decimal(samples.size())}}
  • 7 | {{else}} 8 | {{if (populations.getTotal() > 0) }} 9 |
  • Samples: {{decimal(populations.getTotal())}}
  • 10 | {{end}} 11 | {{end}} 12 |
13 |
Populations
14 | {{if (populations.getTotal() > 0) }} 15 |
    16 | {{for pop in populations.getPopulations()}} 17 |
  • {{pop.label}}: {{decimal(pop.count)}} ({{percentage(pop.percentage)}})
  • 18 | {{end}} 19 |
20 | {{else}} 21 | no ancestry information available 22 | {{end}} 23 | 24 |
25 | -------------------------------------------------------------------------------- /src/main/resources/templates/default/components/score_details.html: -------------------------------------------------------------------------------- 1 | {{for index,score in scores}} 2 |
3 |

{{score.name}}

4 |
5 | {{if score.populationCheckStatus == false}} 6 |
7 | {{score.populationCheckMessage}} 8 |
9 | {{end}} 10 |
Reference score
11 |
    12 |
  • Variants: {{decimal(score.variants)}}
  • 13 |
  • Variants ignored: {{decimal(score.variantsIgnored)}}
  • 14 | {{if score.meta != null}} 15 |
  • 16 | Trait: {{score.meta.trait}} 17 |
  • 18 | {{if score.meta.efo != null}} 19 |
  • Mapped Trait(s): 20 |
      21 | {{for efo in score.meta.efo}} 22 |
    • {{efo.id}}: {{efo.label}}
    • 23 | {{end}} 24 |
    25 |
  • 26 | {{end}} 27 | {{if score.meta.traitAdditional != null}} 28 |
  • Additional Trait: {{score.meta.traitAdditional}}
  • 29 | {{end}} 30 | {{if score.meta.getPopulations() != null}} 31 |
  • Samples: {{decimal(score.meta.getPopulations().getTotal())}}
  • 32 |
  • Population: 33 |
      34 | {{for pop in score.meta.getPopulations().getPopulations()}} 35 |
    • {{pop.label}}: {{percentage(pop.percentage)}}
    • 36 | {{end}} 37 |
    38 |
  • 39 | {{end}} 40 | {{if score.meta.publication != null}} 41 |
  • Publication: {{score.meta.publication.firstauthor}} et.al, {{score.meta.publication.journal}} ({{score.meta.publication.date}})
  • 42 | {{end}} 43 | {{if score.meta.link != null}} 44 |
  • View in {{score.meta.repository}}
  • 45 | {{end}} 46 | {{end}} 47 |
48 | 49 |
Target study
50 |
    51 |
  • Coverage: {{decimal(score.variantsUsed)}} ({{percentage(score.coverage)}}) {{score.coverageLabel}}
  • 52 | {{if (show_samples)}} 53 | {{if score.data != null && score.populationCheckStatus}} 54 |
  • Samples: {{decimal(score.samples)}} / {{decimal(samples.size())}} ({{percentage(score.samplesPercentage)}})
  • 55 | {{else}} 56 |
  • Samples: {{decimal(samples.size())}}
  • 57 | {{end}} 58 | {{end}} 59 |
60 | 61 | {{if (showDistribution == false)}} 62 |
Distribution
63 |

An interactive histogram to investigate samples is available in the extended HTML report.

64 | {{end}} 65 |
66 | {{end}} 67 | -------------------------------------------------------------------------------- /src/main/resources/templates/default/components/score_list.html: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /src/main/resources/templates/default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Report - {{application}} 11 | 12 | 13 | {{include_style("https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css")}} 14 | {{include_style("report.css")}} 15 | 16 | {{include_script("report.json")}} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 62 | 63 | 64 |
65 | {{include "components/score_list.html"}} 66 | 67 |
68 | 69 |
70 |
71 | 72 |
73 | {{include "components/samples.html"}} 74 |
75 | 76 | {{include "components/score_details.html"}} 77 |
78 |
79 | 80 | {{include "components/distribution.html"}} 81 | 82 |
83 | 84 | 85 | {{include_script("https://code.jquery.com/jquery-3.5.1.slim.min.js")}} 86 | {{include_script("https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js")}} 87 | {{include_script("https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js")}} 88 | {{include_script("https://cdn.plot.ly/plotly-latest.min.js")}} 89 | {{include_script("https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js")}} 90 | 91 | {{include_script("report.js")}} 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/main/resources/templates/default/report.css: -------------------------------------------------------------------------------- 1 | .bd-placeholder-img { 2 | font-size: 1.125rem; 3 | text-anchor: middle; 4 | -webkit-user-select: none; 5 | -moz-user-select: none; 6 | -ms-user-select: none; 7 | user-select: none; 8 | } 9 | 10 | @media (min-width: 768px) { 11 | .bd-placeholder-img-lg { 12 | font-size: 3.5rem; 13 | } 14 | } 15 | 16 | #wrapper { 17 | overflow-x: hidden; 18 | } 19 | 20 | #sidebar-wrapper { 21 | height: 100%; 22 | position: fixed; 23 | margin-left: 0rem; 24 | -webkit-transition: margin .25s ease-out; 25 | -moz-transition: margin .25s ease-out; 26 | -o-transition: margin .25s ease-out; 27 | transition: margin .25s ease-out; 28 | } 29 | 30 | #page-content-wrapper { 31 | padding-left: 250px; 32 | margin-top: 90px; 33 | width: 100%; 34 | } 35 | 36 | #wrapper.toggled #sidebar-wrapper { 37 | margin-left: 0; 38 | } 39 | 40 | .sidebar-search { 41 | margin-top: 80px; 42 | width: 250px; 43 | } 44 | 45 | .sidebar-list { 46 | width: 242px; 47 | top: 135px; 48 | position: fixed; 49 | overflow-y: scroll; 50 | bottom: 0px; 51 | padding-top: 0px; 52 | padding-right: 8px; 53 | } 54 | 55 | .coverage-low { 56 | border-left-width: 8px; 57 | border-left-color: #dc3545; 58 | } 59 | 60 | .coverage-medium { 61 | border-left-width: 8px; 62 | border-left-color: #ffc107; 63 | } 64 | 65 | .coverage-high { 66 | border-left-width: 8px; 67 | border-left-color: #28a745; 68 | } 69 | 70 | .coverage-zero { 71 | border-left-width: 8px; 72 | border-left-color: #dc3545; 73 | } 74 | 75 | .badge-low { 76 | color: #ffffff; 77 | background: #dc3545; 78 | } 79 | 80 | .badge-medium { 81 | color: #ffffff; 82 | background: #ffc107; 83 | } 84 | 85 | .badge-high { 86 | color: #ffffff; 87 | background: #28a745; 88 | } 89 | 90 | .badge-zero { 91 | color: #ffffff; 92 | background: #dc3545; 93 | } 94 | -------------------------------------------------------------------------------- /src/main/resources/templates/default/report.json: -------------------------------------------------------------------------------- 1 | data = []; 2 | excluded = []; 3 | {{for index,score in scores}} 4 | {{if score.data != null}} 5 | data['score{{index}}']= {{json(score.data)}}; 6 | excluded['score{{index}}'] = {{json(score.excluded)}}; 7 | {{end}} 8 | {{end}} 9 | 10 | {{if (show_samples)}} 11 | samples = {{json(samples)}}; 12 | {{end}} 13 | 14 | -------------------------------------------------------------------------------- /src/main/resources/templates/multi-page/components/score_list.html: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /src/main/resources/templates/multi-page/components/score_list.js: -------------------------------------------------------------------------------- 1 | activeItem = $('#sample-item'); 2 | 3 | function setActive(e) { 4 | 5 | if (activeItem){ 6 | activeItem.removeClass("active"); 7 | } 8 | $(this).addClass("active"); 9 | activeItem = $(this); 10 | } 11 | 12 | 13 | $(document).ready(function() { 14 | 15 | //event handler 16 | $('.list-group-item').on('click', setActive); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /src/main/resources/templates/multi-page/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Report - {{application}} 11 | 12 | 13 | {{include_style("https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css")}} 14 | {{include_style("../default/report.css")}} 15 | 16 | {{include_script("report.json")}} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 50 | 51 | 52 |
53 | {{include "components/score_list.html"}} 54 | 55 |
56 | 57 | 58 | {{include_script("https://code.jquery.com/jquery-3.5.1.slim.min.js")}} 59 | {{include_script("https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js")}} 60 | {{include_script("https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js")}} 61 | {{include_script("https://cdn.plot.ly/plotly-latest.min.js")}} 62 | {{include_script("https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js")}} 63 | 64 | {{include_script("../default/report.js")}} 65 | {{include_script("components/score_list.js")}} 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/main/resources/templates/multi-page/report.json: -------------------------------------------------------------------------------- 1 | data = []; 2 | excluded = []; 3 | -------------------------------------------------------------------------------- /src/main/resources/templates/multi-page/samples.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Report - {{application}} 11 | 12 | 13 | {{include_style("https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css")}} 14 | {{include_style("../default/report.css")}} 15 | 16 | {{include_script("report.json")}} 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | {{include "../default/components/samples.html"}} 25 |
26 | 27 | 28 | {{include_script("https://code.jquery.com/jquery-3.5.1.slim.min.js")}} 29 | {{include_script("https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js")}} 30 | {{include_script("https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js")}} 31 | {{include_script("https://cdn.plot.ly/plotly-latest.min.js")}} 32 | {{include_script("https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js")}} 33 | {{include_script("../default/report.js")}} 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/main/resources/templates/multi-page/score.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Report - {{application}} 11 | 12 | 13 | {{include_style("https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css")}} 14 | {{include_style("../default/report.css")}} 15 | 16 | {{include_script("../default/report.json")}} 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | {{include "../default/components/score_details.html"}} 25 | {{include "../default/components/distribution.html"}} 26 |
27 | 28 | 29 | {{include_script("https://code.jquery.com/jquery-3.5.1.slim.min.js")}} 30 | {{include_script("https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js")}} 31 | {{include_script("https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js")}} 32 | {{include_script("https://cdn.plot.ly/plotly-latest.min.js")}} 33 | {{include_script("https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js")}} 34 | {{include_script("../default/report.js")}} 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/main/resources/templates/txt/index.html: -------------------------------------------------------------------------------- 1 | score,coverage,variants_used,variants_total,variants_flipped,variants_ambiguous,trait,trait_efo 2 | {{for index,score in scores}}{{score.name}},{{score.coverage}},{{score.variantsUsed}},{{score.variants}},{{score.flipped}},{{score.ambiguous}},{{if score.meta != null}}{{score.meta.trait.replaceAll(","," ")}},{{if score.meta.efo != null}}{{score.meta.efo[0].id}}{{end}}{{else}},{{end}} 3 | {{end}} -------------------------------------------------------------------------------- /src/test/java/genepi/riskscore/commands/CreateHtmlReportCommandTest.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Before; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | 9 | import genepi.io.FileUtil; 10 | import genepi.riskscore.io.PGSCatalog; 11 | import lukfor.progress.TaskService; 12 | import picocli.CommandLine; 13 | 14 | public class CreateHtmlReportCommandTest { 15 | 16 | @BeforeClass 17 | public static void setup() { 18 | TaskService.setAnsiSupport(false); 19 | PGSCatalog.ENABLE_CACHE = false; 20 | } 21 | 22 | @Before 23 | public void beforeTest() { 24 | System.out.println("Clean up output directory"); 25 | FileUtil.deleteDirectory("test-data-output"); 26 | FileUtil.createDirectory("test-data-output"); 27 | } 28 | 29 | @Test 30 | public void testReport() throws Exception { 31 | 32 | String[] args = { "--data", "test-data/output.csv", "--info", "test-data/report.json", "--out", 33 | "test-data-output/report.html" }; 34 | int result = new CommandLine(new CreateHtmlReportCommand()).execute(args); 35 | assertEquals(0, result); 36 | 37 | } 38 | 39 | @Test 40 | public void testReportWithoutData() throws Exception { 41 | 42 | String[] args = { "--info", "test-data/report.json", "--out", "test-data-output/report.html" }; 43 | int result = new CommandLine(new CreateHtmlReportCommand()).execute(args); 44 | assertEquals(0, result); 45 | 46 | } 47 | 48 | @Test 49 | public void testReportWithTxtTemplate() throws Exception { 50 | 51 | String[] args = { "--info", "test-data/report.json", "--out", "test-data-output/report.txt", "--template", 52 | "txt" }; 53 | int result = new CommandLine(new CreateHtmlReportCommand()).execute(args); 54 | assertEquals(0, result); 55 | 56 | } 57 | 58 | @Test 59 | public void testReportWithTxtTemplateAndMetaData() throws Exception { 60 | 61 | String[] args = { "--info", "test-data/report.json", "--out", "test-data-output/report.txt", "--template", 62 | "txt", "--meta", "test-data/pgs-catalog-small.json" }; 63 | int result = new CommandLine(new CreateHtmlReportCommand()).execute(args); 64 | assertEquals(0, result); 65 | 66 | } 67 | 68 | @Test 69 | public void testReportWithHtmlTemplateAndMetaData() throws Exception { 70 | 71 | String[] args = { "--info", "test-data/report.json", "--out", "test-data-output/report.html", "--meta", 72 | "test-data/pgs-catalog-small.json" }; 73 | int result = new CommandLine(new CreateHtmlReportCommand()).execute(args); 74 | assertEquals(0, result); 75 | 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/test/java/genepi/riskscore/commands/MergeEffectsCommandTest.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Before; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | 9 | import genepi.io.FileUtil; 10 | import genepi.riskscore.io.PGSCatalog; 11 | import lukfor.progress.TaskService; 12 | import picocli.CommandLine; 13 | 14 | public class MergeEffectsCommandTest { 15 | 16 | @BeforeClass 17 | public static void setup() { 18 | TaskService.setAnsiSupport(false); 19 | PGSCatalog.ENABLE_CACHE = false; 20 | } 21 | 22 | @Before 23 | public void beforeTest() { 24 | System.out.println("Clean up output directory"); 25 | FileUtil.deleteDirectory("test-data-output"); 26 | FileUtil.createDirectory("test-data-output"); 27 | } 28 | 29 | @Test 30 | public void testMerge() throws Exception { 31 | 32 | String[] args = { "test-data/effects.chunk1.txt", "test-data/effects.chunk2.txt", "--out", 33 | "test-data-output/effects.task.txt" }; 34 | int result = new CommandLine(new MergeEffectsCommand()).execute(args); 35 | assertEquals(0, result); 36 | 37 | assertEquals(FileUtil.readFileAsString("test-data/effects.expected.txt"), 38 | FileUtil.readFileAsString("test-data-output/effects.task.txt")); 39 | } 40 | 41 | @Test 42 | public void testMergingChunks() throws Exception { 43 | 44 | // Whole file 45 | String[] args = { "test-data/chr20.dose.vcf.gz", "--ref", 46 | "test-data/PGS000957.txt.gz,test-data/PGS000958.txt.gz", "--out", "test-data-output/output.csv", 47 | "--report-json", "test-data-output/report.json", "--writeEffects", "test-data-output/effects.txt" }; 48 | int result = new CommandLine(new ApplyScoreCommand()).execute(args); 49 | assertEquals(0, result); 50 | 51 | // chunks 52 | 53 | int lengthChr20 = 64444167; 54 | int chunkSize = 10000000; 55 | int chunks = (lengthChr20 / chunkSize); 56 | if (lengthChr20 % chunkSize > 0) { 57 | chunks++; 58 | } 59 | 60 | String[] effectsFiles = new String[chunks]; 61 | String[] chunkFiles = new String[chunks]; 62 | String[] reportFiles = new String[chunks]; 63 | 64 | int count = 0; 65 | for (int i = 1; i <= lengthChr20; i += chunkSize) { 66 | int start = i; 67 | int end = i + chunkSize - 1; 68 | String chunk = "test-data-output/output" + start + "_" + end + ".csv"; 69 | String report = "test-data-output/output" + start + "_" + end + ".json"; 70 | String effects = "test-data-output/effects" + start + "_" + end + ".txt"; 71 | args = new String[] { "test-data/chr20.dose.vcf.gz", "--ref", 72 | "test-data/PGS000957.txt.gz,test-data/PGS000958.txt.gz", "--start", start + "", "--end", end + "", 73 | "--out", chunk, "--report-json", report, "--writeEffects", effects }; 74 | result = new CommandLine(new ApplyScoreCommand()).execute(args); 75 | assertEquals(0, result); 76 | 77 | chunkFiles[count] = chunk; 78 | reportFiles[count] = report; 79 | effectsFiles[count] = effects; 80 | count++; 81 | } 82 | 83 | args = new String[effectsFiles.length + 2]; 84 | for (int i = 0; i < effectsFiles.length; i++) { 85 | args[i] = effectsFiles[i]; 86 | } 87 | args[effectsFiles.length] = "--out"; 88 | args[effectsFiles.length + 1] = "test-data-output/effects.merged.txt"; 89 | 90 | result = new CommandLine(new MergeEffectsCommand()).execute(args); 91 | assertEquals(0, result); 92 | 93 | assertEquals(FileUtil.readFileAsString("test-data-output/effects.txt"), 94 | FileUtil.readFileAsString("test-data-output/effects.merged.txt")); 95 | 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/genepi/riskscore/commands/MergeVariantsCommandTest.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | 6 | import java.util.HashMap; 7 | 8 | import org.junit.Before; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | 12 | import genepi.io.FileUtil; 13 | import genepi.io.table.reader.CsvTableReader; 14 | import genepi.io.table.reader.ITableReader; 15 | import genepi.riskscore.io.PGSCatalog; 16 | import genepi.riskscore.io.VariantFile; 17 | import lukfor.progress.TaskService; 18 | import picocli.CommandLine; 19 | 20 | public class MergeVariantsCommandTest { 21 | 22 | @BeforeClass 23 | public static void setup() { 24 | TaskService.setAnsiSupport(false); 25 | PGSCatalog.ENABLE_CACHE = false; 26 | } 27 | 28 | @Before 29 | public void beforeTest() { 30 | System.out.println("Clean up output directory"); 31 | FileUtil.deleteDirectory("test-data-output"); 32 | FileUtil.createDirectory("test-data-output"); 33 | } 34 | 35 | @Test 36 | public void testMergingChunks() throws Exception { 37 | 38 | // Whole file 39 | String[] args = { "test-data/chr20.dose.vcf.gz", "--ref", 40 | "test-data/PGS000957.txt.gz,test-data/PGS000958.txt.gz", "--out", "test-data-output/output.csv", 41 | "--report-json", "test-data-output/report.json", "--writeVariants", "test-data-output/variants.txt" }; 42 | int result = new CommandLine(new ApplyScoreCommand()).execute(args); 43 | assertEquals(0, result); 44 | 45 | // chunks 46 | 47 | int lengthChr20 = 64444167; 48 | int chunkSize = 10000000; 49 | int chunks = (lengthChr20 / chunkSize); 50 | if (lengthChr20 % chunkSize > 0) { 51 | chunks++; 52 | } 53 | 54 | String[] variantFiles = new String[chunks]; 55 | String[] chunkFiles = new String[chunks]; 56 | String[] reportFiles = new String[chunks]; 57 | 58 | int count = 0; 59 | for (int i = 1; i <= lengthChr20; i += chunkSize) { 60 | int start = i; 61 | int end = i + chunkSize - 1; 62 | String chunk = "test-data-output/output" + start + "_" + end + ".csv"; 63 | String report = "test-data-output/output" + start + "_" + end + ".json"; 64 | String variants = "test-data-output/variants" + start + "_" + end + ".txt"; 65 | args = new String[] { "test-data/chr20.dose.vcf.gz", "--ref", 66 | "test-data/PGS000957.txt.gz,test-data/PGS000958.txt.gz", "--start", start + "", "--end", end + "", 67 | "--out", chunk, "--report-json", report, "--writeVariants", variants }; 68 | result = new CommandLine(new ApplyScoreCommand()).execute(args); 69 | assertEquals(0, result); 70 | 71 | chunkFiles[count] = chunk; 72 | reportFiles[count] = report; 73 | variantFiles[count] = variants; 74 | count++; 75 | } 76 | 77 | args = new String[variantFiles.length + 2]; 78 | for (int i = 0; i < variantFiles.length; i++) { 79 | args[i] = variantFiles[i]; 80 | } 81 | args[variantFiles.length] = "--out"; 82 | args[variantFiles.length + 1] = "test-data-output/variants.merged.txt"; 83 | 84 | result = new CommandLine(new MergeVariantsCommand()).execute(args); 85 | assertEquals(0, result); 86 | 87 | // compare files (order difference of not included variants) 88 | ITableReader reader = new CsvTableReader("test-data-output/variants.txt", VariantFile.SEPARATOR); 89 | HashMap variants = new HashMap(); 90 | while (reader.next()) { 91 | int position = reader.getInteger(VariantFile.POSITION); 92 | int include = reader.getInteger(VariantFile.INCLUDE); 93 | variants.put(position, include); 94 | } 95 | reader.close(); 96 | 97 | ITableReader reader2 = new CsvTableReader("test-data-output/variants.merged.txt", VariantFile.SEPARATOR); 98 | while (reader2.next()) { 99 | int position = reader2.getInteger(VariantFile.POSITION); 100 | Integer include = reader2.getInteger(VariantFile.INCLUDE); 101 | Integer expectIncluded = variants.get(position); 102 | assertNotNull(expectIncluded); 103 | assertEquals(expectIncluded, include); 104 | } 105 | reader2.close(); 106 | 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/genepi/riskscore/commands/ResolveScoreCommandTest.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.commands; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Before; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | 9 | import genepi.io.FileUtil; 10 | import genepi.io.table.reader.CsvTableReader; 11 | import genepi.io.table.reader.ITableReader; 12 | import genepi.riskscore.io.PGSCatalog; 13 | import lukfor.progress.TaskService; 14 | import picocli.CommandLine; 15 | 16 | public class ResolveScoreCommandTest { 17 | 18 | public static String DBSNP_INDEX = "test-data/dbsnp-index.small.txt.gz"; 19 | 20 | public static final int EXPECTED_SAMPLES = 51; 21 | 22 | @BeforeClass 23 | public static void setup() { 24 | TaskService.setAnsiSupport(false); 25 | PGSCatalog.ENABLE_CACHE = false; 26 | } 27 | 28 | @Before 29 | public void beforeTest() { 30 | System.out.println("Clean up output directory"); 31 | FileUtil.deleteDirectory("test-data-output"); 32 | FileUtil.createDirectory("test-data-output"); 33 | } 34 | 35 | @Test 36 | public void testCall() { 37 | 38 | String[] args = { "--in", "test-data/PGS000001.txt.gz", "--out", "test-data-output/PGS000001.converted.txt", 39 | "--dbsnp", DBSNP_INDEX }; 40 | int result = new CommandLine(new ResolveScoreCommand()).execute(args); 41 | assertEquals(0, result); 42 | 43 | int variants = 0; 44 | ITableReader reader = new CsvTableReader("test-data-output/PGS000001.converted.txt", '\t'); 45 | while (reader.next()) { 46 | variants++; 47 | 48 | } 49 | assertEquals(77, variants); 50 | reader.close(); 51 | } 52 | 53 | @Test 54 | public void testResolveofPGSId() { 55 | 56 | String[] args = { "--in", "PGS000001", "--out", "test-data-output/PGS000001.converted.txt", "--dbsnp", 57 | DBSNP_INDEX }; 58 | int result = new CommandLine(new ResolveScoreCommand()).execute(args); 59 | assertEquals(0, result); 60 | 61 | int variants = 0; 62 | ITableReader reader = new CsvTableReader("test-data-output/PGS000001.converted.txt", '\t'); 63 | while (reader.next()) { 64 | variants++; 65 | 66 | } 67 | assertEquals(77, variants); 68 | reader.close(); 69 | } 70 | 71 | @Test 72 | public void testResolveofFileWithPositions() { 73 | 74 | String[] args = { "--in", "test-data/PGS000957.txt.gz", "--out", "test-data-output/PGS000899.converted.txt", "--dbsnp", 75 | DBSNP_INDEX }; 76 | int result = new CommandLine(new ResolveScoreCommand()).execute(args); 77 | assertEquals(0, result); 78 | 79 | int variants = 0; 80 | ITableReader reader = new CsvTableReader("test-data-output/PGS000899.converted.txt", '\t'); 81 | while (reader.next()) { 82 | variants++; 83 | 84 | } 85 | assertEquals(11276, variants); 86 | reader.close(); 87 | } 88 | 89 | @Test 90 | public void testResolveofFileWithPositionsAndChain() { 91 | String[] args = { "--in", "test-data/PGS000957.txt.gz", "--out", "test-data-output/PGS000899.converted.txt", "--dbsnp", 92 | DBSNP_INDEX, "--chain", "test-data/chains/hg19ToHg38.over.chain.gz" }; 93 | int result = new CommandLine(new ResolveScoreCommand()).execute(args); 94 | assertEquals(0, result); 95 | 96 | int variants = 0; 97 | ITableReader reader = new CsvTableReader("test-data-output/PGS000899.converted.txt", '\t'); 98 | while (reader.next()) { 99 | variants++; 100 | 101 | } 102 | assertEquals(11276, variants); 103 | reader.close(); 104 | } 105 | 106 | @Test 107 | public void testResolvePRSWeb() { 108 | String[] args = { "--in", "test-data/PRSWEB_PHECODE153_CRC-Huyghe_PT_UKB_20200608.txt", "--out", "test-data-output/PRSWEB_PHECODE153_CRC-Huyghe_PT_UKB_20200608.hg38.txt", "--dbsnp", 109 | DBSNP_INDEX, "--chain", "test-data/chains/hg19ToHg38.over.chain.gz" }; 110 | int result = new CommandLine(new ResolveScoreCommand()).execute(args); 111 | assertEquals(0, result); 112 | } 113 | 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/genepi/riskscore/io/RiskScoreFileTest.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertNull; 6 | 7 | import org.junit.BeforeClass; 8 | import org.junit.Test; 9 | 10 | import genepi.riskscore.io.formats.RiskScoreFormatFactory.RiskScoreFormat; 11 | 12 | public class RiskScoreFileTest { 13 | 14 | public static String DBSNP_INDEX = "test-data/dbsnp-index.small.txt.gz"; 15 | 16 | @BeforeClass 17 | public static void setup() { 18 | PGSCatalog.ENABLE_CACHE = false; 19 | } 20 | 21 | @Test 22 | public void testLoadTextFile() throws Exception { 23 | RiskScoreFile file = new RiskScoreFile("test-data/chr20.scores.csv", RiskScoreFormat.MAPPING_FILE, DBSNP_INDEX, 24 | null); 25 | file.buildIndex("20"); 26 | assertEquals(4, file.getTotalVariants()); 27 | assertNotNull(file.getVariant(61795)); 28 | assertNull(file.getVariant(55)); 29 | } 30 | 31 | @Test 32 | public void testLoadGZFile() throws Exception { 33 | RiskScoreFile file = new RiskScoreFile("test-data/chr20.scores.csv.gz", RiskScoreFormat.MAPPING_FILE, 34 | DBSNP_INDEX, null); 35 | file.buildIndex("20"); 36 | assertEquals(4, file.getTotalVariants()); 37 | assertNotNull(file.getVariant(61795)); 38 | assertNull(file.getVariant(55)); 39 | } 40 | 41 | @Test 42 | public void testGetName() throws Exception { 43 | assertEquals("PGS000027", RiskScoreFile.getName("PGS000027")); 44 | assertEquals("PGS000027", RiskScoreFile.getName("PGS000027.txt.gz")); 45 | assertEquals("PGS000027", RiskScoreFile.getName("PGS000027.txt")); 46 | assertEquals("PGS000027", RiskScoreFile.getName("folder/path/PGS000027.txt.gz")); 47 | assertEquals("PGS000027", RiskScoreFile.getName("folder/path/PGS000027.txt")); 48 | assertEquals("filename", RiskScoreFile.getName("folder/path/filename.txt.gz")); 49 | assertEquals("filename", RiskScoreFile.getName("folder/path/filename.txt")); 50 | assertEquals("filename", RiskScoreFile.getName("folder/path/filename.csv")); 51 | assertEquals("filename.weights", RiskScoreFile.getName("folder/path/filename.weights")); 52 | } 53 | 54 | @Test 55 | public void testLoadTextFileMissingAlleleInOtherChromosome() throws Exception { 56 | RiskScoreFile file = new RiskScoreFile("test-data/PGS000899.txt.gz", DBSNP_INDEX, null); 57 | file.buildIndex("1"); 58 | assertEquals(17, file.getLoadedVariants()); 59 | assertEquals(176, file.getTotalVariants()); 60 | } 61 | 62 | @Test 63 | public void testLoadTextFileMissingAllele() throws Exception { 64 | RiskScoreFile file = new RiskScoreFile("test-data/PGS000899.txt.gz", DBSNP_INDEX, null); 65 | file.buildIndex("11"); 66 | assertEquals(176, file.getTotalVariants()); 67 | assertEquals(1, file.getIgnoredVariants()); 68 | } 69 | 70 | @Test 71 | public void testLoadRsIdFormatFromPGSCatalog() throws Exception { 72 | RiskScoreFile file = new RiskScoreFile("PGS000001", DBSNP_INDEX, null); 73 | file.buildIndex("1"); 74 | assertEquals(5, file.getLoadedVariants()); 75 | assertEquals(77, file.getTotalVariants()); 76 | } 77 | 78 | @Test 79 | public void testLoadRsIdFormatFromFile() throws Exception { 80 | RiskScoreFile file = new RiskScoreFile("test-data/PGS000001.txt.gz", DBSNP_INDEX, null); 81 | file.buildIndex("1"); 82 | assertEquals(5, file.getLoadedVariants()); 83 | assertEquals(77, file.getTotalVariants()); 84 | } 85 | 86 | @Test 87 | public void testLoadRsIdFormatV1AndV2() throws Exception { 88 | 89 | for (int i = 1; i <= 22; i++) { 90 | RiskScoreFile file = new RiskScoreFile("test-data/PGS000957.txt.gz", DBSNP_INDEX, null); 91 | file.buildIndex(i + ""); 92 | } 93 | 94 | RiskScoreFile file = new RiskScoreFile("test-data/PGS000957.txt.gz", DBSNP_INDEX, null); 95 | file.buildIndex("6"); 96 | assertEquals(11276, file.getTotalVariants()); 97 | assertEquals(1, file.getIgnoredVariants()); 98 | 99 | for (int i = 1; i <= 22; i++) { 100 | RiskScoreFile file2 = new RiskScoreFile("test-data/PGS000958.txt.gz", DBSNP_INDEX, null); 101 | file2.buildIndex(i + ""); 102 | } 103 | 104 | RiskScoreFile file2 = new RiskScoreFile("test-data/PGS000958.txt.gz", DBSNP_INDEX, null); 105 | file2.buildIndex("6"); 106 | assertEquals(9400, file2.getTotalVariants()); 107 | assertEquals(1, file2.getIgnoredVariants()); 108 | 109 | } 110 | 111 | @Test 112 | public void testLoadTextFileWithProxies() throws Exception { 113 | RiskScoreFile file = new RiskScoreFile("test-data/PGS000899.txt.gz", DBSNP_INDEX, null); 114 | file.buildIndex("1"); 115 | assertEquals(17, file.getLoadedVariants()); 116 | assertEquals(176, file.getTotalVariants()); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/test/java/genepi/riskscore/io/dbsnp/DbSnpReaderTest.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.dbsnp; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.BeforeClass; 6 | import org.junit.Test; 7 | 8 | public class DbSnpReaderTest { 9 | 10 | public static String DBSNP_INDEX = "test-data/dbsnp-index.small.txt.gz"; 11 | 12 | @BeforeClass 13 | public static void setup() { 14 | 15 | } 16 | 17 | @Test 18 | public void testGetContig() throws Exception { 19 | assertEquals("rs1000", DbSnpReader.getContig("rs1000140000", 3)); 20 | assertEquals("rs100", DbSnpReader.getContig("rs1001300000", 3)); 21 | assertEquals("rs00", DbSnpReader.getContig("rs001200000", 3)); 22 | assertEquals("rs00", DbSnpReader.getContig("rs00120", 3)); 23 | assertEquals("rs", DbSnpReader.getContig("rs10120", 3)); 24 | } 25 | 26 | @Test 27 | public void testGetPosition() throws Exception { 28 | assertEquals(140000, DbSnpReader.getPosition("rs1000140000", 3)); 29 | assertEquals(1300000, DbSnpReader.getPosition("rs1001300000", 3)); 30 | assertEquals(1200000, DbSnpReader.getPosition("rs001200000", 3)); 31 | assertEquals(120, DbSnpReader.getPosition("rs00120", 3)); 32 | assertEquals(10120, DbSnpReader.getPosition("rs10120", 3)); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/genepi/riskscore/io/proxy/ProxyReaderTest.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.io.proxy; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.IOException; 6 | 7 | import org.junit.BeforeClass; 8 | import org.junit.Test; 9 | 10 | import genepi.riskscore.io.proxy.ProxyReader.ProxySnp; 11 | 12 | public class ProxyReaderTest { 13 | 14 | public static String PROXY_INDEX = "test-data/lpa.snps.sorted.txt.gz"; 15 | 16 | @BeforeClass 17 | public static void setup() { 18 | 19 | } 20 | 21 | @Test 22 | public void testGetProxiesForEntry() throws Exception { 23 | ProxyReader reader = new ProxyReader(PROXY_INDEX); 24 | ProxySnp[] proxies = reader.getByPosition("6", 160447669, "G", "A"); 25 | assertEquals(3, proxies.length); 26 | reader.close(); 27 | } 28 | 29 | @Test 30 | public void testGetProxiesForNonExistsingEntry() throws Exception { 31 | ProxyReader reader = new ProxyReader(PROXY_INDEX); 32 | ProxySnp[] proxies = reader.getByPosition("6", 123, "G", "A"); 33 | assertEquals(0, proxies.length); 34 | reader.close(); 35 | } 36 | 37 | @Test 38 | public void testGetProxiesForEntryWithWrongAlleles() throws Exception { 39 | ProxyReader reader = new ProxyReader(PROXY_INDEX); 40 | ProxySnp[] proxies = reader.getByPosition("6", 160447669, "G", "C"); 41 | assertEquals(0, proxies.length); 42 | reader.close(); 43 | } 44 | 45 | @Test 46 | public void testAlleleMapping() throws Exception { 47 | ProxyReader reader = new ProxyReader(PROXY_INDEX); 48 | ProxySnp[] proxies = reader.getByPosition("6", 160447669, "G", "A"); 49 | assertEquals("A", proxies[0].mapAllele("G")); 50 | assertEquals("T", proxies[0].mapAllele("A")); 51 | assertEquals("C", proxies[1].mapAllele("G")); 52 | assertEquals("G", proxies[1].mapAllele("A")); 53 | assertEquals("G", proxies[2].mapAllele("G")); 54 | assertEquals("A", proxies[2].mapAllele("A")); 55 | reader.close(); 56 | } 57 | 58 | @Test(expected = IOException.class) 59 | public void testWrongAlleleMapping() throws IOException { 60 | ProxyReader reader = new ProxyReader(PROXY_INDEX); 61 | ProxySnp[] proxies = reader.getByPosition("6", 160447669, "G", "A"); 62 | proxies[0].mapAllele("C"); 63 | reader.close(); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/genepi/riskscore/tasks/CreateHtmlReportTaskTest.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.tasks; 2 | 3 | import org.junit.Before; 4 | import org.junit.BeforeClass; 5 | import org.junit.Test; 6 | 7 | import genepi.io.FileUtil; 8 | import genepi.riskscore.io.OutputFile; 9 | import genepi.riskscore.io.PGSCatalog; 10 | import genepi.riskscore.io.ReportFile; 11 | import lukfor.progress.TaskService; 12 | import lukfor.progress.tasks.monitors.TaskMonitorMock; 13 | 14 | public class CreateHtmlReportTaskTest { 15 | 16 | @BeforeClass 17 | public static void setup() { 18 | TaskService.setAnsiSupport(false); 19 | PGSCatalog.ENABLE_CACHE = false; 20 | } 21 | 22 | @Before 23 | public void beforeTest() { 24 | System.out.println("Clean up output directory"); 25 | FileUtil.deleteDirectory("test-data-output"); 26 | FileUtil.createDirectory("test-data-output"); 27 | } 28 | 29 | @Test 30 | public void testReport() throws Exception { 31 | 32 | ReportFile report = ReportFile.loadFromFile("test-data/report.json"); 33 | OutputFile data = new OutputFile("test-data/output.csv"); 34 | 35 | CreateHtmlReportTask task = new CreateHtmlReportTask(); 36 | task.setData(data); 37 | task.setReport(report); 38 | task.setOutput("test-data-output/report.html"); 39 | task.run(new TaskMonitorMock()); 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/genepi/riskscore/tasks/MergeEffectsTaskTest.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.tasks; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Before; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | 9 | import genepi.io.FileUtil; 10 | import genepi.riskscore.commands.ApplyScoreCommand; 11 | import genepi.riskscore.io.PGSCatalog; 12 | import lukfor.progress.TaskService; 13 | import lukfor.progress.tasks.monitors.TaskMonitorMock; 14 | import picocli.CommandLine; 15 | 16 | public class MergeEffectsTaskTest { 17 | 18 | @BeforeClass 19 | public static void setup() { 20 | TaskService.setAnsiSupport(false); 21 | PGSCatalog.ENABLE_CACHE = false; 22 | } 23 | 24 | @Before 25 | public void beforeTest() { 26 | System.out.println("Clean up output directory"); 27 | FileUtil.deleteDirectory("test-data-output"); 28 | FileUtil.createDirectory("test-data-output"); 29 | } 30 | 31 | @Test 32 | public void testMerge() throws Exception { 33 | 34 | MergeEffectsTask task = new MergeEffectsTask(); 35 | task.setInputs("test-data/effects.chunk1.txt", "test-data/effects.chunk2.txt"); 36 | task.setOutput("test-data-output/effects.task.txt"); 37 | task.run(new TaskMonitorMock()); 38 | 39 | assertEquals(FileUtil.readFileAsString("test-data/effects.expected.txt"), 40 | FileUtil.readFileAsString("test-data-output/effects.task.txt")); 41 | } 42 | 43 | @Test 44 | public void testMergingChunks() throws Exception { 45 | 46 | // Whole file 47 | String[] args = { "test-data/chr20.dose.vcf.gz", "--ref", "test-data/PGS000957.txt.gz,test-data/PGS000958.txt.gz", "--out", "test-data-output/output.csv", 48 | "--report-json", "test-data-output/report.json", "--writeEffects", "test-data-output/effects.txt" }; 49 | int result = new CommandLine(new ApplyScoreCommand()).execute(args); 50 | assertEquals(0, result); 51 | 52 | // chunks 53 | 54 | int lengthChr20 = 64444167; 55 | int chunkSize = 10000000; 56 | int chunks = (lengthChr20 / chunkSize); 57 | if (lengthChr20 % chunkSize > 0) { 58 | chunks++; 59 | } 60 | 61 | String[] effectsFiles = new String[chunks]; 62 | String[] chunkFiles = new String[chunks]; 63 | String[] reportFiles = new String[chunks]; 64 | 65 | int count = 0; 66 | for (int i = 1; i <= lengthChr20; i += chunkSize) { 67 | int start = i; 68 | int end = i + chunkSize - 1; 69 | String chunk = "test-data-output/output" + start + "_" + end + ".csv"; 70 | String report = "test-data-output/output" + start + "_" + end + ".json"; 71 | String effects = "test-data-output/effects" + start + "_" + end + ".txt"; 72 | args = new String[] { "test-data/chr20.dose.vcf.gz", "--ref", "test-data/PGS000957.txt.gz,test-data/PGS000958.txt.gz", "--start", start + "", 73 | "--end", end + "", "--out", chunk, "--report-json", report, "--writeEffects", effects }; 74 | result = new CommandLine(new ApplyScoreCommand()).execute(args); 75 | assertEquals(0, result); 76 | 77 | chunkFiles[count] = chunk; 78 | reportFiles[count] = report; 79 | effectsFiles[count] = effects; 80 | count++; 81 | } 82 | 83 | MergeEffectsTask task = new MergeEffectsTask(); 84 | task.setInputs(effectsFiles); 85 | task.setOutput("test-data-output/effects.merged.txt"); 86 | task.run(new TaskMonitorMock()); 87 | 88 | assertEquals(FileUtil.readFileAsString("test-data-output/effects.txt"), FileUtil.readFileAsString("test-data-output/effects.merged.txt")); 89 | 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/genepi/riskscore/tasks/MergeVariantsTaskTest.java: -------------------------------------------------------------------------------- 1 | package genepi.riskscore.tasks; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | 6 | import java.util.HashMap; 7 | 8 | import org.junit.Before; 9 | import org.junit.BeforeClass; 10 | import org.junit.Test; 11 | 12 | import genepi.io.FileUtil; 13 | import genepi.io.table.reader.CsvTableReader; 14 | import genepi.io.table.reader.ITableReader; 15 | import genepi.riskscore.commands.ApplyScoreCommand; 16 | import genepi.riskscore.io.PGSCatalog; 17 | import genepi.riskscore.io.VariantFile; 18 | import lukfor.progress.TaskService; 19 | import lukfor.progress.tasks.monitors.TaskMonitorMock; 20 | import picocli.CommandLine; 21 | 22 | public class MergeVariantsTaskTest { 23 | 24 | @BeforeClass 25 | public static void setup() { 26 | TaskService.setAnsiSupport(false); 27 | PGSCatalog.ENABLE_CACHE = false; 28 | } 29 | 30 | @Before 31 | public void beforeTest() { 32 | System.out.println("Clean up output directory"); 33 | FileUtil.deleteDirectory("test-data-output"); 34 | FileUtil.createDirectory("test-data-output"); 35 | } 36 | 37 | @Test 38 | public void testMergingChunks() throws Exception { 39 | 40 | // Whole file 41 | String[] args = { "test-data/chr20.dose.vcf.gz", "--ref", 42 | "test-data/PGS000957.txt.gz,test-data/PGS000958.txt.gz", "--out", "test-data-output/output.csv", 43 | "--report-json", "test-data-output/report.json", "--writeVariants", "test-data-output/variants.txt" }; 44 | int result = new CommandLine(new ApplyScoreCommand()).execute(args); 45 | assertEquals(0, result); 46 | 47 | // chunks 48 | 49 | int lengthChr20 = 64444167; 50 | int chunkSize = 10000000; 51 | int chunks = (lengthChr20 / chunkSize); 52 | if (lengthChr20 % chunkSize > 0) { 53 | chunks++; 54 | } 55 | 56 | String[] variantFiles = new String[chunks]; 57 | String[] chunkFiles = new String[chunks]; 58 | String[] reportFiles = new String[chunks]; 59 | 60 | int count = 0; 61 | for (int i = 1; i <= lengthChr20; i += chunkSize) { 62 | int start = i; 63 | int end = i + chunkSize - 1; 64 | String chunk = "test-data-output/output" + start + "_" + end + ".csv"; 65 | String report = "test-data-output/output" + start + "_" + end + ".json"; 66 | String variants = "test-data-output/variants" + start + "_" + end + ".txt"; 67 | args = new String[] { "test-data/chr20.dose.vcf.gz", "--ref", 68 | "test-data/PGS000957.txt.gz,test-data/PGS000958.txt.gz", "--start", start + "", "--end", end + "", 69 | "--out", chunk, "--report-json", report, "--writeVariants", variants }; 70 | result = new CommandLine(new ApplyScoreCommand()).execute(args); 71 | assertEquals(0, result); 72 | 73 | chunkFiles[count] = chunk; 74 | reportFiles[count] = report; 75 | variantFiles[count] = variants; 76 | count++; 77 | } 78 | 79 | MergeVariantsTask task = new MergeVariantsTask(); 80 | task.setInputs(variantFiles); 81 | task.setOutput("test-data-output/variants.merged.txt"); 82 | task.run(new TaskMonitorMock()); 83 | 84 | //compare files (order difference of not included variants) 85 | ITableReader reader = new CsvTableReader("test-data-output/variants.txt", VariantFile.SEPARATOR); 86 | HashMap variants = new HashMap(); 87 | while(reader.next()) { 88 | int position = reader.getInteger(VariantFile.POSITION); 89 | int include = reader.getInteger(VariantFile.INCLUDE); 90 | variants.put(position, include); 91 | } 92 | reader.close(); 93 | 94 | 95 | ITableReader reader2 = new CsvTableReader("test-data-output/variants.merged.txt", VariantFile.SEPARATOR); 96 | while(reader2.next()) { 97 | int position = reader2.getInteger(VariantFile.POSITION); 98 | Integer include = reader2.getInteger(VariantFile.INCLUDE); 99 | Integer expectIncluded = variants.get(position); 100 | assertNotNull(expectIncluded); 101 | assertEquals(expectIncluded, include); 102 | } 103 | reader2.close(); 104 | 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /test-data/.gitignore: -------------------------------------------------------------------------------- 1 | /chr20.big.dose.vcf.gz 2 | /PGS000001.txt.gz.positions 3 | -------------------------------------------------------------------------------- /test-data/PGS000001.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/PGS000001.txt.gz -------------------------------------------------------------------------------- /test-data/PGS000018.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/PGS000018.txt.gz -------------------------------------------------------------------------------- /test-data/PGS000781.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/PGS000781.txt.gz -------------------------------------------------------------------------------- /test-data/PGS000899.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/PGS000899.txt.gz -------------------------------------------------------------------------------- /test-data/PGS000957.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/PGS000957.txt.gz -------------------------------------------------------------------------------- /test-data/PGS000958.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/PGS000958.txt.gz -------------------------------------------------------------------------------- /test-data/PRSWEB_PHECODE153_CRC-Huyghe_PT_UKB_20200608.txt: -------------------------------------------------------------------------------- 1 | ## PRSweb reference PRSWEB_PHECODE153_CRC-Huyghe_PT_UKB_20200608 2 | ## PRSweb LD reference MGI 3 | ## PRSweb date 20200608 4 | ## GWAS source 30510241 5 | ## GWAS reference PUBMED 6 | ## GWAS phenotype Colorectal cancer 7 | ## GWAS id CRC_Huyghe 8 | ## GWAS URL https://www.nature.com/articles/s41588-018-0286-6#Sec35 9 | ## PRS method LD Clumping (MAF >= 1%, r^2 <= 0.1) & P-value thresholding (see tuning parameter) 10 | ## PRS tuning parameter 7.8e-06 11 | ## PRS evaluation in UKB 12 | ## Genome build GRCh37/hg19 13 | CHROM POS REF ALT EA OA PVALUE WEIGHT 14 | 1 38455891 G C G C 3.8e-09 0.0523 15 | 1 55246035 T C C T 3.3e-11 0.0665 16 | 1 183002639 A G A G 2.4e-16 0.073 17 | 1 222112634 A G G A 6.1e-16 0.0877 18 | 2 159964552 T C C T 4.4e-08 0.0511 19 | 2 199612407 T C C T 5e-09 0.0535 20 | 2 199781586 T C T C 3.7e-11 0.0627 21 | 2 219191256 T C T C 1.5e-11 0.0613 22 | 3 40915239 A G G A 1.2e-16 0.0994 23 | 3 66365163 G A A G 7.1e-08 0.0597 24 | 3 112999560 G A G A 1.4e-08 0.1761 25 | 3 133701119 G A A G 3.8e-09 0.0597 26 | 3 169517436 C T C T 7.8e-06 0.0453 27 | 4 94938618 C A A C 1.2e-08 0.052 28 | 4 106128760 G A A G 1.6e-08 0.0522 29 | 4 145659064 T C C T 2.9e-08 0.0842 30 | 5 1240204 C T T C 5.1e-09 0.1119 31 | 5 1296486 A G G A 1.4e-22 0.0865 32 | 5 40102443 G A A G 4.2e-09 0.0545 33 | 5 40280076 G A A G 9.3e-25 0.1013 34 | 5 134467220 C T C T 4.8e-15 0.0693 35 | 6 31449620 C T C T 1.8e-10 0.1118 36 | 6 32593080 A G G A 4.9e-14 0.0889 37 | 6 35569562 A G A G 3.6e-08 0.0778 38 | 6 36623379 G A A G 8.6e-08 0.054 39 | 6 55712124 C T C T 1.1e-11 0.0724 40 | 7 45136423 T C T C 4.7e-08 0.065 41 | 8 117630683 A C C A 7.3e-28 0.2099 42 | 8 128413305 G T G T 1.1e-15 0.1052 43 | 8 128571855 G T G T 1.8e-09 0.0608 44 | 9 22103183 G T G T 1.4e-08 0.0504 45 | 9 101679752 T G T G 3.1e-08 0.0818 46 | 9 113671403 T C C T 2.8e-09 0.0637 47 | 10 8739580 T A T A 1.3e-25 0.1064 48 | 10 52648454 C T C T 5e-10 0.073 49 | 10 80819132 A G G A 1.8e-17 0.0765 50 | 10 101351704 A G G A 1e-17 0.0889 51 | 10 114288619 T C C T 1.3e-11 0.0975 52 | 10 114722621 G A A G 7e-07 0.0527 53 | 11 61549025 G A G A 1.2e-11 0.0636 54 | 11 74280012 T G G T 8.9e-19 0.078 55 | 11 74427921 C T C T 3.7e-16 0.1934 56 | 11 101656397 T A T A 1.1e-09 0.0537 57 | 11 111156836 T C T C 1.9e-31 0.1122 58 | 12 4368607 T C C T 3.6e-14 0.089 59 | 12 4388271 C T T C 1.6e-15 0.1181 60 | 12 4400808 C T T C 2.4e-09 0.055 61 | 12 6421174 A T T A 4.1e-09 0.0597 62 | 12 43134191 A G G A 1.3e-09 0.053 63 | 12 51171090 A G G A 1.9e-23 0.0896 64 | 12 57533690 C A A C 9.4e-09 0.053 65 | 12 111973358 A G G A 2.6e-16 0.0737 66 | 12 115890922 T C C T 8.1e-14 0.066 67 | 13 34092164 C T C T 3.4e-07 0.0468 68 | 13 37462010 A G G A 6.3e-13 0.0758 69 | 13 73791554 T C C T 2.6e-08 0.0982 70 | 13 111075881 C T T C 1.8e-09 0.0549 71 | 14 54419106 A C C A 2.1e-23 0.0912 72 | 14 54445157 G A G A 3.1e-07 0.0465 73 | 14 59189361 G A G A 9.9e-07 0.0691 74 | 15 32992836 G A G A 1.1e-06 0.0464 75 | 15 33010736 G A A G 2.3e-29 0.1248 76 | 15 33156386 G A A G 1.5e-10 0.0705 77 | 15 67402824 T C C T 2.4e-13 0.0689 78 | 16 68743939 A C A C 3.1e-08 0.055 79 | 16 80043258 C A C A 2.1e-08 0.0498 80 | 16 86339315 T C T C 2.8e-08 0.0487 81 | 16 86703949 C T T C 6.6e-06 0.0481 82 | 17 809643 G A G A 6.8e-08 0.0514 83 | 17 10707241 G A A G 6.6e-12 0.0748 84 | 17 70413253 G A A G 5.6e-09 0.0595 85 | 18 46453156 A T A T 3.8e-74 0.1606 86 | 19 16417198 C T T C 4.2e-10 0.0868 87 | 19 33519927 T G T G 3.7e-23 0.1939 88 | 19 41871573 G A A G 9.5e-07 0.0441 89 | 19 59079096 C T T C 4.2e-08 0.0632 90 | 20 6376457 G C G C 1.1e-16 0.0795 91 | 20 6603622 C T C T 6.9e-12 0.0627 92 | 20 6699595 T G G T 2.3e-18 0.0819 93 | 20 6762221 C T T C 3.3e-14 0.0714 94 | 20 7740976 A G G A 3.4e-13 0.0874 95 | 20 33213196 A C C A 3e-07 0.045 96 | 20 42666475 C T T C 6.8e-09 0.0597 97 | 20 47340117 A G A G 5.9e-15 0.0719 98 | 20 49055318 C T C T 3.3e-09 0.0547 99 | 20 60932414 T C C T 1.1e-26 0.1146 100 | 20 62308612 T G T G 5.3e-08 0.0593 101 | -------------------------------------------------------------------------------- /test-data/cancer-prsweb.tab: -------------------------------------------------------------------------------- 1 | id trait trait.type method ancestry_distribution trait.efo publication.doi publication.firstauthor publication.journal publication.date variants samples url.weights url.details repository 2 | PRSWEB_PHECODE153_CRC-Huyghe_PT_UKB_20200608 Colorectal cancer LD Clumping (MAF >= 1%, r^2 <= 0.1) & P-value thresholding 87 https://prsweb.sph.umich.edu:8443/displayData/downloadFile?filename=PRSWEB_PHECODE153_CRC-Huyghe_PT_UKB_20200608&type=weight https://prsweb.sph.umich.edu:8443/displayData/showGraphSep?prswebprefix=PRSWEB_PHECODE153_CRC-Huyghe_PT_UKB_20200608 Cancer-PRSweb 3 | -------------------------------------------------------------------------------- /test-data/chains/hg19ToHg38.over.chain.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/chains/hg19ToHg38.over.chain.gz -------------------------------------------------------------------------------- /test-data/chains/hg38ToHg19.over.chain.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/chains/hg38ToHg19.over.chain.gz -------------------------------------------------------------------------------- /test-data/chr20.dose.vcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/chr20.dose.vcf.gz -------------------------------------------------------------------------------- /test-data/chr20.scores.2.csv: -------------------------------------------------------------------------------- 1 | chr position_hg19 effect_weight A1 A2 effect_allele 2 | 20 222 1 G T G 3 | 20 61795 1 G T G 4 | 20 63231 1 T G T 5 | 20 63244 1 A C A 6 | -------------------------------------------------------------------------------- /test-data/chr20.scores.2.csv.format: -------------------------------------------------------------------------------- 1 | { 2 | "chromosome": "chr", 3 | "position": "position_hg19", 4 | "effect_weight": "effect_weight", 5 | "allele_a": "A1", 6 | "allele_b": "A2", 7 | "effect_allele": "effect_allele" 8 | } 9 | -------------------------------------------------------------------------------- /test-data/chr20.scores.2.flips.csv: -------------------------------------------------------------------------------- 1 | chr position_hg19 effect_weight A1 A2 effect_allele 2 | 20 222 1 G T G 3 | 20 61795 1 G A C 4 | 20 63231 1 T G T 5 | 20 63244 1 A C A 6 | -------------------------------------------------------------------------------- /test-data/chr20.scores.csv: -------------------------------------------------------------------------------- 1 | chr position_hg19 effect_weight A2 effect_allele 2 | 20 222 1 T G 3 | 20 61795 1 G T 4 | 20 63231 1 G T 5 | 20 63244 1 C A -------------------------------------------------------------------------------- /test-data/chr20.scores.csv.format: -------------------------------------------------------------------------------- 1 | { 2 | "chromosome": "chr", 3 | "position": "position_hg19", 4 | "effect_weight": "effect_weight", 5 | "allele_a": "A1", 6 | "allele_b": "A2", 7 | "effect_allele": "effect_allele" 8 | } 9 | -------------------------------------------------------------------------------- /test-data/chr20.scores.csv.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/chr20.scores.csv.gz -------------------------------------------------------------------------------- /test-data/chr20.scores.csv.gz.format: -------------------------------------------------------------------------------- 1 | { 2 | "chromosome": "chr", 3 | "position": "position_hg19", 4 | "effect_weight": "effect_weight", 5 | "allele_a": "A1", 6 | "allele_b": "A2", 7 | "effect_allele": "effect_allele" 8 | } 9 | -------------------------------------------------------------------------------- /test-data/dbsnp-index.small.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/dbsnp-index.small.txt.gz -------------------------------------------------------------------------------- /test-data/dbsnp-index.small.txt.gz.tbi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/dbsnp-index.small.txt.gz.tbi -------------------------------------------------------------------------------- /test-data/effects.chunk1.txt: -------------------------------------------------------------------------------- 1 | "score","sample","chr_name","chr_position","effect" 2 | "chr20.scores","FB00000","20","61795","1.1260000467300415" 3 | "chr20.scores","FB00001","20","61795","0.24199999868869781" 4 | "chr20.scores","FB00002","20","61795","1.6699999570846558" 5 | "chr20.scores","FB00005","20","61795","0.12600000202655792" 6 | "chr20.scores","FB00006","20","61795","0.17800000309944153" 7 | "chr20.scores","FB00012","20","61795","1.0089999437332153" 8 | "chr20.scores","FB00015","20","61795","0.29899999499320984" 9 | "chr20.scores","FB00016","20","61795","0.02199999988079071" 10 | "chr20.scores","FB00017","20","61795","0.4189999997615814" 11 | "chr20.scores","FB00021","20","61795","0.1889999955892563" -------------------------------------------------------------------------------- /test-data/effects.chunk2.txt: -------------------------------------------------------------------------------- 1 | "score","sample","chr_name","chr_position","effect" 2 | "chr20.scores","FB00022","20","61795","0.3190000057220459" 3 | "chr20.scores","FB00023","20","61795","0.14300000667572021" 4 | "chr20.scores","FB00025","20","61795","0.9419999718666077" 5 | "chr20.scores","FB00027","20","61795","0.125" 6 | "chr20.scores","FB00031","20","61795","0.1289999932050705" 7 | "chr20.scores","FB00032","20","61795","0.0" 8 | "chr20.scores","FB00034","20","61795","0.4259999990463257" 9 | "chr20.scores","FB00035","20","61795","0.0" 10 | "chr20.scores","FB00037","20","61795","0.3889999985694885" 11 | "chr20.scores","FB00038","20","61795","0.8420000076293945" 12 | "chr20.scores","FB00039","20","61795","0.847000002861023" 13 | "chr20.scores","FB00040","20","61795","0.9490000009536743" 14 | "chr20.scores","FB00041","20","61795","0.9190000295639038" 15 | "chr20.scores","FB00044","20","61795","1.7330000400543213" 16 | "chr20.scores","FB00049","20","61795","0.0" -------------------------------------------------------------------------------- /test-data/effects.expected.txt: -------------------------------------------------------------------------------- 1 | "score","sample","chr_name","chr_position","effect" 2 | "chr20.scores","FB00000","20","61795","1.1260000467300415" 3 | "chr20.scores","FB00001","20","61795","0.24199999868869781" 4 | "chr20.scores","FB00002","20","61795","1.6699999570846558" 5 | "chr20.scores","FB00005","20","61795","0.12600000202655792" 6 | "chr20.scores","FB00006","20","61795","0.17800000309944153" 7 | "chr20.scores","FB00012","20","61795","1.0089999437332153" 8 | "chr20.scores","FB00015","20","61795","0.29899999499320984" 9 | "chr20.scores","FB00016","20","61795","0.02199999988079071" 10 | "chr20.scores","FB00017","20","61795","0.4189999997615814" 11 | "chr20.scores","FB00021","20","61795","0.1889999955892563" 12 | "chr20.scores","FB00022","20","61795","0.3190000057220459" 13 | "chr20.scores","FB00023","20","61795","0.14300000667572021" 14 | "chr20.scores","FB00025","20","61795","0.9419999718666077" 15 | "chr20.scores","FB00027","20","61795","0.125" 16 | "chr20.scores","FB00031","20","61795","0.1289999932050705" 17 | "chr20.scores","FB00032","20","61795","0.0" 18 | "chr20.scores","FB00034","20","61795","0.4259999990463257" 19 | "chr20.scores","FB00035","20","61795","0.0" 20 | "chr20.scores","FB00037","20","61795","0.3889999985694885" 21 | "chr20.scores","FB00038","20","61795","0.8420000076293945" 22 | "chr20.scores","FB00039","20","61795","0.847000002861023" 23 | "chr20.scores","FB00040","20","61795","0.9490000009536743" 24 | "chr20.scores","FB00041","20","61795","0.9190000295639038" 25 | "chr20.scores","FB00044","20","61795","1.7330000400543213" 26 | "chr20.scores","FB00049","20","61795","0.0" 27 | -------------------------------------------------------------------------------- /test-data/lpa.snps.sorted.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/lpa.snps.sorted.txt.gz -------------------------------------------------------------------------------- /test-data/lpa.snps.sorted.txt.gz.tbi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukfor/pgs-calc/27fbf7f069e8fded26262094e87fe9d0c6ad6a16/test-data/lpa.snps.sorted.txt.gz.tbi -------------------------------------------------------------------------------- /test-data/merged.expected.txt: -------------------------------------------------------------------------------- 1 | "sample","score_a","score_b","score_c" 2 | "s1","2.0","3.0","4.0" 3 | "s2","4.0","5.0","6.0" 4 | "s3","6.0","7.0","8.0" 5 | "s4","8.0","9.0","10.0" 6 | -------------------------------------------------------------------------------- /test-data/output.csv: -------------------------------------------------------------------------------- 1 | "sample","PGS000028","PGS000027" 2 | "FB00000","0.0","-0.025961720261766616" 3 | "FB00001","0.0","-0.020048849751990602" 4 | "FB00002","0.0","-0.047861219584833053" 5 | "FB00005","0.0","-0.008517660085550688" 6 | "FB00006","0.0","-0.028507473051402193" 7 | "FB00012","0.0","-0.016976954977904673" 8 | "FB00015","0.0","-0.008052111183653513" 9 | "FB00016","0.0","-0.007338135556069167" 10 | "FB00017","0.0","-0.09373482723821873" 11 | "FB00021","0.0","-0.03711049969256221" 12 | "FB00022","0.0","-0.023994569098042408" 13 | "FB00023","0.0","-0.021595601391866344" 14 | "FB00025","0.0","-0.008552764278144297" 15 | "FB00027","0.0","-1.8872373326789694E-4" 16 | "FB00031","0.0","-0.05910201053019308" 17 | "FB00032","0.0","-0.014914756934823189" 18 | "FB00034","0.0","-0.032705220944274964" 19 | "FB00035","0.0","-0.038270390860924104" 20 | "FB00037","0.0","-0.019206329756164105" 21 | "FB00038","0.0","-0.015552917670511843" 22 | "FB00039","0.0","0.015619809712159358" 23 | "FB00040","0.0","-0.019048544919921133" 24 | "FB00041","0.0","-0.015143098711813456" 25 | "FB00044","0.0","0.004143125733792969" 26 | "FB00049","0.0","-0.032760009907617876" 27 | "FB00051","0.0","-0.0605292266138332" 28 | "FB00052","0.0","-0.02056019635589343" 29 | "FB00053","0.0","-0.03351202920832491" 30 | "FB00055","0.0","0.005149866284339126" 31 | "FB00056","0.0","0.005537618797143148" 32 | "FB00058","0.0","-0.005899067518679413" 33 | "FB00059","0.0","-0.008890280371722833" 34 | "FB00062","0.0","-0.015711549716511963" 35 | "FB00064","0.0","-0.009927149511591338" 36 | "FB00066","0.0","-0.047951933585074075" 37 | "FB00068","0.0","-0.026174471084150837" 38 | "FB00069","0.0","-0.0025529002573332453" 39 | "FB00071","0.0","-0.015713864439307727" 40 | "FB00072","0.0","-0.018945466763326656" 41 | "FB00074","0.0","-0.008088586143031005" 42 | "FB00075","0.0","0.010882239409677199" 43 | "FB00077","0.0","0.003243515570500382" 44 | "FB00078","0.0","-0.012670152497763123" 45 | "FB00082","0.0","-0.003975532682716764" 46 | "FB00086","0.0","-0.0032545626240586788" 47 | "FB00089","0.0","-0.03556566556392213" 48 | "FB00090","0.0","-0.02846534983234937" 49 | "FB00091","0.0","-0.02899517170631432" 50 | "FB00093","0.0","-0.011138847354749508" 51 | "FB00094","0.0","-0.02899212072805521" 52 | "FB00095","0.0","-0.01738372136863698" 53 | -------------------------------------------------------------------------------- /test-data/pgs-catalog-small.json: -------------------------------------------------------------------------------- 1 | { 2 | "PGS000027": { 3 | "id": "PGS000027", 4 | "trait": "Body Mass Index", 5 | "populations": { 6 | "items": { 7 | "EUR": { 8 | "name": "EUR", 9 | "count": -1, 10 | "percentage": 0.991, 11 | "color": "#B5B5B5" 12 | }, 13 | "AMR": { 14 | "name": "AMR", 15 | "count": -1, 16 | "percentage": 0.005, 17 | "color": "#B5B5B5" 18 | }, 19 | "AFR": { 20 | "name": "AFR", 21 | "count": -1, 22 | "percentage": 0.004, 23 | "color": "#B5B5B5" 24 | } 25 | }, 26 | "total": 238944 27 | }, 28 | "variants": 2100302, 29 | "repository": "PGS-Catalog", 30 | "samples": 238944, 31 | "link": "https://www.pgscatalog.org/score/PGS000027" 32 | }, 33 | "PGS000028": { 34 | "id": "PGS000028", 35 | "trait": "Breast cancer", 36 | "populations": { 37 | "items": { 38 | "EUR": { 39 | "name": "EUR", 40 | "count": -1, 41 | "percentage": 0.807, 42 | "color": "#B5B5B5" 43 | }, 44 | "AMR": { 45 | "name": "AMR", 46 | "count": -1, 47 | "percentage": 0.033, 48 | "color": "#B5B5B5" 49 | }, 50 | "EAS": { 51 | "name": "EAS", 52 | "count": -1, 53 | "percentage": 0.134, 54 | "color": "#B5B5B5" 55 | }, 56 | "AFR": { 57 | "name": "AFR", 58 | "count": -1, 59 | "percentage": 0.025999999, 60 | "color": "#B5B5B5" 61 | } 62 | }, 63 | "total": 144871 64 | }, 65 | "variants": 83, 66 | "repository": "PGS-Catalog", 67 | "samples": 144871, 68 | "link": "https://www.pgscatalog.org/score/PGS000028" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test-data/pgs-ids.txt: -------------------------------------------------------------------------------- 1 | PGSID 2 | PGS000027 3 | PGS000028 -------------------------------------------------------------------------------- /test-data/report.json: -------------------------------------------------------------------------------- 1 | [{"name":"PGS000028","variants":86,"variantsUsed":0,"coverage":0.0,"variantsSwitched":0,"variantsMultiAllelic":0,"variantsAlleleMissmatch":0,"r2Filtered":0,"notFound":63480,"filtered":0,"coverageLabel":"zero"},{"name":"PGS000027","variants":2100302,"variantsUsed":52122,"coverage":0.024816431160852106,"variantsSwitched":25969,"variantsMultiAllelic":0,"variantsAlleleMissmatch":0,"r2Filtered":0,"notFound":11358,"filtered":0,"coverageLabel":"low"}] -------------------------------------------------------------------------------- /test-data/samples-population.txt: -------------------------------------------------------------------------------- 1 | sample population 2 | LF001 EUR 3 | LF002 SAS -------------------------------------------------------------------------------- /test-data/samples.txt: -------------------------------------------------------------------------------- 1 | sample 2 | LF002 -------------------------------------------------------------------------------- /test-data/scores.chunk1.txt: -------------------------------------------------------------------------------- 1 | sample,score_a,score_b,score_c 2 | s1,1,1,1 3 | s2,2,2,2 4 | s3,3,3,3 5 | s4,4,4,4 6 | -------------------------------------------------------------------------------- /test-data/scores.chunk2.txt: -------------------------------------------------------------------------------- 1 | sample,score_a,score_b,score_c 2 | s1,1,2,3 3 | s2,2,3,4 4 | s3,3,4,5 5 | s4,4,5,6 6 | -------------------------------------------------------------------------------- /test-data/single.hg38.vcf: -------------------------------------------------------------------------------- 1 | ##fileformat=VCFv4.1 2 | ##filedate=2020.3.13 3 | ##contig= 4 | ##pipeline=michigan-imputationserver-1.2.4 5 | ##imputation=minimac4-1.0.2 6 | ##phasing=eagle-2.4 7 | ##r2Filter=0.0 8 | ##INFO= 9 | ##INFO= 10 | ##INFO= 11 | ##INFO= 12 | ##INFO= 13 | ##INFO= 14 | ##INFO= 15 | ##FORMAT= 16 | ##FORMAT= 17 | #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT LF001 18 | chr20 61795 20:61795:G:T G T . PASS AF=0.26318;MAF=0.26318;R2=0.54658;IMPUTED GT:DS 1|0:0.1 19 | chr20 63231 20:63231:T:G T G . PASS AF=0.03843;MAF=0.03843;R2=0.67736;IMPUTED GT:DS 0|0:0.2 20 | chr20 63244 20:63244:A:C A C . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.3 21 | chr20 63244 20:63244:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.4 22 | chr20 6324422 20:6324422:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.285:10.0 23 | -------------------------------------------------------------------------------- /test-data/single.vcf: -------------------------------------------------------------------------------- 1 | ##fileformat=VCFv4.1 2 | ##filedate=2020.3.13 3 | ##contig= 4 | ##pipeline=michigan-imputationserver-1.2.4 5 | ##imputation=minimac4-1.0.2 6 | ##phasing=eagle-2.4 7 | ##r2Filter=0.0 8 | ##INFO= 9 | ##INFO= 10 | ##INFO= 11 | ##INFO= 12 | ##INFO= 13 | ##INFO= 14 | ##INFO= 15 | ##FORMAT= 16 | ##FORMAT= 17 | #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT LF001 18 | 20 61795 20:61795:G:T G T . PASS AF=0.26318;MAF=0.26318;R2=0.54658;IMPUTED GT:DS 1|0:0.1 19 | 20 63231 20:63231:T:G T G . PASS AF=0.03843;MAF=0.03843;R2=0.67736;IMPUTED GT:DS 0|0:0.2 20 | 20 63244 20:63244:A:C A C . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.3 21 | 20 63244 20:63244:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.4 22 | 20 6324422 20:6324422:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.285:10.0 23 | -------------------------------------------------------------------------------- /test-data/single.wrong_chr.vcf: -------------------------------------------------------------------------------- 1 | ##fileformat=VCFv4.1 2 | ##filedate=2020.3.13 3 | ##contig= 4 | ##pipeline=michigan-imputationserver-1.2.4 5 | ##imputation=minimac4-1.0.2 6 | ##phasing=eagle-2.4 7 | ##r2Filter=0.0 8 | ##INFO= 9 | ##INFO= 10 | ##INFO= 11 | ##INFO= 12 | ##INFO= 13 | ##INFO= 14 | ##INFO= 15 | ##FORMAT= 16 | ##FORMAT= 17 | #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT LF001 18 | 20 61795 20:61795:G:T G T . PASS AF=0.26318;MAF=0.26318;R2=0.54658;IMPUTED GT:DS 1|0:0.1 19 | 20 63231 20:63231:T:G T G . PASS AF=0.03843;MAF=0.03843;R2=0.67736;IMPUTED GT:DS 0|0:0.2 20 | 20 63244 20:63244:A:C A C . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.3 21 | 20 63244 20:63244:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.4 22 | 21 6324422 21:6324422:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.285:10.0 23 | -------------------------------------------------------------------------------- /test-data/test.chr1.vcf: -------------------------------------------------------------------------------- 1 | ##fileformat=VCFv4.1 2 | ##filedate=2020.3.13 3 | ##contig= 4 | ##pipeline=michigan-imputationserver-1.2.4 5 | ##imputation=minimac4-1.0.2 6 | ##phasing=eagle-2.4 7 | ##r2Filter=0.0 8 | ##INFO= 9 | ##INFO= 10 | ##INFO= 11 | ##INFO= 12 | ##INFO= 13 | ##INFO= 14 | ##INFO= 15 | ##FORMAT= 16 | ##FORMAT= 17 | #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT LF001 LF002 18 | 1 1 1:1:G:T G T . PASS AF=0.26318;MAF=0.26318;R2=0.54658;IMPUTED GT:DS 1|0:0.1 1|0:0.2 19 | 1 2 1:2:T:G T G . PASS AF=0.03843;MAF=0.03843;R2=0.67736;IMPUTED GT:DS 0|0:0.2 1|0:0.4 20 | 1 3 1:3:A:C A C . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.3 1|0:0.8 21 | 1 4 1:4:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.4 1|0:1.6 22 | 1 5 1:5:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.1 1|0:0.1 23 | -------------------------------------------------------------------------------- /test-data/test.chr2.vcf: -------------------------------------------------------------------------------- 1 | ##fileformat=VCFv4.1 2 | ##filedate=2020.3.13 3 | ##contig= 4 | ##pipeline=michigan-imputationserver-1.2.4 5 | ##imputation=minimac4-1.0.2 6 | ##phasing=eagle-2.4 7 | ##r2Filter=0.0 8 | ##INFO= 9 | ##INFO= 10 | ##INFO= 11 | ##INFO= 12 | ##INFO= 13 | ##INFO= 14 | ##INFO= 15 | ##FORMAT= 16 | ##FORMAT= 17 | #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT LF001 LF002 18 | 2 1 2:1:G:T G T . PASS AF=0.26318;MAF=0.26318;R2=0.54658;IMPUTED GT:DS 1|0:0.1 1|0:0.2 19 | 2 2 2:2:T:G T G . PASS AF=0.03843;MAF=0.03843;R2=0.67736;IMPUTED GT:DS 0|0:0.2 1|0:0.4 20 | 2 3 2:3:A:C A C . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.3 1|0:0.8 21 | 2 4 2:4:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.4 1|0:1.6 22 | 2 5 2:5:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.1 1|0:0.1 23 | -------------------------------------------------------------------------------- /test-data/test.chr2.wrong.vcf: -------------------------------------------------------------------------------- 1 | ##fileformat=VCFv4.1 2 | ##filedate=2020.3.13 3 | ##contig= 4 | ##pipeline=michigan-imputationserver-1.2.4 5 | ##imputation=minimac4-1.0.2 6 | ##phasing=eagle-2.4 7 | ##r2Filter=0.0 8 | ##INFO= 9 | ##INFO= 10 | ##INFO= 11 | ##INFO= 12 | ##INFO= 13 | ##INFO= 14 | ##INFO= 15 | ##FORMAT= 16 | ##FORMAT= 17 | #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT LF001 LF002 LF003 18 | 2 1 2:1:G:T G T . PASS AF=0.26318;MAF=0.26318;R2=0.54658;IMPUTED GT:DS 1|0:0.1 1|0:0.2 1|0:0.2 19 | 2 2 2:2:T:G T G . PASS AF=0.03843;MAF=0.03843;R2=0.67736;IMPUTED GT:DS 0|0:0.2 1|0:0.4 1|0:0.4 20 | 2 3 2:3:A:C A C . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.3 1|0:0.8 1|0:0.8 21 | 2 4 2:4:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.4 1|0:1.6 1|0:1.6 22 | 2 5 2:5:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.1 1|0:0.1 1|0:1 23 | -------------------------------------------------------------------------------- /test-data/test.scores.csv: -------------------------------------------------------------------------------- 1 | chr position_hg19 effect_weight A1 A2 effect_allele 2 | 1 1 1 G T G 3 | 1 2 1 T G T 4 | 1 3 1 A C A 5 | 1 4 1 A G A 6 | 2 1 5.0 G T G 7 | 2 2 5.0 T G T 8 | 2 3 5.0 A C A 9 | 3 1 10.0 A C A 10 | 3 2 10.0 A C A 11 | 3 3 10.0 A C A 12 | 3 4 10.0 A C A 13 | -------------------------------------------------------------------------------- /test-data/test.scores.csv.format: -------------------------------------------------------------------------------- 1 | { 2 | "chromosome": "chr", 3 | "position": "position_hg19", 4 | "effect_weight": "effect_weight", 5 | "allele_a": "A1", 6 | "allele_b": "A2", 7 | "effect_allele": "effect_allele" 8 | } 9 | -------------------------------------------------------------------------------- /test-data/test.scores2.csv: -------------------------------------------------------------------------------- 1 | chr position_hg19 effect_weight A1 A2 effect_allele 2 | 1 1 1 G T G 3 | 1 2 1 T G T 4 | 1 3 1 A C A 5 | 1 4 1 A G A -------------------------------------------------------------------------------- /test-data/test.scores2.csv.format: -------------------------------------------------------------------------------- 1 | { 2 | "chromosome": "chr", 3 | "position": "position_hg19", 4 | "effect_weight": "effect_weight", 5 | "allele_a": "A1", 6 | "allele_b": "A2", 7 | "effect_allele": "effect_allele" 8 | } 9 | -------------------------------------------------------------------------------- /test-data/two.vcf: -------------------------------------------------------------------------------- 1 | ##fileformat=VCFv4.1 2 | ##filedate=2020.3.13 3 | ##contig= 4 | ##pipeline=michigan-imputationserver-1.2.4 5 | ##imputation=minimac4-1.0.2 6 | ##phasing=eagle-2.4 7 | ##r2Filter=0.0 8 | ##INFO= 9 | ##INFO= 10 | ##INFO= 11 | ##INFO= 12 | ##INFO= 13 | ##INFO= 14 | ##INFO= 15 | ##FORMAT= 16 | ##FORMAT= 17 | #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT LF001 LF002 18 | 20 61795 20:61795:G:T G T . PASS AF=0.26318;MAF=0.26318;R2=0.54658;IMPUTED GT:DS 1|0:0.1 1|0:0.2 19 | 20 63231 20:63231:T:G T G . PASS AF=0.03843;MAF=0.03843;R2=0.67736;IMPUTED GT:DS 0|0:0.2 1|0:0.4 20 | 20 63244 20:63244:A:C A C . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.3 1|0:0.8 21 | 20 63244 20:63244:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.4 1|0:1 22 | 20 6324422 20:6324422:A:G A G . PASS AF=0.16132;MAF=0.16132;R2=0.49907;IMPUTED GT:DS 0|0:0.285:10.0 1|0:0.1 23 | -------------------------------------------------------------------------------- /test-data/variants.txt: -------------------------------------------------------------------------------- 1 | "chr_name" "chr_position" 2 | "1" "1" 3 | "1" "2" 4 | "1" "3" 5 | "2" "1" 6 | "2" "2" 7 | --------------------------------------------------------------------------------