CoolFace
Datasetpublic

chartanno/ChartAnno

ChartAnno: Benchmarking Multimodal Large Language Models for Chart Annotation Generation         The official dataset repository of ChartAnno 1,200 real-world charts  ·  3,600 instructions  ·  10,800 instances (+720 D3/SVG)  ·  3 representations  ·  17 chart types 1. Data Overview Annotations are essential to communicative visualization, helping explain data, emphasize key findings… See the full description on the dataset page: https://huggingface.co/datasets/chartanno/ChartAnno.

sourceHugging Facecc-by-nc-4.0updated 5d agoView on Hugging Face
1likes609downloads
Dataset Card

<p align="center"> <img src="assets/logo.png" width="130" alt="ChartAnno logo"> </p>

<h1 align="center">ChartAnno: Benchmarking Multimodal Large Language Models for Chart Annotation Generation</h1>

<p align="center"> <a href="https://chartanno.github.io/"><img src="https://img.shields.io/badge/Homepage-chartanno.github.io-teal.svg" alt="Homepage"></a> &nbsp; <a href="https://arxiv.org/abs/2608.03464"><img src="https://img.shields.io/badge/arXiv-2608.03464-b31b1b.svg" alt="arXiv"></a> &nbsp; <a href="https://github.com/ChartAnno/ChartAnno"><img src="https://img.shields.io/badge/GitHub-ChartAnno-24292e.svg?logo=github" alt="GitHub"></a> &nbsp; <a href="https://huggingface.co/datasets/chartanno/ChartAnno"><img src="https://img.shields.io/badge/%F0%9F%A4%97%20Dataset-chartanno%2FChartAnno-ffd21f.svg" alt="HuggingFace Dataset"></a> &nbsp; <a href="https://creativecommons.org/licenses/by-nc/4.0/"><img src="https://img.shields.io/badge/License-CC%20BY--NC%204.0-blue.svg" alt="License"></a> </p>

<h3 align="center">The official dataset repository of ChartAnno</h3>

<p align="center"> <b>1,200</b> real-world charts &nbsp;·&nbsp; <b>3,600</b> instructions &nbsp;·&nbsp; <b>10,800</b> instances (+720 D3/SVG) &nbsp;·&nbsp; <b>3</b> representations &nbsp;·&nbsp; <b>17</b> chart types </p>

1. Data Overview

Annotations are essential to communicative visualization, helping explain data, emphasize key findings, and guide attention. ChartAnno is a benchmark for evaluating multimodal large language models (MLLMs) on chart annotation generation: given an existing chart (as executable code, optionally with the rendered image) and an annotation instruction, the model generates executable code that adds the requested annotations.

ChartAnno includes 1,200 real-world charts, each with a paired annotated / unannotated ground-truth (code + rendered image) pair. Every chart is paired with annotation instructions across three levels of specificity — Intent, Operation, and Implementation — yielding 3,600 instruction instances. The primary benchmark tests two input settings (Input: code and Input: code+Image) for 7,200 model input instances; a supplementary Input: Image setting adds 3,600 image-only instances, and a 120-chart D3.js / SVG extension adds 720 more. Across the benchmark the same task is instantiated in three representations — Python, D3.js, and SVG.

<p align="center"> <img src="assets/main-chart.png" width="95%" alt="ChartAnno task design"> </p> <p align="center"><sub>Task design of ChartAnno. Primary chart inputs are Code or Code + Chart Image, with annotation instructions ranging from abstract Intent through Operation to concrete Implementation. For each chart input–instruction combination, the MLLM generates annotated code and its rendered chart, evaluated with reference to the unannotated code, instruction, and annotated ground truth.</sub></p>

2. Task Formats

The dataset is organized into configs, one per input setting:

