SABLE is a versioned antibody-structure benchmark for machine-learning evaluation. The data release is hosted on Zenodo as flat files, while this repository provides the Python package that downloads, verifies, extracts, filters, and loads the dataset for analysis and PyTorch training.
The large PDB archives are not stored in GitHub. Install the package, then use download=True or the sable-download command to fetch the fixed SABLE release from Zenodo into a local cache.
Please visit the SABLE Zenodo and the SABLE web-server for the full data documentation and guides.
PyTorch utilities, Parquet metadata loading, and DockQ 2.1.3 are included in the core installation.
git clone https://github.com/dina-lab3D/SABLE.git
cd SABLE
pip install -e ".[dev]"
pytestfrom sable import SableDataset
train = SableDataset(
root="data",
split="train",
synthetic=False,
non_redundant=True,
version="0.2.0",
download=True,
record_id="21759053",
)
ab = train[0]
print(ab.entry_id)
print(ab.pdb_id)
print(ab.heavy_sequence)
print(ab.region_sequence("H", "CDR3"))
print(ab.structure_path)SableDataset returns Antibody objects by default. If you pass a transform, each item is the transformed sample instead.
SABLE has two metadata splits: train and test. Training rows can be experimental or synthetic, and experimental rows can be redundant or non-redundant. SableDataset exposes these as composable filters:
from sable import SableDataset
all_train = SableDataset(root="data", split="train")
experimental_train = SableDataset(
root="data",
split="train",
synthetic=False,
)
synthetic = SableDataset(
root="data",
split="train",
experimental=False,
)
non_redundant_experimental = SableDataset(
root="data",
split="train",
synthetic=False,
non_redundant=True,
)
protein_or_peptide_antigens = SableDataset(
root="data",
split="train",
has_antigen_only=True,
has_aa_antigen_only=True,
)The main filters are:
| Argument | Meaning |
|---|---|
split |
Keep only "train" or "test" rows. Leave as None to keep both. |
experimental |
Include experimental structures. Set False to keep only synthetic entries. |
synthetic |
Include synthetic entries. Set False to keep only experimental entries. |
non_redundant |
Keep only rows marked as non-redundant. |
has_antigen_only |
Keep only rows with an antigen annotation. |
has_aa_antigen_only |
Keep only rows whose antigen type includes protein or peptide. |
Useful dataset helpers:
len(train)
train.entry_ids
train.get_by_entry_id("10en_0")
train.to_dataframe()
for antibody in train.iter_antibodies():
...An Antibody wraps one metadata row and lazily resolves its processed structure file.
Common metadata properties:
ab.entry_id
ab.pdb_id
ab.split
ab.is_synthetic
ab.is_non_redundant
ab.antibody_type
ab.is_scfv
ab.is_engineered
ab.has_antigen
ab.antigen_types
ab.antigen_names
ab.antigen_chain_ids
ab.antigen_sequence # pipe-separated released metadata
ab.antigen_sequences # per-chain metadata values
ab.antigen_sequences_from_residues()
ab.antigen_ptm
ab.antigen_iptm
ab.antigen_min_paeSequence and region helpers:
ab.heavy_sequence
ab.light_sequence
ab.h_cdr1_sequence
ab.h_cdr2_sequence
ab.h_cdr3_sequence
ab.l_cdr1_sequence
ab.l_cdr2_sequence
ab.l_cdr3_sequence
ab.cdrs_sequences
ab.region_sequence("H", "CDR3")
ab.region_indices("L", "FR2")
ab.cdr_distance(other_ab, "H", 3)
ab.h_cdr3_distance(other_ab)
ab.variable_region_seq_identity(other_ab)Structure helpers load the PDB/mmCIF file on first use:
structure = ab.load_structure()
heavy_residues = ab.heavy_residues
light_residues = ab.light_residues
antigen_groups = ab.antigen_residues
interface = ab.interface_residues(threshold=5.0)Coordinate helpers return (coords, mask) pairs. Heavy/light CA coordinates have shape [residue, 3]; heavy/light backbone atom coordinates have shape [residue, atom, 3].
h_ca, h_ca_mask = ab.heavy_ca_coords()
l_ca, l_ca_mask = ab.light_ca_coords()
h_atoms, h_atom_mask = ab.heavy_atom_coords()
l_atoms, l_atom_mask = ab.light_atom_coords()
ag_ca_list, ag_ca_mask_list = ab.antigen_ca_coords()
ag_atom_list, ag_atom_mask_list = ab.antigen_atom_coords()antigen_sequence and antigen_sequences are read directly from the v0.2 metadata. Use antigen_sequence_from_residues() or antigen_sequences_from_residues() when validating structures or reconstructing the sequence representation. Protein, peptide, and nucleic-acid chains use one-letter sequences; hapten and carbohydrate groups use ordered CCD codes separated by -. Missing polymer residues are lower case.
Synthetic rows additionally expose antigen-focused AlphaFold3 confidence values: antigen_ptm, antigen_iptm, and antigen_min_pae. These are missing for experimental rows; antigen_iptm >= 0.8 was the synthetic-data retention criterion.
Heavy/light coordinates are indexed by the released metadata sequences. Missing positions therefore remain in the tensor with a false mask. Protein/peptide antigen CA coordinates are likewise aligned to the metadata antigen sequence; non-protein antigens use one centroid per residue.
from torch.utils.data import DataLoader
from sable import TorchSableDataset
from sable.collate import collate_antibodies
from sable.transforms import ToCACoords
train = TorchSableDataset(
root="data",
split="train",
synthetic=False,
non_redundant=True,
has_aa_antigen_only=True,
transform=ToCACoords(include_antigen=True),
)
loader = DataLoader(
train,
batch_size=8,
shuffle=True,
num_workers=4,
collate_fn=collate_antibodies,
)
batch = next(iter(loader))
print(batch["h_coords"].shape)
print(batch["h_mask"].shape)
print(batch["l_coords"].shape)
print(batch["l_mask"].shape)
print(batch["ag_coords"].shape)
print(batch["ag_mask"].shape)ToCACoords and ToBackboneAtoms return separate heavy-chain, light-chain, and antigen coordinate fields. They include metadata-backed ag_sequences, ag_types, and ag_chain_ids, as well as antigen_sequence, antigen_ptm, antigen_iptm, and antigen_min_pae. collate_antibodies pads variable-length tensors and concatenates all antigen chains for each entry into one antigen tensor before batching.
The Zenodo record contains flat files such as:
sable_v0.2.0_README.md
sable_v0.2.0_metadata.csv
sable_v0.2.0_metadata.parquet
sable_v0.2.0_metadata_schema.json
sable_v0.2.0_column_descriptions.md
sable_v0.2.0_splits.zip
sable_v0.2.0_sequences.zip
sable_v0.2.0_structures_pdb_000.tar.gz
sable_v0.2.0_manifest.json
sable_v0.2.0_checksums.sha256
sable_v0.2.0_LICENSE-DATA.txt
sable_v0.2.0_VALIDATION_REPORT.md
The package extracts those files into a local release tree:
sable_v0.2.0/
metadata/
metadata.csv
metadata.parquet
metadata_schema.json
column_descriptions.md
splits/default/
train.txt
test.txt
train_experimental.txt
synthetic.txt
train_experimental_non_redundant.txt
train_experimental_non_redundant_and_synthetic.txt
train_experimental_redundant.json
sequences/
heavy.fasta
light.fasta
paired_variable_domains.fasta
structures/pdb/
<entry_id>.pdb
manifest.json
checksums.sha256
README.md
LICENSE-DATA.txt
Download from Zenodo and create the release tree:
sable-download \
--root data \
--version 0.2.0 \
--record-id 21759053Extract from an already downloaded flat Zenodo folder:
sable-extract-release \
--zenodo-upload /path/to/zenodo_upload \
--out data \
--version 0.2.0Validate a release tree, including the release-wide antigen sequence audit:
sable-validate data/sable_v0.2.0 --check-antigen-sequencesSummarize a release tree or metadata file:
sable-summary data/sable_v0.2.0
sable-summary data/sable_v0.2.0 --json
sable-summary data/sable_v0.2.0 --check-structuresSABLE v0.2 uses an LCS-derived HCDR3 distance, computed as max(lengths) - alignment_score with match=1, mismatch=0 and gap=0.
sable.evaluation contains core metrics for antibody-structure benchmark evaluation. The functions work on NumPy-like coordinate arrays, and several helpers accept Antibody-like objects that expose the SABLE coordinate API.
from sable.evaluation import (
aligned_rmsd,
antibody_chain_aligned_rmsd,
cdr_rmsd_after_framework_alignment,
dockq,
dockq_score,
evaluate_antibody_prediction,
sequence_recovery,
)
heavy_rmsd = antibody_chain_aligned_rmsd(reference_ab, predicted_ab, chain="H")
h3_rmsd = cdr_rmsd_after_framework_alignment(reference_ab, predicted_ab, chain="H", cdr=3)
recovery = sequence_recovery(reference_ab.heavy_sequence, predicted_ab.heavy_sequence)
all_metrics = evaluate_antibody_prediction(reference_ab, predicted_ab)The chain and CDR RMSD functions reproduce the metadata-indexed, global-sequence-mapped, Kabsch-superposed implementation. CDR RMSD is measured after fitting the corresponding framework regions. dockq(reference_ab, predicted_ab) uses the official DockQ package and the same global sequence pairing, coordinate-bearing residue filtering, temporary-chain construction, and a merged antibody-receptor/antigen-ligand workflow.
scores = dockq(reference_ab, predicted_ab)
print(
scores["dockq"],
scores["dockq_fnat"],
scores["dockq_irmsd"],
scores["dockq_lrmsd"],
)Coordinate-only approximation remains available explicitly as approximate_dockq_from_coordinates.
If you use SABLE, cite SABLE v0.2.0 using DOI 10.5281/zenodo.21759053, the SABLE paper, and the source PDB/SAbDab resources.
The Python package is released under the MIT license. The dataset itself is under the data license specified in the Zenodo record and LICENSE-DATA.txt. The synthetic patent-derived AlphaFold3 outputs are subjected to AlphaFold3 output terms of use at: https://github.com/google-deepmind/alphafold3/tree/main.
