|
68 | 68 | # The function accepts a few keyword arguments, all to do with the iron compositions
|
69 | 69 | # and related adjustment/corrections:
|
70 | 70 | #
|
71 |
| -# :code:`Fe_correction = <callable>` |
72 |
| -# For specifying the Fe-correction method/function. Currently only Le LeMaitre's |
73 |
| -# correction method is implemented [LeMaitre1976]_ . |
| 71 | +# :code:`Fe_correction = "LeMaitre" | "Middlemost"` |
| 72 | +# For specifying the Fe-correction method/function. Currently includes LeMaitre's |
| 73 | +# correction method [LeMaitre1976]_ (the default) and Middlemost's TAS-based |
| 74 | +# correction [Middlemost1989]_ . |
74 | 75 | #
|
75 | 76 | # :code:`Fe_correction_mode = 'volcanic'`
|
76 |
| -# For specificying the Fe-correction mode where relevant |
| 77 | +# For specificying the Fe-correction mode, for LeMaitre's correction. |
77 | 78 | #
|
78 | 79 | # :code:`adjust_all_Fe = False`
|
79 | 80 | # Specifying whether you want to adjust all iron compositions, or only those
|
80 | 81 | # which are partially specified (i.e. only have a singular value for one of
|
81 | 82 | # FeO, Fe2O3, FeOT, Fe2O3T).
|
82 | 83 | #
|
| 84 | +NORM = CIPW_norm(df.pyrochem.compositional, Fe_correction="Middlemost") |
| 85 | +######################################################################################## |
83 | 86 | # For the purpose of establishing the congruency of our algorithm with Verma's,
|
84 |
| -# we'll use :code:`adjust_all_Fe = True`. Notably, this won't make too much |
85 |
| -# difference to the format of the output, but it will adjust the estimates of |
86 |
| -# normative mineralogy depending on oxidation state. |
| 87 | +# we'll use :code:`adjust_all_Fe = True` and LeMaitre's correction. Notably, this |
| 88 | +# won't make too much difference to the format of the output, but it will adjust |
| 89 | +# the estimates of normative mineralogy depending on oxidation state. |
87 | 90 | #
|
88 |
| -NORM = CIPW_norm(df.pyrochem.compositional, adjust_all_Fe=True) |
| 91 | +NORM = CIPW_norm( |
| 92 | + df.pyrochem.compositional, |
| 93 | + adjust_all_Fe=True, |
| 94 | + Fe_correction="LeMaitre", |
| 95 | + Fe_correction_mode="volcanic", |
| 96 | +) |
89 | 97 | ########################################################################################
|
90 | 98 | # Now we have the normative mineralogical outputs, we can have a look to see how
|
91 | 99 | # these compare to some relevant geochemical inputs:
|
|
132 | 140 | k: v for (k, v) in translation.items() if (df[v] > 0).sum() and (NORM[k] > 0).sum()
|
133 | 141 | }
|
134 | 142 | ########################################################################################
|
135 |
| -import matplotlib.pyplot as plt |
| 143 | +# To compare SINCLAS and the :mod:`pyrolite` NORM outputs, we'll construct a grid |
| 144 | +# of plots which compare the respective mineralogical norms relative to a 1:1 line, |
| 145 | +# and highlight discrepancies. As we'll do it twice below (once for samples labelled as |
| 146 | +# volanic, and once for everything else), we may as well make a function of it. |
| 147 | +# |
| 148 | +# After that, let's take a look at the volcanic samples in isolation, which are the |
| 149 | +# the key samples for which the NORM should be applied: |
| 150 | +# |
136 | 151 | from pyrolite.plot.color import process_color
|
137 | 152 |
|
138 |
| -ncols = 4 |
139 |
| -nrows = len(minerals.keys()) // ncols + 1 if len(minerals.keys()) % ncols else 0 |
140 | 153 |
|
141 |
| -fig, ax = plt.subplots( |
142 |
| - nrows, |
143 |
| - ncols, |
144 |
| - figsize=(ncols * 2.5, nrows * 2), |
145 |
| -) |
146 |
| -fig.suptitle("Comparing pyrolite's CIPW Norm to SINCLAS/IgRoCS", fontsize=16) |
147 |
| -ax = ax.flat |
148 |
| - |
149 |
| -for ix, (b, a) in enumerate(minerals.items()): |
150 |
| - ax[ix].set_title("\n".join(b.split()), y=0.9, va="top") |
151 |
| - if a in df.columns and b in NORM.columns: |
152 |
| - c = process_color( |
153 |
| - np.abs((df[a] / NORM[b]) - 1), |
154 |
| - cmap="RdBu_r", |
155 |
| - norm=plt.Normalize(vmin=0, vmax=0.1), |
156 |
| - )["c"] |
157 |
| - ax[ix].scatter(df[a], NORM[b], c=c) |
158 |
| - ax[ix].plot([0, df[a].max()], [0, df[a].max()], color="k", ls="--") |
159 |
| - |
160 |
| -for a in ax: |
161 |
| - a.set(xticks=[], yticks=[]) # turn off the ticks |
162 |
| - if not a.collections: # turn off the axis for empty axes |
163 |
| - a.axis("off") |
164 |
| -plt.tight_layout() |
| 154 | +def compare_NORMs(SINCLAS_outputs, NORM_outputs, name=""): |
| 155 | + """ |
| 156 | + Create a grid of axes comparing the outputs of SINCLAS and `pyrolite`'s NORM, |
| 157 | + after translating the column names to the appropriate form. |
| 158 | + """ |
| 159 | + ncols = 4 |
| 160 | + nrows = len(minerals.keys()) // ncols + 1 if len(minerals.keys()) % ncols else 0 |
| 161 | + |
| 162 | + fig, ax = plt.subplots(nrows, ncols, figsize=(ncols * 2.5, nrows * 2)) |
| 163 | + fig.suptitle( |
| 164 | + " - ".join( |
| 165 | + ["Comparing pyrolite's CIPW Norm to SINCLAS/IgRoCS"] + [name] |
| 166 | + if name |
| 167 | + else [] |
| 168 | + ), |
| 169 | + fontsize=16, |
| 170 | + y=1.01, |
| 171 | + ) |
| 172 | + ax = ax.flat |
| 173 | + for ix, (b, a) in enumerate(minerals.items()): |
| 174 | + ax[ix].set_title("\n".join(b.split()), y=0.9, va="top") |
| 175 | + if a in SINCLAS_outputs.columns and b in NORM_outputs.columns: |
| 176 | + # colour by deviation from unity |
| 177 | + c = process_color( |
| 178 | + np.abs((SINCLAS_outputs[a] / NORM_outputs[b]) - 1), |
| 179 | + cmap="RdBu_r", |
| 180 | + norm=plt.Normalize(vmin=0, vmax=0.1), |
| 181 | + )["c"] |
| 182 | + ax[ix].scatter(SINCLAS_outputs[a], NORM_outputs[b], c=c) |
| 183 | + # add a 1:1 line |
| 184 | + ax[ix].plot( |
| 185 | + [0, SINCLAS_outputs[a].max()], |
| 186 | + [0, SINCLAS_outputs[a].max()], |
| 187 | + color="k", |
| 188 | + ls="--", |
| 189 | + ) |
| 190 | + |
| 191 | + for a in ax: |
| 192 | + a.set(xticks=[], yticks=[]) # turn off the ticks |
| 193 | + if not a.collections: # turn off the axis for empty axes |
| 194 | + a.axis("off") |
| 195 | + return fig, ax |
| 196 | + |
| 197 | + |
| 198 | +volcanic_filter = df.loc[:, "ROCK_TYPE"].str.lower().str.startswith("volc") |
| 199 | +fig, ax = compare_NORMs(df.loc[volcanic_filter, :], NORM.loc[volcanic_filter]) |
| 200 | + |
| 201 | + |
| 202 | +######################################################################################## |
| 203 | +# And everything else: |
| 204 | +# |
| 205 | +fig, ax = compare_NORMs(df.loc[~volcanic_filter, :], NORM.loc[~volcanic_filter]) |
| 206 | +plt.show() |
165 | 207 | ########################################################################################
|
166 | 208 | # These normative mineralogical components could be input into mineralogical
|
167 | 209 | # classifiers, as mentioned above. For example, the IUGS QAP classifier:
|
|
219 | 261 | # Contributions to Mineralogy and Petrology 56, no. 2 (1 January 1976): 181–89.
|
220 | 262 | # `doi: doi.org/10.1007/BF00399603 <https://doi.org/10.1007/BF00399603>`__
|
221 | 263 | #
|
| 264 | +# .. [Middlemost1989] Middlemost, Eric A. K. (1989). Iron Oxidation Ratios, |
| 265 | +# Norms and the Classification of Volcanic Rocks. |
| 266 | +# Chemical Geology 77, 1: 19–26. |
| 267 | +# `doi: doi.org/10.1016/0009-2541(89)90011-9. <https://doi.org/10.1016/0009-2541(89)90011-9.>`__ |
| 268 | +# |
0 commit comments