Source code for pyrolite.util.plot.interpolation

"""
Line interpolation for matplotlib lines and paths.
"""

import matplotlib.collections
import matplotlib.path
import numpy as np
import scipy.interpolate

from ..log import Handle

logger = Handle(__name__)


[docs]def interpolate_path( path, resolution=100, periodic=False, aspath=True, closefirst=False, **kwargs ): """ Obtain the interpolation of an existing path at a given resolution. Keyword arguments are forwarded to :func:`scipy.interpolate.splprep`. Parameters ----------- path : :class:`matplotlib.path.Path` Path to interpolate. resolution :class:`int` Resolution at which to obtain the new path. The verticies of the new path will have shape (`resolution`, 2). periodic : :class:`bool` Whether to use a periodic spline. periodic : :class:`bool` Whether to return a :code:`matplotlib.path.Path`, or simply a tuple of x-y arrays. closefirst : :class:`bool` Whether to first close the path by appending the first point again. Returns -------- :class:`matplotlib.path.Path` | :class:`tuple` Interpolated :class:`~matplotlib.path.Path` object, if `aspath` is :code:`True`, else a tuple of x-y arrays. """ x, y = path.vertices.T if x.size > 4: if closefirst: x = np.append(x, x[0]) y = np.append(y, y[0]) # s=0 forces the interpolation to go through every point tck, _ = scipy.interpolate.splprep( [x[:-1], y[:-1]], s=0, per=periodic, **kwargs ) xi, yi = scipy.interpolate.splev(np.linspace(0.0, 1.0, resolution), tck) # could get control points for path and construct codes here codes = None pth = matplotlib.path.Path(np.vstack([xi, yi]).T, codes=codes) if aspath: return pth else: return pth.vertices.T else: return path.vertices.T
[docs]def interpolated_patch_path(patch, resolution=100, **kwargs): """ Obtain the periodic interpolation of the existing path of a patch at a given resolution. Parameters ----------- patch : :class:`matplotlib.patches.Patch` Patch to obtain the original path from. resolution :class:`int` Resolution at which to obtain the new path. The verticies of the new path will have shape (`resolution`, 2). Returns -------- :class:`matplotlib.path.Path` Interpolated :class:`~matplotlib.path.Path` object. """ pth = patch.get_path() tfm = patch.get_transform() pathtfm = tfm.transform_path(pth) return interpolate_path( pathtfm, resolution=resolution, aspath=True, periodic=True, **kwargs )
[docs]def get_contour_paths(src, resolution=100, minsize=3): """ Extract the paths of contours from a contour plot. Parameters ------------ ax : :class:`matplotlib.axes.Axes` | Axes to extract contours from. resolution : :class:`int` Resolution of interpolated splines to return. Returns -------- contourspaths : :class:`list` (:class:`list`) List of lists, each represnting one line collection (a single contour). In the case where this contour is multimodal, there will be multiple paths for each contour. contournames : :class:`list` List of names for contours, where they have been labelled, and there are no other text artists on the figure. contourstyles : :class:`list` List of styles for contours. Notes ------ This method assumes that contours are the only :code:`matplotlib.collections.LineCollection` objects within an axes; and when this is not the case, additional non-contour objects will be returned. """ if isinstance(src, matplotlib.axes.Axes): def _iscontour(c): # contours/default lines don't have markers - allows distinguishing scatter return ( isinstance(c, matplotlib.collections.PathCollection) and c.get_sizes().size == 0 ) or isinstance(c, matplotlib.collections.LineCollection) linecolls = [ c for c in src.collections if (_iscontour(c) and len(c.get_paths())) ] names = [None for lc in linecolls] if all([len(a.get_text()) for a in src.texts]): if len(src.texts) == len(linecolls): names = [a.get_text() for a in src.texts] else: logger.debug("Can't line up labels/text with contours.") elif isinstance(src, matplotlib.contour.ContourSet): names = src.labelTexts linecolls = src.collections linecolls = [c for c in src.collections if len(c.get_paths())] rgba = [lc.get_edgecolors() for lc in linecolls] styles = [{"color": c} for c in rgba] return ( [ [ interpolate_path( p, resolution=resolution, periodic=True, aspath=False, ) for p in lc.get_paths() ] for lc in linecolls ], names, styles, )