<table align="center"> <tr> <th align="center">Config</th> <th align="center">Input setting</th> <th align="center">Model input</th> <th align="center">Ground truth</th> </tr> <tr> <td align="center"><code>1pythoncodeimage</code></td> <td align="center">Input: code+Image</td> <td align="center">Instruction + unannotated chart code + chart image</td> <td align="center">Annotated code + annotated chart</td> </tr> <tr> <td align="center"><code>2pythoncodeonly</code></td> <td align="center">Input: code</td> <td align="center">Instruction + unannotated chart code</td> <td align="center">Annotated code + annotated chart</td> </tr> <tr> <td align="center"><code>3pythonimageonly</code></td> <td align="center">Input: Image</td> <td align="center">Instruction + unannotated chart image</td> <td align="center">Annotated code + annotated chart</td> </tr> <tr> <td align="center"><code>4d3codeonly</code></td> <td align="center">Input: code (D3.js)</td> <td align="center">Instruction + unannotated D3.js code</td> <td align="center">Annotated D3.js code + annotated chart</td> </tr> <tr> <td align="center"><code>5svgcode_only</code></td> <td align="center">Input: code (SVG)</td> <td align="center">Instruction + unannotated SVG document</td> <td align="center">Annotated SVG document + annotated chart</td> </tr> </table>

Each instance carries one of three instruction levels:

LevelDescription
intentAbstract communicative goal, e.g. "emphasize the strongest market". The model must infer what to annotate.
operationConcrete annotation operations, e.g. "add an arrow pointing to the peak and a text label with its value".
implementationFully specified implementation details, e.g. exact label text, colors, and positions.

An example pair from the 1_python_code_image config (Area_33): the model receives the unannotated chart on the left (with its code) and produces the annotated version on the right.

<table align="center"> <tr> <th align="center">Input: GT w/o anno chart</th> <th align="center">Expected output: GT chart</th> </tr> <tr> <td align="center"><img src="assets/exampleunannotated.jpg" width="400" alt="Unannotated input chart"></td> <td align="center"><img src="assets/exampleannotated.jpg" width="400" alt="Annotated ground-truth chart"></td> </tr> </table>

D3.js / SVG extension (code-only)

Besides the main Python benchmark, the dataset ships a D3.js and SVG extension: 120 real-world charts (14 chart types), each paired with instructions across the same three levels — 360 rows per backend (4_d3_code_only, 5_svg_code_only). Rows follow the same schema as 2_python_code_only; ids carry a _d3 / _svg suffix, and the code files (.js / .svg) plus full-resolution images are included in chartanno_d3_svg.tar.gz.

3. Data Statistics

The statistics below are computed on the main Python benchmark; the D3/SVG extension follows the same construction.

Overall scale

StatisticValue
GT pair and GT w/o anno pair1,200
Instruction instances3,600
Annotation elements25,772

Annotation complexity

StatisticValue
Avg. elements per chart21.48
Std. elements per chart35.32
Avg. annotation types per chart2.17
Std. annotation types per chart1.04

Instruction length (words)

LevelAvg.Std.
Intent66.3952.97
Operation95.0663.57
Implementation108.7479.78

Code length (tokens)

CodeAvg.Std.
Annotated1535.68972.38
Unannotated1075.22790.45
Increment460.46385.17

Code token increment across representations (120-chart extension)

On the same 120 charts, the annotation increment differs substantially across representations:

RepresentationAvg. code token incrementRelative to Python
Python395.01.00×
D3.js1374.23.48×
SVG2612.76.61× (1.90× D3)

Chart type distribution (17 types)

TypeMultiLineBarScatterErrorpointHeatmapPieAreaHistogram
Count303247213944744443332
TypeCombinationViolinRadarDensityTreemapBoxContourDotTotal
Count3120191917161561,200

4. Download Link

This dataset is gated: click Request access on the repo page first. Once granted, you can download the whole dataset with a read token (settings/tokens):

shell
pip install -U huggingface_hub
hf login --token $HF_TOKEN        # or: hf auth login

mkdir ChartAnno && cd ChartAnno   # cd to the target directory
hf download chartanno/ChartAnno chartanno.tar.gz --repo-type dataset --local-dir .
tar -xzvf chartanno.tar.gz

The optional D3/SVG extension ships as a separate archive:

shell
hf download chartanno/ChartAnno chartanno_d3_svg.tar.gz --repo-type dataset --local-dir .
tar -xzvf chartanno_d3_svg.tar.gz   # extracts to ./d3_svg_data

