Protein Data Bank

El format Protein Data Bank és un format de fitxer comunament utilitzat per emmagatzemar informació sobre estructures moleculars.

Introducció

El RCSB Protein Data Bank (RCSB PDB) proporciona accés i eines per a l’exploració, visualització i anàlisi de:

Aquesta base de dades és el repositori de referència de dades estructurals de proteïnes, un recurs essencial per a aplicacions com el disseny de fàrmacs i l’enginyeria de proteïnes

Pots accedir als registres d’aquesta base de dades a través de la pàgina web de RCSB a https://www.rcsb.org/

Per exemple, pots visualitzar el registre de l’Hemoglobina humana en 3D, que té el codi 4N7N, en aquest enllaç https://www.rcsb.org/3d-view/4n7n

PDB Format

Un fitxer PDB (Protein Data Bank) és un format de fitxer estandarditzat basat en text que emmagatzema les dades estructurals tridimensionals (3D) de macromolècules biològiques, principalment proteïnes i àcids nucleics, així com els seus complexos.

Un fitxer PDB emmagatzema les posicions espacials dels àtoms obtingudes per cristal·lografia de raigs X, espectroscòpia RMN i altres tècniques experimentals, i contenen les coordenades atòmiques, informació d’enllaç i altres detalls rellevants de les biomolècules derivades de mètodes experimentals…

Descarrega el fitxer “Legacy PDB Format” de la proteïna Zeta-Zeta Transmembrane Dimer.

iwr https://files.rcsb.org/download/2HAC.pdb -OutFile 2HAC.pdb

El fitxer és un fitxer de text que pots obrir amb l’editor de text.

Title Section

Els fitxers PDB comencen amb un Title Section. Aquesta secció conté detalls generals sobre les molècules en el fitxer, així com els experiments utilitzats per elucidar les seves estructures. Tot i que hi ha diversos tipus de registres en una secció de títol, els que discutirem a continuació són HEADER, COMPND, i REMARK.

Header Record

La primera línia és un registre header, i té aquest aspecte:

HEADER    MEMBRANE PROTEIN                        12-JUN-06   2HAC

En altres paraules, l’estructura en aquest fitxer és una proteïna de membrana; va ser dipositada el 12 de juny de 2006; i el seu ID PDB és 2HAC.

El més important a notar sobre aquest registre és que la posició de tot dins del registre és important. El format PDB utilitza la posició del caràcter (o “columna”) per delimitar camps dins de cada registre. Això és cert per a tots els tipus de registres, no només per al HEADER. En aquest exemple particular, els primers sis caràcters són el nom del registre ("HEADER"), els caràcters 11-50 estan reservats per al camp de “classificació” (proteïna de membrana), els caràcters 51-59 s’utilitzen per a la data de dipòsit, i els caràcters 63-66 contenen l’ID de l’estructura.

Compound Record

Un dels següents registres en 2hac.pdb és un registre de compost, i té aquest aspecte:

COMPND    MOL_ID: 1;
COMPND   2 MOLECULE: T-CELL SURFACE GLYCOPROTEIN CD3 ZETA CHAIN;
COMPND   3 CHAIN: A, B;
COMPND   4 FRAGMENT: TRANSMEMBRANE REGION (28-60);
COMPND   5 SYNONYM: T-CELL RECEPTOR T3 ZETA CHAIN;
COMPND   6 ENGINEERED: YES

El registre de compost és un exemple d’un únic registre que ocupa múltiples línies. Cada línia consisteix en un parell token/valor, que hauria de recordar-vos el tipus de dades diccionari de Python, o arrays associatius d’altres llenguatges de programació.

Els registres multilínia utilitzen números per permetre la continuació d’un sol registre. Així, per exemple, la línia que comença amb "COMPND 2" simplement continua el registre de compost, donant un altre parell token/valor. En aquest cas, el token (o clau) és MOLECULE i el valor és T-CELL SURFACE GLYCOPROTEIN CD3 ZETA CHAIN.

Remark Record

Poc després del registre de compost hi ha una llista de diversos centenars de línies de remarks. Un comentari PDB és similar als comments en Python o altres llenguatges. En els fitxers PDB, un comentari comença amb REMARK i un número, que simplement identifica el comentari. Per exemple, el comentari #3 comença així:

REMARK   3
REMARK   3 REFINEMENT.
REMARK   3   PROGRAM     : NMRPIPE 1.0, XPLOR-NIH 2.11
REMARK   3   AUTHORS     : FRANK DELAGLIO (NMRPIPE), CHARLES SCHWIETERS
[etc.]

Observa que un comentari pot ser d’una sola línia o multilínia. A més, els números dels comentaris no han d’augmentar d’un en un. Per exemple, el comentari #4 és seguit immediatament pel #100.

Structure

Primary Structure Section

La secció d’estructura primària llista, entre altres coses, la seqüència d’aminoàcids de la proteïna. El tipus principal de registre per fer això és el SEQRES.

Mirem-los a continuació:

SEQRES   1 A   33  ASP SER LYS LEU CYS TYR LEU LEU ASP GLY ILE LEU PHE
SEQRES   2 A   33  ILE TYR GLY VAL ILE LEU THR ALA LEU PHE LEU ARG VAL
SEQRES   3 A   33  LYS PHE SER ARG SER ALA ASP
SEQRES   1 B   33  ASP SER LYS LEU CYS TYR LEU LEU ASP GLY ILE LEU PHE
SEQRES   2 B   33  ILE TYR GLY VAL ILE LEU THR ALA LEU PHE LEU ARG VAL
SEQRES   3 B   33  LYS PHE SER ARG SER ALA ASP

