Skip to content

Finish Matplotlib gallery acceptance repairs [mpl compatibility]#281

Open
sselvakumaran wants to merge 10 commits into
agent/gallery-compat-stack-afrom
agent/gallery-compat-stack-b-final
Open

Finish Matplotlib gallery acceptance repairs [mpl compatibility]#281
sselvakumaran wants to merge 10 commits into
agent/gallery-compat-stack-afrom
agent/gallery-compat-stack-b-final

Conversation

@sselvakumaran

@sselvakumaran sselvakumaran commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Summary

This is the second and final draft in the consolidation stack. It targets #280 and adds the post-integration acceptance repairs for:

  • vector-field option contracts and the remaining contour execution paths
  • the exact Matplotlib flag colormap across Python and the browser client
  • flat single-violin quantiles
  • dictionary-view and generator normalization at bar ingestion
  • date-string coordinates during loc="best" legend scoring
  • public Wedge.theta1 / theta2 metadata

Exact visual evidence

The commit labels, source identities, dimensions, and SHA-256 hashes are recorded in pr-assets/matplotlib-gallery-acceptance/provenance.json.

Violin gallery execution

Stack A fails this exact gallery script while normalizing a flat single-violin quantile. Stack B executes all 12 panels.

Matplotlib, Stack A failure, and Stack B violin gallery comparison

PDSH annotation integration

This is the user-reviewed PDSH text/annotation cell on the final integrated stack. The labels, boxes, axes, legend, and arrows remain readable and within the frame; small placement and stroke differences from Matplotlib remain visible rather than hidden.

Matplotlib and final Stack B PDSH annotation comparison

Verification

  • Exact Matplotlib 3.11 gallery execution at render-code commit 97bfeb6: 81/88 paired examples, up from 77/88 on Stack A and 52/88 on main, with 143 paired figures.
  • Automatic image grouping reports 78 near, 30 similar, and 35 divergent paired figures. These are triage buckets, not blanket pixel-equivalence claims.
  • Pinned PDSH tree 9b080851…: 153/154 applicable non-3D cells passed, with 289 figure captures and zero capture errors.
  • The full 3D chapter is excluded as documented. The sole execution error is Seaborn FacetGrid.map(xy_plt.axhline) forwarding marker=".".
  • The PDSH count is execution/capture coverage, not visual parity. A manual audit found 7/13 included notebooks acceptable, 5 with localized compatibility defects, and the Seaborn notebook broadly recapturing stale xy figures for native Seaborn calls.
  • The current head differs from the exact gallery/PDSH execution boundary only by the evidence/provenance commit; it contains no later render-code change.
  • Exact-head CI: 2,525 Python tests passed with 69 skipped and 122 Rust tests passed. Clippy with warnings denied, TypeScript, JS bundle build, Ruff, formatting, provenance JSON, and git diff --check also pass.
  • All current GitHub checks pass, including Matplotlib 3.11, docs, browser/accessibility, Python 3.11 floor, cross-library and methodology benchmarks, source distribution, aggregate Rust/Python/JS, CodSpeed, and all three wheel jobs. The aggregate job's first attempt timed out launching hosted-runner Chrome; the unchanged retry passed the full suite.
  • CodeRabbit reports no unresolved active thread on this PR.

Performance

The exact-head CodSpeed comparison of 446b854 against Stack A c196c12 is green: 102 benchmarks unchanged, 2 skipped, and 0 regressions.

Known deferred compatibility gaps

Gallery execution

Seven of the 88 examples still fail:

  1. image_antialiasing — display-size-dependent interpolation="auto".
  2. line_demo_dash_controllegend(handlelength=...).
  3. fill_spiral — non-simple polygon tessellation.
  4. pie_and_donut_labels — annotation zorder after the Wedge metadata repair.
  5. log_demo — minor log grid lines.
  6. time_series_histogram — string logarithmic normalization.
  7. subplots_adjust — explicit colorbar(cax=...) placement.

Gallery visual acceptance

