• 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

87.1
/pyrolite/util/lambdas/plot.py
1
"""
2
Functions for the visualisation of reconstructed and deconstructed parameterised REE
3
profiles based on parameterisations using 'lambdas' (and tetrad-equivalent weights
4
'taus').
5
"""
6

7
import numpy as np
12✔
8

9
from ... import plot
12✔
10
from ...geochem.ind import REE, get_ionic_radii
12✔
11
from ..log import Handle
12✔
12
from .eval import (
12✔
13
    get_function_components,
14
    get_lambda_poly_function,
15
    get_tetrads_function,
16
)
17
from .params import _get_params
12✔
18
from .transform import REE_radii_to_z, REE_z_to_radii
12✔
19

20
logger = Handle(__name__)
12✔
21

22

23
def plot_lambdas_components(lambdas, params=None, ax=None, **kwargs):
12✔
24
    """
25
    Plot a decomposed orthogonal polynomial from a single set of lambda coefficients.
26

27
    Parameters
28
    ----------
29
    lambdas
30
        1D array of lambdas.
31
    params : :class:`list`
32
        List of orthongonal polynomial parameters, if defaults are not used.
33
    ax : :class:`matplotlib.axes.Axes`
34
        Optionally specified axes to plot on.
35
    index : :class:`str`
36
        Index to use for the plot (one of :code:`"index", "radii", "z"`).
37

38
    Returns
39
    --------
40
    :class:`matplotlib.axes.Axes`
41
    """
42
    degree = lambdas.size
12✔
43
    params = _get_params(params=params, degree=degree)
12✔
44
    # check the degree and parameters are of consistent degree?
45
    reconstructed_func = get_lambda_poly_function(lambdas, params)
12✔
46

47
    ax = plot.spider.REE_v_radii(ax=ax)
12✔
48

49
    radii = np.array(get_ionic_radii(REE(), charge=3, coordination=8))
12✔
50
    xs = np.linspace(np.max(radii), np.min(radii), 100)
12✔
51
    ax.plot(xs, reconstructed_func(xs), label="Regression", color="k", **kwargs)
12✔
52
    for w, p in zip(lambdas, params):  # plot the components
12✔
53
        l_func = get_lambda_poly_function(
12✔
54
            [w], [p]
55
        )  # pasing singluar vaules and one tuple
56
        label = (
12✔
57
            r"$r^{}: \lambda_{}".format(len(p), len(p))
58
            + [r"\cdot f_{}".format(len(p)), ""][int(len(p) == 0)]
59
            + "$"
60
        )
61
        ax.plot(xs, l_func(xs), label=label, ls="--", **kwargs)  # plot the polynomials
12✔
62
    return ax
12✔
63

64

65
def plot_tetrads_components(
12✔
66
    taus, tetrad_params=None, ax=None, index="radii", logy=True, drop0=True, **kwargs
67
):
68
    """
69
    Individually plot the four tetrad components for one set of $\tau$s.
70

71
    Parameters
72
    ----------
73
    taus : :class:`numpy.ndarray`
74
        1D array of $\tau$ tetrad function coefficients.
75
    tetrad_params : :class:`list`
76
        List of tetrad parameters, if defaults are not used.
77
    ax : :class:`matplotlib.axes.Axes`
78
        Optionally specified axes to plot on.
79
    index : :class:`str`
80
        Index to use for the plot (one of :code:`"index", "radii", "z"`).
81
    logy : :class:`bool`
82
        Whether to log-scale the y-axis.
83
    drop0 : :class:`bool`
84
        Whether to remove zeroes from the outputs such that individual tetrad
85
        functions are shown only within their respective bounds (and not across the
86
        entire REE, where their effective values are zero).
87
    """
88
    # flat 1D array of ts
89
    f = get_tetrads_function(params=tetrad_params)
12✔
90

91
    z = np.arange(57, 72)  # marker
12✔
92
    linez = np.linspace(57, 71, 1000)  # line
12✔
93

94
    taus = taus.reshape(-1, 1)
12✔
95
    ys = (taus * f(z, sum_tetrads=False)).squeeze()
12✔
96
    liney = (taus * f(linez, sum_tetrads=False)).squeeze()
12✔
97

98
    xs = REE_z_to_radii(z)
12✔
99
    linex = REE_z_to_radii(linez)
12✔
100
    ####################################################################################
101
    if index in ["radii", "elements"]:
12✔
102
        ax = plot.spider.REE_v_radii(logy=logy, index=index, ax=ax, **kwargs)
12✔
103
    else:
