Skip to content

Commit a3db5d5

Browse files
committed
fix(charts): histogram emits PowerPoint's auto-binning form (no binCount child) — issue #14 Phase C
Pareto fixed (b3a2207) but histogram still triggered repair. Precise byte-diff vs the PowerPoint-authored histogram: the sole histogram-specific delta was our <cx:binCount>N</cx:binCount> child. dml-chartex.xsd models binCount/binSize as child elements (our emission was schema-valid) but PowerPoint's reader rejects that form; PowerPoint's own histogram uses automatic binning: bare <cx:binning intervalClosed="r"/>. No PowerPoint ground-truth exists for an explicit-bin form, so per the no-inference discipline (memory #25: only ground-truth-verified structure ships) histogram now emits exactly PowerPoint's accepted auto-binning structure. HistogramChartData still accepts bin_count/bin_size for API stability but they no longer emit the rejected child — PowerPoint computes bins from the data (its own default). add_histogram_series signature simplified; slide.py caller updated. Verified via uat/chartex_groundtruth_diff.py: histogram now matches the PowerPoint-authored chart structurally (only delta = PowerPoint's optional <cx:title>). Trinity: pytest 3887 passed 0 failed, ruff clean + fixed point, behave 1109 scenarios 0 failed. Refs #14.
1 parent b3a2207 commit a3db5d5

2 files changed

Lines changed: 15 additions & 24 deletions

File tree

src/pptx/oxml/chart/chartex.py

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -391,17 +391,21 @@ def add_box_whisker_series(
391391
return series
392392

393393
def add_histogram_series(
394-
self,
395-
series_name: str,
396-
series_name_ref: str = "Sheet1!$A$1",
397-
data_id: int = 0,
398-
bin_count: int | None = None,
399-
bin_size: float | None = None,
394+
self, series_name: str, series_name_ref: str = "Sheet1!$A$1", data_id: int = 0
400395
):
401396
"""Add a histogram series (`layoutId="clusteredColumn"` + `<cx:binning>`).
402397
403-
PowerPoint emits no `<cx:dataLabels>` for a histogram (ground-truth
404-
diff, issue #14), so this series omits them.
398+
Emits **automatic binning** — `<cx:binning intervalClosed="r"/>` with
399+
no `binCount`/`binSize` child — which is exactly the structure
400+
PowerPoint itself authors and accepts (verified via ground-truth diff,
401+
issue #14). The `dml-chartex.xsd` models `binCount`/`binSize` as child
402+
elements and our earlier emission was schema-valid, but PowerPoint's
403+
reader rejects that form and shows a repair dialog. Until a
404+
PowerPoint-authored sample with explicit bins exists to confirm the
405+
accepted form, manual bin specification is intentionally not emitted —
406+
PowerPoint computes sensible bins from the data automatically (its own
407+
default behaviour). No `<cx:dataLabels>` either (PowerPoint emits none
408+
for a histogram).
405409
"""
406410
from lxml import etree
407411

@@ -411,14 +415,6 @@ def add_histogram_series(
411415
layoutPr = etree.SubElement(series, qn("cx:layoutPr"))
412416
binning = etree.SubElement(layoutPr, qn("cx:binning"))
413417
binning.set("intervalClosed", "r")
414-
# CT_Binning child is an xsd:choice of binSize | binCount (both optional →
415-
# automatic binning, matching PowerPoint's default, when neither given).
416-
if bin_size is not None:
417-
bs = etree.SubElement(binning, qn("cx:binSize"))
418-
bs.text = str(bin_size)
419-
elif bin_count is not None:
420-
bc = etree.SubElement(binning, qn("cx:binCount"))
421-
bc.text = str(bin_count)
422418
return series
423419

424420
def add_pareto_pair(

src/pptx/parts/slide.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,14 +239,9 @@ def add_chartex_part(self, chart_data: WaterfallChartData) -> str:
239239
"val", chart_data.values_ref, chart_data.series_values, chart_data.number_format
240240
)
241241
elif cx_type == "histogram":
242-
# numeric raw values, binned; no strDim, no dataLabels (PP ground truth)
243-
plotAreaRegion.add_histogram_series(
244-
name,
245-
name_ref,
246-
data_id=0,
247-
bin_count=chart_data.bin_count,
248-
bin_size=chart_data.bin_size,
249-
)
242+
# numeric raw values, auto-binned; no strDim, no dataLabels
243+
# (PowerPoint ground truth, issue #14).
244+
plotAreaRegion.add_histogram_series(name, name_ref, data_id=0)
250245
data_elem.add_numeric_dimension(
251246
"val", chart_data.values_ref, chart_data.series_values, chart_data.number_format
252247
)

0 commit comments

Comments
 (0)