Hi everyone,
I am developing a Python pipeline to annotate bacterial proteins using the STRING database API.
My workflow currently starts from genomic annotations retrieved from NCBI GenBank files. For each feature, I extract:
- feature_id
- protein_id
- translation (amino acid sequence)
- organism name
My main goal is to retrieve the STRING preferredName programmatically.
Using the STRING API endpoint:
/api/json/get_string_ids
I can successfully retrieve preferredName when querying with some identifiers such as:
- protein_id
- RefSeq protein accessions
- locus tags
Example:
result = string_map_protein(
protein_id,
species="Gardnerella vaginalis"
)
However, many proteins are not mapped by the API, even though the STRING website itself is able to identify them when I manually paste the amino acid sequence into the STRING search interface.
For example:
- I provide the amino acid sequence and organism on the STRING website
- STRING performs a similarity search
- STRING returns a candidate protein with identity/e-value
- After selecting the candidate, I can obtain the corresponding
preferredName
What I would like to achieve is reproducing this behavior programmatically.
So far I have tried:
Direct STRING mapping using:
- protein_id
- RefSeq accessions
- UniProt accessions
Fallback workflow:
translation -> UniProt/SwissProt BLAST -> accession -> STRING get_string_ids
This partially works, but often fails because:
- the BLAST best hit belongs to another organism
- the accession is not mapped by STRING for the target species
- homology does not necessarily correspond to the same STRING protein
I also tested UniProt REST/BLAST APIs, but the sequence-based BLAST endpoints seem unstable or deprecated.
My question is:
Is there any official STRING API endpoint that supports sequence similarity searches (amino acid sequence + organism) similar to what the STRING website does interactively?
Or alternatively:
- is there a recommended workflow to retrieve STRING
preferredNamestarting only from an amino acid sequence? - how does the STRING website internally perform this sequence-to-protein mapping?
Any suggestions or best practices would be greatly appreciated.
Thanks!
1 answer
There is no sequence-similarity endpoint in the STRING REST API. The documented methods (get_string_ids, network, interaction_partners, homology, enrichment, ...) all take identifiers, never a raw sequence. The "paste a sequence" box on the website runs a DIAMOND (BLAST-like) search against STRING's own stored protein sequences for the chosen organism and maps to the best hit -- that step is not exposed through the API. To reproduce it you rebuild it locally, and the key is to search against the species' STRING proteome, not a generic UniProt BLAST -- that generic BLAST is exactly why your best hits keep landing in the wrong organism.
Everything you need is on the STRING per-species download page:
- <taxid>.protein.sequences.v12.0.fa.gz -- the STRING protein sequences
- <taxid>.protein.info.v12.0.txt.gz -- maps STRING protein id -> preferred_name
- <taxid>.protein.aliases.v12.0.txt.gz -- maps RefSeq / UniProt / locus_tag -> STRING protein id
Two workflows:
- Sequence -> preferredName (reproduces the website):
- diamond makedb on <taxid>.protein.sequences.fa (your target species only)
- diamond blastp your translation against it, keep the top hit
- the hit id is already a STRING protein id; look up preferred_name in <taxid>.protein.info No API call needed, and because the DB is a single organism the hit is guaranteed to be in-species.
- For the identifiers get_string_ids currently misses: skip the API and map them yourself with <taxid>.protein.aliases. That file is more complete than the online mapping for RefSeq accessions and locus tags, so many of your "not mapped" cases resolve with no BLAST at all.
One bacteria-specific gotcha: STRING keys everything on its own taxon id, sometimes at strain level. Confirm the Gardnerella vaginalis taxid you download the files for matches the STRING entry (search the organism on string-db.org and read the taxid off the URL), otherwise both the API and the local files will come up empty.
Log in to answer this question.