El registre SEQRES:

  • Comença amb un número de sèrie que augmenta d’1 amb cada nova línia.
  • Després del número de sèrie hi ha l’ID de la cadena, en aquest cas, A o B.
  • Després de l’ID de la cadena hi ha el nombre de residus (aminoàcids) en aquesta cadena. Aquest número ha de ser el mateix per a cada línia de la mateixa cadena. En aquest cas, com que les cadenes A i B tenen el mateix nombre de residus (33), ambdues diuen 33.
  • Cada columna posterior simplement llista els residus seqüencialment, des de l’N- fins al C-terminal (és a dir, des del terminal amino fins al carboxi).

Secondary Structure Section

La secció d’estructura secundària proporciona informació sobre l’estructura secundària de la proteïna, específicament, les hèlixs i els fulls. Podeu llegir sobre ells en detall a la pàgina d’estructura secundària de l’especificació PDB. Com podeu suposar, aquests registres donen informació sobre les α-hèlixs i els β-fulls presents en l’estructura de la proteïna.

Les estructures secundàries són determinades per diversos algoritmes utilitzats pels autors o wwPDB. Tingues en compte que aquests algoritmes no sempre coincideixen, per la qual cosa és possible que diferents bases de dades donin informació contradictòria sobre l’estructura secundària.

Connectivity Annotation Section

Aquesta secció proporciona informació sobre els enllaços o connexions presents en l’estructura de la proteïna, però que no es donen en l’estructura primària.

L’estructura 2HAC conté una d’aquestes connexions: un pont disulfur, especificat amb el registre SSBOND.

Here’s what it looks like:

SSBOND   1 CYS A    2    CYS B    2                          1555   1555  2.02

Aquest registre ens diu el nom de cada residu connectat (cisteïna), els seus IDs de cadena i el número de residu dins de les seves respectives cadenes. Els següents dos camps contenen operadors de simetria, que podeu ignorar per ara. L’últim camp conté la longitud del pont disulfur en àngstroms.

Més endavant, parlarem dels registres CONECT, LINK, i CISPEP.

Crystallographic and Coordinates Section

La Secció de Transformació Cristal·logràfica i de Coordenades proporciona informació sobre l’estructura cristal·lina en què es basen les coordenades dels àtoms (amb CRYST1).

Aquesta secció també defineix el sistema de coordenades utilitzant registres ORIGXn i SCALEn.

CRYST1 Record

Moltes estructures de proteïnes es coneixen gràcies a una tècnica anomenada cristal·lografia de raigs X. Aquesta tècnica aprofita el fet que els àtoms que formen part d’un cristall difractaran els raigs X en un patró que es pot utilitzar per elucidar les posicions relatives dels continguts del cristall dins de cada unitat repetitiva en el cristall (coneguda com a cel·la unitària).

El registre CRYST1 descriu la forma de la cel·la unitària. En estructures determinades per cristal·lografia de raigs X, aquesta descripció dona la longitud (en àngstroms) de cada aresta i els angles formats per aquestes arestes. No obstant això, l’estructura 2HAC no va ser determinada per difracció de raigs X, sinó per espectroscòpia de ressonància magnètica nuclear (espectroscòpia RMN). Tot i que no es van utilitzar cristalls en aquest procés, el fitxer PDB encara necessita una entrada CRYST1.

Per a 2HAC, es veu així:

CRYST1    1.000    1.000    1.000  90.00  90.00  90.00 P 1           1

Aquesta és una cel·la unitària cúbica simple; cada aresta té una longitud d’1 àngstrom, tots els angles són de 90°, i el grup espacial és P 1. Qualsevol estructura no determinada per cristal·lografia utilitzarà un registre CRYST1 amb aquests valors.

ORIGXn Record

Quan una estructura de proteïna es presenta per primera vegada a l’arxiu PDB, es dona en coordenades que poden ser diferents de les utilitzades en el fitxer PDB. Les coordenades originals s’anomenen coordenades presentades, i les coordenades utilitzades en el fitxer PDB s’anomenen coordenades ortogonals. Els registres ORIGXn donen la matriu de transformació necessària per obtenir les coordenades presentades a partir de les coordenades ortogonals.

En el cas de 2HAC, ambdues coordenades són les mateixes, per la qual cosa no cal cap transformació. Per això, la matriu de transformació donada és una matriu identitat, i es veu així:

ORIGX1      1.000000  0.000000  0.000000        0.00000
ORIGX2      0.000000  1.000000  0.000000        0.00000
ORIGX3      0.000000  0.000000  1.000000        0.00000

Observa que el nom del registre utilitza els números 1, 2 i 3 en lloc de la n en ORIGXn. n és la N-èsima fila de la matriu de transformació. Mira l’especificació ORIGXn per a més informació.

SCALEn Record

Aquest registre està relacionat amb ORIGXn. Representa la matriu de transformació necessària per passar de coordenades ortogonals a coordenades fraccionals, que són una fracció de la longitud de la cel·la unitària.

De nou, 2HAC no va ser determinada per cristal·lografia, així que es dona una matriu identitat:

SCALE1      1.000000  0.000000  0.000000        0.00000
SCALE2      0.000000  1.000000  0.000000        0.00000
SCALE3      0.000000  0.000000  1.000000        0.00000

