opencode-knowledge-work 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +212 -0
- package/README.md +124 -2
- package/content/bio-research/.mcp.json +48 -0
- package/content/bio-research/CONNECTORS.md +23 -0
- package/content/bio-research/LICENSE +202 -0
- package/content/bio-research/README.md +83 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/LICENSE.txt +201 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/SKILL.md +280 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/references/asm_schema_overview.md +226 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/references/field_classification_guide.md +503 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/references/flattening_guide.md +254 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/references/supported_instruments.md +151 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/requirements.txt +26 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/scripts/convert_to_asm.py +543 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/scripts/export_parser.py +481 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/scripts/flatten_asm.py +254 -0
- package/content/bio-research/skills/bio-research-instrument-data-to-allotrope/scripts/validate_asm.py +1102 -0
- package/content/bio-research/skills/bio-research-nextflow-development/LICENSE.txt +201 -0
- package/content/bio-research/skills/bio-research-nextflow-development/SKILL.md +290 -0
- package/content/bio-research/skills/bio-research-nextflow-development/references/geo-sra-acquisition.md +416 -0
- package/content/bio-research/skills/bio-research-nextflow-development/references/installation.md +96 -0
- package/content/bio-research/skills/bio-research-nextflow-development/references/pipelines/atacseq.md +138 -0
- package/content/bio-research/skills/bio-research-nextflow-development/references/pipelines/rnaseq.md +118 -0
- package/content/bio-research/skills/bio-research-nextflow-development/references/pipelines/sarek.md +145 -0
- package/content/bio-research/skills/bio-research-nextflow-development/references/troubleshooting.md +137 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/check_environment.py +452 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/config/genomes.yaml +148 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/config/pipelines/atacseq.yaml +187 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/config/pipelines/rnaseq.yaml +147 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/config/pipelines/sarek.yaml +233 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/detect_data_type.py +300 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/generate_samplesheet.py +455 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/manage_genomes.py +521 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/sra_geo_fetch.py +732 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/utils/__init__.py +69 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/utils/file_discovery.py +189 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/utils/ncbi_utils.py +808 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/utils/sample_inference.py +290 -0
- package/content/bio-research/skills/bio-research-nextflow-development/scripts/utils/validators.py +256 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/LICENSE.txt +201 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/SKILL.md +269 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/references/01-intuition-pumps.md +264 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/references/02-risk-assessment.md +323 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/references/03-optimization-function.md +481 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/references/04-parameter-strategy.md +396 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/references/05-decision-tree.md +85 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/references/06-adversity-planning.md +123 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/references/07-problem-inversion.md +152 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/references/08-integration-synthesis.md +173 -0
- package/content/bio-research/skills/bio-research-scientific-problem-selection/references/09-meta-framework.md +504 -0
- package/content/bio-research/skills/bio-research-scvi-tools/LICENSE.txt +201 -0
- package/content/bio-research/skills/bio-research-scvi-tools/SKILL.md +155 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/atac_peakvi.md +398 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/batch_correction_sysvi.md +417 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/citeseq_totalvi.md +420 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/data_preparation.md +286 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/environment_setup.md +254 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/label_transfer.md +373 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/multiome_multivi.md +384 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/rna_velocity_velovi.md +410 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/scarches_mapping.md +401 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/scrna_integration.md +429 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/spatial_deconvolution.md +438 -0
- package/content/bio-research/skills/bio-research-scvi-tools/references/troubleshooting.md +420 -0
- package/content/bio-research/skills/bio-research-scvi-tools/scripts/cluster_embed.py +212 -0
- package/content/bio-research/skills/bio-research-scvi-tools/scripts/differential_expression.py +220 -0
- package/content/bio-research/skills/bio-research-scvi-tools/scripts/integrate_datasets.py +237 -0
- package/content/bio-research/skills/bio-research-scvi-tools/scripts/model_utils.py +634 -0
- package/content/bio-research/skills/bio-research-scvi-tools/scripts/prepare_data.py +169 -0
- package/content/bio-research/skills/bio-research-scvi-tools/scripts/train_model.py +370 -0
- package/content/bio-research/skills/bio-research-scvi-tools/scripts/transfer_labels.py +224 -0
- package/content/bio-research/skills/bio-research-scvi-tools/scripts/validate_adata.py +397 -0
- package/content/bio-research/skills/bio-research-single-cell-rna-qc/LICENSE.txt +201 -0
- package/content/bio-research/skills/bio-research-single-cell-rna-qc/SKILL.md +175 -0
- package/content/bio-research/skills/bio-research-single-cell-rna-qc/references/scverse_qc_guidelines.md +186 -0
- package/content/bio-research/skills/bio-research-single-cell-rna-qc/scripts/qc_analysis.py +232 -0
- package/content/bio-research/skills/bio-research-single-cell-rna-qc/scripts/qc_core.py +233 -0
- package/content/bio-research/skills/bio-research-single-cell-rna-qc/scripts/qc_plotting.py +235 -0
- package/content/bio-research/skills/bio-research-start/SKILL.md +79 -0
- package/content/customer-support/.mcp.json +40 -0
- package/content/customer-support/CONNECTORS.md +19 -0
- package/content/customer-support/LICENSE +202 -0
- package/content/customer-support/README.md +140 -0
- package/content/customer-support/skills/customer-support-customer-escalation/SKILL.md +248 -0
- package/content/customer-support/skills/customer-support-customer-research/SKILL.md +252 -0
- package/content/customer-support/skills/customer-support-draft-response/SKILL.md +418 -0
- package/content/customer-support/skills/customer-support-kb-article/SKILL.md +351 -0
- package/content/customer-support/skills/customer-support-ticket-triage/SKILL.md +275 -0
- package/content/data/.mcp.json +36 -0
- package/content/data/CONNECTORS.md +18 -0
- package/content/data/LICENSE +202 -0
- package/content/data/README.md +121 -0
- package/content/data/skills/data-analyze/SKILL.md +119 -0
- package/content/data/skills/data-build-dashboard/SKILL.md +924 -0
- package/content/data/skills/data-create-viz/SKILL.md +154 -0
- package/content/data/skills/data-data-context-extractor/SKILL.md +227 -0
- package/content/data/skills/data-data-context-extractor/references/domain-template.md +147 -0
- package/content/data/skills/data-data-context-extractor/references/example-output.md +198 -0
- package/content/data/skills/data-data-context-extractor/references/skill-template.md +148 -0
- package/content/data/skills/data-data-context-extractor/references/sql-dialects.md +121 -0
- package/content/data/skills/data-data-context-extractor/scripts/package_data_skill.py +126 -0
- package/content/data/skills/data-data-visualization/SKILL.md +305 -0
- package/content/data/skills/data-explore-data/SKILL.md +325 -0
- package/content/data/skills/data-sql-queries/SKILL.md +428 -0
- package/content/data/skills/data-statistical-analysis/SKILL.md +245 -0
- package/content/data/skills/data-validate-data/SKILL.md +383 -0
- package/content/data/skills/data-write-query/SKILL.md +122 -0
- package/content/design/.mcp.json +44 -0
- package/content/design/CONNECTORS.md +18 -0
- package/content/design/README.md +117 -0
- package/content/design/skills/design-accessibility-review/SKILL.md +128 -0
- package/content/design/skills/design-design-critique/SKILL.md +118 -0
- package/content/design/skills/design-design-handoff/SKILL.md +131 -0
- package/content/design/skills/design-design-system/SKILL.md +190 -0
- package/content/design/skills/design-research-synthesis/SKILL.md +92 -0
- package/content/design/skills/design-user-research/SKILL.md +41 -0
- package/content/design/skills/design-ux-copy/SKILL.md +107 -0
- package/content/engineering/.mcp.json +48 -0
- package/content/engineering/CONNECTORS.md +19 -0
- package/content/engineering/README.md +136 -0
- package/content/engineering/skills/engineering-architecture/SKILL.md +85 -0
- package/content/engineering/skills/engineering-code-review/SKILL.md +118 -0
- package/content/engineering/skills/engineering-debug/SKILL.md +95 -0
- package/content/engineering/skills/engineering-deploy-checklist/SKILL.md +78 -0
- package/content/engineering/skills/engineering-documentation/SKILL.md +49 -0
- package/content/engineering/skills/engineering-incident-response/SKILL.md +158 -0
- package/content/engineering/skills/engineering-standup/SKILL.md +75 -0
- package/content/engineering/skills/engineering-system-design/SKILL.md +42 -0
- package/content/engineering/skills/engineering-tech-debt/SKILL.md +32 -0
- package/content/engineering/skills/engineering-testing-strategy/SKILL.md +33 -0
- package/content/enterprise-search/.mcp.json +36 -0
- package/content/enterprise-search/CONNECTORS.md +21 -0
- package/content/enterprise-search/LICENSE +202 -0
- package/content/enterprise-search/README.md +157 -0
- package/content/enterprise-search/skills/enterprise-search-digest/SKILL.md +173 -0
- package/content/enterprise-search/skills/enterprise-search-knowledge-synthesis/SKILL.md +258 -0
- package/content/enterprise-search/skills/enterprise-search-search/SKILL.md +178 -0
- package/content/enterprise-search/skills/enterprise-search-search-strategy/SKILL.md +222 -0
- package/content/enterprise-search/skills/enterprise-search-source-management/SKILL.md +173 -0
- package/content/finance/.mcp.json +32 -0
- package/content/finance/CONNECTORS.md +20 -0
- package/content/finance/LICENSE +202 -0
- package/content/finance/README.md +92 -0
- package/content/finance/skills/finance-audit-support/SKILL.md +374 -0
- package/content/finance/skills/finance-close-management/SKILL.md +221 -0
- package/content/finance/skills/finance-financial-statements/SKILL.md +335 -0
- package/content/finance/skills/finance-journal-entry/SKILL.md +131 -0
- package/content/finance/skills/finance-journal-entry-prep/SKILL.md +186 -0
- package/content/finance/skills/finance-reconciliation/SKILL.md +175 -0
- package/content/finance/skills/finance-sox-testing/SKILL.md +218 -0
- package/content/finance/skills/finance-variance-analysis/SKILL.md +266 -0
- package/content/human-resources/.mcp.json +28 -0
- package/content/human-resources/CONNECTORS.md +19 -0
- package/content/human-resources/README.md +138 -0
- package/content/human-resources/skills/human-resources-comp-analysis/SKILL.md +92 -0
- package/content/human-resources/skills/human-resources-draft-offer/SKILL.md +82 -0
- package/content/human-resources/skills/human-resources-interview-prep/SKILL.md +37 -0
- package/content/human-resources/skills/human-resources-onboarding/SKILL.md +104 -0
- package/content/human-resources/skills/human-resources-org-planning/SKILL.md +28 -0
- package/content/human-resources/skills/human-resources-people-report/SKILL.md +99 -0
- package/content/human-resources/skills/human-resources-performance-review/SKILL.md +149 -0
- package/content/human-resources/skills/human-resources-policy-lookup/SKILL.md +94 -0
- package/content/human-resources/skills/human-resources-recruiting-pipeline/SKILL.md +31 -0
- package/content/legal/.mcp.json +36 -0
- package/content/legal/CONNECTORS.md +21 -0
- package/content/legal/LICENSE +202 -0
- package/content/legal/README.md +234 -0
- package/content/legal/skills/legal-brief/SKILL.md +208 -0
- package/content/legal/skills/legal-compliance-check/SKILL.md +274 -0
- package/content/legal/skills/legal-legal-response/SKILL.md +457 -0
- package/content/legal/skills/legal-legal-risk-assessment/SKILL.md +265 -0
- package/content/legal/skills/legal-meeting-briefing/SKILL.md +220 -0
- package/content/legal/skills/legal-review-contract/SKILL.md +358 -0
- package/content/legal/skills/legal-signature-request/SKILL.md +104 -0
- package/content/legal/skills/legal-triage-nda/SKILL.md +262 -0
- package/content/legal/skills/legal-vendor-check/SKILL.md +159 -0
- package/content/manifest.json +86 -0
- package/content/marketing/.mcp.json +60 -0
- package/content/marketing/CONNECTORS.md +20 -0
- package/content/marketing/LICENSE +202 -0
- package/content/marketing/README.md +90 -0
- package/content/marketing/skills/marketing-brand-review/SKILL.md +276 -0
- package/content/marketing/skills/marketing-campaign-plan/SKILL.md +308 -0
- package/content/marketing/skills/marketing-competitive-brief/SKILL.md +331 -0
- package/content/marketing/skills/marketing-content-creation/SKILL.md +157 -0
- package/content/marketing/skills/marketing-draft-content/SKILL.md +117 -0
- package/content/marketing/skills/marketing-email-sequence/SKILL.md +220 -0
- package/content/marketing/skills/marketing-performance-report/SKILL.md +392 -0
- package/content/marketing/skills/marketing-seo-audit/SKILL.md +190 -0
- package/content/operations/.mcp.json +32 -0
- package/content/operations/CONNECTORS.md +20 -0
- package/content/operations/README.md +135 -0
- package/content/operations/skills/operations-capacity-plan/SKILL.md +113 -0
- package/content/operations/skills/operations-change-request/SKILL.md +121 -0
- package/content/operations/skills/operations-compliance-tracking/SKILL.md +44 -0
- package/content/operations/skills/operations-process-doc/SKILL.md +82 -0
- package/content/operations/skills/operations-process-optimization/SKILL.md +39 -0
- package/content/operations/skills/operations-risk-assessment/SKILL.md +40 -0
- package/content/operations/skills/operations-runbook/SKILL.md +87 -0
- package/content/operations/skills/operations-status-report/SKILL.md +77 -0
- package/content/operations/skills/operations-vendor-review/SKILL.md +104 -0
- package/content/pdf-viewer/.mcp.json +8 -0
- package/content/pdf-viewer/CONNECTORS.md +15 -0
- package/content/pdf-viewer/LICENSE +202 -0
- package/content/pdf-viewer/README.md +57 -0
- package/content/pdf-viewer/commands/annotate.md +51 -0
- package/content/pdf-viewer/commands/fill-form.md +73 -0
- package/content/pdf-viewer/commands/open.md +34 -0
- package/content/pdf-viewer/commands/sign.md +54 -0
- package/content/pdf-viewer/skills/pdf-viewer-view-pdf/SKILL.md +147 -0
- package/content/product-management/.mcp.json +72 -0
- package/content/product-management/CONNECTORS.md +22 -0
- package/content/product-management/LICENSE +202 -0
- package/content/product-management/README.md +118 -0
- package/content/product-management/commands/brainstorm.md +120 -0
- package/content/product-management/skills/product-management-competitive-brief/SKILL.md +302 -0
- package/content/product-management/skills/product-management-metrics-review/SKILL.md +388 -0
- package/content/product-management/skills/product-management-product-brainstorming/SKILL.md +273 -0
- package/content/product-management/skills/product-management-roadmap-update/SKILL.md +266 -0
- package/content/product-management/skills/product-management-sprint-planning/SKILL.md +94 -0
- package/content/product-management/skills/product-management-stakeholder-update/SKILL.md +352 -0
- package/content/product-management/skills/product-management-synthesize-research/SKILL.md +312 -0
- package/content/product-management/skills/product-management-write-spec/SKILL.md +250 -0
- package/content/productivity/.mcp.json +44 -0
- package/content/productivity/CONNECTORS.md +18 -0
- package/content/productivity/LICENSE +202 -0
- package/content/productivity/README.md +97 -0
- package/content/productivity/skills/dashboard.html +3111 -0
- package/content/productivity/skills/productivity-memory-management/SKILL.md +323 -0
- package/content/productivity/skills/productivity-start/SKILL.md +158 -0
- package/content/productivity/skills/productivity-task-management/SKILL.md +91 -0
- package/content/productivity/skills/productivity-update/SKILL.md +168 -0
- package/content/sales/.mcp.json +100 -0
- package/content/sales/CONNECTORS.md +36 -0
- package/content/sales/LICENSE +202 -0
- package/content/sales/README.md +148 -0
- package/content/sales/skills/sales-account-context/SKILL.md +94 -0
- package/content/sales/skills/sales-account-plan/SKILL.md +95 -0
- package/content/sales/skills/sales-account-research/SKILL.md +99 -0
- package/content/sales/skills/sales-account-tiering/SKILL.md +101 -0
- package/content/sales/skills/sales-call-prep/SKILL.md +111 -0
- package/content/sales/skills/sales-call-summary/SKILL.md +111 -0
- package/content/sales/skills/sales-close-plan/SKILL.md +106 -0
- package/content/sales/skills/sales-competitive-intelligence/SKILL.md +102 -0
- package/content/sales/skills/sales-create-an-asset/SKILL.md +105 -0
- package/content/sales/skills/sales-crm-hygiene-check/SKILL.md +103 -0
- package/content/sales/skills/sales-customer-health/SKILL.md +108 -0
- package/content/sales/skills/sales-customer-voice/SKILL.md +94 -0
- package/content/sales/skills/sales-daily-briefing/SKILL.md +61 -0
- package/content/sales/skills/sales-deal-advance-gap/SKILL.md +102 -0
- package/content/sales/skills/sales-deal-review/SKILL.md +105 -0
- package/content/sales/skills/sales-deal-signals/SKILL.md +96 -0
- package/content/sales/skills/sales-deal-slip-scenario/SKILL.md +101 -0
- package/content/sales/skills/sales-draft-outreach/SKILL.md +116 -0
- package/content/sales/skills/sales-end-of-day/SKILL.md +114 -0
- package/content/sales/skills/sales-expansion-whitespace/SKILL.md +97 -0
- package/content/sales/skills/sales-forecast/SKILL.md +100 -0
- package/content/sales/skills/sales-handle-objection/SKILL.md +93 -0
- package/content/sales/skills/sales-inbox-sweep/SKILL.md +114 -0
- package/content/sales/skills/sales-lead-triage/SKILL.md +105 -0
- package/content/sales/skills/sales-log-activity/SKILL.md +111 -0
- package/content/sales/skills/sales-pipeline-review/SKILL.md +97 -0
- package/content/sales/skills/sales-renewal-radar/SKILL.md +95 -0
- package/content/sales/skills/sales-rep-context/SKILL.md +90 -0
- package/content/sales/skills/sales-route-lead/SKILL.md +111 -0
- package/content/sales/skills/sales-schedule-meeting/SKILL.md +99 -0
- package/content/sales/skills/sales-setup/SKILL.md +195 -0
- package/content/sales/skills/sales-stakeholder-map/SKILL.md +107 -0
- package/content/sales/skills/sales-team-pipeline/SKILL.md +105 -0
- package/content/sales/skills/sales-update-opportunity/SKILL.md +111 -0
- package/content/sales/skills/sales-weekly-wrap/SKILL.md +90 -0
- package/content/sales/skills/sales-win-loss-review/SKILL.md +88 -0
- package/content/small-business/.mcp.json +148 -0
- package/content/small-business/README.md +117 -0
- package/content/small-business/skills/small-business-ad-manager/SKILL.md +128 -0
- package/content/small-business/skills/small-business-ad-manager/reference/ad_copy.md +112 -0
- package/content/small-business/skills/small-business-ad-manager/reference/change_playbook.md +127 -0
- package/content/small-business/skills/small-business-ad-manager/reference/data_sources.md +100 -0
- package/content/small-business/skills/small-business-ad-manager/reference/diagnostics.md +89 -0
- package/content/small-business/skills/small-business-ad-manager/reference/gotchas.md +181 -0
- package/content/small-business/skills/small-business-ap-processor/SKILL.md +158 -0
- package/content/small-business/skills/small-business-ap-processor/reference/coding_rules.md +70 -0
- package/content/small-business/skills/small-business-ap-processor/reference/gotchas.md +131 -0
- package/content/small-business/skills/small-business-ap-processor/reference/intake_and_extraction.md +82 -0
- package/content/small-business/skills/small-business-ap-processor/reference/matching_and_exceptions.md +80 -0
- package/content/small-business/skills/small-business-ap-processor/reference/payment_run.md +77 -0
- package/content/small-business/skills/small-business-brand-style/SKILL.md +106 -0
- package/content/small-business/skills/small-business-build-agent/SKILL.md +105 -0
- package/content/small-business/skills/small-business-build-agent/reference/capture.md +133 -0
- package/content/small-business/skills/small-business-build-agent/reference/gotchas.md +204 -0
- package/content/small-business/skills/small-business-build-agent/reference/skill_authoring.md +165 -0
- package/content/small-business/skills/small-business-build-connector/SKILL.md +102 -0
- package/content/small-business/skills/small-business-build-connector/reference/discovery.md +120 -0
- package/content/small-business/skills/small-business-build-connector/reference/gotchas.md +237 -0
- package/content/small-business/skills/small-business-build-connector/reference/paths.md +106 -0
- package/content/small-business/skills/small-business-build-connector/reference/use-zapier.md +128 -0
- package/content/small-business/skills/small-business-business-pulse/SKILL.md +181 -0
- package/content/small-business/skills/small-business-business-pulse/reference/data_sources.md +173 -0
- package/content/small-business/skills/small-business-business-pulse/reference/gotchas.md +103 -0
- package/content/small-business/skills/small-business-business-pulse/reference/output_template.md +109 -0
- package/content/small-business/skills/small-business-business-pulse/reference/thresholds.md +71 -0
- package/content/small-business/skills/small-business-business-pulse/reference/v2_sources.md +63 -0
- package/content/small-business/skills/small-business-call-list/SKILL.md +82 -0
- package/content/small-business/skills/small-business-canva-creator/SKILL.md +448 -0
- package/content/small-business/skills/small-business-canva-creator/reference/canva-api.md +208 -0
- package/content/small-business/skills/small-business-canva-creator/reference/examples/boutique-brief-campaign.md +181 -0
- package/content/small-business/skills/small-business-canva-creator/reference/gotchas.md +380 -0
- package/content/small-business/skills/small-business-canva-creator/reference/hubspot-staging.md +137 -0
- package/content/small-business/skills/small-business-cash-flow-snapshot/SKILL.md +251 -0
- package/content/small-business/skills/small-business-cash-flow-snapshot/reference/examples/worked-example.md +92 -0
- package/content/small-business/skills/small-business-cash-flow-snapshot/reference/gotchas.md +62 -0
- package/content/small-business/skills/small-business-cash-flow-snapshot/reference/v2_sources.md +84 -0
- package/content/small-business/skills/small-business-close-month/SKILL.md +86 -0
- package/content/small-business/skills/small-business-content-strategy/SKILL.md +152 -0
- package/content/small-business/skills/small-business-content-strategy/reference/examples/retail-boutique-example.md +71 -0
- package/content/small-business/skills/small-business-content-strategy/reference/gotchas.md +104 -0
- package/content/small-business/skills/small-business-content-strategy/reference/v2_sources.md +40 -0
- package/content/small-business/skills/small-business-contract-review/SKILL.md +158 -0
- package/content/small-business/skills/small-business-contract-review/reference/docusign-fetch.md +32 -0
- package/content/small-business/skills/small-business-contract-review/reference/examples/flagged-summary-saas.md +97 -0
- package/content/small-business/skills/small-business-contract-review/reference/gmail-fetch.md +30 -0
- package/content/small-business/skills/small-business-contract-review/reference/gotchas.md +105 -0
- package/content/small-business/skills/small-business-contract-review/reference/m365-fetch.md +60 -0
- package/content/small-business/skills/small-business-crm-autopilot/SKILL.md +162 -0
- package/content/small-business/skills/small-business-crm-autopilot/reference/cleanup-checklist.md +82 -0
- package/content/small-business/skills/small-business-crm-autopilot/reference/examples/cleanup-deal.md +83 -0
- package/content/small-business/skills/small-business-crm-autopilot/reference/examples/log-call-happy-path.md +68 -0
- package/content/small-business/skills/small-business-crm-autopilot/reference/examples/log-email-happy-path.md +50 -0
- package/content/small-business/skills/small-business-crm-autopilot/reference/gotchas.md +110 -0
- package/content/small-business/skills/small-business-crm-autopilot/reference/hubspot-fields.md +62 -0
- package/content/small-business/skills/small-business-crm-autopilot/reference/lightweight_crm.md +125 -0
- package/content/small-business/skills/small-business-crm-autopilot/reference/salesforce-fields.md +122 -0
- package/content/small-business/skills/small-business-crm-autopilot/reference/standing_mode.md +144 -0
- package/content/small-business/skills/small-business-grant-rfp-writer/SKILL.md +162 -0
- package/content/small-business/skills/small-business-grant-rfp-writer/reference/drafting.md +129 -0
- package/content/small-business/skills/small-business-grant-rfp-writer/reference/go_no_go.md +125 -0
- package/content/small-business/skills/small-business-grant-rfp-writer/reference/gotchas.md +180 -0
- package/content/small-business/skills/small-business-grant-rfp-writer/reference/opportunity_sources.md +90 -0
- package/content/small-business/skills/small-business-grant-rfp-writer/reference/org_profile.md +81 -0
- package/content/small-business/skills/small-business-grow-pipeline/SKILL.md +92 -0
- package/content/small-business/skills/small-business-growth-pulse/SKILL.md +143 -0
- package/content/small-business/skills/small-business-growth-pulse/reference/data_sources.md +113 -0
- package/content/small-business/skills/small-business-growth-pulse/reference/gotchas.md +175 -0
- package/content/small-business/skills/small-business-growth-pulse/reference/output_template.md +122 -0
- package/content/small-business/skills/small-business-growth-pulse/reference/thresholds.md +110 -0
- package/content/small-business/skills/small-business-hiring-screener/SKILL.md +137 -0
- package/content/small-business/skills/small-business-hiring-screener/reference/candidate_comms.md +132 -0
- package/content/small-business/skills/small-business-hiring-screener/reference/fair_screening.md +103 -0
- package/content/small-business/skills/small-business-hiring-screener/reference/gotchas.md +183 -0
- package/content/small-business/skills/small-business-hiring-screener/reference/onboarding.md +82 -0
- package/content/small-business/skills/small-business-hiring-screener/reference/rubric.md +122 -0
- package/content/small-business/skills/small-business-inbox-manager/SKILL.md +130 -0
- package/content/small-business/skills/small-business-inbox-manager/reference/digest_format.md +110 -0
- package/content/small-business/skills/small-business-inbox-manager/reference/gotchas.md +220 -0
- package/content/small-business/skills/small-business-inbox-manager/reference/handoffs.md +77 -0
- package/content/small-business/skills/small-business-inbox-manager/reference/reply_drafting.md +116 -0
- package/content/small-business/skills/small-business-inbox-manager/reference/triage_rules.md +72 -0
- package/content/small-business/skills/small-business-inventory-planner/SKILL.md +126 -0
- package/content/small-business/skills/small-business-inventory-planner/reference/data_sources.md +94 -0
- package/content/small-business/skills/small-business-inventory-planner/reference/gotchas.md +153 -0
- package/content/small-business/skills/small-business-inventory-planner/reference/po_drafting.md +92 -0
- package/content/small-business/skills/small-business-inventory-planner/reference/seasonality.md +112 -0
- package/content/small-business/skills/small-business-inventory-planner/reference/velocity_and_reorder.md +154 -0
- package/content/small-business/skills/small-business-invoice-chase/SKILL.md +131 -0
- package/content/small-business/skills/small-business-invoice-chase/reference/examples/firm-reminder.md +28 -0
- package/content/small-business/skills/small-business-invoice-chase/reference/examples/gentle-reminder.md +27 -0
- package/content/small-business/skills/small-business-invoice-chase/reference/gotchas.md +75 -0
- package/content/small-business/skills/small-business-invoice-chase/reference/tone-matching.md +44 -0
- package/content/small-business/skills/small-business-invoice-chase/reference/v2_sources.md +78 -0
- package/content/small-business/skills/small-business-job-post-builder/SKILL.md +204 -0
- package/content/small-business/skills/small-business-job-post-builder/reference/docusign-routing.md +63 -0
- package/content/small-business/skills/small-business-job-post-builder/reference/examples/worked-example.md +110 -0
- package/content/small-business/skills/small-business-job-post-builder/reference/existing-document-merge.md +58 -0
- package/content/small-business/skills/small-business-job-post-builder/reference/gotchas.md +68 -0
- package/content/small-business/skills/small-business-job-post-builder/reference/interview-guide-structure.md +93 -0
- package/content/small-business/skills/small-business-job-post-builder/reference/job-post-structure.md +62 -0
- package/content/small-business/skills/small-business-job-post-builder/reference/offer-letter-template.md +145 -0
- package/content/small-business/skills/small-business-job-post-builder/reference/role-intake.md +73 -0
- package/content/small-business/skills/small-business-lead-finder/SKILL.md +119 -0
- package/content/small-business/skills/small-business-lead-finder/reference/gotchas.md +152 -0
- package/content/small-business/skills/small-business-lead-finder/reference/icp_method.md +97 -0
- package/content/small-business/skills/small-business-lead-finder/reference/output_template.md +124 -0
- package/content/small-business/skills/small-business-lead-finder/reference/scoring.md +92 -0
- package/content/small-business/skills/small-business-lead-finder/reference/sourcing.md +78 -0
- package/content/small-business/skills/small-business-lead-triage/SKILL.md +81 -0
- package/content/small-business/skills/small-business-lead-triage/reference/examples/happy-path-triage.md +68 -0
- package/content/small-business/skills/small-business-lead-triage/reference/gotchas.md +76 -0
- package/content/small-business/skills/small-business-lead-triage/reference/hubspot-scoring.md +169 -0
- package/content/small-business/skills/small-business-marketing-monday/SKILL.md +108 -0
- package/content/small-business/skills/small-business-monday-brief/SKILL.md +97 -0
- package/content/small-business/skills/small-business-month-end-prep/SKILL.md +331 -0
- package/content/small-business/skills/small-business-month-end-prep/reference/close-packet-format.md +127 -0
- package/content/small-business/skills/small-business-month-end-prep/reference/examples/pl-narrative.md +52 -0
- package/content/small-business/skills/small-business-month-end-prep/reference/gotchas.md +113 -0
- package/content/small-business/skills/small-business-month-end-prep/reference/paypal-settlements.md +110 -0
- package/content/small-business/skills/small-business-month-end-prep/reference/quickbooks-reconcile.md +71 -0
- package/content/small-business/skills/small-business-month-end-prep/reference/v2_sources.md +125 -0
- package/content/small-business/skills/small-business-month-end-prep/reference/xero-reconcile.md +175 -0
- package/content/small-business/skills/small-business-month-end-prep/reference/zoho-books-reconcile.md +168 -0
- package/content/small-business/skills/small-business-outreach-composer/SKILL.md +144 -0
- package/content/small-business/skills/small-business-outreach-composer/reference/gotchas.md +213 -0
- package/content/small-business/skills/small-business-outreach-composer/reference/output_template.md +147 -0
- package/content/small-business/skills/small-business-outreach-composer/reference/sequence_patterns.md +99 -0
- package/content/small-business/skills/small-business-outreach-composer/reference/slop_test.md +164 -0
- package/content/small-business/skills/small-business-pay-the-bills/SKILL.md +101 -0
- package/content/small-business/skills/small-business-payroll-prep/SKILL.md +139 -0
- package/content/small-business/skills/small-business-payroll-prep/reference/anomaly_rules.md +99 -0
- package/content/small-business/skills/small-business-payroll-prep/reference/books_sync.md +72 -0
- package/content/small-business/skills/small-business-payroll-prep/reference/gotchas.md +153 -0
- package/content/small-business/skills/small-business-payroll-prep/reference/run_sheet_format.md +90 -0
- package/content/small-business/skills/small-business-payroll-prep/reference/timesheet_intake.md +118 -0
- package/content/small-business/skills/small-business-plan-payroll/SKILL.md +88 -0
- package/content/small-business/skills/small-business-proposal-builder/SKILL.md +168 -0
- package/content/small-business/skills/small-business-proposal-builder/reference/discovery_extraction.md +138 -0
- package/content/small-business/skills/small-business-proposal-builder/reference/gotchas.md +184 -0
- package/content/small-business/skills/small-business-proposal-builder/reference/output_template.md +128 -0
- package/content/small-business/skills/small-business-proposal-builder/reference/pricing_method.md +125 -0
- package/content/small-business/skills/small-business-proposal-builder/reference/proposal_structure.md +120 -0
- package/content/small-business/skills/small-business-reactivate/SKILL.md +109 -0
- package/content/small-business/skills/small-business-report-builder/SKILL.md +142 -0
- package/content/small-business/skills/small-business-report-builder/reference/data_sources.md +168 -0
- package/content/small-business/skills/small-business-report-builder/reference/gotchas.md +155 -0
- package/content/small-business/skills/small-business-report-builder/reference/output_template.md +109 -0
- package/content/small-business/skills/small-business-report-builder/reference/report_spec.md +109 -0
- package/content/small-business/skills/small-business-report-builder/reference/saved_reports.md +50 -0
- package/content/small-business/skills/small-business-report-pack/SKILL.md +83 -0
- package/content/small-business/skills/small-business-restock/SKILL.md +88 -0
- package/content/small-business/skills/small-business-review-reputation/SKILL.md +130 -0
- package/content/small-business/skills/small-business-review-reputation/reference/churn-signals.md +110 -0
- package/content/small-business/skills/small-business-review-reputation/reference/examples/example-report.md +150 -0
- package/content/small-business/skills/small-business-review-reputation/reference/gotchas.md +164 -0
- package/content/small-business/skills/small-business-review-reputation/reference/response-patterns.md +123 -0
- package/content/small-business/skills/small-business-review-reputation/reference/sources.md +116 -0
- package/content/small-business/skills/small-business-seo-ai-visibility/SKILL.md +143 -0
- package/content/small-business/skills/small-business-seo-ai-visibility/reference/ai_visibility.md +173 -0
- package/content/small-business/skills/small-business-seo-ai-visibility/reference/audit_checklist.md +134 -0
- package/content/small-business/skills/small-business-seo-ai-visibility/reference/catalog_refresh.md +126 -0
- package/content/small-business/skills/small-business-seo-ai-visibility/reference/content_rewrite.md +113 -0
- package/content/small-business/skills/small-business-seo-ai-visibility/reference/gotchas.md +211 -0
- package/content/small-business/skills/small-business-smb-onboard/SKILL.md +82 -0
- package/content/small-business/skills/small-business-smb-onboard/reference/examples/happy-path.md +190 -0
- package/content/small-business/skills/small-business-smb-onboard/reference/gotchas.md +111 -0
- package/content/small-business/skills/small-business-smb-onboard/reference/onboard-checklist.md +99 -0
- package/content/small-business/skills/small-business-smb-onboard/reference/website-research.md +82 -0
- package/content/small-business/skills/small-business-smb-router/SKILL.md +216 -0
- package/content/small-business/skills/small-business-smb-router/reference/connector-map.md +96 -0
- package/content/small-business/skills/small-business-social-content-engine/SKILL.md +162 -0
- package/content/small-business/skills/small-business-social-content-engine/reference/calendar.md +116 -0
- package/content/small-business/skills/small-business-social-content-engine/reference/canva-api.md +208 -0
- package/content/small-business/skills/small-business-social-content-engine/reference/examples/okonkwo-campaign.md +190 -0
- package/content/small-business/skills/small-business-social-content-engine/reference/gotchas.md +447 -0
- package/content/small-business/skills/small-business-social-content-engine/reference/publishing.md +166 -0
- package/content/small-business/skills/small-business-social-content-engine/reference/shopify-assets.md +77 -0
- package/content/small-business/skills/small-business-speed-to-lead/SKILL.md +172 -0
- package/content/small-business/skills/small-business-speed-to-lead/reference/approval.md +61 -0
- package/content/small-business/skills/small-business-speed-to-lead/reference/gotchas.md +167 -0
- package/content/small-business/skills/small-business-speed-to-lead/reference/qualification.md +153 -0
- package/content/small-business/skills/small-business-speed-to-lead/reference/response_patterns.md +184 -0
- package/content/small-business/skills/small-business-tax-prep/SKILL.md +85 -0
- package/content/small-business/skills/small-business-tax-season-organizer/SKILL.md +210 -0
- package/content/small-business/skills/small-business-tax-season-organizer/reference/calculation-assumptions.md +177 -0
- package/content/small-business/skills/small-business-tax-season-organizer/reference/connector-queries.md +267 -0
- package/content/small-business/skills/small-business-tax-season-organizer/reference/examples/quarterly-estimate.md +92 -0
- package/content/small-business/skills/small-business-tax-season-organizer/reference/examples/year-end-1099.md +102 -0
- package/content/small-business/skills/small-business-tax-season-organizer/reference/gotchas.md +104 -0
- package/content/small-business/skills/small-business-tax-season-organizer/reference/output-formats.md +68 -0
- package/content/small-business/skills/small-business-ticket-deflector/SKILL.md +164 -0
- package/content/small-business/skills/small-business-ticket-deflector/reference/examples/deny-refund-request.md +98 -0
- package/content/small-business/skills/small-business-ticket-deflector/reference/examples/respond-refund-request.md +77 -0
- package/content/small-business/skills/small-business-ticket-deflector/reference/gotchas.md +57 -0
- package/index.ts +84 -0
- package/package.json +30 -3
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Quality Control Analysis for Single-Cell RNA-seq Data
|
|
4
|
+
Following scverse best practices from:
|
|
5
|
+
https://www.sc-best-practices.org/preprocessing_visualization/quality_control.html
|
|
6
|
+
|
|
7
|
+
This is a convenience script that runs a complete QC workflow using the
|
|
8
|
+
modular functions from qc_core.py and qc_plotting.py.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import anndata as ad
|
|
12
|
+
import scanpy as sc
|
|
13
|
+
import sys
|
|
14
|
+
import os
|
|
15
|
+
import argparse
|
|
16
|
+
|
|
17
|
+
# Import our modular utilities
|
|
18
|
+
from qc_core import (
|
|
19
|
+
calculate_qc_metrics,
|
|
20
|
+
detect_outliers_mad,
|
|
21
|
+
apply_hard_threshold,
|
|
22
|
+
filter_cells,
|
|
23
|
+
filter_genes,
|
|
24
|
+
print_qc_summary
|
|
25
|
+
)
|
|
26
|
+
from qc_plotting import (
|
|
27
|
+
plot_qc_distributions,
|
|
28
|
+
plot_filtering_thresholds,
|
|
29
|
+
plot_qc_after_filtering
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
print("=" * 80)
|
|
33
|
+
print("Single-Cell RNA-seq Quality Control Analysis")
|
|
34
|
+
print("=" * 80)
|
|
35
|
+
|
|
36
|
+
# Default parameters (single source of truth)
|
|
37
|
+
DEFAULT_MAD_COUNTS = 5
|
|
38
|
+
DEFAULT_MAD_GENES = 5
|
|
39
|
+
DEFAULT_MAD_MT = 3
|
|
40
|
+
DEFAULT_MT_THRESHOLD = 8
|
|
41
|
+
DEFAULT_MIN_CELLS = 20
|
|
42
|
+
DEFAULT_MT_PATTERN = 'mt-,MT-'
|
|
43
|
+
DEFAULT_RIBO_PATTERN = 'Rpl,Rps,RPL,RPS'
|
|
44
|
+
DEFAULT_HB_PATTERN = '^Hb[^(p)]|^HB[^(P)]'
|
|
45
|
+
|
|
46
|
+
# Parse command-line arguments
|
|
47
|
+
parser = argparse.ArgumentParser(
|
|
48
|
+
description='Quality Control Analysis for Single-Cell RNA-seq Data',
|
|
49
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
50
|
+
epilog="""
|
|
51
|
+
Examples:
|
|
52
|
+
python3 qc_analysis.py data.h5ad
|
|
53
|
+
python3 qc_analysis.py raw_feature_bc_matrix.h5
|
|
54
|
+
python3 qc_analysis.py data.h5ad --mad-counts 4 --mad-genes 4 --mad-mt 2.5
|
|
55
|
+
python3 qc_analysis.py data.h5ad --mt-threshold 10 --min-cells 10
|
|
56
|
+
python3 qc_analysis.py data.h5ad --mt-pattern "^mt-" --ribo-pattern "^Rpl,^Rps"
|
|
57
|
+
"""
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
parser.add_argument('input_file', help='Input .h5ad or .h5 file (10X Genomics format)')
|
|
61
|
+
parser.add_argument('--output-dir', type=str, help='Output directory (default: <input_basename>_qc_results)')
|
|
62
|
+
parser.add_argument('--mad-counts', type=float, default=DEFAULT_MAD_COUNTS, help=f'MAD threshold for total counts (default: {DEFAULT_MAD_COUNTS})')
|
|
63
|
+
parser.add_argument('--mad-genes', type=float, default=DEFAULT_MAD_GENES, help=f'MAD threshold for gene counts (default: {DEFAULT_MAD_GENES})')
|
|
64
|
+
parser.add_argument('--mad-mt', type=float, default=DEFAULT_MAD_MT, help=f'MAD threshold for mitochondrial percentage (default: {DEFAULT_MAD_MT})')
|
|
65
|
+
parser.add_argument('--mt-threshold', type=float, default=DEFAULT_MT_THRESHOLD, help=f'Hard threshold for mitochondrial percentage (default: {DEFAULT_MT_THRESHOLD})')
|
|
66
|
+
parser.add_argument('--min-cells', type=int, default=DEFAULT_MIN_CELLS, help=f'Minimum cells for gene filtering (default: {DEFAULT_MIN_CELLS})')
|
|
67
|
+
parser.add_argument('--mt-pattern', type=str, default=DEFAULT_MT_PATTERN, help=f'Comma-separated mitochondrial gene prefixes (default: "{DEFAULT_MT_PATTERN}")')
|
|
68
|
+
parser.add_argument('--ribo-pattern', type=str, default=DEFAULT_RIBO_PATTERN, help=f'Comma-separated ribosomal gene prefixes (default: "{DEFAULT_RIBO_PATTERN}")')
|
|
69
|
+
parser.add_argument('--hb-pattern', type=str, default=DEFAULT_HB_PATTERN, help=f'Hemoglobin gene regex pattern (default: "{DEFAULT_HB_PATTERN}")')
|
|
70
|
+
|
|
71
|
+
args = parser.parse_args()
|
|
72
|
+
|
|
73
|
+
# Verify input file exists
|
|
74
|
+
if not os.path.exists(args.input_file):
|
|
75
|
+
print(f"\nError: File '{args.input_file}' not found!")
|
|
76
|
+
sys.exit(1)
|
|
77
|
+
|
|
78
|
+
input_file = args.input_file
|
|
79
|
+
base_name = os.path.splitext(os.path.basename(input_file))[0]
|
|
80
|
+
|
|
81
|
+
# Set up output directory
|
|
82
|
+
if args.output_dir:
|
|
83
|
+
output_dir = args.output_dir
|
|
84
|
+
else:
|
|
85
|
+
output_dir = f"{base_name}_qc_results"
|
|
86
|
+
|
|
87
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
88
|
+
print(f"\nOutput directory: {output_dir}")
|
|
89
|
+
|
|
90
|
+
# Display parameters
|
|
91
|
+
print(f"\nParameters:")
|
|
92
|
+
print(f" MAD thresholds: counts={args.mad_counts}, genes={args.mad_genes}, MT%={args.mad_mt}")
|
|
93
|
+
print(f" MT hard threshold: {args.mt_threshold}%")
|
|
94
|
+
print(f" Min cells for gene filtering: {args.min_cells}")
|
|
95
|
+
print(f" Gene patterns: MT={args.mt_pattern}, Ribo={args.ribo_pattern}")
|
|
96
|
+
|
|
97
|
+
# Load the data
|
|
98
|
+
print("\n[1/5] Loading data...")
|
|
99
|
+
file_ext = os.path.splitext(input_file)[1].lower()
|
|
100
|
+
|
|
101
|
+
if file_ext == '.h5ad':
|
|
102
|
+
adata = ad.read_h5ad(input_file)
|
|
103
|
+
print(f"Loaded .h5ad file: {adata.n_obs} cells × {adata.n_vars} genes")
|
|
104
|
+
elif file_ext == '.h5':
|
|
105
|
+
adata = sc.read_10x_h5(input_file)
|
|
106
|
+
print(f"Loaded 10X .h5 file: {adata.n_obs} cells × {adata.n_vars} genes")
|
|
107
|
+
# Make variable names unique (10X data sometimes has duplicate gene names)
|
|
108
|
+
adata.var_names_make_unique()
|
|
109
|
+
else:
|
|
110
|
+
print(f"\nError: Unsupported file format '{file_ext}'. Expected .h5ad or .h5")
|
|
111
|
+
sys.exit(1)
|
|
112
|
+
|
|
113
|
+
# Store original counts for comparison
|
|
114
|
+
n_cells_original = adata.n_obs
|
|
115
|
+
n_genes_original = adata.n_vars
|
|
116
|
+
|
|
117
|
+
# Calculate QC metrics
|
|
118
|
+
print("\n[2/5] Calculating QC metrics...")
|
|
119
|
+
calculate_qc_metrics(adata, mt_pattern=args.mt_pattern,
|
|
120
|
+
ribo_pattern=args.ribo_pattern,
|
|
121
|
+
hb_pattern=args.hb_pattern,
|
|
122
|
+
inplace=True)
|
|
123
|
+
|
|
124
|
+
print(f" Found {adata.var['mt'].sum()} mitochondrial genes (pattern: {args.mt_pattern})")
|
|
125
|
+
print(f" Found {adata.var['ribo'].sum()} ribosomal genes (pattern: {args.ribo_pattern})")
|
|
126
|
+
print(f" Found {adata.var['hb'].sum()} hemoglobin genes (pattern: {args.hb_pattern})")
|
|
127
|
+
|
|
128
|
+
print_qc_summary(adata, label='QC Metrics Summary (before filtering)')
|
|
129
|
+
|
|
130
|
+
# Create before-filtering visualizations
|
|
131
|
+
print("\n[3/5] Creating QC visualizations...")
|
|
132
|
+
before_plot = os.path.join(output_dir, 'qc_metrics_before_filtering.png')
|
|
133
|
+
plot_qc_distributions(adata, before_plot, title='Quality Control Metrics - Before Filtering')
|
|
134
|
+
print(f" Saved: {before_plot}")
|
|
135
|
+
|
|
136
|
+
# Apply MAD-based filtering
|
|
137
|
+
print("\n[4/5] Applying MAD-based filtering thresholds...")
|
|
138
|
+
|
|
139
|
+
# Detect outliers for each metric
|
|
140
|
+
adata.obs['outlier_counts'] = detect_outliers_mad(adata, 'total_counts', args.mad_counts)
|
|
141
|
+
adata.obs['outlier_genes'] = detect_outliers_mad(adata, 'n_genes_by_counts', args.mad_genes)
|
|
142
|
+
adata.obs['outlier_mt'] = detect_outliers_mad(adata, 'pct_counts_mt', args.mad_mt)
|
|
143
|
+
|
|
144
|
+
# Apply hard threshold for mitochondrial content
|
|
145
|
+
print(f"\n Applying hard threshold for mitochondrial content (>{args.mt_threshold}%):")
|
|
146
|
+
high_mt_mask = apply_hard_threshold(adata, 'pct_counts_mt', args.mt_threshold, operator='>')
|
|
147
|
+
|
|
148
|
+
# Combine MT filters (MAD + hard threshold)
|
|
149
|
+
adata.obs['outlier_mt'] = adata.obs['outlier_mt'] | high_mt_mask
|
|
150
|
+
|
|
151
|
+
# Overall filtering decision
|
|
152
|
+
adata.obs['pass_qc'] = ~(
|
|
153
|
+
adata.obs['outlier_counts'] |
|
|
154
|
+
adata.obs['outlier_genes'] |
|
|
155
|
+
adata.obs['outlier_mt']
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
print(f"\n Total cells failing QC: {(~adata.obs['pass_qc']).sum()} ({(~adata.obs['pass_qc']).sum()/adata.n_obs*100:.2f}%)")
|
|
159
|
+
print(f" Cells passing QC: {adata.obs['pass_qc'].sum()} ({adata.obs['pass_qc'].sum()/adata.n_obs*100:.2f}%)")
|
|
160
|
+
|
|
161
|
+
# Visualize filtering thresholds
|
|
162
|
+
outlier_masks = {
|
|
163
|
+
'total_counts': adata.obs['outlier_counts'].values,
|
|
164
|
+
'n_genes_by_counts': adata.obs['outlier_genes'].values,
|
|
165
|
+
'pct_counts_mt': adata.obs['outlier_mt'].values
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
thresholds = {
|
|
169
|
+
'total_counts': {'n_mads': args.mad_counts},
|
|
170
|
+
'n_genes_by_counts': {'n_mads': args.mad_genes},
|
|
171
|
+
'pct_counts_mt': {'n_mads': args.mad_mt, 'hard': args.mt_threshold}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
threshold_plot = os.path.join(output_dir, 'qc_filtering_thresholds.png')
|
|
175
|
+
plot_filtering_thresholds(adata, outlier_masks, thresholds, threshold_plot)
|
|
176
|
+
print(f"\n Saved: {threshold_plot}")
|
|
177
|
+
|
|
178
|
+
# Apply filtering
|
|
179
|
+
print("\n[5/5] Applying filters...")
|
|
180
|
+
adata_filtered = filter_cells(adata, adata.obs['pass_qc'].values, inplace=False)
|
|
181
|
+
print(f" Cells after filtering: {adata_filtered.n_obs} (removed {n_cells_original - adata_filtered.n_obs})")
|
|
182
|
+
|
|
183
|
+
# Filter genes
|
|
184
|
+
print(f"\n Filtering genes detected in <{args.min_cells} cells...")
|
|
185
|
+
filter_genes(adata_filtered, min_cells=args.min_cells, inplace=True)
|
|
186
|
+
print(f" Genes after filtering: {adata_filtered.n_vars} (removed {n_genes_original - adata_filtered.n_vars})")
|
|
187
|
+
|
|
188
|
+
# Generate summary statistics
|
|
189
|
+
print("\n" + "=" * 80)
|
|
190
|
+
print("QC Summary")
|
|
191
|
+
print("=" * 80)
|
|
192
|
+
|
|
193
|
+
print("\nBefore filtering:")
|
|
194
|
+
print(f" Cells: {n_cells_original}")
|
|
195
|
+
print(f" Genes: {n_genes_original}")
|
|
196
|
+
|
|
197
|
+
print("\nAfter filtering:")
|
|
198
|
+
print(f" Cells: {adata_filtered.n_obs} ({adata_filtered.n_obs/n_cells_original*100:.1f}% retained)")
|
|
199
|
+
print(f" Genes: {adata_filtered.n_vars} ({adata_filtered.n_vars/n_genes_original*100:.1f}% retained)")
|
|
200
|
+
|
|
201
|
+
print_qc_summary(adata_filtered, label='\nFiltered data QC metrics')
|
|
202
|
+
|
|
203
|
+
# Create after-filtering visualizations
|
|
204
|
+
after_plot = os.path.join(output_dir, 'qc_metrics_after_filtering.png')
|
|
205
|
+
plot_qc_after_filtering(adata_filtered, after_plot)
|
|
206
|
+
print(f"\n Saved: {after_plot}")
|
|
207
|
+
|
|
208
|
+
# Save filtered data
|
|
209
|
+
print("\nSaving filtered data...")
|
|
210
|
+
output_filtered = os.path.join(output_dir, f'{base_name}_filtered.h5ad')
|
|
211
|
+
output_with_qc = os.path.join(output_dir, f'{base_name}_with_qc.h5ad')
|
|
212
|
+
adata_filtered.write(output_filtered)
|
|
213
|
+
print(f" Saved: {output_filtered}")
|
|
214
|
+
|
|
215
|
+
# Also save the unfiltered data with QC annotations
|
|
216
|
+
adata.write(output_with_qc)
|
|
217
|
+
print(f" Saved: {output_with_qc} (original data with QC annotations)")
|
|
218
|
+
|
|
219
|
+
print("\n" + "=" * 80)
|
|
220
|
+
print("Quality Control Analysis Complete!")
|
|
221
|
+
print("=" * 80)
|
|
222
|
+
print(f"\nAll results saved to: {output_dir}/")
|
|
223
|
+
print("\nGenerated files:")
|
|
224
|
+
print(" 1. qc_metrics_before_filtering.png - Initial QC visualizations")
|
|
225
|
+
print(" 2. qc_filtering_thresholds.png - MAD-based threshold visualization")
|
|
226
|
+
print(" 3. qc_metrics_after_filtering.png - Post-filtering QC visualizations")
|
|
227
|
+
print(f" 4. {base_name}_filtered.h5ad - Filtered dataset")
|
|
228
|
+
print(f" 5. {base_name}_with_qc.h5ad - Original dataset with QC annotations")
|
|
229
|
+
print("\nNext steps:")
|
|
230
|
+
print(" - Consider ambient RNA correction (SoupX)")
|
|
231
|
+
print(" - Consider doublet detection (scDblFinder)")
|
|
232
|
+
print(" - Proceed with normalization and downstream analysis")
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Core utility functions for single-cell RNA-seq quality control.
|
|
4
|
+
|
|
5
|
+
This module provides building blocks for metrics calculation and filtering
|
|
6
|
+
while following scverse best practices from:
|
|
7
|
+
https://www.sc-best-practices.org/preprocessing_visualization/quality_control.html
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import anndata as ad
|
|
11
|
+
import scanpy as sc
|
|
12
|
+
import numpy as np
|
|
13
|
+
from scipy.stats import median_abs_deviation
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def calculate_qc_metrics(adata, mt_pattern='mt-,MT-', ribo_pattern='Rpl,Rps,RPL,RPS',
|
|
17
|
+
hb_pattern='^Hb[^(p)]|^HB[^(P)]', inplace=True):
|
|
18
|
+
"""
|
|
19
|
+
Calculate QC metrics for single-cell RNA-seq data.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
adata : AnnData
|
|
24
|
+
Annotated data matrix
|
|
25
|
+
mt_pattern : str
|
|
26
|
+
Comma-separated mitochondrial gene prefixes (default: 'mt-,MT-')
|
|
27
|
+
ribo_pattern : str
|
|
28
|
+
Comma-separated ribosomal gene prefixes (default: 'Rpl,Rps,RPL,RPS')
|
|
29
|
+
hb_pattern : str
|
|
30
|
+
Regex pattern for hemoglobin genes (default: '^Hb[^(p)]|^HB[^(P)]')
|
|
31
|
+
inplace : bool
|
|
32
|
+
Modify adata in place (default: True)
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
AnnData or None
|
|
37
|
+
If inplace=False, returns modified AnnData. Otherwise modifies in place.
|
|
38
|
+
"""
|
|
39
|
+
if not inplace:
|
|
40
|
+
adata = adata.copy()
|
|
41
|
+
|
|
42
|
+
# Identify gene categories
|
|
43
|
+
mt_prefixes = tuple(mt_pattern.split(','))
|
|
44
|
+
adata.var['mt'] = adata.var_names.str.startswith(mt_prefixes)
|
|
45
|
+
|
|
46
|
+
ribo_prefixes = tuple(ribo_pattern.split(','))
|
|
47
|
+
adata.var['ribo'] = adata.var_names.str.startswith(ribo_prefixes)
|
|
48
|
+
|
|
49
|
+
adata.var['hb'] = adata.var_names.str.match(hb_pattern)
|
|
50
|
+
|
|
51
|
+
# Calculate QC metrics
|
|
52
|
+
sc.pp.calculate_qc_metrics(
|
|
53
|
+
adata,
|
|
54
|
+
qc_vars=['mt', 'ribo', 'hb'],
|
|
55
|
+
percent_top=None,
|
|
56
|
+
log1p=False,
|
|
57
|
+
inplace=True
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if not inplace:
|
|
61
|
+
return adata
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def detect_outliers_mad(adata, metric, n_mads, verbose=True):
|
|
65
|
+
"""
|
|
66
|
+
Detect outliers using Median Absolute Deviation (MAD).
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
adata : AnnData
|
|
71
|
+
Annotated data matrix with QC metrics
|
|
72
|
+
metric : str
|
|
73
|
+
Column name in adata.obs to use for outlier detection
|
|
74
|
+
n_mads : float
|
|
75
|
+
Number of MADs to use as threshold
|
|
76
|
+
verbose : bool
|
|
77
|
+
Print outlier statistics (default: True)
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
np.ndarray
|
|
82
|
+
Boolean mask where True indicates outliers
|
|
83
|
+
"""
|
|
84
|
+
metric_values = adata.obs[metric]
|
|
85
|
+
median = np.median(metric_values)
|
|
86
|
+
mad = median_abs_deviation(metric_values)
|
|
87
|
+
|
|
88
|
+
# Calculate bounds
|
|
89
|
+
lower = median - n_mads * mad
|
|
90
|
+
upper = median + n_mads * mad
|
|
91
|
+
|
|
92
|
+
# Identify outliers
|
|
93
|
+
outlier_mask = (metric_values < lower) | (metric_values > upper)
|
|
94
|
+
|
|
95
|
+
if verbose:
|
|
96
|
+
print(f" {metric}:")
|
|
97
|
+
print(f" Median: {median:.2f}, MAD: {mad:.2f}")
|
|
98
|
+
print(f" Bounds: [{lower:.2f}, {upper:.2f}] ({n_mads} MADs)")
|
|
99
|
+
print(f" Outliers: {outlier_mask.sum()} cells ({outlier_mask.sum()/len(metric_values)*100:.2f}%)")
|
|
100
|
+
|
|
101
|
+
return outlier_mask
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def apply_hard_threshold(adata, metric, threshold, operator='>', verbose=True):
|
|
105
|
+
"""
|
|
106
|
+
Apply a hard threshold filter.
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
adata : AnnData
|
|
111
|
+
Annotated data matrix
|
|
112
|
+
metric : str
|
|
113
|
+
Column name in adata.obs to filter on
|
|
114
|
+
threshold : float
|
|
115
|
+
Threshold value
|
|
116
|
+
operator : str
|
|
117
|
+
Comparison operator: '>', '<', '>=', '<=' (default: '>')
|
|
118
|
+
verbose : bool
|
|
119
|
+
Print filtering statistics (default: True)
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
np.ndarray
|
|
124
|
+
Boolean mask where True indicates cells to filter out
|
|
125
|
+
"""
|
|
126
|
+
metric_values = adata.obs[metric]
|
|
127
|
+
|
|
128
|
+
if operator == '>':
|
|
129
|
+
mask = metric_values > threshold
|
|
130
|
+
elif operator == '<':
|
|
131
|
+
mask = metric_values < threshold
|
|
132
|
+
elif operator == '>=':
|
|
133
|
+
mask = metric_values >= threshold
|
|
134
|
+
elif operator == '<=':
|
|
135
|
+
mask = metric_values <= threshold
|
|
136
|
+
else:
|
|
137
|
+
raise ValueError(f"Invalid operator: {operator}. Use '>', '<', '>=', or '<='")
|
|
138
|
+
|
|
139
|
+
if verbose:
|
|
140
|
+
print(f" {metric} {operator} {threshold}:")
|
|
141
|
+
print(f" Cells filtered: {mask.sum()} ({mask.sum()/len(metric_values)*100:.2f}%)")
|
|
142
|
+
|
|
143
|
+
return mask
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def filter_cells(adata, mask, inplace=False):
|
|
147
|
+
"""
|
|
148
|
+
Filter cells based on a boolean mask.
|
|
149
|
+
|
|
150
|
+
Parameters
|
|
151
|
+
----------
|
|
152
|
+
adata : AnnData
|
|
153
|
+
Annotated data matrix
|
|
154
|
+
mask : np.ndarray or pd.Series
|
|
155
|
+
Boolean mask where True indicates cells to KEEP
|
|
156
|
+
inplace : bool
|
|
157
|
+
Modify adata in place (default: False)
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
-------
|
|
161
|
+
AnnData
|
|
162
|
+
Filtered AnnData object
|
|
163
|
+
"""
|
|
164
|
+
if inplace:
|
|
165
|
+
# This is actually a bit tricky - AnnData doesn't support true inplace filtering
|
|
166
|
+
# Return filtered copy which caller should reassign
|
|
167
|
+
return adata[mask].copy()
|
|
168
|
+
else:
|
|
169
|
+
return adata[mask].copy()
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def filter_genes(adata, min_cells=20, min_counts=None, inplace=True):
|
|
173
|
+
"""
|
|
174
|
+
Filter genes based on detection thresholds.
|
|
175
|
+
|
|
176
|
+
Parameters
|
|
177
|
+
----------
|
|
178
|
+
adata : AnnData
|
|
179
|
+
Annotated data matrix
|
|
180
|
+
min_cells : int
|
|
181
|
+
Minimum number of cells a gene must be detected in (default: 20)
|
|
182
|
+
min_counts : int, optional
|
|
183
|
+
Minimum total counts across all cells
|
|
184
|
+
inplace : bool
|
|
185
|
+
Modify adata in place (default: True)
|
|
186
|
+
|
|
187
|
+
Returns
|
|
188
|
+
-------
|
|
189
|
+
AnnData or None
|
|
190
|
+
If inplace=False, returns filtered AnnData
|
|
191
|
+
"""
|
|
192
|
+
if not inplace:
|
|
193
|
+
adata = adata.copy()
|
|
194
|
+
|
|
195
|
+
if min_cells is not None:
|
|
196
|
+
sc.pp.filter_genes(adata, min_cells=min_cells)
|
|
197
|
+
|
|
198
|
+
if min_counts is not None:
|
|
199
|
+
sc.pp.filter_genes(adata, min_counts=min_counts)
|
|
200
|
+
|
|
201
|
+
if not inplace:
|
|
202
|
+
return adata
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def print_qc_summary(adata, label=''):
|
|
206
|
+
"""
|
|
207
|
+
Print summary statistics for QC metrics.
|
|
208
|
+
|
|
209
|
+
Parameters
|
|
210
|
+
----------
|
|
211
|
+
adata : AnnData
|
|
212
|
+
Annotated data matrix with QC metrics
|
|
213
|
+
label : str
|
|
214
|
+
Label to prepend to output (e.g., 'Before filtering', 'After filtering')
|
|
215
|
+
"""
|
|
216
|
+
if label:
|
|
217
|
+
print(f"\n{label}:")
|
|
218
|
+
print(f" Cells: {adata.n_obs}")
|
|
219
|
+
print(f" Genes: {adata.n_vars}")
|
|
220
|
+
|
|
221
|
+
if 'total_counts' in adata.obs:
|
|
222
|
+
print(f" Mean counts per cell: {adata.obs['total_counts'].mean():.0f}")
|
|
223
|
+
print(f" Median counts per cell: {adata.obs['total_counts'].median():.0f}")
|
|
224
|
+
|
|
225
|
+
if 'n_genes_by_counts' in adata.obs:
|
|
226
|
+
print(f" Mean genes per cell: {adata.obs['n_genes_by_counts'].mean():.0f}")
|
|
227
|
+
print(f" Median genes per cell: {adata.obs['n_genes_by_counts'].median():.0f}")
|
|
228
|
+
|
|
229
|
+
if 'pct_counts_mt' in adata.obs:
|
|
230
|
+
print(f" Mean mitochondrial %: {adata.obs['pct_counts_mt'].mean():.2f}%")
|
|
231
|
+
|
|
232
|
+
if 'pct_counts_ribo' in adata.obs:
|
|
233
|
+
print(f" Mean ribosomal %: {adata.obs['pct_counts_ribo'].mean():.2f}%")
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Visualization functions for single-cell RNA-seq quality control.
|
|
4
|
+
|
|
5
|
+
This module provides plotting utilities for QC metrics and filtering thresholds.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
from scipy.stats import median_abs_deviation
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def plot_qc_distributions(adata, output_path, title='Quality Control Metrics'):
|
|
14
|
+
"""
|
|
15
|
+
Create comprehensive QC distribution plots.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
adata : AnnData
|
|
20
|
+
Annotated data matrix with QC metrics
|
|
21
|
+
output_path : str
|
|
22
|
+
Path to save the figure
|
|
23
|
+
title : str
|
|
24
|
+
Figure title (default: 'Quality Control Metrics')
|
|
25
|
+
"""
|
|
26
|
+
fig, axes = plt.subplots(3, 3, figsize=(15, 12))
|
|
27
|
+
fig.suptitle(title, fontsize=16, y=0.995)
|
|
28
|
+
|
|
29
|
+
# Row 1: Histograms
|
|
30
|
+
axes[0, 0].hist(adata.obs['total_counts'], bins=100, color='steelblue', edgecolor='black')
|
|
31
|
+
axes[0, 0].set_xlabel('Total counts per cell')
|
|
32
|
+
axes[0, 0].set_ylabel('Number of cells')
|
|
33
|
+
axes[0, 0].set_title('Distribution of Total Counts')
|
|
34
|
+
axes[0, 0].axvline(adata.obs['total_counts'].median(), color='red', linestyle='--', label='Median')
|
|
35
|
+
axes[0, 0].legend()
|
|
36
|
+
|
|
37
|
+
axes[0, 1].hist(adata.obs['n_genes_by_counts'], bins=100, color='forestgreen', edgecolor='black')
|
|
38
|
+
axes[0, 1].set_xlabel('Genes per cell')
|
|
39
|
+
axes[0, 1].set_ylabel('Number of cells')
|
|
40
|
+
axes[0, 1].set_title('Distribution of Detected Genes')
|
|
41
|
+
axes[0, 1].axvline(adata.obs['n_genes_by_counts'].median(), color='red', linestyle='--', label='Median')
|
|
42
|
+
axes[0, 1].legend()
|
|
43
|
+
|
|
44
|
+
axes[0, 2].hist(adata.obs['pct_counts_mt'], bins=100, color='coral', edgecolor='black')
|
|
45
|
+
axes[0, 2].set_xlabel('Mitochondrial %')
|
|
46
|
+
axes[0, 2].set_ylabel('Number of cells')
|
|
47
|
+
axes[0, 2].set_title('Distribution of Mitochondrial Content')
|
|
48
|
+
axes[0, 2].axvline(adata.obs['pct_counts_mt'].median(), color='red', linestyle='--', label='Median')
|
|
49
|
+
axes[0, 2].legend()
|
|
50
|
+
|
|
51
|
+
# Row 2: Violin plots
|
|
52
|
+
axes[1, 0].violinplot([adata.obs['total_counts']], positions=[0], showmeans=True, showmedians=True)
|
|
53
|
+
axes[1, 0].set_ylabel('Total counts')
|
|
54
|
+
axes[1, 0].set_title('Total Counts per Cell')
|
|
55
|
+
axes[1, 0].set_xticks([])
|
|
56
|
+
|
|
57
|
+
axes[1, 1].violinplot([adata.obs['n_genes_by_counts']], positions=[0], showmeans=True, showmedians=True)
|
|
58
|
+
axes[1, 1].set_ylabel('Genes detected')
|
|
59
|
+
axes[1, 1].set_title('Genes per Cell')
|
|
60
|
+
axes[1, 1].set_xticks([])
|
|
61
|
+
|
|
62
|
+
axes[1, 2].violinplot([adata.obs['pct_counts_mt']], positions=[0], showmeans=True, showmedians=True)
|
|
63
|
+
axes[1, 2].set_ylabel('Mitochondrial %')
|
|
64
|
+
axes[1, 2].set_title('Mitochondrial Content')
|
|
65
|
+
axes[1, 2].set_xticks([])
|
|
66
|
+
|
|
67
|
+
# Row 3: Scatter plots
|
|
68
|
+
scatter1 = axes[2, 0].scatter(
|
|
69
|
+
adata.obs['total_counts'],
|
|
70
|
+
adata.obs['n_genes_by_counts'],
|
|
71
|
+
c=adata.obs['pct_counts_mt'],
|
|
72
|
+
cmap='viridis',
|
|
73
|
+
alpha=0.5,
|
|
74
|
+
s=10
|
|
75
|
+
)
|
|
76
|
+
axes[2, 0].set_xlabel('Total counts')
|
|
77
|
+
axes[2, 0].set_ylabel('Genes detected')
|
|
78
|
+
axes[2, 0].set_title('Counts vs Genes (colored by MT%)')
|
|
79
|
+
plt.colorbar(scatter1, ax=axes[2, 0], label='MT %')
|
|
80
|
+
|
|
81
|
+
axes[2, 1].scatter(
|
|
82
|
+
adata.obs['total_counts'],
|
|
83
|
+
adata.obs['pct_counts_mt'],
|
|
84
|
+
alpha=0.5,
|
|
85
|
+
s=10,
|
|
86
|
+
color='coral'
|
|
87
|
+
)
|
|
88
|
+
axes[2, 1].set_xlabel('Total counts')
|
|
89
|
+
axes[2, 1].set_ylabel('Mitochondrial %')
|
|
90
|
+
axes[2, 1].set_title('Total Counts vs Mitochondrial %')
|
|
91
|
+
|
|
92
|
+
axes[2, 2].scatter(
|
|
93
|
+
adata.obs['n_genes_by_counts'],
|
|
94
|
+
adata.obs['pct_counts_mt'],
|
|
95
|
+
alpha=0.5,
|
|
96
|
+
s=10,
|
|
97
|
+
color='forestgreen'
|
|
98
|
+
)
|
|
99
|
+
axes[2, 2].set_xlabel('Genes detected')
|
|
100
|
+
axes[2, 2].set_ylabel('Mitochondrial %')
|
|
101
|
+
axes[2, 2].set_title('Genes vs Mitochondrial %')
|
|
102
|
+
|
|
103
|
+
plt.tight_layout()
|
|
104
|
+
plt.savefig(output_path, dpi=300, bbox_inches='tight')
|
|
105
|
+
plt.close()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def plot_filtering_thresholds(adata, outlier_masks, thresholds, output_path):
|
|
109
|
+
"""
|
|
110
|
+
Visualize filtering thresholds overlaid on distributions.
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
adata : AnnData
|
|
115
|
+
Annotated data matrix with QC metrics
|
|
116
|
+
outlier_masks : dict
|
|
117
|
+
Dictionary mapping metric names to boolean outlier masks
|
|
118
|
+
Example: {'total_counts': mask1, 'n_genes_by_counts': mask2, 'pct_counts_mt': mask3}
|
|
119
|
+
thresholds : dict
|
|
120
|
+
Dictionary with threshold information for each metric
|
|
121
|
+
Example: {'total_counts': {'n_mads': 5}, 'pct_counts_mt': {'n_mads': 3, 'hard': 8}}
|
|
122
|
+
output_path : str
|
|
123
|
+
Path to save the figure
|
|
124
|
+
"""
|
|
125
|
+
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
|
|
126
|
+
fig.suptitle('MAD-Based Filtering Thresholds', fontsize=16)
|
|
127
|
+
|
|
128
|
+
# Helper function to plot with thresholds
|
|
129
|
+
def plot_with_threshold(ax, metric, outlier_mask, n_mads, hard_threshold=None):
|
|
130
|
+
data = adata.obs[metric]
|
|
131
|
+
median = np.median(data)
|
|
132
|
+
mad = median_abs_deviation(data)
|
|
133
|
+
lower = median - n_mads * mad
|
|
134
|
+
upper = median + n_mads * mad
|
|
135
|
+
|
|
136
|
+
ax.hist(data[~outlier_mask], bins=100, alpha=0.7, label='Pass QC', color='steelblue')
|
|
137
|
+
ax.hist(data[outlier_mask], bins=100, alpha=0.7, label='Fail QC', color='coral')
|
|
138
|
+
ax.axvline(lower, color='red', linestyle='--', linewidth=2, label=f'Thresholds ({n_mads} MADs)')
|
|
139
|
+
ax.axvline(upper, color='red', linestyle='--', linewidth=2)
|
|
140
|
+
|
|
141
|
+
if hard_threshold is not None:
|
|
142
|
+
ax.axvline(hard_threshold, color='darkred', linestyle=':', linewidth=2,
|
|
143
|
+
label=f'Hard threshold ({hard_threshold})')
|
|
144
|
+
|
|
145
|
+
ax.set_xlabel(metric.replace('_', ' ').title())
|
|
146
|
+
ax.set_ylabel('Number of cells')
|
|
147
|
+
ax.legend()
|
|
148
|
+
|
|
149
|
+
# Plot each metric
|
|
150
|
+
metrics = [
|
|
151
|
+
('total_counts', 'Total Counts'),
|
|
152
|
+
('n_genes_by_counts', 'Genes Detected'),
|
|
153
|
+
('pct_counts_mt', 'Mitochondrial %')
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
for idx, (metric, label) in enumerate(metrics):
|
|
157
|
+
if metric in outlier_masks and metric in thresholds:
|
|
158
|
+
hard = thresholds[metric].get('hard', None)
|
|
159
|
+
plot_with_threshold(axes[idx], metric, outlier_masks[metric],
|
|
160
|
+
thresholds[metric]['n_mads'], hard)
|
|
161
|
+
|
|
162
|
+
plt.tight_layout()
|
|
163
|
+
plt.savefig(output_path, dpi=300, bbox_inches='tight')
|
|
164
|
+
plt.close()
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def plot_qc_after_filtering(adata, output_path):
|
|
168
|
+
"""
|
|
169
|
+
Create QC plots for filtered data (simplified version without outlier overlay).
|
|
170
|
+
|
|
171
|
+
Parameters
|
|
172
|
+
----------
|
|
173
|
+
adata : AnnData
|
|
174
|
+
Filtered annotated data matrix with QC metrics
|
|
175
|
+
output_path : str
|
|
176
|
+
Path to save the figure
|
|
177
|
+
"""
|
|
178
|
+
fig, axes = plt.subplots(2, 3, figsize=(15, 8))
|
|
179
|
+
fig.suptitle('Quality Control Metrics - After Filtering', fontsize=16, y=0.995)
|
|
180
|
+
|
|
181
|
+
# Row 1: Histograms
|
|
182
|
+
axes[0, 0].hist(adata.obs['total_counts'], bins=100, color='steelblue', edgecolor='black')
|
|
183
|
+
axes[0, 0].set_xlabel('Total counts per cell')
|
|
184
|
+
axes[0, 0].set_ylabel('Number of cells')
|
|
185
|
+
axes[0, 0].set_title('Distribution of Total Counts')
|
|
186
|
+
|
|
187
|
+
axes[0, 1].hist(adata.obs['n_genes_by_counts'], bins=100, color='forestgreen', edgecolor='black')
|
|
188
|
+
axes[0, 1].set_xlabel('Genes per cell')
|
|
189
|
+
axes[0, 1].set_ylabel('Number of cells')
|
|
190
|
+
axes[0, 1].set_title('Distribution of Detected Genes')
|
|
191
|
+
|
|
192
|
+
axes[0, 2].hist(adata.obs['pct_counts_mt'], bins=100, color='coral', edgecolor='black')
|
|
193
|
+
axes[0, 2].set_xlabel('Mitochondrial %')
|
|
194
|
+
axes[0, 2].set_ylabel('Number of cells')
|
|
195
|
+
axes[0, 2].set_title('Distribution of Mitochondrial Content')
|
|
196
|
+
|
|
197
|
+
# Row 2: Scatter plots
|
|
198
|
+
scatter1 = axes[1, 0].scatter(
|
|
199
|
+
adata.obs['total_counts'],
|
|
200
|
+
adata.obs['n_genes_by_counts'],
|
|
201
|
+
c=adata.obs['pct_counts_mt'],
|
|
202
|
+
cmap='viridis',
|
|
203
|
+
alpha=0.5,
|
|
204
|
+
s=10
|
|
205
|
+
)
|
|
206
|
+
axes[1, 0].set_xlabel('Total counts')
|
|
207
|
+
axes[1, 0].set_ylabel('Genes detected')
|
|
208
|
+
axes[1, 0].set_title('Counts vs Genes (colored by MT%)')
|
|
209
|
+
plt.colorbar(scatter1, ax=axes[1, 0], label='MT %')
|
|
210
|
+
|
|
211
|
+
axes[1, 1].scatter(
|
|
212
|
+
adata.obs['total_counts'],
|
|
213
|
+
adata.obs['pct_counts_mt'],
|
|
214
|
+
alpha=0.5,
|
|
215
|
+
s=10,
|
|
216
|
+
color='coral'
|
|
217
|
+
)
|
|
218
|
+
axes[1, 1].set_xlabel('Total counts')
|
|
219
|
+
axes[1, 1].set_ylabel('Mitochondrial %')
|
|
220
|
+
axes[1, 1].set_title('Total Counts vs Mitochondrial %')
|
|
221
|
+
|
|
222
|
+
axes[1, 2].scatter(
|
|
223
|
+
adata.obs['n_genes_by_counts'],
|
|
224
|
+
adata.obs['pct_counts_mt'],
|
|
225
|
+
alpha=0.5,
|
|
226
|
+
s=10,
|
|
227
|
+
color='forestgreen'
|
|
228
|
+
)
|
|
229
|
+
axes[1, 2].set_xlabel('Genes detected')
|
|
230
|
+
axes[1, 2].set_ylabel('Mitochondrial %')
|
|
231
|
+
axes[1, 2].set_title('Genes vs Mitochondrial %')
|
|
232
|
+
|
|
233
|
+
plt.tight_layout()
|
|
234
|
+
plt.savefig(output_path, dpi=300, bbox_inches='tight')
|
|
235
|
+
plt.close()
|