Skip to content

Implement Charts#683

Open
ddimaria wants to merge 3 commits into
tafia:masterfrom
ddimaria:implement-charts
Open

Implement Charts#683
ddimaria wants to merge 3 commits into
tafia:masterfrom
ddimaria:implement-charts

Conversation

@ddimaria

@ddimaria ddimaria commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Adds chart reading to the XLSX reader via two new methods:

let charts: Vec<Chart> = workbook.worksheet_charts("Sheet1")?;
let charts = workbook.worksheet_charts_at(0);

The reader walks the worksheet (or chartsheet) relationships to the drawing part, collects the anchored chart frames (two-cell, one-cell and absolute anchors, including their positions), and parses each chart part into a public Chart data model in the new chart module. The API is modelled after rust_xlsxwriter's chart types so the two crates feel symmetrical (write with rust_xlsxwriter, read back with calamine).

Also exposes the workbook theme palette:

let theme: ThemeColors = workbook.theme_colors();
let series_color = theme.accents()[0]; // Excel's default color for an unstyled first series

ThemeColors has named slots (dark1/light1/dark2/light2, accent1accent6, hyperlink, followed_hyperlink), parsed once from xl/theme/theme1.xml, cached and reused by chart/style/conditional-formatting parsing, and falling back to the default Office palette (never errors). Consumers need it to color unstyled chart series the way Excel does (the theme accent cycle) without re-opening the package themselves.

Supported

  • All classic ECMA-376 chart families: bar, column, line, pie, doughnut, pie-of-pie/bar-of-pie, area, scatter, radar, stock, bubble and surface — including stacked, percent-stacked and 3D variants (with standard vs clustered 3D grouping distinguished), wireframe/contour surfaces, and combo charts (multiple plot groups per chart).
  • Excel 2016+ chart-ex parts (xl/charts/chartExN.xml): funnel, treemap, sunburst, histogram, pareto, box & whisker, waterfall and filled map, including the mc:AlternateContent drawing anchors, the chartEx relationship type, and per-series layout options (ChartExLayout: histogram binning, waterfall subtotals/connector lines, box & whisker statistics and element visibility, treemap parent label layout).
  • Series: range formulas plus cached values, multi-level (hierarchical) category caches with all levels preserved, names, per-point formatting, markers, smoothing, pie explosion, data labels (including per-point c:dLbl overrides with delete/custom text/position), trendlines (all six types), error bars, invert-if-negative.
  • Axes: category/value/date/series types, position, min/max, log base, reversed, units, tick marks, tick-label position, crossing, crossing partner (c:crossAx), cross-between, display units, gridlines, number formats, titles, fonts and label text rotation.
  • Chart/group options: titles (rich text and formula-linked), legends, 3D view settings (rotX/rotY/perspective/depth, per Correct MBSC to MBCS in vba.rs #180 in rust_xlsxwriter), gap/overlap, hole size, first slice angle, bubble scale/size-represents, pie-of-pie split settings (including c:custSplit point lists), up/down bars, drop lines, high-low lines, series lines, data tables, dispBlanksAs, and the chart-space flags autoTitleDeleted/plotVisOnly/showDLblsOverMax/date1904.
  • Formatting: solid/gradient/pattern fills (with linear gradient angle), line width/dash/color, fonts, with DrawingML scheme-color resolution against the workbook theme (including lum/tint/shade modifiers).
  • Anchors: ChartPosition carries the anchor cells/extents plus editAs (move/size behavior) and the absolute anchor x/y position.

Not read (documented in the module docs)

Pivot chart sources, manual plot-area layouts, and surface band formats.

Test plan

  • tests/charts.xlsx fixture (pre-generated, committed to tests/ per the feedback on feat(xlsx): implement cell style extraction with rich text and worksheet layout #653 — no generator or dev-dependency added) with 18 classic charts + 5 chart-ex charts exercising every family and the options above.
  • 36 chart integration/unit tests, including exhaustive resolve_chart_type mapping tests, theme palette tests against both a default-theme and a real Excel theme, and a real Excel-generated chartsheet (tests/issue438.xlsx).
  • Full suite passes with --all-features; clippy and rustdoc clean.

Notes

Stacked on #653 (styles) and #628 (conditional formatting); the first two commits here are those PRs. Only the feat(xlsx): implement chart reading commit is new — happy to rebase once the parents land.

ddimaria and others added 2 commits July 16, 2026 09:23
…eet layout

Add style support for Calamine xlsx files.

Public API:
- `Xlsx::worksheet_style(sheet)` returns a row x col grid of cell styles
  using run-length encoding for memory efficiency on large workbooks.
- `Xlsx::worksheet_layout(sheet)` returns column widths and row heights.

Style types (in `src/style.rs`):
- `Style` with optional Font / Fill / Borders / Alignment / NumberFormat
  / Protection.
- `Color` with theme + tint resolution and indexed-color fallback.
- `RichText` / `TextRun` for cells with mixed inline formatting.
- `StyleRange` with RLE storage and a `cells()` iterator.

Parser in `src/xlsx/style_parser.rs` handles fonts (bold / italic /
underline / strikethrough / sz / color), fills, borders (with color and
style per side), number formats (built-in + custom format codes),
alignment (horizontal / vertical / wrap / indent / shrink / text
rotation incl. stacked), protection (locked default per OOXML), theme
colors with tint, and sysClr lastClr fallback.

Shared-string reader now decodes rich text runs and preserves their
formatting, while also handling plain text that precedes rich runs
(consistent with upstream PR tafia#637).

Includes benchmarks in `benches/style.rs` and test fixtures
(styles.xlsx, borders.xlsx, EMSI_JobChange_UK.xlsx,
problematic_formats.xlsx, styles_1M.xlsx) covering the various code
paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add conditional formatting parsing for xlsx files. Builds on the
styles work added in the preceding commit.

Public API:

```rust
// vector of conditional formatting blocks for the named sheet
let cfs = xlsx.worksheet_conditional_formatting("Sheet1")?;
for cf in &cfs {
    println!("range {}: {} rule(s)", cf.sqref, cf.rules.len());
    for rule in &cf.rules {
        match &rule.rule_type {
            ConditionalFormatRuleType::CellIs { operator, formulas } => { /* ... */ }
            ConditionalFormatRuleType::ColorScale3 { /* ... */ } => { /* ... */ }
            /* ... */
        }
    }
}
```

Supported rule types (`src/conditional_format.rs`):

- `CellIs` (greaterThan, lessThan, between, equal, etc.)
- `ColorScale2` and `ColorScale3`
- `DataBar` (with fill and optional border color)
- `IconSet` (3TrafficLights, 5Arrows, ..., with `reversed` / `showValue`)
- `Top10` (top / bottom, percent / count)
- `AboveAverage` (above / below, equal-average, stdDev)
- `Text` (contains, notContains, beginsWith, endsWith)
- `ContainsBlanks` / `NotContainsBlanks`
- `ContainsErrors` / `NotContainsErrors`
- `DuplicateValues` / `UniqueValues`
- `Expression`
- `TimePeriod`
- `Unknown` (forwards the raw type for unrecognised rules)

Each rule carries `priority`, `stop_if_true`, the optional resolved
`Format` (looked up from the `<dxfs>` table), and any per-rule formula
strings.

Includes a criterion benchmark (`benches/conditional_formatting.rs`),
an example (`examples/conditional_formatting.rs`), and a fixture
covering all 25 supported rule variants (`tests/conditional_formatting.xlsx`).

Co-authored-by: Cursor <cursoragent@cursor.com>
@ddimaria ddimaria changed the title feat(xlsx): implement chart reading Implement Charts Jul 16, 2026
Adds Xlsx::worksheet_charts / worksheet_charts_at to read the charts
embedded in a worksheet or chartsheet, with a public data model in the
new `chart` module (API modelled after rust_xlsxwriter's chart types).

Supported:
- All classic ECMA-376 chart families (bar, column, line, pie, doughnut,
  pie-of-pie, area, scatter, radar, stock, bubble, surface) including
  stacked, percent-stacked and 3D variants, and combo charts.
- Excel 2016+ chart-ex parts (funnel, treemap, sunburst, histogram,
  pareto, box & whisker, waterfall, filled map), including the
  mc:AlternateContent drawing anchors and chartEx relationship type,
  hierarchical category levels and series layout options (binning,
  subtotals, statistics, element visibility, parent label layout).
- Series data (range formulas plus cached values, multi-level category
  caches), titles (rich and formula-linked), legends, axes (position,
  scaling, tick marks, crossing partner, display units, text rotation),
  data labels (including per-point overrides), trendlines, error bars,
  up/down bars, drop/high-low/series lines, data tables, 3D view
  settings, and solid/gradient/pattern fills (with gradient angle) with
  theme color resolution.
- Anchor fidelity: twoCellAnchor editAs and absoluteAnchor position.
- Chart-space flags: autoTitleDeleted, plotVisOnly, showDLblsOverMax,
  date1904.

Also exposes the workbook theme palette via Xlsx::theme_colors(), a
named-slot ThemeColors struct (dark/light, accent1-6, hyperlink colors)
parsed once from xl/theme/theme1.xml, cached, and falling back to the
default Office palette, so consumers can reproduce Excel's accent-cycle
coloring of unstyled series without re-parsing the package.

Co-authored-by: Cursor <cursoragent@cursor.com>
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