Skip to content

[Feature] Add Hawkeye option#771

Open
cvanelteren wants to merge 9 commits into
mainfrom
feature/hawkeye
Open

[Feature] Add Hawkeye option#771
cvanelteren wants to merge 9 commits into
mainfrom
feature/hawkeye

Conversation

@cvanelteren

@cvanelteren cvanelteren commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Closes #770

This PR extends the options for annotation on GeoAxes. It add specific "hawkeye" insets for GeoAxes to highlight specific areas of the map. It both adds square as well as circular annotations. Examples:

test2 test1

Succinctly this is now wired in as:

  • Scalar or (width, height) size in parent-axes fractions.
  • Anchoring with xy, transform, and anchor.
  • Geographic extent plus automatic detail/overview relation inference.
  • Extent indicators and either corner connectors or a single leader line.
  • Rectangular or circular inset/target shapes.
  • Projection-preserving circular callouts that pad the shorter map dimension;
    aspect="auto" instead fits an exact extent with distortion.
  • Optional alternative inset projection via proj=.
  • Gridlines disabled by default.

@cvanelteren

cvanelteren commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator Author

TODOS

  • fix the indicator inset behaving differently on mpl 3.9
  • Do a refactor on hawkeye as it is much too long
  • Run through the docs to check the examples and visual fidelity
  • Need to check what is causing the visual regression
  • Get a review

The method previously handled argument validation, inset construction, and
indicator drawing in one long block. It now delegates to a _HawkeyeSpec
dataclass carrying the normalized inputs and three narrow helpers:
_resolve_hawkeye_spec validates and normalizes the arguments,
_build_hawkeye_inset creates and geometrically configures the inset, and
_add_hawkeye_indicator draws the extent indicator and connectors. The
circular-boundary and indicator-patch logic move into stateless module
helpers. Behavior is unchanged; the hawkeye tests gain coverage of the
indicator-disabled path, the overview leader connector, and the
invalid-relation guard.
matplotlib 3.10 changed Axes.indicate_inset_zoom to return an InsetIndicator
artist exposing .rectangle and .connectors, whereas earlier versions such as
3.9 return a plain (rectangle, connectors) tuple. The corners-plus-detail
hawkeye path stored that raw return on the inset, so accessing .connectors
raised AttributeError on matplotlib 3.9. A new _add_hawkeye_zoom_indicator
helper wraps the legacy tuple in a simple namespace so callers can rely on the
same .rectangle and .connectors accessors on every supported version. A test
forces the legacy tuple return to exercise the normalization on newer
matplotlib as well.
When corner connectors join a detail hawkeye to a diagonally placed inset,
matplotlib's indicate_inset_zoom chose a parallel pair of connectors running
along one side instead of the two outer-tangent connectors that wrap the inset,
so the callout did not read as a zoom frustum. matplotlib fixes connector
visibility only once, from a bounding-box rule, so a draw-time hook now
recomputes the enveloping pair from the sign of the inset-to-indicator centre
offset once the inset locator has resolved the final positions. This covers both
the modern InsetIndicator and the legacy tuple return. A test pins the visible
pair for both diagonal placements.
Comment thread ultraplot/axes/geo.py Outdated
Every other hawkeye keyword is singular and the argument selects a single mode
rather than a sequence, so plural was both inconsistent with its siblings and
misleading about what it accepts. The public parameter, its docstring, the spec
field, and the parsing helper are now singular, while the result attribute
inset._hawkeye_connectors stays plural because it holds the collection of drawn
connector lines. Since hawkeye is unreleased this needs no deprecation.
origin/main only contains #772, which reverts the hawkeye/circular-inset
commits that were mis-merged there; that work belongs on this branch. Merge with
the 'ours' strategy so main is recorded as integrated while the feature branch
keeps its hawkeye implementation intact. When this branch later merges back into
main via its PR, the revert becomes the merge base and the hawkeye code is
re-added cleanly.
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.51220% with 43 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
ultraplot/axes/geo.py 84.64% 23 Missing and 16 partials ⚠️
ultraplot/axes/base.py 85.71% 1 Missing and 1 partial ⚠️
ultraplot/tests/test_inset.py 98.59% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

I think we can ignore the visual regression as I didn't touch the code for the inset. I am opening this up.

@cvanelteren
cvanelteren marked this pull request as ready for review July 17, 2026 22:32
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.

Suggestion: improve inset positioning for geoaxes

2 participants