Problem
The "best direction" of a prediction field — whether higher or lower is better — is canonical metadata about the kind, but it isn't currently exposed in a queryable way. Half of it is implicit in BindingPredictionCollection._best_by_score() (max for score) and ._best_by_rank() (min for percentile_rank), and the rest (value direction, which is kind-dependent: IC50 nM lower-better vs half-life higher-better) isn't encoded anywhere.
Why this matters
Downstream consumers that want to aggregate across alleles or groups need to know the direction:
Replicating the table in every consumer means: when mhctools adds a new value-bearing kind, every downstream has to update independently. The source of truth should sit next to Kind.
Proposed API
Add to mhctools.pred (alongside the existing MHC_DEPENDENCE_VALUES / MHC_CLASS_VALUES constants from #210):
```python
Per-field direction defaults (cross-kind):
FIELD_BEST_DIRECTIONS = {
"score": "max", # binding strength, presentation likelihood, ...
"percentile_rank": "min", # 0 = best
}
Per-kind direction for value (kind-dependent semantics):
VALUE_BEST_DIRECTIONS = {
Kind.pMHC_affinity: "min", # IC50 nM, lower is better
Kind.pMHC_stability: "max", # half-life, higher is better
}
def best_direction(kind, field) -> str:
"""Return 'max' or 'min' for the canonical 'best' direction
of a (kind, field) pair. Raises ValueError for kinds without
a registered direction for field='value'."""
```
Kind-keyed lookups stay flexible since mhctools' Kind.pMHC_affinity is just a string.
Refactor opportunity
_best_by_score() / _best_by_rank() in BindingPredictionCollection could be re-implemented in terms of best_direction() — same conventions, one source of truth. A generic _best_by_value() becomes possible too.
Downstream
Once released, openvax/topiary#160 will drop its local _BEST_FIELD_DIRECTIONS / _BEST_VALUE_DIRECTIONS tables and import from mhctools.
Related
Problem
The "best direction" of a prediction field — whether higher or lower is better — is canonical metadata about the kind, but it isn't currently exposed in a queryable way. Half of it is implicit in
BindingPredictionCollection._best_by_score()(max for score) and._best_by_rank()(min for percentile_rank), and the rest (valuedirection, which is kind-dependent: IC50 nM lower-better vs half-life higher-better) isn't encoded anywhere.Why this matters
Downstream consumers that want to aggregate across alleles or groups need to know the direction:
BestAlleleField(Add best-allele aggregation for haplotype-mode presentation (#158) topiary#160) currently maintains its own_BEST_VALUE_DIRECTIONS = {"pMHC_affinity": "min", "pMHC_stability": "max"}table.Replicating the table in every consumer means: when mhctools adds a new value-bearing kind, every downstream has to update independently. The source of truth should sit next to
Kind.Proposed API
Add to
mhctools.pred(alongside the existingMHC_DEPENDENCE_VALUES/MHC_CLASS_VALUESconstants from #210):```python
Per-field direction defaults (cross-kind):
FIELD_BEST_DIRECTIONS = {
"score": "max", # binding strength, presentation likelihood, ...
"percentile_rank": "min", # 0 = best
}
Per-kind direction for
value(kind-dependent semantics):VALUE_BEST_DIRECTIONS = {
Kind.pMHC_affinity: "min", # IC50 nM, lower is better
Kind.pMHC_stability: "max", # half-life, higher is better
}
def best_direction(kind, field) -> str:
"""Return 'max' or 'min' for the canonical 'best' direction
of a (kind, field) pair. Raises ValueError for kinds without
a registered direction for
field='value'."""```
Kind-keyed lookups stay flexible since mhctools'Kind.pMHC_affinityis just a string.Refactor opportunity
_best_by_score()/_best_by_rank()inBindingPredictionCollectioncould be re-implemented in terms ofbest_direction()— same conventions, one source of truth. A generic_best_by_value()becomes possible too.Downstream
Once released, openvax/topiary#160 will drop its local
_BEST_FIELD_DIRECTIONS/_BEST_VALUE_DIRECTIONStables and import from mhctools.Related
Kind)