mcpField
G
graphic-chart

graphic-chart

github.com/varnan-tech数据与数据库68744 次安装2 周前更新
代码仓库

关于 graphic-chart

这项技能可将 JSON 或 CSV 数据制作成 PNG 图表,使用 Playwright 在无头 Chromium 中渲染 Apache ECharts。它涵盖图表配置、样式预设、渲染检查和导出步骤。

主要功能

  1. 01支持柱状、折线、面积、饼图、散点、雷达和矩形树图
  2. 02解析 JSON 数组、对象数组及 CSV
  3. 03提供五种命名样式
  4. 04使用 Apache ECharts 和 Playwright 渲染 HTML
  5. 05以 2× 设备比例导出 PNG

适用场景

  1. 01将结构化数据转换为静态图表图片
  2. 02突出显示选定数值或类别
  3. 03按指定样式和尺寸导出图表

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/varnan-tech/opendirectory --skill graphic-chart

安装后在 Claude Code 中输入/graphic-chart确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
evals/
evals.json
references/
chart-library.md
style-presets.md
scripts/
export-chart.sh
screenshot-chart.mjs

详细介绍

graphic-chart

将数据可视化图表生成为 PNG。通过 Playwright 在无头 Chromium 中使用 Apache ECharts v6 渲染 HTML → 以 2× Retina 画质截图。

CDN:https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js


关键规则(每次生成前阅读)

  1. area 类型 → type: 'line' + areaStyle: {}——ECharts 没有 type: 'area'。
  2. doughnut → type: 'pie' + radius: ['40%', '70%']——ECharts 没有 type: 'doughnut'。
  3. 就绪信号:在 chart.setOption() 之前注册 chart.on('finished', fn)——ECharts bug #14101/#17500:如果在 setOption 之后注册监听器,它会静默地永远不触发。务必在 setOption 之前注册 finished 和 rendered 两个事件。
  4. 必须显式设置 xAxis.type: 'category'——ECharts 不会根据数据推断此类型。忘记设置会生成空白图表。
  5. 类别标签放在 xAxis.data 中,不要放在 data.labels 数组中。ECharts 结构是扁平的:{ xAxis, yAxis, series, grid, title, legend }——不嵌套在 data 或 options 下。
  6. 数据标签为内置功能——在任意系列上使用 label: { show: true }。无需插件。
  7. 通过单项 itemStyle 突出显示特定柱形/数据点——直接在 data 数组中放入 { value: N, itemStyle: { color: '#...' } }。不要使用 Chart.js 风格的 backgroundColor 数组。
  8. ECharts 使用 <div> 容器初始化,而非 <canvas>——echarts.init(document.getElementById('chart'))。容器 div 必须显式设置尺寸。
  9. 在选项中设置 animation: false——禁用动画,实现即时渲染。仍须在 setOption 之前注册 finished + rendered 事件作为就绪信号。
  10. **切勿在聊天中输出 HTML。**保存到文件,只显示摘要。
  11. **标题应说明洞察,而非主题。**使用“Revenue grew 3× in 12 months”,而不是“Monthly Revenue”。
  12. 饼图/圆环图:使用正文 padding: 64px 80px 和 .chart-container { max-height: 860px }——在没有标题时可避免图表铺满整个区域。

步骤 1:收集信息

必填:chart_type、data

可选参数及默认值:

参数默认值说明
chart_type—bar / line / area / pie / doughnut / scatter / radar / treemap
data—JSON 数组或 CSV——必填
title—说明洞察,不超过 10 个词
subtitle—1 句话的背景说明
styleclean-slateclean-slate / midnight-editorial / matt-gray / electric-burst / brutalist
dimensions1080x1080WxH 像素(输出 PNG 通过 deviceScaleFactor 达到 2×)
x_label—X 轴标签文本
y_label—Y 轴标签文本
source—页脚中显示的数据来源
highlight—要突出显示的数据标签(例如 "Q4"、"Dec"、索引 3)

如果缺少 chart_type 或 data,请原样询问:

"要创建图表,我需要:

  1. 图表类型——bar / line / area / pie / doughnut / scatter / radar / treemap
  2. 数据——请提供 JSON 数组或 CSV(例如 [12, 18, 22, 25, 31],标签为 ['Q1','Q2','Q3','Q4','Q5'])

可选:标题、样式(默认:clean-slate)、尺寸(默认:1080×1080)、要突出显示的特定数据点"

