Skip to content

UltraPlot 2.2.0: Precision Placement — colorbars that span, norms that flex, labels that stay

Latest

Choose a tag to compare

@cvanelteren cvanelteren released this 20 Apr 08:53
· 2 commits to main since this release
8bf6ccb

UltraPlot v2.2.0

What's New

Spanning colorbars across subplot slots

Colorbars can now span a specific range of columns or rows using the span parameter, rather than stretching across the entire figure edge. This gives much finer control over colorbar placement in multi-panel figures.

release_v2 2 0_span_colorbar
Example
import ultraplot as uplt
import numpy as np

rng = np.random.default_rng(42)
data = rng.random((20, 20))

fig, axs = uplt.subplots(nrows=2, ncols=3, share=False)

for ax in axs:
    m = ax.pcolormesh(data, cmap="batlow")

# A single colorbar spanning only the first two columns
fig.colorbar(m, loc="bottom", span=(1, 2), label="Shared metric")

axs.format(
    suptitle="Spanning colorbar across selected columns",
    abc="[a.]",
    grid=False,
)

Flexible normalization inputs

Norms can now be specified as strings alongside vmin/vmax kwargs, or as compact tuple/list specs like ('linear', 0.1, 0.9). Previously, passing a string norm with explicit vmin/vmax raised an error.

release_v2 2 0_norm_inputs
Example
import ultraplot as uplt
import numpy as np

rng = np.random.default_rng(0)
data = rng.random((30, 30))

fig, axs = uplt.subplots(ncols=3, share=False)

# String norm with explicit vmin/vmax kwargs
axs[0].pcolormesh(data, norm="linear", vmin=0.2, vmax=0.8, cmap="fire")
axs[0].format(title="String + vmin/vmax")

# Tuple form bundles everything together
axs[1].pcolormesh(data, norm=("linear", 0.2, 0.8), cmap="fire")
axs[1].format(title="Tuple form")

# Works with log norms too
axs[2].pcolormesh(data + 0.01, norm=("log", 0.01, 1), cmap="fire")
axs[2].format(title="Log tuple form")

axs.format(suptitle="Flexible norm specifications", abc="[a.]", grid=False)

Bug Fixes

Title border path effects properly cleared

Disabling titleborder=False now correctly removes the stroke effect from title text. Previously, calling ax.format(titleborder=False) after a title border had been applied would leave the border visible.

release_v2 2 0_titleborder
Example
import ultraplot as uplt
import numpy as np

rng = np.random.default_rng(0)

fig, axs = uplt.subplots(ncols=2)

for ax in axs:
    ax.pcolormesh(rng.random((20, 20)), cmap="batlow")

# Left: border on (default for inset titles)
axs[0].format(title="With border", titleloc="upper left", titleborder=True)

# Right: border explicitly off — now correctly removed
axs[1].format(title="Without border", titleloc="upper left", titleborder=False)

axs.format(suptitle="Title border toggle fix", grid=False)

Outer legends no longer hide shared tick labels

Adding an outer legend (loc='r') no longer suppresses y-tick labels on neighboring axes when using sharey='labs'. The hidden panel backing the legend was incorrectly being counted as a sharing participant.

release_v2 2 0_sharey_legend
Example
import ultraplot as uplt
import numpy as np

x = np.linspace(0, 4 * np.pi, 200)

fig, axs = uplt.subplots(ncols=3, sharey="labs")

for i, ax in enumerate(axs):
    for j in range(3):
        ax.plot(x, np.sin(x + j) * (i + 1), label=f"Wave {j+1}")

# Outer legend on the middle panel — y-tick labels stay visible on all axes
axs[1].legend(loc="r")

axs.format(
    suptitle="Outer legend with shared y-labels",
    xlabel="Phase",
    ylabel="Amplitude",
    abc="[a.]",
)

Other Changes

  • Zenodo publishing fix — corrected metadata for DOI generation (#686)
  • Figure initialization refactor — internal cleanup of figure setup (#687)
  • What's New page generation fix — documentation build improvements (#697)

Full Changelog: v2.1.9...v2.2.0

What's Changed

Full Changelog: v2.1.9...v2.2.0