{"id":"3adf8f2d-ecdd-4a51-b706-757dc71cac4d","entityType":"agent","slug":"clawhub-moniq888-sql-dataviz","name":"SQL Dataviz","canonicalUrl":"https://www.xpersona.co/agent/clawhub-moniq888-sql-dataviz","canonicalPath":"/agent/clawhub-moniq888-sql-dataviz","generatedAt":"2026-10-13T06:52:19.121Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T21:34:47.045Z","emptyReason":null},"description":"Convert SQL query results into production-grade visual charts including bar, line, pie, map, KPI, AI insights, and interactive HTML dashboards with base64 PN... Skill: SQL Dataviz Owner: moniq888 Summary: Convert SQL query results into production-grade visual charts including bar, line, pie, map, KPI, AI insights, and interactive HTML dashboards with base64 PN... Tags: latest:1.0.1 Version history: v1.0.1 | 2026-03-27T10:33:33.832Z | user - 修正协作工具名称，将“report-generator”统一为“sql-report-generator”以匹配实际 Skill 名称 - 数据分析流程示意图和协作流程文档细节微调，增强 Skill 协作关系说明 - 文档其余内容未变，功能和接口保持不变 v1.0.0 |","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 990 downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s1774kyr593ezfy7qtq3g4k9t983g3a1:sql-dataviz","sourceUrl":"https://clawhub.ai/moniq888/sql-dataviz","homepage":"https://clawhub.ai/moniq888/skills/sql-dataviz","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/moniq888/sql-dataviz","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/moniq888/skills/sql-dataviz","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":42,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Convert SQL query results into production-grade visual charts including bar, line, pie, map, KPI, AI insights, and interactive HTML dashboards with base64 PN..."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T21:34:47.045Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T21:34:47.045Z","emptyReason":null},"stars":null,"forks":null,"downloads":990,"likes":null,"task":null,"library":null,"packageName":null,"latestVersion":"1.0.1","tractionLabel":"990 downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T21:34:47.045Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T21:34:47.045Z","lastCrawledAt":"2026-10-11T21:34:47.045Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T21:34:47.045Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.1","createdAt":"2026-03-27T10:33:33.832Z","changelog":"- 修正协作工具名称，将“report-generator”统一为“sql-report-generator”以匹配实际 Skill 名称 - 数据分析流程示意图和协作流程文档细节微调，增强 Skill 协作关系说明 - 文档其余内容未变，功能和接口保持不变","fileCount":28,"zipByteSize":106523},{"version":"1.0.0","createdAt":"2026-03-27T05:25:54.253Z","changelog":"SQL Dataviz 1.0.0 - 新增数据可视化智能体 - 支持25+图表类型、6种预设主题 - 支持Plotly交互式HTML图表 - 内置Dashboard构建器，支持响应式布局","fileCount":27,"zipByteSize":105105}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s1774kyr593ezfy7qtq3g4k9t983g3a1:sql-dataviz","setupComplexity":"low","setupSteps":["Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-moniq888-sql-dataviz/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-moniq888-sql-dataviz/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-moniq888-sql-dataviz/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-moniq888-sql-dataviz/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-moniq888-sql-dataviz/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-moniq888-sql-dataviz/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-13T06:52:19.120Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-moniq888-sql-dataviz/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-moniq888-sql-dataviz/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-moniq888-sql-dataviz/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-moniq888-sql-dataviz/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T21:34:47.045Z","emptyReason":null},"readme":"Skill: SQL Dataviz\n\nOwner: moniq888\n\nSummary: Convert SQL query results into production-grade visual charts including bar, line, pie, map, KPI, AI insights, and interactive HTML dashboards with base64 PN...\n\nTags: latest:1.0.1\n\nVersion history:\n\nv1.0.1 | 2026-03-27T10:33:33.832Z | user\n\n- 修正协作工具名称，将“report-generator”统一为“sql-report-generator”以匹配实际 Skill 名称\n- 数据分析流程示意图和协作流程文档细节微调，增强 Skill 协作关系说明\n- 文档其余内容未变，功能和接口保持不变\n\nv1.0.0 | 2026-03-27T05:25:54.253Z | user\n\nSQL Dataviz 1.0.0\n- 新增数据可视化智能体\n- 支持25+图表类型、6种预设主题\n- 支持Plotly交互式HTML图表\n- 内置Dashboard构建器，支持响应式布局\n\nArchive index:\n\nArchive v1.0.1: 28 files, 106523 bytes\n\nFiles: charts/__init__.py (74361b), FINAL_COMPLETION_REPORT.md (5761b), FINAL_REPORT.md (10520b), FULL_MARKET_COMPARISON.md (8949b), IMPLEMENTATION_SUMMARY.md (10896b), PROJECT_CHECKLIST.md (7582b), QUICK_REFERENCE.md (6467b), references/bar-charts.md (4265b), references/canvas-render.md (2849b), references/chart-selection.md (3259b), references/dashboard.md (5213b), references/distribution.md (14610b), references/heatmap.md (21514b), references/INSTALLATION.md (7674b), references/INTEGRATION_GUIDE.md (12125b), references/line-area.md (3989b), references/plotly-interactive.md (4962b), references/scatter.md (17802b), requirements.txt (218b), scripts/demo.py (14273b), scripts/install_deps.sh (2233b), scripts/interactive_charts.py (50631b), skill-card.md (2692b), SKILL.md (19642b), sql-dataviz/SKILL.md (6097b), SUPPLEMENT_CHECKLIST.md (7254b), VERIFICATION_REPORT.md (7686b), _meta.json (130b)\n\nFile v1.0.1:SKILL.md\n\n# sql-dataviz - SQL 数据可视化 Skill\n\n## ⚠️ 使用前必读\n\n本 Skill 需要 Python 依赖。**首次使用前必须安装依赖**：\n\n```bash\nskillhub_install install_skill sql-dataviz\n```\n\n工具会自动检测 Python3 环境、pip 可用性，并安装所有依赖。\n\n### 依赖安装方式\n\n| 方式 | 命令 | 适用场景 |\n|------|------|---------|\n| **自动安装（推荐）** | `skillhub_install install_skill sql-dataviz` | 一键安装，自动处理 |\n| **手动安装** | `pip install -r requirements.txt` | 熟悉 Python 环境的用户 |\n\n### 无依赖使用（受限模式）\n\n如果无法安装依赖，本 Skill 提供以下**降级能力**：\n\n✅ **可用功能**：\n- 图表选型建议（基于业务场景推荐图表类型）\n- 数据格式规范说明\n- 可视化设计原则指导\n- 配色方案推荐\n\n❌ **不可用功能**：\n- 图表生成（PNG/base64 输出）\n- 交互式 HTML 图表\n- Dashboard 构建\n- 与 sql-master / sql-report-generator 联动\n\n---\n\n## 🔗 Skill 协作关系\n\n本 Skill 与 **sql-master**、**sql-report-generator** 组成完整的数据分析流水线：\n\n```\n┌─────────────┐     ┌──────────────┐     ┌────────────────────────┐\n│ sql-master  │ ──► │ sql-dataviz  │ ──► │ sql-report-generator   │\n│  (数据层)   │     │  (可视化层)   │     │  (报告层)               │\n└─────────────┘     └──────────────┘     └────────────────────────┘\n      │                   │                   │\n      ▼                   ▼                   ▼\n   SQL 查询           图表生成            HTML 报告\n   数据获取           PNG/HTML            AI 洞察\n   格式转换           Dashboard           数据表格\n```\n\n### 协作模式\n\n| 模式 | 组合 | 适用场景 |\n|------|------|---------|\n| **单独使用** | sql-dataviz | 已有数据，仅需图表可视化 |\n| **数据可视化** | sql-master + sql-dataviz | SQL 查询 → 图表输出 |\n| **可视化报告** | sql-dataviz + sql-report-generator | 图表 → 报告（无 SQL） |\n| **完整流程** | sql-master + sql-dataviz + sql-report-generator | 完整数据分析报告 |\n\n### 🥇 最优使用方式：三 Skill 串联\n\n```python\nfrom scripts.unified_pipeline import UnifiedPipeline\n\nresult = (\n    UnifiedPipeline(\"销售分析\")\n    .from_file(\"sales.csv\")                                    # sql-master: 数据获取\n    .query(\"SELECT region, SUM(sales) as total FROM data GROUP BY region\")\n    .interactive_chart(\"bar\", x_col=\"region\", y_col=\"total\")   # sql-dataviz: 可视化\n    .insights(value_cols=[\"total\"])                            # AI 洞察\n    .report(title=\"销售报告\", output=\"report.html\")            # sql-report-generator: 报告\n)\n```\n\n### 决策指南\n\n```\n你需要什么？\n├─ 仅图表可视化 → sql-dataviz 单独使用\n├─ SQL + 图表 → sql-master + sql-dataviz\n├─ 图表 + 报告（无 SQL）→ sql-dataviz + sql-report-generator\n└─ 完整分析报告 → sql-master + sql-dataviz + sql-report-generator ✅ 推荐\n```\n\n---\n\n## 新增功能：交互式 HTML 图表（Plotly）\n\n### `scripts/interactive_charts.py`\n\n基于 Plotly 的 12 种交互式图表，输出自包含 HTML（支持 hover / zoom / pan）：\n\n```python\nfrom scripts.interactive_charts import InteractiveChartFactory, DashboardBuilder\n\nfactory = InteractiveChartFactory(theme=\"powerbi\")\n\n# 12 种图表类型\nhtml = factory.create_line(data)          # 折线图\nhtml = factory.create_bar(data)           # 柱形图\nhtml = factory.create_pie(data)           # 饼图（环形）\nhtml = factory.create_scatter(data)       # 散点图\nhtml = factory.create_heatmap(data)       # 热力图\nhtml = factory.create_funnel(data)        # 漏斗图\nhtml = factory.create_area(data)          # 面积图\nhtml = factory.create_treemap(data)       # 树状图\nhtml = factory.create_gauge(data)         # 仪表盘\nhtml = factory.create_combo(data)         # 组合图（柱+折线）\nhtml = factory.create_table(data)         # 交互式表格\nhtml = factory.create_kpi_cards(data)     # KPI 卡片组\n\nfactory.save_html(html, \"chart.html\")\n\n# 多图表 Dashboard\nbuilder = DashboardBuilder(title=\"销售看板\", theme=\"powerbi\")\nbuilder.add_kpi_cards([{\"title\":\"GMV\",\"value\":\"¥1,234万\",\"change\":\"+18%\"}])\nbuilder.add_chart(factory.create_line(...), title=\"月度趋势\", cols=2)\nbuilder.add_chart(factory.create_bar(...), title=\"区域对比\", cols=1)\nbuilder.build(\"dashboard.html\")\n```\n\n**数据格式** 与现有 ChartFactory 完全一致（line/bar/pie/scatter/funnel/area/combo/table）。\n\n**主题**：powerbi / dark / seaborn / ggplot2\n\n## 概述\n\n将 SQL 查询结果转化为**生产级可视化图表**。集成 Power BI 原生的 **50 种视觉对象**，支持对比、趋势、分布、占比、地理、指标监控、AI 智能分析、统计分析等全场景。\n\n所有图表以 **base64 编码的 PNG** 方式输出，可直接嵌入报告、邮件、Web 应用、Markdown 文档。\n\n## 核心能力矩阵\n\n### 1️⃣ 对比与趋势分析（13种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **簇状柱形图** | 多系列分类对比 | `create_clustered_column()` |\n| **堆积柱形图** | 整体+部分占比对比 | `create_stacked_column()` |\n| **100%堆积柱形图** | 统一尺度结构对比 | `create_percent_stacked_column()` |\n| **簇状条形图** | 长分类名称对比 | `create_clustered_bar()` |\n| **堆积条形图** | 区域/渠道层级对比 | `create_stacked_bar()` |\n| **100%堆积条形图** | 横向结构占比 | `create_percent_stacked_bar()` |\n| **折线图** | 连续数据趋势 | `create_line()` |\n| **平滑折线图** | 弱化波动的趋势 | `create_smooth_line()` |\n| **组合图** | 双指标（柱+折线） | `create_combo()` |\n| **面积图** | 累计总量展示 | `create_area()` |\n| **堆积面积图** | 多业务线累计贡献 | `create_stacked_area()` |\n| **瀑布图** | 增减项影响分析 | `create_waterfall()` |\n| **丝带图** | 排名变动追踪 | `create_line()` |\n\n### 2️⃣ 部分与整体（4种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **饼图** | 单维度占比 | `create_pie()` |\n| **圆环图** | 中心标签占比 | `create_donut()` |\n| **树状图** | 层级数据展示 | `create_treemap()` |\n| **漏斗图** | 流程转化分析 | `create_funnel()` |\n\n### 3️⃣ 分布与关系（4种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **散点图** | 两变量相关性 | `create_scatter()` |\n| **气泡图** | 三变量分析 | `create_bubble()` |\n| **点图** | 分类数据分布 | `create_dot()` |\n| **高密度散点图** | 海量数据聚类 | `create_high_density_scatter()` |\n\n### 4️⃣ 地理空间（4种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **Azure 地图** | 权威地图底图 | `create_azure_map()` |\n| **填充地图** | 区域数据热力 | `create_filled_map()` |\n| **形状地图** | 自定义边界分析 | `create_shape_map()` |\n| **ArcGIS 地图** | 专业空间分析 | `create_arcgis_map()` |\n\n### 5️⃣ 指标监控（5种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **卡片图** | 单一关键指标 | `create_card()` |\n| **多行卡片图** | 多指标汇总 | `create_multi_card()` |\n| **KPI 视觉对象** | 目标达成率 | `create_kpi()` |\n| **仪表盘图** | 指标健康度 | `create_gauge()` |\n| **目标视觉对象** | 团队绩效看板 | `create_target()` |\n\n### 6️⃣ AI 智能分析（4种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **分解树** | 多维度根因分析 | `create_decomposition_tree()` |\n| **关键影响因素** | 驱动因子权重 | `create_key_influencers()` |\n| **异常检测** | 自动异常标注 | `create_anomaly_detection()` |\n| **智能叙事** | 自然语言摘要 | `create_smart_narrative()` |\n\n### 7️⃣ 统计与分布（5种）**[新增]**\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **盒须图** | 数据分布四分位数 | `create_box_plot()` |\n| **直方图** | 数据频率分布 | `create_histogram()` |\n| **密度图** | 概率密度分布 | `create_density_plot()` |\n| **帕累托图** | 80/20 法则分析 | `create_pareto()` |\n| **Q-Q 图** | 正态性检验 | 通过 scipy 实现 |\n\n### 8️⃣ 关系与网络（2种）**[新增]**\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **网络图** | 节点关系展示 | `create_network_graph()` |\n| **桑基图** | 流量/能量流向 | `create_sankey()` |\n\n### 9️⃣ 时序与日期（3种）**[新增]**\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **甘特图** | 项目进度管理 | `create_gantt()` |\n| **日历热力图** | 时间序列热力 | `create_calendar_heatmap()` |\n| **蜡烛图** | 股票价格走势 | `create_candlestick()` |\n\n### 🔟 地理与热力（3种）**[新增]**\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **分级地图** | 区域数据热力 | `create_choropleth_map()` |\n| **路径地图** | 物流路径规划 | `create_route_map()` |\n| **点密度地图** | 点分布密度 | `create_dot_density_map()` |\n\n### 1️⃣1️⃣ 层级与占比（3种）**[新增]**\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **旭日图** | 多层级占比 | `create_sunburst()` |\n| **词云图** | 文本频率可视化 | `create_word_cloud()` |\n| **子弹图** | 目标对比 | `create_bullet()` |\n\n### 1️⃣2️⃣ 交互与辅助（4种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **图像视觉对象** | 品牌 logo、产品图片 | `create_image_visual()` |\n| **文本框与形状** | 报表标题、说明描述 | `create_text_shape()` |\n| **小型序列图** | 多个小图表并排 | `create_small_multiple()` |\n| **视觉对象栏** | 自定义布局 | `create_visual_canvas()` |\n\n## 快速开始\n\n### 基础用法\n\n```python\nfrom sql_dataviz.charts import ChartFactory, ChartConfig, Theme\n\n# 1. 创建工厂\nfactory = ChartFactory()\n\n# 2. 设置主题（可选）\nfactory.set_theme('powerbi')  # 或 'alibaba', 'tencent', 'bytedance'\n\n# 3. 准备数据\ndata = {\n    'categories': ['Q1', 'Q2', 'Q3', 'Q4'],\n    'series': [\n        {'name': '销售额', 'data': [100, 150, 120, 200]},\n        {'name': '成本', 'data': [60, 80, 70, 100]}\n    ]\n}\n\n# 4. 生成图表（base64 PNG）\nchart_b64 = factory.create_clustered_column(data)\n\n# 5. 嵌入到 HTML\nhtml = f'<img src=\"data:image/png;base64,{chart_b64}\" />'\n\n# 6. 或保存为文件\nimport base64\nwith open('chart.png', 'wb') as f:\n    f.write(base64.b64decode(chart_b64))\n```\n\n### 与 sql-master 协作\n\n```python\nfrom sql_master import SQLMaster\nfrom sql_dataviz.charts import ChartFactory\n\n# 1. 执行 SQL 查询\nsql_master = SQLMaster()\nresult = sql_master.execute_query(\"\"\"\n    SELECT quarter, SUM(sales) as total, SUM(cost) as cost\n    FROM orders\n    GROUP BY quarter\n    ORDER BY quarter\n\"\"\")\n\n# 2. 转换为图表数据格式\ndata = {\n    'categories': [row['quarter'] for row in result],\n    'series': [\n        {'name': '销售额', 'data': [row['total'] for row in result]},\n        {'name': '成本', 'data': [row['cost'] for row in result]}\n    ]\n}\n\n# 3. 生成可视化\nfactory = ChartFactory()\nchart_b64 = factory.create_clustered_column(data)\n```\n\n### 与 sql-report-generator 协作\n\n```python\nfrom sql_dataviz.charts import ChartFactory\nfrom sql_report_generator import ReportGenerator\n\n# 1. 生成多个图表\nfactory = ChartFactory()\ncharts = {\n    'sales_trend': factory.create_line(trend_data),\n    'channel_mix': factory.create_pie(channel_data),\n    'regional_heatmap': factory.create_filled_map(region_data)\n}\n\n# 2. 组织成报告\nreport = ReportGenerator()\nreport.add_title('月度业绩报告')\nreport.add_chart('销售趋势', charts['sales_trend'])\nreport.add_chart('渠道占比', charts['channel_mix'])\nreport.add_chart('区域热力', charts['regional_heatmap'])\nreport.export_html('report.html')\n```\n\n\n\n## 文件结构\n\n```\nsql-dataviz/\n├── SKILL.md                          # 本文件\n├── charts/\n│   ├── __init__.py                   # 24种图表实现（base64 PNG）\n│   ├── comparison.py                 # 对比类图表（可选扩展）\n│   ├── composition.py                # 占比类图表（可选扩展）\n│   ├── distribution.py               # 分布类图表（可选扩展）\n│   ├── geographic.py                 # 地理类图表（可选扩展）\n│   ├── kpi.py                        # 指标监控（可选扩展）\n│   └── ai_analysis.py                # AI 智能分析（可选扩展）\n├── scripts/\n│   ├── install_deps.sh               # 依赖安装脚本\n│   ├── demo.py                       # 完整演示脚本\n│   └── benchmark.py                  # 性能基准测试\n└── references/\n    ├── POWERBI_CHARTS.md             # Power BI 图表参考\n    ├── COLOR_SCHEMES.md              # 大厂配色方案\n    ├── DATA_FORMATS.md               # 数据格式规范\n    └── EXAMPLES.md                   # 完整示例库\n```\n\n## 配置选项\n\n### 主题与样式\n\n```python\nfrom sql_dataviz.charts import ChartFactory, ChartConfig, Theme\n\n# 方式1：工厂级设置\nfactory = ChartFactory()\nfactory.set_theme('powerbi')      # Power BI 官方蓝\nfactory.set_theme('alibaba')      # 阿里巴巴红\nfactory.set_theme('tencent')      # 腾讯蓝\nfactory.set_theme('bytedance')    # 字节跳动黑\nfactory.set_theme('neutral')      # 中性灰\n\n# 方式2：配置对象\nconfig = ChartConfig(\n    width=1200,\n    height=600,\n    dpi=100,\n    theme=Theme.POWERBI,\n    title='季度业绩分析',\n    show_legend=True,\n    show_grid=True,\n    font_size=11,\n    title_size=16\n)\nfactory = ChartFactory(config)\n```\n\n### 导出格式\n\n```python\n# 所有图表都支持 base64 PNG 输出\nchart_b64 = factory.create_line(data)\n\n# 嵌入 HTML\nhtml = f'<img src=\"data:image/png;base64,{chart_b64}\" />'\n\n# 嵌入 Markdown\nmarkdown = f'![chart](data:image/png;base64,{chart_b64})'\n\n# 保存为文件\nimport base64\nwith open('chart.png', 'wb') as f:\n    f.write(base64.b64decode(chart_b64))\n```\n\n## 常见问题\n\n### Q: 如何处理超大数据集（>100万行）？\n\nA: 使用高密度散点图或自动聚合：\n\n```python\n# 高密度散点图自动处理海量数据\nchart = factory.create_high_density_scatter({\n    'x': large_x_array,  # 100万+ 数据点\n    'y': large_y_array\n})\n\n# 或先聚合数据\nimport pandas as pd\ndf = pd.read_sql(query, conn)\ndf_agg = df.groupby('category').agg({'value': 'sum'}).reset_index()\nchart = factory.create_pie({\n    'labels': df_agg['category'],\n    'values': df_agg['value']\n})\n```\n\n### Q: 支持实时数据更新吗？\n\nA: 支持。通过定时查询 SQL 并重新生成图表：\n\n```python\nimport time\nfrom sql_master import SQLMaster\nfrom sql_dataviz.charts import ChartFactory\n\nsql = SQLMaster()\nfactory = ChartFactory()\n\nwhile True:\n    # 每分钟更新一次\n    result = sql.execute_query(\"SELECT * FROM metrics WHERE time > NOW() - INTERVAL 1 HOUR\")\n    chart = factory.create_line(transform_data(result))\n    save_chart(chart)\n    time.sleep(60)\n```\n\n### Q: 能否自定义图表样式？\n\nA: 完全支持。修改 `ChartConfig` 或直接编辑图表类：\n\n```python\n# 自定义配置\nconfig = ChartConfig(\n    width=1600,\n    height=800,\n    theme=Theme.ALIBABA,\n    font_size=13,\n    title_size=18,\n    show_grid=False\n)\n\n# 或继承图表类进行深度定制\nfrom sql_dataviz.charts import ClusteredColumnChart\n\nclass CustomColumnChart(ClusteredColumnChart):\n    def create(self, data):\n        fig, ax = self._setup_figure()\n        # 自定义绘制逻辑\n        ...\n        return self._to_base64(fig)\n```\n\n### Q: 如何在报告中使用这些图表？\n\nA: 与 sql-report-generator 无缝协作：\n\n```python\nfrom sql_report_generator import ReportGenerator\nfrom sql_dataviz.charts import ChartFactory\n\nreport = ReportGenerator()\nfactory = ChartFactory()\n\n# 添加图表\nreport.add_chart('销售趋势', factory.create_line(data))\nreport.add_chart('渠道占比', factory.create_pie(data))\n\n# 导出为 HTML/PDF\nreport.export_html('report.html')\nreport.export_pdf('report.pdf')\n```\n\n## 性能指标\n\n| 操作 | 耗时 | 内存 |\n|------|------|------|\n| 生成简单柱形图 | ~50ms | ~5MB |\n| 生成复杂仪表盘（4图） | ~200ms | ~20MB |\n| 处理100万数据点散点图 | ~500ms | ~50MB |\n| 生成完整报告（10图） | ~1s | ~100MB |\n\n## 与其他 Skill 的协作\n\n### sql-master → sql-dataviz → sql-report-generator\n\n```\nSQL 查询 → 数据转换 → 可视化 → 报告生成\n```\n\n**完整流程示例：**\n\n```python\n# 1. sql-master：执行查询\nfrom sql_master import SQLMaster\nsql = SQLMaster()\nsales_data = sql.execute_query(\"\"\"\n    SELECT region, product, SUM(sales) as total\n    FROM orders\n    GROUP BY region, product\n\"\"\")\n\n# 2. sql-dataviz：生成可视化\nfrom sql_dataviz.charts import ChartFactory\nfactory = ChartFactory()\nfactory.set_theme('powerbi')\n\n# 按地区对比\nregional_chart = factory.create_clustered_column({\n    'categories': [row['region'] for row in sales_data],\n    'series': [{'name': 'Sales', 'data': [row['total'] for row in sales_data]}]\n})\n\n# 3. sql-report-generator：组织报告\nfrom sql_report_generator import ReportGenerator\nreport = ReportGenerator()\nreport.add_title('销售分析报告')\nreport.add_chart('地区销售对比', regional_chart)\nreport.export_html('sales_report.html')\n```\n\n## 最佳实践\n\n### 1. 选择合适的图表类型\n\n```python\n# ✓ 对比分析 → 簇状柱形图\nfactory.create_clustered_column(data)\n\n# ✓ 趋势分析 → 折线图\nfactory.create_line(data)\n\n# ✓ 占比分析 → 饼图/圆环图\nfactory.create_pie(data)\n\n# ✓ 分布分析 → 散点图/气泡图\nfactory.create_scatter(data)\n\n# ✓ 流程分析 → 漏斗图\nfactory.create_funnel(data)\n```\n\n### 2. 数据预处理\n\n```python\nimport pandas as pd\n\n# 清理数据\ndf = pd.read_sql(query, conn)\ndf = df.dropna()\ndf = df[df['value'] > 0]\n\n# 聚合数据\ndf_agg = df.groupby('category').agg({\n    'value': 'sum',\n    'count': 'count'\n}).reset_index()\n\n# 转换为图表格式\ndata = {\n    'categories': df_agg['category'].tolist(),\n    'series': [{'name': 'Value', 'data': df_agg['value'].tolist()}]\n}\n```\n\n### 3. 缓存机制\n\n```python\nimport hashlib\nimport json\n\ndef get_chart_cached(chart_type, data, cache_dir='./cache'):\n    # 生成缓存键\n    key = hashlib.md5(json.dumps(data).encode()).hexdigest()\n    cache_file = f\"{cache_dir}/{chart_type}_{key}.b64\"\n    \n    # 检查缓存\n    try:\n        with open(cache_file, 'r') as f:\n            return f.read()\n    except FileNotFoundError:\n        pass\n    \n    # 生成新图表\n    factory = ChartFactory()\n    chart = getattr(factory, f'create_{chart_type}')(data)\n    \n    # 保存缓存\n    with open(cache_file, 'w') as f:\n        f.write(chart)\n    \n    return chart\n```\n\n## 许可证\n\nMIT License - 生产级可商用\n\n## 更新日志\n\n- **v1.0.0** (2026-03-26) - 初始版本，支持 24 种图表，base64 PNG 输出\n- **v1.1.0** (计划) - 支持 SVG 矢量输出、交互式 HTML、实时数据流\n- **v2.0.0** (计划) - 集成 Plotly 交互式图表、WebGL 高性能渲染\n\n## 支持与反馈\n\n- 📧 Email: support@example.com\n- 💬 Discord: https://discord.gg/example\n- 🐛 Issues: https://github.com/example/sql-dataviz/issues\ns\n\nFile v1.0.1:sql-dataviz/SKILL.md\n\n# sql-dataviz - SQL 数据可视化 Skill\n\n## 概述\n\n将 SQL 查询结果转化为**生产级可视化图表**。集成 Power BI 原生的 24+ 种视觉对象，支持对比、趋势、分布、占比、地理、指标监控、AI 智能分析等全场景。\n\n所有图表以 **base64 编码的 PNG/SVG** 方式输出，可直接嵌入报告、邮件、Web 应用。\n\n## 核心能力\n\n### 1. 对比与趋势分析（8种）\n- **簇状柱形图** - 多系列分类对比\n- **堆积柱形图** - 整体+部分占比对比\n- **100%堆积柱形图** - 统一尺度结构对比\n- **簇状条形图** - 长分类名称对比\n- **堆积条形图** - 区域/渠道层级对比\n- **100%堆积条形图** - 横向结构占比\n- **折线图** - 连续数据趋势\n- **平滑折线图** - 弱化波动的趋势\n\n### 2. 高级趋势（5种）\n- **组合图** - 双指标（柱+折线）\n- **面积图** - 累计总量展示\n- **堆积面积图** - 多系列累计贡献\n- **瀑布图** - 增减项影响分析\n- **丝带图** - 排名变动追踪\n\n### 3. 部分与整体（4种）\n- **饼图** - 单维度占比\n- **圆环图** - 中心标签占比\n- **树状图** - 层级数据展示\n- **漏斗图** - 流程转化分析\n\n### 4. 分布与关系（4种）\n- **散点图** - 两变量相关性\n- **气泡图** - 三变量分析\n- **点图** - 分类数据分布\n- **高密度散点图** - 海量数据聚类\n\n### 5. 地理空间（3种）\n- **填充地图** - 区域数据热力\n- **形状地图** - 自定义边界分析\n- **ArcGIS 地图** - 专业空间分析\n\n### 6. 指标监控（3种）\n- **卡片图** - 单一关键指标\n- **KPI 视觉对象** - 目标达成率\n- **仪表盘图** - 指标健康度\n\n### 7. AI 智能分析（4种）\n- **分解树** - 多维度根因分析\n- **关键影响因素** - 驱动因子权重\n- **异常检测** - 自动异常标注\n- **智能叙事** - 自然语言摘要\n\n## 使用方式\n\n### 基础用法\n\n```python\nfrom sql_dataviz import ChartFactory\n\n# 创建图表工厂\nfactory = ChartFactory()\n\n# 从 SQL 结果生成图表\ndata = {\n    'categories': ['Q1', 'Q2', 'Q3', 'Q4'],\n    'series': [\n        {'name': '销售额', 'data': [100, 150, 120, 200]},\n        {'name': '成本', 'data': [60, 80, 70, 100]}\n    ]\n}\n\n# 生成簇状柱形图（base64）\nchart_b64 = factory.create_clustered_column(data)\n\n# 输出为 HTML 可嵌入\nhtml = f'<img src=\"data:image/png;base64,{chart_b64}\" />'\n```\n\n### 高级用法 - 组合分析\n\n```python\n# 多图表联动\ndashboard = factory.create_dashboard({\n    'title': '季度业绩分析',\n    'charts': [\n        {'type': 'clustered_column', 'data': sales_data, 'position': (0, 0)},\n        {'type': 'pie', 'data': channel_data, 'position': (1, 0)},\n        {'type': 'line', 'data': trend_data, 'position': (0, 1)},\n        {'type': 'heatmap', 'data': region_data, 'position': (1, 1)}\n    ]\n})\n```\n\n## 依赖安装\n\n### 自动安装（推荐）\n\n```bash\n# 使用 SkillHub 一键安装\nskillhub_install install_skill sql-dataviz\n```\n\n### 手动安装\n\n```bash\n# 1. 安装 Python 依赖\npip install matplotlib seaborn plotly pandas numpy\n\n# 2. 安装可选的地理数据库\npip install geopandas shapely\n\n# 3. 验证安装\npython -c \"import matplotlib; print(matplotlib.__version__)\"\n```\n\n## 文件结构\n\n```\nsql-dataviz/\n├── SKILL.md                          # 本文件\n├── charts/\n│   ├── __init__.py\n│   ├── comparison.py                 # 对比类图表\n│   ├── trend.py                      # 趋势类图表\n│   ├── composition.py                # 占比类图表\n│   ├── distribution.py               # 分布类图表\n│   ├── geographic.py                 # 地理类图表\n│   ├── kpi.py                        # 指标监控\n│   ├── ai_analysis.py                # AI 智能分析\n│   └── base.py                       # 基类与工具函数\n├── scripts/\n│   ├── install_deps.sh               # 依赖安装脚本\n│   └── demo.py                       # 演示脚本\n└── references/\n    ├── POWERBI_CHARTS.md             # Power BI 图表参考\n    └── COLOR_SCHEMES.md              # 大厂配色方案\n```\n\n## 配置选项\n\n### 主题与样式\n\n```python\n# 内置主题\nfactory.set_theme('powerbi')      # Power BI 官方配色\nfactory.set_theme('alibaba')      # 阿里巴巴配色\nfactory.set_theme('tencent')      # 腾讯配色\nfactory.set_theme('bytedance')    # 字节跳动配色\n```\n\n### 导出格式\n\n```python\n# 支持多种输出格式\nchart_b64 = factory.export_base64()    # Base64 PNG\nchart_svg = factory.export_svg()       # SVG 矢量\nchart_html = factory.export_html()     # 交互式 HTML\n```\n\n## 与其他 Skill 的协作\n\n### 与 sql-master 协作\n\n```python\n# sql-master 提供 SQL 查询结果\nquery_result = sql_master.execute_query(\n    \"SELECT region, SUM(sales) as total FROM orders GROUP BY region\"\n)\n\n# sql-dataviz 进行可视化\nchart = dataviz.create_pie(query_result)\n```\n\n### 与 sql-report-generator 协作\n\n```python\n# sql-dataviz 生成图表\ncharts = dataviz.create_dashboard(data)\n\n# sql-report-generator 组织成报告\nreport = sql_report_generator.create_report({\n    'title': '月度业绩报告',\n    'charts': charts,\n    'tables': tables\n})\n```\n\n## 性能优化\n\n- **大数据集**：自动采样 + 聚合，保留关键信息\n- **缓存机制**：相同查询结果缓存 1 小时\n- **异步渲染**：支持后台生成，前台异步加载\n- **流式输出**：支持分页报表流式生成\n\n## 常见问题\n\n**Q: 如何处理超大数据集（>100万行）？**\nA: 使用高密度散点图或自动聚合功能，系统会智能采样保留关键分布特征。\n\n**Q: 支持实时数据更新吗？**\nA: 支持。通过 WebSocket 连接 SQL 数据源，图表自动刷新。\n\n**Q: 能否自定义图表样式？**\nA: 完全支持。提供 CSS/JSON 配置接口，可自定义颜色、字体、动画等。\n\n## 许可证\n\nMIT License - 生产级可商用\n\n## 更新日志\n\n- **v1.0.0** (2026-03-26) - 初始版本，支持 24+ 种图表\n\nFile v1.0.1:_meta.json\n\n{\n  \"ownerId\": \"kn76k6338wpqydkxgdztg6vb9x83hz20\",\n  \"slug\": \"sql-dataviz\",\n  \"version\": \"1.0.1\",\n  \"publishedAt\": 1774607613832\n}\n\nFile v1.0.1:references/bar-charts.md\n\n# 条形图 & 横向条形图\n\n适用场景：分类比较、排名展示。\n\n---\n\n## 纵向条形图（类别 ≤ 10）\n\n```python\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nfig, ax = plt.subplots(figsize=(10, 6))\n\nbars = ax.bar(df['category'], df['value'],\n              color='#3b82f6', width=0.6, edgecolor='white')\n\n# 柱顶标注数值\nfor bar in bars:\n    h = bar.get_height()\n    ax.text(bar.get_x() + bar.get_width()/2, h + max(df['value'])*0.01,\n            f'{h:,.0f}', ha='center', va='bottom', fontsize=10)\n\nax.set_title('各品类销售额', fontsize=15, fontweight='bold', pad=12)\nax.set_xlabel('品类')\nax.set_ylabel('销售额（万元）')\nax.set_ylim(0, max(df['value']) * 1.15)  # 留出标注空间\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('bar_chart.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 横向条形图（排名 / 类别多 / 名称长）\n\n```python\n# 按值排序，最大值在顶部\ndf_sorted = df.sort_values('value', ascending=True)\n\nfig, ax = plt.subplots(figsize=(10, max(6, len(df_sorted) * 0.4)))\n\n# 高亮 Top 1\ncolors = ['#ef4444' if i == len(df_sorted)-1 else '#3b82f6'\n          for i in range(len(df_sorted))]\n\nbars = ax.barh(df_sorted['name'], df_sorted['value'],\n               color=colors, height=0.6)\n\n# 右侧标注数值\nfor bar in bars:\n    w = bar.get_width()\n    ax.text(w + max(df_sorted['value'])*0.01, bar.get_y() + bar.get_height()/2,\n            f'{w:,.0f}', va='center', fontsize=10)\n\nax.set_title('Top 用户消费排名', fontsize=15, fontweight='bold', pad=12)\nax.set_xlabel('消费金额（元）')\nax.set_xlim(0, max(df_sorted['value']) * 1.12)\nax.grid(axis='x', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('bar_horizontal.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 分组条形图（多系列对比）\n\n```python\n# df 列：month, group_a, group_b, group_c\ncategories = df['month'].tolist()\nx = np.arange(len(categories))\nwidth = 0.25\nPALETTE = ['#3b82f6', '#10b981', '#f59e0b']\n\nfig, ax = plt.subplots(figsize=(12, 6))\n\nfor i, (col, label) in enumerate([('group_a', 'PC端'), ('group_b', '移动端'), ('group_c', '小程序')]):\n    offset = (i - 1) * width\n    bars = ax.bar(x + offset, df[col], width, label=label,\n                  color=PALETTE[i], edgecolor='white')\n\nax.set_xticks(x)\nax.set_xticklabels(categories)\nax.legend()\nax.set_title('各渠道月度订单量对比', fontsize=15, fontweight='bold')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('grouped_bar.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 堆叠条形图（占比构成）\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\nPALETTE = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444']\n\nbottom = np.zeros(len(df))\nfor i, col in enumerate(['cat_a', 'cat_b', 'cat_c', 'cat_d']):\n    ax.bar(df['month'], df[col], bottom=bottom,\n           label=col, color=PALETTE[i], edgecolor='white', linewidth=0.5)\n    bottom += df[col].values\n\nax.legend(loc='upper left')\nax.set_title('各品类月度销售额构成', fontsize=15, fontweight='bold')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('stacked_bar.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 百分比堆叠条形图\n\n```python\n# 先计算百分比\ncols = ['cat_a', 'cat_b', 'cat_c']\ndf_pct = df[cols].div(df[cols].sum(axis=1), axis=0) * 100\n\nfig, ax = plt.subplots(figsize=(12, 6))\nbottom = np.zeros(len(df_pct))\n\nfor i, col in enumerate(cols):\n    ax.bar(df['month'], df_pct[col], bottom=bottom,\n           label=col, color=PALETTE[i], edgecolor='white')\n    bottom += df_pct[col].values\n\nax.set_ylim(0, 100)\nax.set_ylabel('占比（%）')\nax.legend(loc='upper left')\nax.set_title('各品类月度销售额占比', fontsize=15, fontweight='bold')\n\nplt.tight_layout()\nplt.savefig('stacked_pct.png', dpi=150, bbox_inches='tight')\n```\n\nFile v1.0.1:references/canvas-render.md\n\n# Canvas 内嵌渲染\n\n在对话中直接渲染图表，无需保存文件，用户即时看到结果。\n\n---\n\n## 什么时候用 Canvas 渲染\n\n- 用户想在对话里直接看图，不想保存文件\n- 快速验证图表效果\n- 演示/汇报场景，需要即时展示\n\n---\n\n## 使用方式\n\n通过 `canvas` 工具的 `eval` action 执行 JavaScript，渲染 Chart.js 图表。\n\n### 折线图示例\n\n```javascript\n// canvas eval 内容\nconst ctx = document.getElementById('chart').getContext('2d');\nnew Chart(ctx, {\n  type: 'line',\n  data: {\n    labels: ['1月', '2月', '3月', '4月', '5月', '6月'],\n    datasets: [{\n      label: '订单量',\n      data: [1200, 1900, 1500, 2100, 2400, 2800],\n      borderColor: '#3b82f6',\n      backgroundColor: 'rgba(59,130,246,0.1)',\n      borderWidth: 2,\n      fill: true,\n      tension: 0.4,\n      pointRadius: 4\n    }]\n  },\n  options: {\n    responsive: true,\n    plugins: {\n      title: { display: true, text: '月度订单量趋势', font: { size: 16 } },\n      legend: { position: 'top' }\n    },\n    scales: {\n      y: { beginAtZero: true, grid: { color: 'rgba(0,0,0,0.05)' } }\n    }\n  }\n});\n```\n\n### Canvas HTML 模板\n\n```html\n<!DOCTYPE html>\n<html>\n<head>\n  <script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>\n  <style>\n    body { font-family: 'Microsoft YaHei', sans-serif; padding: 20px; background: #fff; }\n    .chart-container { max-width: 800px; margin: 0 auto; }\n  </style>\n</head>\n<body>\n  <div class=\"chart-container\">\n    <canvas id=\"chart\"></canvas>\n  </div>\n  <script>\n    // 在这里放图表代码\n  </script>\n</body>\n</html>\n```\n\n---\n\n## Chart.js 常用图表类型\n\n| type 值 | 图表类型 |\n|---------|---------|\n| `'line'` | 折线图 |\n| `'bar'` | 条形图（纵向） |\n| `'bar'` + `indexAxis: 'y'` | 横向条形图 |\n| `'pie'` | 饼图（慎用） |\n| `'doughnut'` | 环形图 |\n| `'scatter'` | 散点图 |\n| `'bubble'` | 气泡图 |\n| `'radar'` | 雷达图 |\n\n---\n\n## 多系列条形图示例\n\n```javascript\nnew Chart(ctx, {\n  type: 'bar',\n  data: {\n    labels: ['Q1', 'Q2', 'Q3', 'Q4'],\n    datasets: [\n      {\n        label: 'PC端',\n        data: [3200, 4100, 3800, 5200],\n        backgroundColor: '#3b82f6'\n      },\n      {\n        label: '移动端',\n        data: [5100, 6200, 7100, 8900],\n        backgroundColor: '#10b981'\n      }\n    ]\n  },\n  options: {\n    responsive: true,\n    plugins: {\n      title: { display: true, text: '各渠道季度订单量' }\n    },\n    scales: { y: { beginAtZero: true } }\n  }\n});\n```\n\n---\n\n## 注意事项\n\n- Canvas 渲染依赖网络加载 Chart.js CDN，离线环境需本地引入\n- 数据量大时（>1000 点），建议先聚合再渲染，避免卡顿\n- 中文字体在 Canvas 中需要系统已安装对应字体\n- 复杂统计图（箱线图、小提琴图）建议用 Python matplotlib 生成图片，再展示\n\nFile v1.0.1:references/chart-selection.md\n\n# 图表选型决策指南\n\n## 核心问题：你想表达什么？\n\n拿到数据后，先问自己这个问题，再选图表。\n\n---\n\n## 决策树\n\n```\n数据是什么关系？\n│\n├── 随时间变化？\n│   ├── 连续时间序列 → 折线图\n│   ├── 离散时间点比较 → 分组条形图\n│   └── 累计/占比随时间变化 → 堆叠面积图\n│\n├── 分类之间比较？\n│   ├── 类别 ≤ 10 → 纵向条形图\n│   ├── 类别 > 10 或名称较长 → 横向条形图\n│   ├── 多组对比 → 分组条形图\n│   └── 排名展示 → 横向条形图（降序）\n│\n├── 整体中各部分占比？\n│   ├── 类别 ≤ 5 → 堆叠条形图（推荐）或饼图\n│   ├── 类别 > 5 → 矩形树图（Treemap）\n│   └── 占比随时间变化 → 堆叠面积图（百分比）\n│\n├── 数值分布？\n│   ├── 单变量分布 → 直方图\n│   ├── 多组分布对比 → 箱线图 / 小提琴图\n│   └── 密度估计 → KDE 图\n│\n├── 两变量关系？\n│   ├── 相关性探索 → 散点图\n│   ├── 带趋势线 → 回归散点图\n│   └── 多变量相关矩阵 → 热力图\n│\n├── 地理分布？\n│   └── 地图（Choropleth / 气泡地图）\n│\n├── 流向/转化？\n│   ├── 用户转化漏斗 → 漏斗图\n│   └── 流量流向 → 桑基图（Sankey）\n│\n└── 单一关键指标？\n    └── 大数字 KPI 卡片（不需要图表）\n```\n\n---\n\n## 常见场景速查\n\n| 业务场景 | 推荐图表 | 示例 |\n|---------|---------|------|\n| 日/周/月销售趋势 | 折线图 | 近 30 天 GMV |\n| 各品类销售额对比 | 横向条形图 | Top 10 品类 |\n| 用户地区分布 | 横向条形图 / 地图 | 各省用户数 |\n| 订单金额分布 | 直方图 | 0-100/100-500/500+ |\n| 各渠道转化率对比 | 分组条形图 | PC vs 移动端 |\n| 用户留存率 | 热力图（Cohort） | 按注册周分组 |\n| 指标相关性 | 热力图 | 价格/销量/评分 |\n| 漏斗转化 | 漏斗图 | 曝光→点击→购买 |\n| 月度环比增长 | 折线图 + 柱状图组合 | 销售额 + 增长率 |\n| 市场份额 | 堆叠条形图 | 各品牌占比 |\n\n---\n\n## 反模式（常见错误）\n\n### ❌ 饼图滥用\n```\n错误：用饼图展示 10 个品类的销售占比\n原因：人眼无法准确比较扇形大小\n正确：横向条形图，按值排序\n```\n\n### ❌ 双 Y 轴滥用\n```\n错误：左轴销售额（万元），右轴增长率（%），两条线看起来相关\n原因：双 Y 轴可以通过调整比例制造任意\"相关性\"\n正确：分两张图，或用散点图展示真实相关性\n```\n\n### ❌ 截断 Y 轴\n```\n错误：条形图 Y 轴从 95 开始，让微小差异看起来很大\n原因：视觉误导\n正确：Y 轴从 0 开始；如果确实需要放大差异，用折线图并明确标注\n```\n\n### ❌ 3D 图表\n```\n错误：3D 饼图、3D 条形图\n原因：透视变形导致读值不准\n正确：永远用 2D\n```\n\n### ❌ 彩虹配色\n```\n错误：每个柱子用不同颜色，没有语义\n原因：颜色应该传达信息，不是装饰\n正确：同类数据用同色；用颜色高亮重点数据\n```\n\nFile v1.0.1:references/dashboard.md\n\n# 多图面板 / Dashboard\n\n适用场景：需要在一张图里展示多个维度，或生成完整的数据报告。\n\n---\n\n## matplotlib 多图面板\n\n```python\nimport matplotlib.pyplot as plt\nimport matplotlib.gridspec as gridspec\nimport seaborn as sns\nimport pandas as pd\nimport numpy as np\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nfig = plt.figure(figsize=(16, 10))\nfig.suptitle('业务数据周报', fontsize=20, fontweight='bold', y=0.98)\n\n# 使用 GridSpec 灵活布局\ngs = gridspec.GridSpec(2, 3, figure=fig, hspace=0.4, wspace=0.35)\n\n# ── 左上（跨2列）：趋势折线图 ──\nax1 = fig.add_subplot(gs[0, :2])\nax1.plot(df_trend['date'], df_trend['orders'], color='#3b82f6', linewidth=2)\nax1.fill_between(df_trend['date'], df_trend['orders'], alpha=0.1, color='#3b82f6')\nax1.set_title('近30天订单量趋势', fontweight='bold')\nax1.grid(axis='y', alpha=0.3)\nax1.spines['top'].set_visible(False)\nax1.spines['right'].set_visible(False)\nax1.tick_params(axis='x', rotation=45)\n\n# ── 右上：KPI 卡片 ──\nax2 = fig.add_subplot(gs[0, 2])\nax2.axis('off')\nkpis = [\n    ('总订单量', '12,450', '+8.3%', '#10b981'),\n    ('总营收', '¥234万', '+12.1%', '#10b981'),\n    ('客单价', '¥188', '-2.4%', '#ef4444'),\n]\nfor i, (label, value, change, color) in enumerate(kpis):\n    y_pos = 0.85 - i * 0.3\n    ax2.text(0.1, y_pos, label, fontsize=10, color='#6b7280', transform=ax2.transAxes)\n    ax2.text(0.1, y_pos - 0.1, value, fontsize=18, fontweight='bold', transform=ax2.transAxes)\n    ax2.text(0.7, y_pos - 0.1, change, fontsize=12, color=color, transform=ax2.transAxes)\nax2.set_title('核心指标', fontweight='bold')\n\n# ── 左下：品类条形图 ──\nax3 = fig.add_subplot(gs[1, 0])\ndf_cat_sorted = df_cat.sort_values('value', ascending=True)\nax3.barh(df_cat_sorted['name'], df_cat_sorted['value'], color='#3b82f6', height=0.6)\nax3.set_title('品类销售额 Top 5', fontweight='bold')\nax3.spines['top'].set_visible(False)\nax3.spines['right'].set_visible(False)\n\n# ── 中下：金额分布直方图 ──\nax4 = fig.add_subplot(gs[1, 1])\nax4.hist(df_orders['amount'], bins=20, color='#f59e0b', edgecolor='white')\nax4.set_title('订单金额分布', fontweight='bold')\nax4.set_xlabel('金额（元）')\nax4.spines['top'].set_visible(False)\nax4.spines['right'].set_visible(False)\n\n# ── 右下：渠道占比堆叠 ──\nax5 = fig.add_subplot(gs[1, 2])\nbottom = np.zeros(len(df_channel))\nfor col, color in zip(['pc', 'mobile', 'mini'], ['#3b82f6', '#10b981', '#f59e0b']):\n    ax5.bar(df_channel['month'], df_channel[col], bottom=bottom,\n            label=col, color=color, edgecolor='white')\n    bottom += df_channel[col].values\nax5.legend(fontsize=8)\nax5.set_title('渠道构成', fontweight='bold')\nax5.spines['top'].set_visible(False)\nax5.spines['right'].set_visible(False)\n\nplt.savefig('weekly_report.png', dpi=150, bbox_inches='tight')\nprint(\"报告已保存：weekly_report.png\")\n```\n\n---\n\n## 自动化报告生成（SQL → 图表 → PDF）\n\n```python\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom matplotlib.backends.backend_pdf import PdfPages\nimport sqlite3\nfrom datetime import datetime\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nconn = sqlite3.connect('mydb.sqlite')\n\n# 查询数据\ndf_trend = pd.read_sql(\"\"\"\n    SELECT DATE(created_at) as date, COUNT(*) as orders, SUM(amount) as revenue\n    FROM orders WHERE created_at >= DATE('now', '-30 days')\n    GROUP BY DATE(created_at) ORDER BY date\n\"\"\", conn)\n\ndf_cat = pd.read_sql(\"\"\"\n    SELECT category, SUM(amount) as revenue\n    FROM orders WHERE created_at >= DATE('now', '-30 days')\n    GROUP BY category ORDER BY revenue DESC LIMIT 10\n\"\"\", conn)\n\nconn.close()\n\n# 生成 PDF 报告\nwith PdfPages(f'report_{datetime.now().strftime(\"%Y%m%d\")}.pdf') as pdf:\n\n    # 第1页：趋势\n    fig, ax = plt.subplots(figsize=(12, 5))\n    ax.plot(pd.to_datetime(df_trend['date']), df_trend['revenue'],\n            color='#3b82f6', linewidth=2)\n    ax.set_title('近30天营收趋势', fontsize=14, fontweight='bold')\n    ax.grid(axis='y', alpha=0.3)\n    plt.tight_layout()\n    pdf.savefig(fig)\n    plt.close()\n\n    # 第2页：品类排名\n    fig, ax = plt.subplots(figsize=(10, 7))\n    df_sorted = df_cat.sort_values('revenue', ascending=True)\n    ax.barh(df_sorted['category'], df_sorted['revenue'], color='#10b981')\n    ax.set_title('品类营收排名', fontsize=14, fontweight='bold')\n    plt.tight_layout()\n    pdf.savefig(fig)\n    plt.close()\n\n    # PDF 元数据\n    d = pdf.infodict()\n    d['Title'] = '业务数据报告'\n    d['Author'] = 'SQL DataViz'\n    d['CreationDate'] = datetime.now()\n\nprint(f\"PDF 报告已生成：report_{datetime.now().strftime('%Y%m%d')}.pdf\")\n```\n\n---\n\n## 布局建议\n\n| 图表数量 | 推荐布局 | figsize |\n|---------|---------|---------|\n| 2 张 | 1×2 或 2×1 | (14, 5) 或 (8, 10) |\n| 4 张 | 2×2 | (14, 10) |\n| 6 张 | 2×3 或 3×2 | (16, 10) |\n| 混合（大+小） | GridSpec 自定义 | 按需 |\n\n**原则：** 最重要的图放左上角（视线自然落点），KPI 卡片放右上角，细节图放下方。\n\nFile v1.0.1:references/distribution.md\n\n# 分布图 — 直方图、箱线图、小提琴图、密度图\n\n适用场景：展示数值分布、识别异常值、多组分布对比。\n\n---\n\n## 核心问题：你想展示什么样的分布？\n\n| 问题 | 推荐图表 |\n|------|---------|\n| 单变量分布频率？ | 直方图 |\n| 中位数、四分位、异常值？ | 箱线图 |\n| 分布形状 + 密度？ | 小提琴图 / KDE |\n| 多组分布对比？ | 箱线图 / 小提琴图 |\n| 分布是否正态？ | 直方图 + KDE + QQ图 |\n\n---\n\n## 一、直方图（Histogram）\n\n### 基础直方图\n\n```python\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nfig, ax = plt.subplots(figsize=(10, 6))\n\n# 自动 bins 或指定\nn, bins, patches = ax.hist(df['value'], bins=30,\n                           color='#3b82f6', edgecolor='white', alpha=0.8)\n\nax.set_title('订单金额分布', fontsize=15, fontweight='bold', pad=12)\nax.set_xlabel('金额（元）')\nax.set_ylabel('频数')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('histogram.png', dpi=150, bbox_inches='tight')\n```\n\n### Bins 数量选择\n\n```python\n# 方法1：Sturges 公式（适合正态分布）\nbins_sturges = int(np.log2(len(df)) + 1)\n\n# 方法2：Freedman-Diaconis 公式（适合偏态分布，推荐）\nq75, q25 = np.percentile(df['value'], [75, 25])\niqr = q75 - q25\nbin_width = 2 * iqr / (len(df) ** (1/3))\nbins_fd = int((df['value'].max() - df['value'].min()) / bin_width)\n\n# 方法3：Square root（简单快速）\nbins_sqrt = int(np.sqrt(len(df)))\n\nprint(f\"Sturges: {bins_sturges}, FD: {bins_fd}, Sqrt: {bins_sqrt}\")\n```\n\n**生产级建议：**\n- 数据量 < 100：bins = 10~15\n- 数据量 100~10000：使用 FD 公式\n- 数据量 > 10000：bins = 50~100，或使用 KDE\n\n### 直方图 + KDE（密度曲线）\n\n```python\nimport seaborn as sns\n\nfig, ax = plt.subplots(figsize=(10, 6))\n\n# 直方图（密度归一化）\nsns.histplot(df['value'], bins=30, kde=True,\n             color='#3b82f6', edgecolor='white', alpha=0.6, ax=ax)\n\nax.set_title('用户年龄分布（含密度曲线）', fontsize=15, fontweight='bold')\nax.set_xlabel('年龄')\nax.set_ylabel('密度')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('hist_kde.png', dpi=150, bbox_inches='tight')\n```\n\n### 分组直方图对比\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\n# 多组数据叠加\nsns.histplot(data=df, x='value', hue='group',\n             bins=30, alpha=0.5, edgecolor='white', ax=ax)\n\nax.set_title('不同渠道订单金额分布对比', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('hist_grouped.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 二、箱线图（Box Plot）\n\n### 标准箱线图\n\n```python\nfig, ax = plt.subplots(figsize=(10, 6))\n\nbp = ax.boxplot(df['value'],\n                patch_artist=True,\n                widths=0.5,\n                showfliers=True,  # 显示异常值\n                flierprops=dict(marker='o', markerfacecolor='#ef4444',\n                               markersize=6, alpha=0.6))\n\n# 美化\nbp['boxes'][0].set_facecolor('#3b82f6')\nbp['boxes'][0].set_alpha(0.7)\nbp['medians'][0].set_color('#ef4444')\nbp['medians'][0].set_linewidth(2)\n\nax.set_title('响应时间分布', fontsize=15, fontweight='bold', pad=12)\nax.set_ylabel('响应时间（ms）')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('boxplot.png', dpi=150, bbox_inches='tight')\n```\n\n### 多组箱线图对比（最常用）\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\n# 按类别分组\ngroups = df.groupby('category')['value'].apply(list).to_dict()\nlabels = list(groups.keys())\ndata = [groups[k] for k in labels]\n\nbp = ax.boxplot(data, patch_artist=True, labels=labels,\n                showfliers=True, widths=0.6)\n\n# 多色填充\nPALETTE = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6']\nfor i, box in enumerate(bp['boxes']):\n    box.set_facecolor(PALETTE[i % len(PALETTE)])\n    box.set_alpha(0.7)\nfor median in bp['medians']:\n    median.set_color('#1f2937')\n    median.set_linewidth(2)\n\nax.set_title('各品类订单金额分布', fontsize=15, fontweight='bold')\nax.set_xlabel('品类')\nax.set_ylabel('金额（元）')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('boxplot_grouped.png', dpi=150, bbox_inches='tight')\n```\n\n### 使用 Seaborn 简化\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\nsns.boxplot(data=df, x='category', y='value',\n            palette=PALETTE, width=0.6, ax=ax)\n\nax.set_title('各区域用户消费分布', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('boxplot_seaborn.png', dpi=150, bbox_inches='tight')\n```\n\n### 横向箱线图\n\n```python\nfig, ax = plt.subplots(figsize=(10, 8))\n\nsns.boxplot(data=df, y='category', x='value',\n            palette=PALETTE, width=0.6, ax=ax)\n\nax.set_title('各区域用户消费分布', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('boxplot_horizontal.png', dpi=150, bbox_inches='tight')\n```\n\n### 隐藏异常值\n\n```python\n# 场景：异常值过多影响主分布展示\nfig, ax = plt.subplots(figsize=(12, 6))\n\nsns.boxplot(data=df, x='category', y='value',\n            showfliers=False,  # 隐藏异常值\n            palette=PALETTE, ax=ax)\n\nax.set_title('各品类订单金额分布（隐藏极端值）', fontsize=15, fontweight='bold')\n\nplt.tight_layout()\nplt.savefig('boxplot_no_fliers.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 三、小提琴图（Violin Plot）\n\n小提琴图 = 箱线图 + KDE，同时展示分布形状和统计量。\n\n### 标准小提琴图\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\nsns.violinplot(data=df, x='category', y='value',\n               palette=PALETTE, inner='box', ax=ax)\n# inner: 'box', 'quartile', 'point', 'stick', None\n\nax.set_title('各渠道用户年龄分布', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('violin.png', dpi=150, bbox_inches='tight')\n```\n\n### 小提琴图 + 箱线图叠加\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\n# 小提琴（半透明）\nsns.violinplot(data=df, x='category', y='value',\n               palette=PALETTE, inner=None, alpha=0.4, ax=ax)\n\n# 箱线图叠加\nsns.boxplot(data=df, x='category', y='value',\n            width=0.2, color='white', ax=ax,\n            boxprops=dict(zorder=10))\n\nax.set_title('各渠道用户年龄分布（小提琴+箱线）', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('violin_box.png', dpi=150, bbox_inches='tight')\n```\n\n### 分组小提琴图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 6))\n\nsns.violinplot(data=df, x='region', y='value', hue='gender',\n               split=True,  # 左右分割\n               palette=['#3b82f6', '#ef4444'], ax=ax)\n\nax.set_title('各地区男女消费分布对比', fontsize=15, fontweight='bold')\nax.legend(title='性别')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('violin_grouped.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 四、核密度图（KDE）\n\n### 单变量 KDE\n\n```python\nfig, ax = plt.subplots(figsize=(10, 6))\n\nsns.kdeplot(df['value'], fill=True, color='#3b82f6', alpha=0.6, ax=ax)\n\nax.set_title('用户年龄密度分布', fontsize=15, fontweight='bold')\nax.set_xlabel('年龄')\nax.set_ylabel('密度')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('kde.png', dpi=150, bbox_inches='tight')\n```\n\n### 多组 KDE 对比\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\nfor group, color in zip(['A', 'B', 'C'], PALETTE[:3]):\n    subset = df[df['group'] == group]['value']\n    sns.kdeplot(subset, fill=True, alpha=0.4, label=group, color=color, ax=ax)\n\nax.legend(title='渠道')\nax.set_title('各渠道订单金额密度对比', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('kde_grouped.png', dpi=150, bbox_inches='tight')\n```\n\n### 双变量 KDE（2D 密度图）\n\n```python\nfig, ax = plt.subplots(figsize=(10, 8))\n\nsns.kdeplot(data=df, x='feature_a', y='feature_b',\n            fill=True, cmap='Blues', thresh=0.1, levels=10, ax=ax)\n\nax.set_title('用户行为特征二维密度分布', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('kde_2d.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 五、高级场景\n\n### 直方图 + 统计线（均值/中位数）\n\n```python\nfig, ax = plt.subplots(figsize=(10, 6))\n\nax.hist(df['value'], bins=30, color='#3b82f6', edgecolor='white', alpha=0.7)\n\nmean_val = df['value'].mean()\nmedian_val = df['value'].median()\n\nax.axvline(mean_val, color='#ef4444', linestyle='--', linewidth=2, label=f'均值: {mean_val:.1f}')\nax.axvline(median_val, color='#10b981', linestyle='-.', linewidth=2, label=f'中位数: {median_val:.1f}')\n\nax.legend()\nax.set_title('订单金额分布（含统计线）', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('hist_stats.png', dpi=150, bbox_inches='tight')\n```\n\n### 箱线图 + 散点叠加（展示原始数据）\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\n# 箱线图\nsns.boxplot(data=df, x='category', y='value',\n            palette=PALETTE, width=0.5, ax=ax)\n\n# 散点叠加（带抖动）\nsns.stripplot(data=df, x='category', y='value',\n              size=3, alpha=0.3, color='#1f2937', ax=ax)\n\nax.set_title('各品类订单金额分布（含原始数据点）', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('box_strip.png', dpi=150, bbox_inches='tight')\n```\n\n### 分布对比：直方图 vs 箱线图 vs 小提琴图\n\n```python\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\n\n# 直方图\naxes[0].hist(df['value'], bins=30, color='#3b82f6', edgecolor='white', alpha=0.7)\naxes[0].set_title('直方图')\naxes[0].set_xlabel('值')\naxes[0].set_ylabel('频数')\n\n# 箱线图\naxes[1].boxplot(df['value'], patch_artist=True)\naxes[1].set_title('箱线图')\naxes[1].set_ylabel('值')\n\n# 小提琴图\nsns.violinplot(y=df['value'], ax=axes[2], color='#3b82f6')\naxes[2].set_title('小提琴图')\naxes[2].set_ylabel('值')\n\nfor ax in axes:\n    ax.spines['top'].set_visible(False)\n    ax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('distribution_compare.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 六、强制规范\n\n### ✅ MUST DO\n\n- **直方图必须指定 bins 或让算法自动选择**，避免使用默认值\n- **箱线图必须标注异常值定义**（默认 1.5×IQR，可调整）\n- **多组分布对比时，使用相同的 Y 轴范围**\n- **中位数线必须清晰可见**（颜色对比、线宽）\n- **直方图柱子之间必须有白色边框**（避免视觉混淆）\n- **KDE 曲线必须有标签说明**（密度 vs 概率）\n\n### ❌ MUST NOT\n\n- 不在直方图上省略 X 轴标签（值范围）\n- 不用箱线图展示类别 > 20 的数据（改为聚合或筛选）\n- 不在小提琴图中隐藏统计量（至少显示中位数）\n- 不用 3D 直方图\n- 不忽略异常值的解释（是什么原因？是否需要排除？）\n- 不在密度图中使用 fill=False（无法直观比较）\n\n---\n\n## 七、行业最佳实践\n\n### 电商：订单金额分布\n\n```python\n# 典型电商订单金额呈长尾分布，用对数 X 轴\nfig, ax = plt.subplots(figsize=(10, 6))\n\nax.hist(df['order_amount'], bins=50, color='#3b82f6', edgecolor='white', alpha=0.7)\nax.set_xscale('log')  # 对数轴\n\nax.set_title('订单金额分布（对数轴）', fontsize=15, fontweight='bold')\nax.set_xlabel('金额（元，对数刻度）')\nax.set_ylabel('订单数')\n\nplt.tight_layout()\nplt.savefig('order_amount_log.png', dpi=150, bbox_inches='tight')\n```\n\n### 金融：收益率分布\n\n```python\n# 收益率通常接近正态，检查肥尾\nfig, ax = plt.subplots(figsize=(10, 6))\n\nsns.histplot(df['return'], bins=50, kde=True, color='#3b82f6', ax=ax)\n\n# 添加正态分布参考\nfrom scipy import stats\nx = np.linspace(df['return'].min(), df['return'].max(), 100)\ny = stats.norm.pdf(x, df['return'].mean(), df['return'].std())\nax.plot(x, y * len(df) * (x[1] - x[0]), 'r--', label='正态分布参考')\n\nax.legend()\nax.set_title('日收益率分布 vs 正态分布', fontsize=15, fontweight='bold')\n\nplt.tight_layout()\nplt.savefig('return_distribution.png', dpi=150, bbox_inches='tight')\n```\n\n### 运维：响应时间分布\n\n```python\n# P50, P90, P99 分位线\nfig, ax = plt.subplots(figsize=(10, 6))\n\nax.hist(df['response_time'], bins=50, color='#3b82f6', edgecolor='white', alpha=0.7)\n\np50 = df['response_time'].quantile(0.5)\np90 = df['response_time'].quantile(0.9)\np99 = df['response_time'].quantile(0.99)\n\nax.axvline(p50, color='#10b981', linestyle='--', linewidth=2, label=f'P50: {p50:.0f}ms')\nax.axvline(p90, color='#f59e0b', linestyle='--', linewidth=2, label=f'P90: {p90:.0f}ms')\nax.axvline(p99, color='#ef4444', linestyle='--', linewidth=2, label=f'P99: {p99:.0f}ms')\n\nax.legend()\nax.set_title('API 响应时间分布', fontsize=15, fontweight='bold')\nax.set_xlabel('响应时间（ms）')\nax.set_ylabel('请求数')\n\nplt.tight_layout()\nplt.savefig('response_time_p99.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 八、常见问题与解决方案\n\n| 问题 | 原因 | 解决方案 |\n|------|------|---------|\n| 直方图柱子太少/太多 | bins 不合适 | 使用 FD 公式或手动调整 |\n| 箱线图异常值过多 | 数据本身有极端值 | 检查数据质量；可调高异常阈值 |\n| 多组分布无法比较 | Y 轴范围不同 | 设置 `sharey=True` 或手动统一 |\n| KDE 曲线超出数据范围 | 核密度估计外推 | 设置 `clip=(min, max)` |\n| 小提琴图太拥挤 | 类别太多 | 改用箱线图或分面展示 |\n| 直方图右偏严重 | 长尾分布 | 使用对数 X 轴 |\n\nFile v1.0.1:references/heatmap.md\n\n# 热力图 — 相关性矩阵、时间热图、表格热图\n\n适用场景：相关性分析、时间序列密度、分类数据对比、矩阵数据可视化。\n\n---\n\n## 核心问题：你想展示什么类型的热力图？\n\n| 场景 | 推荐类型 |\n|------|---------|\n| 特征之间的相关性？ | 相关性矩阵热力图 |\n| 随时间变化的强度？ | 时间热力图（Calendar/Activity） |\n| 分类数据对比？ | 分类热力图 |\n| 表格数据可视化？ | 表格热力图 |\n| 地理位置密度？ | 地理热力图（需地图数据，见地理图表） |\n\n---\n\n## 一、相关性矩阵热力图\n\n相关性热力图是最常用的场景，用于发现变量之间的关系。\n\n### 基础相关性热力图\n\n```python\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport numpy as np\nimport pandas as pd\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nfig, ax = plt.subplots(figsize=(12, 10))\n\n# 计算相关性矩阵\ncorr = df[['col1', 'col2', 'col3', 'col4', 'col5']].corr()\n\n# 绘制热力图\nmask = np.zeros_like(corr)  # 可选：只显示下三角 mask = np.triu(np.ones_like(corr, dtype=bool))\n\nsns.heatmap(corr,\n            annot=True,          # 显示数值\n            fmt='.2f',           # 数值格式\n            cmap='RdYlGn',       # 颜色映射：红-黄-绿（正相关绿，负相关红）\n            center=0,             # 0 为中心\n            square=True,         # 正方形格子\n            linewidths=0.5,      # 格子间隔线\n            cbar_kws={'shrink': 0.8, 'label': '相关系数'},\n            ax=ax)\n\nax.set_title('特征相关性矩阵', fontsize=15, fontweight='bold', pad=15)\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('corr_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### 只显示下三角（避免重复信息）\n\n```python\nfig, ax = plt.subplots(figsize=(12, 10))\n\n# 上三角遮罩\nmask = np.triu(np.ones_like(corr, dtype=bool))\n\nsns.heatmap(corr, mask=mask,\n            annot=True, fmt='.2f',\n            cmap='RdYlGn', center=0,\n            square=True, linewidths=0.5,\n            cbar_kws={'shrink': 0.8},\n            ax=ax)\n\nax.set_title('特征相关性矩阵（下三角）', fontsize=15, fontweight='bold', pad=15)\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('corr_heatmap_lower.png', dpi=150, bbox_inches='tight')\n```\n\n### 高级：带聚类的相关性热力图\n\n```python\n# 使用 clustermap 进行层次聚类排序\ng = sns.clustermap(corr,\n                    method='ward',        # 聚类方法\n                    cmap='RdYlGn',\n                    center=0,\n                    annot=True,\n                    fmt='.2f',\n                    linewidths=0.5,\n                    figsize=(12, 10),\n                    dendrogram_ratio=(.1, .1),\n                    cbar_pos=(0.02, 0.8, 0.03, 0.15))\n\ng.fig.suptitle('特征相关性矩阵（含聚类）', fontsize=15, fontweight='bold', y=1.02)\ng.savefig('corr_clustermap.png', dpi=150, bbox_inches='tight')\nplt.close()\n```\n\n### 标注显著性（p-value）\n\n```python\nfrom scipy import stats\n\ndef corr_with_pvalue(df):\n    cols = df.columns\n    n = len(cols)\n    corr = np.zeros((n, n))\n    pval = np.zeros((n, n))\n    for i in range(n):\n        for j in range(n):\n            if i == j:\n                corr[i, j] = 1.0\n                pval[i, j] = 0\n            else:\n                r, p = stats.pearsonr(df.iloc[:, i], df.iloc[:, j])\n                corr[i, j] = r\n                pval[i, j] = p\n    return pd.DataFrame(corr, index=cols, columns=cols), pd.DataFrame(pval, index=cols, columns=cols)\n\ncorr_matrix, pval_matrix = corr_with_pvalue(df)\n\nfig, ax = plt.subplots(figsize=(12, 10))\n\n# 显著性标注（* p<0.05, ** p<0.01, *** p<0.001）\nannot = corr_matrix.round(2).copy()\nfor i in range(len(pval_matrix)):\n    for j in range(len(pval_matrix)):\n        p = pval_matrix.iloc[i, j]\n        if p < 0.001:\n            annot.iloc[i, j] = f'{corr_matrix.iloc[i, j]:.2f}***'\n        elif p < 0.01:\n            annot.iloc[i, j] = f'{corr_matrix.iloc[i, j]:.2f}**'\n        elif p < 0.05:\n            annot.iloc[i, j] = f'{corr_matrix.iloc[i, j]:.2f}*'\n\nsns.heatmap(corr_matrix, annot=annot, fmt='',\n            cmap='RdYlGn', center=0,\n            square=True, linewidths=0.5,\n            ax=ax)\n\nax.set_title('相关性矩阵（* p<0.05, ** p<0.01, *** p<0.001）', fontsize=15, fontweight='bold')\nplt.tight_layout()\nplt.savefig('corr_pvalue.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 二、时间热力图\n\n### GitHub 风格贡献热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 6))\n\n# 重塑为周×天的矩阵（周一=0，周日=6）\ndf['date'] = pd.to_datetime(df['date'])\ndf['week'] = df['date'].dt.isocalendar().week\ndf['dayofweek'] = df['date'].dt.dayofweek\n\n# 按周和星期聚合\npivot = df.groupby(['week', 'dayofweek'])['value'].sum().unstack(fill_value=0)\n\n# 绘制热力图\nsns.heatmap(pivot, cmap='YlGnBu', linewidths=0.5,\n             square=False, cbar_kws={'label': '活跃度'},\n             ax=ax)\n\n# Y 轴标签改为星期\nax.set_yticklabels(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'])\nax.set_xticklabels([f'W{int(w)}' for w in ax.get_xticks()], rotation=45, ha='right', fontsize=8)\nax.set_title('每日活跃热力图', fontsize=15, fontweight='bold')\nax.set_xlabel('周数')\nax.set_ylabel('')\n\nplt.tight_layout()\nplt.savefig('calendar_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### Seaborn 内置 Calendar Heatmap（年视图）\n\n```python\n# 使用 calmap 库（更专业）\nimport calmap\n\nfig, ax = plt.subplots(figsize=(15, 6))\n\n# 设置日期索引\ndf_indexed = df.set_index('date')['value']\n\ncalmap.yearplot(df_indexed, year=2026, ax=ax, cmap='YlGnBu')\n\nax.set_title('2026 年度活跃热力图', fontsize=15, fontweight='bold')\nplt.tight_layout()\nplt.savefig('year_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### 月度时间热力图（小时 × 天）\n\n```python\n# 场景：用户活跃时间段分析\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 创建小时×星期的矩阵\ndf['hour'] = df['timestamp'].dt.hour\ndf['weekday'] = df['timestamp'].dt.dayofweek\npivot = df.groupby(['weekday', 'hour'])['value'].sum().unstack(fill_value=0)\n\n# 绘制\nsns.heatmap(pivot, cmap='Blues', linewidths=0.5,\n             xticklabels=range(24), yticklabels=['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],\n             cbar_kws={'label': '活动量'}, ax=ax)\n\nax.set_title('用户活跃时段分布（小时 × 星期）', fontsize=15, fontweight='bold')\nax.set_xlabel('小时')\nax.set_ylabel('星期')\nplt.xticks(rotation=0)\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('hour_weekday_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 三、分类热力图\n\n### 分组数据热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 创建 品类×月份 的数据矩阵\npivot = df.pivot_table(values='sales',\n                        index='category',\n                        columns='month',\n                        aggfunc='sum',\n                        fill_value=0)\n\nsns.heatmap(pivot, cmap='Blues', linewidths=0.5,\n             annot=True, fmt=',.0f',\n             cbar_kws={'label': '销售额（万元）'},\n             ax=ax)\n\nax.set_title('各品类月度销售额', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('category_month_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### 百分比热力图（按行归一化）\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 按行归一化（每行之和为 100%）\npivot_pct = pivot.div(pivot.sum(axis=1), axis=0) * 100\n\nsns.heatmap(pivot_pct, cmap='Blues', linewidths=0.5,\n             annot=True, fmt='.1f',\n             cbar_kws={'label': '占比（%）'},\n             ax=ax)\n\nax.set_title('各品类月度销售额占比（%）', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('category_month_pct.png', dpi=150, bbox_inches='tight')\n```\n\n### 发散型热力图（展示增减变化）\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 计算环比变化\npivot_diff = pivot.pct_change(axis=1) * 100  # 月度环比增长率\n\n# 发散型 colormap（正=绿，负=红）\ncmap = sns.diverging_palette(10, 130, as_cmap=True)  # 红-白-绿\n\nsns.heatmap(pivot_diff, cmap=cmap, center=0,\n             linewidths=0.5, fmt='+.1f',\n             annot=True, vmin=-50, vmax=50,\n             cbar_kws={'label': '环比增长率（%）'},\n             ax=ax)\n\nax.set_title('各品类月度销售额环比变化（%）', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('pivot_diverging.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 四、Cohort 留存热力图\n\n用户留存分析的标准可视化。\n\n```python\ndef cohort_heatmap(df, cohort_col, period_col, value_col='user_id', metric='count'):\n    \"\"\"\n    生成 Cohort 留存热力图\n    df: 包含用户首次行为日期和当前行为日期的数据\n    cohort_col: 首次行为日期列\n    period_col: 当前行为日期列\n    \"\"\"\n    df = df.copy()\n    df[cohort_col] = pd.to_datetime(df[cohort_col])\n    df[period_col] = pd.to_datetime(df[period_col])\n\n    # Cohort 周期（月份）\n    df['cohort_month'] = df[cohort_col].dt.to_period('M')\n    df['period_month'] = df[period_col].dt.to_period('M')\n\n    # 计算相对月份\n    df['period_number'] = (df['period_month'].astype(int) - df['cohort_month'].astype(int))\n\n    # 统计每个 Cohort × Period 的用户数\n    cohort_data = df.groupby(['cohort_month', 'period_number'])[value_col].nunique().reset_index()\n    cohort_table = cohort_data.pivot(index='cohort_month', columns='period_number', values=value_col)\n\n    # 计算留存率\n    cohort_size = cohort_table.iloc[:, 0]\n    retention_table = cohort_table.divide(cohort_size, axis=0) * 100\n\n    return cohort_table, retention_table\n\n# 生成数据\ncohort_table, retention_table = cohort_heatmap(df, 'first_date', 'activity_date')\n\n# 绘制热力图\nfig, ax = plt.subplots(figsize=(16, 10))\n\nsns.heatmap(retention_table, cmap='YlGnBu', linewidths=0.5,\n             annot=True, fmt='.0f', vmin=0, vmax=100,\n             cbar_kws={'label': '留存率（%）'},\n             ax=ax)\n\nax.set_title('Cohort 用户留存率（%）', fontsize=15, fontweight='bold')\nax.set_xlabel('距首次活跃月数')\nax.set_ylabel('Cohort（首次活跃月份）')\nplt.xticks(rotation=0)\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('cohort_retention.png', dpi=150, bbox_inches='tight')\n```\n\n### Cohort 热力图进阶：同时显示人数和留存率\n\n```python\n# 创建双层热力图：人数 + 留存率\nfig, axes = plt.subplots(1, 2, figsize=(20, 10))\n\n# 左图：绝对人数\nsns.heatmap(cohort_table, cmap='Blues', linewidths=0.5,\n             annot=True, fmt=',.0f', ax=axes[0])\naxes[0].set_title('Cohort 用户数', fontsize=14, fontweight='bold')\naxes[0].set_xlabel('距首次活跃月数')\n\n# 右图：留存率\nsns.heatmap(retention_table, cmap='YlGnBu', linewidths=0.5,\n             annot=True, fmt='.0f', vmin=0, vmax=100, ax=axes[1])\naxes[1].set_title('Cohort 留存率（%）', fontsize=14, fontweight='bold')\naxes[1].set_xlabel('距首次活跃月数')\n\nfor ax in axes:\n    ax.set_ylabel('')\n\nplt.suptitle('用户 Cohort 分析', fontsize=16, fontweight='bold', y=1.02)\nplt.tight_layout()\nplt.savefig('cohort_combined.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 五、表格热力图\n\n### 普通表格热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 创建表格数据\ntable_data = df.pivot_table(values='sales',\n                             index='region',\n                             columns='product',\n                             aggfunc='sum',\n                             fill_value=0)\n\nsns.heatmap(table_data, cmap='Oranges', linewidths=1,\n             annot=True, fmt=',.0f',\n             cbar_kws={'label': '销售额（万元）'},\n             ax=ax, annot_kws={'size': 10})\n\nax.set_title('各区域各产品销售额', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right', fontsize=10)\nplt.yticks(rotation=0, fontsize=10)\n\nplt.tight_layout()\nplt.savefig('table_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### 带格式化文本的热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 自定义格式化函数\ndef fmt(val):\n    if val == 0:\n        return '-'\n    elif val >= 10000:\n        return f'{val/10000:.1f}万'\n    elif val >= 1000:\n        return f'{val/1000:.0f}千'\n    else:\n        return f'{val:.0f}'\n\nannot = table_data.applymap(fmt)\n\nsns.heatmap(table_data, cmap='YlOrRd', linewidths=1,\n             annot=annot, fmt='', cbar=False, ax=ax)\n\nax.set_title('各区域各产品销售额', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('table_heatmap_fmt.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 六、颜色映射选择指南\n\n### 何时用哪种 Colormap\n\n| Colormap | 类型 | 适用场景 |\n|----------|------|---------|\n| `RdYlGn` | 发散型 | 相关性、变化率（中心=0） |\n| `RdBu` | 发散型 | 正负对比（金融涨跌） |\n| `seismic` | 发散型 | 地震/极端正负值 |\n| `Blues` / `YlGnBu` | 顺序型 | 单向递增（销售额、用户数） |\n| `Oranges` / `Reds` | 顺序型 | 热度、风险、强度 |\n| `viridis` / `plasma` | 顺序型 | 科学数据、色盲友好 |\n| `coolwarm` | 发散型 | 温度、情感分析 |\n| `cubehelix` | 顺序型 | 亮度渐变、打印友好 |\n\n### 发散型 vs 顺序型\n\n```python\n# 发散型：数据有正负对比\ncmap_div = sns.diverging_palette(10, 130, as_cmap=True)  # 红-白-绿\n\n# 顺序型：数据单向递增\ncmap_seq = sns.color_palette('Blues', as_cmap=True)\n\n# 自定义边界\nimport matplotlib.colors as mcolors\ncmap_custom = mcolors.LinearSegmentedColormap.from_list(\n    'custom', ['#f7fbff', '#3b82f6', '#1e3a5f'])\n```\n\n### 色盲友好建议\n\n```python\n# 推荐色盲友好的 colormap\ncbar_kws={'label': '值', 'cmap': 'viridis'}  # 默认最优\ncbar_kws={'label': '值', 'cmap': 'cividis'}   # 更深的对比\n```\n\n---\n\n## 七、高级场景\n\n### 热力图 + 树状图（层次聚类排序）\n\n```python\ng = sns.clustermap(df.corr(),\n                   method='average',\n                   metric='correlation',\n                   cmap='RdYlGn',\n                   center=0,\n                   annot=True,\n                   fmt='.2f',\n                   linewidths=0.5,\n                   figsize=(12, 10),\n                   dendrogram_ratio=(0.2, 0.2),\n                   cbar_pos=(0.02, 0.8, 0.03, 0.15),\n                   tree_kws={'linewidths': 0.5})\n\ng.fig.suptitle('相关性矩阵（层次聚类）', fontsize=15, fontweight='bold', y=1.02)\nplt.savefig('heatmap_clustered.png', dpi=150, bbox_inches='tight')\nplt.close()\n```\n\n### 带缺失值的热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# NaN 显示为灰色\ncmap = sns.diverging_palette(10, 130, as_cmap=True)\n\nsns.heatmap(table_data, cmap=cmap, center=0,\n             linewidths=0.5, fmt='.1f',\n             annot=True, ax=ax,\n             mask=table_data.isna(),  # 遮罩缺失值\n             na_rep='N/A')\n\nax.set_title('数据热力图（含缺失值显示为 N/A）', fontsize=15, fontweight='bold')\nplt.tight_layout()\nplt.savefig('heatmap_na.png', dpi=150, bbox_inches='tight')\n```\n\n### 热力图边框和单元格大小控制\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 调整单元格比例\nsns.heatmap(table_data, cmap='Blues',\n             linewidths=2,          # 加粗边框\n             linecolor='white',     # 白色分隔线\n             square=True,            # 正方形格子\n             ax=ax)\n\nax.set_title('单元格热力图', fontsize=15, fontweight='bold')\nplt.tight_layout()\nplt.savefig('heatmap_square.png', dpi=150, bbox_inches='tight')\n```\n\n### 热力图 + 散点叠加（双层信息）\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 底色热力图\nsns.heatmap(table_data, cmap='Blues', alpha=0.3,\n             annot=False, linewidths=0, ax=ax)\n\n# 叠加数值散点\nfor i, row_idx in enumerate(table_data.index):\n    for j, col_idx in enumerate(table_data.columns):\n        val = table_data.loc[row_idx, col_idx]\n        if pd.notna(val):\n            ax.scatter(j + 0.5, i + 0.5, s=val/10,\n                       c='red' if val > table_data.median().median() else 'blue',\n                       alpha=0.6, zorder=10)\n\nax.set_title('热力图 + 散点叠加', fontsize=15, fontweight='bold')\nplt.tight_layout()\nplt.savefig('heatmap_scatter.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 八、强制规范\n\n### ✅ MUST DO\n\n- **相关性热力图必须标注数值**（annot=True）\n- **发散型 colormap 必须设置 center=0**\n- **colormap 必须有 colorbar 和标签**\n- **长标签必须旋转**（rotation=45）保证可读\n- **单元格大小应与数据量匹配**：数据多格子小，数据少格子大\n- **缺失值必须处理**：mask 或 na_rep\n\n### ❌ MUST NOT\n\n- 不用 `jet` / `rainbow` 等非色盲友好 colormap\n- 不在正负数据上使用单向 colormap（如 Blues）\n- 不省略 colorbar（无法判断颜色对应数值）\n- 不在过小的格子里显示长数字（改用颜色深浅）\n- 不用 3D 热力图（无法准确读值）\n- 不在类别过多时使用热力图（改用条形图或表格）\n\n---\n\n## 九、行业最佳实践\n\n### 电商：品类×时间 销售热力图\n\n```python\n# 月度销售趋势热力图\nfig, ax = plt.subplots(figsize=(16, 10))\n\npivot = df.pivot_table(values='gmv',\n                       index='category',\n                       columns='month',\n                       aggfunc='sum',\n                       fill_value=0)\n\n# 使用聚类排序\ng = sns.clustermap(pivot, cmap='YlGnBu',\n                    annot=True, fmt=',.0f',\n                    linewidths=0.5,\n                    figsize=(16, 10),\n                    dendrogram_ratio=0.15,\n                    cbar_pos=(0.02, 0.8, 0.03, 0.15))\n\ng.fig.suptitle('各品类月度销售额（聚类排序）', fontsize=15, fontweight='bold', y=1.02)\nplt.savefig('sales_heatmap_clustered.png', dpi=150, bbox_inches='tight')\nplt.close()\n```\n\n### 金融：资产相关性矩阵\n\n```python\nfig, ax = plt.subplots(figsize=(12, 10))\n\n# 计算收益率相关性\nreturns = df[['stock_a', 'stock_b', 'bond', 'gold', 'commodity']].pct_change().dropna()\ncorr = returns.corr()\n\n# 使用 seaborn 内置 clustermap 排序\ng = sns.clustermap(corr, method='single',\n                   cmap='RdYlGn', center=0,\n                   annot=True, fmt='.2f',\n                   linewidths=0.5,\n                   figsize=(10, 8),\n                   vmin=-1, vmax=1,\n                   dendrogram_ratio=0.1)\n\ng.fig.suptitle('资产收益率相关性矩阵', fontsize=15, fontweight='bold', y=1.02)\nplt.savefig('asset_correlation.png', dpi=150, bbox_inches='tight')\nplt.close()\n```\n\n### 运营：客服响应时效热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 按客服×时段 统计平均响应时间\npivot = df.pivot_table(values='response_time',\n                       index='agent',\n                       columns='time_slot',\n                       aggfunc='mean',\n                       fill_value=0)\n\n# 发散型：快=绿，慢=红\ncmap = sns.diverging_palette(10, 130, as_cmap=True)\n\nsns.heatmap(pivot, cmap=cmap, center=pivot.values.mean(),\n             annot=True, fmt='.0f', vmin=0,\n             linewidths=0.5,\n             cbar_kws={'label': '平均响应时间（分钟）'},\n             ax=ax)\n\nax.set_title('各客服不同时段平均响应时间（分钟）', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('response_time_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### 营销：广告效果对比热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 创意维度：渠道×指标\npivot = df.pivot_table(values='value',\n                       index='channel',\n                       columns='metric',\n                       aggfunc='mean')\n\n# 归一化（按列）便于跨指标对比\npivot_norm = pivot.apply(lambda x: (x - x.min()) / (x.max() - x.min()), axis=0)\n\nsns.heatmap(pivot_norm, cmap='RdYlGn', vmin=0, vmax=1,\n             annot=pivot.round(1), fmt='', linewidths=0.5,\n             cbar_kws={'label': '归一化得分'},\n             ax=ax)\n\nax.set_title('各渠道广告效果对比（数值=原始值，颜色=归一化得分）', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('ad_effectiveness_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 十、常见问题与解决方案\n\n| 问题 | 原因 | 解决方案 |\n|------|------|---------|\n| 热力图颜色对比不明显 | 中心值设置不当 | 调整 center 或 vmin/vmax |\n| 长标签重叠 | 列太多 | rotation=45 或改为横向热力图 |\n| 数据差异太大（极端值） | 数值跨度大 | 使用对数刻度或分箱 |\n| 类别标签无法显示 | 列宽太小 | 调整 figsize 或使用横向热力图 |\n| 相关性 0.01 和 0.99 颜色相同 | 没设置 center=0 | 改用 RdYlGn 等发散型 colormap |\n| 色盲无法区分 | 用了红绿对比 | 改用 viridis、cividis、Blues |\n\nFile v1.0.1:references/INSTALLATION.md\n\n# 依赖安装与配置指南\n\n## 快速开始（推荐）\n\n### 方式 1：使用 SkillHub 一键安装（最简单）\n\n```bash\n# 自动检测环境、安装所有依赖、配置 Python 环境\nskillhub_install install_skill sql-dataviz\nskillhub_install install_skill sql-report-generator\n```\n\n**优点：**\n- ✓ 自动处理所有依赖\n- ✓ 跨平台支持（Windows/Linux/macOS）\n- ✓ 自动配置环境变量\n- ✓ 一步完成\n\n---\n\n## 手动安装指南\n\n### 前置要求\n\n- **Python 3.8+**\n- **pip 20.0+**\n- **操作系统**：Windows / Linux / macOS\n\n### 步骤 1：检查 Python 环境\n\n```bash\n# 检查 Python 版本\npython3 --version\n\n# 检查 pip 版本\npip3 --version\n\n# 如果命令不存在，请先安装 Python\n# Windows: https://www.python.org/downloads/\n# Linux: sudo apt-get install python3 python3-pip\n# macOS: brew install python3\n```\n\n### 步骤 2：安装核心依赖\n\n```bash\n# 升级 pip（推荐）\npip3 install --upgrade pip\n\n# 安装核心依赖\npip3 install \\\n    matplotlib \\\n    seaborn \\\n    pandas \\\n    numpy \\\n    pillow\n```\n\n**预期输出：**\n```\nSuccessfully installed matplotlib-3.x.x seaborn-0.x.x pandas-2.x.x numpy-1.x.x pillow-x.x.x\n```\n\n### 步骤 3：安装可选依赖\n\n#### 树状图支持（可选）\n\n```bash\npip3 install squarify\n```\n\n#### 地理数据支持（可选）\n\n```bash\npip3 install geopandas shapely\n```\n\n#### 交互式图表支持（可选）\n\n```bash\npip3 install plotly\n```\n\n#### PDF 导出支持（可选）\n\n```bash\npip3 install reportlab pypdf2\n```\n\n### 步骤 4：验证安装\n\n```bash\n# 验证核心依赖\npython3 << 'EOF'\nimport matplotlib\nimport seaborn\nimport pandas\nimport numpy\nfrom PIL import Image\nprint(\"✓ 所有核心依赖验证成功\")\nEOF\n\n# 验证 sql-dataviz\npython3 << 'EOF'\nfrom sql_dataviz.charts import ChartFactory\nfactory = ChartFactory()\nprint(\"✓ sql-dataviz 验证成功\")\nEOF\n\n# 验证 sql-report-generator\npython3 << 'EOF'\nfrom sql_report_generator.scripts.interactive_components import ReportBuilder\nreport = ReportBuilder()\nprint(\"✓ sql-report-generator 验证成功\")\nEOF\n```\n\n---\n\n## 国内镜像加速（可选）\n\n如果 pip 下载速度慢，可以使用国内镜像：\n\n### 临时使用镜像\n\n```bash\n# 使用阿里云镜像\npip3 install -i https://mirrors.aliyun.com/pypi/simple/ matplotlib seaborn pandas numpy pillow\n\n# 使用清华大学镜像\npip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple matplotlib seaborn pandas numpy pillow\n\n# 使用豆瓣镜像\npip3 install -i http://pypi.douban.com/simple matplotlib seaborn pandas numpy pillow\n```\n\n### 永久配置镜像\n\n**Linux/macOS：**\n\n```bash\n# 编辑 ~/.pip/pip.conf\nmkdir -p ~/.pip\ncat > ~/.pip/pip.conf << 'EOF'\n[global]\nindex-url = https://mirrors.aliyun.com/pypi/simple/\nEOF\n```\n\n**Windows：**\n\n```bash\n# 编辑 %APPDATA%\\pip\\pip.ini\n# 或创建 C:\\Users\\<username>\\AppData\\Roaming\\pip\\pip.ini\n\n[global]\nindex-url = https://mirrors.aliyun.com/pypi/simple/\n```\n\n---\n\n## 常见问题排查\n\n### Q1: \"command not found: python3\"\n\n**解决方案：**\n\n```bash\n# 检查 Python 是否安装\nwhich python3\n\n# 如果未安装，请下载安装\n# https://www.python.org/downloads/\n\n# 或使用包管理器\n# Ubuntu/Debian: sudo apt-get install python3\n# CentOS: sudo yum install python3\n# macOS: brew install python3\n```\n\n### Q2: \"pip3: command not found\"\n\n**解决方案：**\n\n```bash\n# 使用 python3 -m pip 替代\npython3 -m pip install --upgrade pip\n\n# 或重新安装 Python\n```\n\n### Q3: \"ModuleNotFoundError: No module named 'matplotlib'\"\n\n**解决方案：**\n\n```bash\n# 重新安装依赖\npip3 install --force-reinstall matplotlib\n\n# 或检查 Python 环境\npython3 -m pip list | grep matplotlib\n```\n\n### Q4: 权限错误 \"Permission denied\"\n\n**解决方案：**\n\n```bash\n# 方式 1：使用 --user 标志\npip3 install --user matplotlib seaborn pandas numpy pillow\n\n# 方式 2：使用虚拟环境（推荐）\npython3 -m venv venv\nsource venv/bin/activate  # Linux/macOS\n# 或\nvenv\\Scripts\\activate  # Windows\n\npip3 install matplotlib seaborn pandas numpy pillow\n```\n\n### Q5: 版本冲突\n\n**解决方案：**\n\n```bash\n# 查看已安装的包\npip3 list\n\n# 卸载冲突的包\npip3 uninstall matplotlib\n\n# 重新安装指定版本\npip3 install matplotlib==3.7.1\n```\n\n---\n\n## 虚拟环境设置（推荐用于生产环境）\n\n### 创建虚拟环境\n\n```bash\n# 创建虚拟环境\npython3 -m venv dataviz_env\n\n# 激活虚拟环境\n# Linux/macOS:\nsource dataviz_env/bin/activate\n\n# Windows:\ndataviz_env\\Scripts\\activate\n```\n\n### 在虚拟环境中安装依赖\n\n```bash\n# 激活虚拟环境后\npip3 install matplotlib seaborn pandas numpy pillow squarify\n\n# 验证\npython3 -c \"import matplotlib; print(matplotlib.__version__)\"\n```\n\n### 导出依赖列表\n\n```bash\n# 生成 requirements.txt\npip3 freeze > requirements.txt\n\n# 在其他环境中安装\npip3 install -r requirements.txt\n```\n\n---\n\n## Docker 容器化（可选）\n\n如果需要在 Docker 中运行，可以使用以下 Dockerfile：\n\n```dockerfile\nFROM python:3.11-slim\n\nWORKDIR /app\n\n# 安装系统依赖\nRUN apt-get update && apt-get install -y \\\n    build-essential \\\n    && rm -rf /var/lib/apt/lists/*\n\n# 复制 requirements.txt\nCOPY requirements.txt .\n\n# 安装 Python 依赖\nRUN pip install --no-cache-dir -r requirements.txt\n\n# 复制应用代码\nCOPY . .\n\n# 运行演示\nCMD [\"python3\", \"scripts/demo.py\"]\n```\n\n**构建和运行：**\n\n```bash\n# 构建镜像\ndocker build -t sql-dataviz:latest .\n\n# 运行容器\ndocker run -v $(pwd)/output:/app/output sql-dataviz:latest\n```\n\n---\n\n## 性能优化\n\n### 1. 使用 NumPy 加速\n\n```bash\n# 安装优化版本的 NumPy\npip3 install numpy --upgrade\n```\n\n### 2. 使用 Conda（可选）\n\n```bash\n# 安装 Conda\n# https://docs.conda.io/projects/conda/en/latest/user-guide/install/\n\n# 创建环境\nconda create -n dataviz python=3.11\n\n# 激活环境\nconda activate dataviz\n\n# 安装依赖\nconda install matplotlib seaborn pandas numpy pillow\n```\n\n### 3. 使用 PyPy（可选，用于高性能）\n\n```bash\n# 安装 PyPy\n# https://www.pypy.org/\n\n# 使用 PyPy 安装依赖\npypy3 -m pip install matplotlib seaborn pandas numpy pillow\n```\n\n---\n\n## 验证完整安装\n\n运行完整演示脚本：\n\n```bash\n# 进入 sql-dataviz 目录\ncd sql-dataviz\n\n# 运行演示\npython3 scripts/demo.py\n\n# 查看输出\nls -la output/\n```\n\n**预期输出：**\n```\n✓ 所有演示完成！\n\n输出文件位置: ./output/\n\n生成的文件:\n  - 24 种图表 PNG 文件\n  - 表格、矩阵、切片器、导航按钮\n  - demo_report.html (完整报告)\n```\n\n---\n\n## 支持的 Python 版本\n\n| Python 版本 | 支持状态 | 备注 |\n|-----------|--------|------|\n| 3.8 | ✓ 支持 | 最低要求 |\n| 3.9 | ✓ 支持 | 推荐 |\n| 3.10 | ✓ 支持 | 推荐 |\n| 3.11 | ✓ 支持 | 最新稳定版 |\n| 3.12 | ⚠ 测试中 | 部分依赖可能不兼容 |\n\n---\n\n## 依赖版本要求\n\n| 包名 | 最低版本 | 推荐版本 | 用途 |\n|------|--------|--------|------|\n| matplotlib | 3.5.0 | 3.7.1+ | 图表绘制 |\n| seaborn | 0.12.0 | 0.13.0+ | 统计图表 |\n| pandas | 1.5.0 | 2.0.0+ | 数据处理 |\n| numpy | 1.23.0 | 1.24.0+ | 数值计算 |\n| pillow | 9.0.0 | 10.0.0+ | 图像处理 |\n| squarify | 0.4.3 | 0.4.3+ | 树状图（可选） |\n| geopandas | 0.12.0 | 0.13.0+ | 地理数据（可选） |\n| plotly | 5.0.0 | 5.14.0+ | 交互图表（可选） |\n\n---\n\n## 获取帮助\n\n- 📧 Email: support@example.com\n- 💬 Discord: https://discord.gg/example\n- 🐛 Issues: https://github.com/example/sql-dataviz/issues\n- 📖 文档: https://docs.example.com\n\n---\n\n## 更新日志\n\n- **2026-03-26** - 初始版本发布\n- **2026-03-27** - 添加国内镜像加速指南\n- **2026-03-28** - 添加 Docker 支持\n\nFile v1.0.1:references/INTEGRATION_GUIDE.md\n\n# 三 Skill 协作完整指南\n\n## 架构概览\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│                    数据分析完整流程                          │\n└─────────────────────────────────────────────────────────────┘\n\n┌──────────────┐      ┌──────────────┐      ┌──────────────┐\n│  sql-master  │  →   │ sql-dataviz  │  →   │report-gen    │\n│              │      │              │      │              │\n│ SQL 查询     │      │ 可视化图表   │      │ 报告生成     │\n│ 数据获取     │      │ 24 种图表    │      │ 交互组件     │\n│ 数据清洗     │      │ Base64 PNG   │      │ HTML/PDF     │\n└──────────────┘      └──────────────┘      └──────────────┘\n     ↓                      ↓                      ↓\n  SQL 结果              图表 Base64            完整报告\n  DataFrame             JSON 元数据            HTML 文件\n```\n\n## 三个 Skill 的职责\n\n### 1. sql-master（数据层）\n\n**职责：**\n- 执行 SQL 查询\n- 数据清洗与转换\n- 数据聚合与分组\n- 性能优化\n\n**输出：**\n- DataFrame / 列表\n- JSON 格式数据\n\n**示例：**\n```python\nfrom sql_master import SQLMaster\n\nsql = SQLMaster()\nresult = sql.execute_query(\"\"\"\n    SELECT \n        DATE_TRUNC(order_date, MONTH) as month,\n        region,\n        SUM(sales) as total_sales,\n        COUNT(*) as order_count\n    FROM orders\n    WHERE order_date >= '2026-01-01'\n    GROUP BY month, region\n    ORDER BY month, region\n\"\"\")\n```\n\n### 2. sql-dataviz（可视化层）\n\n**职责：**\n- 将数据转换为图表格式\n- 生成 24 种 Power BI 风格图表\n- 输出 Base64 PNG\n- 支持多种主题\n\n**输入：**\n- DataFrame / 列表 / 字典\n\n**输出：**\n- Base64 PNG 字符串\n- 可直接嵌入 HTML/Markdown\n\n**示例：**\n```python\nfrom sql_dataviz.charts import ChartFactory\n\nfactory = ChartFactory()\nfactory.set_theme('powerbi')\n\n# 转换数据格式\ndata = {\n    'categories': [row['month'] for row in result],\n    'series': [\n        {'name': '北京', 'data': [...]},\n        {'name': '上海', 'data': [...]}\n    ]\n}\n\n# 生成图表\nchart_b64 = factory.create_clustered_column(data)\n```\n\n### 3. sql-report-generator（报告层）\n\n**职责：**\n- 组织图表与内容\n- 生成表格、矩阵、切片器\n- 导出 HTML/PDF/JSON\n- 提供交互功能\n\n**输入：**\n- Base64 图表\n- 表格数据\n- 文本内容\n\n**输出：**\n- HTML 报告\n- PDF 文件\n- JSON 数据\n\n**示例：**\n```python\nfrom sql_report_generator.scripts.interactive_components import ReportBuilder\n\nreport = ReportBuilder()\nreport.set_metadata(title='月度销售报告')\nreport.add_title('销售分析', level=1)\nreport.add_chart('销售趋势', chart_b64)\nreport.export_html('report.html')\n```\n\n## 完整工作流示例\n\n### 场景：生成月度销售报告\n\n#### 步骤 1：sql-master 查询数据\n\n```python\nfrom sql_master import SQLMaster\nimport pandas as pd\n\nsql = SQLMaster()\n\n# 查询 1：月度销售总额\nmonthly_sales = sql.execute_query(\"\"\"\n    SELECT \n        DATE_TRUNC(order_date, MONTH) as month,\n        SUM(sales) as total\n    FROM orders\n    WHERE order_date >= '2026-01-01'\n    GROUP BY month\n    ORDER BY month\n\"\"\")\n\n# 查询 2：地区销售对比\nregional_sales = sql.execute_query(\"\"\"\n    SELECT \n        region,\n        SUM(sales) as total\n    FROM orders\n    WHERE order_date >= '2026-01-01'\n    GROUP BY region\n    ORDER BY total DESC\n\"\"\")\n\n# 查询 3：订单明细\norders = sql.execute_query(\"\"\"\n    SELECT \n        order_id, customer_name, region, sales, order_date\n    FROM orders\n    WHERE order_date >= '2026-01-01'\n    ORDER BY order_date DESC\n    LIMIT 100\n\"\"\")\n```\n\n#### 步骤 2：sql-dataviz 生成图表\n\n```python\nfrom sql_dataviz.charts import ChartFactory\nimport pandas as pd\n\nfactory = ChartFactory()\nfactory.set_theme('powerbi')\n\n# 图表 1：月度趋势\ntrend_data = {\n    'categories': [row['month'].strftime('%Y-%m') for row in monthly_sales],\n    'series': [{'name': '销售额', 'data': [row['total'] for row in monthly_sales]}]\n}\ntrend_chart = factory.create_line(trend_data)\n\n# 图表 2：地区对比\nregion_data = {\n    'categories': [row['region'] for row in regional_sales],\n    'series': [{'name': '销售额', 'data': [row['total'] for row in regional_sales]}]\n}\nregion_chart = factory.create_clustered_column(region_data)\n\n# 图表 3：地区占比\nregion_pie_data = {\n    'labels': [row['region'] for row in regional_sales],\n    'values': [row['total'] for row in regional_sales]\n}\nregion_pie_chart = factory.create_pie(region_pie_data)\n\n# 图表 4：KPI 卡片\nkpi_data = {\n    'title': '本月销售额',\n    'value': f\"¥{sum(row['total'] for row in monthly_sales):,.0f}\",\n    'change': '+15.2%'\n}\nkpi_chart = factory.create_card(kpi_data)\n```\n\n#### 步骤 3：sql-report-generator 生成报告\n\n```python\nfrom sql_report_generator.scripts.interactive_components import (\n    ReportBuilder, TableChart, MatrixChart, SlicerComponent\n)\n\n# 创建表格\ntable = TableChart()\ntable_b64 = table.create({\n    'columns': ['订单ID', '客户', '地区', '金额', '日期'],\n    'rows': [[row['order_id'], row['customer_name'], row['region'], \n              f\"¥{row['sales']}\", row['order_date']] for row in orders],\n    'title': '订单明细'\n})\n\n# 创建切片器\nslicer = SlicerComponent()\nslicer_b64 = slicer.create({\n    'title': '地区筛选',\n    'options': ['全部', '北京', '上海', '广州', '深圳'],\n    'selected': '全部'\n})\n\n# 生成报告\nreport = ReportBuilder()\nreport.set_metadata(\n    title='月度销售报告',\n    author='销售部',\n    date='2026-03-26'\n)\n\n# 添加内容\nreport.add_title('月度销售报告', level=1)\nreport.add_text('本报告汇总了本月的销售业绩和地区分析。')\n\n# 关键指标\nreport.add_title('关键指标', level=2)\nreport.add_chart('本月销售额', kpi_chart)\n\n# 趋势分析\nreport.add_title('趋势分析', level=2)\nreport.add_chart('月度销售趋势', trend_chart, '销售额呈上升趋势')\n\n# 地区分析\nreport.add_title('地区分析', level=2)\nreport.add_chart('地区销售对比', region_chart)\nreport.add_chart('地区占比', region_pie_chart)\n\n# 明细数据\nreport.add_title('订单明细', level=2)\nreport.add_slicer(slicer_b64)\nreport.add_table('订单列表', table_b64)\n\n# 导出\nreport.export_html('monthly_sales_report.html')\nreport.export_json('monthly_sales_report.json')\n\nprint(\"✓ 报告已生成: monthly_sales_report.html\")\n```\n\n## 数据格式规范\n\n### sql-master 输出格式\n\n```python\n# 格式 1：列表字典\n[\n    {'month': '2026-01', 'total': 100000},\n    {'month': '2026-02', 'total': 120000},\n    {'month': '2026-03', 'total': 150000}\n]\n\n# 格式 2：DataFrame\nimport pandas as pd\ndf = pd.DataFrame({\n    'month': ['2026-01', '2026-02', '2026-03'],\n    'total': [100000, 120000, 150000]\n})\n\n# 格式 3：JSON\n{\n    \"data\": [\n        {\"month\": \"2026-01\", \"total\": 100000},\n        {\"month\": \"2026-02\", \"total\": 120000}\n    ]\n}\n```\n\n### sql-dataviz 输入格式\n\n```python\n# 对比类图表\n{\n    'categories': ['Q1', 'Q2', 'Q3', 'Q4'],\n    'series': [\n        {'name': '销售额', 'data': [100, 150, 120, 200]},\n        {'name': '成本', 'data': [60, 80, 70, 100]}\n    ]\n}\n\n# 占比类图表\n{\n    'labels': ['北京', '上海', '广州'],\n    'values': [35, 30, 35]\n}\n\n# 分布类图表\n{\n    'x': [1, 2, 3, 4, 5],\n    'y': [2, 4, 5, 4, 6],\n    'labels': ['A', 'B', 'C', 'D', 'E']\n}\n```\n\n### sql-dataviz 输出格式\n\n```python\n# Base64 PNG 字符串\n\"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\"\n\n# 可直接嵌入 HTML\nf'<img src=\"data:image/png;base64,{chart_b64}\" />'\n\n# 可直接嵌入 Markdown\nf'![chart](data:image/png;base64,{chart_b64})'\n```\n\n### sql-report-generator 输入格式\n\n```python\n# 图表\nchart_b64 = \"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\"\n\n# 表格\n{\n    'columns': ['订单ID', '客户', '金额'],\n    'rows': [\n        ['ORD001', '张三', '¥1,000'],\n        ['ORD002', '李四', '¥2,500']\n    ],\n    'title': '订单列表'\n}\n\n# 矩阵\n{\n    'rows': ['北京', '上海', '广州'],\n    'columns': ['Q1', 'Q2', 'Q3', 'Q4'],\n    'values': [\n        [100, 150, 120, 200],\n        [80, 120, 100, 180],\n        [60, 90, 80, 140]\n    ]\n}\n```\n\n## 性能优化建议\n\n### 1. 数据聚合（sql-master）\n\n```python\n# ✓ 好：在 SQL 中聚合\nSELECT DATE_TRUNC(date, MONTH) as month, SUM(sales) as total\nFROM orders\nGROUP BY month\n\n# ✗ 差：在 Python 中聚合\ndf = pd.read_sql(\"SELECT * FROM orders\", conn)\ndf.groupby(pd.Grouper(key='date', freq='M')).sum()\n```\n\n### 2. 数据采样（sql-dataviz）\n\n```python\n# 处理大数据集时采样\nimport pandas as pd\n\ndf = pd.read_sql(query, conn)\nif len(df) > 100000:\n    df = df.sample(n=10000)  # 采样 10000 行\n\nchart = factory.create_scatter({\n    'x': df['x'].tolist(),\n    'y': df['y'].tolist()\n})\n```\n\n### 3. 缓存机制（sql-report-generator）\n\n```python\nimport hashlib\nimport json\n\ndef get_report_cached(config, cache_dir='./cache'):\n    key = hashlib.md5(json.dumps(config).encode()).hexdigest()\n    cache_file = f\"{cache_dir}/report_{key}.html\"\n    \n    if os.path.exists(cache_file):\n        with open(cache_file, 'r') as f:\n            return f.read()\n    \n    # 生成新报告...\n    report = ReportBuilder()\n    # ...\n    html = report._generate_html()\n    \n    # 保存缓存\n    with open(cache_file, 'w') as f:\n        f.write(html)\n    \n    return html\n```\n\n## 错误处理\n\n```python\nfrom sql_master import SQLMaster\nfrom sql_dataviz.charts import ChartFactory\nfrom sql_report_generator.scripts.interactive_components import ReportBuilder\n\ntry:\n    # 1. 查询数据\n    sql = SQLMaster()\n    result = sql.execute_query(query)\n    \n    if not result:\n        raise ValueError(\"查询结果为空\")\n    \n    # 2. 生成图表\n    factory = ChartFactory()\n    chart = factory.create_line(data)\n    \n    if not chart:\n        raise ValueError(\"图表生成失败\")\n    \n    # 3. 生成报告\n    report = ReportBuilder()\n    report.add_chart('标题', chart)\n    report.export_html('report.html')\n    \nexcept ValueError as e:\n    print(f\"数据错误: {e}\")\nexcept Exception as e:\n    print(f\"未知错误: {e}\")\n    import traceback\n    traceback.print_exc()\n```\n\n## 常见问题\n\n### Q: 如何处理大数据集？\n\nA: 使用聚合和采样：\n\n```python\n# 在 SQL 中聚合\nresult = sql.execute_query(\"\"\"\n    SELECT DATE_TRUNC(date, DAY) as day, SUM(sales) as total\n    FROM orders\n    GROUP BY day\n\"\"\")\n\n# 或在 Python 中采样\nimport pandas as pd\ndf = pd.read_sql(query, conn)\ndf_sample = df.sample(n=min(10000, len(df)))\n```\n\n### Q: 如何自定义图表样式？\n\nA: 使用 ChartConfig：\n\n```python\nfrom sql_dataviz.charts import ChartFactory, ChartConfig, Theme\n\nconfig = ChartConfig(\n    width=1600,\n    height=800,\n    theme=Theme.ALIBABA,\n    font_size=13,\n    title_size=18\n)\n\nfactory = ChartFactory(config)\nchart = factory.create_line(data)\n```\n\n### Q: 如何导出为 PDF？\n\nA: 使用 sql-report-generator：\n\n```python\nreport = ReportBuilder()\n# ... 添加内容 ...\nreport.export_pdf('report.pdf')  # 需要安装 reportlab\n```\n\n## 总结\n\n| 阶段 | Skill | 输入 | 输出 | 示例 |\n|------|-------|------|------|------|\n| 数据 | sql-master | SQL 查询 | DataFrame/列表 | `execute_query()` |\n| 可视化 | sql-dataviz | DataFrame/字典 | Base64 PNG | `create_line()` |\n| 报告 | sql-report-generator | Base64 图表 | HTML/PDF | `export_html()` |\n\n通过三个 Skill 的协作，可以快速构建完整的数据分析流程，从 SQL 查询到最终报告生成。\n\nFile v1.0.1:references/line-area.md\n\n# 折线图 & 面积图\n\n适用场景：时间序列趋势、连续变量变化。\n\n---\n\n## 基础折线图\n\n```python\nimport matplotlib.pyplot as plt\nimport pandas as pd\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\n# df 列：date（datetime）, value（数值）\nfig, ax = plt.subplots(figsize=(12, 5))\n\nax.plot(df['date'], df['value'],\n        color='#3b82f6', linewidth=2,\n        marker='o', markersize=4, markerfacecolor='white', markeredgewidth=2)\n\n# 标注最大值和最小值\nmax_idx = df['value'].idxmax()\nmin_idx = df['value'].idxmin()\nax.annotate(f\"最高: {df.loc[max_idx,'value']:,.0f}\",\n            xy=(df.loc[max_idx,'date'], df.loc[max_idx,'value']),\n            xytext=(10, 10), textcoords='offset points',\n            fontsize=9, color='#10b981')\nax.annotate(f\"最低: {df.loc[min_idx,'value']:,.0f}\",\n            xy=(df.loc[min_idx,'date'], df.loc[min_idx,'value']),\n            xytext=(10, -15), textcoords='offset points',\n            fontsize=9, color='#ef4444')\n\nax.set_title('每日订单量趋势', fontsize=15, fontweight='bold', pad=12)\nax.set_xlabel('日期', fontsize=11)\nax.set_ylabel('订单量', fontsize=11)\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\nax.tick_params(axis='x', rotation=45)\n\nplt.tight_layout()\nplt.savefig('line_chart.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 多系列折线图（对比）\n\n```python\nPALETTE = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444']\n\nfig, ax = plt.subplots(figsize=(12, 5))\n\nfor i, col in enumerate(['series_a', 'series_b', 'series_c']):\n    ax.plot(df['date'], df[col],\n            label=col, color=PALETTE[i], linewidth=2)\n\nax.legend(loc='upper left', framealpha=0.9)\nax.set_title('多渠道订单量对比', fontsize=15, fontweight='bold')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\nax.tick_params(axis='x', rotation=45)\n\nplt.tight_layout()\nplt.savefig('multi_line.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 面积图（强调累计/量级）\n\n```python\nfig, ax = plt.subplots(figsize=(12, 5))\n\nax.fill_between(df['date'], df['value'],\n                alpha=0.3, color='#3b82f6')\nax.plot(df['date'], df['value'],\n        color='#3b82f6', linewidth=2)\n\nax.set_title('累计用户增长', fontsize=15, fontweight='bold')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('area_chart.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 折线图 + 柱状图组合（双轴）\n\n适用：同时展示绝对值（柱）和比率（线），如销售额 + 增长率。\n\n```python\nfig, ax1 = plt.subplots(figsize=(12, 5))\nax2 = ax1.twinx()\n\n# 柱状图（左轴）\nbars = ax1.bar(df['month'], df['revenue'],\n               color='#3b82f6', alpha=0.7, width=0.6, label='销售额')\nax1.set_ylabel('销售额（万元）', color='#3b82f6')\nax1.tick_params(axis='y', labelcolor='#3b82f6')\n\n# 折线图（右轴）\nline = ax2.plot(df['month'], df['growth_rate'],\n                color='#ef4444', linewidth=2, marker='o',\n                markersize=5, label='增长率')\nax2.set_ylabel('增长率（%）', color='#ef4444')\nax2.tick_params(axis='y', labelcolor='#ef4444')\nax2.axhline(y=0, color='#ef4444', linestyle='--', alpha=0.3)\n\n# 合并图例\nlines = [bars] + line\nlabels = [l.get_label() for l in lines]\nax1.legend(lines, labels, loc='upper left')\n\nax1.set_title('月度销售额与增长率', fontsize=15, fontweight='bold')\nax1.spines['top'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('combo_chart.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 注意事项\n- 时间轴数据点超过 60 个时，去掉 `marker`，避免密集\n- 多系列超过 5 条时，考虑用小多图（facet）代替\n- 双 Y 轴要谨慎：确保两个指标有真实业务关联，并在标题中说明\n\nArchive v1.0.0: 27 files, 105105 bytes\n\nFiles: charts/__init__.py (74361b), FINAL_COMPLETION_REPORT.md (5749b), FINAL_REPORT.md (10473b), FULL_MARKET_COMPARISON.md (8945b), IMPLEMENTATION_SUMMARY.md (10869b), PROJECT_CHECKLIST.md (7554b), QUICK_REFERENCE.md (6455b), references/bar-charts.md (4265b), references/canvas-render.md (2849b), references/chart-selection.md (3259b), references/dashboard.md (5213b), references/distribution.md (14610b), references/heatmap.md (21514b), references/INSTALLATION.md (7658b), references/INTEGRATION_GUIDE.md (12089b), references/line-area.md (3989b), references/plotly-interactive.md (4962b), references/scatter.md (17802b), requirements.txt (218b), scripts/demo.py (14257b), scripts/install_deps.sh (2233b), scripts/interactive_charts.py (50631b), SKILL.md (19487b), sql-dataviz/SKILL.md (6085b), SUPPLEMENT_CHECKLIST.md (7229b), VERIFICATION_REPORT.md (7656b), _meta.json (130b)\n\nFile v1.0.0:SKILL.md\n\n# sql-dataviz - SQL 数据可视化 Skill\n\n## ⚠️ 使用前必读\n\n本 Skill 需要 Python 依赖。**首次使用前必须安装依赖**：\n\n```bash\nskillhub_install install_skill sql-dataviz\n```\n\n工具会自动检测 Python3 环境、pip 可用性，并安装所有依赖。\n\n### 依赖安装方式\n\n| 方式 | 命令 | 适用场景 |\n|------|------|---------|\n| **自动安装（推荐）** | `skillhub_install install_skill sql-dataviz` | 一键安装，自动处理 |\n| **手动安装** | `pip install -r requirements.txt` | 熟悉 Python 环境的用户 |\n\n### 无依赖使用（受限模式）\n\n如果无法安装依赖，本 Skill 提供以下**降级能力**：\n\n✅ **可用功能**：\n- 图表选型建议（基于业务场景推荐图表类型）\n- 数据格式规范说明\n- 可视化设计原则指导\n- 配色方案推荐\n\n❌ **不可用功能**：\n- 图表生成（PNG/base64 输出）\n- 交互式 HTML 图表\n- Dashboard 构建\n- 与 sql-master / report-generator 联动\n\n---\n\n## 🔗 Skill 协作关系\n\n本 Skill 与 **sql-master**、**report-generator** 组成完整的数据分析流水线：\n\n```\n┌─────────────┐     ┌─────────────┐     ┌─────────────┐\n│ sql-master  │ ──► │ sql-dataviz │ ──► │report-gen   │\n│  (数据层)   │     │  (可视化层)  │     │  (报告层)   │\n└─────────────┘     └─────────────┘     └─────────────┘\n      │                   │                   │\n      ▼                   ▼                   ▼\n   SQL 查询           图表生成            HTML 报告\n   数据获取           PNG/HTML            AI 洞察\n   格式转换           Dashboard           数据表格\n```\n\n### 协作模式\n\n| 模式 | 组合 | 适用场景 |\n|------|------|---------|\n| **单独使用** | sql-dataviz | 已有数据，仅需图表可视化 |\n| **数据可视化** | sql-master + sql-dataviz | SQL 查询 → 图表输出 |\n| **可视化报告** | sql-dataviz + report-generator | 图表 → 报告（无 SQL） |\n| **完整流程** | sql-master + sql-dataviz + report-generator | 完整数据分析报告 |\n\n### 🥇 最优使用方式：三 Skill 串联\n\n```python\nfrom scripts.unified_pipeline import UnifiedPipeline\n\nresult = (\n    UnifiedPipeline(\"销售分析\")\n    .from_file(\"sales.csv\")                                    # sql-master: 数据获取\n    .query(\"SELECT region, SUM(sales) as total FROM data GROUP BY region\")\n    .interactive_chart(\"bar\", x_col=\"region\", y_col=\"total\")   # sql-dataviz: 可视化\n    .insights(value_cols=[\"total\"])                            # AI 洞察\n    .report(title=\"销售报告\", output=\"report.html\")            # report-generator: 报告\n)\n```\n\n### 决策指南\n\n```\n你需要什么？\n├─ 仅图表可视化 → sql-dataviz 单独使用\n├─ SQL + 图表 → sql-master + sql-dataviz\n├─ 图表 + 报告（无 SQL）→ sql-dataviz + report-generator\n└─ 完整分析报告 → sql-master + sql-dataviz + report-generator ✅ 推荐\n```\n\n---\n\n## 新增功能：交互式 HTML 图表（Plotly）\n\n### `scripts/interactive_charts.py`\n\n基于 Plotly 的 12 种交互式图表，输出自包含 HTML（支持 hover / zoom / pan）：\n\n```python\nfrom scripts.interactive_charts import InteractiveChartFactory, DashboardBuilder\n\nfactory = InteractiveChartFactory(theme=\"powerbi\")\n\n# 12 种图表类型\nhtml = factory.create_line(data)          # 折线图\nhtml = factory.create_bar(data)           # 柱形图\nhtml = factory.create_pie(data)           # 饼图（环形）\nhtml = factory.create_scatter(data)       # 散点图\nhtml = factory.create_heatmap(data)       # 热力图\nhtml = factory.create_funnel(data)        # 漏斗图\nhtml = factory.create_area(data)          # 面积图\nhtml = factory.create_treemap(data)       # 树状图\nhtml = factory.create_gauge(data)         # 仪表盘\nhtml = factory.create_combo(data)         # 组合图（柱+折线）\nhtml = factory.create_table(data)         # 交互式表格\nhtml = factory.create_kpi_cards(data)     # KPI 卡片组\n\nfactory.save_html(html, \"chart.html\")\n\n# 多图表 Dashboard\nbuilder = DashboardBuilder(title=\"销售看板\", theme=\"powerbi\")\nbuilder.add_kpi_cards([{\"title\":\"GMV\",\"value\":\"¥1,234万\",\"change\":\"+18%\"}])\nbuilder.add_chart(factory.create_line(...), title=\"月度趋势\", cols=2)\nbuilder.add_chart(factory.create_bar(...), title=\"区域对比\", cols=1)\nbuilder.build(\"dashboard.html\")\n```\n\n**数据格式** 与现有 ChartFactory 完全一致（line/bar/pie/scatter/funnel/area/combo/table）。\n\n**主题**：powerbi / dark / seaborn / ggplot2\n\n## 概述\n\n将 SQL 查询结果转化为**生产级可视化图表**。集成 Power BI 原生的 **50 种视觉对象**，支持对比、趋势、分布、占比、地理、指标监控、AI 智能分析、统计分析等全场景。\n\n所有图表以 **base64 编码的 PNG** 方式输出，可直接嵌入报告、邮件、Web 应用、Markdown 文档。\n\n## 核心能力矩阵\n\n### 1️⃣ 对比与趋势分析（13种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **簇状柱形图** | 多系列分类对比 | `create_clustered_column()` |\n| **堆积柱形图** | 整体+部分占比对比 | `create_stacked_column()` |\n| **100%堆积柱形图** | 统一尺度结构对比 | `create_percent_stacked_column()` |\n| **簇状条形图** | 长分类名称对比 | `create_clustered_bar()` |\n| **堆积条形图** | 区域/渠道层级对比 | `create_stacked_bar()` |\n| **100%堆积条形图** | 横向结构占比 | `create_percent_stacked_bar()` |\n| **折线图** | 连续数据趋势 | `create_line()` |\n| **平滑折线图** | 弱化波动的趋势 | `create_smooth_line()` |\n| **组合图** | 双指标（柱+折线） | `create_combo()` |\n| **面积图** | 累计总量展示 | `create_area()` |\n| **堆积面积图** | 多业务线累计贡献 | `create_stacked_area()` |\n| **瀑布图** | 增减项影响分析 | `create_waterfall()` |\n| **丝带图** | 排名变动追踪 | `create_line()` |\n\n### 2️⃣ 部分与整体（4种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **饼图** | 单维度占比 | `create_pie()` |\n| **圆环图** | 中心标签占比 | `create_donut()` |\n| **树状图** | 层级数据展示 | `create_treemap()` |\n| **漏斗图** | 流程转化分析 | `create_funnel()` |\n\n### 3️⃣ 分布与关系（4种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **散点图** | 两变量相关性 | `create_scatter()` |\n| **气泡图** | 三变量分析 | `create_bubble()` |\n| **点图** | 分类数据分布 | `create_dot()` |\n| **高密度散点图** | 海量数据聚类 | `create_high_density_scatter()` |\n\n### 4️⃣ 地理空间（4种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **Azure 地图** | 权威地图底图 | `create_azure_map()` |\n| **填充地图** | 区域数据热力 | `create_filled_map()` |\n| **形状地图** | 自定义边界分析 | `create_shape_map()` |\n| **ArcGIS 地图** | 专业空间分析 | `create_arcgis_map()` |\n\n### 5️⃣ 指标监控（5种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **卡片图** | 单一关键指标 | `create_card()` |\n| **多行卡片图** | 多指标汇总 | `create_multi_card()` |\n| **KPI 视觉对象** | 目标达成率 | `create_kpi()` |\n| **仪表盘图** | 指标健康度 | `create_gauge()` |\n| **目标视觉对象** | 团队绩效看板 | `create_target()` |\n\n### 6️⃣ AI 智能分析（4种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **分解树** | 多维度根因分析 | `create_decomposition_tree()` |\n| **关键影响因素** | 驱动因子权重 | `create_key_influencers()` |\n| **异常检测** | 自动异常标注 | `create_anomaly_detection()` |\n| **智能叙事** | 自然语言摘要 | `create_smart_narrative()` |\n\n### 7️⃣ 统计与分布（5种）**[新增]**\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **盒须图** | 数据分布四分位数 | `create_box_plot()` |\n| **直方图** | 数据频率分布 | `create_histogram()` |\n| **密度图** | 概率密度分布 | `create_density_plot()` |\n| **帕累托图** | 80/20 法则分析 | `create_pareto()` |\n| **Q-Q 图** | 正态性检验 | 通过 scipy 实现 |\n\n### 8️⃣ 关系与网络（2种）**[新增]**\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **网络图** | 节点关系展示 | `create_network_graph()` |\n| **桑基图** | 流量/能量流向 | `create_sankey()` |\n\n### 9️⃣ 时序与日期（3种）**[新增]**\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **甘特图** | 项目进度管理 | `create_gantt()` |\n| **日历热力图** | 时间序列热力 | `create_calendar_heatmap()` |\n| **蜡烛图** | 股票价格走势 | `create_candlestick()` |\n\n### 🔟 地理与热力（3种）**[新增]**\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **分级地图** | 区域数据热力 | `create_choropleth_map()` |\n| **路径地图** | 物流路径规划 | `create_route_map()` |\n| **点密度地图** | 点分布密度 | `create_dot_density_map()` |\n\n### 1️⃣1️⃣ 层级与占比（3种）**[新增]**\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **旭日图** | 多层级占比 | `create_sunburst()` |\n| **词云图** | 文本频率可视化 | `create_word_cloud()` |\n| **子弹图** | 目标对比 | `create_bullet()` |\n\n### 1️⃣2️⃣ 交互与辅助（4种）\n\n| 图表 | 场景 | 方法 |\n|------|------|------|\n| **图像视觉对象** | 品牌 logo、产品图片 | `create_image_visual()` |\n| **文本框与形状** | 报表标题、说明描述 | `create_text_shape()` |\n| **小型序列图** | 多个小图表并排 | `create_small_multiple()` |\n| **视觉对象栏** | 自定义布局 | `create_visual_canvas()` |\n\n## 快速开始\n\n### 基础用法\n\n```python\nfrom sql_dataviz.charts import ChartFactory, ChartConfig, Theme\n\n# 1. 创建工厂\nfactory = ChartFactory()\n\n# 2. 设置主题（可选）\nfactory.set_theme('powerbi')  # 或 'alibaba', 'tencent', 'bytedance'\n\n# 3. 准备数据\ndata = {\n    'categories': ['Q1', 'Q2', 'Q3', 'Q4'],\n    'series': [\n        {'name': '销售额', 'data': [100, 150, 120, 200]},\n        {'name': '成本', 'data': [60, 80, 70, 100]}\n    ]\n}\n\n# 4. 生成图表（base64 PNG）\nchart_b64 = factory.create_clustered_column(data)\n\n# 5. 嵌入到 HTML\nhtml = f'<img src=\"data:image/png;base64,{chart_b64}\" />'\n\n# 6. 或保存为文件\nimport base64\nwith open('chart.png', 'wb') as f:\n    f.write(base64.b64decode(chart_b64))\n```\n\n### 与 sql-master 协作\n\n```python\nfrom sql_master import SQLMaster\nfrom sql_dataviz.charts import ChartFactory\n\n# 1. 执行 SQL 查询\nsql_master = SQLMaster()\nresult = sql_master.execute_query(\"\"\"\n    SELECT quarter, SUM(sales) as total, SUM(cost) as cost\n    FROM orders\n    GROUP BY quarter\n    ORDER BY quarter\n\"\"\")\n\n# 2. 转换为图表数据格式\ndata = {\n    'categories': [row['quarter'] for row in result],\n    'series': [\n        {'name': '销售额', 'data': [row['total'] for row in result]},\n        {'name': '成本', 'data': [row['cost'] for row in result]}\n    ]\n}\n\n# 3. 生成可视化\nfactory = ChartFactory()\nchart_b64 = factory.create_clustered_column(data)\n```\n\n### 与 report-generator 协作\n\n```python\nfrom sql_dataviz.charts import ChartFactory\nfrom report_generator import ReportGenerator\n\n# 1. 生成多个图表\nfactory = ChartFactory()\ncharts = {\n    'sales_trend': factory.create_line(trend_data),\n    'channel_mix': factory.create_pie(channel_data),\n    'regional_heatmap': factory.create_filled_map(region_data)\n}\n\n# 2. 组织成报告\nreport = ReportGenerator()\nreport.add_title('月度业绩报告')\nreport.add_chart('销售趋势', charts['sales_trend'])\nreport.add_chart('渠道占比', charts['channel_mix'])\nreport.add_chart('区域热力', charts['regional_heatmap'])\nreport.export_html('report.html')\n```\n\n\n\n## 文件结构\n\n```\nsql-dataviz/\n├── SKILL.md                          # 本文件\n├── charts/\n│   ├── __init__.py                   # 24种图表实现（base64 PNG）\n│   ├── comparison.py                 # 对比类图表（可选扩展）\n│   ├── composition.py                # 占比类图表（可选扩展）\n│   ├── distribution.py               # 分布类图表（可选扩展）\n│   ├── geographic.py                 # 地理类图表（可选扩展）\n│   ├── kpi.py                        # 指标监控（可选扩展）\n│   └── ai_analysis.py                # AI 智能分析（可选扩展）\n├── scripts/\n│   ├── install_deps.sh               # 依赖安装脚本\n│   ├── demo.py                       # 完整演示脚本\n│   └── benchmark.py                  # 性能基准测试\n└── references/\n    ├── POWERBI_CHARTS.md             # Power BI 图表参考\n    ├── COLOR_SCHEMES.md              # 大厂配色方案\n    ├── DATA_FORMATS.md               # 数据格式规范\n    └── EXAMPLES.md                   # 完整示例库\n```\n\n## 配置选项\n\n### 主题与样式\n\n```python\nfrom sql_dataviz.charts import ChartFactory, ChartConfig, Theme\n\n# 方式1：工厂级设置\nfactory = ChartFactory()\nfactory.set_theme('powerbi')      # Power BI 官方蓝\nfactory.set_theme('alibaba')      # 阿里巴巴红\nfactory.set_theme('tencent')      # 腾讯蓝\nfactory.set_theme('bytedance')    # 字节跳动黑\nfactory.set_theme('neutral')      # 中性灰\n\n# 方式2：配置对象\nconfig = ChartConfig(\n    width=1200,\n    height=600,\n    dpi=100,\n    theme=Theme.POWERBI,\n    title='季度业绩分析',\n    show_legend=True,\n    show_grid=True,\n    font_size=11,\n    title_size=16\n)\nfactory = ChartFactory(config)\n```\n\n### 导出格式\n\n```python\n# 所有图表都支持 base64 PNG 输出\nchart_b64 = factory.create_line(data)\n\n# 嵌入 HTML\nhtml = f'<img src=\"data:image/png;base64,{chart_b64}\" />'\n\n# 嵌入 Markdown\nmarkdown = f'![chart](data:image/png;base64,{chart_b64})'\n\n# 保存为文件\nimport base64\nwith open('chart.png', 'wb') as f:\n    f.write(base64.b64decode(chart_b64))\n```\n\n## 常见问题\n\n### Q: 如何处理超大数据集（>100万行）？\n\nA: 使用高密度散点图或自动聚合：\n\n```python\n# 高密度散点图自动处理海量数据\nchart = factory.create_high_density_scatter({\n    'x': large_x_array,  # 100万+ 数据点\n    'y': large_y_array\n})\n\n# 或先聚合数据\nimport pandas as pd\ndf = pd.read_sql(query, conn)\ndf_agg = df.groupby('category').agg({'value': 'sum'}).reset_index()\nchart = factory.create_pie({\n    'labels': df_agg['category'],\n    'values': df_agg['value']\n})\n```\n\n### Q: 支持实时数据更新吗？\n\nA: 支持。通过定时查询 SQL 并重新生成图表：\n\n```python\nimport time\nfrom sql_master import SQLMaster\nfrom sql_dataviz.charts import ChartFactory\n\nsql = SQLMaster()\nfactory = ChartFactory()\n\nwhile True:\n    # 每分钟更新一次\n    result = sql.execute_query(\"SELECT * FROM metrics WHERE time > NOW() - INTERVAL 1 HOUR\")\n    chart = factory.create_line(transform_data(result))\n    save_chart(chart)\n    time.sleep(60)\n```\n\n### Q: 能否自定义图表样式？\n\nA: 完全支持。修改 `ChartConfig` 或直接编辑图表类：\n\n```python\n# 自定义配置\nconfig = ChartConfig(\n    width=1600,\n    height=800,\n    theme=Theme.ALIBABA,\n    font_size=13,\n    title_size=18,\n    show_grid=False\n)\n\n# 或继承图表类进行深度定制\nfrom sql_dataviz.charts import ClusteredColumnChart\n\nclass CustomColumnChart(ClusteredColumnChart):\n    def create(self, data):\n        fig, ax = self._setup_figure()\n        # 自定义绘制逻辑\n        ...\n        return self._to_base64(fig)\n```\n\n### Q: 如何在报告中使用这些图表？\n\nA: 与 report-generator 无缝协作：\n\n```python\nfrom report_generator import ReportGenerator\nfrom sql_dataviz.charts import ChartFactory\n\nreport = ReportGenerator()\nfactory = ChartFactory()\n\n# 添加图表\nreport.add_chart('销售趋势', factory.create_line(data))\nreport.add_chart('渠道占比', factory.create_pie(data))\n\n# 导出为 HTML/PDF\nreport.export_html('report.html')\nreport.export_pdf('report.pdf')\n```\n\n## 性能指标\n\n| 操作 | 耗时 | 内存 |\n|------|------|------|\n| 生成简单柱形图 | ~50ms | ~5MB |\n| 生成复杂仪表盘（4图） | ~200ms | ~20MB |\n| 处理100万数据点散点图 | ~500ms | ~50MB |\n| 生成完整报告（10图） | ~1s | ~100MB |\n\n## 与其他 Skill 的协作\n\n### sql-master → sql-dataviz → report-generator\n\n```\nSQL 查询 → 数据转换 → 可视化 → 报告生成\n```\n\n**完整流程示例：**\n\n```python\n# 1. sql-master：执行查询\nfrom sql_master import SQLMaster\nsql = SQLMaster()\nsales_data = sql.execute_query(\"\"\"\n    SELECT region, product, SUM(sales) as total\n    FROM orders\n    GROUP BY region, product\n\"\"\")\n\n# 2. sql-dataviz：生成可视化\nfrom sql_dataviz.charts import ChartFactory\nfactory = ChartFactory()\nfactory.set_theme('powerbi')\n\n# 按地区对比\nregional_chart = factory.create_clustered_column({\n    'categories': [row['region'] for row in sales_data],\n    'series': [{'name': 'Sales', 'data': [row['total'] for row in sales_data]}]\n})\n\n# 3. report-generator：组织报告\nfrom report_generator import ReportGenerator\nreport = ReportGenerator()\nreport.add_title('销售分析报告')\nreport.add_chart('地区销售对比', regional_chart)\nreport.export_html('sales_report.html')\n```\n\n## 最佳实践\n\n### 1. 选择合适的图表类型\n\n```python\n# ✓ 对比分析 → 簇状柱形图\nfactory.create_clustered_column(data)\n\n# ✓ 趋势分析 → 折线图\nfactory.create_line(data)\n\n# ✓ 占比分析 → 饼图/圆环图\nfactory.create_pie(data)\n\n# ✓ 分布分析 → 散点图/气泡图\nfactory.create_scatter(data)\n\n# ✓ 流程分析 → 漏斗图\nfactory.create_funnel(data)\n```\n\n### 2. 数据预处理\n\n```python\nimport pandas as pd\n\n# 清理数据\ndf = pd.read_sql(query, conn)\ndf = df.dropna()\ndf = df[df['value'] > 0]\n\n# 聚合数据\ndf_agg = df.groupby('category').agg({\n    'value': 'sum',\n    'count': 'count'\n}).reset_index()\n\n# 转换为图表格式\ndata = {\n    'categories': df_agg['category'].tolist(),\n    'series': [{'name': 'Value', 'data': df_agg['value'].tolist()}]\n}\n```\n\n### 3. 缓存机制\n\n```python\nimport hashlib\nimport json\n\ndef get_chart_cached(chart_type, data, cache_dir='./cache'):\n    # 生成缓存键\n    key = hashlib.md5(json.dumps(data).encode()).hexdigest()\n    cache_file = f\"{cache_dir}/{chart_type}_{key}.b64\"\n    \n    # 检查缓存\n    try:\n        with open(cache_file, 'r') as f:\n            return f.read()\n    except FileNotFoundError:\n        pass\n    \n    # 生成新图表\n    factory = ChartFactory()\n    chart = getattr(factory, f'create_{chart_type}')(data)\n    \n    # 保存缓存\n    with open(cache_file, 'w') as f:\n        f.write(chart)\n    \n    return chart\n```\n\n## 许可证\n\nMIT License - 生产级可商用\n\n## 更新日志\n\n- **v1.0.0** (2026-03-26) - 初始版本，支持 24 种图表，base64 PNG 输出\n- **v1.1.0** (计划) - 支持 SVG 矢量输出、交互式 HTML、实时数据流\n- **v2.0.0** (计划) - 集成 Plotly 交互式图表、WebGL 高性能渲染\n\n## 支持与反馈\n\n- 📧 Email: support@example.com\n- 💬 Discord: https://discord.gg/example\n- 🐛 Issues: https://github.com/example/sql-dataviz/issues\n\nFile v1.0.0:sql-dataviz/SKILL.md\n\n# sql-dataviz - SQL 数据可视化 Skill\n\n## 概述\n\n将 SQL 查询结果转化为**生产级可视化图表**。集成 Power BI 原生的 24+ 种视觉对象，支持对比、趋势、分布、占比、地理、指标监控、AI 智能分析等全场景。\n\n所有图表以 **base64 编码的 PNG/SVG** 方式输出，可直接嵌入报告、邮件、Web 应用。\n\n## 核心能力\n\n### 1. 对比与趋势分析（8种）\n- **簇状柱形图** - 多系列分类对比\n- **堆积柱形图** - 整体+部分占比对比\n- **100%堆积柱形图** - 统一尺度结构对比\n- **簇状条形图** - 长分类名称对比\n- **堆积条形图** - 区域/渠道层级对比\n- **100%堆积条形图** - 横向结构占比\n- **折线图** - 连续数据趋势\n- **平滑折线图** - 弱化波动的趋势\n\n### 2. 高级趋势（5种）\n- **组合图** - 双指标（柱+折线）\n- **面积图** - 累计总量展示\n- **堆积面积图** - 多系列累计贡献\n- **瀑布图** - 增减项影响分析\n- **丝带图** - 排名变动追踪\n\n### 3. 部分与整体（4种）\n- **饼图** - 单维度占比\n- **圆环图** - 中心标签占比\n- **树状图** - 层级数据展示\n- **漏斗图** - 流程转化分析\n\n### 4. 分布与关系（4种）\n- **散点图** - 两变量相关性\n- **气泡图** - 三变量分析\n- **点图** - 分类数据分布\n- **高密度散点图** - 海量数据聚类\n\n### 5. 地理空间（3种）\n- **填充地图** - 区域数据热力\n- **形状地图** - 自定义边界分析\n- **ArcGIS 地图** - 专业空间分析\n\n### 6. 指标监控（3种）\n- **卡片图** - 单一关键指标\n- **KPI 视觉对象** - 目标达成率\n- **仪表盘图** - 指标健康度\n\n### 7. AI 智能分析（4种）\n- **分解树** - 多维度根因分析\n- **关键影响因素** - 驱动因子权重\n- **异常检测** - 自动异常标注\n- **智能叙事** - 自然语言摘要\n\n## 使用方式\n\n### 基础用法\n\n```python\nfrom sql_dataviz import ChartFactory\n\n# 创建图表工厂\nfactory = ChartFactory()\n\n# 从 SQL 结果生成图表\ndata = {\n    'categories': ['Q1', 'Q2', 'Q3', 'Q4'],\n    'series': [\n        {'name': '销售额', 'data': [100, 150, 120, 200]},\n        {'name': '成本', 'data': [60, 80, 70, 100]}\n    ]\n}\n\n# 生成簇状柱形图（base64）\nchart_b64 = factory.create_clustered_column(data)\n\n# 输出为 HTML 可嵌入\nhtml = f'<img src=\"data:image/png;base64,{chart_b64}\" />'\n```\n\n### 高级用法 - 组合分析\n\n```python\n# 多图表联动\ndashboard = factory.create_dashboard({\n    'title': '季度业绩分析',\n    'charts': [\n        {'type': 'clustered_column', 'data': sales_data, 'position': (0, 0)},\n        {'type': 'pie', 'data': channel_data, 'position': (1, 0)},\n        {'type': 'line', 'data': trend_data, 'position': (0, 1)},\n        {'type': 'heatmap', 'data': region_data, 'position': (1, 1)}\n    ]\n})\n```\n\n## 依赖安装\n\n### 自动安装（推荐）\n\n```bash\n# 使用 SkillHub 一键安装\nskillhub_install install_skill sql-dataviz\n```\n\n### 手动安装\n\n```bash\n# 1. 安装 Python 依赖\npip install matplotlib seaborn plotly pandas numpy\n\n# 2. 安装可选的地理数据库\npip install geopandas shapely\n\n# 3. 验证安装\npython -c \"import matplotlib; print(matplotlib.__version__)\"\n```\n\n## 文件结构\n\n```\nsql-dataviz/\n├── SKILL.md                          # 本文件\n├── charts/\n│   ├── __init__.py\n│   ├── comparison.py                 # 对比类图表\n│   ├── trend.py                      # 趋势类图表\n│   ├── composition.py                # 占比类图表\n│   ├── distribution.py               # 分布类图表\n│   ├── geographic.py                 # 地理类图表\n│   ├── kpi.py                        # 指标监控\n│   ├── ai_analysis.py                # AI 智能分析\n│   └── base.py                       # 基类与工具函数\n├── scripts/\n│   ├── install_deps.sh               # 依赖安装脚本\n│   └── demo.py                       # 演示脚本\n└── references/\n    ├── POWERBI_CHARTS.md             # Power BI 图表参考\n    └── COLOR_SCHEMES.md              # 大厂配色方案\n```\n\n## 配置选项\n\n### 主题与样式\n\n```python\n# 内置主题\nfactory.set_theme('powerbi')      # Power BI 官方配色\nfactory.set_theme('alibaba')      # 阿里巴巴配色\nfactory.set_theme('tencent')      # 腾讯配色\nfactory.set_theme('bytedance')    # 字节跳动配色\n```\n\n### 导出格式\n\n```python\n# 支持多种输出格式\nchart_b64 = factory.export_base64()    # Base64 PNG\nchart_svg = factory.export_svg()       # SVG 矢量\nchart_html = factory.export_html()     # 交互式 HTML\n```\n\n## 与其他 Skill 的协作\n\n### 与 sql-master 协作\n\n```python\n# sql-master 提供 SQL 查询结果\nquery_result = sql_master.execute_query(\n    \"SELECT region, SUM(sales) as total FROM orders GROUP BY region\"\n)\n\n# sql-dataviz 进行可视化\nchart = dataviz.create_pie(query_result)\n```\n\n### 与 report-generator 协作\n\n```python\n# sql-dataviz 生成图表\ncharts = dataviz.create_dashboard(data)\n\n# report-generator 组织成报告\nreport = report_generator.create_report({\n    'title': '月度业绩报告',\n    'charts': charts,\n    'tables': tables\n})\n```\n\n## 性能优化\n\n- **大数据集**：自动采样 + 聚合，保留关键信息\n- **缓存机制**：相同查询结果缓存 1 小时\n- **异步渲染**：支持后台生成，前台异步加载\n- **流式输出**：支持分页报表流式生成\n\n## 常见问题\n\n**Q: 如何处理超大数据集（>100万行）？**\nA: 使用高密度散点图或自动聚合功能，系统会智能采样保留关键分布特征。\n\n**Q: 支持实时数据更新吗？**\nA: 支持。通过 WebSocket 连接 SQL 数据源，图表自动刷新。\n\n**Q: 能否自定义图表样式？**\nA: 完全支持。提供 CSS/JSON 配置接口，可自定义颜色、字体、动画等。\n\n## 许可证\n\nMIT License - 生产级可商用\n\n## 更新日志\n\n- **v1.0.0** (2026-03-26) - 初始版本，支持 24+ 种图表\n\nFile v1.0.0:_meta.json\n\n{\n  \"ownerId\": \"kn76k6338wpqydkxgdztg6vb9x83hz20\",\n  \"slug\": \"sql-dataviz\",\n  \"version\": \"1.0.0\",\n  \"publishedAt\": 1774589154253\n}\n\nFile v1.0.0:references/bar-charts.md\n\n# 条形图 & 横向条形图\n\n适用场景：分类比较、排名展示。\n\n---\n\n## 纵向条形图（类别 ≤ 10）\n\n```python\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nfig, ax = plt.subplots(figsize=(10, 6))\n\nbars = ax.bar(df['category'], df['value'],\n              color='#3b82f6', width=0.6, edgecolor='white')\n\n# 柱顶标注数值\nfor bar in bars:\n    h = bar.get_height()\n    ax.text(bar.get_x() + bar.get_width()/2, h + max(df['value'])*0.01,\n            f'{h:,.0f}', ha='center', va='bottom', fontsize=10)\n\nax.set_title('各品类销售额', fontsize=15, fontweight='bold', pad=12)\nax.set_xlabel('品类')\nax.set_ylabel('销售额（万元）')\nax.set_ylim(0, max(df['value']) * 1.15)  # 留出标注空间\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('bar_chart.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 横向条形图（排名 / 类别多 / 名称长）\n\n```python\n# 按值排序，最大值在顶部\ndf_sorted = df.sort_values('value', ascending=True)\n\nfig, ax = plt.subplots(figsize=(10, max(6, len(df_sorted) * 0.4)))\n\n# 高亮 Top 1\ncolors = ['#ef4444' if i == len(df_sorted)-1 else '#3b82f6'\n          for i in range(len(df_sorted))]\n\nbars = ax.barh(df_sorted['name'], df_sorted['value'],\n               color=colors, height=0.6)\n\n# 右侧标注数值\nfor bar in bars:\n    w = bar.get_width()\n    ax.text(w + max(df_sorted['value'])*0.01, bar.get_y() + bar.get_height()/2,\n            f'{w:,.0f}', va='center', fontsize=10)\n\nax.set_title('Top 用户消费排名', fontsize=15, fontweight='bold', pad=12)\nax.set_xlabel('消费金额（元）')\nax.set_xlim(0, max(df_sorted['value']) * 1.12)\nax.grid(axis='x', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('bar_horizontal.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 分组条形图（多系列对比）\n\n```python\n# df 列：month, group_a, group_b, group_c\ncategories = df['month'].tolist()\nx = np.arange(len(categories))\nwidth = 0.25\nPALETTE = ['#3b82f6', '#10b981', '#f59e0b']\n\nfig, ax = plt.subplots(figsize=(12, 6))\n\nfor i, (col, label) in enumerate([('group_a', 'PC端'), ('group_b', '移动端'), ('group_c', '小程序')]):\n    offset = (i - 1) * width\n    bars = ax.bar(x + offset, df[col], width, label=label,\n                  color=PALETTE[i], edgecolor='white')\n\nax.set_xticks(x)\nax.set_xticklabels(categories)\nax.legend()\nax.set_title('各渠道月度订单量对比', fontsize=15, fontweight='bold')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('grouped_bar.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 堆叠条形图（占比构成）\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\nPALETTE = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444']\n\nbottom = np.zeros(len(df))\nfor i, col in enumerate(['cat_a', 'cat_b', 'cat_c', 'cat_d']):\n    ax.bar(df['month'], df[col], bottom=bottom,\n           label=col, color=PALETTE[i], edgecolor='white', linewidth=0.5)\n    bottom += df[col].values\n\nax.legend(loc='upper left')\nax.set_title('各品类月度销售额构成', fontsize=15, fontweight='bold')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('stacked_bar.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 百分比堆叠条形图\n\n```python\n# 先计算百分比\ncols = ['cat_a', 'cat_b', 'cat_c']\ndf_pct = df[cols].div(df[cols].sum(axis=1), axis=0) * 100\n\nfig, ax = plt.subplots(figsize=(12, 6))\nbottom = np.zeros(len(df_pct))\n\nfor i, col in enumerate(cols):\n    ax.bar(df['month'], df_pct[col], bottom=bottom,\n           label=col, color=PALETTE[i], edgecolor='white')\n    bottom += df_pct[col].values\n\nax.set_ylim(0, 100)\nax.set_ylabel('占比（%）')\nax.legend(loc='upper left')\nax.set_title('各品类月度销售额占比', fontsize=15, fontweight='bold')\n\nplt.tight_layout()\nplt.savefig('stacked_pct.png', dpi=150, bbox_inches='tight')\n```\n\nFile v1.0.0:references/canvas-render.md\n\n# Canvas 内嵌渲染\n\n在对话中直接渲染图表，无需保存文件，用户即时看到结果。\n\n---\n\n## 什么时候用 Canvas 渲染\n\n- 用户想在对话里直接看图，不想保存文件\n- 快速验证图表效果\n- 演示/汇报场景，需要即时展示\n\n---\n\n## 使用方式\n\n通过 `canvas` 工具的 `eval` action 执行 JavaScript，渲染 Chart.js 图表。\n\n### 折线图示例\n\n```javascript\n// canvas eval 内容\nconst ctx = document.getElementById('chart').getContext('2d');\nnew Chart(ctx, {\n  type: 'line',\n  data: {\n    labels: ['1月', '2月', '3月', '4月', '5月', '6月'],\n    datasets: [{\n      label: '订单量',\n      data: [1200, 1900, 1500, 2100, 2400, 2800],\n      borderColor: '#3b82f6',\n      backgroundColor: 'rgba(59,130,246,0.1)',\n      borderWidth: 2,\n      fill: true,\n      tension: 0.4,\n      pointRadius: 4\n    }]\n  },\n  options: {\n    responsive: true,\n    plugins: {\n      title: { display: true, text: '月度订单量趋势', font: { size: 16 } },\n      legend: { position: 'top' }\n    },\n    scales: {\n      y: { beginAtZero: true, grid: { color: 'rgba(0,0,0,0.05)' } }\n    }\n  }\n});\n```\n\n### Canvas HTML 模板\n\n```html\n<!DOCTYPE html>\n<html>\n<head>\n  <script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>\n  <style>\n    body { font-family: 'Microsoft YaHei', sans-serif; padding: 20px; background: #fff; }\n    .chart-container { max-width: 800px; margin: 0 auto; }\n  </style>\n</head>\n<body>\n  <div class=\"chart-container\">\n    <canvas id=\"chart\"></canvas>\n  </div>\n  <script>\n    // 在这里放图表代码\n  </script>\n</body>\n</html>\n```\n\n---\n\n## Chart.js 常用图表类型\n\n| type 值 | 图表类型 |\n|---------|---------|\n| `'line'` | 折线图 |\n| `'bar'` | 条形图（纵向） |\n| `'bar'` + `indexAxis: 'y'` | 横向条形图 |\n| `'pie'` | 饼图（慎用） |\n| `'doughnut'` | 环形图 |\n| `'scatter'` | 散点图 |\n| `'bubble'` | 气泡图 |\n| `'radar'` | 雷达图 |\n\n---\n\n## 多系列条形图示例\n\n```javascript\nnew Chart(ctx, {\n  type: 'bar',\n  data: {\n    labels: ['Q1', 'Q2', 'Q3', 'Q4'],\n    datasets: [\n      {\n        label: 'PC端',\n        data: [3200, 4100, 3800, 5200],\n        backgroundColor: '#3b82f6'\n      },\n      {\n        label: '移动端',\n        data: [5100, 6200, 7100, 8900],\n        backgroundColor: '#10b981'\n      }\n    ]\n  },\n  options: {\n    responsive: true,\n    plugins: {\n      title: { display: true, text: '各渠道季度订单量' }\n    },\n    scales: { y: { beginAtZero: true } }\n  }\n});\n```\n\n---\n\n## 注意事项\n\n- Canvas 渲染依赖网络加载 Chart.js CDN，离线环境需本地引入\n- 数据量大时（>1000 点），建议先聚合再渲染，避免卡顿\n- 中文字体在 Canvas 中需要系统已安装对应字体\n- 复杂统计图（箱线图、小提琴图）建议用 Python matplotlib 生成图片，再展示\n\nFile v1.0.0:references/chart-selection.md\n\n# 图表选型决策指南\n\n## 核心问题：你想表达什么？\n\n拿到数据后，先问自己这个问题，再选图表。\n\n---\n\n## 决策树\n\n```\n数据是什么关系？\n│\n├── 随时间变化？\n│   ├── 连续时间序列 → 折线图\n│   ├── 离散时间点比较 → 分组条形图\n│   └── 累计/占比随时间变化 → 堆叠面积图\n│\n├── 分类之间比较？\n│   ├── 类别 ≤ 10 → 纵向条形图\n│   ├── 类别 > 10 或名称较长 → 横向条形图\n│   ├── 多组对比 → 分组条形图\n│   └── 排名展示 → 横向条形图（降序）\n│\n├── 整体中各部分占比？\n│   ├── 类别 ≤ 5 → 堆叠条形图（推荐）或饼图\n│   ├── 类别 > 5 → 矩形树图（Treemap）\n│   └── 占比随时间变化 → 堆叠面积图（百分比）\n│\n├── 数值分布？\n│   ├── 单变量分布 → 直方图\n│   ├── 多组分布对比 → 箱线图 / 小提琴图\n│   └── 密度估计 → KDE 图\n│\n├── 两变量关系？\n│   ├── 相关性探索 → 散点图\n│   ├── 带趋势线 → 回归散点图\n│   └── 多变量相关矩阵 → 热力图\n│\n├── 地理分布？\n│   └── 地图（Choropleth / 气泡地图）\n│\n├── 流向/转化？\n│   ├── 用户转化漏斗 → 漏斗图\n│   └── 流量流向 → 桑基图（Sankey）\n│\n└── 单一关键指标？\n    └── 大数字 KPI 卡片（不需要图表）\n```\n\n---\n\n## 常见场景速查\n\n| 业务场景 | 推荐图表 | 示例 |\n|---------|---------|------|\n| 日/周/月销售趋势 | 折线图 | 近 30 天 GMV |\n| 各品类销售额对比 | 横向条形图 | Top 10 品类 |\n| 用户地区分布 | 横向条形图 / 地图 | 各省用户数 |\n| 订单金额分布 | 直方图 | 0-100/100-500/500+ |\n| 各渠道转化率对比 | 分组条形图 | PC vs 移动端 |\n| 用户留存率 | 热力图（Cohort） | 按注册周分组 |\n| 指标相关性 | 热力图 | 价格/销量/评分 |\n| 漏斗转化 | 漏斗图 | 曝光→点击→购买 |\n| 月度环比增长 | 折线图 + 柱状图组合 | 销售额 + 增长率 |\n| 市场份额 | 堆叠条形图 | 各品牌占比 |\n\n---\n\n## 反模式（常见错误）\n\n### ❌ 饼图滥用\n```\n错误：用饼图展示 10 个品类的销售占比\n原因：人眼无法准确比较扇形大小\n正确：横向条形图，按值排序\n```\n\n### ❌ 双 Y 轴滥用\n```\n错误：左轴销售额（万元），右轴增长率（%），两条线看起来相关\n原因：双 Y 轴可以通过调整比例制造任意\"相关性\"\n正确：分两张图，或用散点图展示真实相关性\n```\n\n### ❌ 截断 Y 轴\n```\n错误：条形图 Y 轴从 95 开始，让微小差异看起来很大\n原因：视觉误导\n正确：Y 轴从 0 开始；如果确实需要放大差异，用折线图并明确标注\n```\n\n### ❌ 3D 图表\n```\n错误：3D 饼图、3D 条形图\n原因：透视变形导致读值不准\n正确：永远用 2D\n```\n\n### ❌ 彩虹配色\n```\n错误：每个柱子用不同颜色，没有语义\n原因：颜色应该传达信息，不是装饰\n正确：同类数据用同色；用颜色高亮重点数据\n```\n\nFile v1.0.0:references/dashboard.md\n\n# 多图面板 / Dashboard\n\n适用场景：需要在一张图里展示多个维度，或生成完整的数据报告。\n\n---\n\n## matplotlib 多图面板\n\n```python\nimport matplotlib.pyplot as plt\nimport matplotlib.gridspec as gridspec\nimport seaborn as sns\nimport pandas as pd\nimport numpy as np\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nfig = plt.figure(figsize=(16, 10))\nfig.suptitle('业务数据周报', fontsize=20, fontweight='bold', y=0.98)\n\n# 使用 GridSpec 灵活布局\ngs = gridspec.GridSpec(2, 3, figure=fig, hspace=0.4, wspace=0.35)\n\n# ── 左上（跨2列）：趋势折线图 ──\nax1 = fig.add_subplot(gs[0, :2])\nax1.plot(df_trend['date'], df_trend['orders'], color='#3b82f6', linewidth=2)\nax1.fill_between(df_trend['date'], df_trend['orders'], alpha=0.1, color='#3b82f6')\nax1.set_title('近30天订单量趋势', fontweight='bold')\nax1.grid(axis='y', alpha=0.3)\nax1.spines['top'].set_visible(False)\nax1.spines['right'].set_visible(False)\nax1.tick_params(axis='x', rotation=45)\n\n# ── 右上：KPI 卡片 ──\nax2 = fig.add_subplot(gs[0, 2])\nax2.axis('off')\nkpis = [\n    ('总订单量', '12,450', '+8.3%', '#10b981'),\n    ('总营收', '¥234万', '+12.1%', '#10b981'),\n    ('客单价', '¥188', '-2.4%', '#ef4444'),\n]\nfor i, (label, value, change, color) in enumerate(kpis):\n    y_pos = 0.85 - i * 0.3\n    ax2.text(0.1, y_pos, label, fontsize=10, color='#6b7280', transform=ax2.transAxes)\n    ax2.text(0.1, y_pos - 0.1, value, fontsize=18, fontweight='bold', transform=ax2.transAxes)\n    ax2.text(0.7, y_pos - 0.1, change, fontsize=12, color=color, transform=ax2.transAxes)\nax2.set_title('核心指标', fontweight='bold')\n\n# ── 左下：品类条形图 ──\nax3 = fig.add_subplot(gs[1, 0])\ndf_cat_sorted = df_cat.sort_values('value', ascending=True)\nax3.barh(df_cat_sorted['name'], df_cat_sorted['value'], color='#3b82f6', height=0.6)\nax3.set_title('品类销售额 Top 5', fontweight='bold')\nax3.spines['top'].set_visible(False)\nax3.spines['right'].set_visible(False)\n\n# ── 中下：金额分布直方图 ──\nax4 = fig.add_subplot(gs[1, 1])\nax4.hist(df_orders['amount'], bins=20, color='#f59e0b', edgecolor='white')\nax4.set_title('订单金额分布', fontweight='bold')\nax4.set_xlabel('金额（元）')\nax4.spines['top'].set_visible(False)\nax4.spines['right'].set_visible(False)\n\n# ── 右下：渠道占比堆叠 ──\nax5 = fig.add_subplot(gs[1, 2])\nbottom = np.zeros(len(df_channel))\nfor col, color in zip(['pc', 'mobile', 'mini'], ['#3b82f6', '#10b981', '#f59e0b']):\n    ax5.bar(df_channel['month'], df_channel[col], bottom=bottom,\n            label=col, color=color, edgecolor='white')\n    bottom += df_channel[col].values\nax5.legend(fontsize=8)\nax5.set_title('渠道构成', fontweight='bold')\nax5.spines['top'].set_visible(False)\nax5.spines['right'].set_visible(False)\n\nplt.savefig('weekly_report.png', dpi=150, bbox_inches='tight')\nprint(\"报告已保存：weekly_report.png\")\n```\n\n---\n\n## 自动化报告生成（SQL → 图表 → PDF）\n\n```python\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom matplotlib.backends.backend_pdf import PdfPages\nimport sqlite3\nfrom datetime import datetime\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nconn = sqlite3.connect('mydb.sqlite')\n\n# 查询数据\ndf_trend = pd.read_sql(\"\"\"\n    SELECT DATE(created_at) as date, COUNT(*) as orders, SUM(amount) as revenue\n    FROM orders WHERE created_at >= DATE('now', '-30 days')\n    GROUP BY DATE(created_at) ORDER BY date\n\"\"\", conn)\n\ndf_cat = pd.read_sql(\"\"\"\n    SELECT category, SUM(amount) as revenue\n    FROM orders WHERE created_at >= DATE('now', '-30 days')\n    GROUP BY category ORDER BY revenue DESC LIMIT 10\n\"\"\", conn)\n\nconn.close()\n\n# 生成 PDF 报告\nwith PdfPages(f'report_{datetime.now().strftime(\"%Y%m%d\")}.pdf') as pdf:\n\n    # 第1页：趋势\n    fig, ax = plt.subplots(figsize=(12, 5))\n    ax.plot(pd.to_datetime(df_trend['date']), df_trend['revenue'],\n            color='#3b82f6', linewidth=2)\n    ax.set_title('近30天营收趋势', fontsize=14, fontweight='bold')\n    ax.grid(axis='y', alpha=0.3)\n    plt.tight_layout()\n    pdf.savefig(fig)\n    plt.close()\n\n    # 第2页：品类排名\n    fig, ax = plt.subplots(figsize=(10, 7))\n    df_sorted = df_cat.sort_values('revenue', ascending=True)\n    ax.barh(df_sorted['category'], df_sorted['revenue'], color='#10b981')\n    ax.set_title('品类营收排名', fontsize=14, fontweight='bold')\n    plt.tight_layout()\n    pdf.savefig(fig)\n    plt.close()\n\n    # PDF 元数据\n    d = pdf.infodict()\n    d['Title'] = '业务数据报告'\n    d['Author'] = 'SQL DataViz'\n    d['CreationDate'] = datetime.now()\n\nprint(f\"PDF 报告已生成：report_{datetime.now().strftime('%Y%m%d')}.pdf\")\n```\n\n---\n\n## 布局建议\n\n| 图表数量 | 推荐布局 | figsize |\n|---------|---------|---------|\n| 2 张 | 1×2 或 2×1 | (14, 5) 或 (8, 10) |\n| 4 张 | 2×2 | (14, 10) |\n| 6 张 | 2×3 或 3×2 | (16, 10) |\n| 混合（大+小） | GridSpec 自定义 | 按需 |\n\n**原则：** 最重要的图放左上角（视线自然落点），KPI 卡片放右上角，细节图放下方。\n\nFile v1.0.0:references/distribution.md\n\n# 分布图 — 直方图、箱线图、小提琴图、密度图\n\n适用场景：展示数值分布、识别异常值、多组分布对比。\n\n---\n\n## 核心问题：你想展示什么样的分布？\n\n| 问题 | 推荐图表 |\n|------|---------|\n| 单变量分布频率？ | 直方图 |\n| 中位数、四分位、异常值？ | 箱线图 |\n| 分布形状 + 密度？ | 小提琴图 / KDE |\n| 多组分布对比？ | 箱线图 / 小提琴图 |\n| 分布是否正态？ | 直方图 + KDE + QQ图 |\n\n---\n\n## 一、直方图（Histogram）\n\n### 基础直方图\n\n```python\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nfig, ax = plt.subplots(figsize=(10, 6))\n\n# 自动 bins 或指定\nn, bins, patches = ax.hist(df['value'], bins=30,\n                           color='#3b82f6', edgecolor='white', alpha=0.8)\n\nax.set_title('订单金额分布', fontsize=15, fontweight='bold', pad=12)\nax.set_xlabel('金额（元）')\nax.set_ylabel('频数')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('histogram.png', dpi=150, bbox_inches='tight')\n```\n\n### Bins 数量选择\n\n```python\n# 方法1：Sturges 公式（适合正态分布）\nbins_sturges = int(np.log2(len(df)) + 1)\n\n# 方法2：Freedman-Diaconis 公式（适合偏态分布，推荐）\nq75, q25 = np.percentile(df['value'], [75, 25])\niqr = q75 - q25\nbin_width = 2 * iqr / (len(df) ** (1/3))\nbins_fd = int((df['value'].max() - df['value'].min()) / bin_width)\n\n# 方法3：Square root（简单快速）\nbins_sqrt = int(np.sqrt(len(df)))\n\nprint(f\"Sturges: {bins_sturges}, FD: {bins_fd}, Sqrt: {bins_sqrt}\")\n```\n\n**生产级建议：**\n- 数据量 < 100：bins = 10~15\n- 数据量 100~10000：使用 FD 公式\n- 数据量 > 10000：bins = 50~100，或使用 KDE\n\n### 直方图 + KDE（密度曲线）\n\n```python\nimport seaborn as sns\n\nfig, ax = plt.subplots(figsize=(10, 6))\n\n# 直方图（密度归一化）\nsns.histplot(df['value'], bins=30, kde=True,\n             color='#3b82f6', edgecolor='white', alpha=0.6, ax=ax)\n\nax.set_title('用户年龄分布（含密度曲线）', fontsize=15, fontweight='bold')\nax.set_xlabel('年龄')\nax.set_ylabel('密度')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('hist_kde.png', dpi=150, bbox_inches='tight')\n```\n\n### 分组直方图对比\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\n# 多组数据叠加\nsns.histplot(data=df, x='value', hue='group',\n             bins=30, alpha=0.5, edgecolor='white', ax=ax)\n\nax.set_title('不同渠道订单金额分布对比', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('hist_grouped.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 二、箱线图（Box Plot）\n\n### 标准箱线图\n\n```python\nfig, ax = plt.subplots(figsize=(10, 6))\n\nbp = ax.boxplot(df['value'],\n                patch_artist=True,\n                widths=0.5,\n                showfliers=True,  # 显示异常值\n                flierprops=dict(marker='o', markerfacecolor='#ef4444',\n                               markersize=6, alpha=0.6))\n\n# 美化\nbp['boxes'][0].set_facecolor('#3b82f6')\nbp['boxes'][0].set_alpha(0.7)\nbp['medians'][0].set_color('#ef4444')\nbp['medians'][0].set_linewidth(2)\n\nax.set_title('响应时间分布', fontsize=15, fontweight='bold', pad=12)\nax.set_ylabel('响应时间（ms）')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('boxplot.png', dpi=150, bbox_inches='tight')\n```\n\n### 多组箱线图对比（最常用）\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\n# 按类别分组\ngroups = df.groupby('category')['value'].apply(list).to_dict()\nlabels = list(groups.keys())\ndata = [groups[k] for k in labels]\n\nbp = ax.boxplot(data, patch_artist=True, labels=labels,\n                showfliers=True, widths=0.6)\n\n# 多色填充\nPALETTE = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6']\nfor i, box in enumerate(bp['boxes']):\n    box.set_facecolor(PALETTE[i % len(PALETTE)])\n    box.set_alpha(0.7)\nfor median in bp['medians']:\n    median.set_color('#1f2937')\n    median.set_linewidth(2)\n\nax.set_title('各品类订单金额分布', fontsize=15, fontweight='bold')\nax.set_xlabel('品类')\nax.set_ylabel('金额（元）')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('boxplot_grouped.png', dpi=150, bbox_inches='tight')\n```\n\n### 使用 Seaborn 简化\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\nsns.boxplot(data=df, x='category', y='value',\n            palette=PALETTE, width=0.6, ax=ax)\n\nax.set_title('各区域用户消费分布', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('boxplot_seaborn.png', dpi=150, bbox_inches='tight')\n```\n\n### 横向箱线图\n\n```python\nfig, ax = plt.subplots(figsize=(10, 8))\n\nsns.boxplot(data=df, y='category', x='value',\n            palette=PALETTE, width=0.6, ax=ax)\n\nax.set_title('各区域用户消费分布', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('boxplot_horizontal.png', dpi=150, bbox_inches='tight')\n```\n\n### 隐藏异常值\n\n```python\n# 场景：异常值过多影响主分布展示\nfig, ax = plt.subplots(figsize=(12, 6))\n\nsns.boxplot(data=df, x='category', y='value',\n            showfliers=False,  # 隐藏异常值\n            palette=PALETTE, ax=ax)\n\nax.set_title('各品类订单金额分布（隐藏极端值）', fontsize=15, fontweight='bold')\n\nplt.tight_layout()\nplt.savefig('boxplot_no_fliers.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 三、小提琴图（Violin Plot）\n\n小提琴图 = 箱线图 + KDE，同时展示分布形状和统计量。\n\n### 标准小提琴图\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\nsns.violinplot(data=df, x='category', y='value',\n               palette=PALETTE, inner='box', ax=ax)\n# inner: 'box', 'quartile', 'point', 'stick', None\n\nax.set_title('各渠道用户年龄分布', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('violin.png', dpi=150, bbox_inches='tight')\n```\n\n### 小提琴图 + 箱线图叠加\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\n# 小提琴（半透明）\nsns.violinplot(data=df, x='category', y='value',\n               palette=PALETTE, inner=None, alpha=0.4, ax=ax)\n\n# 箱线图叠加\nsns.boxplot(data=df, x='category', y='value',\n            width=0.2, color='white', ax=ax,\n            boxprops=dict(zorder=10))\n\nax.set_title('各渠道用户年龄分布（小提琴+箱线）', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('violin_box.png', dpi=150, bbox_inches='tight')\n```\n\n### 分组小提琴图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 6))\n\nsns.violinplot(data=df, x='region', y='value', hue='gender',\n               split=True,  # 左右分割\n               palette=['#3b82f6', '#ef4444'], ax=ax)\n\nax.set_title('各地区男女消费分布对比', fontsize=15, fontweight='bold')\nax.legend(title='性别')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('violin_grouped.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 四、核密度图（KDE）\n\n### 单变量 KDE\n\n```python\nfig, ax = plt.subplots(figsize=(10, 6))\n\nsns.kdeplot(df['value'], fill=True, color='#3b82f6', alpha=0.6, ax=ax)\n\nax.set_title('用户年龄密度分布', fontsize=15, fontweight='bold')\nax.set_xlabel('年龄')\nax.set_ylabel('密度')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('kde.png', dpi=150, bbox_inches='tight')\n```\n\n### 多组 KDE 对比\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\nfor group, color in zip(['A', 'B', 'C'], PALETTE[:3]):\n    subset = df[df['group'] == group]['value']\n    sns.kdeplot(subset, fill=True, alpha=0.4, label=group, color=color, ax=ax)\n\nax.legend(title='渠道')\nax.set_title('各渠道订单金额密度对比', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('kde_grouped.png', dpi=150, bbox_inches='tight')\n```\n\n### 双变量 KDE（2D 密度图）\n\n```python\nfig, ax = plt.subplots(figsize=(10, 8))\n\nsns.kdeplot(data=df, x='feature_a', y='feature_b',\n            fill=True, cmap='Blues', thresh=0.1, levels=10, ax=ax)\n\nax.set_title('用户行为特征二维密度分布', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('kde_2d.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 五、高级场景\n\n### 直方图 + 统计线（均值/中位数）\n\n```python\nfig, ax = plt.subplots(figsize=(10, 6))\n\nax.hist(df['value'], bins=30, color='#3b82f6', edgecolor='white', alpha=0.7)\n\nmean_val = df['value'].mean()\nmedian_val = df['value'].median()\n\nax.axvline(mean_val, color='#ef4444', linestyle='--', linewidth=2, label=f'均值: {mean_val:.1f}')\nax.axvline(median_val, color='#10b981', linestyle='-.', linewidth=2, label=f'中位数: {median_val:.1f}')\n\nax.legend()\nax.set_title('订单金额分布（含统计线）', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('hist_stats.png', dpi=150, bbox_inches='tight')\n```\n\n### 箱线图 + 散点叠加（展示原始数据）\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\n\n# 箱线图\nsns.boxplot(data=df, x='category', y='value',\n            palette=PALETTE, width=0.5, ax=ax)\n\n# 散点叠加（带抖动）\nsns.stripplot(data=df, x='category', y='value',\n              size=3, alpha=0.3, color='#1f2937', ax=ax)\n\nax.set_title('各品类订单金额分布（含原始数据点）', fontsize=15, fontweight='bold')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('box_strip.png', dpi=150, bbox_inches='tight')\n```\n\n### 分布对比：直方图 vs 箱线图 vs 小提琴图\n\n```python\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\n\n# 直方图\naxes[0].hist(df['value'], bins=30, color='#3b82f6', edgecolor='white', alpha=0.7)\naxes[0].set_title('直方图')\naxes[0].set_xlabel('值')\naxes[0].set_ylabel('频数')\n\n# 箱线图\naxes[1].boxplot(df['value'], patch_artist=True)\naxes[1].set_title('箱线图')\naxes[1].set_ylabel('值')\n\n# 小提琴图\nsns.violinplot(y=df['value'], ax=axes[2], color='#3b82f6')\naxes[2].set_title('小提琴图')\naxes[2].set_ylabel('值')\n\nfor ax in axes:\n    ax.spines['top'].set_visible(False)\n    ax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('distribution_compare.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 六、强制规范\n\n### ✅ MUST DO\n\n- **直方图必须指定 bins 或让算法自动选择**，避免使用默认值\n- **箱线图必须标注异常值定义**（默认 1.5×IQR，可调整）\n- **多组分布对比时，使用相同的 Y 轴范围**\n- **中位数线必须清晰可见**（颜色对比、线宽）\n- **直方图柱子之间必须有白色边框**（避免视觉混淆）\n- **KDE 曲线必须有标签说明**（密度 vs 概率）\n\n### ❌ MUST NOT\n\n- 不在直方图上省略 X 轴标签（值范围）\n- 不用箱线图展示类别 > 20 的数据（改为聚合或筛选）\n- 不在小提琴图中隐藏统计量（至少显示中位数）\n- 不用 3D 直方图\n- 不忽略异常值的解释（是什么原因？是否需要排除？）\n- 不在密度图中使用 fill=False（无法直观比较）\n\n---\n\n## 七、行业最佳实践\n\n### 电商：订单金额分布\n\n```python\n# 典型电商订单金额呈长尾分布，用对数 X 轴\nfig, ax = plt.subplots(figsize=(10, 6))\n\nax.hist(df['order_amount'], bins=50, color='#3b82f6', edgecolor='white', alpha=0.7)\nax.set_xscale('log')  # 对数轴\n\nax.set_title('订单金额分布（对数轴）', fontsize=15, fontweight='bold')\nax.set_xlabel('金额（元，对数刻度）')\nax.set_ylabel('订单数')\n\nplt.tight_layout()\nplt.savefig('order_amount_log.png', dpi=150, bbox_inches='tight')\n```\n\n### 金融：收益率分布\n\n```python\n# 收益率通常接近正态，检查肥尾\nfig, ax = plt.subplots(figsize=(10, 6))\n\nsns.histplot(df['return'], bins=50, kde=True, color='#3b82f6', ax=ax)\n\n# 添加正态分布参考\nfrom scipy import stats\nx = np.linspace(df['return'].min(), df['return'].max(), 100)\ny = stats.norm.pdf(x, df['return'].mean(), df['return'].std())\nax.plot(x, y * len(df) * (x[1] - x[0]), 'r--', label='正态分布参考')\n\nax.legend()\nax.set_title('日收益率分布 vs 正态分布', fontsize=15, fontweight='bold')\n\nplt.tight_layout()\nplt.savefig('return_distribution.png', dpi=150, bbox_inches='tight')\n```\n\n### 运维：响应时间分布\n\n```python\n# P50, P90, P99 分位线\nfig, ax = plt.subplots(figsize=(10, 6))\n\nax.hist(df['response_time'], bins=50, color='#3b82f6', edgecolor='white', alpha=0.7)\n\np50 = df['response_time'].quantile(0.5)\np90 = df['response_time'].quantile(0.9)\np99 = df['response_time'].quantile(0.99)\n\nax.axvline(p50, color='#10b981', linestyle='--', linewidth=2, label=f'P50: {p50:.0f}ms')\nax.axvline(p90, color='#f59e0b', linestyle='--', linewidth=2, label=f'P90: {p90:.0f}ms')\nax.axvline(p99, color='#ef4444', linestyle='--', linewidth=2, label=f'P99: {p99:.0f}ms')\n\nax.legend()\nax.set_title('API 响应时间分布', fontsize=15, fontweight='bold')\nax.set_xlabel('响应时间（ms）')\nax.set_ylabel('请求数')\n\nplt.tight_layout()\nplt.savefig('response_time_p99.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 八、常见问题与解决方案\n\n| 问题 | 原因 | 解决方案 |\n|------|------|---------|\n| 直方图柱子太少/太多 | bins 不合适 | 使用 FD 公式或手动调整 |\n| 箱线图异常值过多 | 数据本身有极端值 | 检查数据质量；可调高异常阈值 |\n| 多组分布无法比较 | Y 轴范围不同 | 设置 `sharey=True` 或手动统一 |\n| KDE 曲线超出数据范围 | 核密度估计外推 | 设置 `clip=(min, max)` |\n| 小提琴图太拥挤 | 类别太多 | 改用箱线图或分面展示 |\n| 直方图右偏严重 | 长尾分布 | 使用对数 X 轴 |\n\nFile v1.0.0:references/heatmap.md\n\n# 热力图 — 相关性矩阵、时间热图、表格热图\n\n适用场景：相关性分析、时间序列密度、分类数据对比、矩阵数据可视化。\n\n---\n\n## 核心问题：你想展示什么类型的热力图？\n\n| 场景 | 推荐类型 |\n|------|---------|\n| 特征之间的相关性？ | 相关性矩阵热力图 |\n| 随时间变化的强度？ | 时间热力图（Calendar/Activity） |\n| 分类数据对比？ | 分类热力图 |\n| 表格数据可视化？ | 表格热力图 |\n| 地理位置密度？ | 地理热力图（需地图数据，见地理图表） |\n\n---\n\n## 一、相关性矩阵热力图\n\n相关性热力图是最常用的场景，用于发现变量之间的关系。\n\n### 基础相关性热力图\n\n```python\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport numpy as np\nimport pandas as pd\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nfig, ax = plt.subplots(figsize=(12, 10))\n\n# 计算相关性矩阵\ncorr = df[['col1', 'col2', 'col3', 'col4', 'col5']].corr()\n\n# 绘制热力图\nmask = np.zeros_like(corr)  # 可选：只显示下三角 mask = np.triu(np.ones_like(corr, dtype=bool))\n\nsns.heatmap(corr,\n            annot=True,          # 显示数值\n            fmt='.2f',           # 数值格式\n            cmap='RdYlGn',       # 颜色映射：红-黄-绿（正相关绿，负相关红）\n            center=0,             # 0 为中心\n            square=True,         # 正方形格子\n            linewidths=0.5,      # 格子间隔线\n            cbar_kws={'shrink': 0.8, 'label': '相关系数'},\n            ax=ax)\n\nax.set_title('特征相关性矩阵', fontsize=15, fontweight='bold', pad=15)\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('corr_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### 只显示下三角（避免重复信息）\n\n```python\nfig, ax = plt.subplots(figsize=(12, 10))\n\n# 上三角遮罩\nmask = np.triu(np.ones_like(corr, dtype=bool))\n\nsns.heatmap(corr, mask=mask,\n            annot=True, fmt='.2f',\n            cmap='RdYlGn', center=0,\n            square=True, linewidths=0.5,\n            cbar_kws={'shrink': 0.8},\n            ax=ax)\n\nax.set_title('特征相关性矩阵（下三角）', fontsize=15, fontweight='bold', pad=15)\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('corr_heatmap_lower.png', dpi=150, bbox_inches='tight')\n```\n\n### 高级：带聚类的相关性热力图\n\n```python\n# 使用 clustermap 进行层次聚类排序\ng = sns.clustermap(corr,\n                    method='ward',        # 聚类方法\n                    cmap='RdYlGn',\n                    center=0,\n                    annot=True,\n                    fmt='.2f',\n                    linewidths=0.5,\n                    figsize=(12, 10),\n                    dendrogram_ratio=(.1, .1),\n                    cbar_pos=(0.02, 0.8, 0.03, 0.15))\n\ng.fig.suptitle('特征相关性矩阵（含聚类）', fontsize=15, fontweight='bold', y=1.02)\ng.savefig('corr_clustermap.png', dpi=150, bbox_inches='tight')\nplt.close()\n```\n\n### 标注显著性（p-value）\n\n```python\nfrom scipy import stats\n\ndef corr_with_pvalue(df):\n    cols = df.columns\n    n = len(cols)\n    corr = np.zeros((n, n))\n    pval = np.zeros((n, n))\n    for i in range(n):\n        for j in range(n):\n            if i == j:\n                corr[i, j] = 1.0\n                pval[i, j] = 0\n            else:\n                r, p = stats.pearsonr(df.iloc[:, i], df.iloc[:, j])\n                corr[i, j] = r\n                pval[i, j] = p\n    return pd.DataFrame(corr, index=cols, columns=cols), pd.DataFrame(pval, index=cols, columns=cols)\n\ncorr_matrix, pval_matrix = corr_with_pvalue(df)\n\nfig, ax = plt.subplots(figsize=(12, 10))\n\n# 显著性标注（* p<0.05, ** p<0.01, *** p<0.001）\nannot = corr_matrix.round(2).copy()\nfor i in range(len(pval_matrix)):\n    for j in range(len(pval_matrix)):\n        p = pval_matrix.iloc[i, j]\n        if p < 0.001:\n            annot.iloc[i, j] = f'{corr_matrix.iloc[i, j]:.2f}***'\n        elif p < 0.01:\n            annot.iloc[i, j] = f'{corr_matrix.iloc[i, j]:.2f}**'\n        elif p < 0.05:\n            annot.iloc[i, j] = f'{corr_matrix.iloc[i, j]:.2f}*'\n\nsns.heatmap(corr_matrix, annot=annot, fmt='',\n            cmap='RdYlGn', center=0,\n            square=True, linewidths=0.5,\n            ax=ax)\n\nax.set_title('相关性矩阵（* p<0.05, ** p<0.01, *** p<0.001）', fontsize=15, fontweight='bold')\nplt.tight_layout()\nplt.savefig('corr_pvalue.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 二、时间热力图\n\n### GitHub 风格贡献热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 6))\n\n# 重塑为周×天的矩阵（周一=0，周日=6）\ndf['date'] = pd.to_datetime(df['date'])\ndf['week'] = df['date'].dt.isocalendar().week\ndf['dayofweek'] = df['date'].dt.dayofweek\n\n# 按周和星期聚合\npivot = df.groupby(['week', 'dayofweek'])['value'].sum().unstack(fill_value=0)\n\n# 绘制热力图\nsns.heatmap(pivot, cmap='YlGnBu', linewidths=0.5,\n             square=False, cbar_kws={'label': '活跃度'},\n             ax=ax)\n\n# Y 轴标签改为星期\nax.set_yticklabels(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'])\nax.set_xticklabels([f'W{int(w)}' for w in ax.get_xticks()], rotation=45, ha='right', fontsize=8)\nax.set_title('每日活跃热力图', fontsize=15, fontweight='bold')\nax.set_xlabel('周数')\nax.set_ylabel('')\n\nplt.tight_layout()\nplt.savefig('calendar_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### Seaborn 内置 Calendar Heatmap（年视图）\n\n```python\n# 使用 calmap 库（更专业）\nimport calmap\n\nfig, ax = plt.subplots(figsize=(15, 6))\n\n# 设置日期索引\ndf_indexed = df.set_index('date')['value']\n\ncalmap.yearplot(df_indexed, year=2026, ax=ax, cmap='YlGnBu')\n\nax.set_title('2026 年度活跃热力图', fontsize=15, fontweight='bold')\nplt.tight_layout()\nplt.savefig('year_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### 月度时间热力图（小时 × 天）\n\n```python\n# 场景：用户活跃时间段分析\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 创建小时×星期的矩阵\ndf['hour'] = df['timestamp'].dt.hour\ndf['weekday'] = df['timestamp'].dt.dayofweek\npivot = df.groupby(['weekday', 'hour'])['value'].sum().unstack(fill_value=0)\n\n# 绘制\nsns.heatmap(pivot, cmap='Blues', linewidths=0.5,\n             xticklabels=range(24), yticklabels=['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],\n             cbar_kws={'label': '活动量'}, ax=ax)\n\nax.set_title('用户活跃时段分布（小时 × 星期）', fontsize=15, fontweight='bold')\nax.set_xlabel('小时')\nax.set_ylabel('星期')\nplt.xticks(rotation=0)\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('hour_weekday_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 三、分类热力图\n\n### 分组数据热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 创建 品类×月份 的数据矩阵\npivot = df.pivot_table(values='sales',\n                        index='category',\n                        columns='month',\n                        aggfunc='sum',\n                        fill_value=0)\n\nsns.heatmap(pivot, cmap='Blues', linewidths=0.5,\n             annot=True, fmt=',.0f',\n             cbar_kws={'label': '销售额（万元）'},\n             ax=ax)\n\nax.set_title('各品类月度销售额', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('category_month_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### 百分比热力图（按行归一化）\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 按行归一化（每行之和为 100%）\npivot_pct = pivot.div(pivot.sum(axis=1), axis=0) * 100\n\nsns.heatmap(pivot_pct, cmap='Blues', linewidths=0.5,\n             annot=True, fmt='.1f',\n             cbar_kws={'label': '占比（%）'},\n             ax=ax)\n\nax.set_title('各品类月度销售额占比（%）', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('category_month_pct.png', dpi=150, bbox_inches='tight')\n```\n\n### 发散型热力图（展示增减变化）\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 计算环比变化\npivot_diff = pivot.pct_change(axis=1) * 100  # 月度环比增长率\n\n# 发散型 colormap（正=绿，负=红）\ncmap = sns.diverging_palette(10, 130, as_cmap=True)  # 红-白-绿\n\nsns.heatmap(pivot_diff, cmap=cmap, center=0,\n             linewidths=0.5, fmt='+.1f',\n             annot=True, vmin=-50, vmax=50,\n             cbar_kws={'label': '环比增长率（%）'},\n             ax=ax)\n\nax.set_title('各品类月度销售额环比变化（%）', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('pivot_diverging.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 四、Cohort 留存热力图\n\n用户留存分析的标准可视化。\n\n```python\ndef cohort_heatmap(df, cohort_col, period_col, value_col='user_id', metric='count'):\n    \"\"\"\n    生成 Cohort 留存热力图\n    df: 包含用户首次行为日期和当前行为日期的数据\n    cohort_col: 首次行为日期列\n    period_col: 当前行为日期列\n    \"\"\"\n    df = df.copy()\n    df[cohort_col] = pd.to_datetime(df[cohort_col])\n    df[period_col] = pd.to_datetime(df[period_col])\n\n    # Cohort 周期（月份）\n    df['cohort_month'] = df[cohort_col].dt.to_period('M')\n    df['period_month'] = df[period_col].dt.to_period('M')\n\n    # 计算相对月份\n    df['period_number'] = (df['period_month'].astype(int) - df['cohort_month'].astype(int))\n\n    # 统计每个 Cohort × Period 的用户数\n    cohort_data = df.groupby(['cohort_month', 'period_number'])[value_col].nunique().reset_index()\n    cohort_table = cohort_data.pivot(index='cohort_month', columns='period_number', values=value_col)\n\n    # 计算留存率\n    cohort_size = cohort_table.iloc[:, 0]\n    retention_table = cohort_table.divide(cohort_size, axis=0) * 100\n\n    return cohort_table, retention_table\n\n# 生成数据\ncohort_table, retention_table = cohort_heatmap(df, 'first_date', 'activity_date')\n\n# 绘制热力图\nfig, ax = plt.subplots(figsize=(16, 10))\n\nsns.heatmap(retention_table, cmap='YlGnBu', linewidths=0.5,\n             annot=True, fmt='.0f', vmin=0, vmax=100,\n             cbar_kws={'label': '留存率（%）'},\n             ax=ax)\n\nax.set_title('Cohort 用户留存率（%）', fontsize=15, fontweight='bold')\nax.set_xlabel('距首次活跃月数')\nax.set_ylabel('Cohort（首次活跃月份）')\nplt.xticks(rotation=0)\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('cohort_retention.png', dpi=150, bbox_inches='tight')\n```\n\n### Cohort 热力图进阶：同时显示人数和留存率\n\n```python\n# 创建双层热力图：人数 + 留存率\nfig, axes = plt.subplots(1, 2, figsize=(20, 10))\n\n# 左图：绝对人数\nsns.heatmap(cohort_table, cmap='Blues', linewidths=0.5,\n             annot=True, fmt=',.0f', ax=axes[0])\naxes[0].set_title('Cohort 用户数', fontsize=14, fontweight='bold')\naxes[0].set_xlabel('距首次活跃月数')\n\n# 右图：留存率\nsns.heatmap(retention_table, cmap='YlGnBu', linewidths=0.5,\n             annot=True, fmt='.0f', vmin=0, vmax=100, ax=axes[1])\naxes[1].set_title('Cohort 留存率（%）', fontsize=14, fontweight='bold')\naxes[1].set_xlabel('距首次活跃月数')\n\nfor ax in axes:\n    ax.set_ylabel('')\n\nplt.suptitle('用户 Cohort 分析', fontsize=16, fontweight='bold', y=1.02)\nplt.tight_layout()\nplt.savefig('cohort_combined.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 五、表格热力图\n\n### 普通表格热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 创建表格数据\ntable_data = df.pivot_table(values='sales',\n                             index='region',\n                             columns='product',\n                             aggfunc='sum',\n                             fill_value=0)\n\nsns.heatmap(table_data, cmap='Oranges', linewidths=1,\n             annot=True, fmt=',.0f',\n             cbar_kws={'label': '销售额（万元）'},\n             ax=ax, annot_kws={'size': 10})\n\nax.set_title('各区域各产品销售额', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right', fontsize=10)\nplt.yticks(rotation=0, fontsize=10)\n\nplt.tight_layout()\nplt.savefig('table_heatmap.png', dpi=150, bbox_inches='tight')\n```\n\n### 带格式化文本的热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 自定义格式化函数\ndef fmt(val):\n    if val == 0:\n        return '-'\n    elif val >= 10000:\n        return f'{val/10000:.1f}万'\n    elif val >= 1000:\n        return f'{val/1000:.0f}千'\n    else:\n        return f'{val:.0f}'\n\nannot = table_data.applymap(fmt)\n\nsns.heatmap(table_data, cmap='YlOrRd', linewidths=1,\n             annot=annot, fmt='', cbar=False, ax=ax)\n\nax.set_title('各区域各产品销售额', fontsize=15, fontweight='bold')\nplt.xticks(rotation=45, ha='right')\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.savefig('table_heatmap_fmt.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 六、颜色映射选择指南\n\n### 何时用哪种 Colormap\n\n| Colormap | 类型 | 适用场景 |\n|----------|------|---------|\n| `RdYlGn` | 发散型 | 相关性、变化率（中心=0） |\n| `RdBu` | 发散型 | 正负对比（金融涨跌） |\n| `seismic` | 发散型 | 地震/极端正负值 |\n| `Blues` / `YlGnBu` | 顺序型 | 单向递增（销售额、用户数） |\n| `Oranges` / `Reds` | 顺序型 | 热度、风险、强度 |\n| `viridis` / `plasma` | 顺序型 | 科学数据、色盲友好 |\n| `coolwarm` | 发散型 | 温度、情感分析 |\n| `cubehelix` | 顺序型 | 亮度渐变、打印友好 |\n\n### 发散型 vs 顺序型\n\n```python\n# 发散型：数据有正负对比\ncmap_div = sns.diverging_palette(10, 130, as_cmap=True)  # 红-白-绿\n\n# 顺序型：数据单向递增\ncmap_seq = sns.color_palette('Blues', as_cmap=True)\n\n# 自定义边界\nimport matplotlib.colors as mcolors\ncmap_custom = mcolors.LinearSegmentedColormap.from_list(\n    'custom', ['#f7fbff', '#3b82f6', '#1e3a5f'])\n```\n\n### 色盲友好建议\n\n```python\n# 推荐色盲友好的 colormap\ncbar_kws={'label': '值', 'cmap': 'viridis'}  # 默认最优\ncbar_kws={'label': '值', 'cmap': 'cividis'}   # 更深的对比\n```\n\n---\n\n## 七、高级场景\n\n### 热力图 + 树状图（层次聚类排序）\n\n```python\ng = sns.clustermap(df.corr(),\n                   method='average',\n                   metric='correlation',\n                   cmap='RdYlGn',\n                   center=0,\n                   annot=True,\n                   fmt='.2f',\n                   linewidths=0.5,\n                   figsize=(12, 10),\n                   dendrogram_ratio=(0.2, 0.2),\n                   cbar_pos=(0.02, 0.8, 0.03, 0.15),\n                   tree_kws={'linewidths': 0.5})\n\ng.fig.suptitle('相关性矩阵（层次聚类）', fontsize=15, fontweight='bold', y=1.02)\nplt.savefig('heatmap_clustered.png', dpi=150, bbox_inches='tight')\nplt.close()\n```\n\n### 带缺失值的热力图\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# NaN 显示为灰色\ncmap = sns.diverging_palette(10, 130, as_cmap=True)\n\nsns.heatmap(table_data, cmap=cmap, center=0,\n             linewidths=0.5, fmt='.1f',\n             annot=True, ax=ax,\n             mask=table_data.isna(),  # 遮罩缺失值\n             na_rep='N/A')\n\nax.set_title('数据热力图（含缺失值显示为 N/A）', fontsize=15, fontweight='bold')\nplt.tight_layout()\nplt.savefig('heatmap_na.png', dpi=150, bbox_inches='tight')\n```\n\n### 热力图边框和单元格大小控制\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 调整单元格比例\nsns.heatmap(table_data, cmap='Blues',\n             linewidths=2,          # 加粗边框\n             linecolor='white',     # 白色分隔线\n             square=True,            # 正方形格子\n             ax=ax)\n\nax.set_title('单元格热力图', fontsize=15, fontweight='bold')\nplt.tight_layout()\nplt.savefig('heatmap_square.png', dpi=150, bbox_inches='tight')\n```\n\n### 热力图 + 散点叠加（双层信息）\n\n```python\nfig, ax = plt.subplots(figsize=(14, 8))\n\n# 底色热力图\nsns.heatmap(table_data, cmap='Blues', alpha=0.3,\n             annot=False, linewidths=0, ax=ax)\n\n# 叠加数值散点\nfor i, row_idx in enumerate(table_data.index):\n    for j, col_idx in enumerate(table_data.columns):\n        val = table_data.loc[row_idx, col_idx]\n        if pd.notna(val):\n            ax.scatter(j + 0.5, i + 0.5, s=val/10,\n                       c='red' if val > table_data.median().median() else 'blue',\n                       alpha=0.6, zorder=10)\n\nax.set_title('热力图 + 散点叠加', fontsize=15, fontweight='bold')\nplt.tight_layout()\nplt.savefig('heatmap_scatter.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 八、强制规范\n\n### ✅ MUST DO\n\n- **相关性热力图必须标注数值**（annot=True）\n- **发散型 colormap 必须设置 center=0**\n- **colormap 必须有 colorbar 和标签**\n- **长标签必须旋转**（rotation=45）保证可读\n- **单元格大小应与数据量匹配**：数据多格子小，数据少格子大\n- **缺失值必须处理**：mask 或 na_rep\n\n### ❌ MUST NOT\n\n- 不用 `jet` / `rainbow` 等非色盲友好 colormap\n- 不在正负数据上使用单向 colormap（如 Blues）\n- 不省略 colorbar（无法判断颜色对应数值）\n- 不在过小的格子里显示长数字（改用颜色深浅）\n- 不用 3D 热力图（无法准确读值）\n- 不在类别过多时使用热力图（改用条形图或表格）\n\n---\n\n## 九、行业最佳实践\n\n### 电商：品类×时间 销售热力图\n\n```python\n# 月度销售趋势热力图\nfig, ax = plt.subplots(figsize=(16, 10))\n\npivot = df.pivot_table(values='gmv',\n                       index='category',\n                       columns='month',\n                       aggfunc='sum',\n                       fill_value=0)\n\n# 使用聚类排序\ng = sns.clustermap(pivot, cmap='YlGnBu',","readmeExcerpt":"Skill: SQL Dataviz Owner: moniq888 Summary: Convert SQL query results into production-grade visual charts including bar, line, pie, map, KPI, AI insights, and interactive HTML dashboards with base64 PN... Tags: latest:1.0.1 Version history: v1.0.1 | 2026-03-27T10:33:33.832Z | user - 修正协作工具名称，将“report-generator”统一为“sql-report-generator”以匹配实际 Skill 名称 - 数据分析流程示意图和协作流程文档细节微调，增强 Skill 协作关系说明 - 文档其余内容未变，功能和接口保持不变 v1.0.0 |","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"skillhub_install install_skill sql-dataviz"},{"language":"text","snippet":"┌─────────────┐     ┌──────────────┐     ┌────────────────────────┐\n│ sql-master  │ ──► │ sql-dataviz  │ ──► │ sql-report-generator   │\n│  (数据层)   │     │  (可视化层)   │     │  (报告层)               │\n└─────────────┘     └──────────────┘     └────────────────────────┘\n      │                   │                   │\n      ▼                   ▼                   ▼\n   SQL 查询           图表生成            HTML 报告\n   数据获取           PNG/HTML            AI 洞察\n   格式转换           Dashboard           数据表格"},{"language":"python","snippet":"from scripts.unified_pipeline import UnifiedPipeline\n\nresult = (\n    UnifiedPipeline(\"销售分析\")\n    .from_file(\"sales.csv\")                                    # sql-master: 数据获取\n    .query(\"SELECT region, SUM(sales) as total FROM data GROUP BY region\")\n    .interactive_chart(\"bar\", x_col=\"region\", y_col=\"total\")   # sql-dataviz: 可视化\n    .insights(value_cols=[\"total\"])                            # AI 洞察\n    .report(title=\"销售报告\", output=\"report.html\")            # sql-report-generator: 报告\n)"},{"language":"text","snippet":"你需要什么？\n├─ 仅图表可视化 → sql-dataviz 单独使用\n├─ SQL + 图表 → sql-master + sql-dataviz\n├─ 图表 + 报告（无 SQL）→ sql-dataviz + sql-report-generator\n└─ 完整分析报告 → sql-master + sql-dataviz + sql-report-generator ✅ 推荐"},{"language":"python","snippet":"from scripts.interactive_charts import InteractiveChartFactory, DashboardBuilder\n\nfactory = InteractiveChartFactory(theme=\"powerbi\")\n\n# 12 种图表类型\nhtml = factory.create_line(data)          # 折线图\nhtml = factory.create_bar(data)           # 柱形图\nhtml = factory.create_pie(data)           # 饼图（环形）\nhtml = factory.create_scatter(data)       # 散点图\nhtml = factory.create_heatmap(data)       # 热力图\nhtml = factory.create_funnel(data)        # 漏斗图\nhtml = factory.create_area(data)          # 面积图\nhtml = factory.create_treemap(data)       # 树状图\nhtml = factory.create_gauge(data)         # 仪表盘\nhtml = factory.create_combo(data)         # 组合图（柱+折线）\nhtml = factory.create_table(data)         # 交互式表格\nhtml = factory.create_kpi_cards(data)     # KPI 卡片组\n\nfactory.save_html(html, \"chart.html\")\n\n# 多图表 Dashboard\nbuilder = DashboardBuilder(title=\"销售看板\", theme=\"powerbi\")\nbuilder.add_kpi_cards([{\"title\":\"GMV\",\"value\":\"¥1,234万\",\"change\":\"+18%\"}])\nbuilder.add_chart(factory.create_line(...), title=\"月度趋势\", cols=2)\nbuilder.add_chart(factory.create_bar(...), title=\"区域对比\", cols=1)\nbuilder.build(\"dashboard.html\")"},{"language":"python","snippet":"from sql_dataviz.charts import ChartFactory, ChartConfig, Theme\n\n# 1. 创建工厂\nfactory = ChartFactory()\n\n# 2. 设置主题（可选）\nfactory.set_theme('powerbi')  # 或 'alibaba', 'tencent', 'bytedance'\n\n# 3. 准备数据\ndata = {\n    'categories': ['Q1', 'Q2', 'Q3', 'Q4'],\n    'series': [\n        {'name': '销售额', 'data': [100, 150, 120, 200]},\n        {'name': '成本', 'data': [60, 80, 70, 100]}\n    ]\n}\n\n# 4. 生成图表（base64 PNG）\nchart_b64 = factory.create_clustered_column(data)\n\n# 5. 嵌入到 HTML\nhtml = f'<img src=\"data:image/png;base64,{chart_b64}\" />'\n\n# 6. 或保存为文件\nimport base64\nwith open('chart.png', 'wb') as f:\n    f.write(base64.b64decode(chart_b64))"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"# sql-dataviz - SQL 数据可视化 Skill\n\n## ⚠️ 使用前必读\n\n本 Skill 需要 Python 依赖。**首次使用前必须安装依赖**：\n\n```bash\nskillhub_install install_skill sql-dataviz\n```\n\n工具会自动检测 Python3 环境、pip 可用性，并安装所有依赖。\n\n### 依赖安装方式\n\n| 方式 | 命令 | 适用场景 |\n|------|------|---------|\n| **自动安装（推荐）** | `skillhub_install install_skill sql-dataviz` | 一键安装，自动处理 |\n| **手动安装** | `pip install -r requirements.txt` | 熟悉 Python 环境的用户 |\n\n### 无依赖使用（受限模式）\n\n如果无法安装依赖，本 Skill 提供以下**降级能力**：\n\n✅ **可用功能**：\n- 图表选型建议（基于业务场景推荐图表类型）\n- 数据格式规范说明\n- 可视化设计原则指导\n- 配色方案推荐\n\n❌ **不可用功能**：\n- 图表生成（PNG/base64 输出）\n- 交互式 HTML 图表\n- Dashboard 构建\n- 与 sql-master / sql-report-generator 联动\n\n---\n\n## 🔗 Skill 协作关系\n\n本 Skill 与 **sql-master**、**sql-report-generator** 组成完整的数据分析流水线：\n\n```\n┌─────────────┐     ┌──────────────┐     ┌────────────────────────┐\n│ sql-master  │ ──► │ sql-dataviz  │ ──► │ sql-report-generator   │\n│  (数据层)   │     │  (可视化层)   │     │  (报告层)               │\n└─────────────┘     └──────────────┘     └────────────────────────┘\n      │                   │                   │\n      ▼                   ▼                   ▼\n   SQL 查询           图表生成            HTML 报告\n   数据获取           PNG/HTML            AI 洞察\n   格式转换           Dashboard           数据表格\n```\n\n### 协作模式\n\n| 模式 | 组合 | 适用场景 |\n|------|------|---------|\n| **单独使用** | sql-dataviz | 已有数据，仅需图表可视化 |\n| **数据可视化** | sql-master + sql-dataviz | SQL 查询 → 图表输出 |\n| **可视化报告** | sql-dataviz + sql-report-generator | 图表 → 报告（无 SQL） |\n| **完整流程** | sql-master + sql-dataviz + sql-report-generator | 完整数据分析报告 |\n\n### 🥇 最优使用方式：三 Skill 串联\n\n```python\nfrom scripts.unified_pipeline import UnifiedPipeline\n\nresult = (\n    UnifiedPipeline(\"销售分析\")\n    .from_file(\"sales.csv\")                                    # sql-master: 数据获取\n    .query(\"SELECT region, SUM(sales) as total FROM data GROUP BY region\")\n    .interactive_chart(\"bar\", x_col=\"region\", y_col=\"total\")   # sql-dataviz: 可视化\n    .insights(value_cols=[\"total\"])                            # AI 洞察\n    .report(title=\"销售报告\", output=\"report.html\")            # sql-report-generator: 报告\n)\n```\n\n### 决策指南\n\n```\n你需要什么？\n├─ 仅图表可视化 → sql-dataviz 单独使用\n├─ SQL + 图表 → sql-master + sql-dataviz\n├─ 图表 + 报告（无 SQL）→ sql-dataviz + sql-report-generator\n└─ 完整分析报告 → sql-master + sql-dataviz + sql-report-generator ✅ 推荐\n```\n\n---\n\n## 新增功能：交互式 HTML 图表（Plotly）\n\n### `scripts/interactive_charts.py`\n\n基于 Plotly 的 12 种交互式图表，输出自包含 HTML（支持 hover / zoom / pan）：\n\n```python\nfrom scripts.interactive_charts import InteractiveChartFactory, DashboardBuilder\n\nfactory = InteractiveChartFactory(theme=\"powerbi\")\n\n# 12 种图表类型\nhtml = factory.create_line(data)          # 折线图\nhtml = factory.create_bar(data)           # 柱形图\nhtml = factory.create_pie(data)           # 饼图（环形）\nhtml = factory.create_scatter(data)       # 散点图\nhtml = factory.create_heatmap(data)       # 热力图\nhtml = factory.create_funnel(data)        # 漏斗图\nhtml = factory.create_area(data)          # 面积图\nhtml = factory.create_treemap(data)       # 树状图\nhtml = factory.create_gauge(data)         # 仪表盘\nhtml = factory.create_combo(data)         # 组合图（柱"},{"path":"sql-dataviz/SKILL.md","content":"# sql-dataviz - SQL 数据可视化 Skill\n\n## 概述\n\n将 SQL 查询结果转化为**生产级可视化图表**。集成 Power BI 原生的 24+ 种视觉对象，支持对比、趋势、分布、占比、地理、指标监控、AI 智能分析等全场景。\n\n所有图表以 **base64 编码的 PNG/SVG** 方式输出，可直接嵌入报告、邮件、Web 应用。\n\n## 核心能力\n\n### 1. 对比与趋势分析（8种）\n- **簇状柱形图** - 多系列分类对比\n- **堆积柱形图** - 整体+部分占比对比\n- **100%堆积柱形图** - 统一尺度结构对比\n- **簇状条形图** - 长分类名称对比\n- **堆积条形图** - 区域/渠道层级对比\n- **100%堆积条形图** - 横向结构占比\n- **折线图** - 连续数据趋势\n- **平滑折线图** - 弱化波动的趋势\n\n### 2. 高级趋势（5种）\n- **组合图** - 双指标（柱+折线）\n- **面积图** - 累计总量展示\n- **堆积面积图** - 多系列累计贡献\n- **瀑布图** - 增减项影响分析\n- **丝带图** - 排名变动追踪\n\n### 3. 部分与整体（4种）\n- **饼图** - 单维度占比\n- **圆环图** - 中心标签占比\n- **树状图** - 层级数据展示\n- **漏斗图** - 流程转化分析\n\n### 4. 分布与关系（4种）\n- **散点图** - 两变量相关性\n- **气泡图** - 三变量分析\n- **点图** - 分类数据分布\n- **高密度散点图** - 海量数据聚类\n\n### 5. 地理空间（3种）\n- **填充地图** - 区域数据热力\n- **形状地图** - 自定义边界分析\n- **ArcGIS 地图** - 专业空间分析\n\n### 6. 指标监控（3种）\n- **卡片图** - 单一关键指标\n- **KPI 视觉对象** - 目标达成率\n- **仪表盘图** - 指标健康度\n\n### 7. AI 智能分析（4种）\n- **分解树** - 多维度根因分析\n- **关键影响因素** - 驱动因子权重\n- **异常检测** - 自动异常标注\n- **智能叙事** - 自然语言摘要\n\n## 使用方式\n\n### 基础用法\n\n```python\nfrom sql_dataviz import ChartFactory\n\n# 创建图表工厂\nfactory = ChartFactory()\n\n# 从 SQL 结果生成图表\ndata = {\n    'categories': ['Q1', 'Q2', 'Q3', 'Q4'],\n    'series': [\n        {'name': '销售额', 'data': [100, 150, 120, 200]},\n        {'name': '成本', 'data': [60, 80, 70, 100]}\n    ]\n}\n\n# 生成簇状柱形图（base64）\nchart_b64 = factory.create_clustered_column(data)\n\n# 输出为 HTML 可嵌入\nhtml = f'<img src=\"data:image/png;base64,{chart_b64}\" />'\n```\n\n### 高级用法 - 组合分析\n\n```python\n# 多图表联动\ndashboard = factory.create_dashboard({\n    'title': '季度业绩分析',\n    'charts': [\n        {'type': 'clustered_column', 'data': sales_data, 'position': (0, 0)},\n        {'type': 'pie', 'data': channel_data, 'position': (1, 0)},\n        {'type': 'line', 'data': trend_data, 'position': (0, 1)},\n        {'type': 'heatmap', 'data': region_data, 'position': (1, 1)}\n    ]\n})\n```\n\n## 依赖安装\n\n### 自动安装（推荐）\n\n```bash\n# 使用 SkillHub 一键安装\nskillhub_install install_skill sql-dataviz\n```\n\n### 手动安装\n\n```bash\n# 1. 安装 Python 依赖\npip install matplotlib seaborn plotly pandas numpy\n\n# 2. 安装可选的地理数据库\npip install geopandas shapely\n\n# 3. 验证安装\npython -c \"import matplotlib; print(matplotlib.__version__)\"\n```\n\n## 文件结构\n\n```\nsql-dataviz/\n├── SKILL.md                          # 本文件\n├── charts/\n│   ├── __init__.py\n│   ├── comparison.py                 # 对比类图表\n│   ├── trend.py                      # 趋势类图表\n│   ├── composition.py                # 占比类图表\n│   ├── distribution.py               # 分布类图表\n│   ├── geographic.py                 # 地理类图表\n│   ├── kpi.py                        # 指标监控\n│   ├── ai_analysis.py                # AI 智能分析\n│   └── base.py                       # 基类与工具函数\n├── scripts/\n│   ├── install_deps.sh               # 依赖安装脚本\n│   └── demo.py                       # 演示脚本\n└── references/\n    ├── POWERBI_CHARTS.md             # Power BI 图表参考\n    └── COLOR_SCHEMES.md              # 大厂配色方案\n```\n\n## 配置选项\n\n### 主题与样式\n\n```python\n# 内置主题\nfactory.set_theme('powerbi')      # Power BI 官方配色\nfactory.set_theme('alibaba')      # 阿里巴巴配色\nfactory.set_theme('tencent')      # 腾讯配色\nf"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn76k6338wpqydkxgdztg6vb9x83hz20\",\n  \"slug\": \"sql-dataviz\",\n  \"version\": \"1.0.1\",\n  \"publishedAt\": 1774607613832\n}"},{"path":"references/bar-charts.md","content":"# 条形图 & 横向条形图\n\n适用场景：分类比较、排名展示。\n\n---\n\n## 纵向条形图（类别 ≤ 10）\n\n```python\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nplt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']\nplt.rcParams['axes.unicode_minus'] = False\n\nfig, ax = plt.subplots(figsize=(10, 6))\n\nbars = ax.bar(df['category'], df['value'],\n              color='#3b82f6', width=0.6, edgecolor='white')\n\n# 柱顶标注数值\nfor bar in bars:\n    h = bar.get_height()\n    ax.text(bar.get_x() + bar.get_width()/2, h + max(df['value'])*0.01,\n            f'{h:,.0f}', ha='center', va='bottom', fontsize=10)\n\nax.set_title('各品类销售额', fontsize=15, fontweight='bold', pad=12)\nax.set_xlabel('品类')\nax.set_ylabel('销售额（万元）')\nax.set_ylim(0, max(df['value']) * 1.15)  # 留出标注空间\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('bar_chart.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 横向条形图（排名 / 类别多 / 名称长）\n\n```python\n# 按值排序，最大值在顶部\ndf_sorted = df.sort_values('value', ascending=True)\n\nfig, ax = plt.subplots(figsize=(10, max(6, len(df_sorted) * 0.4)))\n\n# 高亮 Top 1\ncolors = ['#ef4444' if i == len(df_sorted)-1 else '#3b82f6'\n          for i in range(len(df_sorted))]\n\nbars = ax.barh(df_sorted['name'], df_sorted['value'],\n               color=colors, height=0.6)\n\n# 右侧标注数值\nfor bar in bars:\n    w = bar.get_width()\n    ax.text(w + max(df_sorted['value'])*0.01, bar.get_y() + bar.get_height()/2,\n            f'{w:,.0f}', va='center', fontsize=10)\n\nax.set_title('Top 用户消费排名', fontsize=15, fontweight='bold', pad=12)\nax.set_xlabel('消费金额（元）')\nax.set_xlim(0, max(df_sorted['value']) * 1.12)\nax.grid(axis='x', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('bar_horizontal.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 分组条形图（多系列对比）\n\n```python\n# df 列：month, group_a, group_b, group_c\ncategories = df['month'].tolist()\nx = np.arange(len(categories))\nwidth = 0.25\nPALETTE = ['#3b82f6', '#10b981', '#f59e0b']\n\nfig, ax = plt.subplots(figsize=(12, 6))\n\nfor i, (col, label) in enumerate([('group_a', 'PC端'), ('group_b', '移动端'), ('group_c', '小程序')]):\n    offset = (i - 1) * width\n    bars = ax.bar(x + offset, df[col], width, label=label,\n                  color=PALETTE[i], edgecolor='white')\n\nax.set_xticks(x)\nax.set_xticklabels(categories)\nax.legend()\nax.set_title('各渠道月度订单量对比', fontsize=15, fontweight='bold')\nax.grid(axis='y', alpha=0.3, linestyle='--')\nax.spines['top'].set_visible(False)\nax.spines['right'].set_visible(False)\n\nplt.tight_layout()\nplt.savefig('grouped_bar.png', dpi=150, bbox_inches='tight')\n```\n\n---\n\n## 堆叠条形图（占比构成）\n\n```python\nfig, ax = plt.subplots(figsize=(12, 6))\nPALETTE = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444']\n\nbottom = np.zeros(len(df))\nfor i, col in enumerate(['cat_a', 'cat_b', 'cat_c', 'cat_d']):\n    ax.bar(df['month'], df[col], bottom=bottom,\n           label=col, color=PALETTE[i], edgecolor='white', linewidth=0.5)\n    bottom += df[col].val"},{"path":"references/canvas-render.md","content":"# Canvas 内嵌渲染\n\n在对话中直接渲染图表，无需保存文件，用户即时看到结果。\n\n---\n\n## 什么时候用 Canvas 渲染\n\n- 用户想在对话里直接看图，不想保存文件\n- 快速验证图表效果\n- 演示/汇报场景，需要即时展示\n\n---\n\n## 使用方式\n\n通过 `canvas` 工具的 `eval` action 执行 JavaScript，渲染 Chart.js 图表。\n\n### 折线图示例\n\n```javascript\n// canvas eval 内容\nconst ctx = document.getElementById('chart').getContext('2d');\nnew Chart(ctx, {\n  type: 'line',\n  data: {\n    labels: ['1月', '2月', '3月', '4月', '5月', '6月'],\n    datasets: [{\n      label: '订单量',\n      data: [1200, 1900, 1500, 2100, 2400, 2800],\n      borderColor: '#3b82f6',\n      backgroundColor: 'rgba(59,130,246,0.1)',\n      borderWidth: 2,\n      fill: true,\n      tension: 0.4,\n      pointRadius: 4\n    }]\n  },\n  options: {\n    responsive: true,\n    plugins: {\n      title: { display: true, text: '月度订单量趋势', font: { size: 16 } },\n      legend: { position: 'top' }\n    },\n    scales: {\n      y: { beginAtZero: true, grid: { color: 'rgba(0,0,0,0.05)' } }\n    }\n  }\n});\n```\n\n### Canvas HTML 模板\n\n```html\n<!DOCTYPE html>\n<html>\n<head>\n  <script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>\n  <style>\n    body { font-family: 'Microsoft YaHei', sans-serif; padding: 20px; background: #fff; }\n    .chart-container { max-width: 800px; margin: 0 auto; }\n  </style>\n</head>\n<body>\n  <div class=\"chart-container\">\n    <canvas id=\"chart\"></canvas>\n  </div>\n  <script>\n    // 在这里放图表代码\n  </script>\n</body>\n</html>\n```\n\n---\n\n## Chart.js 常用图表类型\n\n| type 值 | 图表类型 |\n|---------|---------|\n| `'line'` | 折线图 |\n| `'bar'` | 条形图（纵向） |\n| `'bar'` + `indexAxis: 'y'` | 横向条形图 |\n| `'pie'` | 饼图（慎用） |\n| `'doughnut'` | 环形图 |\n| `'scatter'` | 散点图 |\n| `'bubble'` | 气泡图 |\n| `'radar'` | 雷达图 |\n\n---\n\n## 多系列条形图示例\n\n```javascript\nnew Chart(ctx, {\n  type: 'bar',\n  data: {\n    labels: ['Q1', 'Q2', 'Q3', 'Q4'],\n    datasets: [\n      {\n        label: 'PC端',\n        data: [3200, 4100, 3800, 5200],\n        backgroundColor: '#3b82f6'\n      },\n      {\n        label: '移动端',\n        data: [5100, 6200, 7100, 8900],\n        backgroundColor: '#10b981'\n      }\n    ]\n  },\n  options: {\n    responsive: true,\n    plugins: {\n      title: { display: true, text: '各渠道季度订单量' }\n    },\n    scales: { y: { beginAtZero: true } }\n  }\n});\n```\n\n---\n\n## 注意事项\n\n- Canvas 渲染依赖网络加载 Chart.js CDN，离线环境需本地引入\n- 数据量大时（>1000 点），建议先聚合再渲染，避免卡顿\n- 中文字体在 Canvas 中需要系统已安装对应字体\n- 复杂统计图（箱线图、小提琴图）建议用 Python matplotlib 生成图片，再展示"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Convert SQL query results into production-grade visual charts including bar, line, pie, map, KPI, AI insights, and interactive HTML dashboards with base64 PN... Skill: SQL Dataviz Owner: moniq888 Summary: Convert SQL query results into production-grade visual charts including bar, line, pie, map, KPI, AI insights, and interactive HTML dashboards with base64 PN... Tags: latest:1.0.1 Version history: v1.0.1 | 2026-03-27T10:33:33.832Z | user - 修正协作工具名称，将“report-generator”统一为“sql-report-generator”以匹配实际 Skill 名称 - 数据分析流程示意图和协作流程文档细节微调，增强 Skill 协作关系说明 - 文档其余内容未变，功能和接口保持不变 v1.0.0 |","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":787,"uniquenessScore":58,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T21:34:47.045Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T21:34:47.045Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-13T06:52:19.121Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}