alterlab-primekg
Queries the Precision Medicine Knowledge Graph (PrimeKG) for multiscale biomedical relationships across genes, drugs, diseases, phenotypes, pathways, and biological processes. Use when exploring drug-disease or gene-disease links, building disease-centric knowledge subgraphs, or
Install
npx skills add https://github.com/AlterLab-IEU/AlterLab-Academic-Skills/tree/main/skills/cheminformatics/alterlab-primekg
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install alterlab-ieu-alterlab-academic-skills@llmmart
git clone https://github.com/AlterLab-IEU/AlterLab-Academic-Skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole alterlab-ieu/alterlab-academic-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
PrimeKG Knowledge Graph Skill
Overview
PrimeKG (Chandak, Huang & Zitnik, Scientific Data 2023; mims-harvard/PrimeKG) is a precision medicine knowledge graph integrating 20 primary resources. It contains 129,375 nodes and 4,050,249 edges across 30 edge types and 10 node types, including drug-target, disease-gene, and disease-phenotype associations. The published Dataverse files are a fixed 2022 snapshot.
Superseded upstream. The PrimeKG maintainers now state that PrimeKG has been superseded by OptimusKG (same lab; a superset with more current data — 190,531 nodes, 21.8M edges, 26 relation types) and recommend it for almost all new work. Use OptimusKG for new analyses (
uv pip install optimuskg, Python ≥ 3.12;import optimuskg; nodes, edges = optimuskg.load_graph(lcc=True)orG = optimuskg.load_networkx(lcc=True); data: Harvard Dataverse doi:10.7910/DVN/IYNGEV, docs: https://optimuskg.ai). Keep this PrimeKG workflow for reproducing or comparing against published PrimeKG results and benchmarks.
Key capabilities:
- Search for nodes (genes, proteins, drugs, diseases, phenotypes)
- Retrieve direct neighbors (associated entities and clinical evidence)
- Analyze local disease context (related genes, drugs, phenotypes)
- Identify drug-disease paths (potential repurposing opportunities)
Data access: Programmatic access via scripts/query_primekg.py. Point the loader at the kg.csv released on Harvard Dataverse via the PRIMEKG_DATA_PATH environment variable (it defaults to ../data/kg.csv relative to the script). All functions operate on the x_*/y_*/relation/display_relation columns of kg.csv.
When to Use This Skill
This skill should be used when:
- Knowledge-based drug discovery: Identifying targets and mechanisms for diseases.
- Drug repurposing: Finding existing drugs that might have evidence for new indications.
- Phenotype analysis: Understanding how symptoms/phenotypes relate to diseases and genes.
- Multiscale biology: Bridging the gap between molecular targets (genes) and clinical outcomes (diseases).
- Network pharmacology: Investigating the broader network effects of drug-target interactions.
Does NOT Trigger
| Scenario | Use Instead |
|---|---|
| Scored target–disease evidence, tractability, and known drugs for a target | alterlab-opentargets |
| Cross-species disease–gene–phenotype associations (HPO, OMIM, Orphanet) | alterlab-monarch |
| A drug's full record: pharmacology, interactions, targets, labels | alterlab-drugbank |
| Training knowledge-graph embedding models (TransE/RotatE) for link prediction | alterlab-torchdrug |
Core Workflow
Run under uv run python from the skill directory (so scripts/ is importable),
or add the scripts/ dir to sys.path. Set PRIMEKG_DATA_PATH to your kg.csv.
1. Search for Entities
Find identifiers for genes, drugs, or diseases. Pass node_type using PrimeKG's
exact type strings (see node types below) — e.g. "gene/protein", not "gene".
from scripts.query_primekg import search_nodes
# Search for Alzheimer's disease nodes
results = search_nodes("Alzheimer", node_type="disease")
# Returns: [{"id": <MONDO id>, "type": "disease", "name": "...",
# "source": "MONDO" | "MONDO_grouped"}, ...]
# Disease ids are MONDO ids; PrimeKG groups diseases, so one name can map to
# several MONDO ids. Use the returned id with get_neighbors.
2. Get Neighbors (Direct Associations)
Retrieve all connected nodes and relationship types.
from scripts.query_primekg import get_neighbors
# Get all neighbors of a specific disease ID (the MONDO id from search_nodes)
neighbors = get_neighbors(disease_id, relation_type="disease_protein")
# Returns: List of neighbors like
# {"neighbor_name": "APOE", "neighbor_type": "gene/protein",
# "relation": "disease_protein", "display_relation": "associated with", ...}
3. Analyze Disease Context
A high-level function to summarize associations for a disease.
from scripts.query_primekg import get_disease_context
# Comprehensive summary for a disease
context = get_disease_context("Alzheimer")
# Access: context['associated_genes'], context['associated_drugs'],
# context['phenotypes'], context['related_diseases']
4. Trace Drug-Disease Paths (Repurposing)
Find depth-2 paths (drug -> shared gene/protein target -> disease) as graph-based repurposing evidence.
from scripts.query_primekg import find_paths
# drug_id and disease_id come from search_nodes
paths = find_paths(drug_id, disease_id, max_depth=2)
# Each path is a list of edge dicts; a drug -> gene/protein -> disease path is a
# candidate new-indication hypothesis. For deeper traversal, load kg.csv into networkx.
Node and Relation Types in PrimeKG
These are the exact strings used in kg.csv — match them verbatim when filtering.
Node types (x_type/y_type, 10 total): gene/protein, drug, disease,
effect/phenotype, biological_process, molecular_function, cellular_component,
pathway, anatomy, exposure. Note: genes use gene/protein (not gene) and
phenotypes use effect/phenotype (not phenotype).
Key relations (relation, 30 total). Edges are undirected; check both endpoints.
protein_protein: physical PPIsdrug_protein: drug target/mechanism associationsdisease_protein: disease-gene/protein associations (there is nodisease_gene)indication,contraindication,off-label use: the three drug-disease relations (there is no singledrug_disease)disease_phenotype_positive/disease_phenotype_negative: phenotype present/absentbioprocess_protein,pathway_protein,molfunc_protein,cellcomp_protein: GO / pathway annotationsanatomy_protein_present/anatomy_protein_absent,exposure_*: anatomy/exposure links
Best Practices
- Use specific IDs: When using
get_neighbors, ensure you have the correct ID fromsearch_nodes(disease IDs are MONDO ids). - Context first: Use
get_disease_contextfor a broad overview before diving into specific genes or drugs. - Filter relationships: Use the
relation_typefilter inget_neighborsto focus on specific evidence (e.g., onlydrug_protein, orindicationfor treatment links). Use exact relation strings from the list above. - Mind disease grouping: PrimeKG collapses ~22k MONDO concepts into ~17k grouped disease nodes, so one disease name may resolve to multiple MONDO ids that share a
node_index.
Resources
Scripts
scripts/query_primekg.py: Core functions —search_nodes,get_neighbors,find_paths,get_disease_context.
Data Path
- Data:
kg.csv(setPRIMEKG_DATA_PATH; default../data/kg.csv), from Harvard Dataverse (doi:10.7910/DVN/IXA7BM). Download:wget -O kg.csv https://dataverse.harvard.edu/api/access/datafile/6180620. Alternatively PyTDC ships a loader (from tdc.resource import PrimeKG). - 129,375 nodes, 4,050,249 edges; 10 node types, 30 edge types.
- Loaded with pandas (
pd.read_csv,low_memory=True). kg.csv is ~0.98 GB (981,751,236 bytes) — each function reloads it; for repeated queries, cache the DataFrame or use a real graph store.
Part of the AlterLab Academic Skills suite.
Files (alterlab-academic-skills)
-
evals
-
evals.json 3.6 KB
{ "skill": "alterlab-primekg", "evals": [ { "id": "drug-disease-neighbors", "prompt": "Using PrimeKG, find the genes and drugs associated with type 2 diabetes and summarize the strongest relationships.", "expected_output": "Invokes alterlab-primekg: runs query_primekg.py to search for the disease node, retrieves its direct neighbors (associated genes, drugs, phenotypes) from kg.csv, and summarizes the relationships across the relevant relation types.", "assertions": [ { "type": "should_trigger", "value": true }, { "type": "output_contains", "value": "PrimeKG" }, { "type": "behavior", "value": "Queries the PrimeKG knowledge graph for a disease's neighboring genes and drugs and summarizes the relations." } ] }, { "id": "drug-repurposing-paths", "prompt": "I'm looking for drug repurposing candidates for Alzheimer's disease. Use the knowledge graph to find existing drugs with paths to the disease through shared targets.", "expected_output": "Invokes alterlab-primekg: identifies drug-disease paths in PrimeKG (e.g. drug to target gene to disease), surfacing existing drugs with graph-based evidence for a new indication, as repurposing candidates.", "assertions": [ { "type": "should_trigger", "value": true }, { "type": "output_contains", "value": "repurpos" }, { "type": "behavior", "value": "Uses PrimeKG drug-disease paths through shared targets to surface repurposing candidates." } ] }, { "id": "phenotype-disease-context", "prompt": "Build a disease-centric subgraph for Parkinson's disease in PrimeKG showing related phenotypes, genes, and biological processes.", "expected_output": "Invokes alterlab-primekg: constructs a local disease-context subgraph around the Parkinson's node, pulling related phenotypes, genes, pathways, and biological processes across PrimeKG's relation types.", "assertions": [ { "type": "should_trigger", "value": true }, { "type": "behavior", "value": "Builds a multiscale disease-centric subgraph (phenotypes, genes, processes) from PrimeKG." } ] }, { "id": "near-miss-rdkit", "prompt": "Parse this SMILES string, compute its molecular weight, LogP, and TPSA, and generate a Morgan fingerprint.", "expected_output": "Does NOT invoke alterlab-primekg; defers to a cheminformatics toolkit (alterlab-rdkit). The ask is single-molecule structure parsing and descriptor/fingerprint calculation, not querying a biomedical knowledge graph for entity relationships. PrimeKG answers relational drug/gene/disease questions, not molecular descriptors.", "assertions": [ { "type": "should_not_trigger", "value": true }, { "type": "output_contains", "value": "rdkit" }, { "type": "behavior", "value": "Recognizes molecular descriptor/fingerprint work as RDKit territory, not knowledge-graph querying, and defers." } ] }, { "id": "near-miss-opentargets", "prompt": "For the gene LRRK2, pull the Open Targets association scores across diseases, its tractability assessment, and the known drugs in clinical development.", "expected_output": "Does NOT invoke alterlab-primekg; defers to alterlab-opentargets. The user wants Open Targets Platform evidence scores, tractability, and known-drug data via its GraphQL API, not traversal of the static PrimeKG knowledge-graph CSV.", "assertions": [ { "type": "should_not_trigger", "value": true }, { "type": "output_contains", "value": "alterlab-opentargets" } ] } ] }
-
-
scripts
-
query_primekg.py 6.2 KB
import pandas as pd import os from typing import List, Dict, Optional, Union # Default data path DATA_PATH = os.environ.get( "PRIMEKG_DATA_PATH", os.path.join(os.path.dirname(__file__), "..", "data", "kg.csv") ) def _load_kg(): """Internal helper to load the KG efficiently.""" if not os.path.exists(DATA_PATH): raise FileNotFoundError( f"PrimeKG data not found at {DATA_PATH}. Please ensure the file is downloaded." ) # For very large files, we might want to use a database or specialized graph library. # For now, we'll use pandas for simplicity but with low_memory=True. return pd.read_csv(DATA_PATH, low_memory=True) def search_nodes(name_query: str, node_type: Optional[str] = None) -> List[Dict]: """ Search for nodes in PrimeKG by name and optionally type. Args: name_query: String to search for in node names. node_type: Optional type of node (e.g., 'gene/protein', 'drug', 'disease'). Returns: List of matching nodes with their metadata. """ kg = _load_kg() # Check both x and y columns for unique nodes x_nodes = kg[["x_id", "x_type", "x_name", "x_source"]].drop_duplicates() x_nodes.columns = ["id", "type", "name", "source"] y_nodes = kg[["y_id", "y_type", "y_name", "y_source"]].drop_duplicates() y_nodes.columns = ["id", "type", "name", "source"] nodes = pd.concat([x_nodes, y_nodes]).drop_duplicates() mask = nodes["name"].str.contains(name_query, case=False, na=False) if node_type: mask &= nodes["type"] == node_type results = nodes[mask].head(20).to_dict(orient="records") return results def get_neighbors( node_id: Union[str, int], relation_type: Optional[str] = None ) -> List[Dict]: """ Get all direct neighbors of a specific node. Args: node_id: The ID of the node (e.g., NCBI Gene ID or ChEMBL ID). relation_type: Optional filter for specific relationship types. Returns: List of neighbors and the relationship metadata. """ kg = _load_kg() node_id = str(node_id) mask_x = kg["x_id"].astype(str) == node_id mask_y = kg["y_id"].astype(str) == node_id if relation_type: mask_x &= kg["relation"] == relation_type mask_y &= kg["relation"] == relation_type neighbors_x = kg[mask_x][ ["relation", "display_relation", "y_id", "y_type", "y_name", "y_source"] ] neighbors_x.columns = [ "relation", "display_relation", "neighbor_id", "neighbor_type", "neighbor_name", "neighbor_source", ] neighbors_y = kg[mask_y][ ["relation", "display_relation", "x_id", "x_type", "x_name", "x_source"] ] neighbors_y.columns = [ "relation", "display_relation", "neighbor_id", "neighbor_type", "neighbor_name", "neighbor_source", ] results = pd.concat([neighbors_x, neighbors_y]).to_dict(orient="records") return results def find_paths( start_node_id: Union[str, int], end_node_id: Union[str, int], max_depth: int = 2, ) -> List[List[Dict]]: """ Find paths between two nodes (e.g., Drug -> shared target -> Disease) up to ``max_depth`` hops. Used for graph-based drug-repurposing hypotheses, where a depth-2 path drug -> gene/protein -> disease is candidate evidence for a new indication. Args: start_node_id: PrimeKG ``x_id``/``y_id`` of the start node (e.g. a drug). end_node_id: PrimeKG ``x_id``/``y_id`` of the end node (e.g. a disease). max_depth: 1 (direct edge only) or 2 (one intermediate node). Depth > 2 is not supported here — for deeper traversal use a real graph library (e.g. networkx) on the same kg.csv. Returns: List of paths; each path is a list of edge dicts (one per hop). """ kg = _load_kg() start_node_id = str(start_node_id) end_node_id = str(end_node_id) x_str = kg["x_id"].astype(str) y_str = kg["y_id"].astype(str) paths: List[List[Dict]] = [] # Depth 1: a direct edge between start and end (either orientation). direct = kg[ ((x_str == start_node_id) & (y_str == end_node_id)) | ((y_str == start_node_id) & (x_str == end_node_id)) ] for _, row in direct.iterrows(): paths.append([row.to_dict()]) if max_depth >= 2: # Edges incident to the start node; the "other" endpoint is the intermediate. start_edges = kg[(x_str == start_node_id) | (y_str == start_node_id)] for _, e1 in start_edges.iterrows(): mid_id = ( str(e1["y_id"]) if str(e1["x_id"]) == start_node_id else str(e1["x_id"]) ) if mid_id in (start_node_id, end_node_id): continue # skip self-loops and the depth-1 case (already covered) # Edges connecting the intermediate node to the end node. mid_to_end = kg[ ((x_str == mid_id) & (y_str == end_node_id)) | ((y_str == mid_id) & (x_str == end_node_id)) ] for _, e2 in mid_to_end.iterrows(): paths.append([e1.to_dict(), e2.to_dict()]) return paths def get_disease_context(disease_name: str) -> Dict: """ Analyze the local graph around a disease: associated genes, drugs, and phenotypes. """ results = search_nodes(disease_name, node_type="disease") if not results: return {"error": "Disease not found"} disease_id = results[0]["id"] neighbors = get_neighbors(disease_id) # PrimeKG node types: phenotypes are "effect/phenotype" (NOT "phenotype"). # Disease nodes are grouped, so one disease name can map to several MONDO x_id/ # y_id values sharing a node_index; this uses the first match's id. summary = { "disease_info": results[0], "associated_genes": [ n for n in neighbors if n["neighbor_type"] == "gene/protein" ], "associated_drugs": [n for n in neighbors if n["neighbor_type"] == "drug"], "phenotypes": [ n for n in neighbors if n["neighbor_type"] == "effect/phenotype" ], "related_diseases": [n for n in neighbors if n["neighbor_type"] == "disease"], } return summary
-
-
SKILL.md 8 KB
--- name: alterlab-primekg description: Queries the Precision Medicine Knowledge Graph (PrimeKG) for multiscale biomedical relationships across genes, drugs, diseases, phenotypes, pathways, and biological processes. Use when exploring drug-disease or gene-disease links, building disease-centric knowledge subgraphs, or sourcing relations for drug repurposing and precision-medicine analyses; also points to OptimusKG, the maintainers' successor graph, for new work. Part of the AlterLab Academic Skills suite. license: MIT allowed-tools: Read Write Edit Bash(python:*) Bash(uv:*) compatibility: "Runs under `uv run python` with pandas installed and the PrimeKG `kg.csv` available locally (set `PRIMEKG_DATA_PATH`); no API key or account required." metadata: skill-author: AlterLab version: "1.1.0" last_updated: "2026-09-23" --- # PrimeKG Knowledge Graph Skill ## Overview PrimeKG (Chandak, Huang & Zitnik, *Scientific Data* 2023; mims-harvard/PrimeKG) is a precision medicine knowledge graph integrating 20 primary resources. It contains 129,375 nodes and 4,050,249 edges across 30 edge types and 10 node types, including drug-target, disease-gene, and disease-phenotype associations. The published Dataverse files are a fixed 2022 snapshot. > **Superseded upstream.** The PrimeKG maintainers now state that PrimeKG has been superseded by **OptimusKG** (same lab; a superset with more current data — 190,531 nodes, 21.8M edges, 26 relation types) and recommend it for almost all new work. Use OptimusKG for new analyses (`uv pip install optimuskg`, Python ≥ 3.12; `import optimuskg; nodes, edges = optimuskg.load_graph(lcc=True)` or `G = optimuskg.load_networkx(lcc=True)`; data: Harvard Dataverse doi:10.7910/DVN/IYNGEV, docs: https://optimuskg.ai). Keep this PrimeKG workflow for reproducing or comparing against published PrimeKG results and benchmarks. **Key capabilities:** - Search for nodes (genes, proteins, drugs, diseases, phenotypes) - Retrieve direct neighbors (associated entities and clinical evidence) - Analyze local disease context (related genes, drugs, phenotypes) - Identify drug-disease paths (potential repurposing opportunities) **Data access:** Programmatic access via `scripts/query_primekg.py`. Point the loader at the `kg.csv` released on Harvard Dataverse via the `PRIMEKG_DATA_PATH` environment variable (it defaults to `../data/kg.csv` relative to the script). All functions operate on the `x_*`/`y_*`/`relation`/`display_relation` columns of `kg.csv`. ## When to Use This Skill This skill should be used when: - **Knowledge-based drug discovery:** Identifying targets and mechanisms for diseases. - **Drug repurposing:** Finding existing drugs that might have evidence for new indications. - **Phenotype analysis:** Understanding how symptoms/phenotypes relate to diseases and genes. - **Multiscale biology:** Bridging the gap between molecular targets (genes) and clinical outcomes (diseases). - **Network pharmacology:** Investigating the broader network effects of drug-target interactions. ### Does NOT Trigger | Scenario | Use Instead | |----------|-------------| | Scored target–disease evidence, tractability, and known drugs for a target | `alterlab-opentargets` | | Cross-species disease–gene–phenotype associations (HPO, OMIM, Orphanet) | `alterlab-monarch` | | A drug's full record: pharmacology, interactions, targets, labels | `alterlab-drugbank` | | Training knowledge-graph embedding models (TransE/RotatE) for link prediction | `alterlab-torchdrug` | ## Core Workflow Run under `uv run python` from the skill directory (so `scripts/` is importable), or add the `scripts/` dir to `sys.path`. Set `PRIMEKG_DATA_PATH` to your `kg.csv`. ### 1. Search for Entities Find identifiers for genes, drugs, or diseases. Pass `node_type` using PrimeKG's exact type strings (see node types below) — e.g. `"gene/protein"`, not `"gene"`. ```python from scripts.query_primekg import search_nodes # Search for Alzheimer's disease nodes results = search_nodes("Alzheimer", node_type="disease") # Returns: [{"id": <MONDO id>, "type": "disease", "name": "...", # "source": "MONDO" | "MONDO_grouped"}, ...] # Disease ids are MONDO ids; PrimeKG groups diseases, so one name can map to # several MONDO ids. Use the returned id with get_neighbors. ``` ### 2. Get Neighbors (Direct Associations) Retrieve all connected nodes and relationship types. ```python from scripts.query_primekg import get_neighbors # Get all neighbors of a specific disease ID (the MONDO id from search_nodes) neighbors = get_neighbors(disease_id, relation_type="disease_protein") # Returns: List of neighbors like # {"neighbor_name": "APOE", "neighbor_type": "gene/protein", # "relation": "disease_protein", "display_relation": "associated with", ...} ``` ### 3. Analyze Disease Context A high-level function to summarize associations for a disease. ```python from scripts.query_primekg import get_disease_context # Comprehensive summary for a disease context = get_disease_context("Alzheimer") # Access: context['associated_genes'], context['associated_drugs'], # context['phenotypes'], context['related_diseases'] ``` ### 4. Trace Drug-Disease Paths (Repurposing) Find depth-2 paths (drug -> shared gene/protein target -> disease) as graph-based repurposing evidence. ```python from scripts.query_primekg import find_paths # drug_id and disease_id come from search_nodes paths = find_paths(drug_id, disease_id, max_depth=2) # Each path is a list of edge dicts; a drug -> gene/protein -> disease path is a # candidate new-indication hypothesis. For deeper traversal, load kg.csv into networkx. ``` ## Node and Relation Types in PrimeKG These are the exact strings used in `kg.csv` — match them verbatim when filtering. **Node types** (`x_type`/`y_type`, 10 total): `gene/protein`, `drug`, `disease`, `effect/phenotype`, `biological_process`, `molecular_function`, `cellular_component`, `pathway`, `anatomy`, `exposure`. Note: genes use `gene/protein` (not `gene`) and phenotypes use `effect/phenotype` (not `phenotype`). **Key relations** (`relation`, 30 total). Edges are undirected; check both endpoints. - `protein_protein`: physical PPIs - `drug_protein`: drug target/mechanism associations - `disease_protein`: disease-gene/protein associations (there is no `disease_gene`) - `indication`, `contraindication`, `off-label use`: the three drug-disease relations (there is no single `drug_disease`) - `disease_phenotype_positive` / `disease_phenotype_negative`: phenotype present/absent - `bioprocess_protein`, `pathway_protein`, `molfunc_protein`, `cellcomp_protein`: GO / pathway annotations - `anatomy_protein_present` / `anatomy_protein_absent`, `exposure_*`: anatomy/exposure links ## Best Practices 1. **Use specific IDs:** When using `get_neighbors`, ensure you have the correct ID from `search_nodes` (disease IDs are MONDO ids). 2. **Context first:** Use `get_disease_context` for a broad overview before diving into specific genes or drugs. 3. **Filter relationships:** Use the `relation_type` filter in `get_neighbors` to focus on specific evidence (e.g., only `drug_protein`, or `indication` for treatment links). Use exact relation strings from the list above. 4. **Mind disease grouping:** PrimeKG collapses ~22k MONDO concepts into ~17k grouped disease nodes, so one disease name may resolve to multiple MONDO ids that share a `node_index`. ## Resources ### Scripts - `scripts/query_primekg.py`: Core functions — `search_nodes`, `get_neighbors`, `find_paths`, `get_disease_context`. ### Data Path - Data: `kg.csv` (set `PRIMEKG_DATA_PATH`; default `../data/kg.csv`), from Harvard Dataverse (doi:10.7910/DVN/IXA7BM). Download: `wget -O kg.csv https://dataverse.harvard.edu/api/access/datafile/6180620`. Alternatively PyTDC ships a loader (`from tdc.resource import PrimeKG`). - 129,375 nodes, 4,050,249 edges; 10 node types, 30 edge types. - Loaded with pandas (`pd.read_csv`, `low_memory=True`). kg.csv is ~0.98 GB (981,751,236 bytes) — each function reloads it; for repeated queries, cache the DataFrame or use a real graph store. Part of the AlterLab Academic Skills suite.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.