From sciagent-skills
Queries GtoPdb REST API for receptor-ligand interactions, affinities (pKi/pIC50/pEC50), ligand classes (drugs, biologics), target families (GPCRs, ion channels, kinases), and selectivity profiles. For pharmacology research.
npx claudepluginhub jaechang-hits/sciagent-skills --plugin sciagent-skillsThis skill uses the workspace's default tool permissions.
The Guide to Pharmacology (GtoPdb), maintained by IUPHAR/BPS, is the curated reference database for pharmacological targets and their ligands. It covers 3,000+ targets (GPCRs, ion channels, nuclear receptors, catalytic receptors, transporters, and enzymes) with 12,000+ ligands and 90,000+ interaction records annotated with quantitative affinity values (Ki, IC50, EC50, Kd). Access is via a free ...
Researches GPCR receptors, ligands (agonists/antagonists/biased), mutations, crystal/cryo-EM structures, antibody CDRs, and protein interfaces using GPCRdb, SAbDab, PDBePISA. For pharmacology and drug discovery queries.
Queries ChEMBL database for bioactive molecules, targets, bioactivity data (IC50, Ki), and drugs. Searches compounds by name, structure, properties; finds inhibitors for medicinal chemistry and SAR studies.
Access and query DrugBank database via Python for drug properties, interactions, targets, pathways, structures, and pharmacology data. Useful for drug discovery, interaction analysis, and pharmaceutical research.
Share bugs, ideas, or general feedback.
The Guide to Pharmacology (GtoPdb), maintained by IUPHAR/BPS, is the curated reference database for pharmacological targets and their ligands. It covers 3,000+ targets (GPCRs, ion channels, nuclear receptors, catalytic receptors, transporters, and enzymes) with 12,000+ ligands and 90,000+ interaction records annotated with quantitative affinity values (Ki, IC50, EC50, Kd). Access is via a free REST API at https://www.guidetopharmacology.org/services/ — no authentication required.
chembl-database-bioactivity; GtoPdb is the authoritative source for receptor pharmacology annotationpdb-database; GtoPdb provides affinity numbers, not 3D structuresrequests, pandas, matplotlibtime.sleep(0.2) in batch loops for polite accesspip install requests pandas matplotlib
import requests
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def gtopdb_get(endpoint: str, params: dict = None) -> list | dict:
"""GET request to GtoPdb API; raise on HTTP errors."""
r = requests.get(f"{GTOPDB_API}/{endpoint}", params=params, timeout=20)
r.raise_for_status()
return r.json()
# Find the beta-2 adrenoceptor target
targets = gtopdb_get("targets", params={"name": "beta-2 adrenoceptor"})
if targets:
t = targets[0]
tid = t["targetId"]
print(f"Target: {t['name']} (GtoPdb ID: {tid})")
print(f"Family: {t.get('familyIds', [])}")
# Get its approved drug interactions
interactions = gtopdb_get(f"targets/{tid}/interactions")
approved = [i for i in interactions if i.get("ligandType") == "Approved"]
print(f"Approved drugs acting on beta-2 AR: {len(approved)}")
for ia in approved[:3]:
affinity = ia.get("affinityParameter", ""), ia.get("affinity", "")
print(f" {ia['ligandName']:25s} {affinity[0]}={affinity[1]}")
Search targets by name, HGNC symbol, UniProt accession, or target family type. Returns target metadata including GtoPdb target ID, gene symbol, family assignment, and species.
import requests, pandas as pd
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def search_targets(name: str = None, hgnc_symbol: str = None,
target_type: str = None) -> pd.DataFrame:
"""Search GtoPdb targets.
Args:
name: Partial target name (case-insensitive substring match)
hgnc_symbol: Exact HGNC gene symbol (e.g., 'ADRB2')
target_type: One of 'GPCR', 'Ion channel', 'Nuclear receptor',
'Catalytic receptor', 'Transporter', 'Enzyme', 'Other'
"""
params = {}
if name:
params["name"] = name
if hgnc_symbol:
params["geneSymbol"] = hgnc_symbol
if target_type:
params["type"] = target_type
r = requests.get(f"{GTOPDB_API}/targets", params=params, timeout=20)
r.raise_for_status()
targets = r.json()
if not targets:
return pd.DataFrame()
rows = []
for t in targets:
rows.append({
"target_id": t.get("targetId"),
"name": t.get("name"),
"type": t.get("type"),
"hgnc_symbol": t.get("hgncSymbol"),
"uniprot_id": t.get("uniprotId"),
"species": t.get("species", "Human"),
})
return pd.DataFrame(rows)
# Search for dopamine receptors
df = search_targets(name="dopamine receptor")
print(f"Found {len(df)} dopamine receptor targets:")
print(df[["target_id", "name", "type", "hgnc_symbol"]].to_string(index=False))
# Get full details for a specific target
def get_target_details(target_id: int) -> dict:
"""Retrieve full target record by GtoPdb target ID."""
r = requests.get(f"{GTOPDB_API}/targets/{target_id}", timeout=15)
r.raise_for_status()
return r.json()
# Mu-opioid receptor (OPRM1)
target = get_target_details(319)
print(f"Target: {target['name']}")
print(f"Type: {target.get('type')}")
print(f"HGNC symbol: {target.get('hgncSymbol')}")
print(f"UniProt: {target.get('uniprotId')}")
print(f"Family IDs: {target.get('familyIds', [])}")
print(f"Synonyms: {', '.join(target.get('synonyms', [])[:4])}")
Retrieve all ligand-target interactions for a given target, including quantitative affinity values, ligand type classification, and experimental context.
import requests, pandas as pd
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def get_target_interactions(target_id: int,
species: str = "Human") -> pd.DataFrame:
"""Get all interactions for a target with affinity data.
Returns a DataFrame with ligand name, type, affinity parameters, and action type.
"""
r = requests.get(f"{GTOPDB_API}/targets/{target_id}/interactions",
params={"species": species}, timeout=20)
r.raise_for_status()
interactions = r.json()
rows = []
for ia in interactions:
rows.append({
"ligand_id": ia.get("ligandId"),
"ligand_name": ia.get("ligandName"),
"ligand_type": ia.get("ligandType"),
"action": ia.get("action"), # agonist, antagonist, etc.
"action_comment": ia.get("actionComment"),
"affinity_param": ia.get("affinityParameter"), # pKi, pIC50, pEC50
"affinity": ia.get("affinity"), # numeric value
"affinity_high": ia.get("affinityHigh"),
"affinity_low": ia.get("affinityLow"),
"endogenous": ia.get("endogenous", False),
"primary_target": ia.get("primaryTarget", False),
"assay_type": ia.get("assayType"),
"pubmed_id": ia.get("refs", [{}])[0].get("pmid") if ia.get("refs") else None,
})
return pd.DataFrame(rows)
# Serotonin 2A receptor (5-HT2A, target_id=11)
df = get_target_interactions(11)
print(f"5-HT2A receptor interactions: {len(df)} total")
print(f"\nAction type breakdown:")
print(df["action"].value_counts().head(8))
print(f"\nLigand type breakdown:")
print(df["ligand_type"].value_counts().head(6))
# Show top antagonists by affinity
antagonists = df[df["action"] == "Antagonist"].dropna(subset=["affinity"])
antagonists = antagonists.sort_values("affinity", ascending=False)
print(f"\nTop 5-HT2A antagonists (by pKi/pIC50):")
print(antagonists[["ligand_name", "ligand_type", "affinity_param", "affinity"]].head(8).to_string(index=False))
Search for ligands by name, approved drug status, or ligand type. Retrieve full ligand records including structure IDs (InChIKey, SMILES), clinical status, and cross-references.
import requests, pandas as pd
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def search_ligands(name: str = None, approved_drug: bool = None,
ligand_type: str = None) -> pd.DataFrame:
"""Search GtoPdb ligands.
Args:
name: Ligand name substring (case-insensitive)
approved_drug: If True, filter to approved drugs only
ligand_type: One of 'Approved', 'Labelled', 'Peptide', 'Antibody',
'Endogenous', 'Inorganic', 'Metabolite', 'Natural product',
'Synthetic organic'
"""
params = {}
if name:
params["name"] = name
if approved_drug is not None:
params["approvedDrug"] = str(approved_drug).lower()
if ligand_type:
params["type"] = ligand_type
r = requests.get(f"{GTOPDB_API}/ligands", params=params, timeout=20)
r.raise_for_status()
ligands = r.json()
rows = []
for lig in ligands:
rows.append({
"ligand_id": lig.get("ligandId"),
"name": lig.get("name"),
"type": lig.get("type"),
"approved": lig.get("approvedDrug", False),
"inchikey": lig.get("inchikey"),
"smiles": lig.get("smiles", "")[:60] if lig.get("smiles") else "",
"pubchem_cid": lig.get("pubchemCid"),
"chembl_id": lig.get("chemblId"),
})
return pd.DataFrame(rows)
# Search for beta-blocker drugs
df = search_ligands(name="propranolol")
print(df[["ligand_id", "name", "type", "approved", "inchikey", "chembl_id"]].to_string(index=False))
# Get full details for a specific ligand
def get_ligand_details(ligand_id: int) -> dict:
"""Retrieve full ligand record by GtoPdb ligand ID."""
r = requests.get(f"{GTOPDB_API}/ligands/{ligand_id}", timeout=15)
r.raise_for_status()
return r.json()
# Morphine (ligand_id=1627)
lig = get_ligand_details(1627)
print(f"Name: {lig['name']}")
print(f"Type: {lig.get('type')}")
print(f"Approved drug: {lig.get('approvedDrug')}")
print(f"InChIKey: {lig.get('inchikey')}")
print(f"SMILES: {lig.get('smiles', 'N/A')[:80]}")
print(f"ChEMBL ID: {lig.get('chemblId')}")
print(f"PubChem CID: {lig.get('pubchemCid')}")
Given a ligand, retrieve all targets it acts on with affinity values. Use this to build a selectivity profile or identify off-target effects.
import requests, pandas as pd
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def get_ligand_interactions(ligand_id: int,
species: str = "Human") -> pd.DataFrame:
"""Get all target interactions for a ligand.
Returns a DataFrame with target name, type, action, and affinity.
"""
r = requests.get(f"{GTOPDB_API}/ligands/{ligand_id}/interactions",
params={"species": species}, timeout=20)
r.raise_for_status()
interactions = r.json()
rows = []
for ia in interactions:
rows.append({
"target_id": ia.get("targetId"),
"target_name": ia.get("targetName"),
"target_type": ia.get("targetType"),
"action": ia.get("action"),
"affinity_param": ia.get("affinityParameter"),
"affinity": ia.get("affinity"),
"endogenous": ia.get("endogenous", False),
"primary_target": ia.get("primaryTarget", False),
})
return pd.DataFrame(rows)
# Clozapine selectivity profile (ligand_id=31 in GtoPdb)
df = get_ligand_interactions(31)
print(f"Clozapine interactions: {len(df)} targets")
# Filter to records with affinity data
has_affinity = df.dropna(subset=["affinity"]).sort_values("affinity", ascending=False)
print(f"\nTargets with quantitative affinity (n={len(has_affinity)}):")
print(has_affinity[["target_name", "target_type", "action",
"affinity_param", "affinity"]].head(10).to_string(index=False))
Retrieve the receptor family hierarchy: superfamilies → families → individual targets. Use this to enumerate all GPCRs, ion channels, or nuclear receptors.
import requests, pandas as pd
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def get_families(family_id: int = None) -> list:
"""Get all families or a specific family by ID."""
endpoint = f"families/{family_id}" if family_id else "families"
r = requests.get(f"{GTOPDB_API}/{endpoint}", timeout=20)
r.raise_for_status()
data = r.json()
return data if isinstance(data, list) else [data]
def get_family_targets(family_id: int) -> pd.DataFrame:
"""Get all targets in a given receptor family."""
r = requests.get(f"{GTOPDB_API}/targets",
params={"familyId": family_id}, timeout=20)
r.raise_for_status()
targets = r.json()
rows = [{"target_id": t.get("targetId"), "name": t.get("name"),
"type": t.get("type"), "hgnc_symbol": t.get("hgncSymbol"),
"uniprot_id": t.get("uniprotId")} for t in targets]
return pd.DataFrame(rows)
# Browse top-level families
families = get_families()
print(f"Total GtoPdb families: {len(families)}")
for fam in families[:8]:
print(f" [{fam['familyId']}] {fam['name']}")
# Get all targets in a specific GPCR subfamily
# Family ID 694 = Adenosine receptors
adenosine_targets = get_family_targets(694)
print(f"\nAdenosine receptor targets: {len(adenosine_targets)}")
print(adenosine_targets[["target_id", "name", "hgnc_symbol"]].to_string(index=False))
Search all interactions by affinity type, action, or ligand type to extract a curated dataset for pharmacological analysis.
import requests, pandas as pd, time
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def search_interactions(action: str = None,
target_type: str = None,
affinity_param: str = None,
species: str = "Human") -> pd.DataFrame:
"""Search all GtoPdb interactions with optional filters.
Args:
action: 'Agonist', 'Antagonist', 'Inhibitor', 'Allosteric modulator', etc.
target_type: 'GPCR', 'Ion channel', 'Nuclear receptor', etc.
affinity_param: 'pKi', 'pIC50', 'pEC50', 'pKd'
species: 'Human' (default), 'Mouse', 'Rat'
"""
params = {"species": species}
if action:
params["action"] = action
if target_type:
params["targetType"] = target_type
if affinity_param:
params["affinityParameter"] = affinity_param
r = requests.get(f"{GTOPDB_API}/interactions", params=params, timeout=60)
r.raise_for_status()
interactions = r.json()
rows = []
for ia in interactions:
rows.append({
"target_id": ia.get("targetId"),
"target_name": ia.get("targetName"),
"target_type": ia.get("targetType"),
"ligand_id": ia.get("ligandId"),
"ligand_name": ia.get("ligandName"),
"ligand_type": ia.get("ligandType"),
"action": ia.get("action"),
"affinity_param": ia.get("affinityParameter"),
"affinity": ia.get("affinity"),
"endogenous": ia.get("endogenous", False),
"approved_drug": ia.get("approvedDrug", False),
})
return pd.DataFrame(rows)
# Get all GPCR antagonist interactions with pKi values
df = search_interactions(action="Antagonist", target_type="GPCR", affinity_param="pKi")
print(f"GPCR antagonists with pKi data: {len(df)} interactions")
df_clean = df.dropna(subset=["affinity"])
print(f"With numeric affinity: {len(df_clean)}")
print(f"\npKi distribution:")
print(df_clean["affinity"].describe().round(2))
print(f"\nTop 5 by pKi:")
print(df_clean.nlargest(5, "affinity")[["ligand_name", "target_name", "affinity"]].to_string(index=False))
GtoPdb organizes targets into a two-level hierarchy: target types (GPCR, Ion channel, Nuclear receptor, Catalytic receptor, Transporter, Enzyme, Other protein) → families (e.g., GPCR > Aminergic receptors > Adrenoceptors > beta-Adrenoceptors) → individual targets (e.g., beta-2 adrenoceptor). The familyId parameter lets you enumerate all members of a receptor family efficiently.
| Parameter | Definition | Typical range | Notes |
|---|---|---|---|
pKi | -log₁₀(Ki) equilibrium dissociation constant | 4–12 | Direct binding; higher = tighter |
pIC50 | -log₁₀(IC50) half-maximal inhibitory concentration | 4–12 | Functional inhibition |
pEC50 | -log₁₀(EC50) half-maximal effective concentration | 4–12 | Functional activation |
pKd | -log₁₀(Kd) dissociation constant | 4–12 | Equilibrium binding (often from SPR/ITC) |
% | Percent effect at fixed concentration | 0–100 | Qualitative; no affinity constant |
A pKi of 9 = Ki of 1 nM (high affinity); pKi of 6 = Ki of 1 µM (moderate). GtoPdb requires at least two independent measurements to include a value.
| Type | Description |
|---|---|
Approved | Regulatory-approved drug (FDA, EMA) |
Synthetic organic | Research tool compound |
Natural product | Plant/animal/microbial origin |
Endogenous | Endogenous ligand (neurotransmitter, hormone) |
Peptide | Peptide/peptidomimetic |
Antibody | Therapeutic antibody |
Inorganic | Metal ions, inorganic compounds |
Metabolite | Metabolic product |
Goal: Retrieve all interactions for a GPCR, separate by action type, and export a structured table with quantitative affinities for SAR analysis.
import requests, pandas as pd
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def get_pharmacology_table(target_id: int, species: str = "Human") -> pd.DataFrame:
"""Full pharmacology table for a target: agonists, antagonists, allosteric modulators."""
r = requests.get(f"{GTOPDB_API}/targets/{target_id}/interactions",
params={"species": species}, timeout=30)
r.raise_for_status()
rows = []
for ia in r.json():
rows.append({
"ligand_id": ia.get("ligandId"),
"ligand_name": ia.get("ligandName"),
"ligand_type": ia.get("ligandType"),
"action": ia.get("action"),
"action_comment": ia.get("actionComment"),
"affinity_param": ia.get("affinityParameter"),
"affinity": ia.get("affinity"),
"affinity_high": ia.get("affinityHigh"),
"affinity_low": ia.get("affinityLow"),
"endogenous": ia.get("endogenous", False),
"approved": ia.get("approvedDrug", False),
"pubmed_id": ia.get("refs", [{}])[0].get("pmid") if ia.get("refs") else None,
})
df = pd.DataFrame(rows)
if df.empty:
return df
df["affinity"] = pd.to_numeric(df["affinity"], errors="coerce")
return df
# Adenosine A2A receptor (target_id=3)
df = get_pharmacology_table(3)
print(f"Adenosine A2A receptor — {len(df)} total interactions")
# Pivot by action type
for action in ["Agonist", "Antagonist", "Allosteric modulator"]:
subset = df[df["action"] == action].dropna(subset=["affinity"])
subset = subset.sort_values("affinity", ascending=False)
print(f"\n{action}s with affinity data (n={len(subset)}):")
cols = ["ligand_name", "ligand_type", "affinity_param", "affinity", "approved"]
print(subset[cols].head(5).to_string(index=False))
df.to_csv("A2A_pharmacology.csv", index=False)
print(f"\nSaved A2A_pharmacology.csv ({len(df)} interactions)")
Goal: For a set of ligands, query their affinity across a receptor panel and visualize as a heatmap.
import requests, time
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def get_ligand_selectivity(ligand_id: int, species: str = "Human") -> dict:
"""Return {target_name: affinity} for a ligand (best affinity per target)."""
r = requests.get(f"{GTOPDB_API}/ligands/{ligand_id}/interactions",
params={"species": species}, timeout=20)
r.raise_for_status()
targets = {}
for ia in r.json():
name = ia.get("targetName", "")
aff = ia.get("affinity")
if name and aff is not None:
try:
val = float(aff)
if name not in targets or val > targets[name]:
targets[name] = val
except (ValueError, TypeError):
pass
return targets
# Typical antipsychotics: clozapine, haloperidol, olanzapine
# Use small sample GtoPdb ligand IDs for illustration
ligands = {
"clozapine": 31, # GtoPdb ligand ID
"haloperidol": 78,
"olanzapine": 4,
}
all_data = {}
for name, lid in ligands.items():
all_data[name] = get_ligand_selectivity(lid)
time.sleep(0.2)
# Build matrix: rows=ligands, columns=shared targets
all_targets = sorted(set().union(*all_data.values()))
matrix = pd.DataFrame(index=ligands.keys(), columns=all_targets, dtype=float)
for lig, targets in all_data.items():
for tgt, aff in targets.items():
matrix.loc[lig, tgt] = aff
# Keep only targets with data for at least 2 ligands
matrix = matrix.dropna(axis=1, thresh=2)
print(f"Selectivity matrix: {matrix.shape[0]} ligands × {matrix.shape[1]} targets")
# Plot heatmap
fig, ax = plt.subplots(figsize=(max(10, matrix.shape[1] * 0.5), 4))
im = ax.imshow(matrix.values.astype(float), aspect="auto", cmap="YlOrRd", vmin=5, vmax=10)
ax.set_xticks(range(matrix.shape[1]))
ax.set_xticklabels(matrix.columns, rotation=45, ha="right", fontsize=7)
ax.set_yticks(range(matrix.shape[0]))
ax.set_yticklabels(matrix.index)
plt.colorbar(im, ax=ax, label="pAffinity (pKi / pIC50 / pEC50)")
ax.set_title("GtoPdb Antipsychotic Selectivity Profile")
plt.tight_layout()
plt.savefig("antipsychotic_selectivity.png", dpi=150, bbox_inches="tight")
print("Saved antipsychotic_selectivity.png")
Goal: Enumerate all members of a receptor family, count approved drugs per target, and rank by drug coverage.
import requests, time, pandas as pd
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def approved_drug_coverage(family_id: int, species: str = "Human") -> pd.DataFrame:
"""Return approved drug counts and ligands for each target in a receptor family.
Args:
family_id: GtoPdb family ID (e.g., 694 for Adenosine receptors)
species: 'Human', 'Mouse', 'Rat'
"""
# Get all targets in the family
r = requests.get(f"{GTOPDB_API}/targets",
params={"familyId": family_id}, timeout=20)
r.raise_for_status()
targets = r.json()
rows = []
for t in targets:
tid = t["targetId"]
time.sleep(0.2)
r2 = requests.get(f"{GTOPDB_API}/targets/{tid}/interactions",
params={"species": species}, timeout=20)
if not r2.ok:
continue
interactions = r2.json()
approved = [ia for ia in interactions if ia.get("approvedDrug")]
drug_names = list({ia["ligandName"] for ia in approved})[:5]
rows.append({
"target_id": tid,
"target_name": t.get("name"),
"hgnc_symbol": t.get("hgncSymbol"),
"n_interactions": len(interactions),
"n_approved_drugs": len(approved),
"approved_drugs": ", ".join(drug_names),
})
df = pd.DataFrame(rows).sort_values("n_approved_drugs", ascending=False)
return df
# Opioid receptor family (family_id varies; search for it)
r = requests.get(f"{GTOPDB_API}/families", timeout=15)
families = r.json()
opioid = next((f for f in families if "opioid" in f.get("name", "").lower()), None)
if opioid:
print(f"Opioid family: {opioid['name']} (ID={opioid['familyId']})")
df = approved_drug_coverage(opioid["familyId"])
print(df[["target_name", "n_approved_drugs", "approved_drugs"]].to_string(index=False))
df.to_csv("opioid_approved_drugs.csv", index=False)
print(f"\nSaved opioid_approved_drugs.csv")
| Parameter | Function/Endpoint | Default | Range / Options | Effect |
|---|---|---|---|---|
name | GET /targets, GET /ligands | — | Partial string (case-insensitive) | Substring match on target or ligand name |
type | GET /targets | — | 'GPCR', 'Ion channel', 'Nuclear receptor', 'Catalytic receptor', 'Transporter', 'Enzyme', 'Other' | Filter targets by receptor class |
familyId | GET /targets | — | Integer family ID | Return all targets belonging to a receptor family |
geneSymbol | GET /targets | — | HGNC symbol string (e.g., 'ADRB2') | Exact match on HGNC gene symbol |
species | GET /targets/{id}/interactions, GET /ligands/{id}/interactions | 'Human' | 'Human', 'Mouse', 'Rat' | Filter interactions to a specific species |
approvedDrug | GET /ligands | — | 'true', 'false' | Filter ligands to FDA/EMA approved drugs |
action | GET /interactions | — | 'Agonist', 'Antagonist', 'Inhibitor', 'Allosteric modulator', 'Activator', 'Blocker', 'Opener' | Filter by pharmacological action type |
affinityParameter | GET /interactions | — | 'pKi', 'pIC50', 'pEC50', 'pKd' | Return only interactions with this affinity type |
targetType | GET /interactions | — | Same as type for targets | Filter interactions by target class |
Resolve target IDs before batch queries: GtoPdb uses integer target IDs. Always start with a GET /targets?name=... search to get the correct targetId rather than hard-coding IDs across analyses, as family assignments and IDs can change between database releases.
Filter interactions by species for quantitative analyses: The same target may have interactions from multiple species. For drug discovery (human pharmacology), always pass species=Human. Cross-species data is useful for selectivity validation but should be flagged separately.
Use dropna(subset=["affinity"]) before ranking: Many interaction records have qualitative action annotations (e.g., "Agonist" without a Ki value). Always filter to records with numeric affinity before computing potency rankings.
Check endogenous flag to separate endogenous ligands from drugs: Endogenous peptides, neurotransmitters, and lipids will appear in interaction tables. Use df[~df["endogenous"]] to focus on drug/tool compound interactions in SAR analyses.
Cross-reference with ChEMBL via chembl_id: Ligand records include chemblId. Use this to enrich GtoPdb affinity data with larger bioactivity datasets from ChEMBL using chembl-database-bioactivity.
lig = get_ligand_details(ligand_id)
chembl_id = lig.get("chemblId") # e.g., 'CHEMBL192'
# Then query ChEMBL for full bioactivity profile
When to use: Quick lookup of marketed drugs targeting a specific receptor given only the gene name.
import requests
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def approved_drugs_for_gene(hgnc_symbol: str, species: str = "Human") -> list[dict]:
"""Return approved drugs for a target identified by HGNC gene symbol."""
# Step 1: find the target
r = requests.get(f"{GTOPDB_API}/targets",
params={"geneSymbol": hgnc_symbol}, timeout=15)
r.raise_for_status()
targets = r.json()
human_targets = [t for t in targets if t.get("species", "Human") == "Human"]
if not human_targets:
print(f"No human target found for {hgnc_symbol}")
return []
target_id = human_targets[0]["targetId"]
target_name = human_targets[0]["name"]
# Step 2: get interactions
r2 = requests.get(f"{GTOPDB_API}/targets/{target_id}/interactions",
params={"species": species}, timeout=20)
r2.raise_for_status()
approved = [
{"ligand_name": ia["ligandName"], "action": ia.get("action"),
"affinity_param": ia.get("affinityParameter"), "affinity": ia.get("affinity")}
for ia in r2.json() if ia.get("approvedDrug")
]
print(f"{target_name} (ID={target_id}): {len(approved)} approved drugs")
return approved
drugs = approved_drugs_for_gene("DRD2") # Dopamine D2 receptor
for d in drugs[:6]:
aff = f"{d['affinity_param']}={d['affinity']}" if d['affinity'] else "no affinity"
print(f" {d['ligand_name']:20s} {d['action']:15s} {aff}")
When to use: Assess how drug potency compares to the endogenous agonist at a given receptor.
import requests, pandas as pd
GTOPDB_API = "https://www.guidetopharmacology.org/services"
def compare_endogenous_vs_drugs(target_id: int, species: str = "Human") -> pd.DataFrame:
"""Compare endogenous ligand affinities to approved drug affinities."""
r = requests.get(f"{GTOPDB_API}/targets/{target_id}/interactions",
params={"species": species}, timeout=20)
r.raise_for_status()
rows = []
for ia in r.json():
aff = ia.get("affinity")
if aff is None:
continue
try:
rows.append({
"ligand": ia["ligandName"],
"category": "Endogenous" if ia.get("endogenous") else
("Approved drug" if ia.get("approvedDrug") else "Research compound"),
"action": ia.get("action"),
"affinity_param": ia.get("affinityParameter"),
"affinity": float(aff),
})
except (ValueError, TypeError):
pass
df = pd.DataFrame(rows)
if df.empty:
return df
return df.sort_values(["category", "affinity"], ascending=[True, False])
# Beta-2 adrenoceptor (target_id=24)
df = compare_endogenous_vs_drugs(24)
print("Beta-2 adrenoceptor — Endogenous vs approved drug affinities:")
for cat, group in df.groupby("category"):
print(f"\n{cat} (n={len(group)}):")
print(group[["ligand", "action", "affinity_param", "affinity"]].head(5).to_string(index=False))
When to use: Build a comprehensive dataset of all approved GPCR drugs with quantitative affinity for pharmacological analysis.
import requests, pandas as pd
GTOPDB_API = "https://www.guidetopharmacology.org/services"
# Get all interactions filtered to GPCR targets and approved drugs
r = requests.get(f"{GTOPDB_API}/interactions",
params={"targetType": "GPCR", "species": "Human"}, timeout=60)
r.raise_for_status()
interactions = r.json()
rows = []
for ia in interactions:
if not ia.get("approvedDrug"):
continue
rows.append({
"target_id": ia.get("targetId"),
"target_name": ia.get("targetName"),
"ligand_id": ia.get("ligandId"),
"ligand_name": ia.get("ligandName"),
"action": ia.get("action"),
"affinity_param": ia.get("affinityParameter"),
"affinity": ia.get("affinity"),
"endogenous": ia.get("endogenous", False),
})
df = pd.DataFrame(rows)
df_clean = df.dropna(subset=["affinity"])
df_clean["affinity"] = pd.to_numeric(df_clean["affinity"], errors="coerce")
df_clean = df_clean.dropna(subset=["affinity"]).sort_values("affinity", ascending=False)
df_clean.to_csv("gpcr_approved_drugs.csv", index=False)
print(f"GPCR approved drug interactions: {len(df_clean)} with affinity data")
print(f"Unique targets: {df_clean['target_id'].nunique()}")
print(f"Unique drugs: {df_clean['ligand_name'].nunique()}")
print(df_clean.head(5)[["target_name", "ligand_name", "action", "affinity_param", "affinity"]].to_string(index=False))
| Problem | Cause | Solution |
|---|---|---|
Empty list from GET /targets?name=... | Exact name mismatch; GtoPdb uses official IUPHAR nomenclature | Try a shorter substring (e.g., "beta-2" instead of "beta-2 adrenoceptor"); use HGNC symbol with geneSymbol param |
GET /interactions times out | Large result set (all GPCRs is 90K+ records) | Add filters (action, targetType, affinityParameter) to reduce result set; increase timeout to 120s |
Interactions return None affinity for many records | Many interactions are qualitative (presence/absence, not Ki values) | Use df.dropna(subset=["affinity"]) to work only with quantitative records; expect ~40% have numeric values |
| Ligand search returns unexpected results | name parameter does substring match; common words match multiple ligands | Filter results by ligand_type or approved flag after retrieval; use ligandId if known |
| Target found but no interactions returned | Rare target with no curated interactions or wrong species | Check species param — some targets have only Rat/Mouse data; try without species filter |
requests.exceptions.ConnectionError | GtoPdb server temporarily unavailable | Retry after 30s; GtoPdb is academic infrastructure and has occasional downtime |
| Duplicate interactions for same ligand-target pair | Multiple assay entries per interaction (different labs, assay conditions) | Deduplicate by keeping the highest affinity value: df.sort_values("affinity").drop_duplicates(subset=["ligand_id","target_id"], keep="last") |
chembl-database-bioactivity — Larger bioactivity dataset for SAR studies; complement GtoPdb curated potency data with ChEMBL's broader coverageunichem-database — Translate GtoPdb chemblId or pubchemCid fields to cross-database identifierspdb-database — Retrieve 3D binding structures for receptor-ligand pairs identified in GtoPdbopentargets-database — Integrate GtoPdb pharmacology data with genetic evidence and disease associations via Open Targets