Coordinate Section

La secció de coordenades conté les coordenades de cada àtom per a cada model en l’estructura de la proteïna. Aquesta secció és la més gran de qualsevol fitxer PDB. La manera més fàcil de trobar-la és buscar la primera línia que comenci amb ATOM.

✅ Activitat

Escriu un script en Python que et mostri la primera línia:

En aquesta activitat, parlarem dels registres MODEL, ATOM, i TER.

Model Record

T ípicament, les proteïnes determinades per cristal·lografia només tindran un model. Com que 2HAC va ser determinada per espectroscòpia RMN, hi ha diverses conformacions de proteïnes que són consistents amb les dades de RMN. Cada conformació es registra com el seu propi model.

Un model generalment es veu així:

MODEL        [model_num]
ATOM      1  [...]
ATOM      2  [...]
ATOM      3  [...]
[...]
ENDMDL

És a dir, un registre de model comença amb MODEL, seguit d’una llista de registres ATOM, i acaba amb ENDMDL.

Hi ha 15 registres de model donats en 2HAC.

✅ Activitat

Escriu un script en Python que conti el número de models:

Atom Record

Un registre ATOM és d’una sola línia i apareix múltiples vegades (una per cada àtom, per cada model).

Aquí hi ha un exemple:

ATOM      2  CA  ASP A  -3     -24.877   1.931  -4.644  1.00  0.00           C

Aquest registre indica que l’àtom #2 s’anomena CA, que forma part del residu d’àcid aspàrtic a la cadena A, i el seu ID de residu és -3. Després se’ns donen les coordenades ortogonals de l’àtom (-24.877, 1.931, -4.644).

Després de les coordenades de l’àtom, tenim dos números especials: l’ocupació i el factor de temperatura (també conegut com a factor B).

L’ocupació és la proporció de temps que l’àtom passa ocupant una posició particular. Aquest camp és especialment important quan una regió molecular és molt flexible. En el cas de 2HAC, tots els àtoms (de cada model) prenen només una conformació, així que la seva ocupació és del 100% (o 1.00).

El factor B es discuteix en detall a Average and …. Els àtoms amb un factor B gran generalment corresponen a regions més flexibles de la molècula.

L’últim camp en aquest registre és el símbol elemental de l’àtom. Aquest és el símbol de l’àtom que es donaria en una taula periòdica d’elements. Com que l’àtom #2 és un àtom de carboni, el seu símbol és C.

TER Record

Com hem mencionat anteriorment, 2HAC té dues cadenes, anomenades A i B. Es dona un registre TER després que es llisten tots els àtoms d’una cadena.

Per exemple, aquest és el registre TER donat al final de la cadena A en el model 1:

ATOM    543  HB2 ASP A  30      13.952  -5.133 -14.399  1.00  0.00           H
ATOM    544  HB3 ASP A  30      13.434  -6.033 -12.973  1.00  0.00           H
TER     545      ASP A  30
ATOM    546  N   ASP B  -3     -24.040  -6.834   4.973  1.00  0.00           N
ATOM    547  CA  ASP B  -3     -24.918  -6.297   3.894  1.00  0.00           C

El registre TER indica el nom de l’últim residu i cadena per a l’àtom que s’acaba de donar.

Bookkeeping Section

Hi ha dos registres al final d’un fitxer PDB: MASTER i END.

El registre MASTER llista el nombre total de certs registres que apareixen:

MASTER      151    0    0    2    0    0    0    6  530    2    2    6

In the above example, we can see that there are 124 REMARK records and 530 atomic coordinate records(ATOM + HETATM).

✅ Activitat

Ves a la secció MASTER de l’especificació i digues que indiquen els altres números.

The final record is simply END.

✅ Activitat

Escriu un script en Python que mostri la informació de la secció MASTER indicant a que correspon cada valor:

PDB Visualization

PyMol

PyMOL is a molecular-viewing program that can be used to view molecular structures like 2HAC.

TODO completar

iCn3D

TODO revisar

L’NCBI proporciona una eina molt potent per a visualitzar i treballar amb proteïnes i altres estructures en format PDB i molts altres: ICN3D.

iCn3D

I see in 3D” (iCn3D) Structure Viewer is not only a web-based 3D viewer, but also a structure analysis tool interactively or in the batch mode using NodeJS scripts based on the npm package icn3d. iCn3D synchronizes the display of 3D structure, 2D interaction, and 1D sequences and annotation.

TODO té tutorials, etc.

frame “https://structure.ncbi.nlm.nih.gov/Structure/icn3d/

Obrim la pàgina, i ens dóna diverses opcions per visualizar en 3D les proteïnes.

O bé indicant una llista d’indentificadors (de PDB o altres) i pitjant INTRO.

Per exemple 1HHO,4N7N;

frame “https://structure.ncbi.nlm.nih.gov/Structure/icn3d/?mmdbafid=1HH0,4N7N&bu=1

Apart d’obtenir la animació en 3d de 2 proteïnes alhora, teniu una barra d’eines molt potent.

L’altra manera de carregar el/s fitxers PDB (o altres formats) és obrint un o més fitxers descarregats.

Provem de carregar la proteïna 6YYT del SARS-CoV-2 al portal web de l’icn3d. És la polimerasa (encarregada de replicar el virus) Primer cal descarregar-la:

$ wget https://files.rcsb.org/download/6YYT.pdb

