Nutrient Chart Parsing · commercial
Read a chart image and return its data and structure as one JSON object. The Nutrient chart-parsing model takes a rendered chart (bar, line, pie, scatter, area, box, bubble, heatmap, histogram, treemap, funnel, radar, violin, stem, step, candlestick, combo) and returns the title, chart type, data table, value representation, encoding, axes, series, legend, and data-label state in a single pass. Values are what a reader can recover from the pixels: printed labels verbatim, shares for pie and donut charts, axis-scaled estimates otherwise.
The runnable weights are commercial and are not downloadable from this repository. This public page is the product specification and scorecard; see License and access to evaluate or deploy it.
- 🧪 Try it:
nutrientdocs/chart-parsing-demo - 🏆 Leaderboard:
nutrientdocs/chart-parsing-leaderboard - 📊 Benchmark:
nutrientdocs/chart-parsing-benchmark
Headline result
Systems are ranked by mean per-chart cell F1 at 3% tolerance on the frozen 2,500-chart benchmark: every chart's data cells are matched by row identity and column, a value counts when it is within 3% of the chart's value range (3 percentage points on share charts, exact when the chart prints data labels), and the per-chart F1 is averaged so every chart counts once. Strict F1 demands values within 0.1%. Every entry sees the same charts and the same prompt.
| System | F1 · 3% | Strict F1 | F1 · 5% | Shape | Type | Title | sec/chart |
|---|---|---|---|---|---|---|---|
| Nutrient Chart Parsing | 0.857 | 0.746 | 0.871 | 0.946 | 0.972 | 0.983 | 0.27 |
| Gemini 3.8 Flash | 0.710 | 0.640 | 0.713 | 0.796 | 0.960 | 0.998 | — |
| Claude Opus 5 | 0.697 | 0.617 | 0.703 | 0.792 | 0.967 | 0.998 | — |
| GPT-6 Astra | 0.675 | 0.628 | 0.676 | 0.802 | 0.964 | 0.997 | — |
| Gemini 3.5 Flash Lite | 0.663 | 0.600 | 0.672 | 0.771 | 0.947 | 0.992 | — |
| Claude Sonnet 5 | 0.657 | 0.586 | 0.664 | 0.741 | 0.973 | 0.998 | — |
| GPT-5.6 Terra | 0.630 | 0.569 | 0.634 | 0.709 | 0.960 | 0.998 | — |
| Gemini 3.1 Pro | 0.628 | 0.567 | 0.633 | 0.726 | 0.950 | 0.996 | — |
| Claude Haiku 4.5 | 0.570 | 0.469 | 0.596 | 0.708 | 0.943 | 0.995 | — |
| GPT-5.6 Sol | 0.566 | 0.514 | 0.569 | 0.658 | 0.954 | 0.997 | — |
| Qwen3.8-27B | 0.524 | 0.445 | 0.531 | 0.625 | 0.793 | 0.826 | 2.80 |
| Qwen3-VL-4B-Instruct | 0.518 | 0.443 | 0.536 | 0.623 | 0.908 | 0.984 | 0.30 |
| Qwen3.5-4B | 0.169 | 0.143 | 0.171 | 0.200 | 0.290 | 0.312 | 1.00 |
The Nutrient model reaches 0.857, ahead of the strongest cloud model here, Gemini 3.8 Flash (0.710), and it recovers the right table shape on 94.6% of charts against 80% for the best cloud model. Its lead is in the data cells, not in the labels: cloud models read titles and chart types about as well. Seconds per chart are measured on one NVIDIA A100 80GB with vLLM at 64-way concurrency and compare only within that setup; provider APIs give no comparable latency. Full per-field and per-type breakdowns are on the leaderboard.
Result by chart type
Mean per-chart cell F1 for the Nutrient model at the three tolerance levels, with the number of benchmark charts of each type.
| Chart type | n | Strict | 3% | 5% |
|---|---|---|---|---|
| line | 552 | 0.788 | 0.904 | 0.916 |
| bar | 463 | 0.841 | 0.928 | 0.935 |
| pie | 249 | 0.731 | 0.734 | 0.734 |
| scatter | 235 | 0.749 | 0.814 | 0.820 |
| area | 224 | 0.786 | 0.863 | 0.883 |
| box | 171 | 0.671 | 0.968 | 0.981 |
| bubble | 164 | 0.595 | 0.688 | 0.698 |
| heatmap | 100 | 0.798 | 0.800 | 0.827 |
| histogram | 54 | 0.723 | 0.840 | 0.870 |
| treemap | 54 | 0.182 | 0.868 | 0.985 |
| combo | 51 | 0.748 | 0.903 | 0.911 |
| funnel | 49 | 0.901 | 0.903 | 0.923 |
| radar | 46 | 0.496 | 0.602 | 0.638 |
| violin | 33 | 0.526 | 0.942 | 0.981 |
| stem | 25 | 0.766 | 0.866 | 0.876 |
| step | 15 | 0.850 | 0.850 | 0.850 |
| candlestick | 15 | 0.671 | 0.774 | 0.791 |
Per-field accuracy on the same set: chart type 0.972, title 0.983, x and y axis labels 0.979 and 0.978, axis scales 0.967 and 0.976, legend visibility 0.985, data-label visibility 0.983, column types 0.981, column roles 0.979, axis bounds 0.747. Set F1 over encoding pairs 0.966 and over series pairs 0.986.
Output
One JSON object per chart. data.rows is the table; every other key describes how the chart shows it.
{
"title": "Programming Language Popularity",
"chartType": "pie",
"data": {
"columns": [
{"name": "Language", "type": "categorical", "role": "category", "unit": null},
{"name": "Popularity", "type": "numeric", "role": "value", "unit": null}
],
"rows": [["Python", 21.6], ["Java", 19.4], ["C++", 17.7]]
},
"valueRepresentation": {"mode": "percentage_of_total", "format": "0.0%"},
"encoding": {"category": "Language", "value": "Popularity", "color": "Language"},
"axes": null,
"series": [{"name": "Popularity", "field": "Popularity"}],
"legend": {"visible": false, "position": null, "entries": null},
"dataLabels": {"visible": true, "format": "percentage"}
}
chartTypeis one ofbar, line, area, pie, scatter, bubble, histogram, box, violin, heatmap, treemap, funnel, radar, candlestick, step, stem, combo.- Column
typeiscategorical,numeric, ortemporal; columnroleis one ofcategory, value, series, x, y, z, size, color. valueRepresentation.modeispercentage_of_totalfor pie, donut, treemap, and 100%-stacked charts, otherwiseabsolute.axesholds{label, unit, scale, min, max}per axis with the visible limits, ornullfor charts without axes.- Any field the image does not support is
null.
The data block converts to CSV, HTML, or a spreadsheet with plain code; the model is not asked to emit
those formats.
Intended use and limits
- Use it for: turning rendered chart images (exports from plotting libraries, report figures, dashboard screenshots) into a data table and a description of how the chart shows it, for indexing, analysis, re-plotting, or conversion to spreadsheets.
- Values are visual estimates. When a chart prints no data labels the model reads values off the axis scale; expect errors within a few percent of the value range, and check the strict versus 3% columns above for how much that costs per chart type. Pie and donut charts return shares of the total, never the underlying absolute values.
- Weaker chart types: bubble (size legends are hard to invert), radar, and candlestick charts, and axis bounds in general (0.747 field accuracy). Pie charts read printed shares well but estimating unlabeled wedges is imprecise.
- Validate downstream. The output is well-formed JSON in practice, but parse it defensively and check
that
data.rowshas the widthdata.columnsdeclares before feeding it to automated pipelines.
License and access
The model weights are offered under a commercial Nutrient license and are not published here. The
benchmark charts derive from ChartGen-200K, CC BY 4.0.
The benchmark is public and reproducible through
nutrientdocs/chart-parsing-benchmark.
📩 Get access
Nutrient Chart Parsing is commercial. To evaluate or deploy it on-prem, with your documents staying in your infrastructure, contact Nutrient: nutrient.io/contact-sales.
About the author
This project is maintained and funded by Nutrient - The deterministic document infrastructure enterprises run their highest-stakes workflows on: replayable output, clear exceptions, and full audit trails on the messy, regulated documents where AI alone breaks.
Spaces using nutrientdocs/chart-parsing-vlm 2
Evaluation results
- Mean per-chart cell F1 (3% tolerance) on Chart Parsing Benchmarktest set self-reported0.857
- Mean per-chart cell F1 (strict) on Chart Parsing Benchmarktest set self-reported0.746