[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M73J9JP6RDFF4AFPQS6PS2J6":3,"skill-same:01M73J9JP6RDFF4AFPQS6PS2J6":48},{"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":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":27,"repositoryHtmlUrl":28,"repositoryHomepageUrl":29,"ownerHtmlUrl":30,"ownerBlogUrl":31,"ownerDescription":32,"updatedAt":33,"install":34,"resources":47},"01M73J9JP6RDFF4AFPQS6PS2J6","scanpy-scrna-seq",null,"scRNA-seq with Scanpy: QC, normalization, HVG selection, PCA, neighborhood graph, UMAP\u002Ft-SNE, Leiden clustering, markers, cell annotation, trajectory inference. Standard scRNA-seq exploration.","bg-szy\u002FTOP-SKILLS","bg-szy","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F106576190?v=4","01M73A4E8KPV67SFXRY8XZGNBX","ShuZhiyong","01M73A4E96MQ294MHM74TZBVQD",6,"CC-BY-4.0","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fawesome-skills\u002Fscanpy-scrna-seq\u002FSKILL.md",[],[],"2026-11-11 15:11:14",false,"---\nname: \"scanpy-scrna-seq\"\ndescription: \"scRNA-seq with Scanpy: QC, normalization, HVG selection, PCA, neighborhood graph, UMAP\u002Ft-SNE, Leiden clustering, markers, cell annotation, trajectory inference. Standard scRNA-seq exploration.\"\nlicense: \"CC-BY-4.0\"\n---\n\n# Scanpy Single-Cell RNA-seq Analysis\n\n## Overview\n\nScanpy is a scalable Python toolkit for analyzing single-cell RNA-seq data built on the AnnData format. This skill covers the end-to-end standard workflow: quality control, normalization, highly variable gene selection, dimensionality reduction, clustering, marker gene identification, and cell type annotation. It produces annotated datasets and publication-quality visualizations.\n\n## When to Use\n\n- Analyzing single-cell RNA-seq count matrices (10X Genomics, h5ad, CSV, loom)\n- Performing quality control filtering on scRNA-seq datasets (mitochondrial %, gene counts)\n- Running dimensionality reduction: PCA, UMAP, t-SNE\n- Identifying cell clusters via Leiden community detection\n- Finding differentially expressed marker genes per cluster (Wilcoxon, t-test, logistic regression)\n- Annotating cell types from known marker gene panels\n- Conducting trajectory inference and pseudotime analysis (PAGA, diffusion pseudotime)\n- Generating publication-quality single-cell plots (dot plots, heatmaps, stacked violins)\n- Comparing gene expression across experimental conditions within cell types\n- Use **omics-plotting** SKILL for generic figures (volcano\u002Fheatmap\u002Fbar\u002FKM) from exported tables; single-cell views stay in scanpy `sc.pl.*`\n- Use **Seurat** (R\u002FBioconductor) instead for scRNA-seq analysis in an existing R workflow or when Seurat-specific assay types are required\n\n## Prerequisites\n\n- **Python packages**: `scanpy>=1.10`, `leidenalg`, `igraph`, `anndata`\n- **Data requirements**: Gene expression count matrix (cells x genes). Common formats: 10X Cell Ranger output (`filtered_feature_bc_matrix\u002F`), `.h5ad`, `.h5`, `.csv`\n- **Environment**: Python 3.9+; 16GB+ RAM recommended for >50k cells\n\n```bash\npip install \"scanpy[leiden]\" anndata\n```\n\n## Pre-flight Interview\n\nSettle these with the user before writing any analysis code.\n\n```yaml\ndecisions:\n  - id: D1\n    param: pct_counts_mt\n    kind: required\n    source: data\n    ask: \"Dying cells leak cytoplasmic RNA and read as high-mitochondrial - where should the cut sit for this tissue?\"\n    default: \"20% (PBMC ~5%, solid tumour ~20%; propose from the observed distribution)\"\n\n  - id: D2\n    param: batch_key\n    kind: required\n    source: data\n    ask: \"Which variable separates samples that were processed apart (donor, run, 10X lane), so its effect is not read as biology?\"\n    default: null\n    skip_if: \"all cells come from one sample and one processing run\"\n\n  - id: D3\n    param: resolution\n    kind: optional\n    source: user\n    ask: \"How finely should cells be split - broad lineages, or subtypes within them?\"\n    default: \"0.8 (0.1-0.3 broad lineages, 1.0-2.0 fine subtypes)\"\n\n  - id: D4\n    param: n_top_genes\n    kind: optional\n    source: user\n    ask: \"How many variable genes should drive the embedding? More captures subtle states but adds noise.\"\n    default: 2000\n\n  - id: D5\n    param: n_pcs\n    kind: optional_conditional\n    source: data\n    depends_on: [D4]\n    ask: \"How many principal components carry real structure, by the variance-ratio elbow?\"\n    default: 40\n\n  - id: D6\n    param: min_genes, min_cells\n    kind: optional_conditional\n    source: data\n    ask: \"Where should empty droplets and undetected genes be cut off?\"\n    default: \"cells with \u003C200 genes, genes in \u003C3 cells\"\n\n  - id: D6b\n    param: annotationStrategy\n    kind: required\n    source: user\n    ask: \"Markers (A), a CellTypist model (B), an ensemble on your labelled reference (C), or markers and transfer compared (D)?\"\n    default: null\n\n  - id: D6c\n    param: markerPanel\n    kind: optional\n    source: literature\n    ask: \"Which canonical markers define the expected populations?\"\n    default: \"agent-drafted panel for the tissue and state, listed in the plan\"\n    skip_if: \"label transfer only\"\n\n  - id: D7\n    param: method (rank_genes_groups)\n    kind: optional\n    source: user\n    ask: \"Which test should rank marker genes per cluster?\"\n    default: \"wilcoxon\"\n\n  - id: D8\n    param: target_sum, flavor\n    kind: optional\n    source: user\n    ask: \"Should the standard library-size normalization and Seurat v3 highly-variable-gene selection be used?\"\n    default: \"target_sum 1e4, flavor seurat_v3\"\n\n  - id: D9\n    param: random_state\n    kind: never_ask\n    source: data\n    reason: \"Fixes the draw for reproducibility; does not change what the data supports\"\n    default: 0\n```\n\nD5 hangs on D4 because the elbow is read off a PCA computed over the selected\nvariable genes — a different gene count moves where it sits. D2 shapes the\npipeline rather than a single call: naming a batch adds a correction stage\n(`harmony-batch-correction` or ComBat) before the neighbor graph. D6b and D6c\nare the same questions as `cell-type-annotation` D2 and D4; ask each once.\n\n## Workflow\n\n### Step 1: Setup and Data Loading\n\nConfigure scanpy settings and read the count matrix into an AnnData object. Ensure gene names are unique.\n\n```python\nimport scanpy as sc\nimport numpy as np\nimport pandas as pd\n\n# Configure settings\nsc.settings.verbosity = 3  # errors=0, warnings=1, info=2, hints=3\nsc.settings.set_figure_params(dpi=80, facecolor=\"white\")\n\n# Load data — pick the reader matching your format\nadata = sc.read_10x_mtx(\n    \"path\u002Fto\u002Ffiltered_feature_bc_matrix\u002F\",\n    var_names=\"gene_symbols\",\n    cache=True,\n)\n# Alternatives:\n# adata = sc.read_h5ad(\"data.h5ad\")\n# adata = sc.read_10x_h5(\"data.h5\")\n\nadata.var_names_make_unique()\nprint(f\"Loaded: {adata.n_obs} cells x {adata.n_vars} genes\")\nprint(f\"Sparsity: {1 - adata.X.nnz \u002F (adata.n_obs * adata.n_vars):.1%}\")\n```\n\n### Step 2: Quality Control\n\nAnnotate mitochondrial\u002Fribosomal genes, compute QC metrics, visualize distributions, and filter low-quality cells.\n\n```python\n# Annotate gene groups\nadata.var[\"mt\"] = adata.var_names.str.startswith(\"MT-\")    # human; use \"mt-\" for mouse\nadata.var[\"ribo\"] = adata.var_names.str.startswith((\"RPS\", \"RPL\"))\n\n# Calculate QC metrics\nsc.pp.calculate_qc_metrics(\n    adata, qc_vars=[\"mt\", \"ribo\"], percent_top=None, log1p=False, inplace=True\n)\n\n# Visualize QC distributions\nsc.pl.violin(\n    adata,\n    [\"n_genes_by_counts\", \"total_counts\", \"pct_counts_mt\"],\n    jitter=0.4,\n    multi_panel=True,\n)\nsc.pl.scatter(adata, x=\"total_counts\", y=\"pct_counts_mt\")\nsc.pl.scatter(adata, x=\"total_counts\", y=\"n_genes_by_counts\")\n\n# Filter — adjust thresholds based on the QC plots above\nsc.pp.filter_cells(adata, min_genes=200)\nsc.pp.filter_genes(adata, min_cells=3)\nadata = adata[adata.obs.n_genes_by_counts \u003C 5000, :]  # remove potential doublets\nadata = adata[adata.obs.pct_counts_mt \u003C 20, :]         # remove dying cells\n\nprint(f\"After QC: {adata.n_obs} cells x {adata.n_vars} genes\")\n```\n\n### Step 3: Normalization and Feature Selection\n\nNormalize library sizes, log-transform, and identify highly variable genes (HVGs). Store raw counts for later differential expression.\n\n```python\n# Preserve raw counts in a layer\nadata.layers[\"counts\"] = adata.X.copy()\n\n# Normalize to 10,000 counts per cell, then log-transform\nsc.pp.normalize_total(adata, target_sum=1e4)\nsc.pp.log1p(adata)\n\n# Save normalized data as .raw for visualization\nadata.raw = adata\n\n# Identify highly variable genes\nsc.pp.highly_variable_genes(adata, n_top_genes=2000, flavor=\"seurat_v3\", layer=\"counts\")\nsc.pl.highly_variable_genes(adata)\n\n# Subset to HVGs\nadata = adata[:, adata.var.highly_variable]\nprint(f\"HVG subset: {adata.n_obs} cells x {adata.n_vars} genes\")\n```\n\n### Step 4: Scaling and Regression\n\nRegress out confounders and scale gene expression values. This prepares data for PCA.\n\n```python\n# Regress out unwanted sources of variation\nsc.pp.regress_out(adata, [\"total_counts\", \"pct_counts_mt\"])\n\n# Scale to unit variance, clip extreme values\nsc.pp.scale(adata, max_value=10)\n\nprint(f\"Scaled matrix: mean={adata.X.mean():.4f}, std={adata.X.std():.4f}\")\n```\n\n### Step 5: Dimensionality Reduction\n\nCompute PCA, inspect the variance ratio elbow plot, then build a neighborhood graph and embed with UMAP.\n\n```python\n# PCA\nsc.tl.pca(adata, svd_solver=\"arpack\", n_comps=50)\nsc.pl.pca_variance_ratio(adata, log=True, n_pcs=50)\n\n# Determine n_pcs from elbow plot (typically 30-50)\nn_pcs = 40\n\n# Compute k-nearest neighbor graph\nsc.pp.neighbors(adata, n_neighbors=15, n_pcs=n_pcs)\n\n# UMAP embedding\nsc.tl.umap(adata)\nsc.pl.umap(adata, color=[\"n_genes_by_counts\", \"total_counts\", \"pct_counts_mt\"])\n\nprint(f\"UMAP shape: {adata.obsm['X_umap'].shape}\")\n```\n\n### Step 6: Clustering\n\nRun Leiden clustering at multiple resolutions and select the best granularity by visual inspection.\n\n```python\n# Test multiple resolutions\nfor res in [0.3, 0.5, 0.8, 1.0, 1.2]:\n    sc.tl.leiden(adata, resolution=res, key_added=f\"leiden_res{res}\", flavor=\"igraph\", n_iterations=2)\n\n# Compare resolutions side-by-side\nsc.pl.umap(\n    adata,\n    color=[\"leiden_res0.3\", \"leiden_res0.5\", \"leiden_res0.8\", \"leiden_res1.0\"],\n    ncols=2,\n    legend_loc=\"on data\",\n)\n\n# Pick final resolution based on biological plausibility\nadata.obs[\"leiden\"] = adata.obs[\"leiden_res0.5\"]\nn_clusters = adata.obs[\"leiden\"].nunique()\nprint(f\"Selected resolution=0.5: {n_clusters} clusters\")\n```\n\n### Step 7: Marker Gene Identification\n\nFind differentially expressed genes per cluster using Wilcoxon rank-sum test on raw counts.\n\n```python\n# Rank genes per cluster\nsc.tl.rank_genes_groups(adata, groupby=\"leiden\", method=\"wilcoxon\", use_raw=True)\n\n# Visualization\nsc.pl.rank_genes_groups(adata, n_genes=20, sharey=False)\nsc.pl.rank_genes_groups_dotplot(adata, n_genes=5)\nsc.pl.rank_genes_groups_heatmap(adata, n_genes=10, use_raw=True, show_gene_labels=True)\n\n# Extract as DataFrame\nmarkers_df = sc.get.rank_genes_groups_df(adata, group=None)\ntop_markers = markers_df[markers_df[\"pvals_adj\"] \u003C 0.05].groupby(\"group\").head(10)\nprint(f\"Significant markers: {len(top_markers)} genes across {top_markers['group'].nunique()} clusters\")\nprint(top_markers[[\"group\", \"names\", \"logfoldchanges\", \"pvals_adj\"]].head(15))\n```\n\n### Step 8: Cell Type Annotation and Export\n\nAssign cell types based on canonical marker genes, visualize, and save all results.\n\n```python\n# Define canonical markers (example: human PBMC)\nmarker_genes = {\n    \"CD4 T cells\":      [\"CD3D\", \"CD3E\", \"IL7R\"],\n    \"CD8 T cells\":      [\"CD8A\", \"CD8B\", \"GZMK\"],\n    \"B cells\":          [\"MS4A1\", \"CD79A\", \"CD79B\"],\n    \"NK cells\":         [\"NKG7\", \"GNLY\", \"KLRD1\"],\n    \"CD14+ Monocytes\":  [\"CD14\", \"LYZ\", \"S100A9\"],\n    \"FCGR3A+ Monocytes\":[\"FCGR3A\", \"MS4A7\"],\n    \"Dendritic cells\":  [\"FCER1A\", \"CST3\"],\n    \"Platelets\":        [\"PPBP\", \"PF4\"],\n}\n\n# Dot plot — rows = clusters, columns = markers\nsc.pl.dotplot(adata, var_names=marker_genes, groupby=\"leiden\", use_raw=True)\n\n# Map clusters → cell types (adjust based on your dot plot)\ncluster_to_celltype = {\n    \"0\": \"CD4 T cells\",\n    \"1\": \"CD14+ Monocytes\",\n    \"2\": \"B cells\",\n    \"3\": \"CD8 T cells\",\n    \"4\": \"NK cells\",\n    \"5\": \"FCGR3A+ Monocytes\",\n    \"6\": \"Dendritic cells\",\n    \"7\": \"Platelets\",\n}\nadata.obs[\"cell_type\"] = adata.obs[\"leiden\"].map(cluster_to_celltype).fillna(\"Unknown\")\nsc.pl.umap(adata, color=\"cell_type\", legend_loc=\"on data\", frameon=False)\n\n# Save results\nadata.write(\"results\u002Fannotated_data.h5ad\", compression=\"gzip\")\nadata.obs.to_csv(\"results\u002Fcell_metadata.csv\")\nmarkers_df.to_csv(\"results\u002Fmarker_genes.csv\", index=False)\nprint(f\"Saved: {adata.n_obs} cells with {adata.obs['cell_type'].nunique()} cell types\")\n```\n\n## Key Parameters\n\n| Parameter | Default | Range \u002F Options | Effect |\n|-----------|---------|-----------------|--------|\n| `min_genes` (filter_cells) | `200` | `100`-`500` | Minimum genes detected per cell; lower keeps more cells |\n| `min_cells` (filter_genes) | `3` | `3`-`10` | Minimum cells expressing a gene; higher is stricter |\n| `pct_counts_mt` threshold | `20` | `5`-`30` | Max mitochondrial %; tissue-dependent (5% for PBMCs, 20% for tumors) |\n| `n_top_genes` (HVG) | `2000` | `1000`-`5000` | Number of highly variable genes; more captures subtle variation |\n| `flavor` (HVG) | `\"seurat_v3\"` | `\"seurat\"`, `\"seurat_v3\"`, `\"cell_ranger\"` | HVG detection algorithm |\n| `n_pcs` (neighbors) | `40` | `20`-`50` | Number of PCs for neighbor graph; check elbow plot |\n| `n_neighbors` | `15` | `5`-`50` | k for k-NN graph; lower emphasizes local structure |\n| `resolution` (leiden) | `0.5` | `0.1`-`2.0` | Clustering granularity; higher → more clusters |\n| `method` (rank_genes) | `\"wilcoxon\"` | `\"wilcoxon\"`, `\"t-test\"`, `\"logreg\"` | DE test; Wilcoxon recommended for publication |\n| `target_sum` (normalize) | `1e4` | `1e4`-`1e5` | Target library size per cell |\n\n## Common Recipes\n\n### Recipe: Batch Correction with ComBat\n\nWhen to use: multiple samples\u002Fbatches with visible batch effects on the UMAP.\n\n```python\n# Requires 'batch' column in adata.obs\nsc.pp.combat(adata, key=\"batch\")\n# Re-run PCA, neighbors, UMAP, clustering after correction\nsc.tl.pca(adata, svd_solver=\"arpack\")\nsc.pp.neighbors(adata, n_pcs=40)\nsc.tl.umap(adata)\nsc.pl.umap(adata, color=[\"batch\", \"leiden\"])\n```\n\n### Recipe: Trajectory Inference with PAGA + Diffusion Pseudotime\n\nWhen to use: cells follow a developmental continuum rather than discrete clusters.\n\n```python\n# PAGA graph abstraction\nsc.tl.paga(adata, groups=\"leiden\")\nsc.pl.paga(adata, color=\"leiden\", threshold=0.03)\n\n# Reinitialize UMAP with PAGA layout\nsc.tl.umap(adata, init_pos=\"paga\")\n\n# Diffusion pseudotime — set root cell\nadata.uns[\"iroot\"] = np.flatnonzero(adata.obs[\"leiden\"] == \"0\")[0]\nsc.tl.diffmap(adata)\nsc.tl.dpt(adata)\nsc.pl.umap(adata, color=[\"dpt_pseudotime\", \"leiden\"])\n```\n\n### Recipe: Publication-Quality Figures\n\nWhen to use: generating figures for manuscripts or presentations.\n\n```python\nsc.settings.set_figure_params(dpi=300, frameon=False, figsize=(5, 5))\n\n# UMAP with custom palette\nsc.pl.umap(\n    adata, color=\"cell_type\",\n    palette=\"Set2\",\n    legend_loc=\"on data\",\n    legend_fontsize=10,\n    legend_fontoutline=2,\n    title=\"\",\n    save=\"_celltype_publication.pdf\",\n)\n\n# Stacked violin plot of top markers\nflat_markers = [g for genes in marker_genes.values() for g in genes[:2]]\nsc.pl.stacked_violin(\n    adata, var_names=flat_markers, groupby=\"cell_type\",\n    use_raw=True, swap_axes=True,\n    save=\"_markers_violin.pdf\",\n)\n```\n\n### Recipe: Differential Expression Between Conditions\n\nWhen to use: comparing treated vs control within a specific cell type.\n\n```python\n# Subset to cell type of interest\nadata_t = adata[adata.obs[\"cell_type\"] == \"CD4 T cells\"].copy()\n\n# DE between conditions\nsc.tl.rank_genes_groups(adata_t, groupby=\"condition\", groups=[\"treated\"], reference=\"control\", method=\"wilcoxon\", use_raw=True)\nsc.pl.rank_genes_groups_volcano(adata_t, groups=[\"treated\"])\n\nde_results = sc.get.rank_genes_groups_df(adata_t, group=\"treated\")\nsig_genes = de_results[de_results[\"pvals_adj\"] \u003C 0.05]\nprint(f\"Significant DE genes: {len(sig_genes)}\")\n```\n\n## Expected Outputs\n\n- `results\u002Fannotated_data.h5ad` — Full AnnData with embeddings (PCA, UMAP), cluster labels, cell type annotations, and raw counts layer\n- `results\u002Fcell_metadata.csv` — Per-cell table: barcode, cluster, cell type, QC metrics (n_genes, total_counts, pct_mt)\n- `results\u002Fmarker_genes.csv` — DE genes per cluster: gene name, log fold change, adjusted p-value\n- QC figures: violin plots (n_genes, total_counts, pct_mt), scatter plots\n- Embedding figures: UMAP colored by cluster, cell type, QC metrics, pseudotime\n- Marker figures: dot plot, heatmap, stacked violin of canonical markers\n\n## Troubleshooting\n\n| Problem | Cause | Solution |\n|---------|-------|----------|\n| `ModuleNotFoundError: leidenalg` | Leiden package not installed | `pip install leidenalg igraph` |\n| `MemoryError` during PCA | Dense matrix exceeds RAM | Use `sc.pp.pca(adata, chunked=True, chunk_size=20000)` |\n| UMAP shows single blob | Over-filtering or too few HVGs | Relax QC thresholds; increase `n_top_genes` to 3000-5000 |\n| Too many\u002Ffew clusters | Resolution mismatch | Sweep `resolution` from 0.1 to 2.0 and compare UMAPs |\n| `KeyError: 'MT-'` not found | Wrong species prefix | Use `mt-` (lowercase) for mouse, `MT-` for human |\n| Batch effects dominate UMAP | Uncorrected technical variation | Apply ComBat recipe or use Harmony\u002FscVI for integration |\n| `adata.raw is None` error | Forgot to save raw before subsetting | Set `adata.raw = adata` after normalization, before HVG subset |\n| Marker genes non-specific | Resolution too low merging cell types | Increase resolution or use `logistic_regression` method |\n| Slow `regress_out` | Large cell count | Skip regress_out; use `sc.pp.scale()` alone (often sufficient) |\n| `ValueError` in `rank_genes_groups` | Cluster with too few cells | Remove clusters with \u003C10 cells before DE: `adata = adata[adata.obs.groupby('leiden').filter(lambda x: len(x)>=10).index]` |\n\n## Bundled Resources\n\nThis skill includes reference files for deeper lookup. Read these on demand when the main SKILL.md needs more detail.\n\n### references\u002Fapi_reference.md\nQuick-lookup table of all scanpy functions organized by module (sc.pp.*, sc.tl.*, sc.pl.*), with full signatures, common parameters, and AnnData structure reference. **Use when**: you need the exact function name or parameter for a specific operation.\n\n### references\u002Fplotting_guide.md\nComprehensive visualization guide: QC plots, UMAP styling, marker gene plots (dot plot, heatmap, stacked violin), trajectory plots, multi-panel figures, publication customization, and color palette recommendations. **Use when**: creating figures for publications or presentations.\n\n### references\u002Fstandard_workflow.md\nDetailed step-by-step reference for each pipeline stage with decision points, parameter rationale, and alternative approaches (MAD-based filtering, scran normalization, automated annotation). **Use when**: performing a full analysis from scratch and needing deeper guidance than the Workflow section above.\n\n## References\n\n- [Scanpy documentation](https:\u002F\u002Fscanpy.readthedocs.io\u002F) — Official API reference and tutorials (BSD-3)\n- [Scanpy PBMC3k tutorial](https:\u002F\u002Fscanpy-tutorials.readthedocs.io\u002Fen\u002Flatest\u002Fpbmc3k.html) — Canonical walkthrough (BSD-3)\n- [Galaxy Training: Clustering 3K PBMCs with Scanpy](https:\u002F\u002Ftraining.galaxyproject.org\u002Ftraining-material\u002Ftopics\u002Fsingle-cell\u002F) — Step-by-step tutorial (CC-BY)\n- [Luecken & Theis (2019)](https:\u002F\u002Fdoi.org\u002F10.15252\u002Fmsb.20188746) — \"Current best practices in single-cell RNA-seq analysis: a tutorial\", *Mol Syst Biol*\n- [Heumos et al. (2023)](https:\u002F\u002Fdoi.org\u002F10.1038\u002Fs41576-023-00586-w) — \"Best practices for single-cell analysis across modalities\", *Nat Rev Genet*\n- [scverse ecosystem](https:\u002F\u002Fscverse.org\u002F) — Related tools: anndata, scvi-tools, squidpy, cellrank\n","# Scanpy Single-Cell RNA-seq Analysis\n\n## Overview\n\nScanpy is a scalable Python toolkit for analyzing single-cell RNA-seq data built on the AnnData format. This skill covers the end-to-end standard workflow: quality control, normalization, highly variable gene selection, dimensionality reduction, clustering, marker gene identification, and cell type annotation. It produces annotated datasets and publication-quality visualizations.\n\n## When to Use\n\n- Analyzing single-cell RNA-seq count matrices (10X Genomics, h5ad, CSV, loom)\n- Performing quality control filtering on scRNA-seq datasets (mitochondrial %, gene counts)\n- Running dimensionality reduction: PCA, UMAP, t-SNE\n- Identifying cell clusters via Leiden community detection\n- Finding differentially expressed marker genes per cluster (Wilcoxon, t-test, logistic regression)\n- Annotating cell types from known marker gene panels\n- Conducting trajectory inference and pseudotime analysis (PAGA, diffusion pseudotime)\n- Generating publication-quality single-cell plots (dot plots, heatmaps, stacked violins)\n- Comparing gene expression across experimental conditions within cell types\n- Use **omics-plotting** SKILL for generic figures (volcano\u002Fheatmap\u002Fbar\u002FKM) from exported tables; single-cell views stay in scanpy `sc.pl.*`\n- Use **Seurat** (R\u002FBioconductor) instead for scRNA-seq analysis in an existing R workflow or when Seurat-specific assay types are required\n\n## Prerequisites\n\n- **Python packages**: `scanpy>=1.10`, `leidenalg`, `igraph`, `anndata`\n- **Data requirements**: Gene expression count matrix (cells x genes). Common formats: 10X Cell Ranger output (`filtered_feature_bc_matrix\u002F`), `.h5ad`, `.h5`, `.csv`\n- **Environment**: Python 3.9+; 16GB+ RAM recommended for >50k cells\n\n```bash\npip install \"scanpy[leiden]\" anndata\n```\n\n## Pre-flight Interview\n\nSettle these with the user before writing any analysis code.\n\n```yaml\ndecisions:\n  - id: D1\n    param: pct_counts_mt\n    kind: required\n    source: data\n    ask: \"Dying cells leak cytoplasmic RNA and read as high-mitochondrial - where should the cut sit for this tissue?\"\n    default: \"20% (PBMC ~5%, solid tumour ~20%; propose from the observed distribution)\"\n\n  - id: D2\n    param: batch_key\n    kind: required\n    source: data\n    ask: \"Which variable separates samples that were processed apart (donor, run, 10X lane), so its effect is not read as biology?\"\n    default: null\n    skip_if: \"all cells come from one sample and one processing run\"\n\n  - id: D3\n    param: resolution\n    kind: optional\n    source: user\n    ask: \"How finely should cells be split - broad lineages, or subtypes within them?\"\n    default: \"0.8 (0.1-0.3 broad lineages, 1.0-2.0 fine subtypes)\"\n\n  - id: D4\n    param: n_top_genes\n    kind: optional\n    source: user\n    ask: \"How many variable genes should drive the embedding? More captures subtle states but adds noise.\"\n    default: 2000\n\n  - id: D5\n    param: n_pcs\n    kind: optional_conditional\n    source: data\n    depends_on: [D4]\n    ask: \"How many principal components carry real structure, by the variance-ratio elbow?\"\n    default: 40\n\n  - id: D6\n    param: min_genes, min_cells\n    kind: optional_conditional\n    source: data\n    ask: \"Where should empty droplets and undetected genes be cut off?\"\n    default: \"cells with \u003C200 genes, genes in \u003C3 cells\"\n\n  - id: D6b\n    param: annotationStrategy\n    kind: required\n    source: user\n    ask: \"Markers (A), a CellTypist model (B), an ensemble on your labelled reference (C), or markers and transfer compared (D)?\"\n    default: null\n\n  - id: D6c\n    param: markerPanel\n    kind: optional\n    source: literature\n    ask: \"Which canonical markers define the expected populations?\"\n    default: \"agent-drafted panel for the tissue and state, listed in the plan\"\n    skip_if: \"label transfer only\"\n\n  - id: D7\n    param: method (rank_genes_groups)\n    kind: optional\n    source: user\n    ask: \"Which test should rank marker genes per cluster?\"\n    default: \"wilcoxon\"\n\n  - id: D8\n    param: target_sum, flavor\n    kind: optional\n    source: user\n    ask: \"Should the standard library-size normalization and Seurat v3 highly-variable-gene selection be used?\"\n    default: \"target_sum 1e4, flavor seurat_v3\"\n\n  - id: D9\n    param: random_state\n    kind: never_ask\n    source: data\n    reason: \"Fixes the draw for reproducibility; does not change what the data supports\"\n    default: 0\n```\n\nD5 hangs on D4 because the elbow is read off a PCA computed over the selected\nvariable genes — a different gene count moves where it sits. D2 shapes the\npipeline rather than a single call: naming a batch adds a correction stage\n(`harmony-batch-correction` or ComBat) before the neighbor graph. D6b and D6c\nare the same questions as `cell-type-annotation` D2 and D4; ask each once.\n\n## Workflow\n\n### Step 1: Setup and Data Loading\n\nConfigure scanpy settings and read the count matrix into an AnnData object. Ensure gene names are unique.\n\n```python\nimport scanpy as sc\nimport numpy as np\nimport pandas as pd\n\n# Configure settings\nsc.settings.verbosity = 3  # errors=0, warnings=1, info=2, hints=3\nsc.settings.set_figure_params(dpi=80, facecolor=\"white\")\n\n# Load data — pick the reader matching your format\nadata = sc.read_10x_mtx(\n    \"path\u002Fto\u002Ffiltered_feature_bc_matrix\u002F\",\n    var_names=\"gene_symbols\",\n    cache=True,\n)\n# Alternatives:\n# adata = sc.read_h5ad(\"data.h5ad\")\n# adata = sc.read_10x_h5(\"data.h5\")\n\nadata.var_names_make_unique()\nprint(f\"Loaded: {adata.n_obs} cells x {adata.n_vars} genes\")\nprint(f\"Sparsity: {1 - adata.X.nnz \u002F (adata.n_obs * adata.n_vars):.1%}\")\n```\n\n### Step 2: Quality Control\n\nAnnotate mitochondrial\u002Fribosomal genes, compute QC metrics, visualize distributions, and filter low-quality cells.\n\n```python\n# Annotate gene groups\nadata.var[\"mt\"] = adata.var_names.str.startswith(\"MT-\")    # human; use \"mt-\" for mouse\nadata.var[\"ribo\"] = adata.var_names.str.startswith((\"RPS\", \"RPL\"))\n\n# Calculate QC metrics\nsc.pp.calculate_qc_metrics(\n    adata, qc_vars=[\"mt\", \"ribo\"], percent_top=None, log1p=False, inplace=True\n)\n\n# Visualize QC distributions\nsc.pl.violin(\n    adata,\n    [\"n_genes_by_counts\", \"total_counts\", \"pct_counts_mt\"],\n    jitter=0.4,\n    multi_panel=True,\n)\nsc.pl.scatter(adata, x=\"total_counts\", y=\"pct_counts_mt\")\nsc.pl.scatter(adata, x=\"total_counts\", y=\"n_genes_by_counts\")\n\n# Filter — adjust thresholds based on the QC plots above\nsc.pp.filter_cells(adata, min_genes=200)\nsc.pp.filter_genes(adata, min_cells=3)\nadata = adata[adata.obs.n_genes_by_counts \u003C 5000, :]  # remove potential doublets\nadata = adata[adata.obs.pct_counts_mt \u003C 20, :]         # remove dying cells\n\nprint(f\"After QC: {adata.n_obs} cells x {adata.n_vars} genes\")\n```\n\n### Step 3: Normalization and Feature Selection\n\nNormalize library sizes, log-transform, and identify highly variable genes (HVGs). Store raw counts for later differential expression.\n\n```python\n# Preserve raw counts in a layer\nadata.layers[\"counts\"] = adata.X.copy()\n\n# Normalize to 10,000 counts per cell, then log-transform\nsc.pp.normalize_total(adata, target_sum=1e4)\nsc.pp.log1p(adata)\n\n# Save normalized data as .raw for visualization\nadata.raw = adata\n\n# Identify highly variable genes\nsc.pp.highly_variable_genes(adata, n_top_genes=2000, flavor=\"seurat_v3\", layer=\"counts\")\nsc.pl.highly_variable_genes(adata)\n\n# Subset to HVGs\nadata = adata[:, adata.var.highly_variable]\nprint(f\"HVG subset: {adata.n_obs} cells x {adata.n_vars} genes\")\n```\n\n### Step 4: Scaling and Regression\n\nRegress out confounders and scale gene expression values. This prepares data for PCA.\n\n```python\n# Regress out unwanted sources of variation\nsc.pp.regress_out(adata, [\"total_counts\", \"pct_counts_mt\"])\n\n# Scale to unit variance, clip extreme values\nsc.pp.scale(adata, max_value=10)\n\nprint(f\"Scaled matrix: mean={adata.X.mean():.4f}, std={adata.X.std():.4f}\")\n```\n\n### Step 5: Dimensionality Reduction\n\nCompute PCA, inspect the variance ratio elbow plot, then build a neighborhood graph and embed with UMAP.\n\n```python\n# PCA\nsc.tl.pca(adata, svd_solver=\"arpack\", n_comps=50)\nsc.pl.pca_variance_ratio(adata, log=True, n_pcs=50)\n\n# Determine n_pcs from elbow plot (typically 30-50)\nn_pcs = 40\n\n# Compute k-nearest neighbor graph\nsc.pp.neighbors(adata, n_neighbors=15, n_pcs=n_pcs)\n\n# UMAP embedding\nsc.tl.umap(adata)\nsc.pl.umap(adata, color=[\"n_genes_by_counts\", \"total_counts\", \"pct_counts_mt\"])\n\nprint(f\"UMAP shape: {adata.obsm['X_umap'].shape}\")\n```\n\n### Step 6: Clustering\n\nRun Leiden clustering at multiple resolutions and select the best granularity by visual inspection.\n\n```python\n# Test multiple resolutions\nfor res in [0.3, 0.5, 0.8, 1.0, 1.2]:\n    sc.tl.leiden(adata, resolution=res, key_added=f\"leiden_res{res}\", flavor=\"igraph\", n_iterations=2)\n\n# Compare resolutions side-by-side\nsc.pl.umap(\n    adata,\n    color=[\"leiden_res0.3\", \"leiden_res0.5\", \"leiden_res0.8\", \"leiden_res1.0\"],\n    ncols=2,\n    legend_loc=\"on data\",\n)\n\n# Pick final resolution based on biological plausibility\nadata.obs[\"leiden\"] = adata.obs[\"leiden_res0.5\"]\nn_clusters = adata.obs[\"leiden\"].nunique()\nprint(f\"Selected resolution=0.5: {n_clusters} clusters\")\n```\n\n### Step 7: Marker Gene Identification\n\nFind differentially expressed genes per cluster using Wilcoxon rank-sum test on raw counts.\n\n```python\n# Rank genes per cluster\nsc.tl.rank_genes_groups(adata, groupby=\"leiden\", method=\"wilcoxon\", use_raw=True)\n\n# Visualization\nsc.pl.rank_genes_groups(adata, n_genes=20, sharey=False)\nsc.pl.rank_genes_groups_dotplot(adata, n_genes=5)\nsc.pl.rank_genes_groups_heatmap(adata, n_genes=10, use_raw=True, show_gene_labels=True)\n\n# Extract as DataFrame\nmarkers_df = sc.get.rank_genes_groups_df(adata, group=None)\ntop_markers = markers_df[markers_df[\"pvals_adj\"] \u003C 0.05].groupby(\"group\").head(10)\nprint(f\"Significant markers: {len(top_markers)} genes across {top_markers['group'].nunique()} clusters\")\nprint(top_markers[[\"group\", \"names\", \"logfoldchanges\", \"pvals_adj\"]].head(15))\n```\n\n### Step 8: Cell Type Annotation and Export\n\nAssign cell types based on canonical marker genes, visualize, and save all results.\n\n```python\n# Define canonical markers (example: human PBMC)\nmarker_genes = {\n    \"CD4 T cells\":      [\"CD3D\", \"CD3E\", \"IL7R\"],\n    \"CD8 T cells\":      [\"CD8A\", \"CD8B\", \"GZMK\"],\n    \"B cells\":          [\"MS4A1\", \"CD79A\", \"CD79B\"],\n    \"NK cells\":         [\"NKG7\", \"GNLY\", \"KLRD1\"],\n    \"CD14+ Monocytes\":  [\"CD14\", \"LYZ\", \"S100A9\"],\n    \"FCGR3A+ Monocytes\":[\"FCGR3A\", \"MS4A7\"],\n    \"Dendritic cells\":  [\"FCER1A\", \"CST3\"],\n    \"Platelets\":        [\"PPBP\", \"PF4\"],\n}\n\n# Dot plot — rows = clusters, columns = markers\nsc.pl.dotplot(adata, var_names=marker_genes, groupby=\"leiden\", use_raw=True)\n\n# Map clusters → cell types (adjust based on your dot plot)\ncluster_to_celltype = {\n    \"0\": \"CD4 T cells\",\n    \"1\": \"CD14+ Monocytes\",\n    \"2\": \"B cells\",\n    \"3\": \"CD8 T cells\",\n    \"4\": \"NK cells\",\n    \"5\": \"FCGR3A+ Monocytes\",\n    \"6\": \"Dendritic cells\",\n    \"7\": \"Platelets\",\n}\nadata.obs[\"cell_type\"] = adata.obs[\"leiden\"].map(cluster_to_celltype).fillna(\"Unknown\")\nsc.pl.umap(adata, color=\"cell_type\", legend_loc=\"on data\", frameon=False)\n\n# Save results\nadata.write(\"results\u002Fannotated_data.h5ad\", compression=\"gzip\")\nadata.obs.to_csv(\"results\u002Fcell_metadata.csv\")\nmarkers_df.to_csv(\"results\u002Fmarker_genes.csv\", index=False)\nprint(f\"Saved: {adata.n_obs} cells with {adata.obs['cell_type'].nunique()} cell types\")\n```\n\n## Key Parameters\n\n| Parameter | Default | Range \u002F Options | Effect |\n|-----------|---------|-----------------|--------|\n| `min_genes` (filter_cells) | `200` | `100`-`500` | Minimum genes detected per cell; lower keeps more cells |\n| `min_cells` (filter_genes) | `3` | `3`-`10` | Minimum cells expressing a gene; higher is stricter |\n| `pct_counts_mt` threshold | `20` | `5`-`30` | Max mitochondrial %; tissue-dependent (5% for PBMCs, 20% for tumors) |\n| `n_top_genes` (HVG) | `2000` | `1000`-`5000` | Number of highly variable genes; more captures subtle variation |\n| `flavor` (HVG) | `\"seurat_v3\"` | `\"seurat\"`, `\"seurat_v3\"`, `\"cell_ranger\"` | HVG detection algorithm |\n| `n_pcs` (neighbors) | `40` | `20`-`50` | Number of PCs for neighbor graph; check elbow plot |\n| `n_neighbors` | `15` | `5`-`50` | k for k-NN graph; lower emphasizes local structure |\n| `resolution` (leiden) | `0.5` | `0.1`-`2.0` | Clustering granularity; higher → more clusters |\n| `method` (rank_genes) | `\"wilcoxon\"` | `\"wilcoxon\"`, `\"t-test\"`, `\"logreg\"` | DE test; Wilcoxon recommended for publication |\n| `target_sum` (normalize) | `1e4` | `1e4`-`1e5` | Target library size per cell |\n\n## Common Recipes\n\n### Recipe: Batch Correction with ComBat\n\nWhen to use: multiple samples\u002Fbatches with visible batch effects on the UMAP.\n\n```python\n# Requires 'batch' column in adata.obs\nsc.pp.combat(adata, key=\"batch\")\n# Re-run PCA, neighbors, UMAP, clustering after correction\nsc.tl.pca(adata, svd_solver=\"arpack\")\nsc.pp.neighbors(adata, n_pcs=40)\nsc.tl.umap(adata)\nsc.pl.umap(adata, color=[\"batch\", \"leiden\"])\n```\n\n### Recipe: Trajectory Inference with PAGA + Diffusion Pseudotime\n\nWhen to use: cells follow a developmental continuum rather than discrete clusters.\n\n```python\n# PAGA graph abstraction\nsc.tl.paga(adata, groups=\"leiden\")\nsc.pl.paga(adata, color=\"leiden\", threshold=0.03)\n\n# Reinitialize UMAP with PAGA layout\nsc.tl.umap(adata, init_pos=\"paga\")\n\n# Diffusion pseudotime — set root cell\nadata.uns[\"iroot\"] = np.flatnonzero(adata.obs[\"leiden\"] == \"0\")[0]\nsc.tl.diffmap(adata)\nsc.tl.dpt(adata)\nsc.pl.umap(adata, color=[\"dpt_pseudotime\", \"leiden\"])\n```\n\n### Recipe: Publication-Quality Figures\n\nWhen to use: generating figures for manuscripts or presentations.\n\n```python\nsc.settings.set_figure_params(dpi=300, frameon=False, figsize=(5, 5))\n\n# UMAP with custom palette\nsc.pl.umap(\n    adata, color=\"cell_type\",\n    palette=\"Set2\",\n    legend_loc=\"on data\",\n    legend_fontsize=10,\n    legend_fontoutline=2,\n    title=\"\",\n    save=\"_celltype_publication.pdf\",\n)\n\n# Stacked violin plot of top markers\nflat_markers = [g for genes in marker_genes.values() for g in genes[:2]]\nsc.pl.stacked_violin(\n    adata, var_names=flat_markers, groupby=\"cell_type\",\n    use_raw=True, swap_axes=True,\n    save=\"_markers_violin.pdf\",\n)\n```\n\n### Recipe: Differential Expression Between Conditions\n\nWhen to use: comparing treated vs control within a specific cell type.\n\n```python\n# Subset to cell type of interest\nadata_t = adata[adata.obs[\"cell_type\"] == \"CD4 T cells\"].copy()\n\n# DE between conditions\nsc.tl.rank_genes_groups(adata_t, groupby=\"condition\", groups=[\"treated\"], reference=\"control\", method=\"wilcoxon\", use_raw=True)\nsc.pl.rank_genes_groups_volcano(adata_t, groups=[\"treated\"])\n\nde_results = sc.get.rank_genes_groups_df(adata_t, group=\"treated\")\nsig_genes = de_results[de_results[\"pvals_adj\"] \u003C 0.05]\nprint(f\"Significant DE genes: {len(sig_genes)}\")\n```\n\n## Expected Outputs\n\n- `results\u002Fannotated_data.h5ad` — Full AnnData with embeddings (PCA, UMAP), cluster labels, cell type annotations, and raw counts layer\n- `results\u002Fcell_metadata.csv` — Per-cell table: barcode, cluster, cell type, QC metrics (n_genes, total_counts, pct_mt)\n- `results\u002Fmarker_genes.csv` — DE genes per cluster: gene name, log fold change, adjusted p-value\n- QC figures: violin plots (n_genes, total_counts, pct_mt), scatter plots\n- Embedding figures: UMAP colored by cluster, cell type, QC metrics, pseudotime\n- Marker figures: dot plot, heatmap, stacked violin of canonical markers\n\n## Troubleshooting\n\n| Problem | Cause | Solution |\n|---------|-------|----------|\n| `ModuleNotFoundError: leidenalg` | Leiden package not installed | `pip install leidenalg igraph` |\n| `MemoryError` during PCA | Dense matrix exceeds RAM | Use `sc.pp.pca(adata, chunked=True, chunk_size=20000)` |\n| UMAP shows single blob | Over-filtering or too few HVGs | Relax QC thresholds; increase `n_top_genes` to 3000-5000 |\n| Too many\u002Ffew clusters | Resolution mismatch | Sweep `resolution` from 0.1 to 2.0 and compare UMAPs |\n| `KeyError: 'MT-'` not found | Wrong species prefix | Use `mt-` (lowercase) for mouse, `MT-` for human |\n| Batch effects dominate UMAP | Uncorrected technical variation | Apply ComBat recipe or use Harmony\u002FscVI for integration |\n| `adata.raw is None` error | Forgot to save raw before subsetting | Set `adata.raw = adata` after normalization, before HVG subset |\n| Marker genes non-specific | Resolution too low merging cell types | Increase resolution or use `logistic_regression` method |\n| Slow `regress_out` | Large cell count | Skip regress_out; use `sc.pp.scale()` alone (often sufficient) |\n| `ValueError` in `rank_genes_groups` | Cluster with too few cells | Remove clusters with \u003C10 cells before DE: `adata = adata[adata.obs.groupby('leiden').filter(lambda x: len(x)>=10).index]` |\n\n## Bundled Resources\n\nThis skill includes reference files for deeper lookup. Read these on demand when the main SKILL.md needs more detail.\n\n### references\u002Fapi_reference.md\nQuick-lookup table of all scanpy functions organized by module (sc.pp.*, sc.tl.*, sc.pl.*), with full signatures, common parameters, and AnnData structure reference. **Use when**: you need the exact function name or parameter for a specific operation.\n\n### references\u002Fplotting_guide.md\nComprehensive visualization guide: QC plots, UMAP styling, marker gene plots (dot plot, heatmap, stacked violin), trajectory plots, multi-panel figures, publication customization, and color palette recommendations. **Use when**: creating figures for publications or presentations.\n\n### references\u002Fstandard_workflow.md\nDetailed step-by-step reference for each pipeline stage with decision points, parameter rationale, and alternative approaches (MAD-based filtering, scran normalization, automated annotation). **Use when**: performing a full analysis from scratch and needing deeper guidance than the Workflow section above.\n\n## References\n\n- [Scanpy documentation](https:\u002F\u002Fscanpy.readthedocs.io\u002F) — Official API reference and tutorials (BSD-3)\n- [Scanpy PBMC3k tutorial](https:\u002F\u002Fscanpy-tutorials.readthedocs.io\u002Fen\u002Flatest\u002Fpbmc3k.html) — Canonical walkthrough (BSD-3)\n- [Galaxy Training: Clustering 3K PBMCs with Scanpy](https:\u002F\u002Ftraining.galaxyproject.org\u002Ftraining-material\u002Ftopics\u002Fsingle-cell\u002F) — Step-by-step tutorial (CC-BY)\n- [Luecken & Theis (2019)](https:\u002F\u002Fdoi.org\u002F10.15252\u002Fmsb.20188746) — \"Current best practices in single-cell RNA-seq analysis: a tutorial\", *Mol Syst Biol*\n- [Heumos et al. (2023)](https:\u002F\u002Fdoi.org\u002F10.1038\u002Fs41576-023-00586-w) — \"Best practices for single-cell analysis across modalities\", *Nat Rev Genet*\n- [scverse ecosystem](https:\u002F\u002Fscverse.org\u002F) — Related tools: anndata, scvi-tools, squidpy, cellrank\n",{"name":5,"license":15,"description":7},"master","fd76f882a04e445e899d5cfb2732f2105ea054ee","skills\u002Fawesome-skills\u002Fscanpy-scrna-seq",0,"https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS","https:\u002F\u002Fbg-szy.github.io\u002FTOP-SKILLS\u002F","https:\u002F\u002Fgithub.com\u002Fbg-szy","https:\u002F\u002Fwww.ecust.edu.cn\u002F","a student of East China University of Science and Technology","2026-11-15 03:38:02",{"source":8,"skillName":5,"commands":35,"prompt":45,"zipAvailable":46},[36,39,42],{"tool":37,"command":38},"npx","npx skills add bg-szy\u002FTOP-SKILLS --skill scanpy-scrna-seq",{"tool":40,"command":41},"bunx","bunx skills add bg-szy\u002FTOP-SKILLS --skill scanpy-scrna-seq",{"tool":43,"command":44},"pnpm","pnpm dlx skills add bg-szy\u002FTOP-SKILLS --skill scanpy-scrna-seq","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fawesome-skills\u002Fscanpy-scrna-seq\u002FSKILL.md",true,[],[49,59,67,75,84,91],{"skillNo":50,"name":51,"nameZh":6,"description":52,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":53,"licenseFileUrl":54,"sourceHtmlUrl":55,"categories":56,"keywords":57,"publishedAt":58},"01M748668J70YKWKS2VFVZ0ZRF","xlsx","Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .xltx, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like \"the xlsx in my downloads\") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fskills\u002Fxlsx\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fskills\u002Fxlsx\u002FSKILL.md",[],[],"2026-11-12 13:55:43",{"skillNo":60,"name":61,"nameZh":6,"description":62,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":53,"licenseFileUrl":63,"sourceHtmlUrl":64,"categories":65,"keywords":66,"publishedAt":58},"01M747X09GNGYJ7V4YE3NGGH7A","pptx","Use this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx or .potx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates (.potx), layouts, speaker notes, or comments. Trigger whenever the user mentions \"deck,\" \"slides,\" \"presentation,\" or references a .pptx or .potx filename, regardless of what they plan to do with the content afterward. If a .pptx or .potx file needs to be opened, created, or touched, use this skill.","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fskills\u002Fpptx\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fskills\u002Fpptx\u002FSKILL.md",[],[],{"skillNo":68,"name":69,"nameZh":6,"description":70,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":53,"licenseFileUrl":71,"sourceHtmlUrl":72,"categories":73,"keywords":74,"publishedAt":58},"01M747QR3VN12KXYDZGRXETTGS","docx","Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files) or Word templates (.dotx files). Triggers include: any mention of 'Word doc', 'word document', '.docx', '.dotx', or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx or .dotx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a 'report', 'memo', 'letter', 'template', or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation.","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fskills\u002Fdocx\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fskills\u002Fdocx\u002FSKILL.md",[],[],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":80,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":58},"01M76KTXGSTXVVDC7YSBM41ZZS","wxpusher-integration","Use when（适用场景）：用户明确询问、指定或上下文已选定 WxPusher，需要了解、接入或排查通知（含微信 ClawBot\u002FiLink、appToken、UID、Topic、SPT）；仅说“微信通知”、未选服务商，或只出现通用 UID\u002FTopic 时不触发。","MIT","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fmarketplace\u002Fwxpusher-integration\u002FLICENSE.md","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fmarketplace\u002Fwxpusher-integration\u002FSKILL.md",[],[],{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":90,"publishedAt":19},"01M748C5DS5BQBVBMG22FCGG34","branding","When the user wants to define, audit, or apply brand strategy—purpose, values, positioning, storytelling, voice, narrative (not only visuals). Also use when the user mentions \"brand strategy\", \"brand story\", \"brand storytelling\" or \"brand voice\". For typography, colors, design tokens, and frontend visuals, use brand-visual-generator.","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fsuperskills\u002Fbranding\u002FSKILL.md",[],[],{"skillNo":92,"name":93,"nameZh":6,"description":94,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":79,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":97,"publishedAt":19},"01M748C1GXJ9WRKP18X45DKP6G","brand-visual-generator","When the user wants to define, audit, or apply visual identity (typography, colors, spacing, design tokens, frontend aesthetics). Also use when the user mentions \"brand style guide\", \"visual identity\", \"design system\" or \"typography\". For brand story, positioning, and voice, use branding.","https:\u002F\u002Fgithub.com\u002Fbg-szy\u002FTOP-SKILLS\u002Fblob\u002Fmaster\u002Fskills\u002Fsuperskills\u002Fbrand-visual-generator\u002FSKILL.md",[],[]]