In UltraPlot 2.5.0, we introduce the Hawkeye feature for GeoAxes, a new automatic text-alignment feature, and the ability to change latex fonts with more control.
New Features
- Hawkeye map insets (
GeoAxes.hawkeye): Added a geographic callout inset
that draws attention to a region of a map without inheriting the parent
projection's aspect. Regular insets follow the parent projection, so Cartopy
stretches them to whatever the projection dictates; a hawkeye instead lets you
request a square — or circular — locator map, anchored anywhere on the parent
axes, with an automatically drawn indicator box and optional connectors.
Hawkeyes are excluded from automatic layout, so they can extend past the parent
axes without reserving subplot space, and the returned object is an ordinary
GeoAxesyou can draw external geospatial data into.
snippet
import ultraplot as uplt
singapore = (103.8198, 1.3521)
fig, ax = uplt.subplots(proj="robin", refwidth=4)
ax.format(land=True, landcolor="gray8", oceancolor="blue9")
ax.plot(*singapore, marker="o", color="red", ms=5, transform="cyl")
ax.text(106, 4, "Singapore", color="red", size=7, transform="map")
# A circular locator map anchored to the upper-right corner
inax = ax.hawkeye(
(0.97, 0.97),
size=0.23,
anchor="ur",
proj="merc",
extent=(103.76, 103.90, 1.27, 1.41),
shape="circle",
target="circle",
connector="line",
color="red",
indicator_kw={"linewidth": 1.5},
)
inax.format(land=True, landcolor="gray9", oceancolor="blue9")
inax.plot(*singapore, marker="o", color="red", ms=5, transform="cyl")- Circular and aspect-aware insets: Generalized inset support so geographic
insets can use a circular frame while still preserving projection scale. A new
aspect-aware locator keeps a circular or square inset anchored to its
lower-left corner after the box-aspect adjustment, so callout maps stay put
under resizing. Rectangular frames preserve both the requested extent and the
projection scale; circular frames expand the shorter projected dimension to
keep the projection faithful (passaspect='auto'to instead fit the exact
extent with distortion).
snippet
import ultraplot as uplt
fig, ax = uplt.subplots(proj="robin", refwidth=4)
ax.format(land=True, landcolor="gray8", oceancolor="blue9")
# `shape` controls the inset frame; `target` controls the indicator on the parent
inax = ax.hawkeye(
(0.97, 0.97), size=0.23, anchor="ur", proj="merc",
extent=(103.76, 103.90, 1.27, 1.41),
shape="circle", target="circle", connectors="line",
)
inax.format(land=True, landcolor="gray9", oceancolor="blue9")- Automatic text alignment (
Axes.auto_align_text): Added a KD-tree-based
relaxation solver that repositions text and annotations so they stop
overlapping each other, the plotted data, and the axes edges, then pulls them
back toward where you put them. Because it runs at draw time, the layout stays
valid across resizing and changing data limits. Opt individual labels in with
avoid_overlap=True, enable it globally with the newtext.alignrc setting,
and tune it withtext.align.pad,text.align.maxiter, and
text.align.arrows(which draws a connector back to each displaced label).
snippet
import ultraplot as uplt
fig, ax = uplt.subplots()
ax.scatter(x, y)
for xi, yi, name in zip(x, y, names):
ax.text(xi, yi, name)
# Relax the labels apart; `arrows=True` connects moved labels to their points
ax.auto_align_text(arrows=True)- Computer Modern math symbols (
mathtext.cm_symbols): Added a middle ground
between font-matched math and fulltext.usetex. With the setting on,
ordinary letters and numbers keep the active document font, while\mathcal
routes throughcmsy10and big operators (\sum,\prod,\int,\oint,
\bigcup,\bigoplus) route throughcmex10for an authentic Computer Modern
look — no external LaTeX required. Math is parsed when the figure is drawn,
so set this globally rather than inside a context block.
snippet
import ultraplot as uplt
expr = r"$\mathcal{ABCXYZ}\quad\sum_{i=0}^{n}\quad\prod_{j=1}^{m}\quad\int_a^b\quad\oint_C$"
uplt.rc["mathtext.cm_symbols"] = True
fig, ax = uplt.subplots(refwidth=6, refheight=1.1)
ax.text(0.02, 0.5, expr, transform="axes", va="center", fontsize=24)
ax.format(title="Computer Modern math symbols", titleloc="left")- Geographic axes in mixed subplot layouts (
abcanchor+ geo aspect): Gave
map users explicit control over the fixed-aspect-vs-slot trade-off that arises
when a map shares a GridSpec with Cartesian axes. The newabcanchoroption
chooses whether an a-b-c label attaches to the visible map boundary
('axes', the default) or to the original GridSpec slot ('slot', useful for
a regular label grid across mixed subplot types). Maps can also be stretched to
fill their slot withaspect='auto', or made the figure's layout reference so
the whole figure resizes around them.
snippet
import ultraplot as uplt
layout = [[1, 1, 1, 2, 2, 2], [3, 3, 4, 4, 5, 5]]
fig, axs = uplt.subplots(layout, refwidth=2.4, proj={4: "cyl"}, share=False)
axs[3].format(
lonlim=(0, 1),
latlim=(0, 1),
abcanchor="slot", # align the map's a-b-c label with the Cartesian slots
)
fig.format(abc="A.", abcloc="left")-
Shared row/column label spacing: When figure-level row or column labels and
a shared spanning axis label sit on the same side, the row/column labels are
now placed nearer the axes and the spanning label outside them. The gap is
controlled by the newleftlabel.sharedpad,rightlabel.sharedpad,
bottomlabel.sharedpad, andtoplabel.sharedpadsettings, which can also be
passed toformat(e.g.fig.format(leftlabelsharedpad='2em')).snippet
import ultraplot as uplt fig, axs = uplt.subplots(ncols=2, nrows=2, share=True, span=True) fig.format( leftlabels=("Row A", "Row B"), ylabel="shared y label", leftlabelsharedpad="2em", # gap between the row labels and the spanning label )
-
Keyword-alias cleanup (
_alias_kwargs): Extracted the keyword/alias
resolution helpers out of theinternalsgrab-bag into a dedicated
internals/kwargs.py, and added an@_alias_kwargsdecorator that folds
synonym keywords into their canonical names with the same precedence and
conflict warning as the old_not_noneboilerplate.Figure.__init__is the
first adopter. As a user-visible upshot, the shared style docstrings (line,
patch, pcolor/contour, text) now lead each numpydoc field with the canonical
parameter name instead of a pile of aliases, making the parameter tables much
easier to scan.
Bug Fixes
- Title centering: Fixed the horizontal centering of titles (#766).
ListedColormapdeprecation: Fixed aListedColormapNdeprecation
warning from newer matplotlib (#769).- Cross-product deprecation: Fixed a deprecation in the cross-product
computation (#777).
Maintenance & Internals
- Deprecation cleanup: Removed deprecated items and unused imports (#763).
- Docs: Simplified the docs and expanded the insets, projections, fonts, and
subplots guides with the new features above. - History hygiene: Reverted a set of misplaced hawkeye commits from
main
before re-landing the feature cleanly (#772).
Commits
83b0e73c8[Feature] Add Hawkeye option (#771)ceab2bfc4Add circular inset options9175fafab[Feature] Text alignment (#754)fa26deeceRoute selected mathtext glyphs to Computer Modern (#744)384a6259f[Feature] Abc anchor and Geo aspect (#767)8b174295bReorder visual hierarchy when side-cap labels are given (#765)1be6eeacdRefactor/alias kwargs (#775)7a5ddfb5eFix centering of titles (#766)4ab628987Fix ListedColormap N deprecation (#769)c3d1e2d7bDeprecation fix for cross product computation. (#777)410de735dRemove unused imports (#763)50cbc622fRemove deprecated items6e39447fcSimplify docsd26943592Revert misplaced hawkeye commits from main (#772)
What's Changed
- [Chore] Remove unused imports by @cvanelteren in #763
- Reorder visual hierarchy when side-cap labels are given by @cvanelteren in #765
- Fix centering of titles by @cvanelteren in #766
- [Feature] Text alignment by @cvanelteren in #754
- Fix ListedColormap N deprecation by @cvanelteren in #769
- [Feature] Abc anchor and Geo aspect by @cvanelteren in #767
- Revert misplaced hawkeye commits from main by @cvanelteren in #772
- Refactor/alias kwargs by @cvanelteren in #775
- Route selected mathtext glyphs to Computer Modern by @cvanelteren in #744
- [Feature] Add Hawkeye option by @cvanelteren in #771
- Deprecation fix for cross product computation. by @cvanelteren in #777
Full Changelog: v2.4.1...v2.5.0