返回技能市场
数据分析 安全

智能图表生成

@bailian/smart-chart-generation

Intelligent chart generation and data analysis skill. Reads user-supplied data files (CSV/Excel/JSON), analyzes data characteristics with LLM assistance, auto-recommends and generates interactive ECharts visualizations.

阿里云百炼 热度 311v1.1

智能图表

本 skill 用于将数据文件(CSV/Excel/JSON)自动转化为交互式 ECharts 图表。
上传数据 → 自动分析 → 推荐图表类型 → 生成交互式 HTML。支持 16 种图表类型,多文件合并,以及 LLM 生成的数据转换代码(在沙箱中安全执行)。
以下各节面向 agent 编写。请阅读这些内容,以决定何时以及如何调用此 skill。

---

启用条件

满足以下任一条件时,加载此 skill:

  • 用户提到:“分析数据”、“生成图表”、“数据可视化”、“图表”、“可视化”
  • / 用户提到:「分析数据」「生成图表」「数据可视化」

  • 用户提供数据文件并要求进行分析或可视化
  • 用户要求根据表格数据生成图表或报告

---

硬性约束(必须遵循)

  1. 必须遵循 CLI 工作流data_parser.py → 确认并推荐 → chart_generator.py。即使数据看起来杂乱,也不得编写临时 Python 脚本来替代 CLI 调用。
  2. 处理杂乱表头时必须使用 CLI 参数,不得绕过工作流。data_parser.pychart_generator.py 均支持使用 --skiprows N / --header-row N / --sheet <name|index> 处理多行表头、开头的无关行和多工作表 Excel 文件。N 的值必须通过检查实际数据来确定,禁止硬编码。
  3. 当原始列与目标图表格式不匹配时,必须使用 --transform-code 进行列重命名/重塑/聚合。数据解析层仅处理“哪一行是表头”;其他所有清洗都应通过转换代码完成。
  4. 必须报告不支持的场景:如果 CLI 确实不支持某种数据结构(例如嵌套对象超过 1 层),则必须先向用户报告问题并提供建议,然后才能回退到手动编写脚本。禁止静默绕过。
  5. 不得在生成的代码中硬编码绝对路径;应在运行时解析路径。
  6. 不得跳过确认步骤,除非用户明确表示“自动生成” / “无需确认”。
  7. 必须使图表语言与数据语言保持一致:所有图表文本(标题、系列名称、提示框、按钮、页脚、HTML 的 lang)均采用数据的语言(自动检测:CJK 比例 > 5% 时为中文,否则为英文)。仅当用户明确要求特定语言时才传入 --lang zh|en。禁止在同一图表中混用语言。

---

能力边界

支持: CSV(.csv/.tsv/.txt)、Excel(.xlsx/.xls)、JSON(.json);16 种图表类型(见下文);最多可自动合并约 10 个文件;单个文件 ≤ 100 MB(建议 ≤ 50 MB);自动检测 UTF-8/GBK/GB2312。

不支持: 数据库(先导出为 CSV)、实时/流式数据、地理地图、超过 100 MB 的文件、嵌套层级超过 1 层的 JSON、非表格数据(图像/音频/视频)。自动合并要求列重叠率 ≥ 50%。

网络要求: 生成的 HTML 通过 CDN(jsdelivr/unpkg)加载 ECharts。渲染图表需要互联网连接。Agent 运行时假定网络已连通。

---

安全性

由 LLM 生成的转换代码在三层安全防护下执行(无需用户确认):(1)关键字黑名单(阻止 execevalopenimportos.system 等),(2)AST 白名单(仅允许赋值、调用、循环和推导式),(3)沙箱内置函数(仅允许 lenrangesorted 等安全函数;已移除 open/exec/eval/__import__)。被阻止的代码会引发 CodeValidationError,其中 suggestion 字段会说明解决方法。

---

