Metadata-Version: 2.4
Name: docxchart
Version: 0.1.1
Summary: Edit the data behind Word charts without disturbing the formatting.
Author-email: Max Kemmler <106467576+Kemmler1@users.noreply.github.com>
License: MIT
Project-URL: Homepage, https://github.com/Kemmler1/docxchart
Project-URL: Repository, https://github.com/Kemmler1/docxchart
Project-URL: Issues, https://github.com/Kemmler1/docxchart/issues
Keywords: docx,word,chart,ooxml,openxml,office
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business
Classifier: Topic :: Text Processing :: Markup
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: lxml>=4.9
Requires-Dist: openpyxl>=3.1
Dynamic: license-file

# docxchart

Edit the data behind Word charts without disturbing the formatting.

Extract every chart's values from a `.docx` to JSON, edit the JSON, apply it
back. Fills, label positions, axis settings and theme bindings are never
touched.

**Status:** early. Handles same-length value edits on standard category charts.
Anything it can't handle raises rather than guessing — see [Limitations](#limitations).

## Install

```bash
pip install docxchart
```

Requires Python 3.11+.

## CLI

```bash
docxchart list    report.docx
docxchart extract report.docx -o data.json
docxchart apply   report.docx --data data.json -o report-updated.docx
```

| Command | |
|---|---|
| `list FILE` | chart keys, titles, and shape |
| `extract FILE [-o OUT]` | write chart data to JSON (default `data.json`) |
| `apply FILE --data JSON [-o OUT]` | write edited data back to a new docx |
| `--sidecar` | on `extract`, also emit the internal manifest |

`apply` never writes in place. Omit `-o` and it errors.

## Data format

```json
{
  "_docxchart": {
    "source": "report.docx",
    "basedOn": "sha256:1f3a…",
    "extractedAt": "2026-07-29T09:14:22Z",
    "formatVersion": "1.0"
  },
  "charts": [
    {
      "key": "revenue_by_quarter",
      "_meta": {
        "title": "Revenue by Quarter",
        "type": "barChart",
        "keyStable": true,
        "readOnly": true
      },
      "series": [
        { "name": "2024", "formatCode": "#,##0" },
        { "name": "2025", "formatCode": "#,##0" }
      ],
      "rows": [
        { "category": "Q1", "2024": 120,  "2025": 130 },
        { "category": "Q2", "2024": null, "2025": 110 },
        { "category": "Q3", "2024": 95,   "2025": 99  }
      ]
    }
  ]
}
```

| Field | |
|---|---|
| `key` | chart identifier (see [Naming](#naming)) |
| `_meta` | read-only. `apply` errors if changed. |
| `series` | display order of the series. Order matters for legend and stacking. |
| `rows` | one row per category. Series values keyed by series name. |
| `basedOn` | hash of the source docx. `apply` refuses if the file has changed since extract. |

`null` is a genuine blank in the chart, rendered as a gap. It is **not** zero.
Omitting a key means the same thing.

Dates are stored as Excel serial numbers with a `formatCode`, and are passed
through unconverted.

## Python API

```python
from docxchart import ChartDoc

doc = ChartDoc.open("report.docx")

list(doc.charts)
# ['revenue_by_quarter', 'headcount']

chart = doc.charts["revenue_by_quarter"]
chart.table
# ChartTable(
#     categories=['Q1', 'Q2', 'Q3'],
#     series=[Series(name='2024', values=[120, None, 95])],
# )

chart.table.series[0].values = [130, 110, 99]

doc.validate()               # -> list[Finding]
doc.save("report-updated.docx")
```

`ChartTable` and `Series` are plain dataclasses. No XML is exposed.

## Naming

Charts are identified by their **Alt Text**, which survives Word re-saves,
insertions and deletions — unlike file paths and relationship IDs.

1. Right-click the chart → **Edit Alt Text**
2. Enter a key, e.g. `revenue_by_quarter`

Without Alt Text, the key falls back to the chart's title, slugified. This
works, but the key changes if anyone edits the title. `list` marks these as
unstable. Duplicate titles are suffixed by document order: `revenue`,
`revenue-2`.

## Limitations

Unsupported cases raise `UnsupportedChart` or `UnsupportedEdit` with a reason.
Nothing is written on a partial or best-guess basis.

Not supported:

- Adding or removing categories — values can be changed, not the number of them
- Adding or removing series
- Scatter and bubble charts
- `chartEx` types: waterfall, treemap, sunburst, funnel, histogram, box &
  whisker, map
- Multi-level category axes
- Charts in headers, footers or footnotes
- Charts bound to an external data source
- Any change to appearance — colours, fonts, chart type, axis config and layout
  are read-only

Charts must be created in Word. `docxchart` only rebinds data on charts that
already exist.

## Notes

Word renders from the chart's cached values, not from the embedded workbook, but
the workbook is what you see when you click *Edit Data*. `docxchart` always
writes both, so the two never disagree.

Parts of the package that weren't changed come out byte-identical.

## License

MIT — see [LICENSE](LICENSE).
