Source code for autopew.util.plot
import logging
import matplotlib.pyplot as plt
import numpy as np
import scipy.interpolate
import scipy.spatial
from matplotlib.patches import ConnectionPatch
from ..transform.affine import affine_from_AB, affine_transform
logging.getLogger(__name__).addHandler(logging.NullHandler())
logger = logging.getLogger(__name__)
[docs]def data_to_pixels_transform(ax):
# convert pixels to axes
a2p = ax.transData.transform
d2a = ax.transAxes.transform
return lambda x: a2p(d2a(x))
[docs]def bin_centres_to_edges(centres):
"""
Translates point estimates at the centres of bins to equivalent edges,
for the case of evenly spaced bins.
Todo
------
* This can be updated to unevenly spaced bins, just need to calculate outer bins.
"""
step = (centres[1] - centres[0]) / 2
return np.append(centres - step, centres[-1] + step)
[docs]def bin_edges_to_centres(edges):
"""
Translates edges of histogram bins to bin centres.
"""
if edges.ndim == 1:
steps = (edges[1:] - edges[:-1]) / 2
return edges[:-1] + steps
else:
steps = (edges[1:, 1:] - edges[:-1, :-1]) / 2
centres = edges[:-1, :-1] + steps
return centres
[docs]def plot_2dhull(data, ax=None, s=0, **plotkwargs):
"""
Plots a 2D convex hull around an array of xy data points.
"""
if ax is None:
fig, ax = plt.subplots(1)
chull = scipy.spatial.ConvexHull(data, incremental=True)
x, y = data[chull.vertices].T
lines = ax.plot(np.append(x, [x[0]]), np.append(y, [y[0]]), **plotkwargs)
return lines
[docs]def plot_transform(
src,
dest=None,
tfm=None,
ref=None,
ax=None,
sharex=False,
sharey=False,
invert0=[False, True],
invert1=[False, True],
figsize=(10, 5),
titles=["Source Coordinates", "Destination Coordinates"],
hull=True,
):
"""
Visualise an affine transfrom.
"""
assert not ((dest is None) and (tfm is None))
src = np.array(src)
if dest is None:
dest = tfm(src)
else:
tfm = affine_transform(affine_from_AB(src, dest))
if ax is None:
fig, ax = plt.subplots(1, 2, figsize=figsize, sharex=sharex, sharey=sharey)
else:
fig = ax[0].figure
for a in ax:
a.patch.set_alpha(0)
a.set_aspect("equal")
for ix in range(src.shape[0]):
con = ConnectionPatch(
xyA=src[ix],
xyB=dest[ix],
coordsA="data",
coordsB="data",
axesA=ax[0],
axesB=ax[1],
color="0.5",
zorder=5,
ls="--",
lw=0.5,
)
ax[0].add_artist(con)
ax[0].set_title(titles[0])
ax[1].set_title(titles[1])
ax[0].scatter(*src.T, marker="x", c="k", alpha=0.8)
ax[1].scatter(*dest.T, marker="x", c="r", alpha=0.8)
if ref is not None:
s = fig.get_size_inches()[0] * 6.0
ref = np.array(ref)
tref = tfm(ref)
for ix in range(ref.shape[0]):
con = ConnectionPatch(
xyA=ref[ix],
xyB=tref[ix],
coordsA="data",
coordsB="data",
axesA=ax[0],
axesB=ax[1],
color="k",
zorder=5,
ls="--",
lw=0.5,
)
ax[0].add_artist(con)
st = dict(edgecolors="k", facecolors="none", marker="o", s=s)
ax[0].scatter(*ref.T, **st)
ax[1].scatter(*tref.T, **st)
if hull:
_hull = src
if ref is not None: # incorporate the reference points here too
_hull = np.vstack([_hull, ref])
lines = plot_2dhull(_hull, ax=ax[0], color="k", ls="-", lw=0.5)
ax[1].plot(*tfm(lines[0].get_path().vertices).T, color="k", ls="-", lw=0.5)
ax[1].yaxis.tick_right()
ax[1].yaxis.set_label_position("right")
for b, lims, setr in zip(
list(invert0) + list(invert1),
[ax[0].get_xlim(), ax[0].get_ylim(), ax[1].get_xlim(), ax[1].get_ylim()],
[ax[0].set_xlim, ax[0].set_ylim, ax[1].set_xlim, ax[1].set_ylim],
):
if b & (lims[1] > lims[0]):
setr(lims[::-1])
plt.subplots_adjust(hspace=0.1)
return fig