执行工作流

  1. 获取数据 — 用户上传文件或提供路径。
  2. 解析数据 — 对所有文件调用 data_parser.py;若有多个文件,则评估合并可行性。
  3. 确认并推荐 — 显示摘要表;根据数据语义推荐合并、分别处理或连接策略以及图表类型;等待用户确认。
  4. 转换(如有需要) — 如果原始数据与目标图表的输入格式不匹配,则由 LLM 生成 pandas 转换代码 → 安全检查(黑名单 + AST)→ 在沙箱中执行 → 标准化的 DataFrame。失败时:最多重试 2 次,随后回退到原始数据 + 自动检测。
  5. 生成图表 — 调用 chart_generator.py → ECharts HTML。合并数据 → 跨组比较;分开处理的数据 → 每个文件生成独立图表。
  6. 呈现结果 — 通过 html_path 提供交互式图表。

关键原则: 多文件优先;执行前确认;LLM 根据数据语义选择图表类型(禁止硬编码映射);禁止硬编码绝对路径(在运行时解析);立即呈现结果;必要时通过转换代码适配数据;默认保障安全。

---

配置

output_dir: ./smart_charts_output  # optional; never hard-code absolute paths

---

错误码

所有错误均通过 SmartChartsError.to_dict() 以结构化字典形式返回: {"error": <message>, "code": <int>, "code_name": <str>, "details": {...}}details 字段始终包含 suggestion,用于告知 agent 如何恢复。

| 代码 | 名称 | 含义 | |------|------|---------| | 1001 | FILE_NOT_FOUND | 文件路径不存在 | | 1002 | FILE_PERMISSION_DENIED | 路径不是常规文件 | | 1003 | FILE_FORMAT_INVALID | 不支持的文件扩展名 | | 1004 | FILE_SIZE_EXCEEDED | 文件大小超过 100 MB 上限 | | 2001 | DATA_PARSE_ERROR | 解析失败(编码、结构等) | | 2003 | DATA_EMPTY | 文件或清洗后的数据为空 | | 2004 | DATA_TYPE_MISMATCH | 数据类型不匹配 | | 3001 | TRANSFORM_EXEC_ERROR | 转换代码执行失败(黑名单/AST/超时) | | 3002 | TRANSFORM_NO_RESULT | 转换代码未生成 result 变量 | | 3003 | TRANSFORM_INVALID_RESULT | result 不是 DataFrame | | 3004 | TRANSFORM_EMPTY_RESULT | result DataFrame 为空 | | 4001 | CHART_GENERATION_ERROR | 图表生成失败 | | 4002 | CHART_TYPE_UNSUPPORTED | 不支持的图表类型 | | 4003 | CHART_CONFIG_ERROR | DataFrame 中不存在轴字段 | | 9999 | UNKNOWN_ERROR | 未分类错误 |

---

数据解析

{skill_base} = 此 skill 的根目录(包含 SKILL.md)。

单个文件:

python {skill_base}/core/data_parser.py <file_path> [--summary] [--skiprows N] [--header-row N] [--sheet <name|index>]

多个文件(可选自动合并):

python {skill_base}/core/data_parser.py <file1> <file2> ... [--merge] [--summary]

表头 / 跳过行标志(仅限单文件):

  • --skiprows N — 跳过前 N 行,然后将下一行作为表头读取。当文件在任意表头之前存在前置无效行(注释、空行)时使用。
  • --header-row N — 将以 0 为起始索引的第 N 行作为表头;丢弃 N 上方的行。当文件具有多行表头(合并单元格、子表头),且要将其中某一行用作列名时使用。
  • --sheet <name|index> — 按名称或以 0 为起始索引的位置选择 Excel 工作表(默认值:0)。
  • N 的值通过检查实际数据确定(例如,首次运行 data_parser.py 时不使用标志)。禁止假定所有文件都使用固定的 N 值。

合并行为:

  • 列完全相同 → 纵向拼接。⚠️ 会注入一个 source_file,用于指示每行的来源文件。下游转换代码必须考虑这个额外列。
  • 列重合度 ≥ 50% → 基于共享键横向连接。
  • 无共同结构 → 报错(建议分别分析)。

Programmatic API: DataParser.parse_files(paths, merge=...) -> {'merged': bool, 'data': ..., 'merge_type': Optional[str]}.

  • parse_file(path, skiprows=None, header_row=None, sheet_name=0) — 单个文件,可选择清理表头。
  • parse_files(paths, merge=...) — 多个文件;merge=False 返回 List[{'file', 'data'}]merge=True 返回合并后的 DataFrame

---

图表生成

python {skill_base}/core/chart_generator.py \
  <file_path> <chart_type> \
  --title "Chart Title" \
  --x-axis "date" \
  --y-axis "revenue profit" \
  --transform-code "<pandas code>" \
  --skiprows N --header-row N --sheet <name|index> \
  --lang zh|en \
  --output-dir "./output"

参数: file_path(必填),chart_type(必填,见下表),--title(默认值遵循 --lang / 数据语言),--x-axis(省略时自动检测),--y-axis(以空格分隔;默认使用前 5 个数值列),--transform-code(由 LLM 生成的 pandas 代码,经验证并在渲染前执行),--skiprows / --header-row / --sheet(与 data_parser.py 语义相同;透传至解析步骤),--lang zh|en(可选;覆盖自动检测结果),--output-dir(默认值:./smart_charts_output)。

语言一致性(必须遵循):所有图表文本——标题、系列名称、工具提示标签、操作按钮(“保存图片” / “全屏”)、滚动提示、页脚以及 HTML 的 lang 属性——都必须遵循数据的语言。CLI 根据列名和字符串单元格内容自动检测中文或英文(CJK 字符占比 > 5% → zh,否则为 en)。仅当用户明确要求特定语言时,才传入 --lang zh--lang en;否则,让自动检测结果与数据保持一致。禁止在同一图表中混用多种语言。

溢出处理:当图表的数据点数量超过缩放阈值(默认值为 15)时,生成的 HTML 会自动启用 ECharts dataZoom(滑块 + 内部拖动),并在图表容器上启用水平滚动条,因此用户可以拖动滑块、水平滚动或单击全屏按钮来查看所有数据点。agent 无需执行任何操作。

图表类型

LLM 必须检查原始数据是否符合所需格式;如果不符合,则生成转换代码。

| ID | 最适用场景 | 触发关键词 | y_axis 基数 | 所需的 DataFrame 格式 | 示例列 | |----|----------|------------------|:-------------------:|--------------------------|-----------------| | line | 时间序列趋势 | trend, change, over time, 趋势, 变化, 走势 | 1~N | 1 个类别/时间列 + 1 至 N 个数值列 | month, productA, productB | | bar | 类别比较 | compare, rank, difference, 对比, 比较, 排名, 差异 | 1~N | 1 个类别列 + 1 至 N 个数值列 | city, revenue, profit | | area | 累计变化 | cumulative, change, 累计, 变化 | 1~N | 1 个类别/时间列 + 1 至 N 个数值列 | date, uv, pv | | pie | Composition/share | share, composition, proportion, 占比, 构成, 比例 | 1 | 1 个名称列 + 1 个值列 | category, share | | scatter | 相关性 | correlation, relationship, scatter, 相关, 关系, 散点 | 1 | 2 个数值列,或 1 个类别列 + 1 个数值列 | height, weight | | radar | 多维比较 | multi-dimension, comprehensive, radar, 多维, 综合, 雷达 | N | 1 个指标列 + N 个数值列 | metric, productA, productB | | heatmap | Density/cross-tab | density, cross, matrix, heatmap, 密度, 交叉, 矩阵, 热力 | N | 2 个类别列 + 1 个数值列 | row, col, value | | treemap | 层级占比 | hierarchy, proportion, nested, 层级, 占比, 嵌套 | 1 | 1 个名称列 + 1 个值列 | category, sales | | graph | 实体关系 | relationship, network, topology, 关系, 网络, 拓扑 | 特殊 | 源列 + 目标列(+ 值列) | from, to, weight | | boxplot | Distribution/outliers | distribution, outlier, quartile, 分布, 离群, 四分位 | N | N 个数值列 | math, chinese, english | | waterfall | 增量变化 | increment, change, waterfall, 增量, 变化, 瀑布 | 1 | 1 个类别列 + 1 个数值列(增量) | month, profit_delta | | gauge | KPI 进度 | progress, kpi, achievement, 进度, KPI, 达成 | 1 | 1 个数值列(使用均值) | completion_rate | | sankey | 流量转移 | flow, transfer, sankey, 流向, 流量, 转移 | 特殊 | 源 + 目标 + 值 | origin, destination, amount | | funnel | 转化率 | conversion, funnel, churn, 转化, 漏斗, 流失 | 1 | 1 个名称列 + 1 个值列 | stage, count | | sunburst | 多层级构成 | hierarchy, proportion, nested, 层级, 占比, 嵌套 | 1 | 1 个名称列 + 1 个值列 | category, value | | wordcloud | Frequency/keywords | word frequency, keywords, text, 词频, 关键词, 词云 | 1 | 1 个名称列 + 1 个值列 | word, frequency |

