跳至主要内容
小龙虾小龙虾AI
🤖

smart-charts

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.

下载1.2k
星标2
版本4.0.1
营销推广
安全通过

技能说明


name: "smart-charts" version: “4.0.1” description: "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." author: "smart-charts" license: "MIT" cost: tokens_per_call: "~500-2500" execution_time: "1-10s" permissions: file_read: true file_write: true network: true safety: sandbox: "LLM-generated transform code runs in a restricted sandbox (keyword blacklist + AST whitelist + safe builtins). No user confirmation required." input_formats: ["csv", "tsv", "txt", "xlsx", "xls", "json"] output_format: "html" max_file_size_mb: 100

Smart Charts

本 skill 用于将数据文件(CSV/Excel/JSON)自动转化为交互式 ECharts 图表。 上传数据 → 自动分析 → 推荐图表类型 → 生成交互式 HTML。支持 16 种图表类型,多文件合并,以及 LLM 生成的数据转换代码(在沙箱中安全执行)。

The sections below are written for the agent. Read them to decide when and how to call this skill.


Activation Triggers

Load this skill when any of the following is met:

  • User mentions: "analyze data", "generate chart", "data visualization", "chart", "visualization" / 用户提到:「分析数据」「生成图表」「数据可视化」
  • User provides a data file and asks for analysis or visualization
  • User asks to generate charts or a report from tabular data

Hard Constraints (MUST follow)

  1. MUST follow the CLI workflow: data_parser.py → confirm & recommend → chart_generator.py. Do NOT write ad-hoc Python scripts to replace CLI calls, even if the data looks messy.
  2. MUST use CLI parameters for messy headers instead of bypassing the workflow. data_parser.py and chart_generator.py both accept --skiprows N / --header-row N / --sheet <name|index> for multi-row headers, leading junk rows, and multi-sheet Excel files. The value of N is determined by inspecting the actual data — never hard-coded.
  3. MUST use --transform-code for column renaming / reshaping / aggregation when raw columns don't match the target chart format. Data parsing layer only handles "which row is the header"; all other cleaning belongs to transform code.
  4. MUST report unsupported scenarios: if a data structure is genuinely unsupported by CLI (e.g. nested objects >1 level), report the issue to the user with a suggestion before falling back to manual scripting. Never silently bypass.
  5. MUST NOT hard-code absolute paths in generated code; resolve paths at runtime.
  6. MUST NOT skip the confirm step unless the user explicitly says "auto-generate" / "no need to confirm".
  7. MUST keep chart language consistent with the data language: all chart text (title, series names, tooltips, buttons, footer, HTML lang) follows the data's language (auto-detected: CJK ratio > 5% → Chinese, otherwise English). Pass --lang zh|en ONLY when the user explicitly requests a specific language. Never mix languages within one chart.

Capability Boundaries

Supported: CSV (.csv/.tsv/.txt), Excel (.xlsx/.xls), JSON (.json); 16 chart types (see below); up to ~10 files with auto-merge; single file ≤ 100 MB (≤ 50 MB recommended); auto-detects UTF-8/GBK/GB2312.

Not supported: Databases (export to CSV first), real-time/streaming data, geo maps, >100 MB files, nested JSON >1 level, non-tabular data (images/audio/video). Auto-merge requires ≥50% column overlap.

Network requirement: Generated HTML loads ECharts via CDN (jsdelivr/unpkg). An internet connection is required to render the charts. Agent operation assumes connectivity is already available.


Security

LLM-generated transform code is executed with three safety layers (no user confirmation needed): (1) keyword blacklist (blocks exec, eval, open, import, os.system, etc.), (2) AST whitelist (only allows assignments, calls, loops, comprehensions), (3) sandbox builtins (only safe functions like len, range, sorted; open/exec/eval/__import__ removed). Blocked code raises CodeValidationError with a suggestion field explaining how to resolve.


Execution Workflow

  1. Obtain data — user uploads file(s) or provides path(s).
  2. Parse data — call data_parser.py on all files; for multiple files, assess merge feasibility.
  3. Confirm & recommend — display summary table; recommend merge/separate/join strategy and chart type(s) based on data semantics; wait for user confirmation.
  4. Transform (if needed) — if raw data doesn't match target chart's input format, LLM generates pandas transform code → security check (blacklist + AST) → execute in sandbox → standardized DataFrame. On failure: retry max 2 times, then fall back to original data + auto-detection.
  5. Generate charts — call chart_generator.py → ECharts HTML. Merged data → cross-group comparison; separate data → independent charts per file.
  6. Present results — interactive charts via html_path.

