• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

morganjwilliams / pyrolite / 17569160869

09 Sep 2025 01:41AM UTC coverage: 91.465% (-0.1%) from 91.614%
17569160869

push

github

morganjwilliams
Add uncertainties, add optional deps for pyproject.toml; WIP demo NB

6226 of 6807 relevant lines covered (91.46%)

10.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.5
/pyrolite/util/plot/grid.py
1
"""
2
Gridding and binning functions.
3
"""
4

5
import numpy as np
12✔
6
import scipy.interpolate
12✔
7

8
from ...comp.codata import close
12✔
9
from ..log import Handle
12✔
10
from .transform import ABC_to_xy, xy_to_ABC
12✔
11

12
logger = Handle(__name__)
12✔
13

14

15
def bin_centres_to_edges(centres, sort=True):
12✔
16
    """
17
    Translates point estimates at the centres of bins to equivalent edges,
18
    for the case of evenly spaced bins.
19

20
    Todo
21
    ------
22
        * This can be updated to unevenly spaced bins, just need to calculate outer bins.
23
    """
24
    if sort:
12✔
25
        centres = np.sort(centres.flatten())
12✔
26
    internal_means = (centres[1:] + centres[:-1]) / 2.0
12✔
27
    before, after = (
12✔
28
        centres[0] - (internal_means[0] - centres[0]),
29
        centres[-1] + (centres[-1] - internal_means[-1]),
30
    )
31
    return np.hstack([before, internal_means, after])
12✔
32

33

34
def bin_edges_to_centres(edges):
12✔
35
    """
36
    Translates edges of histogram bins to bin centres.
37
    """
38
    if edges.ndim == 1:
12✔
39
        steps = (edges[1:] - edges[:-1]) / 2
12✔
40
        return edges[:-1] + steps
12✔
41
    else:
42
        steps = (edges[1:, 1:] - edges[:-1, :-1]) / 2
×
43
        centres = edges[:-1, :-1] + steps
×
44
        return centres
×
45

46

47
def ternary_grid(
12✔
48
    data=None, nbins=10, margin=0.001, force_margin=False, yscale=1.0, tfm=lambda x: x
49
):
50
    """
51
    Construct a graphical linearly-spaced grid within a ternary space.
52

53
    Parameters
54
    ------------
55
    data : :class:`numpy.ndarray`
56
        Data to construct the grid around (:code:`(samples, 3)`).
57
    nbins : :class:`int`
58
        Number of bins for grid.
59
    margin : :class:`float`
60
        Proportional value for the position of the outer boundary of the grid.
61
    forge_margin : :class:`bool`
62
        Whether to enforce the grid margin.
63
    yscale : :class:`float`
64
        Y scale for the specific ternary diagram.
65
    tfm :
66
        Log transform to use for the grid creation.
67

68
    Returns
69
    --------
70
    bins : :class:`numpy.ndarray`
71
        Bin centres along each of the ternary axes (:code:`(samples, 3)`)
72
    binedges : :class:`numpy.ndarray`
73
        Position of bin edges.
74
    centregrid : :class:`list` of :class:`numpy.ndarray`
75
        Meshgrid of bin centres.
76
    edgegrid : :class:`list` of :class:`numpy.ndarray`
77
        Meshgrid of bin edges.
78
    """
79
    if data is not None:
12✔
80
        data = close(data)
12✔
81

82
        if not force_margin:
12✔
83
            margin = min([margin, np.nanmin(data[data > 0])])
12✔
84

85
    # let's construct a bounding triangle
86
    bounds = np.array(  # three points defining the edges of what will be rendered
12✔
87
        [
88
            [margin, margin, 1.0 - 2 * margin],
89
            [margin, 1.0 - 2 * margin, margin],
90
            [1.0 - 2 * margin, margin, margin],
91
        ]
92
    )
93
    xbounds, ybounds = ABC_to_xy(bounds, yscale=yscale).T  # in the cartesian xy space
12✔
94
    xbounds = np.hstack((xbounds, [xbounds[0]]))
12✔
95
    ybounds = np.hstack((ybounds, [ybounds[0]]))
12✔
96
    tck, u = scipy.interpolate.splprep([xbounds, ybounds], per=True, s=0, k=1)
12✔
97
    # interpolated outer boundary
98
    xi, yi = scipy.interpolate.splev(np.linspace(0, 1.0, 10000), tck)
12✔
99

100
    A, B, C = xy_to_ABC(np.vstack([xi, yi]).T, yscale=yscale).T
12✔
101
    abcbounds = np.vstack([A, B, C])
12✔
102

103
    abounds = tfm(abcbounds.T)
12✔
104
    ndim = abounds.shape[1]
12✔
105
    # bins for evaluation
106
    bins = [
12✔
107
        np.linspace(np.nanmin(abounds[:, dim]), np.nanmax(abounds[:, dim]), nbins)
108
        for dim in range(ndim)
109
    ]
110
    binedges = [bin_centres_to_edges(b) for b in bins]
12✔
111
    centregrid = np.meshgrid(*bins)
12✔
112
    edgegrid = np.meshgrid(*binedges)
12✔
113

114
    assert len(bins) == ndim
12✔
115
    return bins, binedges, centregrid, edgegrid
12✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc