Skip to content

Repository files navigation

mpl_wrap

PyPI Python versions Builds Tests

Matplotlib helper functions for plotting wrapped, angular, or periodic data: angles, phases, times of day, longitudes, and anything else that repeats or rotates.

Manually plotting this data can be tricky. Using a modulus such as y % 360 is simple, but introduces a few problems:

  • Line jumps at the crossing points, and lines that stop short of the wrap boundaries at the crossing points
  • Aliasing when data spans multiple crossings, obscuring the real underlying behavior
  • Completely broken rendering for fill_between

mpl_wrap solves these issues, and provides simple functions to make plotting wrapped data easy.

Unwrapped vs modulus vs mpl_wrap

Installation

pip install mpl_wrap

Or install from source:

git clone https://github.com/scottshambaugh/mpl_wrap.git
cd mpl_wrap
uv sync --group dev

Basic Usage

import numpy as np
import matplotlib.pyplot as plt
from mpl_wrap import set_wrap, plot_wrapped, fill_between_wrapped, errorbar_wrapped

t = np.linspace(0, 10, 500)
angle = 80.0 * t  # degrees
width = 5.0 + 4.0 * t  # degrees

fig, ax = plt.subplots()
set_wrap(ax, wrapy=(0, 360))  # helpers on ax now wrap y into (0, 360)
fill_between_wrapped(ax, t, angle - width, angle + width, alpha=0.3, label='uncertainty')
plot_wrapped(ax, t, angle, label='angle')
ax.set(xlabel="time (s)", ylabel="angle (deg)")
ax.legend()

Basic usage: wrapped angle with uncertainty band and error bars

The helpers mirror their matplotlib counterparts, taking the target Axes as the first argument plus optional wrapx / wrapy (min, max) windows:

mpl_wrap mirrors
plot_wrapped(ax, x, y, ...) ax.plot
scatter_wrapped(ax, x, y, ...) ax.scatter
hlines_wrapped(ax, y, xmin, xmax) ax.hlines
vlines_wrapped(ax, x, ymin, ymax) ax.vlines
axhspan_wrapped(ax, ymin, ymax) ax.axhspan
axvspan_wrapped(ax, xmin, xmax) ax.axvspan
fill_between_wrapped(ax, x, y1, y2) ax.fill_between
fill_betweenx_wrapped(ax, y, x1, x2) ax.fill_betweenx
step_wrapped(ax, x, y, where=...) ax.step
stairs_wrapped(ax, values, edges) ax.stairs
errorbar_wrapped(ax, x, y, yerr, xerr) ax.errorbar

Each returns the same artist type as the method it mirrors, in the same Axes container. The two span helpers return a list of Rectangle, since a band across the seam is two rectangles.

Passing wrapx=False / wrapy=False disables wrapping for a single call (or clears the stored window when passed to set_wrap), and wrapx=True / wrapy=True requires the stored window. set_wrap also sets the axis limits to the window by default, and ticks the window evenly so that ticks land exactly on the window edges, at about the automatic tick density. Opt out with set_lims=False / edge_ticks=False, or pass seam_lines=True to mark the window edges with lines.

You must pass the original unwrapped data for these to work. If your data is already wrapped, np.unwrap may be able to recover that if it's sampled at a high enough rate.

API

The helpers are free functions, and are also available as methods on an AxesWrap axes. These three are equivalent:

from mpl_wrap import set_wrap, plot_wrapped, wrap_axes

# 1. Free functions, on any existing axes
fig, ax = plt.subplots()
set_wrap(ax, wrapy=(0, 360))
plot_wrapped(ax, t, angle)

# 2. Methods on an AxesWrap axes, created with the "wrap" projection
fig, ax = plt.subplots(subplot_kw={"projection": "wrap"})
ax.set_wrap(wrapy=(0, 360))
ax.plot_wrapped(t, angle)

# 3. Methods on an existing axes, upgraded in place from Axes to AxesWrap
fig, ax = plt.subplots()
wrap_axes(ax, wrapy=(0, 360))
ax.plot_wrapped(t, angle)

The data processing is also exposed on its own: wrap_line and wrap_points take data plus windows and return the wrapped arrays without plotting anything (also available as AxesWrap methods).

Wrapping x, y, or both

Both axes can be wrapped independently or together:

Circle wrapped in x, y, and both

Datetime data

Datetime data and windows work on either axis. Here a five-day series is wrapped to show a time-of-day view:

set_wrap(ax, wrapx=(t0, t0 + np.timedelta64(1, "D")))
plot_wrapped(ax, times, signal)

Datetime wrapping

Radians

Windows that are multiples of π/2 are automatically detected and labeled with ticks that are fractions of π.

set_wrap(ax, wrapy=(-np.pi, np.pi))
plot_wrapped(ax, t, angle)

pi demo

About

Matplotlib helper library for plotting wrapped, angular, or periodic data.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages