Skip to content

feat: first-class original-vs-reconstructed comparison on AggregationResult - #93

Merged
FBumann merged 2 commits into
mainfrom
feat/compare-original-reconstructed
Jul 20, 2026
Merged

feat: first-class original-vs-reconstructed comparison on AggregationResult#93
FBumann merged 2 commits into
mainfrom
feat/compare-original-reconstructed

Conversation

@FBumann

@FBumann FBumann commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Resolves both papercuts in #92.

Papercut 1 — consistent dim order

tsam emits reconstructed as (time, *cluster_dims), which disagreed with original whenever the input placed time last (the case in the issue). reconstructed is now transposed to the input's dim order, so original, reconstructed, and residuals always share dim order and line up directly in .to_dataframe()/plotting. No-op for time-first inputs.

Papercut 2 — comparison helpers

  • AggregationResult.compare(**sel) → a single DataArray stacked along a new variant dim (["original", "reconstructed"]) on the original time axis. Plots directly via color="variant" — no concat/melt. Optional coord selection, e.g. compare(variable="solar").
  • AggregationResult.to_dataframe(**sel) → tidy long-form DataFrame (variant, time, cluster/slice dims, value column) for direct handoff to a plotting lib.

Naming

Dim is variant, not the issue's suggested representation — the latter is already tsam's SegmentConfig(representation=...) and is serialized into the clustering JSON, so reusing it would overload the term. series was rejected for colliding with "time series". Values stay original/reconstructed to match the existing .original/.reconstructed attributes.

Docs

getting-started.ipynb "Reconstructed vs original" now uses the compare() one-liner in place of the manual concat/assign_coords boilerplate the issue quotes.

Tests

Added TestDimOrderConsistency (3) and TestCompare (4). Full suite green (mypy + ruff clean, notebook executes end-to-end).

Closes #92

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added comparison tools for viewing original and reconstructed data together.
    • Added conversion of aggregation results to long-form DataFrames.
    • Comparison supports selecting specific variables or dimensions.
  • Bug Fixes

    • Improved consistency of dimension ordering between original, reconstructed, and residual data.
    • Updated comparison plots to use the new streamlined comparison functionality.
  • Documentation

    • Expanded getting-started examples to demonstrate comparison plots and aligned data dimensions.

Resolves the two papercuts in #92 for eyeballing aggregation quality.

- Dim order: tsam emits `reconstructed` as `(time, *cluster_dims)`, which
  disagreed with `original` whenever the input placed `time` last. Transpose
  `reconstructed` to the input's dim order so `original`, `reconstructed`, and
  `residuals` always align for `.to_dataframe()`/plotting.
- `AggregationResult.compare(**sel)`: stacks `original` and `reconstructed`
  along a new `variant` dim (`["original", "reconstructed"]`) on the original
  time axis, plottable directly via `color="variant"` with no melt step.
- `AggregationResult.to_dataframe(**sel)`: tidy long-form DataFrame for direct
  handoff to a plotting library.
- Docs: getting-started "Reconstructed vs original" now uses the compare()
  one-liner in place of the manual concat/assign_coords boilerplate.

Closes #92

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@FBumann, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 9 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2dec7079-eee0-4cfe-8fa0-3405a52ba315

📥 Commits

Reviewing files that changed from the base of the PR and between 6393f4b and 6ee04dc.

📒 Files selected for processing (2)
  • src/tsam_xarray/_result.py
  • test/test_aggregate.py
📝 Walkthrough

Walkthrough

AggregationResult now preserves dimension ordering between original and reconstructed data, adds comparison and long-form DataFrame helpers, and updates tests and notebook examples for selection and plotting workflows.

Changes

Aggregation comparison utilities

Layer / File(s) Summary
Dimension alignment and validation
src/tsam_xarray/_core.py, test/test_aggregate.py
Reconstructed and residual results retain the input dimension order, including sliced and time-last inputs.
Comparison and DataFrame API
src/tsam_xarray/_result.py, test/test_aggregate.py
AggregationResult.compare() stacks original and reconstructed values along variant; to_dataframe() returns a reset-index long-form DataFrame with a fallback value column name.
Notebook comparison workflow
docs/examples/getting-started.ipynb
The notebook documents and uses result.compare() for plotting while preserving the xarray import needed by disaggregation examples.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AggregationResult
  participant xarrayDataArray
  participant pandasDataFrame
  AggregationResult->>xarrayDataArray: compare with optional selections
  xarrayDataArray-->>AggregationResult: variant-stacked comparison
  AggregationResult->>pandasDataFrame: to_dataframe conversion
  pandasDataFrame-->>AggregationResult: reset-index long-form table
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding first-class original-vs-reconstructed comparison support on AggregationResult.
Linked Issues check ✅ Passed The PR implements the requested dim-order alignment, compare/to_dataframe helpers, optional selection, and notebook usage for issue #92.
Out of Scope Changes check ✅ Passed The changes stay focused on comparison helpers, dim-order fixes, docs, and tests, with no obvious unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/compare-original-reconstructed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/tsam_xarray/_result.py (1)

148-151: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use Examples: instead of Example: for Google-style docstrings.

As per coding guidelines, the project uses Google-style docstrings. The Google Python Style Guide specifies that the section header should be plural (Examples:), even if there is only a single example provided.

💡 Proposed tweak
-        Example:
+        Examples:
             >>> agg.compare(variable="solar").plotly.line(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tsam_xarray/_result.py` around lines 148 - 151, Change the docstring
section heading in the affected result aggregation documentation from “Example:”
to “Examples:” while leaving the existing example content unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tsam_xarray/_result.py`:
- Around line 180-181: Update the DataArray-to-dataframe conversion around
combined.name so the selected data column name falls back to "value" when it
equals the added "variant" dimension coordinate name. Pass this collision-safe
name to combined.to_dataframe(), while preserving existing names for all other
inputs.

---

Nitpick comments:
In `@src/tsam_xarray/_result.py`:
- Around line 148-151: Change the docstring section heading in the affected
result aggregation documentation from “Example:” to “Examples:” while leaving
the existing example content unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 54056ffc-734b-4e7c-a626-188c2c09899a

📥 Commits

Reviewing files that changed from the base of the PR and between 1e87965 and 6393f4b.

📒 Files selected for processing (4)
  • docs/examples/getting-started.ipynb
  • src/tsam_xarray/_core.py
  • src/tsam_xarray/_result.py
  • test/test_aggregate.py

Comment thread src/tsam_xarray/_result.py Outdated
When the input DataArray is named "variant", to_dataframe() reused that as
the value-column name and clashed with the added "variant" dim on insert
(ValueError: cannot insert variant, already exists). Fall back to "value" in
that case; all other input names are preserved. Also fix the docstring
section heading Example -> Examples (Google style).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@FBumann
FBumann merged commit b3fd174 into main Jul 20, 2026
9 checks passed
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.

Convenience: first-class original-vs-reconstructed comparison on AggregationResult

1 participant