The theme's bare text colour made chart text black on a light theme,
where it used to be 595959. PowerPoint's default is `tx1` at lumMod 65000
and lumOff 35000: 595959 on a light theme, a light grey on a dark one, so
the dark-theme fix stays. The render test now checks the light-theme title
is dark but not black; the chart.options doc says what null gives.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A textColor set on a chart (chart.options, or Font Color with the chart
selected) coloured the title, axes and legend but left a pie's data labels
white. They stay white by default, on the slices, and follow a colour the
chart's text was given.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A chart's title, axis labels, legend and data labels were drawn in a
fixed grey (0x595959) whenever `text_color` was unset, which is
near-invisible on a dark theme. The renderer now resolves the theme's
tx1 instead, so a chart is readable by default on Nocturne as well as
on Harbor; an explicit colour still wins.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A bar series' own fill was read only when solid or a gradient: a pattern
(a:pattFill) was dropped, and an a:noFill series was read but drawn in the
palette's colour anyway, because the chart renderer turned every fill into
one colour and fell back to the palette for anything but solid. PowerPoint
for Mac draws the pattern, leaves an a:noFill bar empty and draws its
outline (c:spPr/a:ln) where it has one: a synthetic column chart with a
red-on-yellow dkDnDiag series, an empty series with a 3 pt blue outline
and an empty one without, exported as PDF, shows exactly that, legend
keys included.
- The chart reader reads a:pattFill (dml::pattern, shared with shapes);
the chart writer writes it back for an edited chart.
- Bars and their legend keys paint with the series' or point's own fill:
a colour, a preset pattern (pattern::fill) or nothing, then the series'
solid outline at its width.
- Lines, areas and markers, which take one colour, use a pattern's
foreground colour instead of the palette's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reader stored a series-level `c:dLbls/c:showVal` in
`Series.data_labels`, but every drawing path tested only the chart-wide
`Chart.data_labels`: a series that asked for labels got none, and a
series that asked for none got them. The series' own setting now wins,
and a bare `<c:showVal/>` (no `val` attribute) means true, as the
schema's default.
The plot group's own setting is respected too: a group that asks for no
labels keeps them off, even when another group of a combo chart asks for
them. Before, any group that asked turned the chart-wide setting on, and
the group that said no inherited it.
Tests: `crates/pptx/tests/chart_data_labels.rs` - a bare series
`showVal` shows that series' labels while its siblings stay quiet; an
explicit `val="0"` on the first series keeps it quiet under a chart-wide
on; a combo chart keeps each group's own setting; all three settings
round-trip. Red-proof: with the series-level setting ignored, the first
two fail; with the group's setting ignored, the combo chart's bar group
shows labels it asked to keep quiet.
The model gains `Chart::series_data_labels`, the one place that decides
whether a series' labels show; the render paths (bar, column, line,
area, pie, doughnut, radar, scatter) call it.
Fix-ups in the merge: error-bar statistics are computed once per series (was once per point,
quadratic on long series); reading custom amounts uses the chart-wide point budget (#480).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#666's minor gridlines stepped in value units, but #669 scales a log axis in
exponents of its base; map each minor step back through the base.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#662 gives scatter and bubble charts one x scale over every series; #603's
trendlines still mapped x over each series' own extent, so a fit drifted off
its points. Use the chart's x scale where there is one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#640 orders category slots bottom-to-top on horizontal bars (or reversed via
c:orientation) while #603 pads the axis for trendline forecasts. Slots now
include the forecast padding on the right side, and trendlines map their
category positions through the same slot order as the bars.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
f64::clamp panics when the plot is narrower than the caption's minimum width;
use main's clamp_soft, as the rest of the chart code now does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Radar and filled radar charts are drawn polar: spokes per category,
polygon gridlines and value labels up the first spoke. Stock charts
draw high-low lines with close dashes, or up/down bars between open
and close, and are saved as c:stockChart (hiLowLines, upDownBars)
instead of a line chart; c:upDownBars is read, and chart.options takes
upDownBars. New stock charts start as high-low-close and new combo
charts as columns with a line.
Co-authored-by: Cursor <cursoragent@cursor.com>
Read the regionMap chartEx layout as a RegionMap chart (regions and
their colour values), write the part back as read while unchanged, and
when edited rebuild it with the original geography (projection, culture
and cached boundaries) carried over. With no map data in the repo, the
renderer draws each region as a value-coloured tile with a colour scale
and a note that the map itself is not drawn.
Co-authored-by: Cursor <cursoragent@cursor.com>
Read, keep and write every cx:lvl of a chartEx category dimension,
build a category tree from runs of parent labels, and draw treemaps as
nested squarified groups with banners and sunbursts as one ring per
level. Box & whisker honours quartileMethod="inclusive" (QUARTILE.INC)
on import, render, save and the chart.options command.
Co-authored-by: Cursor <cursoragent@cursor.com>
Histograms and Paretos bin their observations (bin count, bin width or
Scott's rule) and draw as touching columns, a Pareto with its cumulative
line on a percentage axis. Box and whisker charts draw exclusive-quartile
boxes, 1.5 IQR whiskers, means and outliers per category group.
Edited and new Office 2016 charts are written as chartEx parts from the
model (with the plain-chart fallback), so a waterfall stays a waterfall.
The chart menus list all seven types, and chart.options sets bins and
waterfall totals.
Co-authored-by: Cursor <cursoragent@cursor.com>
These Office 2016 charts were drawn as plain columns. Now:
- waterfall: bars float from the running total, total points
(cx:subtotals, now read into Chart.subtotals) stand on the axis and
reset it, increases/decreases/totals take accents 1-3 with a matching
legend, and connectors join each bar to the next;
- funnel: centred bars as wide as their value, category labels on the
left and values inside;
- treemap: squarified tiles in proportion to their value, labelled;
- sunburst: the innermost level as a ring with an open centre.
Co-authored-by: Cursor <cursoragent@cursor.com>
soak_tests.rs drives every non-file command with plausible and hostile
parameters over a ~100-slide deck, checking after each step that the
document validates, the selection is in range, the undo stack is bounded,
undo then redo restores the exact document, and every 100 steps that the
deck saves and reopens as .deckcraft and .pptx. Four seeds x 400 steps run
in CI (under a second); DECKCRAFT_SOAK_STEPS/SEED run it long.
The long soak found that a chart a few points wide panicked in f64::clamp
(label gutter min above max), and the render guard then blanked the whole
slide. chart.rs now uses a non-panicking clamp_soft for the gutters and the
zero line; a render test draws tiny charts next to a shape without the
guard.
Co-authored-by: Cursor <cursoragent@cursor.com>