Source code for pen_assemble.catalog

"""
Catalog loading utilities for PEN-ASSEMBLE release data.

Functions load the release CSV/Parquet files into pandas DataFrames and
provide convenience views (P1 beaters, P5 top-5, strategy subsets).
"""

from __future__ import annotations

from pathlib import Path

import pandas as pd

__all__ = [
    "load_catalog",
    "load_p1_beaters",
    "load_top5",
    "filter_strategy",
    "RELEASE_DIR",
]

# Default release directory (relative to package root)
_PKG_ROOT = Path(__file__).resolve().parent.parent
RELEASE_DIR: Path = _PKG_ROOT / "catalog" / "release_v0.5.0"

#: IS621 verbatim lockpoint used for P1 beater definition.
IS621_LOCKPOINT = 0.929


[docs] def load_catalog( release_dir: str | Path | None = None, fmt: str = "parquet", ) -> pd.DataFrame: """Load the full 1,029-design PEN-ASSEMBLE scorecard. Parameters ---------- release_dir: Path to the release directory. Defaults to ``catalog/release_v0.5.0/`` relative to the repository root. fmt: ``"parquet"`` (default) or ``"csv"``. Returns ------- pd.DataFrame Scorecard with all catalog columns plus ``protein_sequence``. Raises ------ FileNotFoundError If the release directory or catalog file does not exist. Examples -------- >>> from pen_assemble.catalog import load_catalog >>> df = load_catalog() >>> len(df) 1029 >>> "pen_score" in df.columns True """ rdir = Path(release_dir) if release_dir else RELEASE_DIR if not rdir.exists(): raise FileNotFoundError( f"Release directory not found: {rdir}\n" "Run scripts/50_assemble_catalog.py to generate it." ) if fmt == "parquet": fpath = rdir / "pen_assemble_catalog.parquet" else: fpath = rdir / "pen_assemble_catalog.csv" if not fpath.exists(): raise FileNotFoundError(f"Catalog file not found: {fpath}") return pd.read_parquet(fpath) if fmt == "parquet" else pd.read_csv(fpath)
[docs] def load_p1_beaters( release_dir: str | Path | None = None, ) -> pd.DataFrame: """Load the 16 designs that beat the IS621 verbatim lockpoint (pen_score > 0.929). Parameters ---------- release_dir: Path to the release directory. Returns ------- pd.DataFrame Sorted by pen_score descending. Examples -------- >>> from pen_assemble.catalog import load_p1_beaters >>> p1 = load_p1_beaters() >>> len(p1) 16 >>> (p1["pen_score"] > 0.929).all() True """ rdir = Path(release_dir) if release_dir else RELEASE_DIR fpath = rdir / "p1_beaters_catalog.csv" if not fpath.exists(): raise FileNotFoundError(f"P1 beaters file not found: {fpath}") df = pd.read_csv(fpath) return df.sort_values("pen_score", ascending=False).reset_index(drop=True)
[docs] def load_top5( release_dir: str | Path | None = None, ) -> pd.DataFrame: """Load the five P5-compliant top designs (diversity-enforced top-5). Note: the top-5 is not purely rank-ordered - rank-5 was diversity-enforced (A_007 replaces natural rank-5 D023). See validation/P5_diversity_result.json. Parameters ---------- release_dir: Path to the release directory. Returns ------- pd.DataFrame Five designs sorted by pen_score descending. Examples -------- >>> from pen_assemble.catalog import load_top5 >>> t5 = load_top5() >>> len(t5) 5 >>> t5["strategy"].nunique() >= 3 True """ rdir = Path(release_dir) if release_dir else RELEASE_DIR fpath = rdir / "p5_top5_catalog.csv" if not fpath.exists(): raise FileNotFoundError(f"Top-5 file not found: {fpath}") df = pd.read_csv(fpath) return df.sort_values("pen_score", ascending=False).reset_index(drop=True)
[docs] def filter_strategy( df: pd.DataFrame, strategy: str, ) -> pd.DataFrame: """Filter a catalog DataFrame to a single strategy. Parameters ---------- df: Catalog DataFrame (from :func:`load_catalog` or similar). strategy: One of ``"A"``, ``"B"``, ``"C"``, ``"D"``. Returns ------- pd.DataFrame Filtered view, sorted by pen_score descending. Raises ------ ValueError If strategy is not A/B/C/D or not present in ``df``. Examples -------- >>> from pen_assemble.catalog import load_catalog, filter_strategy >>> df = load_catalog() >>> filter_strategy(df, "C")["design_id"].tolist() ['IS621_deimmunized_v2_Y255K_D41C_G65K_E187M_D27C_D203C_V285C_V152C_T224C_L318K_E87C_L193I_L275I_P177V', 'C_targeted_001'] """ valid = {"A", "B", "C", "D"} if strategy not in valid: raise ValueError(f"strategy must be one of {valid}; got {strategy!r}") sub = df[df["strategy"] == strategy].copy() if sub.empty: raise ValueError(f"No designs found for strategy {strategy!r}") return sub.sort_values("pen_score", ascending=False).reset_index(drop=True)