Skip to content

Report styling: widget/text linewidth+sizes, double-click targets, draggable insets (0.4.0)#38

Merged
CSSFrancis merged 5 commits into
mainfrom
feat/report-styling-widgets
Jul 18, 2026
Merged

Report styling: widget/text linewidth+sizes, double-click targets, draggable insets (0.4.0)#38
CSSFrancis merged 5 commits into
mainfrom
feat/report-styling-widgets

Conversation

@CSSFrancis

Copy link
Copy Markdown
Owner

Summary

Report-styling and interactive-inset features, targeting the 0.4.0 release. These are the anyplotlib-side capabilities behind SpyDE's report builder polish (widget/text styling, draggable callout insets, double-click-to-edit chrome), plus a few 0.4.0 items that were already staged on this working branch.

New features

Widget & text styling

  • linewidth= on every overlay widget — every 2-D and 1-D overlay widget constructor and add_*_widget factory (rectangle, circle, annular, crosshair, polygon, vline, hline, range, point) now takes a linewidth (px, default 2), stored and round-tripped like color. Previously only ArrowWidget honored a linewidth; the others hardcoded a 2px stroke in the renderer.
  • Plot1D.set_legend_fontsize() — control the 1-D legend text size (was a hardcoded 10px).

Double-click-to-edit chrome

  • The double_click Event gains a target field naming which text element was hit ('title', 'x_label', 'x_ticks', 'y_label', 'y_ticks', 'colorbar_label', 'legend'), so a host can open the right editor for a label vs. ticks vs. legend. 2-D panels hit-test the separate axis/title/colorbar canvases; 1-D panels zone-split the single canvas around the plot rect and legend box. A plain plot-area double-click is unchanged and carries no target (fully back-compatible).

Interactive insets

  • Native drag & resize of insets in edit_chrome mode: drag the body to move (a corner-stacked inset converts to a free anchor and its siblings re-stack), drag the bottom-right grip to resize (min 64px/dim). On release the renderer emits a figure-level inset_geometry_change event with the final anchor/w_frac/h_frac, observable via add_event_handler to persist layout. The same geometry can be set programmatically via the new InsetAxes.set_geometry(). Off edit mode the affordances are hidden and the inset is inert.
  • No title bar when the inset has no titleadd_inset(title="") (the default) now renders as a clean bordered plot box with content filling the whole area, instead of a useless empty header strip. Titled insets are unchanged (bar + click-to-minimize); title-less insets keep drag-to-move/resize (those gestures are on the body, not the bar).

Also in this release (already staged on the branch before this work)

  • indicate_point() — the point sibling of indicate_region(): a marker at a parent data point plus a leader line to the inset.
  • add_layer(tint=) / Layer.set(tint=) — render a layer as a clear→colour intensity ramp (256×4 RGBA LUT) instead of a named colormap; cmap= reverts.
  • exportPNG 3-D fix — WebGPU-rendered 3-D panels (scatter3d/voxels) no longer composite as blank rectangles; the 3-D pass is re-rendered synchronously before readback.

Changelog

Towncrier fragments added under upcoming_changes/ (orphan +slug form) for every item above. towncrier build --draft --version 0.4.0 renders a clean 0.4.0 section (7 New Features + 1 Bug Fix).

Tests

New/extended coverage across the affected suites: test_widgets (per-widget linewidth), test_label_api (legend fontsize), test_callbacks_unit/test_callbacks_playwright (double-click targets), test_inset/test_inset_callout (set_geometry, inset_geometry_change round-trip, title-bar auto-hide, real Playwright drag). The full suite passes (1600+ passed / the standard skips); the double-click and drag paths are exercised in real headless Chromium.

Previously only ArrowWidget accepted linewidth; circle/rect/annular/
crosshair/polygon and the 1D vline/hline/range/point widgets hardcoded a
2px stroke in the JS renderer. Add a linewidth kwarg (default 2) stored in
_data on every widget class and forwarded by the add_*_widget factories;
the JS drawOverlay honors it. Round-trips through widget.set/to_dict with
no allowlist changes.
Add Plot1D.set_legend_fontsize(size) writing a legend_fontsize state key
(the JS legend was a hardcoded 10px monospace); the renderer scales the
legend rows to match. Also thread the new linewidth kwarg through the 1D
add_vline/hline/range/point widget factories.
…ing 0.4.0 work)

These source files interleave this change's two features with pre-existing
uncommitted 0.4.0 work already in the tree, so they land together.

New this session:
- double_click events carry an optional `target` field ('title'/'x_label'/
  'x_ticks'/'y_label'/'y_ticks'/'legend'/'colorbar_label') via dblclick
  listeners on the axis/colorbar/title canvases + 1D gutter/legend hit-tests;
  Event gains `target`. Plot-area double_click stays untagged (back-compat).
- InsetAxes native drag + corner-resize when edit_chrome is on: dragging the
  body moves (corner->anchor on first move), a bottom-right grip resizes, and
  pointerup emits a figure-level `inset_geometry_change {inset_id, anchor,
  w_frac, h_frac}`. InsetAxes.set_geometry() + dispatch branch + Event fields.

Pre-existing (already in the working tree, not authored this session): layer
tint (LayerSpec.tint / add_layer(tint=)), InsetAxes.indicate_point, and the
3D exportPNG fix. Their towncrier fragments are included.
An inset with no title (the default) now hides its title-bar strip
entirely instead of rendering a useless empty header — the content div
fills the whole box, a clean bordered plot. Every layout computation
that used to read the raw INSET_TITLE_H constant (drag/resize clamps,
corner/anchor stacking) now goes through _insetTitleH(spec), which
returns 0 for a title-less inset, so its box height equals its content
height with no phantom gap.

A titled inset is unchanged: bar renders, click still toggles minimize.
A title-less inset has no minimize affordance (nothing to click), but
drag-to-move/resize in edit mode still works since those gestures are
wired on insetDiv itself, not the title bar. Guard added so a stray
'minimized' state on a title-less inset falls back to normal instead of
collapsing to zero height.

Extends test_inset_callout.py with DOM/behaviour coverage: default and
explicit empty/whitespace title hide the bar; non-empty title keeps it
and its click-to-minimize; title-less inset body-drag still moves it.
…uto-hide

Two CI failures on the PR:
- Docs (-W): the Event docstring's new 'target' field wrapped its description
  across indented continuation lines, which docutils flagged as 'Unexpected
  indentation'. Collapse it (and the new panel-swap / inset-geometry field
  entries) to single lines matching the existing fields; verified the docstring
  now parses clean through docutils.
- Tests: test_inset_title_drawn_in_titlebar_band assumed an empty-title inset
  still has a titlebar band to diff against, but the title-bar auto-hide feature
  removed it. Rewrite it to (a) assert a titled inset draws text in its band
  (vs a text-free baseline row) and (b) a new test asserting an empty-title
  inset has NO band. Both pass in headless chromium.
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.04762% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 90.38%. Comparing base (6b632d1) to head (f395d71).

Files with missing lines Patch % Lines
anyplotlib/axes/_inset_axes.py 97.61% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #38      +/-   ##
==========================================
+ Coverage   90.18%   90.38%   +0.20%     
==========================================
  Files          39       39              
  Lines        3902     3994      +92     
==========================================
+ Hits         3519     3610      +91     
- Misses        383      384       +1     

☔ 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@CSSFrancis
CSSFrancis merged commit 94b9c8e into main Jul 18, 2026
12 checks passed
@CSSFrancis CSSFrancis mentioned this pull request Jul 18, 2026
4 tasks
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.

2 participants