Execution pairing is not the same as compatibility. Manual review of all 143 pairs flagged 25 figures as technically wrong or unreadable. The recurring areas are:

  • contour-label duplication/corruption and one missing colorbar
  • clipped legends, raw math commands, and bar labels crossing error bars
  • lost subplot-mosaic/GridSpec spans and overlapping titles
  • unsupported authored marker forms and visible pie-wedge fan seams
  • collapsed tables, malformed violin densities, incorrect hexbin masking/log ticks, and incorrect stacked-density normalization
  • ignored explicit tick rotation/thinning and clipped categorical/date labels

These are intentionally deferred from this shipping stack rather than hidden by the 81/88 execution number.

PDSH visual acceptance

The 153/154 result proves that the selected xy cells execute and save images. It does not prove notebook parity. The visual audit found:

  • localized blockers in 04_01, 04_05, 04_06, 04_07, and 04_10 involving axes reuse, image autoscale/data ownership, scatter-size legend samples, and missing plots
  • broad Seaborn routing/capture gaps in 04_14, where many native Seaborn calls leave stale xy figures that are captured again

Those PDSH gaps remain compatibility backlog; the 3D notebook remains explicitly out of scope.

Stack

  1. Consolidate Matplotlib gallery rendering repairs [mpl compatibility] #280 — consolidation base
  2. Finish Matplotlib gallery acceptance repairs [mpl compatibility] #281 — this final acceptance delta

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 859890f1-6ea2-4117-9dbb-5af4f56b0e41

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds Matplotlib-compatible flag colormap support across JavaScript and Python, updates SVG LUT validation, and adjusts bar, legend, violin, contour, and pie plotting behavior with regression tests.

Changes

Flag colormap support

Layer / File(s) Summary
Flag generation and registration
js/src/10_colormaps.ts, python/xy/_svg.py, python/xy/channels.py, python/xy/pyplot/__init__.py, python/xy/pyplot/_colors.py
Adds procedural 256-entry flag stops and registers flag across JavaScript and Python colormap paths, including fallback discovery.
Flag validation and provenance
tests/test_svg_export.py, pr-assets/matplotlib-gallery-acceptance/provenance.json
Validates flag LUT values, reverse registration, aliases, JavaScript generation, and gallery comparison provenance.

Plotting compatibility contracts

Layer / File(s) Summary
Bar and datetime input handling
python/xy/pyplot/_axes.py, tests/pyplot/test_categorical_gallery_regressions.py, tests/pyplot/test_best_legend_placement.py
Materializes eligible bar inputs, converts datetime legend values, and covers both behaviors with regression tests.
Violin and contour option contracts
python/xy/pyplot/_plot_types.py, tests/pyplot/test_p3_option_contracts.py
Normalizes violin quantiles and separates internal contour geometry options from preserved public extend values.
Pie wedge geometry
python/xy/pyplot/_plot_types.py, python/xy/pyplot/_artists.py
Stores pie boundary angles in dedicated entry fields and exposes them through Wedge.theta1 and Wedge.theta2.

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

Suggested reviewers: farhanaliraza

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the PR’s main goal of finishing Matplotlib compatibility repairs for gallery acceptance.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/gallery-compat-stack-b-final

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

@codspeed-hq

codspeed-hq Bot commented Jul 25, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 103 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing agent/gallery-compat-stack-b-final (2f860eb) with agent/gallery-compat-stack-a (e5b9a95)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@sselvakumaran
sselvakumaran force-pushed the agent/gallery-compat-stack-a branch from 1df83ef to ba93136 Compare July 25, 2026 03:08
@sselvakumaran
sselvakumaran force-pushed the agent/gallery-compat-stack-b-final branch 2 times, most recently from 7ca7b58 to 1d8cad0 Compare July 25, 2026 04:02
@sselvakumaran

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@sselvakumaran
sselvakumaran force-pushed the agent/gallery-compat-stack-b-final branch from 1d8cad0 to cadf5cf Compare July 25, 2026 04:12