Obrim el menú principal de la pàgina, opció File i seleccionem el format.

Així és la proteïna 6YYT SARS-CoV-2:

  • Dos suports helicoïdals amb diferents tons de color blau són la cadena de plantilla d’ARN i la seva cadena de producte.

  • La major part de les cintes de color rosa és la polimerasa, que és un enzim (proteïna funcional) que fa còpies de la cadena d’ARN. Aquesta polimerasa és un objectiu atractiu per a la vacuna antiviral COVID-19.

Si voltem la molècula, podem veure les cintes grogues, verdes i taronges, que són les proteïnes víriques que ajuden a la polimerasa a mantenir-se en el camí i copiar porcions llargues de la cadena d’ARN.

Hi ha diverses formes d’exposar la proteïna animada o una imatge estàtica (PNG) a la nostra pàgina web. S’exposa com funciona cada una a la web oficial:

frame “https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d.html#HowToUse

Tal i com veieu les captures, tenim maneres molt interessants: crear scripts de Python juntament amb Biopython i bolcar els resultats al front-end.

Mètode 1. Embedir el giny (widget) amb un IFrame d’HTML (tal i com faríem amb Google Maps i altres serveis)

La web proposa aquest Iframe:

<iframe allowFullScreen='true' src='https://www.ncbi.nlm.nih.gov/Structure/icn3d/?mmdbid=1tup&width=300&height=300&closepopup=1&showcommand=0&shownote=0&mobilemenu=1&showtitle=0' width='320' height='320' style='border:none'></iframe>

Per a què quedi una mica millor cal decidit adaptar-lo d’aquesta manera, així es mostrarà el títol:

      <main className="container mt-5">
        <h2 className="text-center mt-5 fs-2">BioActivitat 6 - Estructures de proteïnes.</h2>
        <iframe src='https://www.ncbi.nlm.nih.gov/Structure/icn3d/?mmdbid=1tup&closepopup=1&showcommand=0&shownote=0&mobilemenu=1&showtitle=1'
          class="w-full aspect-video">
        </iframe>
      </main>

I així ja el pots en una pàgina qualsevol.

El paràmetre de l’iframe que defineix la proteïna és mmdbid, pots provar de canviar-la per veure si et visualitza una altra proteïna; per exemple, la mmdbid=4N78.


Activitats

1.- Prova d’embedir l’ <iframe> en una de les teves pàgines web, assegura’t que es vegi bé i surti el títol de la proteïna.

2.- A fegeix una utilitat al plugin per tal que l’usuari pugui posar un id de proteïna en un camp d’un formulari i al pitjar el botó se li carregui la proteïna en 3d que ha seleccionat.

En ambdós casos hauràs de personalitzar de manera estàtica (2.1) o dinàmica (2.2) la URL del iframe:

El resultat hauria de ser semblant a aquest:

Pista:

  const url = `https://www.ncbi.nlm.nih.gov/Structure/icn3d/?mmdbid=${protid}&closepopup=1&showcommand=1&shownote=0&mobilemenu=1&showtitle=1`;

Més sobre el Format PDB

Utilitzarem eines de visualització PDB per ajudar-nos a entendre algunes característiques addicionals dels fitxers PDB.

iwr https://files.rcsb.org/download/4HG6.pdb -OutFile 4HG6.pdb

L’estructura PDB 4HG6 va ser determinada per cristal·lografia de raigs X, i es veu així:

En la imatge anterior, la cadena A està acolorida en cian, la cadena B en taronja, i els àtoms d’heterògens es mostren com a esferes.

Heterògens

El format PDB es pot utilitzar per descriure residus “no estàndard”, anomenats heterògens.

La Heterogen Section i la Coordinate Section contenen informació sobre heterògens.

La secció d’heterògens de 4HG6 comença amb un registre HET a la línia 1221.

HET    BGC  C   1      12

Aquest registre ens diu que l’heterogen #901 s’anomena BGC, forma part de la cadena A, i té 12 registres HETATM corresponents.

Unes línies més endavant, un registre HETNAM ens diu el nom complet de BGC:

HETNAM     BGC BETA-D-GLUCOPYRANOSE

Els registres HETATM són anàlegs als registres ATOM, excepte que donen informació sobre substàncies químiques que no són aminoàcids o nucleòtids estàndard. Per exemple, tant l’aigua com els aminoàcids modificats es consideren heterògens.

A continuació es mostra la primera entrada d’àtom heterogen:

HETATM10783  C2  BGC C   1      11.313  82.102 123.399  1.00195.30           C

L’àtom té el número de sèrie 10783, s’anomena C2, forma part del residu BGC #901, i és un àtom de carboni.

Com que hi ha tants àtoms en aquesta entrada PDB, els dos primers camps (HETATM i 10783) no estan separats. Com s’ha mencionat anteriorment, això és perquè el format PDB utilitza la posició de columna per delimitar camps.

La imatge següent mostra tots els heterògens presents en 4HG6:

Aquí, BGC és β-D-glucosa, UDP és uridina difosfat, i LDA és òxid de lauril dimetilamina-n. Cal notar que hi ha diversos residus BGC enllaçats junts, formant un oligosacàrid d’una sola cadena. També cal notar que els àtoms d’hidrogen s’ometen d’aquesta entrada PDB. Això és perquè la resolució de raigs X ha de ser molt alta (per sota d’1Å) per veure els àtoms d’hidrogen.

Connectivitat

