---
audience: developers
summary: "Dual-emission \u2014 native chart parts when the library supports them,\
  \ ECharts SVG image fallback otherwise."
title: Charts
path: concepts/charts
status: published
---


# Charts

ScaiScribe emits charts in two ways: as **native** OOXML chart parts (so the recipient can double-click and edit chart data in Word/Excel/PowerPoint), or as **rendered images** (an ECharts-generated SVG embedded as an image). The right choice depends on the format, the chart kind, and your preference.

## The chart element

```json
{
  "type": "chart",
  "kind": "column",
  "title": "Quarterly revenue",
  "render_mode": "auto",
  "data": {
    "categories": ["Q1", "Q2", "Q3", "Q4"],
    "series": [
      { "name": "EMEA", "values": [1200, 1450, 1600, 1800] },
      { "name": "AMER", "values": [1000, 1100, 1300, 1400] }
    ]
  }
}
```

`kind` ∈ `bar | column | line | area | pie | doughnut | scatter | bubble | radar | combo | stacked_bar | stacked_column | sankey | treemap | sunburst | heatmap | waterfall | gauge`.

`render_mode` ∈ `auto | native | image`:
- **`auto`** (default) — native if the format + kind supports it; ECharts SVG fallback otherwise.
- **`native`** — force native. If the format+kind doesn't support it, you get a placeholder paragraph and a `NATIVE_FALLBACK` fidelity warning.
- **`image`** — force ECharts SVG. Useful when the native rendering disappoints visually (some kinds are markedly better in ECharts than in pptxgenjs).

## Support matrix

| Kind | DOCX | PPTX | XLSX |
|---|---|---|---|
| `bar` (horizontal) | **Native** | **Native** | **Native** |
| `column` (vertical) | **Native** | **Native** | **Native** |
| `line` | **Native** | **Native** | **Native** |
| `pie` | **Native** | **Native** | **Native** |
| `area` | Image | **Native** | Image |
| `doughnut` | Image | **Native** | Image |
| `scatter` | Image | **Native** | **Native** |
| `bubble` | Image | **Native** | Image |
| `radar` | Image | **Native** | Image |
| `stacked_bar` / `stacked_column` | Image (auto) | **Native** | **Native** |
| `sankey` / `treemap` / `sunburst` / `heatmap` / `waterfall` / `gauge` | Image | Image | Image |

**Native** means: editable chart in the recipient's Office app. Series data lives inside the OOXML zip and survives round-trip through ingestion.

**Image** means: high-quality ECharts SVG rendered server-side, embedded as a normal image. Looks great, but the recipient can't edit the underlying data without re-rendering.

## Why some kinds are native and others aren't

Two factors:

1. **What the underlying library supports natively.** `pptxgenjs` covers most chart kinds via `addChart`. `dolanmiu/docx` and `exceljs` have no chart-write API at all, so the DOCX/XLSX "Native" cells above are hand-emitted OOXML — we write `word/charts/chartN.xml` (or `xl/charts/chartN.xml` + a drawing anchor) directly and patch them into the zip.
2. **What's worth hand-emitting.** Bar, column, line, pie cover most business documents. Hand-emitting every variant (area, doughnut, sankey, gauge, …) duplicates work ECharts already does. So we drew the line at the four high-traffic kinds; the rest fall through to the image fallback by design.

The image fallback isn't a placeholder. It's a real chart, themed with the document's `chart_palette`, rendered at native resolution. Visually you can't tell it from a native chart; the only difference is whether the recipient can double-click to edit data.

## Theming

Series colours come from the active theme's `components.chart_palette`. For native charts (DOCX/XLSX), the palette is passed through to the OOXML emitter as `<a:srgbClr val="...">` on each series. For image charts, the palette is baked into the compiled ECharts theme that the SVG renderer consumes.

Override per-series colours by setting `series[i].color`. Override the title and axis colours via the optional `axes` and `legend` blocks (see [Reference → API](/docs/scaiscribe/reference/api)).

## Data shapes by kind

Most kinds use categorical data:

```json
{ "categories": [...], "series": [{ "name": "...", "values": [...] }, ...] }
```

`scatter` and `bubble` use point data:

```json
{ "series": [{ "name": "...", "points": [{ "x": 1, "y": 2 }, { "x": 3, "y": 4, "size": 5 }] }] }
```

Hierarchical kinds (`sankey`, `treemap`, `sunburst`) mirror ECharts' native option shape — see the ECharts docs and pass the option through verbatim.

## Charts in PPTX slides

Chart on a slide:

```json
{
  "layout": "content",
  "elements": [
    { "type": "slide_title", "text": "Revenue" },
    { "type": "chart", "kind": "column", "title": "By region", "data": {...} }
  ]
}
```

Charts in PPTX honour their slide's layout: the chart sizes itself to fill the layout's content placeholder.

## Charts in XLSX sheets

Sheet charts anchor to a cell:

```json
{
  "charts": [
    {
      "anchor": "E2",
      "kind": "column",
      "title": "Sales",
      "data": {...}
    }
  ]
}
```

The chart spans 9 columns × 15 rows from the anchor (a reasonable default for an inline chart). Native-kind charts emit `xl/charts/chartN.xml` + `xl/drawings/drawingN.xml`; image-kind charts use `exceljs.addImage` to embed the SVG.

## What happens on ingest

When you ingest an external document containing charts:
- **PPTX**: the OOXML walker detects chart placeholders and emits a `chart` element where it can extract kind + data; otherwise emits an `image` element + a `INGEST_CHART_REDUCED_TO_IMAGE` warning.
- **DOCX/XLSX**: charts surface as image elements (mammoth/exceljs surface drawings as images on read). The original chart spec doesn't round-trip for externally-authored documents.
- **ScaiScribe-authored documents**: the JSON breadcrumb in the zip restores the full chart element exactly as authored — no information loss. See [Ingestion](/docs/scaiscribe/concepts/ingestion).

## Where to next

- [Tutorials → Charts](/docs/scaiscribe/tutorials/charts) — concrete examples for each kind.
- [Themes](/docs/scaiscribe/concepts/themes) — chart_palette and how it propagates.
- [Reference → API](/docs/scaiscribe/reference/api) — full `Chart` schema.