@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 (5)
tests/test_svg_export.py (2)

764-771: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Validate generated LUT behavior, not only source fragments.

The flag branch checks the helper name and two expressions, but not the green expression, 256-entry length, clipping, or numerical output. A JavaScript/Python LUT divergence could therefore pass this test.

Suggested additions
+            assert "Math.sin(x * 31.5 * Math.PI)" in js
+            assert "Array.from({ length: 256 })" in js

Preferably compare the generated 256-byte LUT against the Python values.

🤖 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 `@tests/test_svg_export.py` around lines 764 - 771, Extend the flag-specific
assertions in the colormap export test around COLORMAP_STOPS to validate
generated LUT behavior: verify the green expression, ensure the LUT has 256
entries and applies clipping, and numerically compare the JavaScript-generated
256-byte LUT with the corresponding Python values. Retain the existing
helper-name and source-expression checks.

856-871: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover the new resolver contract and more LUT positions.

This test validates channels.is_colormap() and raw stop reversal, but never exercises resolve_cmap("flag") or resolve_cmap("flag_r"); a typo in the mapping at Line 95 would go unnoticed. Five sampled entries also will not catch quantization drift elsewhere.

Suggested additions
+    assert resolve_cmap("flag") == "flag"
+    assert resolve_cmap("flag_r") == "flag_r"

Also compare the complete 256-entry LUT, or include samples known to distinguish truncation from rounding.

🤖 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 `@tests/test_svg_export.py` around lines 856 - 871, Extend
test_flag_colormap_matches_matplotlib_lut_and_gray_aliases to call resolve_cmap
for both "flag" and "flag_r", asserting the resolver outputs match the expected
256-entry LUT and its reversal. Replace or supplement the sparse five-index
checks with a complete entry-by-entry comparison, or add samples that detect
truncation versus rounding, while preserving the existing colormap and alias
assertions.
tests/pyplot/test_categorical_gallery_regressions.py (1)

80-90: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the remaining iterable inputs.

This regression only exercises dictionary views for x and height; the changed helper also materializes one-shot width and bottom inputs. Add generator cases and assertions for those fields so those paths cannot regress silently.

🤖 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 `@tests/pyplot/test_categorical_gallery_regressions.py` around lines 80 - 90,
Extend test_bar_materializes_dictionary_views_before_shape_and_autoscale to pass
one-shot generators for bar width and bottom, then assert the recorded entry
fields preserve their materialized values and remain correctly aligned with the
bars. Cover both changed helper inputs without altering the existing
dictionary-view assertions.
tests/pyplot/test_best_legend_placement.py (1)

350-351: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the legend-scoring assertion distinguish the new paths.

The added artists exercise datetime conversion, but the existing expected location may still pass if text/annotation entries are ignored. Place one artist in a candidate corner that changes the result, or compare against a line-only control.

🤖 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 `@tests/pyplot/test_best_legend_placement.py` around lines 350 - 351, Update
the test setup around the added ax.text and ax.annotate artists so the
legend-scoring assertion produces a different expected placement when those
datetime-based artists are considered. Place an artist in a candidate corner
that affects scoring, or add a line-only control comparison, ensuring the
assertion cannot pass when text and annotation entries are ignored.
tests/pyplot/test_p3_option_contracts.py (1)

464-473: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the quantile values, not only their count.

The current assertion would still pass if normalization emitted three incorrect or duplicated coordinates. Verify the expected values as well.

Proposed test adjustment
-    assert len(result["cquantiles"]._entry["args"][0]) == 3
+    assert list(result["cquantiles"]._entry["args"][1]) == [1.75, 2.5, 3.25]
🤖 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 `@tests/pyplot/test_p3_option_contracts.py` around lines 464 - 473, Update
test_violinplot_flat_quantiles_are_one_single_violin_group to assert that
result["cquantiles"]._entry["args"][0] contains the expected quantile values
[0.25, 0.5, 0.75], while retaining the existing count assertion if useful.
🤖 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 `@js/src/10_colormaps.ts`:
- Around line 15-17: Use truncation rather than rounding for 8-bit channel
conversion in both colormap implementations: in js/src/10_colormaps.ts lines
15-17, replace Math.round around the clipped channel values; in
python/xy/_svg.py lines 57-58, remove np.rint before astype(np.uint8). Preserve
clipping and ensure both implementations match Matplotlib’s truncating
bytes=True behavior.

