Source code for dae.pheno_tool.pheno_tool_adapter
from collections import Counter
from typing import Any, cast
from dae.effect_annotation.effect import EffectTypesMixin
from dae.pheno_tool.tool import PhenoResult, PhenoTool, PhenoToolHelper
from dae.variants.attributes import Sex
[docs]
class PhenoToolAdapterBase:
"""Base class for pheno tool adapters."""
[docs]
def calc_by_effect(
self, measure_id: str, effect: str, people_variants: Counter,
person_ids: list[str] | None = None,
family_ids: list[str] | None = None,
normalize_by: list[dict[str, str]] | None = None,
) -> dict[str, Any]:
raise NotImplementedError
[docs]
def calc_variants(
self, data: dict[str, Any], effect_groups: list[str],
) -> dict[str, Any]:
raise NotImplementedError
[docs]
class PhenoToolAdapter(PhenoToolAdapterBase):
"""Adapter for PhenoTool class."""
def __init__(
self,
pheno_tool: PhenoTool,
pheno_tool_helper: PhenoToolHelper,
) -> None:
self.pheno_tool = pheno_tool
self.helper = pheno_tool_helper
[docs]
def get_result_by_sex(
self, result: dict[str, PhenoResult],
sex: str,
) -> dict[str, Any]:
return {
"negative": {
"count": result[sex].negative_count,
"deviation": result[sex].negative_deviation,
"mean": result[sex].negative_mean,
},
"positive": {
"count": result[sex].positive_count,
"deviation": result[sex].positive_deviation,
"mean": result[sex].positive_mean,
},
"pValue": result[sex].pvalue,
}
[docs]
def calc_by_effect(
self, measure_id: str, effect: str, people_variants: Counter,
person_ids: list[str] | None = None,
family_ids: list[str] | None = None,
normalize_by: list[dict[str, str]] | None = None,
) -> dict[str, Any]:
result = self.pheno_tool.calc(
measure_id, people_variants,
sex_split=True,
person_ids=person_ids,
family_ids=family_ids,
normalize_by=normalize_by,
)
assert isinstance(result, dict)
return {
"effect": effect,
"maleResults": self.get_result_by_sex(result, Sex.M.name),
"femaleResults": self.get_result_by_sex(result, Sex.F.name),
}
[docs]
@staticmethod
def align_na_results(
results: list[dict[str, Any]],
) -> None:
"""Align NA results."""
for result in results:
for sex in ["femaleResults", "maleResults"]:
res = result[sex]
if res["positive"]["count"] == 0:
assert res["positive"]["mean"] == 0
assert res["positive"]["deviation"] == 0
assert res["pValue"] == "NA"
res["positive"]["mean"] = res["negative"]["mean"]
if res["negative"]["count"] == 0:
assert res["negative"]["mean"] == 0
assert res["negative"]["deviation"] == 0
assert res["pValue"] == "NA"
res["negative"]["mean"] = res["positive"]["mean"]
[docs]
def build_report_description(
self, measure_id: str, normalize_by: Any,
) -> str:
normalize_by = self.pheno_tool.init_normalize_measures(
measure_id, normalize_by,
)
if not normalize_by:
return measure_id
return f"{measure_id} ~ {' + '.join(normalize_by)}"
[docs]
def calc_variants(
self, data: dict[str, Any], effect_groups: list[str],
) -> dict[str, Any]:
"""Run pheno tool on given data."""
measure_id = data["measureId"]
family_ids = data.get("phenoFilterFamilyIds")
person_ids = self.helper.genotype_data_persons(
data.get("family_ids", []),
)
normalize_by = data.get("normalizeBy")
effect_groups = EffectTypesMixin.build_effect_types_list(effect_groups)
people_variants = self.helper.genotype_data_variants(
data, effect_groups)
results = [
self.calc_by_effect(
measure_id, effect, people_variants.get(effect, Counter()),
person_ids=cast(list[str], person_ids),
family_ids=family_ids,
normalize_by=normalize_by,
)
for effect in effect_groups
]
self.align_na_results(results)
return {
"description": self.build_report_description(
measure_id, normalize_by,
),
"results": results,
}