Key principles: multi-file first; confirm before executing; LLM chooses chart types by data semantics (never hard-code mapping); never hard-code absolute paths (resolve at runtime); present results immediately; adapt data via transform code when needed; security by default.


Configuration

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

Error Codes

All errors are returned as structured dicts via SmartChartsError.to_dict(): {"error": <message>, "code": <int>, "code_name": <str>, "details": {...}}. The details field always includes a suggestion telling the agent how to recover.

CodeNameMeaning
1001FILE_NOT_FOUNDFile path does not exist
1002FILE_PERMISSION_DENIEDPath is not a regular file
1003FILE_FORMAT_INVALIDUnsupported file extension
1004FILE_SIZE_EXCEEDEDFile exceeds 100 MB limit
2001DATA_PARSE_ERRORParsing failed (encoding, structure, etc.)
2003DATA_EMPTYFile or cleaned data is empty
2004DATA_TYPE_MISMATCHData type mismatch
3001TRANSFORM_EXEC_ERRORTransform code execution failed (blacklist/AST/timeout)
3002TRANSFORM_NO_RESULTTransform code did not produce result variable
3003TRANSFORM_INVALID_RESULTresult is not a DataFrame
3004TRANSFORM_EMPTY_RESULTresult DataFrame is empty
4001CHART_GENERATION_ERRORChart generation failed
4002CHART_TYPE_UNSUPPORTEDUnsupported chart type
4003CHART_CONFIG_ERRORAxis field does not exist in DataFrame
9999UNKNOWN_ERRORUnclassified error

Data Parsing

{skill_base} = root directory of this skill (contains SKILL.md).

Single file:

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

Multiple files (with optional auto-merge):

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

Header / row-skipping flags (single-file only):

  • --skiprows N — skip the first N rows, then read the next row as the header. Use when the file has leading junk rows (notes, blanks) before any header.
  • --header-row N — treat the 0-indexed row N as the header; rows above N are dropped. Use when the file has multi-row headers (merged cells, sub-headers) and you want one specific row as the column name.
  • --sheet <name|index> — pick an Excel sheet by name or 0-indexed position (default: 0).
  • The value of N is determined by inspecting the actual data (e.g. via a first data_parser.py run without flags). Never assume a fixed N for all files.

Merge behavior:

  • Identical columns → vertical concat. ⚠️ A source_file column is injected to indicate each row's origin file. Downstream transform code must account for this extra column.
  • ≥50% column overlap → horizontal join on shared key.
  • No common structure → error (advise analyzing separately).

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) — single file with optional header cleaning.
  • parse_files(paths, merge=...) — multi-file; merge=False returns List[{'file', 'data'}], merge=True returns merged DataFrame.

Chart Generation

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"

Parameters: file_path (required), chart_type (required, see table), --title (default follows --lang / data language), --x-axis (auto-detected if omitted), --y-axis (space-separated; defaults to first 5 numeric columns), --transform-code (LLM-generated pandas code, validated + executed before rendering), --skiprows / --header-row / --sheet (same semantics as data_parser.py; pass-through to the parsing step), --lang zh|en (optional; overrides auto-detection), --output-dir (default: ./smart_charts_output).

Language consistency (MUST follow): all chart text — title, series names, tooltip labels, action buttons ("Save Image" / "Fullscreen"), scroll hint, footer, and the HTML lang attribute — MUST follow the data's language. The CLI auto-detects Chinese vs. English from column names and string-cell content (CJK ratio > 5% → zh, otherwise en). Pass --lang zh or --lang en ONLY when the user explicitly requests a specific language; otherwise let auto-detection match the data. Never mix languages within a single chart.

Overflow handling: when a chart's data points exceed the zoom threshold (default 15), the generated HTML automatically enables ECharts dataZoom (slider + inside-drag) and a horizontal scrollbar on the chart container, so users can drag the slider, scroll horizontally, or click the fullscreen button to inspect all data points. No agent action needed.

Chart Types

LLM must check whether raw data matches the required format; if not, generate transform code.