---

Nitpick comments:
In `@tests/pyplot/test_best_legend_placement.py`:
- Around line 350-351: Update the test setup around the added ax.text and
ax.annotate artists so the legend-scoring assertion produces a different
expected placement when those datetime-based artists are considered. Place an
artist in a candidate corner that affects scoring, or add a line-only control
comparison, ensuring the assertion cannot pass when text and annotation entries
are ignored.

In `@tests/pyplot/test_categorical_gallery_regressions.py`:
- Around line 80-90: Extend
test_bar_materializes_dictionary_views_before_shape_and_autoscale to pass
one-shot generators for bar width and bottom, then assert the recorded entry
fields preserve their materialized values and remain correctly aligned with the
bars. Cover both changed helper inputs without altering the existing
dictionary-view assertions.

In `@tests/pyplot/test_p3_option_contracts.py`:
- Around line 464-473: Update
test_violinplot_flat_quantiles_are_one_single_violin_group to assert that
result["cquantiles"]._entry["args"][0] contains the expected quantile values
[0.25, 0.5, 0.75], while retaining the existing count assertion if useful.

In `@tests/test_svg_export.py`:
- Around line 764-771: Extend the flag-specific assertions in the colormap
export test around COLORMAP_STOPS to validate generated LUT behavior: verify the
green expression, ensure the LUT has 256 entries and applies clipping, and
numerically compare the JavaScript-generated 256-byte LUT with the corresponding
Python values. Retain the existing helper-name and source-expression checks.
- Around line 856-871: Extend
test_flag_colormap_matches_matplotlib_lut_and_gray_aliases to call resolve_cmap
for both "flag" and "flag_r", asserting the resolver outputs match the expected
256-entry LUT and its reversal. Replace or supplement the sparse five-index
checks with a complete entry-by-entry comparison, or add samples that detect
truncation versus rounding, while preserving the existing colormap and alias
assertions.
🪄 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 Plus

Run ID: 42f17b8e-80d0-4ff5-b497-0afba42e85bc

📥 Commits

Reviewing files that changed from the base of the PR and between 85e3686 and 1d8cad0.

⛔ Files ignored due to path filters (2)
  • pr-assets/matplotlib-gallery-acceptance/pdsh-text-annotation.png is excluded by !**/*.png
  • pr-assets/matplotlib-gallery-acceptance/violinplot.png is excluded by !**/*.png
📒 Files selected for processing (13)
  • js/src/10_colormaps.ts
  • pr-assets/matplotlib-gallery-acceptance/provenance.json
  • python/xy/_svg.py
  • python/xy/channels.py
  • python/xy/pyplot/__init__.py
  • python/xy/pyplot/_artists.py
  • python/xy/pyplot/_axes.py
  • python/xy/pyplot/_colors.py
  • python/xy/pyplot/_plot_types.py
  • tests/pyplot/test_best_legend_placement.py
  • tests/pyplot/test_categorical_gallery_regressions.py
  • tests/pyplot/test_p3_option_contracts.py
  • tests/test_svg_export.py

Comment thread js/src/10_colormaps.ts Outdated
@sselvakumaran

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@sselvakumaran
sselvakumaran force-pushed the agent/gallery-compat-stack-b-final branch 3 times, most recently from 96cc716 to 10ade55 Compare July 25, 2026 06:21
@sselvakumaran
sselvakumaran force-pushed the agent/gallery-compat-stack-b-final branch from 10ade55 to 446b854 Compare July 25, 2026 06:32
@sselvakumaran
sselvakumaran marked this pull request as ready for review July 26, 2026 05:43
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