Skip to content

ChartEx (cx:) modern charts — Phase A round-trip + Phase B Waterfall writer (Refs #14)#56

Merged
MHoroszowski merged 1 commit into
masterfrom
feature/cx-modern-charts
May 17, 2026
Merged

ChartEx (cx:) modern charts — Phase A round-trip + Phase B Waterfall writer (Refs #14)#56
MHoroszowski merged 1 commit into
masterfrom
feature/cx-modern-charts

Conversation

@MHoroszowski
Copy link
Copy Markdown
Owner

Phase A + Phase B of the #14 epic (Modern Charts via cx: namespace). Refs #14does not close the epic; Phase C (remaining writers + cx: replace_data) is tracked separately.

What ships

Manual semantic port of GetThematic/python-pptx master ChartEx (the epic's named highest-quality cherry-pick candidate) onto this fork's ruff-formatted, #19/#25-diverged master. Never git cherry-picked (repo §2) — the diff was re-derived and applied as additive shims.

  • Phase A — round-trip preservation, all cx: types. A deck containing a PowerPoint-authored waterfall/treemap/sunburst/etc. opens, edits unrelated slides, and saves without corrupting the chartEx part. mc:AlternateContent/mc:Choice unwrap in CT_GroupShape.iter_shape_elms. Round-trip proven c14n byte-identical for unmodeled elements (treemap-shaped part with unmodeled <cx:parentLabelLayout> + hierarchical <cx:lvl>).
  • Phase B — Waterfall writer. slide.shapes.add_chartex(WaterfallChartData, x,y,cx,cy) and a thin add_chart(XL_CHART_TYPE.WATERFALL, …) dispatch shim.
  • Foundation: cx+mc namespaces, RT.CHARTEX/CHART_STYLE, GRAPHIC_DATA_URI_CHARTEX, 28 cx: oxml element classes, ChartExPart/ChartStylePart/ChartColorStylePart part-factory wiring, new oxml/chart/chartex.py + chart/chartex.py + parts/chartex.py, WaterfallChartData.
  • XL_CHART_TYPE extended: WATERFALL (writable) + TREEMAP/SUNBURST/FUNNEL/BOX_WHISKER/HISTOGRAM/PARETO (values ≥1000, fork-private — the MS COM enum predates chartEx). The six non-waterfall types raise NotImplementedError from add_chart (round-trip only).
  • Docs: docs/user/charts.rst ChartEx section + docs/api/enum/XlChartType.rst members.

Deliberately deferred to Phase C (follow-up issue)

Treemap/Sunburst/Funnel/Box-Whisker/Histogram/Pareto writers and a cx: replace_data API. GetThematic ships none of these; hand-authoring unvalidated <cx:treemap> OOXML would violate the round-trip-safety principle. Draft follow-up: uat/FOLLOWUP_issue14_phaseC_writers.md.

Tests (.venv toolchain)

Gate Result
pytest 3813 passed in 6.35s (3761 baseline + 52 new chartex tests, 0 failed)
ruff All checks passed! (src tests); format at fixed point
behave 1094 scenarios passed, 0 failed (32 new cx: scenarios)

UAT: uat/uat_cx_modern_charts.py (10/10 script-QA) — maintainer visual signoff received in PowerPoint/Keynote.

Adaptation note: GetThematic's tests/unitutil/cxml.py pyparsing-3 changes were deliberately not ported — this fork hard-pins pyparsing<3; the existing generic-grammar cxml already handles cx: tags.

Port provenance: GetThematic/python-pptx master. Refs #14.

…e B Waterfall writer — issue #14

Manual semantic port of the GetThematic/python-pptx master ChartEx
implementation (the epic's named highest-quality cherry-pick candidate)
onto this fork's ruff-formatted master. Never cherry-picked (repo §2):
the diff was re-derived against current master (#19/#25 merged) and
applied as additive shims onto the diverged wiring files.

Delivered:
- Phase A — cx: round-trip preservation for ALL chartEx types. A deck
  containing a PowerPoint-authored waterfall/treemap/sunburst/etc. opens,
  edits unrelated slides, and saves without corrupting the chartEx part.
  mc:AlternateContent/mc:Choice unwrap in CT_GroupShape.iter_shape_elms.
- Phase B — Waterfall WRITER. add_chartex(WaterfallChartData, x,y,cx,cy)
  and a thin add_chart(XL_CHART_TYPE.WATERFALL, ...) dispatch shim.
- Foundation: cx + mc namespaces (ns.py), RT.CHARTEX/CHART_STYLE
  (constants.py), GRAPHIC_DATA_URI_CHARTEX (spec.py), 28 cx: oxml element
  classes registered (oxml/__init__.py), ChartExPart/ChartStylePart/
  ChartColorStylePart part-factory wiring (__init__.py), new
  oxml/chart/chartex.py, chart/chartex.py, parts/chartex.py, and
  WaterfallChartData in chart/data.py.
- XL_CHART_TYPE extended: WATERFALL (writable) + TREEMAP/SUNBURST/FUNNEL/
  BOX_WHISKER/HISTOGRAM/PARETO. The six non-waterfall types raise
  NotImplementedError from add_chart (round-trip only); writers tracked
  as a Phase C follow-up (uat/FOLLOWUP_issue14_phaseC_writers.md).

Adaptation notes:
- GetThematic's cxml.py changes deliberately NOT ported: they migrate to
  pyparsing-3 APIs but this fork pins pyparsing<3 (2.4.7). The existing
  generic-grammar cxml.py already parses cx: tags; porting would break.
- Treemap/Sunburst writers do not exist in GetThematic; shipping
  unvalidated hand-authored cx: OOXML would violate round-trip safety.

Tests (this fork, .venv toolchain):
- pytest: 3812 passed, 0 failed (3761 baseline + 51 new chartex tests).
- ruff check src tests: All checks passed; ruff format: fixed point.
- behave: 1094 scenarios passed, 0 failed (32 new cx: scenarios across
  cht-chartex-{waterfall,roundtrip,types}.feature; baseline preserved).

UAT (maintainer-gated, NOT signoff): uat/uat_cx_modern_charts.py builds a
multi-slide waterfall deck + round-trip read-back, exits non-zero on
failure. Agent ran it for QA-on-the-test only; visual signoff in
PowerPoint/Keynote remains the maintainer's (repo §6a).

Port provenance: GetThematic/python-pptx master (clean waterfall +
chartEx round-trip). Refs #14.
@MHoroszowski MHoroszowski merged commit bdd71c3 into master May 17, 2026
16 checks passed
@MHoroszowski MHoroszowski deleted the feature/cx-modern-charts branch May 17, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant