Chemistry: ligands, cofactors, PTMs & catalytic activity
UniProt annotates a lot of chemistry directly on a protein entry: the ligands and cofactors bound at specific sites (cross-referenced to ChEBI), post-translational modifications (PTMs) like phosphorylation, and the catalytic activity of enzymes (linked to Rhea reactions and EC numbers). For some questions, UniProt also federates out with a live SPARQL SERVICE call to other public endpoints - this page ends with a chemical substructure similarity search against IDSM/Sachem, finding proteins that bind something structurally similar to a given molecule (kept as a reference example rather than runnable, for reasons explained there).
Catalytic activity
Adapted from sparql-examples UniProt/39.
A up:Catalytic_Activity_Annotation links a protein to the Rhea reaction it catalyzes. Like most UniProt annotations, that link can itself be backed by evidence - here, using RDF reification to attach an ECO evidence code (ECO:0000269 = experimental evidence) to the specific up:catalyticActivity triple.
Example data (Turtle) — edit it, then re-run any query below
base <http://purl.uniprot.org/uniprot/>
prefix up: <http://purl.uniprot.org/core/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rh: <http://rdf.rhea-db.org/>
prefix obo: <http://purl.obolibrary.org/obo/>
<Q07973> up:reviewed true ;
up:annotation <Q07973#CA> ;
up:attribution <Q07973#Attr1> .
<Q07973#CA> a up:Catalytic_Activity_Annotation ;
up:catalyticActivity <Q07973#CAca> .
<Q07973#CAca> up:catalyzedReaction rh:10743 .
[] rdf:subject <Q07973#CA> ;
rdf:predicate up:catalyticActivity ;
rdf:object <Q07973#CAca> ;
up:attribution <Q07973#Attr1> .
<Q07973#Attr1> up:evidence obo:ECO_0000269 .PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX up: <http://purl.uniprot.org/core/>
SELECT ?protein ?rhea
WHERE {
# ECO 269 is experimental evidence
BIND (<http://purl.obolibrary.org/obo/ECO_0000269> as ?evidence)
?protein up:reviewed true ;
up:annotation ?a ;
up:attribution ?attribution .
?a a up:Catalytic_Activity_Annotation ;
up:catalyticActivity ?ca .
?ca up:catalyzedReaction ?rhea .
[] rdf:subject ?a ;
rdf:predicate up:catalyticActivity ;
rdf:object ?ca ;
up:attribution ?attribution .
?attribution up:evidence ?evidence .
}Cofactors & metal binding
Adapted from sparql-examples UniProt/55.
Binding sites are annotated with up:ligand, pointing at a ligand resource that is itself rdfs:subClassOf a ChEBI term - so you can search “binds a metal ion” by walking up the ChEBI hierarchy with a property path, rather than listing every possible metal individually. CHEBI:25213 is the general “metal cation” class.
Example data (Turtle) — edit it, then re-run any query below
base <http://purl.uniprot.org/uniprot/>
prefix up: <http://purl.uniprot.org/core/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix obo: <http://purl.obolibrary.org/obo/>
prefix CHEBI: <http://purl.obolibrary.org/obo/CHEBI_>
<P0A877> up:annotation <P0A877#BS1> .
<P0A877#BS1> up:ligand <P0A877#BS1_Zn> .
<P0A877#BS1_Zn> rdfs:subClassOf CHEBI:29105 .
CHEBI:29105 rdfs:subClassOf CHEBI:25213 ;
rdfs:label "zinc ion" .
[] rdf:subject <P0A877> ;
rdf:predicate up:annotation ;
rdf:object <P0A877#BS1> ;
up:attribution <P0A877#Attr1> .
<P0A877#Attr1> up:evidence obo:ECO_0000269 .PREFIX CHEBI: <http://purl.obolibrary.org/obo/CHEBI_>
PREFIX obo: <http://purl.obolibrary.org/obo/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX up: <http://purl.uniprot.org/core/>
SELECT
?ligand
?ligandName
(COUNT(DISTINCT ?protein) as ?entries)
WHERE {
?protein up:annotation ?annotation .
VALUES ?evs { obo:ECO_0000269 obo:ECO_0007744 } .
VALUES ?chebids { CHEBI:25213 CHEBI:25214 } .
?st rdf:subject ?protein ;
rdf:predicate up:annotation ;
rdf:object ?annotation ;
up:attribution/up:evidence ?evs .
?annotation up:ligand/rdfs:subClassOf ?ligand .
?ligand rdfs:subClassOf+ ?chebids ;
rdfs:label ?ligandName .
}
GROUP BY ?ligand ?ligandName
ORDER BY DESC(?entries)CHEBI:25213 (metal cation) and CHEBI:25214 (metal cluster) are the two top-level classes being matched against here; ECO:0000269 (experimental evidence) and ECO:0007744 (combinatorial computational and experimental evidence) are the two evidence codes accepted.
Post-translational modifications
Adapted from sparql-examples UniProt/220.
Modified residues are annotated with up:Modified_Residue_Annotation; which residue was modified and how is recorded as free text in rdfs:comment (e.g. "Phosphoserine", sometimes followed by the responsible kinase, e.g. "Phosphoserine; by PKA"). This example buckets reviewed human proteins by which of the three phosphorylatable residues (serine, threonine, tyrosine) they have annotated.
Example data (Turtle) — edit it, then re-run any query below
base <http://purl.uniprot.org/uniprot/>
prefix up: <http://purl.uniprot.org/core/>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix taxon: <http://purl.uniprot.org/taxonomy/>
<P1> a up:Protein ;
up:organism taxon:9606 ;
up:reviewed true ;
up:annotation <P1#Mod1> .
<P1#Mod1> a up:Modified_Residue_Annotation ;
rdfs:comment "Phosphoserine" .
<P2> a up:Protein ;
up:organism taxon:9606 ;
up:reviewed true ;
up:annotation <P2#Mod1> .
<P2#Mod1> a up:Modified_Residue_Annotation ;
rdfs:comment "Phosphoserine; by PKA" .
<P3> a up:Protein ;
up:organism taxon:9606 ;
up:reviewed true ;
up:annotation <P3#Mod1> .
<P3#Mod1> a up:Modified_Residue_Annotation ;
rdfs:comment "Phosphotyrosine" .PREFIX up: <http://purl.uniprot.org/core/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX taxon: <http://purl.uniprot.org/taxonomy/>
SELECT
?residue
(COUNT(DISTINCT ?protein) AS ?proteinCount)
WHERE {
?protein a up:Protein ;
up:organism taxon:9606 ;
up:reviewed true ;
up:annotation ?annotation .
?annotation a up:Modified_Residue_Annotation ;
rdfs:comment ?comment .
BIND(
IF(STRSTARTS(?comment, "Phosphoserine"), "Serine",
IF(STRSTARTS(?comment, "Phosphothreonine"), "Threonine",
IF(STRSTARTS(?comment, "Phosphotyrosine"), "Tyrosine", ?comment)))
AS ?residue)
FILTER(?residue IN ("Serine", "Threonine", "Tyrosine"))
}
GROUP BY ?residue
ORDER BY DESC(?proteinCount)Chemical similarity search: ligands like heme
Adapted from sparql-examples UniProt/54.
IDSM/Sachem is a specialized cheminformatics engine that indexes ChEBI by molecular structure. Given a query molecule as a SMILES string (here, heme), it returns every ChEBI compound structurally similar to it, ranked by similarity score - and because ChEBI compounds are exactly what UniProt’s up:ligand links point at, the result plugs directly into “which proteins bind something like this molecule?”.
Comunica limitation
This site’s Comunica engine is capable of real, live federation - standard public endpoints likesparql.uniprot.org and sparql.rhea-db.org reliably answer arbitrary SPARQL sent to them this way. IDSM/Sachem is different: it’s a non-standard SPARQL extension (the sachem:similaritySearch predicate isn’t a real triple, it’s a trigger for a procedural structure search), and testing it repeatedly showed Comunica’s query planner handles that inconsistently - sometimes it sends the real search, sometimes it gives up after a discovery request the service doesn’t answer the way a normal endpoint would, non-deterministically, request to request. The service itself is fine every time, the current flakiness is specifically in how the generic federation engine talks to this specific non-standard one.Rather than ship a Run query button that silently fails at random, this one stays a reference example - paste it into the UniProt SPARQL endpoint to run it for real, every time:
Reference only — not runnable on this page: Chemical substructure similarity search via IDSM/Sachem - run at https://sparql.uniprot.org/sparql
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sachem: <http://bioinfo.uochb.cas.cz/rdf/v1.0/sachem#>
PREFIX up: <http://purl.uniprot.org/core/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT
?protein
?mnemonic
?proteinName
?ligandSimilarityScore
?ligand
WHERE {
SERVICE <https://idsm.elixir-czech.cz/sparql/endpoint/chebi> {
?ssc sachem:compound ?ligand;
sachem:score ?ligandSimilarityScore ;
sachem:similaritySearch ?sss .
# Smiles of Heme
?sss sachem:query "CC1=C(CCC([O-])=O)C2=[N+]3C1=Cc1c(C)c(C=C)c4C=C5C(C)=C(C=C)C6=[N+]5[Fe-]3(n14)n1c(=C6)c(C)c(CCC([O-])=O)c1=C2";
sachem:cutoff "8e-1"^^xsd:double ;
sachem:aromaticityMode sachem:aromaticityDetect ;
sachem:similarityRadius 1 ;
sachem:tautomerMode sachem:ignoreTautomers .
}
?protein up:mnemonic ?mnemonic ;
up:recommendedName/up:fullName ?proteinName ;
up:annotation ?annotation .
?annotation a up:Binding_Site_Annotation ;
up:ligand/rdfs:subClassOf ?ligand .
}
ORDER BY DESC(?ligandSimilarityScore)The sachem:cutoff, sachem:similarityRadius and sachem:tautomerMode parameters control how strict the “similar to” match is. SERVICE idsm:chebi (a shorthand for this same endpoint) also appears in the Rhea metabolism tutorial on this site, searching Rhea reactions instead of UniProt binding sites - same reasoning applies there.
Active site chemistry
Adapted from sparql-examples UniProt/77.
An active site’s position is recorded with FALDO (a small ontology for describing sequence positions/ranges), pointing at a specific position on the protein’s sequence. Combined with the raw sequence string, you can check what residue is actually sitting there - here, filtering for active sites where that residue is tyrosine (Y).
Example data (Turtle) — edit it, then re-run any query below
base <http://purl.uniprot.org/uniprot/>
prefix up: <http://purl.uniprot.org/core/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix faldo: <http://biohackathon.org/resource/faldo#>
prefix isoform: <http://purl.uniprot.org/isoforms/>
<P1> up:annotation <P1#AS1> ;
up:sequence isoform:P1-1 .
<P1#AS1> a up:Active_Site_Annotation ;
up:range <P1#AS1_range> .
<P1#AS1_range> faldo:begin <P1#AS1_begin> .
<P1#AS1_begin> faldo:position 5 ;
faldo:reference isoform:P1-1 .
isoform:P1-1 rdf:value "MKTAYIVLRS" .PREFIX faldo: <http://biohackathon.org/resource/faldo#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX up: <http://purl.uniprot.org/core/>
SELECT
?protein
WHERE {
?protein up:annotation ?activeSiteAnnotation .
?activeSiteAnnotation a up:Active_Site_Annotation ;
up:range ?range .
?range faldo:begin ?begin .
?begin faldo:position ?beginPosition ;
faldo:reference ?sequence .
?sequence rdf:value ?sequenceVal .
FILTER(SUBSTR(?sequenceVal, ?beginPosition, 1) = 'Y')
}Allosteric ligands
Adapted from sparql-examples UniProt/56.
Not every ligand just sits in the active site - some regulate the enzyme from elsewhere on the protein. UniProt records this kind of detail as free text in rdfs:comment on the ligand resource itself, so it’s searchable with a simple REGEX.
Example data (Turtle) — edit it, then re-run any query below
base <http://purl.uniprot.org/uniprot/>
prefix up: <http://purl.uniprot.org/core/>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix CHEBI: <http://purl.obolibrary.org/obo/CHEBI_>
<P1> up:annotation <P1#BS1> .
<P1#BS1> a up:Binding_Site_Annotation ;
up:ligand <P1#BS1_ATP> .
<P1#BS1_ATP> rdfs:comment "Allosteric activator" ;
rdfs:subClassOf CHEBI:30616 ;
rdfs:label "ATP" .PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX up: <http://purl.uniprot.org/core/>
SELECT
?protein
?ligandName
?ligandNote
?chebi
WHERE {
?protein up:annotation ?annotation .
?annotation a up:Binding_Site_Annotation .
?annotation up:ligand ?ligand .
?ligand rdfs:comment ?ligandNote ;
rdfs:subClassOf ?chebi ;
rdfs:label ?ligandName .
FILTER(REGEX(?ligandNote, "allosteric", "i"))
}Enzyme classification (EC)
Adapted from sparql-examples UniProt/18.
Finally, zooming out: every enzyme can be classified with an EC (Enzyme Commission) number, which itself forms a small hierarchy down to ec:1.-.-.- … ec:7.-.-.- at the top level. An enzyme number can be attached to a whole protein, or (for multi-functional proteins) to just one up:domain or up:component - the property path (up:enzyme | up:domain/up:enzyme | up:component/up:enzyme) catches all three cases in one go.
Example data (Turtle) — edit it, then re-run any query below
base <http://purl.uniprot.org/uniprot/>
prefix up: <http://purl.uniprot.org/core/>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix ec: <http://purl.uniprot.org/enzyme/>
ec:1.1.1.1 rdfs:subClassOf ec:1.-.-.- .
ec:2.7.1.1 rdfs:subClassOf ec:2.-.-.- .
<P1> up:enzyme ec:1.1.1.1 .
<P2> up:enzyme ec:1.1.1.1 .
<P3> up:domain <P3#dom1> .
<P3#dom1> up:enzyme ec:2.7.1.1 .PREFIX ec: <http://purl.uniprot.org/enzyme/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX up: <http://purl.uniprot.org/core/>
SELECT ?ecClass (COUNT(?protein) as ?size)
WHERE
{
VALUES (?ecClass) {(ec:1.-.-.-) (ec:2.-.-.-) (ec:3.-.-.-) (ec:4.-.-.-) (ec:5.-.-.-) (ec:6.-.-.-) (ec:7.-.-.-)} .
?protein ( up:enzyme | up:domain/up:enzyme | up:component/up:enzyme ) ?enzyme .
# Enzyme subclasses are materialized on the live endpoint, no need for rdfs:subClassOf+ there
?enzyme rdfs:subClassOf ?ecClass .
}
GROUP BY ?ecClass ORDER BY ?ecClass