[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DP3D4132ME2YCF4V9CK8GS":3,"skill-same:01M6DP3D4132ME2YCF4V9CK8GS":68},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":49,"commitSha":50,"skillDirectory":5,"forksCount":14,"repositoryHtmlUrl":51,"repositoryHomepageUrl":6,"ownerHtmlUrl":52,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":53,"install":54,"resources":67},"01M6DP3D4132ME2YCF4V9CK8GS","jaspar-database",null,"Query JASPAR for transcription factor binding site (TFBS) profiles (PWMs\u002FPFMs). Search by TF name, species, or class; scan DNA sequences for TF binding sites; compare matrices; essential for regulatory genomics, motif analysis, and GWAS regulatory variant interpretation.","huamu668\u002Fclawhub-openclaw-medical","huamu668","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F202473531?v=4","01M6DK1V7D7VP9PJ06Z1VXVK13","huamu","01M6DK1VBYG1BX5FT154AFZHAS",0,"CC0-1.0","https:\u002F\u002Fgithub.com\u002Fhuamu668\u002Fclawhub-openclaw-medical\u002Fblob\u002Fmain\u002Fjaspar-database\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"database","jaspar database","binding","interpretation","name","sites","factor","matrices","essential","DNA","genomics","query","scan","transcription","regulatory","site","analysis","search","2026-11-10 10:12:30",false,"---\nname: jaspar-database\ndescription: Query JASPAR for transcription factor binding site (TFBS) profiles (PWMs\u002FPFMs). Search by TF name, species, or class; scan DNA sequences for TF binding sites; compare matrices; essential for regulatory genomics, motif analysis, and GWAS regulatory variant interpretation.\nlicense: CC0-1.0\nmetadata:\n    skill-author: Kuan-lin Huang\n---\n\n# JASPAR Database\n\n## Overview\n\nJASPAR (https:\u002F\u002Fjaspar.elixir.no\u002F) is the gold-standard open-access database of curated, non-redundant transcription factor (TF) binding profiles stored as position frequency matrices (PFMs). JASPAR 2024 contains 1,210 non-redundant TF binding profiles for 164 eukaryotic species. Each profile is experimentally derived (ChIP-seq, SELEX, HT-SELEX, protein binding microarray, etc.) and rigorously validated.\n\n**Key resources:**\n- JASPAR portal: https:\u002F\u002Fjaspar.elixir.no\u002F\n- REST API: https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002F\n- API docs: https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002Fdocs\u002F\n- Python package: `jaspar` (via Biopython) or direct API\n\n## When to Use This Skill\n\nUse JASPAR when:\n\n- **TF binding site prediction**: Scan a DNA sequence for potential binding sites of a TF\n- **Regulatory variant interpretation**: Does a GWAS\u002FeQTL variant disrupt a TF binding motif?\n- **Promoter\u002Fenhancer analysis**: What TFs are predicted to bind to a regulatory element?\n- **Gene regulatory network construction**: Link TFs to their target genes via motif scanning\n- **TF family analysis**: Compare binding profiles across a TF family (e.g., all homeobox factors)\n- **ChIP-seq analysis**: Find known TF motifs enriched in ChIP-seq peaks\n- **ENCODE\u002FATAC-seq interpretation**: Match open chromatin regions to TF binding profiles\n\n## Core Capabilities\n\n### 1. JASPAR REST API\n\nBase URL: `https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002F`\n\n```python\nimport requests\n\nBASE_URL = \"https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\"\n\ndef jaspar_get(endpoint, params=None):\n    url = f\"{BASE_URL}\u002F{endpoint}\"\n    response = requests.get(url, params=params, headers={\"Accept\": \"application\u002Fjson\"})\n    response.raise_for_status()\n    return response.json()\n```\n\n### 2. Search for TF Profiles\n\n```python\ndef search_jaspar(\n    tf_name=None,\n    species=None,\n    collection=\"CORE\",\n    tf_class=None,\n    tf_family=None,\n    page=1,\n    page_size=25\n):\n    \"\"\"Search JASPAR for TF binding profiles.\"\"\"\n    params = {\n        \"collection\": collection,\n        \"page\": page,\n        \"page_size\": page_size,\n        \"format\": \"json\"\n    }\n    if tf_name:\n        params[\"name\"] = tf_name\n    if species:\n        params[\"species\"] = species  # Use taxonomy ID or name, e.g., \"9606\" for human\n    if tf_class:\n        params[\"tf_class\"] = tf_class\n    if tf_family:\n        params[\"tf_family\"] = tf_family\n\n    return jaspar_get(\"matrix\", params)\n\n# Examples:\n# Search for human CTCF profile\nctcf = search_jaspar(\"CTCF\", species=\"9606\")\nprint(f\"Found {ctcf['count']} CTCF profiles\")\n\n# Search for all homeobox TFs in human\nhox_tfs = search_jaspar(tf_class=\"Homeodomain\", species=\"9606\")\n\n# Search for a TF family\nnfkb = search_jaspar(tf_family=\"NF-kappaB\")\n```\n\n### 3. Fetch a Specific Matrix (PFM\u002FPWM)\n\n```python\ndef get_matrix(matrix_id):\n    \"\"\"Fetch a specific JASPAR matrix by ID (e.g., 'MA0139.1' for CTCF).\"\"\"\n    return jaspar_get(f\"matrix\u002F{matrix_id}\u002F\")\n\n# Example: Get CTCF matrix\nctcf_matrix = get_matrix(\"MA0139.1\")\n\n# Matrix structure:\n# {\n#   \"matrix_id\": \"MA0139.1\",\n#   \"name\": \"CTCF\",\n#   \"collection\": \"CORE\",\n#   \"tax_group\": \"vertebrates\",\n#   \"pfm\": { \"A\": [...], \"C\": [...], \"G\": [...], \"T\": [...] },\n#   \"consensus\": \"CCGCGNGGNGGCAG\",\n#   \"length\": 19,\n#   \"species\": [{\"tax_id\": 9606, \"name\": \"Homo sapiens\"}],\n#   \"class\": [\"C2H2 zinc finger factors\"],\n#   \"family\": [\"BEN domain factors\"],\n#   \"type\": \"ChIP-seq\",\n#   \"uniprot_ids\": [\"P49711\"]\n# }\n```\n\n### 4. Download PFM\u002FPWM as Matrix\n\n```python\nimport numpy as np\n\ndef get_pwm(matrix_id, pseudocount=0.8):\n    \"\"\"\n    Fetch a PFM from JASPAR and convert to PWM (log-odds).\n    Returns numpy array of shape (4, L) in order A, C, G, T.\n    \"\"\"\n    matrix = get_matrix(matrix_id)\n    pfm = matrix[\"pfm\"]\n\n    # Convert PFM to numpy\n    pfm_array = np.array([pfm[\"A\"], pfm[\"C\"], pfm[\"G\"], pfm[\"T\"]], dtype=float)\n\n    # Add pseudocount\n    pfm_array += pseudocount\n\n    # Normalize to get PPM\n    ppm = pfm_array \u002F pfm_array.sum(axis=0, keepdims=True)\n\n    # Convert to PWM (log-odds relative to background 0.25)\n    background = 0.25\n    pwm = np.log2(ppm \u002F background)\n\n    return pwm, matrix[\"name\"]\n\n# Example\npwm, name = get_pwm(\"MA0139.1\")  # CTCF\nprint(f\"PWM for {name}: shape {pwm.shape}\")\nmax_score = pwm.max(axis=0).sum()\nprint(f\"Maximum possible score: {max_score:.2f} bits\")\n```\n\n### 5. Scan a DNA Sequence for TF Binding Sites\n\n```python\nimport numpy as np\nfrom typing import List, Tuple\n\nNUCLEOTIDE_MAP = {'A': 0, 'C': 1, 'G': 2, 'T': 3,\n                  'a': 0, 'c': 1, 'g': 2, 't': 3}\n\ndef scan_sequence(sequence: str, pwm: np.ndarray, threshold_pct: float = 0.8) -> List[dict]:\n    \"\"\"\n    Scan a DNA sequence for TF binding sites using a PWM.\n\n    Args:\n        sequence: DNA sequence string\n        pwm: PWM array (4 x L) in ACGT order\n        threshold_pct: Fraction of max score to use as threshold (0-1)\n\n    Returns:\n        List of hits with position, score, and matched sequence\n    \"\"\"\n    motif_len = pwm.shape[1]\n    max_score = pwm.max(axis=0).sum()\n    min_score = pwm.min(axis=0).sum()\n    threshold = min_score + threshold_pct * (max_score - min_score)\n\n    hits = []\n    seq = sequence.upper()\n\n    for i in range(len(seq) - motif_len + 1):\n        subseq = seq[i:i + motif_len]\n        # Skip if contains non-ACGT\n        if any(c not in NUCLEOTIDE_MAP for c in subseq):\n            continue\n\n        score = sum(pwm[NUCLEOTIDE_MAP[c], j] for j, c in enumerate(subseq))\n\n        if score >= threshold:\n            relative_score = (score - min_score) \u002F (max_score - min_score)\n            hits.append({\n                \"position\": i + 1,  # 1-based\n                \"score\": score,\n                \"relative_score\": relative_score,\n                \"sequence\": subseq,\n                \"strand\": \"+\"\n            })\n\n    return hits\n\n# Example: Scan a promoter sequence for CTCF binding sites\npromoter = \"AGCCCGCGAGGNGGCAGTTGCCTGGAGCAGGATCAGCAGATC\"\npwm, name = get_pwm(\"MA0139.1\")\nhits = scan_sequence(promoter, pwm, threshold_pct=0.75)\nfor hit in hits:\n    print(f\"  Position {hit['position']}: {hit['sequence']} (score: {hit['score']:.2f}, {hit['relative_score']:.0%})\")\n```\n\n### 6. Scan Both Strands\n\n```python\ndef reverse_complement(seq: str) -> str:\n    complement = {'A': 'T', 'T': 'A', 'C': 'G', 'G': 'C', 'N': 'N'}\n    return ''.join(complement.get(b, 'N') for b in reversed(seq.upper()))\n\ndef scan_both_strands(sequence: str, pwm: np.ndarray, threshold_pct: float = 0.8):\n    \"\"\"Scan forward and reverse complement strands.\"\"\"\n    fwd_hits = scan_sequence(sequence, pwm, threshold_pct)\n    for h in fwd_hits:\n        h[\"strand\"] = \"+\"\n\n    rev_seq = reverse_complement(sequence)\n    rev_hits = scan_sequence(rev_seq, pwm, threshold_pct)\n    seq_len = len(sequence)\n    for h in rev_hits:\n        h[\"strand\"] = \"-\"\n        h[\"position\"] = seq_len - h[\"position\"] - len(h[\"sequence\"]) + 2  # Convert to fwd coords\n\n    all_hits = fwd_hits + rev_hits\n    return sorted(all_hits, key=lambda x: x[\"position\"])\n```\n\n### 7. Variant Impact on TF Binding\n\n```python\ndef variant_tfbs_impact(ref_seq: str, alt_seq: str, pwm: np.ndarray,\n                          tf_name: str, threshold_pct: float = 0.7):\n    \"\"\"\n    Assess impact of a SNP on TF binding by comparing ref vs alt sequences.\n    Both sequences should be centered on the variant with flanking context.\n    \"\"\"\n    ref_hits = scan_both_strands(ref_seq, pwm, threshold_pct)\n    alt_hits = scan_both_strands(alt_seq, pwm, threshold_pct)\n\n    max_ref = max((h[\"score\"] for h in ref_hits), default=None)\n    max_alt = max((h[\"score\"] for h in alt_hits), default=None)\n\n    result = {\n        \"tf\": tf_name,\n        \"ref_max_score\": max_ref,\n        \"alt_max_score\": max_alt,\n        \"ref_has_site\": len(ref_hits) > 0,\n        \"alt_has_site\": len(alt_hits) > 0,\n    }\n    if max_ref and max_alt:\n        result[\"score_change\"] = max_alt - max_ref\n        result[\"effect\"] = \"gained\" if max_alt > max_ref else \"disrupted\"\n    elif max_ref and not max_alt:\n        result[\"effect\"] = \"disrupted\"\n    elif not max_ref and max_alt:\n        result[\"effect\"] = \"gained\"\n    else:\n        result[\"effect\"] = \"no_site\"\n\n    return result\n```\n\n## Query Workflows\n\n### Workflow 1: Find All TF Binding Sites in a Promoter\n\n```python\nimport requests, numpy as np\n\n# 1. Get relevant TF matrices (e.g., all human TFs in CORE collection)\nresponse = requests.get(\n    \"https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002Fmatrix\u002F\",\n    params={\"species\": \"9606\", \"collection\": \"CORE\", \"page_size\": 500, \"page\": 1}\n)\nmatrices = response.json()[\"results\"]\n\n# 2. For each matrix, compute PWM and scan promoter\npromoter = \"CCCGCCCGCCCGCCGCCCGCAGTTAATGAGCCCAGCGTGCC\"  # Example\n\nall_hits = []\nfor m in matrices[:10]:  # Limit for demo\n    pwm_data = requests.get(f\"https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002Fmatrix\u002F{m['matrix_id']}\u002F\").json()\n    pfm = pfm_data[\"pfm\"]\n    pfm_arr = np.array([pfm[\"A\"], pfm[\"C\"], pfm[\"G\"], pfm[\"T\"]], dtype=float) + 0.8\n    ppm = pfm_arr \u002F pfm_arr.sum(axis=0)\n    pwm = np.log2(ppm \u002F 0.25)\n\n    hits = scan_sequence(promoter, pwm, threshold_pct=0.8)\n    for h in hits:\n        h[\"tf_name\"] = m[\"name\"]\n        h[\"matrix_id\"] = m[\"matrix_id\"]\n    all_hits.extend(hits)\n\nprint(f\"Found {len(all_hits)} TF binding sites\")\nfor h in sorted(all_hits, key=lambda x: -x[\"score\"])[:5]:\n    print(f\"  {h['tf_name']} ({h['matrix_id']}): pos {h['position']}, score {h['score']:.2f}\")\n```\n\n### Workflow 2: SNP Impact on TF Binding (Regulatory Variant Analysis)\n\n1. Retrieve the genomic sequence flanking the SNP (±20 bp each side)\n2. Construct ref and alt sequences\n3. Scan with all relevant TF PWMs\n4. Report TFs whose binding is created or destroyed by the SNP\n\n### Workflow 3: Motif Enrichment Analysis\n\n1. Identify a set of peak sequences (e.g., from ChIP-seq or ATAC-seq)\n2. Scan all peaks with JASPAR PWMs\n3. Compare hit rates in peaks vs. background sequences\n4. Report significantly enriched motifs (Fisher's exact test or FIMO-style scoring)\n\n## Collections Available\n\n| Collection | Description | Profiles |\n|------------|-------------|----------|\n| `CORE` | Non-redundant, high-quality profiles | ~1,210 |\n| `UNVALIDATED` | Experimentally derived but not validated | ~500 |\n| `PHYLOFACTS` | Phylogenetically conserved sites | ~50 |\n| `CNE` | Conserved non-coding elements | ~30 |\n| `POLII` | RNA Pol II binding profiles | ~20 |\n| `FAM` | TF family representative profiles | ~170 |\n| `SPLICE` | Splice factor profiles | ~20 |\n\n## Best Practices\n\n- **Use CORE collection** for most analyses — best validated and non-redundant\n- **Threshold selection**: 80% of max score is common for de novo prediction; 90% for high-confidence\n- **Always scan both strands** — TFs can bind in either orientation\n- **Provide flanking context** for variant analysis: at least (motif_length - 1) bp on each side\n- **Consider background**: PWM scores relative to uniform (0.25) background; adjust for actual GC content\n- **Cross-validate with ChIP-seq data** when available — motif scanning has many false positives\n- **Use Biopython's motifs module** for full-featured scanning: `from Bio import motifs`\n\n## Additional Resources\n\n- **JASPAR portal**: https:\u002F\u002Fjaspar.elixir.no\u002F\n- **API documentation**: https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002Fdocs\u002F\n- **JASPAR 2024 paper**: Castro-Mondragon et al. (2022) Nucleic Acids Research. PMID: 34875674\n- **Biopython motifs**: https:\u002F\u002Fbiopython.org\u002Fdocs\u002Flatest\u002FTutorial\u002Fchapter_motifs.html\n- **FIMO tool** (for large-scale scanning): https:\u002F\u002Fmeme-suite.org\u002Fmeme\u002Ftools\u002Ffimo\n- **HOMER** (motif enrichment): http:\u002F\u002Fhomer.ucsd.edu\u002Fhomer\u002F\n- **GitHub**: https:\u002F\u002Fgithub.com\u002Fwassermanlab\u002FJASPAR-UCSC-tracks\n","# JASPAR Database\n\n## Overview\n\nJASPAR (https:\u002F\u002Fjaspar.elixir.no\u002F) is the gold-standard open-access database of curated, non-redundant transcription factor (TF) binding profiles stored as position frequency matrices (PFMs). JASPAR 2024 contains 1,210 non-redundant TF binding profiles for 164 eukaryotic species. Each profile is experimentally derived (ChIP-seq, SELEX, HT-SELEX, protein binding microarray, etc.) and rigorously validated.\n\n**Key resources:**\n- JASPAR portal: https:\u002F\u002Fjaspar.elixir.no\u002F\n- REST API: https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002F\n- API docs: https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002Fdocs\u002F\n- Python package: `jaspar` (via Biopython) or direct API\n\n## When to Use This Skill\n\nUse JASPAR when:\n\n- **TF binding site prediction**: Scan a DNA sequence for potential binding sites of a TF\n- **Regulatory variant interpretation**: Does a GWAS\u002FeQTL variant disrupt a TF binding motif?\n- **Promoter\u002Fenhancer analysis**: What TFs are predicted to bind to a regulatory element?\n- **Gene regulatory network construction**: Link TFs to their target genes via motif scanning\n- **TF family analysis**: Compare binding profiles across a TF family (e.g., all homeobox factors)\n- **ChIP-seq analysis**: Find known TF motifs enriched in ChIP-seq peaks\n- **ENCODE\u002FATAC-seq interpretation**: Match open chromatin regions to TF binding profiles\n\n## Core Capabilities\n\n### 1. JASPAR REST API\n\nBase URL: `https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002F`\n\n```python\nimport requests\n\nBASE_URL = \"https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\"\n\ndef jaspar_get(endpoint, params=None):\n    url = f\"{BASE_URL}\u002F{endpoint}\"\n    response = requests.get(url, params=params, headers={\"Accept\": \"application\u002Fjson\"})\n    response.raise_for_status()\n    return response.json()\n```\n\n### 2. Search for TF Profiles\n\n```python\ndef search_jaspar(\n    tf_name=None,\n    species=None,\n    collection=\"CORE\",\n    tf_class=None,\n    tf_family=None,\n    page=1,\n    page_size=25\n):\n    \"\"\"Search JASPAR for TF binding profiles.\"\"\"\n    params = {\n        \"collection\": collection,\n        \"page\": page,\n        \"page_size\": page_size,\n        \"format\": \"json\"\n    }\n    if tf_name:\n        params[\"name\"] = tf_name\n    if species:\n        params[\"species\"] = species  # Use taxonomy ID or name, e.g., \"9606\" for human\n    if tf_class:\n        params[\"tf_class\"] = tf_class\n    if tf_family:\n        params[\"tf_family\"] = tf_family\n\n    return jaspar_get(\"matrix\", params)\n\n# Examples:\n# Search for human CTCF profile\nctcf = search_jaspar(\"CTCF\", species=\"9606\")\nprint(f\"Found {ctcf['count']} CTCF profiles\")\n\n# Search for all homeobox TFs in human\nhox_tfs = search_jaspar(tf_class=\"Homeodomain\", species=\"9606\")\n\n# Search for a TF family\nnfkb = search_jaspar(tf_family=\"NF-kappaB\")\n```\n\n### 3. Fetch a Specific Matrix (PFM\u002FPWM)\n\n```python\ndef get_matrix(matrix_id):\n    \"\"\"Fetch a specific JASPAR matrix by ID (e.g., 'MA0139.1' for CTCF).\"\"\"\n    return jaspar_get(f\"matrix\u002F{matrix_id}\u002F\")\n\n# Example: Get CTCF matrix\nctcf_matrix = get_matrix(\"MA0139.1\")\n\n# Matrix structure:\n# {\n#   \"matrix_id\": \"MA0139.1\",\n#   \"name\": \"CTCF\",\n#   \"collection\": \"CORE\",\n#   \"tax_group\": \"vertebrates\",\n#   \"pfm\": { \"A\": [...], \"C\": [...], \"G\": [...], \"T\": [...] },\n#   \"consensus\": \"CCGCGNGGNGGCAG\",\n#   \"length\": 19,\n#   \"species\": [{\"tax_id\": 9606, \"name\": \"Homo sapiens\"}],\n#   \"class\": [\"C2H2 zinc finger factors\"],\n#   \"family\": [\"BEN domain factors\"],\n#   \"type\": \"ChIP-seq\",\n#   \"uniprot_ids\": [\"P49711\"]\n# }\n```\n\n### 4. Download PFM\u002FPWM as Matrix\n\n```python\nimport numpy as np\n\ndef get_pwm(matrix_id, pseudocount=0.8):\n    \"\"\"\n    Fetch a PFM from JASPAR and convert to PWM (log-odds).\n    Returns numpy array of shape (4, L) in order A, C, G, T.\n    \"\"\"\n    matrix = get_matrix(matrix_id)\n    pfm = matrix[\"pfm\"]\n\n    # Convert PFM to numpy\n    pfm_array = np.array([pfm[\"A\"], pfm[\"C\"], pfm[\"G\"], pfm[\"T\"]], dtype=float)\n\n    # Add pseudocount\n    pfm_array += pseudocount\n\n    # Normalize to get PPM\n    ppm = pfm_array \u002F pfm_array.sum(axis=0, keepdims=True)\n\n    # Convert to PWM (log-odds relative to background 0.25)\n    background = 0.25\n    pwm = np.log2(ppm \u002F background)\n\n    return pwm, matrix[\"name\"]\n\n# Example\npwm, name = get_pwm(\"MA0139.1\")  # CTCF\nprint(f\"PWM for {name}: shape {pwm.shape}\")\nmax_score = pwm.max(axis=0).sum()\nprint(f\"Maximum possible score: {max_score:.2f} bits\")\n```\n\n### 5. Scan a DNA Sequence for TF Binding Sites\n\n```python\nimport numpy as np\nfrom typing import List, Tuple\n\nNUCLEOTIDE_MAP = {'A': 0, 'C': 1, 'G': 2, 'T': 3,\n                  'a': 0, 'c': 1, 'g': 2, 't': 3}\n\ndef scan_sequence(sequence: str, pwm: np.ndarray, threshold_pct: float = 0.8) -> List[dict]:\n    \"\"\"\n    Scan a DNA sequence for TF binding sites using a PWM.\n\n    Args:\n        sequence: DNA sequence string\n        pwm: PWM array (4 x L) in ACGT order\n        threshold_pct: Fraction of max score to use as threshold (0-1)\n\n    Returns:\n        List of hits with position, score, and matched sequence\n    \"\"\"\n    motif_len = pwm.shape[1]\n    max_score = pwm.max(axis=0).sum()\n    min_score = pwm.min(axis=0).sum()\n    threshold = min_score + threshold_pct * (max_score - min_score)\n\n    hits = []\n    seq = sequence.upper()\n\n    for i in range(len(seq) - motif_len + 1):\n        subseq = seq[i:i + motif_len]\n        # Skip if contains non-ACGT\n        if any(c not in NUCLEOTIDE_MAP for c in subseq):\n            continue\n\n        score = sum(pwm[NUCLEOTIDE_MAP[c], j] for j, c in enumerate(subseq))\n\n        if score >= threshold:\n            relative_score = (score - min_score) \u002F (max_score - min_score)\n            hits.append({\n                \"position\": i + 1,  # 1-based\n                \"score\": score,\n                \"relative_score\": relative_score,\n                \"sequence\": subseq,\n                \"strand\": \"+\"\n            })\n\n    return hits\n\n# Example: Scan a promoter sequence for CTCF binding sites\npromoter = \"AGCCCGCGAGGNGGCAGTTGCCTGGAGCAGGATCAGCAGATC\"\npwm, name = get_pwm(\"MA0139.1\")\nhits = scan_sequence(promoter, pwm, threshold_pct=0.75)\nfor hit in hits:\n    print(f\"  Position {hit['position']}: {hit['sequence']} (score: {hit['score']:.2f}, {hit['relative_score']:.0%})\")\n```\n\n### 6. Scan Both Strands\n\n```python\ndef reverse_complement(seq: str) -> str:\n    complement = {'A': 'T', 'T': 'A', 'C': 'G', 'G': 'C', 'N': 'N'}\n    return ''.join(complement.get(b, 'N') for b in reversed(seq.upper()))\n\ndef scan_both_strands(sequence: str, pwm: np.ndarray, threshold_pct: float = 0.8):\n    \"\"\"Scan forward and reverse complement strands.\"\"\"\n    fwd_hits = scan_sequence(sequence, pwm, threshold_pct)\n    for h in fwd_hits:\n        h[\"strand\"] = \"+\"\n\n    rev_seq = reverse_complement(sequence)\n    rev_hits = scan_sequence(rev_seq, pwm, threshold_pct)\n    seq_len = len(sequence)\n    for h in rev_hits:\n        h[\"strand\"] = \"-\"\n        h[\"position\"] = seq_len - h[\"position\"] - len(h[\"sequence\"]) + 2  # Convert to fwd coords\n\n    all_hits = fwd_hits + rev_hits\n    return sorted(all_hits, key=lambda x: x[\"position\"])\n```\n\n### 7. Variant Impact on TF Binding\n\n```python\ndef variant_tfbs_impact(ref_seq: str, alt_seq: str, pwm: np.ndarray,\n                          tf_name: str, threshold_pct: float = 0.7):\n    \"\"\"\n    Assess impact of a SNP on TF binding by comparing ref vs alt sequences.\n    Both sequences should be centered on the variant with flanking context.\n    \"\"\"\n    ref_hits = scan_both_strands(ref_seq, pwm, threshold_pct)\n    alt_hits = scan_both_strands(alt_seq, pwm, threshold_pct)\n\n    max_ref = max((h[\"score\"] for h in ref_hits), default=None)\n    max_alt = max((h[\"score\"] for h in alt_hits), default=None)\n\n    result = {\n        \"tf\": tf_name,\n        \"ref_max_score\": max_ref,\n        \"alt_max_score\": max_alt,\n        \"ref_has_site\": len(ref_hits) > 0,\n        \"alt_has_site\": len(alt_hits) > 0,\n    }\n    if max_ref and max_alt:\n        result[\"score_change\"] = max_alt - max_ref\n        result[\"effect\"] = \"gained\" if max_alt > max_ref else \"disrupted\"\n    elif max_ref and not max_alt:\n        result[\"effect\"] = \"disrupted\"\n    elif not max_ref and max_alt:\n        result[\"effect\"] = \"gained\"\n    else:\n        result[\"effect\"] = \"no_site\"\n\n    return result\n```\n\n## Query Workflows\n\n### Workflow 1: Find All TF Binding Sites in a Promoter\n\n```python\nimport requests, numpy as np\n\n# 1. Get relevant TF matrices (e.g., all human TFs in CORE collection)\nresponse = requests.get(\n    \"https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002Fmatrix\u002F\",\n    params={\"species\": \"9606\", \"collection\": \"CORE\", \"page_size\": 500, \"page\": 1}\n)\nmatrices = response.json()[\"results\"]\n\n# 2. For each matrix, compute PWM and scan promoter\npromoter = \"CCCGCCCGCCCGCCGCCCGCAGTTAATGAGCCCAGCGTGCC\"  # Example\n\nall_hits = []\nfor m in matrices[:10]:  # Limit for demo\n    pwm_data = requests.get(f\"https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002Fmatrix\u002F{m['matrix_id']}\u002F\").json()\n    pfm = pfm_data[\"pfm\"]\n    pfm_arr = np.array([pfm[\"A\"], pfm[\"C\"], pfm[\"G\"], pfm[\"T\"]], dtype=float) + 0.8\n    ppm = pfm_arr \u002F pfm_arr.sum(axis=0)\n    pwm = np.log2(ppm \u002F 0.25)\n\n    hits = scan_sequence(promoter, pwm, threshold_pct=0.8)\n    for h in hits:\n        h[\"tf_name\"] = m[\"name\"]\n        h[\"matrix_id\"] = m[\"matrix_id\"]\n    all_hits.extend(hits)\n\nprint(f\"Found {len(all_hits)} TF binding sites\")\nfor h in sorted(all_hits, key=lambda x: -x[\"score\"])[:5]:\n    print(f\"  {h['tf_name']} ({h['matrix_id']}): pos {h['position']}, score {h['score']:.2f}\")\n```\n\n### Workflow 2: SNP Impact on TF Binding (Regulatory Variant Analysis)\n\n1. Retrieve the genomic sequence flanking the SNP (±20 bp each side)\n2. Construct ref and alt sequences\n3. Scan with all relevant TF PWMs\n4. Report TFs whose binding is created or destroyed by the SNP\n\n### Workflow 3: Motif Enrichment Analysis\n\n1. Identify a set of peak sequences (e.g., from ChIP-seq or ATAC-seq)\n2. Scan all peaks with JASPAR PWMs\n3. Compare hit rates in peaks vs. background sequences\n4. Report significantly enriched motifs (Fisher's exact test or FIMO-style scoring)\n\n## Collections Available\n\n| Collection | Description | Profiles |\n|------------|-------------|----------|\n| `CORE` | Non-redundant, high-quality profiles | ~1,210 |\n| `UNVALIDATED` | Experimentally derived but not validated | ~500 |\n| `PHYLOFACTS` | Phylogenetically conserved sites | ~50 |\n| `CNE` | Conserved non-coding elements | ~30 |\n| `POLII` | RNA Pol II binding profiles | ~20 |\n| `FAM` | TF family representative profiles | ~170 |\n| `SPLICE` | Splice factor profiles | ~20 |\n\n## Best Practices\n\n- **Use CORE collection** for most analyses — best validated and non-redundant\n- **Threshold selection**: 80% of max score is common for de novo prediction; 90% for high-confidence\n- **Always scan both strands** — TFs can bind in either orientation\n- **Provide flanking context** for variant analysis: at least (motif_length - 1) bp on each side\n- **Consider background**: PWM scores relative to uniform (0.25) background; adjust for actual GC content\n- **Cross-validate with ChIP-seq data** when available — motif scanning has many false positives\n- **Use Biopython's motifs module** for full-featured scanning: `from Bio import motifs`\n\n## Additional Resources\n\n- **JASPAR portal**: https:\u002F\u002Fjaspar.elixir.no\u002F\n- **API documentation**: https:\u002F\u002Fjaspar.elixir.no\u002Fapi\u002Fv1\u002Fdocs\u002F\n- **JASPAR 2024 paper**: Castro-Mondragon et al. (2022) Nucleic Acids Research. PMID: 34875674\n- **Biopython motifs**: https:\u002F\u002Fbiopython.org\u002Fdocs\u002Flatest\u002FTutorial\u002Fchapter_motifs.html\n- **FIMO tool** (for large-scale scanning): https:\u002F\u002Fmeme-suite.org\u002Fmeme\u002Ftools\u002Ffimo\n- **HOMER** (motif enrichment): http:\u002F\u002Fhomer.ucsd.edu\u002Fhomer\u002F\n- **GitHub**: https:\u002F\u002Fgithub.com\u002Fwassermanlab\u002FJASPAR-UCSC-tracks\n",{"name":5,"license":15,"metadata":47,"description":7},{"skill-author":48},"Kuan-lin Huang","main","d3998984163a67a891ee8397e35adf79b14e872d","https:\u002F\u002Fgithub.com\u002Fhuamu668\u002Fclawhub-openclaw-medical","https:\u002F\u002Fgithub.com\u002Fhuamu668","2026-03-12 11:49:42",{"source":8,"skillName":5,"commands":55,"prompt":65,"zipAvailable":66},[56,59,62],{"tool":57,"command":58},"npx","npx skills add huamu668\u002Fclawhub-openclaw-medical --skill jaspar-database",{"tool":60,"command":61},"bunx","bunx skills add huamu668\u002Fclawhub-openclaw-medical --skill jaspar-database",{"tool":63,"command":64},"pnpm","pnpm dlx skills add huamu668\u002Fclawhub-openclaw-medical --skill jaspar-database","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fhuamu668\u002Fclawhub-openclaw-medical\u002Fblob\u002Fmain\u002Fjaspar-database\u002FSKILL.md",true,[],[69,90,119,139,152,181],{"skillNo":70,"name":71,"nameZh":6,"description":72,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":73,"licenseFileUrl":6,"sourceHtmlUrl":74,"categories":75,"keywords":76,"publishedAt":42},"01M6DR3JGAEX5G5FR7TK3D8NS8","zarr-python","Chunked N-D arrays for cloud storage. Compressed arrays, parallel I\u002FO, S3\u002FGCS integration, NumPy\u002FDask\u002FXarray compatible, for large-scale scientific computing pipelines.","MIT","https:\u002F\u002Fgithub.com\u002Fhuamu668\u002Fclawhub-openclaw-medical\u002Fblob\u002Fmain\u002Fzarr-python\u002FSKILL.md",[],[77,78,79,80,81,82,83,84,85,86,87,88,89],"python","zarr python","storage","scientific computing","numpy","arrays","pipelines","parallel","dask","cloud","gcs","s3","integration",{"skillNo":91,"name":92,"nameZh":6,"description":93,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":73,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":99,"publishedAt":42},"01M6DR101MEDE5XT2ZZ5VBEAA5","vaex","Use this skill for processing and analyzing large tabular datasets (billions of rows) that exceed available RAM. Vaex excels at out-of-core DataFrame operations, lazy evaluation, fast aggregations, efficient visualization of big data, and machine learning on large datasets. Apply when users need to work with large CSV\u002FHDF5\u002FArrow\u002FParquet files, perform fast statistics on massive datasets, create visualizations of big data, or build ML pipelines that do not fit in memory.","https:\u002F\u002Fgithub.com\u002Fhuamu668\u002Fclawhub-openclaw-medical\u002Fblob\u002Fmain\u002Fvaex\u002FSKILL.md",[96],{"categoryNo":97,"categoryName":98,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000013","分析与可视化",[92,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118],"machine learning","in memory","learning","csv","visualization","create","core","ml","big data","memory","visualizations","fit","statistics","do","build","files","use","operations","work",{"skillNo":120,"name":121,"nameZh":6,"description":122,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":73,"licenseFileUrl":6,"sourceHtmlUrl":123,"categories":124,"keywords":125,"publishedAt":42},"01M6DQVMB0GBKF2W44FKXVD1P7","torch-geometric","Graph Neural Networks (PyG). Node\u002Fgraph classification, link prediction, GCN, GAT, GraphSAGE, heterogeneous graphs, molecular property prediction, for geometric deep learning.","https:\u002F\u002Fgithub.com\u002Fhuamu668\u002Fclawhub-openclaw-medical\u002Fblob\u002Fmain\u002Ftorch-geometric\u002FSKILL.md",[],[126,102,127,128,129,130,131,132,133,134,135,136,137,138],"torch geometric","node","Neural","link","gat","molecular","graphs","deep","networks","graph","neural networks","deep learning","classification",{"skillNo":140,"name":141,"nameZh":6,"description":142,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":73,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":145,"publishedAt":42},"01M6DQH2GZPZKEQ140GRCJ9746","tiledbvcf","Efficient storage and retrieval of genomic variant data using TileDB. Scalable VCF\u002FBCF ingestion, incremental sample addition, compressed storage, parallel queries, and export capabilities for population genomics.","https:\u002F\u002Fgithub.com\u002Fhuamu668\u002Fclawhub-openclaw-medical\u002Fblob\u002Fmain\u002Ftiledbvcf\u002FSKILL.md",[],[141,146,34,147,148,149,150,84,151,79],"data","sample","queries","ingestion","export","capabilities",{"skillNo":153,"name":154,"nameZh":6,"description":155,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":73,"licenseFileUrl":6,"sourceHtmlUrl":156,"categories":157,"keywords":166,"publishedAt":42},"01M6DQD9G958EM6NHJ994D0SK1","solublempnn","Solubility-optimized protein sequence design using SolubleMPNN. Use this skill when: (1) Designing for E. coli expression, (2) Optimizing solubility of designed proteins, (3) Reducing aggregation propensity, (4) Need high-yield expression, (5) Avoiding inclusion body formation.\nFor standard design, use proteinmpnn. For ligand-aware design, use ligandmpnn.","https:\u002F\u002Fgithub.com\u002Fhuamu668\u002Fclawhub-openclaw-medical\u002Fblob\u002Fmain\u002Fsolublempnn\u002FSKILL.md",[158,161],{"categoryNo":159,"categoryName":160,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":162,"categoryName":163,"taxonomyType":164,"taxonomyTypeDesc":165},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[154,167,168,116,169,170,171,172,173,174,175,176,177,178,179,180],"inclusion","yield","modal","Tools","aggregation","design","proteins","solubility","proteinmpnn","ligandmpnn","ligand-aware","inverse-folding","expression","sequence-design",{"skillNo":182,"name":183,"nameZh":6,"description":184,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":185,"licenseFileUrl":6,"sourceHtmlUrl":186,"categories":187,"keywords":188,"publishedAt":42},"01M6DQ8W91A93MGGCEEW949HBC","scvelo","RNA velocity analysis with scVelo. Estimate cell state transitions from unspliced\u002Fspliced mRNA dynamics, infer trajectory directions, compute latent time, and identify driver genes in single-cell RNA-seq data. Complements Scanpy\u002FscVI-tools for trajectory inference.","BSD-3-Clause","https:\u002F\u002Fgithub.com\u002Fhuamu668\u002Fclawhub-openclaw-medical\u002Fblob\u002Fmain\u002Fscvelo\u002FSKILL.md",[],[183,189,190,191,192,193,194,195,196,197,40,170,146,198,199],"RNA","single-cell","infer","cell","transitions","time","compute","velocity","scanpy","state","inference"]