IDBest ForTrigger Keywordsy_axis CardinalityRequired DataFrame FormatExample Columns
lineTime-series trendstrend, change, over time, 趋势, 变化, 走势1~N1 category/time + 1~N numericmonth, productA, productB
barCategory comparisoncompare, rank, difference, 对比, 比较, 排名, 差异1~N1 category + 1~N numericcity, revenue, profit
areaCumulative changecumulative, change, 累计, 变化1~N1 category/time + 1~N numericdate, uv, pv
pieComposition/shareshare, composition, proportion, 占比, 构成, 比例11 name + 1 valuecategory, share
scatterCorrelationcorrelation, relationship, scatter, 相关, 关系, 散点12 numeric, or 1 category + 1 numericheight, weight
radarMulti-dimension comparisonmulti-dimension, comprehensive, radar, 多维, 综合, 雷达N1 indicator + N numericmetric, productA, productB
heatmapDensity/cross-tabdensity, cross, matrix, heatmap, 密度, 交叉, 矩阵, 热力N2 category + 1 numericrow, col, value
treemapHierarchical proportionhierarchy, proportion, nested, 层级, 占比, 嵌套11 name + 1 valuecategory, sales
graphEntity relationshipsrelationship, network, topology, 关系, 网络, 拓扑specialsource + target (+ value)from, to, weight
boxplotDistribution/outliersdistribution, outlier, quartile, 分布, 离群, 四分位NN numericmath, chinese, english
waterfallIncremental changeincrement, change, waterfall, 增量, 变化, 瀑布11 category + 1 numeric (increments)month, profit_delta
gaugeKPI progressprogress, kpi, achievement, 进度, KPI, 达成11 numeric (mean used)completion_rate
sankeyFlow transferflow, transfer, sankey, 流向, 流量, 转移specialsource + target + valueorigin, destination, amount
funnelConversion rateconversion, funnel, churn, 转化, 漏斗, 流失11 name + 1 valuestage, count
sunburstMulti-level compositionhierarchy, proportion, nested, 层级, 占比, 嵌套11 name + 1 valuecategory, value
wordcloudFrequency/keywordsword frequency, keywords, text, 词频, 关键词, 词云11 name + 1 valueword, frequency

y_axis cardinality key: 1 = only first column used (extras silently ignored); 1~N = each column becomes a series; N = multiple columns expected; special = auto-detects source/target/value columns.

Programmatic 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,
)

On failure, success is False and error holds the structured dict (same shape as SmartChartsError.to_dict()). No exception is raised — the agent inspects success to decide next steps.


Transform Code Generation

When raw data doesn't match the target chart's input format, use this prompt template:

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:
```python
# {one-line description of what the transform does}
{transform_code}

**Common transform patterns:**
- Long→multi-series: `result = df.pivot_table(index='<time>', columns='<category>', values='<value>', aggfunc='sum').reset_index()`
- Long→pie (filter): `result = df[df['metric']=='revenue'][['category','value']].rename(columns={'category':'name'})`
- Wide→long: `result = df.melt(id_vars=['date'], var_name='name', value_name='value')`
- Aggregate→bar: `result = df.groupby('<category>')['<value>'].sum().reset_index()`
- Rename columns: `result = df.rename(columns={'来源':'source','去向':'target','金额':'value'})`
- Compute delta→waterfall: `tmp = df.copy(); tmp['delta'] = tmp['profit'].diff().fillna(tmp['profit'].iloc[0]); result = tmp[['month','delta']]`
- Rename messy/uninformative column names (after `--header-row` leaves columns like `10分`, `unnamed_3`): `result = df.rename(columns={'unnamed_0':'student_id','unnamed_1':'name','10分':'homework_score','30分':'exam_score'})`
- Forward-fill merged cells (when only the first row of a group is populated): `result = df.ffill()`
- Combine sub-headers into a single column name (when `--header-row N` flattens one row but loses context): `result = df.rename(columns={c: f'{c}_score' for c in df.columns if c not in ['student_id','name']})`

For CLI reference and installation instructions, see [REFERENCE.md](./REFERENCE.md).

如何使用「smart-charts」?

  1. 打开小龙虾AI(Web 或 iOS App)
  2. 点击上方「立即使用」按钮,或在对话框中输入任务描述
  3. 小龙虾AI 会自动匹配并调用「smart-charts技能完成任务
  4. 结果即时呈现,支持继续对话优化

相关技能