Skip to content

[FEAT] Enable concatenation of stylers - #1455

Open
priyam0k wants to merge 5 commits into
mainfrom
feature/issue-1336-concat-stylers
Open

priyam0k wants to merge 5 commits into
mainfrom
feature/issue-1336-concat-stylers

Conversation

@priyam0k

@priyam0k priyam0k commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary of Changes

Enables Styler.concat() to vertically stack styled triangles, link ratios, and pattern selections into a single exhibit:

  • Aligns components across differing column intervals based on common development periods, padding trailing cells with blanks.
  • Preserves pre-computed style contexts across padded shapes without re-evaluating styling functions.
  • Validates index level depth, valuation vs development alignment, and grain compatibility.
  • Adds test coverage and a user guide section.

Related GitHub Issue(s)

Closes #1336
Part of #1331

AI/LLM Usage

Used basic model for initial unit test drafting and lint checks.

Additional Context for Reviewers

Standard pandas Styler.concat requires identical column names. This enables combining loss triangles with link ratios (such as 12-24) and CDF patterns while keeping individual formats and highlights intact.

Submitter's Checklist

  • I have reviewed and am adhering to the standards outlined in the project Governing Doc.
  • The PR subject title summarizes the changes, with one proper prefix ([FIX], [FEAT], [DOCS], [TST], [CHORE], or [BRK]).
  • I am a human (not a bot), and this PR form is written by a human.

Reviewer's Checklist

  • The implementation addresses the associated issue(s).
  • The implementation is appropriate, maintainable, and follows ARCHITECTURE.md.
  • PR subject title has the proper prefix and the subject is appropriate.
  • Relevant issue(s) are linked.
  • AI/LLM usage is disclosed and appropriate.
  • Documentation and tests are appropriate.
  • CI tests passed, or any failures are acceptable.
  • Leave a comment with the final recommendation (e.g. approve as is, request a secondary review, or flag an area for more review).

Note

Low Risk
Presentation-layer changes to Styler with extensive tests; no auth, persistence, or core reserving math paths.

Overview
Adds Styler.concat() so users can vertically stack styled loss triangles, link ratios, and development patterns (LDF/CDF) into one HTML/LaTeX exhibit without requiring identical pandas column names.

When column labels differ but development lags align, the implementation compares starting development periods (including pattern intervals like 12-24 vs 12-Ult), pads missing columns with blanks, and snapshots/restores pre-computed style contexts so highlights and formats survive widening without shape errors. It validates index depth, valuation vs development mode, development grain, and lag compatibility; copies the appended styler so callers are not mutated.

Includes broad pytest coverage (chaining, widening, style preservation, error cases) and a Concatenating Stylers section in the style user guide.

Reviewed by Cursor Bugbot for commit 4f3118a. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Pyright Type Completeness

View the full pyright --verifytypes output for this commit

