Skip to content

Cliff

Class for detecting activity cliffs in a set of compounds based on their similarities and activities.

ActivityCliffs(id_a, id_b, similarity, pAct_diff, pAct_a, pAct_b, winning_type_a, winning_type_b, is_cross_type, is_low_quality, is_same_assay, involves_inactive, landscape_index, severity_label=None)

Dataclass holding the results of one activity cliff detection pass over a set of compounds.

id_a

The compound id of the first compound in the cliff pair.

id_b

The compound id of the second compound in the cliff pair.

involves_inactive

True when at least one compound is labelled inactive by its source assay. This indicates an active-vs-inactive cliff.

is_cross_type

True when the two winning types differ between the two compounds in the cliff pair.

is_low_quality

True if either compound failed the activity quality gate. These cliffs may rest on measurement noise and can be excluded downstream.

is_same_assay

True when the two compounds share at least one assay id (a within-assay cliff, firmest ground). Cross-assay cliffs can carry a systematic offset.

landscape_index

The computed value of the landscape index SALI or TS_SALI (per params.metric) for this pair. It is None only on the SALI branch at Tm == 1 (resolved during labelling by sali_undefined).

pAct_a

pActivity of compound a.

pAct_b

pActivity of compound b.

pAct_diff

The absolute difference in pActivity between the two compounds in the cliff pair.

severity_label = None

The severity label (EXTREME / STRONG / MODERATE) for this cliff pair. It is None until label_cliff_severity runs, or if the pair was not part of the ranked population.

similarity

The Tanimoto similarity between the two compounds in the cliff pair.

winning_type_a

Winning assay type behind pAct_a.

winning_type_b

Winning assay type behind pAct_b.

CliffParams(min_delta=2.0, min_similarity=0.55, metric=SeverityMetric.TS_SALI, ts_truncation=3, extreme_frac=0.01, strong_frac=0.05, sali_undefined=SaliUndefined.NEXT_LARGEST)

Configuration for a single cliff detection and severity pass.

extreme_frac = 0.01

Top fraction of ranked cliffs to be labelled EXTREME.

metric = SeverityMetric.TS_SALI

Which landscape index to compute and rank by. Default is TS_SALI.

min_delta = 2.0

Minimum absolute difference in pActivity for a pair to be considered a cliff. Default is 2.0 which means a 100-fold difference.

min_similarity = 0.55

Minimum Tanimoto similarity for a pair to be considered a cliff. Default is 0.55.

sali_undefined = SaliUndefined.NEXT_LARGEST

SALI only parameter identifying the policy for Tm == 1 pairs i.e, the undefined values.

strong_frac = 0.05

Cumulative top fraction of ranked cliffs to be labelled at least STRONG.

ts_truncation = 3

TS_SALI only parameter representing the Taylor order k. Default is 3, which is the original order used by López-Pérez, K., & Miranda-Quintana, R. A. (2025).

__post_init__()

CliffResult(cliffs, params, n_undefined=0)

The standardized output of a cliff pass. It contains the pairs and the params that produced them.

cliffs

All detected cliff pairs, in detection order (all cliffs generated by find_activity_cliffs).

metric

The landscape index that will be used to label the severity of the cliffs.

n_cliffs

Number of cliff pairs.

n_undefined = 0

Count of SALI-branch pairs undefined at Tm == 1. This would be 0 when using TS_SALI, or when the SALI branch had no Tm == 1 pairs.

params

The configuration these cliffs has used to be detected and will be used to label severity. It is stored here for reproducibility.

severity_counts()

Count of cliffs in each severity band where unlabelled pairs are ignored.

CliffSeverity

Bases: StrEnum

An enum for the Severity label assigned by rank within the ranked cliff set.

EXTREME = 'extreme'

MODERATE = 'moderate'

STRONG = 'strong'

SaliUndefined

Bases: StrEnum

Enum to declare how the SALI severity metric resolves pairs that are undefined at Tanimoto similarity (Tm) == 1.