y_axis 基数说明:1 = 仅使用第一列(其余列将被静默忽略);1~N = 每列都会成为一个系列;N = 预期有多列;special = 自动检测源列、目标列和值列。

编程 API

from core.chart_generator import ChartGenerator

# Single chart — returns {'chart': {'success', 'html_path'/'error', ...}}
# lang=None auto-detects from data; pass 'zh'/'en' to override (only when user asks).
result = ChartGenerator(output_dir="./output").generate_chart(
    df=df, chart_type="bar", title="Regional Revenue",
    x_axis="region", y_axis=["revenue"], lang=None,
)
# result = {"chart": {"success": True, "html_path": "...", "chart_type": "bar", "title": "..."}}

# Batch — returns {'charts': [...]} where each item has the same shape as 'chart' above
result = ChartGenerator(output_dir="./output").generate_multi_charts(
    df=df,
    chart_configs=[
        {"type": "bar",  "title": "Regional Revenue", "x_axis": "region", "y_axis": ["revenue"]},
        {"type": "line", "title": "Monthly Trend",   "x_axis": "month",  "y_axis": ["revenue", "profit"]},
    ],
    lang=None,
)

失败时,successFalseerror 包含结构化字典(其结构与 SmartChartsError.to_dict() 相同)。不会抛出异常——agent 会检查 success 以决定后续步骤。

---

转换代码生成

当原始数据与目标图表的输入格式不匹配时,使用以下提示词模板:

Known information:
- Raw data columns: {columns_with_dtypes}
- Data sample (first 5 rows): {sample}
- Target chart type: {chart_type}
- Required format for this chart: {chart_input_spec}

Generate a pandas code snippet that transforms df into a result DataFrame matching the chart's input format.

Rules:
1. Only use variables: df, pd, np
2. Must produce a variable named result (pd.DataFrame)
3. Do not modify df in-place; use df.copy() or chain operations
4. Keep code concise; prefer pandas built-in methods (pivot_table, melt, groupby, rename, etc.)
5. If raw data already matches the required format, output an empty string
6. Do NOT use: import, open, exec, eval, os, sys, subprocess, file I/O, network calls

Output format:

{转换操作的单行说明}

{transform_code}

常见转换模式:

  • 长格式→多系列:result = df.pivot_table(index='<time>', columns='<category>', values='<value>', aggfunc='sum').reset_index()
  • 长格式→饼图(筛选):result = df[df['metric']=='revenue'][['category','value']].rename(columns={'category':'name'})
  • 宽格式→长格式:result = df.melt(id_vars=['date'], var_name='name', value_name='value')
  • 聚合→柱状图:result = df.groupby('<category>')['<value>'].sum().reset_index()
  • 重命名列:result = df.rename(columns={'来源':'source','去向':'target','金额':'value'})
  • 计算差值→瀑布图:tmp = df.copy(); tmp['delta'] = tmp['profit'].diff().fillna(tmp['profit'].iloc[0]); result = tmp[['month','delta']]
  • 重命名混乱或表意不明的列名(当使用 --header-row 后留下类似 10分unnamed_3 的列名时):result = df.rename(columns={'unnamed_0':'student_id','unnamed_1':'name','10分':'homework_score','30分':'exam_score'})
  • 向前填充合并单元格(当一个分组中只有第一行有值时):result = df.ffill()
  • 将子表头合并为单个列名(当 --header-row N 将一行扁平化但丢失上下文时):result = df.rename(columns={c: f'{c}_score' for c in df.columns if c not in ['student_id','name']})

有关 CLI 参考文档和安装说明,请参阅 [REFERENCE.md](./REFERENCE.md)。

qianwen skills install @bailian/smart-chart-generation