Interpretation Algorithms¶
Interpretation algorithms extend rule evaluation with additional logic. They are configured per project in the metadata JSON at respro init time and stored in the project database. See Database Preparation for how to add them.
How ResPro evaluates resistance¶
ResPro evaluates resistance at three levels:
- Single rules — each row in the primary rules TSV maps one mutation to an interpretation.
- Combination rules — boolean formulas over single-rule
member_idvalues (e.g. "mutation A AND mutation B"). - Interpretation algorithms — project-level logic that aggregates matched rules into per-drug results in the report.
Rule notation basics¶
Rules are amino-acid-centric. A notation such as A123V means the reference amino acid A at position 123 changes to V.
| Type | Example | Meaning |
|---|---|---|
| Substitution | A123V | Position 123 changed from A to V. |
| Anchored deletion | VG215V | The G after position 215 is deleted. |
| Anchored insertion | V215VG | Insertion of G after the V at position 215. |
| Frameshift | L201LfsX | Reading-frame shift after the L at position 201. |
| Phenotype | sensitive / resistant | In-vitro susceptibility interpretation. |
| Clinical phenotype | sensitive / resistant | Treatment-oriented interpretation, where available. |
See Rules TSV Format for the full mutation normalisation reference.
Combination rules¶
Combination rules allow interpretation based on boolean logic across multiple mutation members. They are defined separately from single rules (in the --formula-rules TSV) and evaluated with operators AND, OR, NOT, and XOR.
Combination members are evaluated based on a fixed member allele-frequency threshold (AF > 0.75 by default).
AND
All specified mutations must be present.
A AND B
OR
At least one specified mutation must be present.
A OR B
NOT
The specified mutation must not be present.
A AND NOT B
XOR
Exactly one specified mutation must be present.
A XOR B
Single rules represent one mutation-to-interpretation mapping. Combination rules fire only when their formula conditions are satisfied. Parentheses are supported and should be used whenever precedence should be explicit.
Interpretation algorithms¶
drug_interpretation — turn rule hits into a per-drug assessment¶
Combines the matched rules for a drug into one overall result. Depending on your database, this can be based on phenotype labels, scores, IC50 values, or fold-change cutoffs. Threshold keys are phenotype labels (or bare ranks 1–5) resolved via the rank vocabulary; the report shows the stored verbatim label coloured by its inferred rank, so multi-tier vocabularies (e.g. {1, 3, 5}) work without special-casing.
Methods:
| Method | How it decides | Needs thresholds? |
|---|---|---|
by_phenotype |
The highest-rank phenotype label among the drug's hits wins. contradictory wins over susceptible (rank 1) but loses to any higher-tier severity (ranks 2–5). Hits with no label yield susceptible. |
No — labels come from the rules, not the config. |
by_score |
Sums the score values per drug and compares the total against thresholds. |
Yes |
by_ic50 |
Checks each hit's IC50; the highest-rank label whose breakpoint is met wins, otherwise the rank-1 label. | Yes |
by_fold_ic50 |
Same logic as by_ic50, using fold-IC50 values. |
Yes |
Configuration keys:
method— required; must be"by_phenotype","by_score","by_ic50", or"by_fold_ic50".thresholds— required forby_score,by_ic50, andby_fold_ic50; not accepted forby_phenotype. An object mapping phenotype labels (or bare ranks) to threshold values. Must include at least one severity label (a phenotype label with rank 1-5); thresholds must be non-decreasing with severity rank. Labels are lowercased + whitespace-stripped and resolved via the rank vocabulary, so multi-tier configs work.by_score: threshold values are positive integers.by_ic50/by_fold_ic50: threshold values are positive numbers. The config must include at least one rank-1 label (e.g.susceptible), which is returned when the value falls below all higher-rank breakpoints.
drug_thresholds— optional list of per-drug overrides; not accepted forby_phenotype. See Per-drug / per-reference overrides below.
Each method may appear at most once; two entries with the same method are rejected.
by_phenotype preserves label provenance: the assessment reports the phenotype label stored in the database (most frequent label among the winning rank's hits, alphabetical tie-break), falling back to the canonical rank label only when a drug has no labelled hits.
When multiple methods are configured, the report shows a per-method assessment column (plain text) alongside the final Assessment column. The final assessment is strongest-wins by inferred rank: rank 5 (resistant) > … > rank 2 (potential low-level resistance) > contradictory (rank -1) > rank 1 (susceptible), with unknown (rank 0) weakest. contradictory thus wins over susceptible but loses to any higher-tier severity. The most severe result across all methods becomes the final call.
When drug_thresholds overrides are configured, each per-method assessment cell in the report shows an info icon on hover naming the resolved thresholds and their source (override (reference, drug), override (drug), or global default). The table layout, badge styling, and final Assessment column are unchanged; without overrides the report renders identically to the global-only case.
Example:
{
"name": "drug_interpretation",
"method": "by_phenotype"
}
A numeric example with a rank-1 label:
{
"name": "drug_interpretation",
"method": "by_ic50",
"thresholds": {
"susceptible": 0.0,
"intermediate": 3.0,
"resistant": 10.0
}
}
Per-drug / per-reference overrides¶
drug_interpretation accepts an optional drug_thresholds list that overrides the global thresholds for specific drugs, optionally scoped to a single reference. This is useful when a drug needs finer breakpoints than the database-wide default, or when the same drug has different breakpoints across references (e.g. different viral species).
Each entry is an object with:
reference— optional non-empty string; when present, the override applies only to rules/drugs whose reference matches (accession-version tolerant, e.g.NC_001345.1matchesNC_001345)drug— required non-empty string; the drug name to overridethresholds— required object with the same shape and constraints as the parent algorithm'sthresholds:- must include at least one severity label (rank 1-5); integer for
by_score, positive number forby_ic50/by_fold_ic50; thresholds must be non-decreasing with severity rank
Resolution precedence (most specific wins):
- an override matching
(reference, drug) - an override matching
(drug)only (noreference) - the global
thresholds
Duplicate (reference, drug) or (drug)-only keys are rejected. Two overrides whose reference values differ only by accession version (e.g. NC_001345 and NC_001345.1) are treated as the same key and rejected as duplicates. Overrides with no matching drug or reference fall back to the next precedence level. The Database Dashboard condenses overrides for display: entries sharing the same reference (shown as (all) when absent) and the same threshold values collapse into one row with a sorted drug set, mirroring the effect_as_resistant condensing.
When a drug has hits under multiple references in a single report (e.g. a multi-species run), the reference used to resolve per-(reference, drug) overrides is selected deterministically as the alphabetically first reference name. This keeps the report output stable across process invocations (set iteration order is otherwise hash-seed dependent).
Example — drug_interpretation with a per-reference override:
{
"name": "drug_interpretation",
"method": "by_score",
"thresholds": {"resistant": 1, "intermediate": 1},
"drug_thresholds": [
{"reference": "ref", "drug": "ACV", "thresholds": {"resistant": 1, "intermediate": 1}}
]
}
effect_as_resistant — treat high-impact effects as resistant¶
Produces report-only metadata hits when a variant has a high-impact consequence in a given feature and reference. This does not create curated rule hits — it only adds a resistant metadata row for the configured drug.
Configured high-impact variant effects (frameshift, stop_gained, stop_lost, start_lost, insertion, deletion) observed in a feature/reference pair are interpreted as phenotype='resistant' for the configured drug. This algorithm does not set clinical_phenotype.
Configuration keys:
rules— required non-empty list. Each rule must include:feature— case-sensitive exact feature name.reference— case-sensitive exact reference name.drug— case-sensitive exact drug name.effect— a non-empty list of strings, each one of:frameshift,stop_gained,stop_lost,start_lost,insertion,deletion.
- Each (
feature,reference,drug) tuple must be unique across the list.
This metadata output is only produced when the project database has at least one curated rule with a known phenotype or clinical phenotype.
Example:
{
"name": "effect_as_resistant",
"rules": [
{
"feature": "UL23",
"effect": ["frameshift", "stop_gained", "stop_lost"],
"reference": "NC_001806",
"drug": "Aciclovir"
}
]
}
drug_groups — group drugs in the report¶
Assigns drugs to named groups (for example, drug classes) for display in the final report.
groups— required non-empty object. Each key is a group name; each value is a non-empty list of drug name strings. A drug may not appear in more than one group.
Example:
{
"name": "drug_groups",
"groups": {
"Nucleoside Analogues": ["ACV", "PCV"],
"Pyrophosphate Analogues": ["FOS"]
}
}
drug_alias — short drug names in the report¶
Maps canonical drug names to short aliases shown in the report (for example, Aciclovir (ACV)).
groups— required non-empty object. Keys are canonical drug names; values are aliases. Each key and value must be a non-empty string, and aliases must be unique across drugs.
These mappings are written to the drug.alias column during respro init.
Example:
{
"name": "drug_alias",
"groups": {
"Aciclovir": "ACV",
"Penciclovir": "PCV"
}
}
Phenotype and clinical phenotype¶
Two independent phenotype fields are tracked per rule:
- Phenotype — in-vitro susceptibility interpretation.
- Clinical phenotype — treatment-oriented interpretation, where available.
Both are stored verbatim (lowercased + whitespace-stripped) and resolved to a rank via the rank vocabulary (1 = susceptible … 5 = resistant; sentinels 0 = unknown, -1 = contradictory). Severity comparison and report colouring use the inferred rank so multi-tier vocabularies (e.g. {susceptible, low-level resistance, resistant}) work uniformly.
Full configuration example¶
For a complete metadata JSON with all interpretation algorithms, see Database Preparation.