I have a lot of PDB IDs and I need to get uniprot fasta sequences of these PDB IDs special chains by API services. For example, imagine that I need to get fasta sequence of '1kf6' 'A' chain. The uniprot entry (Accession) for this '1kf6' chain is 'P00363'. If I find a way to get this entry, I can simply retrieve its fasta sequence using bioservices package:

from bioservices import *
u = UniProt()
sequence = u.retrieve("P00363","fasta")

The main problem is that I don't know how can I find this uniprot entry("P00363" here) for each chains in PDB IDs(here I imagine that I don't know this "P00363" is the uniprot entry for '1kf6' 'A' chain and I'm trying to find it using API services). I tried to use ID mapping. In ID mapping cross-references, the chain name for each entry is specified and if I can add a cross-reference column to u.search('1kf6', columns="id,entry name,length, genes,pdb"), I can simply find the entry related to my favourite chain. The following code returns some entries each related to one of '1kf6' chains. The problem is that I don't know exactly which entry is related to 'A' chain that here is my favorite chain. In the following code, id searches for entry and other parameters search for sth else related to them:

from bioservices import *
u = UniProt()
res = u.search("1kf6",columns="id,entry name,length, genes")

Each one of the following words can be used and added to columns part:

'id', 'entry name', 'genes', 'genes(PREFERRED)', 'genes(ALTERNATIVE)', 'genes(OLN)', 'genes(ORF)', 'organism', 'organism-id', 'protein names', 'proteome', 'lineage(ALL)', 'lineage-id', 'virus hosts', 'fragement', 'sequence', 'length', 'mass', 'encodedon', 'comment(ALTERNATIVE PRODUCTS)', 'comment(ERRONEOUS GENE MODEL PREDICTION)', 'comment(ERRONEOUS INITIATION)', 'comment(ERRONEOUS TERMINATION)', 'comment(ERRONEOUS TRANSLATION)', 'comment(FRAMESHIFT)', 'comment(MASS SPECTROMETRY)', 'comment(POLYMORPHISM)', 'comment(RNA EDITING)', 'comment(SEQUENCE CAUTION)', 'feature(ALTERNATIVE SEQUENCE)', 'feature(NATURAL VARIANT)', 'feature(NON ADJACENT RESIDUES)', 'feature(NON STANDARD RESIDUE)', 'feature(NON TERMINAL RESIDUE)', 'feature(SEQUENCE CONFLICT)', 'feature(SEQUENCE UNCERTAINTY)', 'version(sequence)', 'domains', 'domain', 'comment(DOMAIN)', 'comment(SIMILARITY)', 'feature(COILED COIL)', 'feature(COMPOSITIONAL BIAS)', 'feature(DOMAIN EXTENT)', 'feature(MOTIF)', 'feature(REGION)', 'feature(REPEAT)', 'feature(ZINC FINGER)', 'ec', 'comment(ABSORPTION)', 'comment(CATALYTIC ACTIVITY)', 'comment(COFACTOR)', 'comment(ENZYME REGULATION)', 'comment(FUNCTION)', 'comment(KINETICS)', 'comment(PATHWAY)', 'comment(REDOX POTENTIAL)', 'comment(TEMPERATURE DEPENDENCE)', 'comment(PH DEPENDENCE)', 'feature(ACTIVE SITE)', 'feature(BINDING SITE)', 'feature(DNA BINDING)', 'feature(METAL BINDING)', 'feature(NP BIND)', 'feature(SITE)', 'go', 'go(biological process)', 'go(molecular function)', 'go(cellular component)', 'go-id', 'interpro', 'interactor', 'comment(SUBUNIT)', 'citation', 'citationmapping', 'created', 'last-modified', 'sequence-modified', 'version(entry)', '3d', 'feature(BETA STRAND)', 'feature(HELIX)', 'feature(TURN)', 'comment(SUBCELLULAR LOCATION)', 'feature(INTRAMEMBRANE)', 'feature(TOPOLOGICAL DOMAIN)', 'feature(TRANSMEMBRANE)', 'annotation score', 'score', 'features', 'comment(CAUTION)', 'comment(TISSUE SPECIFICITY)', 'comment(GENERAL)', 'keywords', 'context', 'existence', 'tools', 'reviewed', 'feature', 'families', 'subcellular locations', 'taxonomy', 'version', 'clusters', 'comments', 'database', 'keyword-id', 'pathway', 'score'

I used some of the above words in columns part but they couldn't retrieve chain name. Anyone know which one of the above parameters can give me the chain name for this PDB ID? or anyone has any other idea for finding uniprot entry(UniprotKB AC) related to each PDB ID chain by API services?


I found the answer and I thought it may be useful for others. we can use pypdb package for that purpose (it works in unix systems):

import pypdb

all_info = pypdb.get_all_info('1kf6')

the output is as follows:

{'polymer': [{'@entityNr': '1', '@length': '602', '@type': 'protein', '@weight': '66057.6', 'chain': [{'@id': 'A'}, {'@id': 'M'}], 'Taxonomy': {'@name': 'Escherichia coli', '@id': '562'}, 'macroMolecule': {'@name': 'Fumarate reductase flavoprotein subunit', 'accession': {'@id': 'P00363'}}, 'polymerDescription': {'@description': 'FUMARATE REDUCTASE FLAVOPROTEIN'}, 'enzClass': {'@ec': ''}}, {'@entityNr': '2', '@length': '243', '@type': 'protein', '@weight': '27021.9', 'chain': [{'@id': 'B'}, {'@id': 'N'}], 'Taxonomy': {'@name': 'Escherichia coli', '@id': '562'}, 'macroMolecule': {'@name': 'Fumarate reductase iron-sulfur subunit', 'accession': {'@id': 'P0AC47'}}, 'polymerDescription': {'@description': 'FUMARATE REDUCTASE IRON-SULFUR PROTEIN'}, 'enzClass': {'@ec': ''}}, {'@entityNr': '3', '@length': '130', '@type': 'protein', '@weight': '14898.8', 'chain': [{'@id': 'C'}, {'@id': 'O'}], 'Taxonomy': {'@name': 'Escherichia coli', '@id': '562'}, 'macroMolecule': {'@name': 'Fumarate reductase subunit C', 'accession': {'@id': 'P0A8Q0'}}, 'polymerDescription': {'@description': 'FUMARATE REDUCTASE 15 KDA HYDROPHOBIC PROTEIN'}}, {'@entityNr': '4', '@length': '119', '@type': 'protein', '@weight': '13118.9', 'chain': [{'@id': 'D'}, {'@id': 'P'}], 'Taxonomy': {'@name': 'Escherichia coli', '@id': '562'}, 'macroMolecule': {'@name': 'Fumarate reductase subunit D', 'accession': {'@id': 'P0A8Q3'}}, 'polymerDescription': {'@description': 'FUMARATE REDUCTASE 13 KDA HYDROPHOBIC PROTEIN'}}], 'id': '1KF6'}

This output gives all the information related to all chains and we can simply find uniprotkb AC of each chain in this output. I also found another answer for this question. This answer can be found here and the following code:

import requests
from xml.etree.ElementTree import fromstring

pdb_id = '1kf6.A'
pdb_mapping_url = 'http://www.rcsb.org/pdb/rest/das/pdb_uniprot_mapping/alignment'
uniprot_url = 'http://www.uniprot.org/uniprot/{}.xml'

def get_uniprot_accession_id(response_xml):
    root = fromstring(response_xml)
    return next(
        el for el in root.getchildren()[0].getchildren()
        if el.attrib['dbSource'] == 'UniProt'

def get_uniprot_protein_name(uniport_id):
    uinprot_response = requests.get(
    return fromstring(uinprot_response).find('.//{http://uniprot.org/uniprot}recommendedName/{http://uniprot.org/uniprot}fullName'

def map_pdb_to_uniprot(pdb_id):
    pdb_mapping_response = requests.get(
        pdb_mapping_url, params={'query': pdb_id}
    uniprot_id = get_uniprot_accession_id(pdb_mapping_response)
    uniprot_name = get_uniprot_protein_name(uniprot_id)
    return {
        'pdb_id': pdb_id,
        'uniprot_id': uniprot_id,
        'uniprot_name': uniprot_name

print (map_pdb_to_uniprot(pdb_id))

The output of this code is as follows:

{'pdb_id': '1kf6.A', 'uniprot_id': 'P00363', 'uniprot_name': 'Fumarate reductase flavoprotein subunit'}

An alternative solution involves the use of the SIFTS resource from the EBI. I wrote a python parser for their xml format, which will give you a mapping between a pdb and a uniprot entry at the single residue level.

$ curl --silent "ftp://ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/1kf6.xml.gz" | gunzip | python parse_sifts.py
1kf6    A       M       0       P00363  M       1
1kf6    A       Q       1       P00363  Q       2
1kf6    A       T       2       P00363  T       3
1kf6    A       F       3       P00363  F       4
1kf6    A       Q       4       P00363  Q       5
1kf6    A       A       5       P00363  A       6
1kf6    A       D       6       P00363  D       7
1kf6    A       L       7       P00363  L       8
1kf6    A       A       8       P00363  A       9
1kf6    A       I       9       P00363  I       10

The returned fields are as follows:

  • pdb ID
  • chain
  • pdb residue
  • pdb position
  • uniprot ID
  • uniprot residue
  • uniprot position

In the above snippet, just put your PDB ID of choice to retrieve the data you need.

  • $\begingroup$ It seems to be good but when I entered the code ($ curl --silent "ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/1kf6.xml.gz" | gunzip | python parse_sifts.py) in Cygwin, I got the following error: python: can't open file 'parse_sifts.py': [Errno 2] No such file or directory (23) Failed writing body $\endgroup$ – Sara Oct 27 '17 at 20:22
  • $\begingroup$ Are you sure that the Python script was in the same directory where you executed the snippet? $\endgroup$ – mgalardini Oct 29 '17 at 11:34
  • $\begingroup$ When I try to open "ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/1kf6.xml.gz" in my browser, I'll get this error: This site can’t be reached The webpage at ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/1kf6.xml.gz" might be temporarily down or it may have moved permanently to a new web address. ERR_FTP_FAILED. I think the problem is because of the server. $\endgroup$ – Sara Oct 29 '17 at 13:45
  • $\begingroup$ I just tried and it worked for me fine: ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/1kf6.xml.gz $\endgroup$ – mgalardini Oct 29 '17 at 20:58
  • $\begingroup$ Now it just worked for me too... $\endgroup$ – Sara Oct 30 '17 at 20:05

Check out this file on SIFT. ftp.ebi.ac.uk/pub/databases/msd/sifts/csv/pdb_chain_uniprot.csv It contains residue-wise mapping of PDB chains with uniprot ids.

# 2020/04/12 - 21:03 | PDB: 15.20 | UniProt: 2020.02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.