Module 4 · Section 4.1
Format PDB
50 min · niveau debutant · dernière révision : 2026-11-01
Objectifs d'apprentissage
- Décoder une ligne ATOM du format PDB à partir de ses colonnes fixes et de ses champs numériques
- Distinguer les enregistrements HEADER, TITLE, COMPND, REMARK, SEQRES, ATOM, HETATM, TER et MODEL
- Interpréter coordonnées, occupancy, facteur B, altLoc, modèles et résidus manquants
- Écrire un parseur robuste et repérer les pièges du découpage naïf par espaces
- Résumer une structure réelle avec Python et Biopython, puis comparer PDB et mmCIF
Prérequis : 1.1 Représentations computationnelles du dogme central
Python 3.11+Biopython 1.88
Prérequis
Cette section suppose acquis le vocabulaire des acides aminés et des chaînes polypeptidiques présenté en 1.1, ainsi que la lecture de fichiers biologiques vue en 1.2. Côté Python, les tranches de chaînes, les dictionnaires, les ensembles et les conversions int et float doivent être familiers. Biopython 1.88 est installé ; le code fonctionne avec Python 3.11 et versions ultérieures.
Introduction
Une protéine n'est pas seulement une séquence : c'est un objet tridimensionnel dont la forme commande la reconnaissance d'un ligand, la catalyse d'une réaction ou l'assemblage d'un complexe. La crambine, une petite protéine de graine de Crambe hispanica, illustre ce lien avec une économie remarquable : 46 résidus, trois ponts disulfure et une structure déterminée à 1,50 Å de résolution, déposée dans la Protein Data Bank sous l'identifiant 1CRN. Pour étudier une telle structure, il faut d'abord lire les coordonnées de ses 327 atomes, puis retrouver les résidus, les chaînes et les éventuels conformères alternatifs.
Le format PDB (Protein Data Bank) est le plus ancien format standard de la biologie structurale. Il est né en 1971 et conserve cette contrainte : chaque information occupe des colonnes de largeur fixe dans une ligne de 80 caractères. Un programme doit respecter scrupuleusement ces positions ; un décalage d'une colonne transforme un nom d'atome en chaîne vide et une coordonnée en texte. Les bibliothèques modernes masquent cette difficulté sans l'éliminer : un fichier mal formé ou un choix de colonnes erroné produit des structures fausses sans lever d'erreur.
Cette section apprend à décoder le format à la main, puis avec du code. Elle montre ce que contiennent réellement les enregistrements, comment interpréter les coordonnées et le facteur B, pourquoi les conformères alternatifs et les modèles multiples compliquent le comptage, et comment résumer la crambine sans se tromper. Elle situe enfin le PDB face à son successeur, le format mmCIF, devenu le format maître de la Protein Data Bank.
Théorie
Un format hérité des cartes perforées
Le format PDB décrit une structure macromoléculaire par une suite d'enregistrements textuels. Chaque enregistrement commence par un mot-clé de six caractères au plus, placé dans les six premières colonnes : HEADER, TITLE, ATOM, HETATM, TER, MODEL, ENDMDL, END. Le reste de la ligne est découpé en champs de largeur fixe. Une ligne ATOM fait 80 caractères, complétés par des espaces, et la spécification numérote les colonnes à partir de 1.
Le format a été figé en version 3.30 en 2012. Il ne peut pas représenter plus de 99 999 atomes, plus de 9 999 résidus par chaîne, plus de 62 chaînes ni des identifiants de chaîne de plus d'un caractère. La Protein Data Bank mondiale (wwPDB) utilise donc PDBx/mmCIF comme format d'archivage principal, tout en distribuant une représentation PDB des structures qui restent représentables.
Colonnes fixes et index 1-based
La difficulté centrale tient au décalage entre la spécification et Python. La spécification PDB compte les colonnes à partir de 1 et désigne des intervalles inclusifs : le numéro de série occupe les colonnes 7 à 11. Une tranche Python est 0-based et semi-ouverte : elle s'écrit line[6:11]. La règle de conversion est donc simple : soustraire 1 à la première colonne et conserver la seconde comme borne exclue. Pour un champ d'une seule colonne, comme altLoc en colonne 17, la tranche devient line[16:17].
| Champ | Colonnes PDB | Tranche Python |
|---|---|---|
serial | 7-11 | line[6:11] |
name | 13-16 | line[12:16] |
altLoc | 17 | line[16:17] |
resName | 18-20 | line[17:20] |
chainID | 22 | line[21:22] |
resSeq | 23-26 | line[22:26] |
iCode | 27 | line[26:27] |
x, y, z | 31-38, 39-46, 47-54 | line[30:38], line[38:46], line[46:54] |
occupancy | 55-60 | line[54:60] |
tempFactor | 61-66 | line[60:66] |
element | 77-78 | line[76:78] |
La colonne 12 est vide dans une ligne ATOM ; elle sépare le numéro de série du nom d'atome. La colonne 21 sépare le nom de résidu du chaînage, et les colonnes 28 à 30 séparent le code d'insertion de la coordonnée . Ces espaces font partie du contrat de lecture.
Les enregistrements qui structurent le fichier
HEADER porte la classification, la date de dépôt et l'identifiant à quatre caractères, dans les colonnes 63 à 66. Dans 1CRN, il indique PLANT PROTEIN, 30-APR-81 et 1CRN. TITLE donne le titre de l'entrée, souvent sur plusieurs lignes numérotées ; il faut concaténer les morceaux, pas ne garder que le premier. COMPND décrit la composition moléculaire, les chaînes et parfois le caractère recombinant. REMARK regroupe des remarques numérotées : la résolution figure dans REMARK 2, les détails d'affinement dans REMARK 3, les géométries anormales dans REMARK 500.
SEQRES énumère la séquence complète des résidus par chaîne, telle que l'expérimentateur l'a déclarée. ATOM contient les coordonnées des atomes du polymère. HETATM contient les atomes non polymériques : eau, ions, ligands, cofacteurs, parfois des résidus modifiés. TER marque la fin d'une chaîne. MODEL et ENDMDL encadrent chaque modèle d'un ensemble, typiquement en RMN. END termine le fichier. D'autres enregistrements enrichissent l'entrée : HELIX et SHEET pour la structure secondaire, SSBOND pour les ponts disulfure, CONECT pour les liaisons covalentes explicites, MASTER pour les compteurs finaux.
Un enregistrement ATOM ne suffit donc pas à décrire une entrée. La séquence observée peut différer de SEQRES, les ligands ne sont pas des résidus protéiques, et un fichier sans MODEL n'est pas un fichier sans modèle : il possède un modèle implicite.
Anatomie d'une ligne ATOM
Prenons la première ligne ATOM de 1CRN :
ATOM 1 N THR A 1 17.047 14.099 3.625 1.00 13.79 NLe numéro de série vaut 1. Le nom d'atome est N, l'azote du squelette. altLoc est vide, ce qui signifie qu'il n'existe qu'un conformère. Le résidu est THR, la thréonine. La chaîne est A, le numéro de résidu vaut 1 et le code d'insertion est vide. Les coordonnées sont , et ångströms. L'occupancy vaut 1,00, le facteur B vaut 13,79 Ų et l'élément est l'azote.
Le nom d'atome mérite une attention particulière. Les colonnes 13 à 16 sont alignées selon la longueur de l'élément : un carbone alpha CA est décalé d'une position vers la droite, tandis qu'un calcium, également noté CA, commence en colonne 13. La colonne 77-78 lève l'ambiguïté en donnant l'élément réel.
Coordonnées, occupancy et facteur B
Les coordonnées sont exprimées en ångströms dans un repère cartésien droitier, propre au cristal ou au modèle. Elles décrivent une position moyenne : un atome vibre autour de cette position, et le facteur B, ou facteur de température, mesure l'amplitude de ce déplacement. Pour un déplacement isotrope d'écart quadratique moyen , la relation est
Un facteur B de 13,79 Ų correspond à Å. Un facteur B élevé signale une région mobile, désordonnée ou mal résolue ; il ne signifie pas nécessairement que l'atome est absent. Dans 1CRN, le facteur B moyen vaut 6,92 Ų, avec un minimum de 3,38 Ų et un maximum de 28,98 Ų sur l'hydroxyle de la tyrosine 29.
L'occupancy indique la fraction de molécules où l'atome occupe la position décrite. Une valeur de 1,00 correspond à une position pleinement occupée. Lorsqu'une chaîne latérale adopte deux conformations, deux jeux de coordonnées sont étiquetés A et B dans altLoc, avec des occupancies qui se partagent approximativement l'unité. Additionner naïvement les atomes double alors le compte des résidus.
Modèles multiples, TER et chaînes
En cristallographie, un fichier contient généralement un seul modèle. En RMN, chaque conformère du faisceau de structures est encadré par MODEL et ENDMDL, et le numéro du modèle figure dans les colonnes 11 à 14. Un fichier de 20 modèles décrit 20 structures compatibles avec les contraintes expérimentales, pas 20 copies présentes simultanément dans un cristal. Biopython expose cette hiérarchie sous la forme Structure > Model > Chain > Residue > Atom.
TER sépare deux chaînes polymériques. Il ne contient pas de coordonnées et ne doit jamais être compté comme un atome. L'identifiant de chaîne tient dans une seule colonne, ce qui limite à 62 chaînes nommées. Une chaîne non nommée laisse la colonne 22 vide ; cette valeur manquante n'est pas un identifiant.
Résidus manquants et hydrogènes
SEQRES décrit la séquence attendue, ATOM la partie effectivement observée. Un résidu présent dans SEQRES mais absent des coordonnées est manquant : la chaîne est désordonnée, clivée ou trop mobile. Un trou dans resSeq suggère souvent une absence, mais ce n'est qu'un indice : les numérotations peuvent sauter, et les codes d'insertion intercalent des résidus sans renuméroter. Dans 1CRN, les 46 résidus de SEQRES correspondent aux 46 observés. Dans 1CRN, les 46 résidus de SEQRES correspondent aux 46 résidus observés, sans trou.
Les hydrogènes sont généralement absents des structures cristallographiques à résolution moyenne, car leur densité électronique est trop faible. Les structures RMN et les expériences de diffraction neutronique peuvent les contenir. Dans 1CRN, les 327 atomes se répartissent en 202 carbones, 64 oxygènes, 55 azotes et 6 soufres : aucun hydrogène. Les programmes de visualisation ajoutent souvent des hydrogènes calculés ; leur position est une géométrie idéalisée, pas une mesure.
Du PDB à mmCIF
Le format mmCIF (macromolecular Crystallographic Information File), ou PDBx/mmCIF, remplace les colonnes fixes par des paires clé-valeur et des boucles. Une boucle _atom_site déclare explicitement les noms de champs, puis liste les valeurs. Les identifiants de chaîne peuvent dépasser un caractère, les grands assemblages sont représentables, et les métadonnées sont structurées par un dictionnaire. Un fichier mmCIF est plus verbeux, mais plus robuste et plus expressif.
Les deux formats ne sont pas équivalents. Le PDB impose des largeurs et des positions ; mmCIF impose des noms de champs et une syntaxe. Un parseur PDB peut lire un fichier mmCIF par accident et produire des champs vides. Biopython fournit PDBParser, MMCIFParser et FastMMCIFParser ; le choix doit correspondre au format réel.
Exemple travaillé à la main
Reprenons la première ligne ATOM de 1CRN et découpons-la avec les tranches Python. Le nom d'atome N occupe les colonnes 13 à 16, soit line[12:16], et vaut " N " avant nettoyage. Le résidu THR occupe line[17:20], la chaîne A occupe line[21:22], le numéro 1 occupe line[22:26] et le code d'insertion line[26:27] est vide. Les trois coordonnées se lisent dans line[30:38], line[38:46] et line[46:54].
La distance entre l'azote et le carbone alpha du premier résidu se calcule avec la formule euclidienne :
Avec les coordonnées du fichier, Å, une valeur compatible avec une liaison covalente N-CA. Le carbone alpha et le carbone carbonyl du même résidu donnent Å. Ces contrôles détectent une erreur de colonne : une coordonnée lue dans le champ voisin produit une distance absurde.
Complexité et stratégie de parsing
Le parsing d'un fichier PDB est linéaire en nombre de lignes : chaque ligne est lue une fois, et les champs sont extraits par des tranches de coût constant. La mémoire dépend de la stratégie : un parcours en flux garde un atome à la fois, une liste complète stocke tous les atomes. Un calcul de distances exige de conserver les coordonnées.
La validation doit être explicite. Vérifier la longueur minimale de la ligne, le type d'enregistrement et la conversion des champs numériques évite les erreurs silencieuses. Un fichier tronqué à la colonne 50 ne contient plus de facteur B ; le parser peut décider de le refuser ou d'utiliser une valeur par défaut, mais ce choix doit être documenté.
Implémentation
Les sorties de cette section ont été exécutées le 2026-11-01 avec Python 3.13.5 et Biopython 1.88. Vérifions d'abord les versions.
python -c "import sys, Bio; print(sys.version.split()[0], Bio.__version__)"3.13.5 1.88Voici un parseur minimal d'une ligne ATOM ou HETATM. Il lit les colonnes fixes, convertit les nombres et laisse les champs texte sans espaces de remplissage. Les commentaires indiquent la correspondance avec la spécification.
def parse_atom_line(line):
line = line.rstrip("\r\n")
if len(line) < 54:
raise ValueError("ATOM/HETATM line shorter than 54 columns")
record = line[0:6].strip()
if record not in {"ATOM", "HETATM"}:
raise ValueError(f"not an ATOM or HETATM record: {record!r}")
return {
"record": record, # colonnes 1-6
"serial": int(line[6:11]), # colonnes 7-11
"name": line[12:16].strip(), # colonnes 13-16
"alt_loc": line[16:17].strip(), # colonne 17
"res_name": line[17:20].strip(), # colonnes 18-20
"chain_id": line[21:22].strip(), # colonne 22
"res_seq": int(line[22:26]), # colonnes 23-26
"i_code": line[26:27].strip(), # colonne 27
"x": float(line[30:38]), # colonnes 31-38
"y": float(line[38:46]), # colonnes 39-46
"z": float(line[46:54]), # colonnes 47-54
"occupancy": float(line[54:60]) if line[54:60].strip() else 1.0,
"temp_factor": float(line[60:66]) if line[60:66].strip() else 0.0,
"element": line[76:78].strip() if len(line) >= 78 else "",
}Les conversions int et float acceptent les espaces de remplissage, mais pas une chaîne vide. D'où les valeurs par défaut pour l'occupancy et le facteur B. Le champ element reste vide si la ligne est trop courte : un parseur complet le déduirait de l'alignement du nom, avec le risque de confondre CA carbone alpha et CA calcium.
Le découpage naïf par espaces est dangereux. Construisons une ligne synthétique où l'altLoc, le nom de résidu, le numéro et le code d'insertion se touchent, et où l'occupancy touche le facteur B.
fields = [
"ATOM ", " 1000", " ", " CA ", "A", "THR", " ", "A",
"1000", "A", " ", " 17.047", " 14.099", " 3.625",
" 1.00", "123.45", " ", " C", " ",
]
line = "".join(fields)
print(len(line))
print(line.split())80
['ATOM', '1000', 'CA', 'ATHR', 'A1000A', '17.047', '14.099', '3.625', '1.00123.45', 'C']split() perd le champ altLoc vide et fusionne ATHR, A1000A et 1.00123.45. Les tranches fixes donnent au contraire A, THR, A, 1000, A, 1.00 et 123.45. C'est la démonstration la plus directe de la nécessité des colonnes.
Pour les conformères alternatifs, une fonction d'extraction doit choisir un atome par résidu : occupancy décroissante, puis étiquette A, puis ordre lexicographique. Ce choix est une convention et doit être documenté, car un calcul de distances peut varier selon le conformère retenu. Une analyse fine conserve tous les conformères et pondère les observables par l'occupancy.
Étude de cas
La question est simple : que contient réellement public/pdb/1CRN.pdb, et les chiffres d'un parseur en colonnes fixes concordent-ils avec Biopython ? Le fichier est une structure expérimentale réelle, déposée en 1981.
La première étape compte les enregistrements et les entités sans passer par Biopython. Le code suivant lit le fichier, isole les lignes ATOM, puis applique les tranches de la spécification.
from collections import Counter
from pathlib import Path
lines = Path("public/pdb/1CRN.pdb").read_text().splitlines()
records = Counter(line[0:6].strip() for line in lines)
atom_lines = [line for line in lines if line.startswith("ATOM")]
hetatm_lines = [line for line in lines if line.startswith("HETATM")]
chains = sorted({line[21] for line in atom_lines})
residues = {(line[21], int(line[22:26]), line[26]) for line in atom_lines}
models = [line for line in lines if line.startswith("MODEL")]
altlocs = sorted({line[16] for line in atom_lines if line[16] != " "})
b_factors = [float(line[60:66]) for line in atom_lines]
print("ATOM :", records["ATOM"])
print("HETATM :", records["HETATM"])
print("chaînes :", chains)
print("résidus :", len(residues))
print("modèles :", max(1, len(models)))
print("atomes CA :", sum(1 for line in atom_lines if line[12:16].strip() == "CA"))
print("altLoc :", altlocs)
print("B moyen :", round(sum(b_factors) / len(b_factors), 2))ATOM : 327
HETATM : 0
chaînes : ['A']
résidus : 46
modèles : 1
atomes CA : 46
altLoc : []
B moyen : 6.92Le fichier contient donc 327 atomes de polymère, aucun atome HETATM, une seule chaîne A, 46 résidus et 46 carbones alpha. Aucun conformère alternatif n'est déclaré, et aucun enregistrement MODEL n'apparaît : le modèle est implicite. Le facteur B moyen vaut 6,92 Ų, ce qui est faible et cohérent avec une structure bien ordonnée à 1,50 Å.
La seconde étape vérifie ces valeurs avec Biopython.
from Bio.PDB import PDBParser
structure = PDBParser(QUIET=True).get_structure("1CRN", "public/pdb/1CRN.pdb")
model = structure[0]
residues = list(model["A"])
print("modèles :", len(structure))
print("chaînes :", [chain.id for chain in model])
print("résidus :", len(residues))
print("atomes :", sum(1 for residue in residues for atom in residue))
print("premier résidu :", residues[0].get_resname(), residues[0].id[1])
print("dernier résidu :", residues[-1].get_resname(), residues[-1].id[1])modèles : 1
chaînes : ['A']
résidus : 46
atomes : 327
premier résidu : THR 1
dernier résidu : ASN 46Les deux lectures concordent. La crambine commence par une thréonine et finit par une asparagine, ce que confirment SEQRES et les enregistrements ATOM. Les trois ponts disulfure déclarés dans SSBOND relient les cystéines 3-40, 4-32 et 16-26 ; ils stabilisent une petite protéine riche en cystéines. Le fichier ne contient ni eau ni ligand en HETATM, et aucun hydrogène : les 327 atomes sont les atomes lourds du polymère.
Chargement du visualiseur Mol*…
Rendu par Mol* (chargé depuis un CDN). Les fichiers locaux du dépôt sont utilisés lorsqu'ils sont fournis.
L'interprétation reste prudente : un fichier PDB décrit un modèle expérimental, pas la vérité en solution. Les facteurs B élevés signalent des régions flexibles, les résidus manquants ne sont pas observés et les hydrogènes sont absents. Pour une analyse quantitative, citez l'identifiant, la résolution, la méthode et la date de téléchargement.
Erreurs fréquentes
Quiz
Exercices
Énoncé
Écrire parse_atom_line(line) et count_residues(atoms). La première lit une ligne ATOM ou HETATM en colonnes fixes et renvoie un dictionnaire dont les clés sont record, serial, name, alt_loc, res_name, chain_id, res_seq, i_code, x, y, z, occupancy, temp_factor et element. Les champs numériques sont convertis, les champs texte nettoyés, et une ligne trop courte, un mauvais enregistrement ou un nombre invalide lèvent ValueError. La seconde compte les résidus distincts, identifiés par (chain_id, res_seq, i_code), sans compter deux fois les conformères alternatifs. Testez sur la première ligne de public/pdb/1CRN.pdb et sur des lignes synthétiques.
Comment vérifier votre travail
Les tests se trouvent dans exercises/module-4/4.1-format-pdb/test_4_1.py. Depuis la racine du dépôt :
python -m pytest exercises/module-4/4.1-format-pdb -qCorrigé verrouillé
Le corrigé est chargé uniquement après confirmation. Il n'est pas présent dans la page avant cette action.
Énoncé
Écrire extract_ca_coords(atoms), qui renvoie la liste des carbones alpha sous la forme de tuples (chain_id, res_seq, i_code, x, y, z). Seuls les enregistrements ATOM nommés CA sont retenus : un calcium HETATM nommé CA ne doit pas être pris pour un carbone alpha. Si un résidu possède plusieurs conformères, retenez celui de plus forte occupancy ; à occupation égale, préférez l'étiquette altLoc A. L'ordre de première rencontre des résidus est conservé. Vérifiez que 1CRN donne 46 coordonnées et que la première vaut ("A", 1, "", 16.967, 12.784, 4.338).
Comment vérifier votre travail
Les tests se trouvent dans exercises/module-4/4.1-format-pdb/test_4_1.py. Depuis la racine du dépôt :
python -m pytest exercises/module-4/4.1-format-pdb -qCorrigé verrouillé
Le corrigé est chargé uniquement après confirmation. Il n'est pas présent dans la page avant cette action.
Énoncé
Mini-projet : résumé d'un fichier PDB. Écrire pdb_summary(text) qui renvoie un dictionnaire contenant id, title, n_models, n_chains, chains, n_residues, n_atoms, n_hetatm, has_hetatm, altlocs et atoms_per_model. Lire les colonnes fixes, valider la longueur des lignes ATOM/HETATM et la conversion des nombres, concaténer les lignes TITLE, compter un modèle implicite sans MODEL, suivre les blocs MODEL/ENDMDL, ignorer TER et ne pas compter deux fois un résidu dont les atomes portent des altLoc différents. Un atome hors bloc MODEL ou un numéro de modèle dupliqué lève ValueError.
Comment vérifier votre travail
Les tests se trouvent dans exercises/module-4/4.1-format-pdb/projet/test_projet_4_1.py. Depuis la racine du dépôt :
python -m pytest exercises/module-4/4.1-format-pdb/projet -qCorrigé verrouillé
Le corrigé est chargé uniquement après confirmation. Il n'est pas présent dans la page avant cette action.
Résumé
- Le format PDB encode chaque information dans des colonnes fixes, numérotées à partir de 1 ; les tranches Python sont décalées d'un caractère et semi-ouvertes.
- Une ligne
ATOMcontient le numéro de série, le nom d'atome, l'altLoc, le résidu, la chaîne, le numéro de résidu, le code d'insertion, trois coordonnées, l'occupancy, le facteur B et l'élément. - Le facteur B mesure le déplacement autour de la position moyenne selon ; l'occupancy décrit la population d'un conformère.
HEADER,TITLE,COMPND,REMARKetSEQRESdocumentent l'entrée ;ATOM,HETATM,TERetMODELdécrivent les coordonnées et leur organisation.- Les résidus manquants existent dans
SEQRESmais pas dansATOM; un trou de numérotation n'est qu'un indice. - 1CRN contient 327 atomes lourds, 46 résidus, une chaîne
A, un modèle implicite, aucun HETATM et aucun hydrogène. - mmCIF, format maître de la wwPDB, lève les limites de chaînes, d'atomes et d'identifiants du PDB historique.
Références
- Berman, H. M., Westbrook, J., Feng, Z., Gilliland, G., Bhat, T. N., Weissig, H., Shindyalov, I. N. & Bourne, P. E. (2000). The Protein Data Bank. Nucleic Acids Research, 28(1), 235–242.
- Bernstein, F. C., Koetzle, T. F., Williams, G. J. B., Meyer, E. F., Brice, M. D., Rodgers, J. R., Kennard, O., Shimanouchi, T. & Tasumi, M. (1977). The Protein Data Bank: a computer-based archival file for macromolecular structures. Journal of Molecular Biology, 112(3), 535–542.
- Berman, H. M., Henrick, K. & Nakamura, H. (2003). Announcing the worldwide Protein Data Bank. Nature Structural Biology, 10, 980.
- wwPDB. File Format Documentation — spécifications PDB et PDBx/mmCIF. https://www.wwpdb.org/documentation/file-format
- Biopython. Tutorial and Cookbook — chapitre sur
Bio.PDB. https://biopython.org/docs/1.88/Tutorial/ - Biopython. Bio.PDB API —
PDBParser,MMCIFParser,Structure,Model,Chain,Residue,Atom. https://biopython.org/docs/1.88/api/Bio.PDB.html