104
        index = "z"
×
105
        ax = plot.spider.spider(
×
106
            np.array([np.nan] * len(z)), indexes=z, logy=logy, ax=ax, **kwargs
107
        )
108
        ax.set_xticklabels(REE(dropPm=False))
×
109
        # xs = z
110
        # linex = linez
111

112
    if drop0:
12✔
113
        yfltr = np.isclose(ys, 0)
12✔
114
        # we can leave in markers which should actually be there at zero - 1/ea tetrad
115
        yfltr = yfltr * (
12✔
116
            1 - np.isclose(z[:, None] - np.array([57, 64, 64, 71]).T, 0).T
117
        ).astype(bool)
118
        ys[yfltr] = np.nan
12✔
119
        liney[np.isclose(liney, 0)] = np.nan
12✔
120
    return ax
12✔
121

122

123
def plot_profiles(
12✔
124
    coefficients,
125
    tetrads=False,
126
    params=None,
127
    tetrad_params=None,
128
    ax=None,
129
    index="radii",
130
    logy=False,
131
    **kwargs,
132
):
133
    r"""
134
    Plot the reconstructed REE profiles of a 2D dataset of coefficients ($\lambda$s,
135
    and optionally $\tau$s).
136

137
    Parameters
138
    ----------
139
    coefficients : :class:`numpy.ndarray`
140
        2D array of $\lambda$ orthogonal polynomial coefficients, and optionally
141
        including $\tau$ tetrad function coefficients in the last four columns
142
        (where :code:`tetrads=True`).
143
    tetrads : :class:`bool`
144
        Whether the coefficient array contains tetrad coefficients ($\tau$s).
145
    params : :class:`list`
146
        List of orthongonal polynomial parameters, if defaults are not used.
147
    tetrad_params : :class:`list`
148
        List of tetrad parameters, if defaults are not used.
149
    ax : :class:`matplotlib.axes.Axes`
150
        Optionally specified axes to plot on.
151
    index : :class:`str`
152
        Index to use for the plot (one of :code:`"index", "radii", "z"`).
153
    logy : :class:`bool`
154
        Whether to log-scale the y-axis.
155

156
    Returns
157
    --------
158
    :class:`matplotlib.axes.Axes`
159
    """
160
    radii = get_ionic_radii(REE(), charge=3, coordination=8)
12✔
161
    # check the degree required for the lambda coefficients and get the OP parameters
162
    lambda_degree = coefficients.shape[1] - [0, 4][tetrads]
12✔
163
    params = _get_params(params or "full", degree=lambda_degree)
12✔
164

165
    # get the components and y values for the points/element locations
166
    _, x0, components = get_function_components(
12✔
167
        radii,
168
        params=params,
169
        fit_tetrads=tetrads,
170
        tetrad_params=tetrad_params,
171
    )
172
    ys = np.exp(coefficients @ components)
12✔
173
    # get the components and y values for the smooth lines
174
    lineradii = np.linspace(radii[0], radii[-1], 1000)
12✔
175

176
    _, x0, linecomponents = get_function_components(
12✔
177
        lineradii,
178
        params=params,
179
        fit_tetrads=tetrads,
180
        tetrad_params=tetrad_params,
181
    )
182
    liney = np.exp(coefficients @ linecomponents)
12✔
183
    z, linez = REE_radii_to_z(radii), REE_radii_to_z(lineradii)
12✔
184
    xs, linex = radii, lineradii
12✔
185
    ####################################################################################
186
    if index in ["radii", "elements"]:
12✔
187
        ax = plot.spider.REE_v_radii(ax=ax, logy=logy, index=index, **kwargs)
12✔
188
    else:
189
        index = "z"
×
190
        ax = plot.spider.spider(
×
191
            np.array([np.nan] * len(z)), ax=ax, indexes=z, logy=logy, **kwargs
192
        )
193
        ax.set_xticklabels(REE(dropPm=False))
×
194
        xs = z
×
195
        linex = linez
×
196

197
    # ys = np.exp(ys)
198
    # liney = np.exp(liney)
199
    # scatter-only spider
200
    plot.spider.spider(
12✔
201
        ys, ax=ax, indexes=xs, logy=logy, set_ticks=False, **{**kwargs, "linewidth": 0}
202
    )
203
    # line-only spider
204
    plot.spider.spider(
12✔
205
        liney,
206
        ax=ax,
207
        indexes=linex,
208
        logy=logy,
209
        set_ticks=False,
210
        **{**kwargs, "marker": ""},
211
    )
212

213
    return ax
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