Source code for pyrolite.util.plot.grid

"""
Gridding and binning functions.
"""
import numpy as np
import scipy.interpolate

from ...comp.codata import close
from ..log import Handle
from .transform import ABC_to_xy, xy_to_ABC

logger = Handle(__name__)


[docs]def bin_centres_to_edges(centres, sort=True): """ 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. """ if sort: centres = np.sort(centres.flatten()) internal_means = (centres[1:] + centres[:-1]) / 2.0 before, after = ( centres[0] - (internal_means[0] - centres[0]), centres[-1] + (centres[-1] - internal_means[-1]), ) return np.hstack([before, internal_means, after])
[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 ternary_grid( data=None, nbins=10, margin=0.001, force_margin=False, yscale=1.0, tfm=lambda x: x ): """ Construct a graphical linearly-spaced grid within a ternary space. Parameters ------------ data : :class:`numpy.ndarray` Data to construct the grid around (:code:`(samples, 3)`). nbins : :class:`int` Number of bins for grid. margin : :class:`float` Proportional value for the position of the outer boundary of the grid. forge_margin : :class:`bool` Whether to enforce the grid margin. yscale : :class:`float` Y scale for the specific ternary diagram. tfm : Log transform to use for the grid creation. Returns -------- bins : :class:`numpy.ndarray` Bin centres along each of the ternary axes (:code:`(samples, 3)`) binedges : :class:`numpy.ndarray` Position of bin edges. centregrid : :class:`list` of :class:`numpy.ndarray` Meshgrid of bin centres. edgegrid : :class:`list` of :class:`numpy.ndarray` Meshgrid of bin edges. """ if data is not None: data = close(data) if not force_margin: margin = min([margin, np.nanmin(data[data > 0])]) # let's construct a bounding triangle bounds = np.array( # three points defining the edges of what will be rendered [ [margin, margin, 1.0 - 2 * margin], [margin, 1.0 - 2 * margin, margin], [1.0 - 2 * margin, margin, margin], ] ) xbounds, ybounds = ABC_to_xy(bounds, yscale=yscale).T # in the cartesian xy space xbounds = np.hstack((xbounds, [xbounds[0]])) ybounds = np.hstack((ybounds, [ybounds[0]])) tck, u = scipy.interpolate.splprep([xbounds, ybounds], per=True, s=0, k=1) # interpolated outer boundary xi, yi = scipy.interpolate.splev(np.linspace(0, 1.0, 10000), tck) A, B, C = xy_to_ABC(np.vstack([xi, yi]).T, yscale=yscale).T abcbounds = np.vstack([A, B, C]) abounds = tfm(abcbounds.T) ndim = abounds.shape[1] # bins for evaluation bins = [ np.linspace(np.nanmin(abounds[:, dim]), np.nanmax(abounds[:, dim]), nbins) for dim in range(ndim) ] binedges = [bin_centres_to_edges(b) for b in bins] centregrid = np.meshgrid(*bins) edgegrid = np.meshgrid(*binedges) assert len(bins) == ndim return bins, binedges, centregrid, edgegrid