Project (full chainladder package, at this PR's head): 15.2% of exported symbols fully typed (225 / 1478)

Known Ambiguous Unknown Total
Project (head) 225 108 1145 1478

Other symbols referenced but not exported by chainladder: 13

Known Ambiguous Unknown Total
Other (head) 3 1 9 13

Symbols without documentation:

  • Functions without docstring: 326
  • Functions without default param: 0
  • Classes without docstring: 8

Patch (exported symbols added or changed by this PR): 4.0% fully typed (1 / 25)

Known Ambiguous Unknown Total
Patch 1 0 24 25
Patch symbol details
Symbol Status Change
chainladder.core.style.Styler.columns ❌ unknown new
chainladder.core.style.Styler.concat ✅ known new
chainladder.core.style.Styler.ctx ❌ unknown new
chainladder.core.style.Styler.ctx_columns ❌ unknown new
chainladder.core.style.Styler.ctx_index ❌ unknown new
chainladder.core.tests.test_style.test_concat_copy_preserves_concatenated ❌ unknown new
chainladder.core.tests.test_style.test_concat_identical_columns ❌ unknown new
chainladder.core.tests.test_style.test_concat_identical_columns_does_not_mutate_other_on_later_widening ❌ unknown new
chainladder.core.tests.test_style.test_concat_link_ratio_and_cdf ❌ unknown new
chainladder.core.tests.test_style.test_concat_multiple_chaining ❌ unknown new
chainladder.core.tests.test_style.test_concat_output_formats ❌ unknown new
chainladder.core.tests.test_style.test_concat_preserves_lower_triangle_styling ❌ unknown new
chainladder.core.tests.test_style.test_concat_preserves_styles ❌ unknown new
chainladder.core.tests.test_style.test_concat_prior_identical_columns_styler_frozen_on_subsequent_widen ❌ unknown new
chainladder.core.tests.test_style.test_concat_rejects_incompatible_grain ❌ unknown new
chainladder.core.tests.test_style.test_concat_rejects_incompatible_lags ❌ unknown new
chainladder.core.tests.test_style.test_concat_rejects_mismatched_index_levels ❌ unknown new
chainladder.core.tests.test_style.test_concat_rejects_non_styler ❌ unknown new
chainladder.core.tests.test_style.test_concat_rejects_raw_triangle ❌ unknown new
chainladder.core.tests.test_style.test_concat_rejects_valuation_with_development ❌ unknown new
chainladder.core.tests.test_style.test_concat_triangle_and_link_ratio ❌ unknown new
chainladder.core.tests.test_style.test_concat_widening_preserves_highlights_on_self ❌ unknown new
chainladder.core.tests.test_style.test_concat_widening_updates_prior_concatenated ❌ unknown new
chainladder.core.tests.test_style.test_concat_widens_self_with_tail ❌ unknown new
chainladder.core.tests.test_style.test_concat_with_plain_pandas_styler ❌ unknown new

@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.29730% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.14%. Comparing base (a003277) to head (4f3118a).

Files with missing lines Patch % Lines
chainladder/core/style.py 97.29% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1455      +/-   ##
==========================================
+ Coverage   94.10%   94.14%   +0.03%     
==========================================
  Files          96       96              
  Lines        5835     5909      +74     
  Branches      739      758      +19     
==========================================
+ Hits         5491     5563      +72     
- Misses        222      223       +1     
- Partials      122      123       +1     
Flag Coverage Δ
unittests 94.14% <97.29%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cursor cursor 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.

Stale Bugbot comment from a previous run.

Comment thread chainladder/core/style.py Outdated
Comment thread chainladder/core/style.py Outdated
@genedan genedan self-assigned this Oct 2, 2026

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b5b0139. Configure here.

Comment thread chainladder/core/style.py Outdated
@priyam0k
priyam0k marked this pull request as ready for review October 2, 2026 22:08
@henrydingliu

henrydingliu commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

@priyam0k thanks for putting this together. my recommendation is to add it to the axis stack.

i say this because, things like _get_starting_dev_lags shouldn't be necessary after TriangleAxis goes live. while i'm not up to date on the progress of #1304 and rest of the axis stack. i'm hoping that somewhere in that stack we are defining things like TriangleAxis.concat or TriangleAxisAxis.__add__ and then just relying on that here. if you look at what Triangle.add does, e.g. raa.iloc[:,:,:,:5] + raa.iloc[:,:,:,5:], there is reusable logic from Triangle dunders that we can centralize into TriangleAxis and leverage here.

in the current implementation, it's easy to walk into annoying corner cases (something like link_ratio_styler.concat(triangle_styler) in the User Guide example). there's already a pretty hefty if nest. i'd like to avoid bloating the styler with even more logic to catch all those corner cases.

my only other comment is that you can probably break out a _pad private method to deal with padding.

@priyam0k

priyam0k commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

my recommendation is to add it to the axis stack.

i say this because, things like _get_starting_dev_lags shouldn't be necessary after TriangleAxis goes live. while i'm not up to date on the progress of #1304 and rest of the axis stack. i'm hoping that somewhere in that stack we are defining things like TriangleAxis.concat or TriangleAxisAxis.__add__ and then just relying on that here. if you look at what Triangle.add does, e.g. raa.iloc[:,:,:,:5] + raa.iloc[:,:,:,5:], there is reusable logic from Triangle dunders that we can centralize into TriangleAxis and leverage here.

PR #1304 and the active axis stack (#1303 through #1454) focus on establishing property descriptors and deprecating legacy dimensions, without introducing axis set/arithmetic operations yet. Also, Triangle.add operates on 4D numeric arrays for tensor arithmetic, whereas Styler is 2D presentation for display DataFrames where patterns carry string interval headers like 12-24. Centralizing interval parsing into TriangleAxis once the axis stack expands makes sense, but keeping it localized here avoids blocking Styler concatenation on future axis features. Looping in @genedan in case he has thoughts on timing.

in the current implementation, it's easy to walk into annoying corner cases (something like link_ratio_styler.concat(triangle_styler) in the User Guide example). there's already a pretty hefty if nest. i'd like to avoid bloating the styler with even more logic to catch all those corner cases.

The reverse widening case (concatenating a shorter styler with a longer one) is now resolved and covered with tests. Snapshotting the styling context on the parent styler before expanding columns prevents shape mismatch errors on existing highlights during render.

my only other comment is that you can probably break out a _pad private method to deal with padding.

Broke out _pad_columns and _snapshot_context helper methods to flatten Styler.concat and eliminate the nested if blocks.

@henrydingliu

Copy link
Copy Markdown
Member

sounds good. i didn't see gene already assigned this before leaving my comment. will let gene take over from here.

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.

[ENH] Enable concatenation of stylers

3 participants