Anteriorment hem mencionat el tipus de registre SSBOND, que dona informació sobre els enllaços disulfur.

A més d’un enllaç disulfur, 4HG6 especifica altres connexions. Els residus heterògens en 4HG6 estan connectats entre si mitjançant registres LINK:

LINK         O4  BGC C   1                 C1  BGC C   2     1555   1555  1.44

En altres paraules, l’àtom O4 de BGC #912 està connectat a l’àtom C1 de BGC #913, i la distància d’enllaç és d’1,42 àngstroms.

El registre LINK anterior especifica una connexió entre residus (entre BGC 912 i 913). No obstant això, els heterògens també han d’especificar les connexions entre altres àtoms heterògens.

Això es fa amb el registre CONECT:

CONECT 6748 8743

Aquest exemple simplement enllaça dos àtoms (#6748 i #8743).

A continuació hi ha un exemple més complicat:

CONECT10783107841078810790

De nou, aquest format tan compacte es deu a l’ús de números de columna per delimitar camps, en lloc d’utilitzar un caràcter separador de camp (com una coma o espai).

Això és com es veuria el registre anterior amb espais entre cada camp:

CONECT 10783 10784 10788 10790

Per entendre què està passant en aquest registre, compara’l amb la següent imatge:

En el residu BGC anterior, cada àtom està etiquetat pel seu número de sèrie. Ara podem veure que l’àtom 10783 està connectat als àtoms 10784, 10788 i 10790.

mmCIF

El 2014, els desenvolupadors del PDB van deixar de modificar i estendre el format PDB. Com que el format PDB utilitza la posició de columnes per delimitar camps, una de les seves principals limitacions és que no permet la descripció d’estructures que continguin més de 99.999 àtoms. Això és perquè només es reserven 5 posicions de columna per al número de sèrie d’un àtom. De manera similar, ja que només una columna pot descriure un identificador de cadena, cap estructura en format PDB pot tenir més de 62 cadenes (els caràcters permesos són: a-z, A-Z i 0-9).

Per aquestes i altres raons, hi ha un nou format estàndard per a estructures a l’arxiu PDB: PDBx/mmCIF, o simplement mmCIF, que significa “Macromolecular CIF”. El nom deriva del format Crystallographic Information File (CIF), que descriu petites molècules. En aquesta lliçó, descrivim les característiques importants del format mmCIF.

Lesson 4: PDBx/mmCIF

Activitats

Principals estructures de proteïnes humanes

De les aproximadament 20.000 seqüències de proteïnes humanes canòniques, en data de 20 de gener de 2021, s’han determinat les estructures completes o parcials, de resolució mitjana a alta, de 7.077 proteïnes mitjançant cristal·lografia de raigs X o altres mètodes. Quines d’aquestes proteïnes dominen el banc de dades de proteïnes (el PDB) i per què? En aquest article, llistem les 273 principals estructures de proteïnes humanes basades en el nombre de les seves entrades PDB. Aquest conjunt de proteïnes representa més del 40% de totes les entrades PDB humanes disponibles i representa tant les tendències passades com l’estat actual de la biologia estructural de proteïnes.


Biopython

Referència: Going 3D: The PDB module

Biopython té un el mòdul PDB que ens permet obtenir tota la informació de les proteïnes, i manipular-la.

Aquí en veiem un exemple, que descarrega una cadena d’aminoàcids del Sars-Cov-2.

from Bio.PDB import PDBParser
import urllib.parse
import os
# Original sources.
# https://biopython.org/DIST/docs/tutorial/Tutorial.html#sec240

pdb_file : str = 'data/6YYT.pdb' 
if not os.path.exists(pdb_file):
    urllib.request.urlretrieve('http://files.rcsb.org/download/6YYT.pdb', pdb_file)

parser = PDBParser()
structure = parser.get_structure('6YYT', pdb_file)
print(structure)

# To identify how many chains this 6YYT SARS-CoV-2 viral protein has, we use chain.id function which gives us the list of the chains that are present.
for chain in structure[0]:
    print(f'chain ID: {chain.id}')

# Other useful data.
# Long JSON.
# print(structure.header)
print('Keywords ',structure.header["keywords"])

Fitxers PDB

Working with PDB files in Python

El punt principal d’aquesta activitat és mostrar com podem manipular les dades de PDB amb la pila habitual de PyData, especialment els dataframes de Pandas (de manera que no cal que aprenguis una API completament nova) i com podem visualitzar de manerar simle les proteïnes.


Càrrega en fitxers PDB

Per a aquesta part, farem servir BioPandas i ProDy, podeu instal·lar-los al vostre entorn Python mitjançant pip:

pip install biopandas prody 

A continuació tens una funció que llegeix un fitxer PDB des d’una ruta d’arxiu o un ID PDB/Uniprot a un DataFrame de pandas, que s’ha adaptat del paquet Graphein:

import pandas as pd
from biopandas.pdb import PandasPdb
from prody import parsePDBHeader
from typing import Optional

def read_pdb_to_dataframe(
    pdb_path: Optional[str] = None,
    model_index: int = 1,
    parse_header: bool = True,
    ) -> pd.DataFrame:
    """
    Read a PDB file, and return a Pandas DataFrame containing the atomic coordinates and metadata.

    Args:
        pdb_path (str, optional): Path to a local PDB file to read. Defaults to None.
        model_index (int, optional): Index of the model to extract from the PDB file, in case
            it contains multiple models. Defaults to 1.
        parse_header (bool, optional): Whether to parse the PDB header and extract metadata.
            Defaults to True.

    Returns:
        pd.DataFrame: A DataFrame containing the atomic coordinates and metadata, with one row
            per atom
    """
    atomic_df = PandasPdb().read_pdb(pdb_path)
    if parse_header:
        header = parsePDBHeader(pdb_path)
    else:
        header = None
    atomic_df = atomic_df.get_model(model_index)
    if len(atomic_df.df["ATOM"]) == 0:
        raise ValueError(f"No model found for index: {model_index}")

    return pd.concat([atomic_df.df["ATOM"], atomic_df.df["HETATM"]]), header

Aquesta funció integra la capacitat d’analitzar la capçalera PDB en forma de diccionari de tal manera que ens permet emmagatzemar tota la informació útil que cal utilitzar en les tasques posteriors.

Descarregua el fitxer 3NIR:

$ wget https://files.rcsb.org/download/3NIR.pdb

Llegim el fitxer

df, df_header = read_pdb_to_dataframe('3nir.pdb')
df.head(10)

TODO resultat

>>> print(df.shape)
(1026, 22)
>>> print(df_header.keys())
dict_keys(['helix', 'helix_range', 'sheet', 'sheet_range', 'chemicals', 'polymers', 'reference', 'resolution', 'biomoltrans', 'version', 'deposition_date', 'classification', 'identifier', 'title', 'experiment', 'authors', 'space_group', 'related_entries', 'EOH', 'A'])

La variable df és un dataframe Pandas que permet manipular i analitzar dades de manera molt fàcil.

Aquí tens un exemple d’obtenir les coordenades x, y, z dels carbonis alfa:

df.loc[df['atom_name']=='CA', ['x_coord', 'y_coord', 'z_coord']]

Visualitzacions en 3D senzilles: traçar àtoms

La visualització de proteïnes és crucial perquè proporciona una manera tangible d’entendre les seves complexes estructures 3D, que és fonamental per entendre les seves funcions, interaccions i el paper que tenen en els processos biològics.

Per a això, utilitzem el paquet Plotly de Python per a la visualització en 3D.

Si encara no està instal·lat al vostre entorn Python, podeu instal·lar-lo fàcilment:

$ pip install plotly 

Utilitzant la funció scatter_3d, podem representar el núvol de punts àtoms acolorit pel seu element:

import plotly.express as px

fig = px.scatter_3d(df, x='x_coord', y='y_coord', z='z_coord', color='element_symbol')
fig.update_traces(marker_size = 4)

fig.show()

TODO mostrar gràfic

Manipulació de marcs de dades PDB — Construcció de gràfics de proteïnes

Utilitzarem el paquet Graphein a Python com a eix vertebrador de les nostres manipulacions i visualitzacions de dades més complexes. Per instal·lar-lo executeu:

pip install graphein

Admet la creació de representacions de gràfics a partir de dades estructurals de proteïnes, permetent una anàlisi i una visualització més detallada i interactiva de les estructures de proteïnes més enllà del simple gràfic de núvols de punts. Tracem gràfics de residus per entendre les complexes relacions espacials i interaccions entre diferents residus en una estructura de proteïnes. Graphein proposa una API d’alt nivell, però, es carrega directament a la proteïna des del fitxer PDB, forçant la manipulació de dades a través de la seva API opaca, que pot ser feixuga. Per evitar-ho, aquí teniu passos ràpids i senzills per construir el gràfic a partir d’un marc de dades de Pandas (que hem carregat anteriorment al pas 1):

Primer processem el marc de dades mitjançant mètodes pandas estàndard. És important etiquetar cada node (àtom/residu) amb un identificador únic. Per a això fem servir label_node_id , que concatena chain_id:residue_name:residue_number:alt_loc (si la granularitat s’estableix a ‘atom’, substitueix residue amb atom ).

from graphein.protein.graphs import label_node_id

def process_dataframe(df: pd.DataFrame, granularity='CA') -> pd.DataFrame:
    """
    Process a DataFrame of protein structure data to reduce ambiguity and simplify analysis.

    This function performs the following steps:
    1. Handles alternate locations for an atom, defaulting to keep the first one if multiple exist.
    2. Assigns a unique node_id to each residue in the DataFrame, using a helper function label_node_id.
    3. Filters the DataFrame based on specified granularity (defaults to 'CA' for alpha carbon).

    Parameters
    ----------
    df : pd.DataFrame
        The DataFrame containing protein structure data to process. It is expected to contain columns 'alt_loc' and 'atom_name'.
        
    granularity : str, optional
        The level of detail or perspective at which the DataFrame should be analyzed. Defaults to 'CA' (alpha carbon).
    """
    # handle the case of alternative locations,
    # if so default to the 1st one = A
    if 'alt_loc' in df.columns:
      df['alt_loc'] = df['alt_loc'].replace('', 'A')
      df = df.loc[(df['alt_loc']=='A')]
    df = label_node_id(df, granularity)
    df = df.loc[(df['atom_name']==granularity)]
    return df
>>> process_df = process_dataframe(df)
>>> print(process_df.shape)
(46, 24)
  1. A continuació, inicialitzem un gràfic (és a networkx object) amb totes les metadades útils.
from graphein.protein.graphs import initialise_graph_with_metadata

>>> g = initialise_graph_with_metadata(protein_df=process_df, # from above cell
                                    raw_pdb_df=df, # Store this for traceability
                                    pdb_code = '3nir', #and again
                                    granularity = 'CA' # Store this so we know what kind of graph we have
                                    )
  1. Ara afegim tots els nodes al nostre gràfic.
from graphein.protein.graphs import add_nodes_to_graph

>>> g = add_nodes_to_graph(g)
>>> print(g.nodes)

NodeView(('A:THR:1:A', 'A:THR:2:A', 'A:CYS:3:A', 'A:CYS:4:A', 'A:PRO:5:A', 'A:SER:6:A', 'A:ILE:7:A', 'A:VAL:8:A', 'A:ALA:9:A', 
'A:ARG:10:A', 'A:SER:11:A', 'A:ASN:12:A', 'A:PHE:13:A', 'A:ASN:14:A', 'A:VAL:15:A', 'A:CYS:16:A', 'A:ARG:17:A', 'A:LEU:18:A', 
'A:PRO:19:A', 'A:GLY:20:A', 'A:THR:21:A', 'A:PRO:22:A', 'A:GLU:23:A', 'A:ALA:24:A', 'A:LEU:25:A', 'A:CYS:26:A', 'A:ALA:27:A', 
'A:THR:28:A', 'A:TYR:29:A', 'A:THR:30:A', 'A:GLY:31:A', 'A:CYS:32:A', 'A:ILE:33:A', 'A:ILE:34:A', 'A:ILE:35:A', 'A:PRO:36:A', 
'A:GLY:37:A', 'A:ALA:38:A', 'A:THR:39:A', 'A:CYS:40:A', 'A:PRO:41:A', 'A:GLY:42:A', 'A:ASP:43:A', 'A:TYR:44:A', 'A:ALA:45:A', 
'A:ASN:46:A'))
  1. Les interaccions que volem capturar a la nostra proteïna defineixen quin tipus d’arestes construirem en el nostre gràfic. Per a aquest exemple, simplement connectarem els residus seguint la columna vertebral, això il·lustra com podem escriure funcions de vora personalitzades. La majoria dels bons ja estan implementats graphein.protein.edges. Aquesta és una versió simplificada de add_peptide_bond
import networkx as nx
def add_backbone_edges(G: nx.Graph) -> nx.Graph:
    # Iterate over every chain
    for chain_id in G.graph["chain_ids"]:
        # Find chain residues
        chain_residues = [
            (n, v) for n, v in G.nodes(data=True) if v["chain_id"] == chain_id
        ]
        # Iterate over every residue in chain
        for i, residue in enumerate(chain_residues):
            try:
                # Checks not at chain terminus
                if i == len(chain_residues) - 1:
                    continue
                # Asserts residues are on the same chain
                cond_1 = ( residue[1]["chain_id"] == chain_residues[i + 1][1]["chain_id"])
                # Asserts residue numbers are adjacent
                cond_2 = (abs(residue[1]["residue_number"] - chain_residues[i + 1][1]["residue_number"])== 1)

                # If this checks out, we add a peptide bond
                if (cond_1) and (cond_2):
                    # Adds "peptide bond" between current residue and the next
                    if G.has_edge(i, i + 1):
                        G.edges[i, i + 1]["kind"].add('backbone_bond')
                    else:
                        G.add_edge(residue[0],chain_residues[i + 1][0],kind={'backbone_bond'},)
            except IndexError as e:
                print(e)
    return G
>>> g = add_backbone_edges(g)
>>> print(len(g.edges()))
45

Nota: el paquet Graphein és molt rígid en la manera com està dissenyat per utilitzar-lo. Requereix que ho inicialitzeu tot mitjançant les classes Graphein, qualsevol pas fora de l’ecosistema sol trobar-se amb errors. Això no funciona bé en un context de recerca. Tanmateix, trobo que el paquet és útil per a les plantilles de codi que puc modificar per adaptar-se als meus casos d’ús específics.

El paquet Graphein a Python (creat amb Plotly) també es pot utilitzar per visualitzar proteïnes.

Cada residu aquí està representat i connectat pel seu carboni alfa.

from graphein.protein.visualisation import plotly_protein_structure_graph

p = plotly_protein_structure_graph(
    g,
    colour_edges_by="kind",
    colour_nodes_by="seq_position",
    label_node_ids=False,
    plot_title="3NIR Backbone Protein Graph",
    node_size_multiplier=1,
)
p.show()

Treballar amb fitxers PDB multicadena

No ens limitem a cadenes proteiques úniques. Les proteïnes sovint formen complexos perquè molts processos biològics requereixen l’acció coordinada de múltiples proteïnes. Una proteïna multicadena és un complex proteic format per més d’una cadena polipeptídica, cadascuna codificada per un gen separat, que interaccionen junts per realitzar una funció o conjunt de funcions específics.

Per a això, prenem el complex https://www.rcsb.org/structure/6KDE[6KDE]() (heterodímer). Mirant la capçalera del fitxer PDB ( descarregueu aquí ) observem que tenim informació sobre cada cadena:

HEADER    OXIDOREDUCTASE                          02-JUL-19   6KDE              
TITLE     CRYSTAL STRUCTURE OF THE ALPHA BETA HETERODIMER OF HUMAN IDH3 IN      
TITLE    2 COMPLEX WITH CA(2+)                                                  
COMPND    MOL_ID: 1;                                                            
COMPND   2 MOLECULE: ISOCITRATE DEHYDROGENASE [NAD] SUBUNIT ALPHA,              
COMPND   3 MITOCHONDRIAL;                                                       
COMPND   4 CHAIN: A, C;                                                         
COMPND   5 SYNONYM: ISOCITRIC DEHYDROGENASE SUBUNIT ALPHA,NAD(+)-SPECIFIC ICDH  
COMPND   6 SUBUNIT ALPHA;                                                       
COMPND   7 EC: 1.1.1.41;                                                        
COMPND   8 ENGINEERED: YES;                                                     
COMPND   9 MOL_ID: 2;                                                           
COMPND  10 MOLECULE: ISOCITRATE DEHYDROGENASE [NAD] SUBUNIT BETA, MITOCHONDRIAL;
COMPND  11 CHAIN: B, D;                                                         
COMPND  12 SYNONYM: ISOCITRIC DEHYDROGENASE SUBUNIT BETA,NAD(+)-SPECIFIC ICDH   
COMPND  13 SUBUNIT BETA;                                                        
COMPND  14 ENGINEERED: YES 

El complex està format per cadenes A i C (subunitat alfa) que s’uneixen amb cadenes B i D (subunitat beta). El dibuix del núvol de punts atòmics acolorit per la cadena d’identificació dóna:

df, df_header = read_pdb_to_dataframe('6kde.pdb')
fig = px.scatter_3d(df, x='x_coord', y='y_coord', z='z_coord', color='chain_id')
fig.update_traces(marker_size = 4)

fig.show()

Només podem mirar el complex format per les cadenes A i B. Cada àtom del marc de dades està vinculat a una cadena específica amb el chain_id atribut.

df = pd.concat((df[df['chain_id']=='A'], df[df['chain_id']=='B']))

>>> df['chain_id'].unique()
array(['A', 'B'], dtype=object)

Això torna a ressaltar el fàcil que és manipular dades de proteïnes amb Pandas. Representació del marc de dades actualitzat df utilitzant el mateix codi anterior: Extracció d’interfícies de proteïnes mitjançant Pandas

Les interfícies de proteïnes tenen un paper crucial en la comprensió de la funció i les interaccions de les proteïnes dins dels sistemes biològics. Per il·lustrar el treball amb proteïnes multicadenes, podem extreure la interfície o el contacte entre dues cadenes. La funció següent mostra com es pot aconseguir fàcilment amb numpy.

import numpy as np

def get_contact_atoms(df1: pd.DataFrame, df2:pd.DataFrame = None , threshold:float = 7., coord_names=['x_coord', 'y_coord', 'z_coord']):
    # Extract coordinates from dataframes
    coords1 = df1[coord_names].to_numpy()
    coords2 = df2[coord_names].to_numpy()

    # Compute pairwise distances between atoms
    dist_matrix = np.sqrt(((coords1[:, None] - coords2) ** 2).sum(axis=2))

    # Create a new dataframe containing pairs of atoms whose distance is below the threshold
    pairs = np.argwhere(dist_matrix < threshold)
    atoms1, atoms2 = df1.iloc[pairs[:, 0]], df2.iloc[pairs[:, 1]]
    atoms1_id = atoms1['chain_id'].map(str) + ":" + atoms1['residue_name'].map(str) + ":" + atoms1['residue_number'].map(str)
    atoms2_id = atoms2['chain_id'].map(str) + ":" + atoms2['residue_name'].map(str) + ":" + atoms2['residue_number'].map(str)
    node_pairs = np.vstack((atoms1_id.values, atoms2_id.values)).T
    result = pd.concat([df1.iloc[np.unique(pairs[:, 0])], df2.iloc[np.unique(pairs[:, 1])]])

    return result, node_pairs

En aquest exemple obtindrem tots els àtoms entre les cadenes A i B que tenen una diferència de 7 Angstrom:

df_A = df[df['chain_id']=='A']
df_B = df[df['chain_id']=='B']
contact_atoms, node_pairs = get_contact_atoms(df_A, df_B, 7.)

Traçant això a Plotly, la interfície es ressalta en taronja:

import plotly.express as px
import plotly.graph_objects as go

# Create 3D scatter plots for df_A, df_B, and contact_atoms
fig = go.Figure()

# Add trace for df_A
fig.add_trace(
    go.Scatter3d(
        name='Chain A',
        x=df_A['x_coord'],
        y=df_A['y_coord'],
        z=df_A['z_coord'],
        mode='markers',
        marker=dict(size=4, color='blue', opacity=0.5),  # Adjust opacity here
    )
)

# Add trace for df_B
fig.add_trace(
    go.Scatter3d(
        name='Chain B',
        x=df_B['x_coord'],
        y=df_B['y_coord'],
        z=df_B['z_coord'],
        mode='markers',
        marker=dict(size=4, color='red', opacity=0.5),  # Adjust opacity here
    )
)

# Add trace for contact_atoms
fig.add_trace(
    go.Scatter3d(
        name='Contact Atoms',
        x=contact_atoms['x_coord'],
        y=contact_atoms['y_coord'],
        z=contact_atoms['z_coord'],
        mode='markers',
        marker=dict(size=6, color='orange'),  # You can adjust the color and opacity here
    )
)

# Customize the layout
fig.update_layout(
    scene=dict(
        aspectmode="cube",  # To maintain equal axis scaling
    ),
    margin=dict(l=0, r=0, b=0, t=0),
)

# Show the plot
fig.show()

TODO