如果两项都已提供 → 跳至步骤 2。


第 2 步:内部架构(绝不向用户显示)

1. 规范化图表类型:

  • area → line + 在系列上设置 areaStyle: {}
  • doughnut → pie + 在系列上设置 radius: ['40%', '70%']
  • horizontal bar → bar + 交换 xAxis/yAxis(类目轴在 y 轴)
  • 其他类型:保持原样

2. 阅读 references/chart-library.md —— 加载此图表类型的完整配置规范。

3. 阅读 references/style-presets.md —— 加载所选样式的 CSS 令牌和数据调色板。

4. 确定设计方向:

决策依据
基调专业 / 编辑风 / 大胆 / 技术风——与数据受众相匹配
数据故事此图表要证明的单一洞见(作为标题)
强调策略哪个数据点需要视觉强调,原因是什么?
背景浅色(clean-slate、matt-gray)或深色(midnight-editorial、electric-burst、brutalist)

5. 解析数据:

  • 简单数组 [12, 18, 22] → series.data,标签单独提供
  • 对象数组 [{x: 'Jan', y: 12}] → 从 x 键设置 xAxis.data,从 y 值设置 series.data
  • CSV:将标题行解析为 xAxis.data,将数值行解析为 series.data
  • 多系列:使用多个 series 条目,每个条目包含 type、name、data
  • 散点图:使用 series.data: [[x1,y1], [x2,y2], ...] 格式

6. 解析尺寸: "1080x1080" → W=1080,H=1080。主体尺寸 = WxH。输出 PNG = 2W × 2H。


第 3 步:生成 HTML

生成前阅读所有内容:

  • references/chart-library.md 中此图表类型的完整 ECharts 配置规范
  • references/style-presets.md 中所选样式的 CSS 令牌和调色板

必需的 HTML 结构:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
[font CDN link from style preset]
<style>
:root {
  [all CSS tokens from style preset]
}

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
  width: [W]px; height: [H]px;
  overflow: hidden;
  background: var(--bg);
  font-family: var(--font-body);
}
body {
  display: flex;
  flex-direction: column;
  padding: 40px 48px 32px;   /* pie/doughnut: use 64px 80px */
}

/* ECharts container must have explicit size */
.chart-container {
  flex: 1;
  min-height: 0;
  /* pie/doughnut only: max-height: 860px; */
}

.chart-header { margin-bottom: 24px; }
.chart-title {
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 2.5vw, 1.6rem);
  font-weight: 700;
  color: var(--text);
  line-height: 1.2;
}
.chart-subtitle {
  font-family: var(--font-body);
  font-size: clamp(0.75rem, 1.2vw, 0.9rem);
  color: var(--text-muted);
  margin-top: 6px;
  line-height: 1.5;
}
.chart-footer {
  margin-top: 14px;
  font-family: var(--font-body);
  font-size: 10px;
  color: var(--text-muted);
  opacity: 0.65;
}
</style>
</head>
<body>

[if title or subtitle: <div class="chart-header"><div class="chart-title">...</div>...</div>]

<div id="chart" class="chart-container"></div>

[if source: <div class="chart-footer">Source: [source]</div>]

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>

<script>
window.__chartReady = false;

document.fonts.ready.then(() => {
  const container = document.getElementById('chart');
  const chart = echarts.init(container, null, { renderer: 'canvas' });

  // CRITICAL: register events BEFORE setOption — ECharts bug #14101/#17500
  // 'finished' may silently not fire if registered after setOption with animation:false
  chart.on('finished', () => {
    window.__chartReady = true;
  });
  // Belt-and-suspenders fallback via 'rendered'
  chart.on('rendered', () => {
    clearTimeout(window.__renderDebounce);
    window.__renderDebounce = setTimeout(() => { window.__chartReady = true; }, 100);
  });

  const palette = [palette from style preset];

  const option = {
    animation: false,                            // instant render for screenshot

    backgroundColor: 'transparent',             // body CSS handles bg color

    textStyle: {
      fontFamily: '[--font-body value]',
      color: '[--text-muted value]',
    },

    [title config if title param provided],
    [legend config per chart type],
    [grid config per chart type],
    [xAxis config per chart type],
    [yAxis config per chart type],

    series: [{
      [full series config from chart-library.md for this type]
      [palette colors applied per chart type]
      [if highlight: per-item itemStyle on the highlighted data point]
    }]
  };

  chart.setOption(option);   // setOption ALWAYS comes after event registration
});
</script>
</body>
</html>