EXCLUDE = 'exclude'

Drop undefined pairs from the ranking where their severity_label remains None. This was also used in the original Guha & Van Drie (2008) paper, but it is not recommended because it discards potentially important extreme cliffs.

MAX_SEVERITY = 'max_severity'

Rank undefined pairs above all finite ones by assigning them to infinity. As by definition,a Tm = 1 pair with a large activity gap is an extreme cliff where the same structure (based on the fingerprint), yet different activity. Thus, it should outrank even the largest finite SALI, not merely tie it.

NEXT_LARGEST = 'next_largest'

Replace the undefined value with the largest finite SALI in the ranked set as described by Guha & Van Drie (2008). This is the default policy.

SeverityMetric

Bases: StrEnum

Enum to declare which landscape index to use for severity ranking.

SALI = 'sali'

This is the classic Structure-activity landscape index (SALI) introduced by Guha and Van Drie in 2008. It is undefined at Tanimoto similarity (Tm) == 1, so the user must choose a policy for how to handle those undefined pairs. by declaring the sali_undefined parameter in CliffParams.

TS_SALI = 'ts_sali'

Taylor-series Structure-activity landscape index (SALI). It is introduced by López-Pérez, K., & Miranda-Quintana, R. A. (2025). It is a taylor series expansion version of the classic SALI that is finite everywhere. It is the default metric.

find_activity_cliffs(sims, activity, params=CliffParams())

Detect activity cliffs in a set of compounds based on their similarities and activities.

PARAMETER DESCRIPTION
sims

Output of compute_pairwise over the compounds to analyze.

TYPE: TanimotoSimilarities

activity

A dictionary with the compound ids as the keys and their CompoundActivity records as the values.

TYPE: dict[str, CompoundActivity]

params

the CliffParams object containing the detection and scoring configuration (min_delta, metric branch, thresholds).

TYPE: CliffParams DEFAULT: CliffParams()

Returns: A CliffResult holding the detected cliffs; severity labels are None until label_cliff_severity is called.

high_confidence(c)

Check whether a cliff is high-confidence, i.e. both compounds passed the quality gate and share a winning type.

PARAMETER DESCRIPTION
c

The cliff pair to test.

TYPE: ActivityCliffs

RETURNS DESCRIPTION
bool

True if both compounds passed the quality gate and share a winning type.

high_confidence_cliffs(cliffs)

Filter a list of cliffs to only those that are high confidence, i.e. both compounds passed the quality gate and share a winning type.

PARAMETER DESCRIPTION
cliffs

The full list from find_activity_cliffs, including flagged pairs.

TYPE: list[ActivityCliffs]

RETURNS DESCRIPTION
list[ActivityCliffs]

Only the cliffs where both compounds passed the quality gate and share a winning type.

label_cliff_severity(result, restrict=None)

Assign severity level by ranking the cliffs based on their landscape index.

PARAMETER DESCRIPTION
result

The CliffResult object holding all cliffs and their associated thresholds and the SALI undefined policy are read from its params.

TYPE: CliffResult

restrict

A rule to filter the cliffs to be ranked. If true only cliffs that meet the criteria will be labelled. If None, all cliffs will be ranked.

TYPE: Callable[[ActivityCliffs], bool] | None DEFAULT: None

Returns: A new CliffResult with severity_label filled on the ranked cliffs.

same_assay(c)

Check if a cliff pair is within-assay, i.e. the two compounds share at least one assay id.

PARAMETER DESCRIPTION
c

The cliff pair to test.

TYPE: ActivityCliffs

RETURNS DESCRIPTION
bool

True if the two compounds share at least one assay id.

same_assay_cliffs(cliffs)

Filter a list of cliffs to only within-assay pairs.

PARAMETER DESCRIPTION
cliffs

The full list of cliffs identified in the detection pass, including cross-assay pairs.

TYPE: list[ActivityCliffs]

RETURNS DESCRIPTION
list[ActivityCliffs]

Only the cliffs whose two compounds share at least one assay id.