Skill Tracer
Skills › Scientific Agent Skills › bioservices › identifier_mapping.md

identifier_mapping.md

136 lines · skills/bioservices/references/identifier_mapping.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Identifier mapping with BioServices 1.16.0
2
3Reviewed 2026-09-30. Resolve species and identifier namespace before mapping;
4identical gene symbols across organisms are not equivalent entities.
5

Identifier mapping with BioServices 1.16.0

Reviewed 2026-09-30. Resolve species and identifier namespace before mapping; identical gene symbols across organisms are not equivalent entities.

Raw lines 1 to 5
6## UniProt request and response
7
8```python
9from bioservices import UniProt
10u = UniProt(verbose=False)
11source, target = "UniProtKB_AC-ID", "KEGG"
12if target not in u.valid_mapping.get(source, []):
13 raise ValueError("Unsupported mapping pair")
14response = u.mapping(fr=source, to=target, query="P43403,P04637")
15if not isinstance(response, dict) or "results" not in response:
16 raise RuntimeError("UniProt mapping did not complete")
17by_source = {}
18for row in response["results"]:
19 by_source.setdefault(row["from"], []).append(row["to"])
20print(by_source)
21print("Explicitly unmapped:", response.get("failedIds", []))
22```
24The SDK submits form data to `https://rest.uniprot.org/idmapping/run`, gets a
25`jobId`, polls `idmapping/status/{jobId}`, and follows result links. The response
26is `results` plus optional `failedIds`. A live P43403 -> KEGG lookup returned
27`{"from": "P43403", "to": "hsa:7535"}` within `results`. Do not call
28`response.get("P43403")` or merge envelopes with `dict.update` across batches.
30A reverse lookup uses `fr="KEGG", to="UniProtKB", query="hsa:7535"`. Its `to`
31value is a full protein record; normalize with `row["to"]["primaryAccession"]`.
32The source code `UniProtKB_AC-ID` is not a valid target. Alias `--to uniprot`
33in the bundled converter becomes `UniProtKB`, while `--from uniprot` becomes
34`UniProtKB_AC-ID`.
36`u.valid_mapping` is populated from the live
37[mapping catalogue](https://rest.uniprot.org/configure/idmapping/fields).
38Its rules constrain allowed pairs; a database can be source-only or target-only.
39Common current codes include KEGG, Ensembl, Ensembl_Protein,
40Ensembl_Transcript, GeneID, RefSeq_Protein, RefSeq_Nucleotide, HGNC, PDB,
41Reactome, STRING, and BioGRID. HGNC expects an HGNC identifier, not a bare symbol.
42GO, Pfam, InterPro, PRIDE and PaxDb were **absent** from the reviewed mapping
43catalogue; retrieve their cross-references or annotation fields from UniProt
44records instead of inventing a mapping job.
46```python
47record = u.retrieve("P43403", frmt="json")
48links = [item for item in record["uniProtKBCrossReferences"]
49 if item["database"] in {"GO", "Pfam", "InterPro"}]
50```
52The service permits up to 100,000 input IDs per job; output/enrichment/filter
53limits differ. Small chunks of 50–100 in the bundled converter are a workflow
54choice, not the provider's maximum. `max_waiting_time` bounds the SDK wait and
55may yield `None`. A `failedIds`-only completion can time out in 1.16.0 because
56its loop expects `results`; classify that as unresolved, not proven absent.
57For large jobs, use the provider's explicit job/status/details/results workflow
58so the job ID can be retained and resumed.
60[SDK mapping implementation](https://bioservices.readthedocs.io/en/main/_modules/bioservices/uniprot.html)
61and [UniProt mapping help](https://www.uniprot.org/help/id_mapping) describe the
62job contract. Search a symbol with `gene_exact:ZAP70 AND organism_id:9606` and
63review all candidate accessions before conversion. Searching reviewed records
64is useful when appropriate, but excludes unreviewed biology by design.

UniProt request and response

from bioservices import UniProt
u = UniProt(verbose=False)
source, target = "UniProtKB_AC-ID", "KEGG"
if target not in u.valid_mapping.get(source, []):
    raise ValueError("Unsupported mapping pair")
response = u.mapping(fr=source, to=target, query="P43403,P04637")
if not isinstance(response, dict) or "results" not in response:
    raise RuntimeError("UniProt mapping did not complete")
by_source = {}
for row in response["results"]:
    by_source.setdefault(row["from"], []).append(row["to"])
print(by_source)
print("Explicitly unmapped:", response.get("failedIds", []))

The SDK submits form data to https://rest.uniprot.org/idmapping/run, gets a jobId, polls idmapping/status/{jobId}, and follows result links. The response is results plus optional failedIds. A live P43403 -> KEGG lookup returned {"from": "P43403", "to": "hsa:7535"} within results. Do not call response.get("P43403") or merge envelopes with dict.update across batches.

A reverse lookup uses fr="KEGG", to="UniProtKB", query="hsa:7535". Its to value is a full protein record; normalize with row["to"]["primaryAccession"]. The source code UniProtKB_AC-ID is not a valid target. Alias --to uniprot in the bundled converter becomes UniProtKB, while --from uniprot becomes UniProtKB_AC-ID.

u.valid_mapping is populated from the live mapping catalogue. Its rules constrain allowed pairs; a database can be source-only or target-only. Common current codes include KEGG, Ensembl, Ensembl_Protein, Ensembl_Transcript, GeneID, RefSeq_Protein, RefSeq_Nucleotide, HGNC, PDB, Reactome, STRING, and BioGRID. HGNC expects an HGNC identifier, not a bare symbol. GO, Pfam, InterPro, PRIDE and PaxDb were absent from the reviewed mapping catalogue; retrieve their cross-references or annotation fields from UniProt records instead of inventing a mapping job.

record = u.retrieve("P43403", frmt="json")
links = [item for item in record["uniProtKBCrossReferences"]
         if item["database"] in {"GO", "Pfam", "InterPro"}]

The service permits up to 100,000 input IDs per job; output/enrichment/filter limits differ. Small chunks of 50–100 in the bundled converter are a workflow choice, not the provider's maximum. max_waiting_time bounds the SDK wait and may yield None. A failedIds-only completion can time out in 1.16.0 because its loop expects results; classify that as unresolved, not proven absent. For large jobs, use the provider's explicit job/status/details/results workflow so the job ID can be retained and resumed.

SDK mapping implementation and UniProt mapping help describe the job contract. Search a symbol with gene_exact:ZAP70 AND organism_id:9606 and review all candidate accessions before conversion. Searching reviewed records is useful when appropriate, but excludes unreviewed biology by design.

Raw lines 6 to 65
66## Bundled batch converter
68```bash
69python scripts/batch_id_converter.py ids.txt --from UniProtKB_AC-ID --to KEGG -o mapping.csv
70python scripts/batch_id_converter.py kegg_ids.txt --from KEGG --to UniProtKB --save-failed
71```
73`mapping_to_lists` normalizes current result rows, preserves distinct targets,
74and extracts `primaryAccession`, `uniParcId`, or `id` from supported record
75targets. Unknown record shapes fail explicitly. Its internal values are:
77| Value | CSV status | Meaning |
78| --- | --- | --- |
79| Nonempty target list | Success | One or more returned mappings |
80| `[]` | Unmapped | ID explicitly present in `failedIds` |
81| `None` | Failed | Request failed, timed out, or omitted the ID |
83`--save-failed` includes both Unmapped and Failed identifiers for later review.
84The CSV preserves unique input IDs, not duplicate input row multiplicity. Never
85report a mapping rate using only returned successful rows as the denominator.

Bundled batch converter

python scripts/batch_id_converter.py ids.txt --from UniProtKB_AC-ID --to KEGG -o mapping.csv
python scripts/batch_id_converter.py kegg_ids.txt --from KEGG --to UniProtKB --save-failed

mapping_to_lists normalizes current result rows, preserves distinct targets, and extracts primaryAccession, uniParcId, or id from supported record targets. Unknown record shapes fail explicitly. Its internal values are:

ValueCSV statusMeaning
Nonempty target listSuccessOne or more returned mappings
[]UnmappedID explicitly present in failedIds
NoneFailedRequest failed, timed out, or omitted the ID

--save-failed includes both Unmapped and Failed identifiers for later review. The CSV preserves unique input IDs, not duplicate input row multiplicity. Never report a mapping rate using only returned successful rows as the denominator.

Raw lines 66 to 86
Runs code python scripts/batch_id_converter.py :69
87## KEGG links
89The REST API returns TSV for `/conv/{target}/{source}` and `/link/{target}/{source}`.
90BioServices converts these to dictionaries, which can lose repeated source
91keys. For one-to-many membership preserve the raw rows:
93```python
94from bioservices import KEGG
95k = KEGG(verbose=False)
96k.services.url = "https://rest.kegg.jp"
97raw = k.services.http_get("link/pathway/hsa:7535", frmt="txt")
98if not isinstance(raw, str):
99 raise RuntimeError("KEGG links request failed")
100pairs = [tuple(line.split("\t")) for line in raw.splitlines() if line]
101```
103`get_pathway_by_gene("7535", "hsa")` parses the PATHWAY section to a dictionary;
104use `.items()`, not list slicing. To retrieve pathway genes, `k.parse(k.get(id))`
105provides the `GENE` section; a hand-written loop can accidentally skip the first
106GENE line. For a compound, preserve every DBLINKS ChEBI candidate. KEGG's PubChem
107cross-reference uses a **SID**, not necessarily a CID.
108[KEGG conversion/link semantics](https://www.kegg.jp/kegg/rest/keggapi.html).

KEGG links

The REST API returns TSV for /conv/{target}/{source} and /link/{target}/{source}. BioServices converts these to dictionaries, which can lose repeated source keys. For one-to-many membership preserve the raw rows:

from bioservices import KEGG
k = KEGG(verbose=False)
k.services.url = "https://rest.kegg.jp"
raw = k.services.http_get("link/pathway/hsa:7535", frmt="txt")
if not isinstance(raw, str):
    raise RuntimeError("KEGG links request failed")
pairs = [tuple(line.split("\t")) for line in raw.splitlines() if line]

get_pathway_by_gene("7535", "hsa") parses the PATHWAY section to a dictionary; use .items(), not list slicing. To retrieve pathway genes, k.parse(k.get(id)) provides the GENE section; a hand-written loop can accidentally skip the first GENE line. For a compound, preserve every DBLINKS ChEBI candidate. KEGG's PubChem cross-reference uses a SID, not necessarily a CID. KEGG conversion/link semantics.

Raw lines 87 to 109
110## UniChem compound mapping
112```python
113from bioservices import UniChem
114uc = UniChem(verbose=False)
115response = uc.get_compounds("BSYNRYMUTXBXSQ-UHFFFAOYSA-N", "inchikey")
116if not isinstance(response, dict) or "compounds" not in response:
117 raise RuntimeError("UniChem lookup failed")
118pairs = sorted({(source["shortName"], source["compoundId"])
119 for match in response["compounds"]
120 for source in match.get("sources", [])})
121print(pairs)
122```
124The aspirin InChIKey and `("CHEBI:15365", "chebi")` queries yielded CHEMBL25
125in review. `get_compounds` sends JSON to `/unichem/api/v1/compounds` with
126`compound`, `type`, `sourceID`; it is a search POST, not an external mutation.
127Discover supported names through `source_ids`; do not reuse historical numeric
128source IDs or assume KEGG is accepted. Some legacy UniChem methods remain in the
129SDK, but the examples here use the current API v1 route.
131Mapping must preserve chemical identity. KEGG C00022, for example, links multiple
132ChEBI forms; selecting the first can mix a neutral acid and an anion. The bundled
133compound script leaves multiple KEGG search hits, multiple ChEBI forms, or
134multiple ChEMBL mappings unresolved. Review salts, stereochemistry, protonation,
135and connectivity before joining potency or physicochemical data.
136[UniChem API](https://www.ebi.ac.uk/unichem/api/docs).

UniChem compound mapping

from bioservices import UniChem
uc = UniChem(verbose=False)
response = uc.get_compounds("BSYNRYMUTXBXSQ-UHFFFAOYSA-N", "inchikey")
if not isinstance(response, dict) or "compounds" not in response:
    raise RuntimeError("UniChem lookup failed")
pairs = sorted({(source["shortName"], source["compoundId"])
                for match in response["compounds"]
                for source in match.get("sources", [])})
print(pairs)

The aspirin InChIKey and ("CHEBI:15365", "chebi") queries yielded CHEMBL25 in review. get_compounds sends JSON to /unichem/api/v1/compounds with compound, type, sourceID; it is a search POST, not an external mutation. Discover supported names through source_ids; do not reuse historical numeric source IDs or assume KEGG is accepted. Some legacy UniChem methods remain in the SDK, but the examples here use the current API v1 route.

Mapping must preserve chemical identity. KEGG C00022, for example, links multiple ChEBI forms; selecting the first can mix a neutral acid and an anion. The bundled compound script leaves multiple KEGG search hits, multiple ChEBI forms, or multiple ChEMBL mappings unresolved. Review salts, stereochemistry, protonation, and connectivity before joining potency or physicochemical data. UniChem API.

Raw lines 110 to 136