设计质量规则:

  • 标题字体:fontWeight: 'bold'、fontSize: 20–24 —— 不使用细体标题
  • 网格线:低不透明度(0.06–0.10)——弱化网格线,突出数据
  • 柱形:barMaxWidth: 60,通过 itemStyle.borderRadius: [4,4,0,0] 设置圆角
  • 折线:使用 smooth: true 绘制自然曲线,点的 symbolSize: 8
  • 饼图/环形图:使用 label.formatter: '{b}\n{d}%' 显示内置扇区标签
  • 深色预设:网格使用 rgba(255,255,255,0.07),坐标轴线/刻度颜色使用 rgba(255,255,255,0.15)
  • Tooltip:show: false —— 静态 PNG,无悬停交互
  • 未提供标题时:跳过 .chart-header,并从 ECharts option 中省略标题

第 4 步:自检(在第 5 步前修复所有问题)

结构:

  • 容器是 <div>,不是 <canvas>
  • 在 document.fonts.ready 之前声明 window.__chartReady = false
  • 在 chart.setOption() 之前注册 chart.on('finished', ...)
  • 在 chart.setOption() 之前注册 chart.on('rendered', ...) 防抖回退处理程序
  • option 对象中设置 animation: false
  • chart.setOption(option) 是初始化代码块中的最后一次调用

特定类型:

  • 面积图:type: 'line' + areaStyle: {} —— 不使用 type: 'area'
  • 环形图:type: 'pie' + radius: ['40%', '70%'] —— 不使用 type: 'doughnut'
  • 柱状图:显式设置 xAxis.type: 'category'
  • 类目数据放在 xAxis.data 中(而不是 data.labels)
  • 饼图/环形图:主体 padding: 64px 80px + .chart-container { max-height: 860px }
  • 高亮:在数据数组中使用单项 { value: N, itemStyle: { color } }

设计:

  • 所有调色板颜色均来自 references/style-presets.md
  • 标题说明洞见(不只是主题)
  • tooltip: { show: false } 或省略(静态 PNG 无悬停交互)
  • 深色预设:网格/坐标轴颜色使用 rgba(255,255,255,...)
  • 如果提供了 source 参数,则在页脚注明来源
  • 数据标签可见(在系列上启用内置 label: { show: true })

第 5 步:导出

根据标题或“图表类型 + 数据背景”确定 slug(kebab-case,≤30 个字符):

mkdir -p chart/[slug]

保存 HTML:chart/[slug]/chart.html

快速检查浏览器:

open chart/[slug]/chart.html

运行导出(将 [skill-root] 替换为此技能目录的实际路径):

bash [skill-root]/scripts/export-chart.sh \
  chart/[slug]/chart.html \
  chart/[slug]/chart.png \
  --width [W] \
  --height [H]

脚本首次运行时会安装 Playwright(下载约 200MB 的 Chromium),随后以 deviceScaleFactor: 2 截取图表。


第 6 步:输出摘要

## Chart: [title]
Date: [YYYY-MM-DD] | Type: [chart_type] | Style: [style]
Dimensions: [W×H]px → PNG: [2W×2H]px @2× retina

Files
  Source:   chart/[slug]/chart.html
  Output:   chart/[slug]/chart.png
  Size:     [X] KB

Checklist
- [ ] Title states the insight clearly
- [ ] Data labels legible at display size
- [ ] Highlight visible on correct data point
- [ ] Source attribution present in footer

提示词技巧(用户寻求指导时展示)

“提供结构化数据——使用 JSON 或 CSV,而非文字描述。”

“明确指定图表类型。写‘对比第 1 季度至第 4 季度的柱状图’,不要写‘展示各季度的图表’。”

“说明数据所表达的故事。‘突出表现优于其他季度的第 4 季度’能提供注释所需的背景。”

✅ 好:“创建折线图。标题:‘12 个月内 ARR 从 1.2 万美元增至 9.5 万美元’。数据:[12, 18, 22, 25, 31, 38, 44, 52, 61, 68, 78, 95](2024 年 1 月至 12 月)。突出显示 12 月。来源:内部 CRM。风格:electric-burst。”

❌ 不好:“制作一张展示公司增长的图表”

评论

支持 Markdown