The file structure of the dataset is as follows:

text
data/
├── input_code.jsonl              # Input: code task, 3,600 rows
├── input_code_image.jsonl        # Input: code+Image task, 3,600 rows
├── input_image_only.jsonl        # Input: Image task, 3,600 rows
├── manifest.json                 # row-count summary and schema description
├── README.md
└── images/
    ├── GT_chart/                 # 1,200 annotated ground-truth charts (jpg)
    │   ├── Area/  Bar/  ...      # one subdirectory per chart type (17 types)
    └── GT_w_o_anno_chart/        # 1,200 unannotated charts, same layout

The Dataset Viewer above serves the full dataset: all 3,600 rows per config are loadable via load_dataset("chartanno/ChartAnno", "<config>") (configs 1_python_code_image, 2_python_code_only, 3_python_image_only are the main benchmark; 4_d3_code_only / 5_svg_code_only are the extension). Chart images in the viewer parquet are embedded as compressed JPEG thumbnails for fast previewing; the full-resolution images are included in chartanno.tar.gz.

5. Data Fields

We take an instance from the 1_python_code_image config as an example (Area_1_intent_code_image, long values truncated):

json
{
  "id": "Area_1_intent_code_image",
  "category": "Area",
  "sample_id": "Area_1",
  "level": "intent",
  "input_type": "Input: code+Image",
  "instruction": "You are an expert in chart annotation and Python visualization. I have created a figure but have not added any annotations yet. ...",
  "GT w/o anno code": "import matplotlib.pyplot as plt\nimport numpy as np\nmonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']\nvisitors = [12, 120, 229, 990, 4104, 3250, 5720, 43152, ...",
  "GT w/o anno chart": "data/images/GT_w_o_anno_chart/Area/Area_1.jpg",
  "GT code": "import matplotlib.pyplot as plt\nimport numpy as np\nmonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']\nvisitors = [12, 120, 229, 990, 4104, 3250, 5720, 43152, ...",
  "GT chart": "data/images/GT_chart/Area/Area_1.jpg"
}

Details of the data fields are as follows:

FieldDescription
idStable row id: <sample_id>_<level>_code or <sample_id>_<level>_code_image.
categoryChart type, one of 17 types (e.g. Area, Bar, Line).
sample_idSource chart id, <Category>_<n> (e.g. Area_1).
levelInstruction level: intent, operation, or implementation.
input_typeInput: code or Input: code+Image.
instructionThe full model input prompt: task instruction with the unannotated code embedded.
GT w/o anno codeGround-truth chart code before annotation.
GT w/o anno chartPath to the unannotated chart image; always null in the 2_python_code_only config.
GT codeGround-truth annotated chart code.
GT chartPath to the annotated ground-truth chart image.

Image paths are relative to the repository root of the extracted data/ folder. In the viewer parquet the two image fields are named gt_chart / gt_wo_anno_chart (space-free, for Dataset Viewer compatibility) and are embedded as compressed thumbnails of these files.

6. Evaluation

ChartAnno comes with a self-contained evaluation pipeline (see the GitHub repository): it renders the generated code into charts and scores them with rule-based metrics (execution success, chart fidelity, annotation matching, color matching) and LLM-judged metrics (semantic faithfulness, semantic clarity, visual clarity, annotation organization quality, attention guidance). The final aggregate scores are:

AggregateInputs
Structural compliancechart fidelity (+ annotation & color matching for operation/implementation levels)
Semantic consistencysemantic faithfulness, semantic clarity
Design effectivenessvisual clarity, annotation organization quality, attention guidance

7. Citation

If you find ChartAnno useful, please consider citing our paper:

bibtex
@article{chen2026chartanno,
      title={ChartAnno: Benchmarking Multimodal Large Language Models for Chart Annotation Generation},
      author={Zhenghan Chen and Zekai Shao and Lidan Tan and Xin Lin and Xingchen Zeng and Yi Shan and Ziyue Lin and Xiaoliang Fu and Xinyuan Liu and Yuetong Guo and Fen Wang and Bongshin Lee and Siming Chen},
      year={2026},
      journal={arXiv preprint arXiv:2608.03464},
}