Source code for pyrolite.plot.biplot

import numpy as np

from ..comp import codata
from ..util.log import Handle
from ..util.plot.axes import init_axes

logger = Handle(__name__)


[docs]def compositional_SVD(X: np.ndarray): """ Breakdown a set of compositions to vertexes and cases for adding to a compositional biplot. Parameters ---------- X : :class:`numpy.ndarray` Compositional array. Returns --------- vertexes, cases : :class:`numpy.ndarray`, :class:`numpy.ndarray` """ U, K, V = np.linalg.svd(codata.CLR(X)) N = X.shape[1] # dimensionality vertexes = K * V.T / (N - 1) ** 0.5 cases = (N - 1) ** 0.5 * U.T return vertexes, cases
[docs]def plot_origin_to_points( xs, ys, labels=None, ax=None, origin=(0, 0), color="k", marker="o", pad=0.05, **kwargs ): """ Plot lines radiating from a specific origin. Fornulated for creation of biplots (:func:`covariance_biplot`, :func:`compositional_biplot`). Parameters ----------- xs, ys : :class:`numpy.ndarray` Coordinates for points to add. labels : :class:`list` Labels for verticies. ax : :class:`matplotlib.axes.Axes` Axes to plot on. origin : :class:`tuple` Origin to plot from. color : :class:`str` Line color to use. marker : :class:`str` Marker to use for ends of vectors and origin. pad : :class:`float` Fraction of vector to pad text label. Returns -------- :class:`matplotlib.axes.Axes` Axes on which radial plot is added. """ x0, y0 = origin ax = init_axes(ax=ax, **kwargs) _xs, _ys = ( np.vstack([x0 * np.ones_like(xs), xs]), np.vstack([y0 * np.ones_like(ys), ys]), ) ax.plot(_xs, _ys, color=color, marker=marker, **kwargs) if labels is not None: for ix, label in enumerate(labels): x, y = xs[ix], ys[ix] dx, dy = x - x0, y - y0 theta = np.rad2deg(np.arctan(dy / dx)) x += pad * dx y += pad * dy if np.abs(theta) > 60: ha = "center" else: ha = ["right" if x < x0 else "left"][0] if np.abs(theta) < 30: va = "center" else: va = ["top" if y < y0 else "bottom"][0] ax.annotate(label, (x, y), ha=ha, va=va, rotation=theta) return ax
[docs]def compositional_biplot(data, labels=None, ax=None, **kwargs): """ Create a compositional biplot. Parameters ----------- data : :class:`numpy.ndarray` Coordinates for points to add. labels : :class:`list` Labels for verticies. ax : :class:`matplotlib.axes.Axes` Axes to plot on. Returns -------- :class:`matplotlib.axes.Axes` Axes on which biplot is added. """ ax = init_axes(ax=ax, **kwargs) v, c = compositional_SVD(data) ax.scatter(*c[:, :2].T, **kwargs) plot_origin_to_points( *v[:, :2].T, ax=ax, marker=None, labels=labels, alpha=0.5, zorder=-1, label="Variables", ) return ax