pheval 0.4.7__py3-none-any.whl → 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pheval might be problematic. Click here for more details.
- pheval/analyse/benchmark.py +156 -0
- pheval/analyse/benchmark_db_manager.py +16 -134
- pheval/analyse/benchmark_output_type.py +43 -0
- pheval/analyse/binary_classification_curves.py +132 -0
- pheval/analyse/binary_classification_stats.py +164 -307
- pheval/analyse/generate_plots.py +210 -395
- pheval/analyse/generate_rank_comparisons.py +44 -0
- pheval/analyse/rank_stats.py +190 -382
- pheval/analyse/run_data_parser.py +21 -39
- pheval/cli.py +27 -24
- pheval/cli_pheval_utils.py +7 -8
- pheval/post_processing/phenopacket_truth_set.py +235 -0
- pheval/post_processing/post_processing.py +185 -337
- pheval/post_processing/validate_result_format.py +92 -0
- pheval/prepare/update_phenopacket.py +11 -9
- pheval/utils/logger.py +35 -0
- pheval/utils/phenopacket_utils.py +85 -91
- {pheval-0.4.7.dist-info → pheval-0.5.0.dist-info}/METADATA +4 -4
- {pheval-0.4.7.dist-info → pheval-0.5.0.dist-info}/RECORD +22 -26
- pheval/analyse/analysis.py +0 -104
- pheval/analyse/assess_prioritisation_base.py +0 -108
- pheval/analyse/benchmark_generator.py +0 -126
- pheval/analyse/benchmarking_data.py +0 -25
- pheval/analyse/disease_prioritisation_analysis.py +0 -152
- pheval/analyse/gene_prioritisation_analysis.py +0 -147
- pheval/analyse/generate_summary_outputs.py +0 -105
- pheval/analyse/parse_benchmark_summary.py +0 -81
- pheval/analyse/parse_corpus.py +0 -219
- pheval/analyse/prioritisation_result_types.py +0 -52
- pheval/analyse/variant_prioritisation_analysis.py +0 -159
- {pheval-0.4.7.dist-info → pheval-0.5.0.dist-info}/LICENSE +0 -0
- {pheval-0.4.7.dist-info → pheval-0.5.0.dist-info}/WHEEL +0 -0
- {pheval-0.4.7.dist-info → pheval-0.5.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,13 +1,25 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import operator
|
|
3
|
-
from dataclasses import dataclass, field
|
|
4
1
|
from enum import Enum
|
|
5
2
|
from pathlib import Path
|
|
6
|
-
from typing import
|
|
3
|
+
from typing import Callable, Tuple
|
|
7
4
|
|
|
8
|
-
import
|
|
5
|
+
import polars as pl
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
from pheval.post_processing.phenopacket_truth_set import PhenopacketTruthSet
|
|
8
|
+
from pheval.post_processing.validate_result_format import ResultSchema, validate_dataframe
|
|
9
|
+
from pheval.utils.file_utils import all_files
|
|
10
|
+
from pheval.utils.logger import get_logger
|
|
11
|
+
|
|
12
|
+
logger = get_logger()
|
|
13
|
+
|
|
14
|
+
executed_results = set()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ResultType(Enum):
|
|
18
|
+
"""Enumeration of the possible result types."""
|
|
19
|
+
|
|
20
|
+
GENE = "gene"
|
|
21
|
+
DISEASE = "disease"
|
|
22
|
+
VARIANT = "variant"
|
|
11
23
|
|
|
12
24
|
|
|
13
25
|
def calculate_end_pos(variant_start: int, variant_ref: str) -> int:
|
|
@@ -22,397 +34,233 @@ def calculate_end_pos(variant_start: int, variant_ref: str) -> int:
|
|
|
22
34
|
return variant_start + len(variant_ref) - 1
|
|
23
35
|
|
|
24
36
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"""Base class for PhEval results."""
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@dataclass
|
|
31
|
-
class PhEvalGeneResult(PhEvalResult):
|
|
32
|
-
"""Minimal data required from tool-specific output for gene prioritisation result
|
|
33
|
-
Args:
|
|
34
|
-
gene_symbol (Union[List[str], str]): The gene symbol(s) for the result entry
|
|
35
|
-
gene_identifier (Union[List[str], str]): The ENSEMBL gene identifier(s) for the result entry
|
|
36
|
-
score (float): The score for the gene result entry
|
|
37
|
-
Notes:
|
|
38
|
-
While we recommend providing the gene identifier in the ENSEMBL namespace,
|
|
39
|
-
any matching format used in Phenopacket interpretations is acceptable for result matching purposes
|
|
40
|
-
in the analysis.
|
|
41
|
-
"""
|
|
37
|
+
class SortOrder(Enum):
|
|
38
|
+
"""Enumeration representing sorting orders."""
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
ASCENDING = 1
|
|
41
|
+
"""Ascending sort order."""
|
|
42
|
+
DESCENDING = 2
|
|
43
|
+
"""Descending sort order."""
|
|
46
44
|
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
class RankedPhEvalGeneResult(PhEvalGeneResult):
|
|
50
|
-
"""PhEval gene result with corresponding rank
|
|
51
|
-
Args:
|
|
52
|
-
rank (int): The rank for the result entry
|
|
46
|
+
def _rank_results(results: pl.DataFrame, sort_order: SortOrder) -> pl.DataFrame:
|
|
53
47
|
"""
|
|
54
|
-
|
|
55
|
-
rank: int
|
|
56
|
-
|
|
57
|
-
@staticmethod
|
|
58
|
-
def from_gene_result(pheval_gene_result: PhEvalGeneResult, rank: int):
|
|
59
|
-
"""Return RankedPhEvalGeneResult from a PhEvalGeneResult and rank
|
|
60
|
-
Args:
|
|
61
|
-
pheval_gene_result (PhEvalGeneResult): The gene result entry
|
|
62
|
-
rank (int): The corresponding rank for the result entry
|
|
63
|
-
|
|
64
|
-
Returns:
|
|
65
|
-
RankedPhEvalGeneResult: The result as a RankedPhEvalGeneResult
|
|
66
|
-
"""
|
|
67
|
-
return RankedPhEvalGeneResult(
|
|
68
|
-
gene_symbol=pheval_gene_result.gene_symbol,
|
|
69
|
-
gene_identifier=pheval_gene_result.gene_identifier,
|
|
70
|
-
score=pheval_gene_result.score,
|
|
71
|
-
rank=rank,
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
@dataclass
|
|
76
|
-
class PhEvalVariantResult(PhEvalResult):
|
|
77
|
-
"""Minimal data required from tool-specific output for variant prioritisation
|
|
48
|
+
Rank results with the given sort order.
|
|
78
49
|
Args:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
end (int): The end position of the variant
|
|
84
|
-
ref (str): The reference allele of the variant
|
|
85
|
-
alt (str): The alternate allele of the variant
|
|
86
|
-
score (float): The score for the variant result entry
|
|
87
|
-
Notes:
|
|
88
|
-
While we recommend providing the variant's chromosome in the specified format,
|
|
89
|
-
any matching format used in Phenopacket interpretations is acceptable for result matching purposes
|
|
90
|
-
in the analysis.
|
|
50
|
+
results (pl.DataFrame): The results to rank.
|
|
51
|
+
sort_order (SortOrder): The sort order to use.
|
|
52
|
+
Returns:
|
|
53
|
+
pl.DataFrame: The ranked results.
|
|
91
54
|
"""
|
|
55
|
+
sort_descending = True if sort_order == SortOrder.DESCENDING else False
|
|
56
|
+
has_grouping_id = "grouping_id" in results.columns
|
|
57
|
+
if has_grouping_id:
|
|
58
|
+
results = (
|
|
59
|
+
results.sort("score", descending=sort_descending)
|
|
60
|
+
.with_columns(
|
|
61
|
+
pl.struct(["score", "grouping_id"])
|
|
62
|
+
.rank(method="dense", descending=sort_descending)
|
|
63
|
+
.cast(pl.Int32)
|
|
64
|
+
.alias("min_rank")
|
|
65
|
+
)
|
|
66
|
+
.with_columns(pl.col("min_rank").max().over("score").alias("rank"))
|
|
67
|
+
)
|
|
68
|
+
else:
|
|
69
|
+
results = results.sort("score", descending=sort_descending).with_columns(
|
|
70
|
+
pl.col("score").rank(method="max", descending=sort_descending).alias("rank")
|
|
71
|
+
)
|
|
92
72
|
|
|
93
|
-
|
|
94
|
-
start: int
|
|
95
|
-
end: int
|
|
96
|
-
ref: str
|
|
97
|
-
alt: str
|
|
98
|
-
score: float
|
|
99
|
-
grouping_id: str = field(default=None)
|
|
73
|
+
return results
|
|
100
74
|
|
|
101
75
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
76
|
+
def _write_results_file(out_file: Path, output_df: pl.DataFrame) -> None:
|
|
77
|
+
"""
|
|
78
|
+
Write results to compressed Parquet output.
|
|
105
79
|
Args:
|
|
106
|
-
|
|
80
|
+
out_file (Path): Output file to write to.
|
|
81
|
+
output_df (pl.DataFrame): Output dataframe.
|
|
107
82
|
"""
|
|
83
|
+
output_df.write_parquet(out_file, compression="zstd")
|
|
108
84
|
|
|
109
|
-
rank: int = 0
|
|
110
|
-
|
|
111
|
-
@staticmethod
|
|
112
|
-
def from_variant_result(pheval_variant_result: PhEvalVariantResult, rank: int):
|
|
113
|
-
"""Return RankedPhEvalVariantResult from a PhEvalVariantResult and rank
|
|
114
|
-
Args:
|
|
115
|
-
pheval_variant_result (PhEvalVariantResult): The variant result entry
|
|
116
|
-
rank (int): The corresponding rank for the result entry
|
|
117
|
-
|
|
118
|
-
Returns:
|
|
119
|
-
RankedPhEvalVariantResult: The result as a RankedPhEvalVariantResult
|
|
120
|
-
"""
|
|
121
|
-
return RankedPhEvalVariantResult(
|
|
122
|
-
chromosome=pheval_variant_result.chromosome,
|
|
123
|
-
start=pheval_variant_result.start,
|
|
124
|
-
end=pheval_variant_result.end,
|
|
125
|
-
ref=pheval_variant_result.ref,
|
|
126
|
-
alt=pheval_variant_result.alt,
|
|
127
|
-
score=pheval_variant_result.score,
|
|
128
|
-
rank=rank,
|
|
129
|
-
)
|
|
130
85
|
|
|
86
|
+
def _write_gene_result(ranked_results: pl.DataFrame, output_file: Path) -> None:
|
|
87
|
+
"""
|
|
88
|
+
Write ranked PhEval gene results to a parquet file.
|
|
131
89
|
|
|
132
|
-
@dataclass
|
|
133
|
-
class PhEvalDiseaseResult(PhEvalResult):
|
|
134
|
-
"""Minimal data required from tool-specific output for disease prioritisation
|
|
135
90
|
Args:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
score (str): Score for the disease result entry
|
|
139
|
-
Notes:
|
|
140
|
-
While we recommend providing the disease identifier in the OMIM namespace,
|
|
141
|
-
any matching format used in Phenopacket interpretations is acceptable for result matching purposes
|
|
142
|
-
in the analysis.
|
|
91
|
+
ranked_results ([PhEvalResult]): List of ranked PhEval gene results.
|
|
92
|
+
output_file (Path): Path to the output file.
|
|
143
93
|
"""
|
|
94
|
+
gene_output = ranked_results.select(
|
|
95
|
+
["rank", "score", "gene_symbol", "gene_identifier", "true_positive"]
|
|
96
|
+
)
|
|
97
|
+
_write_results_file(output_file, gene_output)
|
|
144
98
|
|
|
145
|
-
disease_name: str
|
|
146
|
-
disease_identifier: str
|
|
147
|
-
score: float
|
|
148
99
|
|
|
100
|
+
def _write_variant_result(ranked_results: pl.DataFrame, output_file: Path) -> None:
|
|
101
|
+
"""
|
|
102
|
+
Write ranked PhEval variant results to a parquet file.
|
|
149
103
|
|
|
150
|
-
@dataclass
|
|
151
|
-
class RankedPhEvalDiseaseResult(PhEvalDiseaseResult):
|
|
152
|
-
"""PhEval disease result with corresponding rank
|
|
153
104
|
Args:
|
|
154
|
-
|
|
105
|
+
ranked_results ([PhEvalResult]): List of ranked PhEval variant results.
|
|
106
|
+
output_file (Path): Path to the output file.
|
|
155
107
|
"""
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
def from_disease_result(pheval_disease_result: PhEvalDiseaseResult, rank: int):
|
|
161
|
-
"""Return RankedPhEvalDiseaseResult from a PhEvalDiseaseResult and rank
|
|
162
|
-
Args:
|
|
163
|
-
pheval_disease_result (PhEvalDiseaseResult): The disease result entry
|
|
164
|
-
rank (int): The corresponding rank for the result entry
|
|
165
|
-
|
|
166
|
-
Returns:
|
|
167
|
-
RankedPhEvalDiseaseResult: The result as a RankedPhEvalDiseaseResult
|
|
168
|
-
"""
|
|
169
|
-
return RankedPhEvalDiseaseResult(
|
|
170
|
-
disease_name=pheval_disease_result.disease_name,
|
|
171
|
-
disease_identifier=pheval_disease_result.disease_identifier,
|
|
172
|
-
score=pheval_disease_result.score,
|
|
173
|
-
rank=rank,
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
class SortOrder(Enum):
|
|
178
|
-
"""Enumeration representing sorting orders."""
|
|
179
|
-
|
|
180
|
-
ASCENDING = 1
|
|
181
|
-
"""Ascending sort order."""
|
|
182
|
-
DESCENDING = 2
|
|
183
|
-
"""Descending sort order."""
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
class ResultSorter:
|
|
187
|
-
"""Class for sorting PhEvalResult instances based on a given sort order."""
|
|
188
|
-
|
|
189
|
-
def __init__(self, pheval_results: [PhEvalResult], sort_order: SortOrder):
|
|
190
|
-
"""
|
|
191
|
-
Initialise ResultSorter
|
|
192
|
-
|
|
193
|
-
Args:
|
|
194
|
-
pheval_results ([PhEvalResult]): List of PhEvalResult instances to be sorted
|
|
195
|
-
sort_order (SortOrder): Sorting order to be applied
|
|
196
|
-
"""
|
|
197
|
-
self.pheval_results = pheval_results
|
|
198
|
-
self.sort_order = sort_order
|
|
199
|
-
|
|
200
|
-
def _sort_by_decreasing_score(self) -> [PhEvalResult]:
|
|
201
|
-
"""
|
|
202
|
-
Sort results in descending order based on the score
|
|
203
|
-
|
|
204
|
-
Returns:
|
|
205
|
-
[PhEvalResult]: Sorted list of PhEvalResult instances.
|
|
206
|
-
"""
|
|
207
|
-
return sorted(self.pheval_results, key=operator.attrgetter("score"), reverse=True)
|
|
208
|
-
|
|
209
|
-
def _sort_by_increasing_score(self) -> [PhEvalResult]:
|
|
210
|
-
"""
|
|
211
|
-
Sort results in ascending order based on the score
|
|
212
|
-
|
|
213
|
-
Returns:
|
|
214
|
-
[PhEvalResult]: Sorted list of PhEvalResult instances.
|
|
215
|
-
"""
|
|
216
|
-
return sorted(self.pheval_results, key=operator.attrgetter("score"), reverse=False)
|
|
217
|
-
|
|
218
|
-
def sort_pheval_results(self) -> [PhEvalResult]:
|
|
219
|
-
"""
|
|
220
|
-
Sort results based on the specified sort order.
|
|
221
|
-
|
|
222
|
-
Returns:
|
|
223
|
-
[PhEvalResult]: Sorted list of PhEvalResult instances.
|
|
224
|
-
"""
|
|
225
|
-
return (
|
|
226
|
-
self._sort_by_increasing_score()
|
|
227
|
-
if self.sort_order == SortOrder.ASCENDING
|
|
228
|
-
else self._sort_by_decreasing_score()
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
class ResultRanker:
|
|
233
|
-
def __init__(self, pheval_result: List[PhEvalResult], sort_order: SortOrder):
|
|
234
|
-
"""
|
|
235
|
-
Initialise the PhEvalRanker.
|
|
236
|
-
Args:
|
|
237
|
-
pheval_result (List[PhEvalResult]): PhEval results to rank.
|
|
238
|
-
sort_order (SortOrder): Sorting order based on which ranking is performed.
|
|
239
|
-
"""
|
|
240
|
-
self.pheval_result = pheval_result
|
|
241
|
-
self.sort_order = sort_order
|
|
242
|
-
self.ascending = sort_order == SortOrder.ASCENDING
|
|
243
|
-
|
|
244
|
-
def rank(self) -> pd.DataFrame:
|
|
245
|
-
"""
|
|
246
|
-
Rank PhEval results, managing tied scores (ex aequo) and handling grouping_id if present.
|
|
247
|
-
|
|
248
|
-
Returns:
|
|
249
|
-
pd.DataFrame : Ranked PhEval results with tied scores managed.
|
|
250
|
-
"""
|
|
251
|
-
pheval_result_df = pd.DataFrame([data.__dict__ for data in self.pheval_result])
|
|
252
|
-
|
|
253
|
-
if self._has_valid_grouping_id(pheval_result_df):
|
|
254
|
-
pheval_result_df = self._rank_with_grouping_id(pheval_result_df)
|
|
255
|
-
else:
|
|
256
|
-
pheval_result_df = self._rank_without_grouping_id(pheval_result_df)
|
|
257
|
-
return pheval_result_df.drop(columns=["min_rank", "grouping_id"], errors="ignore")
|
|
258
|
-
|
|
259
|
-
@staticmethod
|
|
260
|
-
def _has_valid_grouping_id(pheval_result_df: pd.DataFrame) -> bool:
|
|
261
|
-
"""Check if grouping_id exists and has no None values."""
|
|
262
|
-
return (
|
|
263
|
-
"grouping_id" in pheval_result_df.columns
|
|
264
|
-
and not pheval_result_df["grouping_id"].isnull().any()
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
def _rank_with_grouping_id(self, pheval_result_df: pd.DataFrame) -> pd.DataFrame:
|
|
268
|
-
"""Apply ranking when grouping_id is present and has no None values."""
|
|
269
|
-
pheval_result_df["min_rank"] = (
|
|
270
|
-
pheval_result_df.groupby(["score", "grouping_id"])
|
|
271
|
-
.ngroup()
|
|
272
|
-
.rank(method="dense", ascending=self.ascending)
|
|
273
|
-
).astype(int)
|
|
274
|
-
pheval_result_df["rank"] = pheval_result_df.groupby("score")["min_rank"].transform("max")
|
|
275
|
-
return pheval_result_df
|
|
276
|
-
|
|
277
|
-
def _rank_without_grouping_id(self, pheval_result_df: pd.DataFrame) -> pd.DataFrame:
|
|
278
|
-
"""Apply ranking without using grouping_id."""
|
|
279
|
-
pheval_result_df["rank"] = (
|
|
280
|
-
pheval_result_df["score"].rank(method="max", ascending=self.ascending).astype(int)
|
|
281
|
-
)
|
|
282
|
-
return pheval_result_df
|
|
108
|
+
variant_output = ranked_results.select(
|
|
109
|
+
["rank", "score", "chromosome", "start", "end", "ref", "alt", "variant_id", "true_positive"]
|
|
110
|
+
)
|
|
111
|
+
_write_results_file(output_file, variant_output)
|
|
283
112
|
|
|
284
113
|
|
|
285
|
-
def
|
|
114
|
+
def _write_disease_result(ranked_results: pl.DataFrame, output_file: Path) -> None:
|
|
286
115
|
"""
|
|
287
|
-
|
|
116
|
+
Write ranked PhEval disease results to a parquet file.
|
|
288
117
|
|
|
289
118
|
Args:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
Returns:
|
|
293
|
-
SortOrder: Enum representing the specified sorting order
|
|
294
|
-
|
|
295
|
-
Raises:
|
|
296
|
-
ValueError: If an incompatible or unknown sorting method is provided
|
|
119
|
+
ranked_results ([PhEvalResult]): List of ranked PhEval disease results.
|
|
120
|
+
output_file (Path): Path to the output file.
|
|
297
121
|
"""
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
122
|
+
disease_output = ranked_results.select(
|
|
123
|
+
["rank", "score", "disease_name", "disease_identifier", "true_positive"]
|
|
124
|
+
)
|
|
125
|
+
_write_results_file(output_file, disease_output)
|
|
302
126
|
|
|
303
127
|
|
|
304
|
-
def
|
|
128
|
+
def _get_result_type(
|
|
129
|
+
result_type: ResultType, phenopacket_truth_set: PhenopacketTruthSet
|
|
130
|
+
) -> Tuple[Callable, Callable]:
|
|
305
131
|
"""
|
|
306
|
-
|
|
307
|
-
|
|
132
|
+
Get the methods for extracting the entity and writing the result for a given result type.
|
|
308
133
|
Args:
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
134
|
+
result_type (ResultType): The result type.
|
|
135
|
+
phenopacket_truth_set (PhenopacketTruthSet): The phenotype truth set class instance.
|
|
312
136
|
Returns:
|
|
313
|
-
|
|
137
|
+
Tuple[Callable, Callable]: The methods for extracting the entity and the write method.
|
|
314
138
|
"""
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
139
|
+
match result_type:
|
|
140
|
+
case ResultType.GENE:
|
|
141
|
+
return phenopacket_truth_set.classified_gene, _write_gene_result
|
|
142
|
+
case ResultType.VARIANT:
|
|
143
|
+
return phenopacket_truth_set.classified_variant, _write_variant_result
|
|
144
|
+
case ResultType.DISEASE:
|
|
145
|
+
return phenopacket_truth_set.classified_disease, _write_disease_result
|
|
318
146
|
|
|
319
147
|
|
|
320
|
-
def
|
|
321
|
-
|
|
148
|
+
def create_empty_pheval_result(
|
|
149
|
+
phenopacket_dir: Path, output_dir: Path, result_type: ResultType
|
|
322
150
|
) -> None:
|
|
323
151
|
"""
|
|
324
|
-
|
|
152
|
+
Create an empty PhEval result for a given result type (gene, variant, or disease).
|
|
153
|
+
|
|
154
|
+
Notes:
|
|
155
|
+
This is necessary because some tools may not generate a result output for certain cases.
|
|
156
|
+
By explicitly creating an empty result, which will contain the known entity with a rank and score of 0,
|
|
157
|
+
we can track and identify false negatives during benchmarking,
|
|
158
|
+
ensuring that missing predictions are accounted for in the evaluation.
|
|
325
159
|
|
|
326
160
|
Args:
|
|
327
|
-
|
|
328
|
-
output_dir (Path):
|
|
329
|
-
|
|
161
|
+
phenopacket_dir (Path): The directory containing the phenopackets.
|
|
162
|
+
output_dir (Path): The output directory.
|
|
163
|
+
result_type (ResultType): The result type.
|
|
164
|
+
|
|
330
165
|
"""
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
)
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
166
|
+
if result_type in executed_results:
|
|
167
|
+
return
|
|
168
|
+
executed_results.add(result_type)
|
|
169
|
+
phenopacket_truth_set = PhenopacketTruthSet(phenopacket_dir)
|
|
170
|
+
classify_method, write_method = _get_result_type(result_type, phenopacket_truth_set)
|
|
171
|
+
for file in all_files(phenopacket_dir):
|
|
172
|
+
classified_results = classify_method(file.stem)
|
|
173
|
+
write_method(
|
|
174
|
+
classified_results,
|
|
175
|
+
output_dir.joinpath(f"{file.stem}-{result_type.value}_result.parquet"),
|
|
176
|
+
)
|
|
341
177
|
|
|
342
178
|
|
|
343
|
-
|
|
344
|
-
|
|
179
|
+
@validate_dataframe(ResultSchema.GENE_RESULT_SCHEMA)
|
|
180
|
+
def generate_gene_result(
|
|
181
|
+
results: pl.DataFrame,
|
|
182
|
+
sort_order: SortOrder,
|
|
183
|
+
output_dir: Path,
|
|
184
|
+
result_path: Path,
|
|
185
|
+
phenopacket_dir: Path,
|
|
345
186
|
) -> None:
|
|
346
187
|
"""
|
|
347
|
-
|
|
348
|
-
|
|
188
|
+
Generate PhEval gene results to a compressed Parquet output.
|
|
349
189
|
Args:
|
|
350
|
-
|
|
190
|
+
results (pl.DataFrame): The gene results.
|
|
191
|
+
sort_order (SortOrder): The sort order to use.
|
|
351
192
|
output_dir (Path): Path to the output directory
|
|
352
|
-
|
|
193
|
+
result_path (Path): Path to the tool-specific result file.
|
|
194
|
+
phenopacket_dir (Path): Path to the Phenopacket directory
|
|
353
195
|
"""
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
sep="\t",
|
|
362
|
-
index=False,
|
|
196
|
+
output_file = output_dir.joinpath(f"pheval_gene_results/{result_path.stem}-gene_result.parquet")
|
|
197
|
+
create_empty_pheval_result(
|
|
198
|
+
phenopacket_dir, output_dir.joinpath("pheval_gene_results"), ResultType.GENE
|
|
199
|
+
)
|
|
200
|
+
ranked_results = _rank_results(results, sort_order)
|
|
201
|
+
classified_results = PhenopacketTruthSet(phenopacket_dir).merge_gene_results(
|
|
202
|
+
ranked_results, output_file
|
|
363
203
|
)
|
|
204
|
+
_write_gene_result(classified_results, output_file)
|
|
364
205
|
|
|
365
206
|
|
|
366
|
-
|
|
367
|
-
|
|
207
|
+
@validate_dataframe(ResultSchema.VARIANT_RESULT_SCHEMA)
|
|
208
|
+
def generate_variant_result(
|
|
209
|
+
results: pl.DataFrame,
|
|
210
|
+
sort_order: SortOrder,
|
|
211
|
+
output_dir: Path,
|
|
212
|
+
result_path: Path,
|
|
213
|
+
phenopacket_dir: Path,
|
|
368
214
|
) -> None:
|
|
369
215
|
"""
|
|
370
|
-
|
|
371
|
-
|
|
216
|
+
Generate PhEval variant results to a compressed Parquet output.
|
|
372
217
|
Args:
|
|
373
|
-
|
|
218
|
+
results (pl.DataFrame): The variant results.
|
|
219
|
+
sort_order (SortOrder): The sort order to use.
|
|
374
220
|
output_dir (Path): Path to the output directory
|
|
375
|
-
|
|
221
|
+
result_path (Path): Path to the tool-specific result file.
|
|
222
|
+
phenopacket_dir (Path): Path to the Phenopacket directory
|
|
376
223
|
"""
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
output_dir.joinpath(
|
|
382
|
-
"pheval_disease_results/" + tool_result_path.stem + "-pheval_disease_result.tsv"
|
|
383
|
-
),
|
|
384
|
-
sep="\t",
|
|
385
|
-
index=False,
|
|
224
|
+
output_file = output_dir.joinpath(
|
|
225
|
+
f"pheval_variant_results/{result_path.stem}-variant_result.parquet"
|
|
226
|
+
)
|
|
227
|
+
create_empty_pheval_result(
|
|
228
|
+
phenopacket_dir, output_dir.joinpath("pheval_variant_results"), ResultType.VARIANT
|
|
386
229
|
)
|
|
230
|
+
ranked_results = _rank_results(results, sort_order).with_columns(
|
|
231
|
+
pl.concat_str(["chrom", "pos", "ref", "alt"], separator="-").alias("variant_id")
|
|
232
|
+
)
|
|
233
|
+
classified_results = PhenopacketTruthSet(phenopacket_dir).merge_variant_results(
|
|
234
|
+
ranked_results, output_file
|
|
235
|
+
)
|
|
236
|
+
_write_variant_result(classified_results, output_file)
|
|
387
237
|
|
|
388
238
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
239
|
+
@validate_dataframe(ResultSchema.DISEASE_RESULT_SCHEMA)
|
|
240
|
+
def generate_disease_result(
|
|
241
|
+
results: pl.DataFrame,
|
|
242
|
+
sort_order: SortOrder,
|
|
392
243
|
output_dir: Path,
|
|
393
|
-
|
|
244
|
+
result_path: Path,
|
|
245
|
+
phenopacket_dir: Path,
|
|
394
246
|
) -> None:
|
|
395
247
|
"""
|
|
396
|
-
Generate PhEval
|
|
397
|
-
|
|
248
|
+
Generate PhEval disease results to a compressed Parquet output.
|
|
398
249
|
Args:
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
output_dir (Path): Path to the output directory
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
Raises:
|
|
405
|
-
ValueError: If the results are not all the same type or an error occurs during file writing.
|
|
250
|
+
results (pl.DataFrame): The disease results.
|
|
251
|
+
sort_order (SortOrder): The sort order to use.
|
|
252
|
+
output_dir (Path): Path to the output directory
|
|
253
|
+
result_path (Path): Path to the tool-specific result file.
|
|
254
|
+
phenopacket_dir (Path): Path to the Phenopacket directory
|
|
406
255
|
"""
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
raise ValueError("Results are not all of the same type.")
|
|
256
|
+
output_file = output_dir.joinpath(
|
|
257
|
+
f"pheval_disease_results/{result_path.stem}-disease_result.parquet"
|
|
258
|
+
)
|
|
259
|
+
create_empty_pheval_result(
|
|
260
|
+
phenopacket_dir, output_dir.joinpath("pheval_disease_results"), ResultType.DISEASE
|
|
261
|
+
)
|
|
262
|
+
ranked_results = _rank_results(results, sort_order)
|
|
263
|
+
classified_results = PhenopacketTruthSet(phenopacket_dir).merge_disease_results(
|
|
264
|
+
ranked_results, output_file
|
|
265
|
+
)
|
|
266
|
+
_write_disease_result(classified_results, output_file)
|