This page was generated from docs/examples/mineralML_mapping.ipynb. Interactive online version: Binder badge.

Python Notebook Download

[1]:
""" Created on November 13, 2023 // Updated on March 20, 2026 // @author: Sarah Shi """

import os
import numpy as np
import pandas as pd

import mineralML as mm

import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'png'

mineralML Quickstart for Mapped EDS Data

This notebook shows how to load and run your quantitative EDS data through mineralML with an example gabbroic nodule from the Galapagos: 09g3. These data are from Gleeson et al., 2024 (find the paper here: https://doi.org/10.1093/petrology/egaf031) in this GitHub repository (https://github.com/gleesonm1/GleesonEtAl_JPet_2024_supplement/tree/main/Code_Figures/Data/LargeScaleMaps/Gabbro%20Samples). Please refer to the paper for more information about this sample.

This is a five step process:

  1. Load a directory containing all your CSVs of mapped chemical data with mm.load_df (or pd.read_csv directly). [Optional] Convert the input from element to oxide wt%.

  2. Predict the mineral class with mineralML and automatically plot the mineral phase map, mineral phase counts, and prediction score histograms

  3. Plot prediction score map and individual oxide maps.

  4. Plot compositions of mapped minerals in various classification diagrams (ternary, quadrilateral).

  5. Plot chemical variation maps.

I have conveniently (I hope!) wrapped all of these bits into one function, called mm.run_map.

We loaded in the mineralML Python package as mm. mineralML has trained machine learning models for classifying minerals. This implementation aims to get your electron microprobe or quantitative EDS compositions classified and processed. We remove some degrees of freedom to simplify the process as much as possible. The minerals considered for this study include: Amphibole, Apatite, Biotite, Calcite, Chlorite, Epidote, Feldspar (Alkali Feldspar and Plagioclase), Garnet, Glass, Kalsilite, Leucite, Melilite, Muscovite, Nepheline, Olivine, Oxide (Rhombohedral_Oxides including Hematite-Ilmenite, Spinel_Group including Magnetite-Spinel), Pyroxene (Clinopyroxene, Orthopyroxene, Na-Pyroxene), Quartz, Rutile, Serpentine, Titanite, Tourmaline, and Zircon.

CSV files containing your mapped data in oxide weight percentages (or converted to) is necessary. Find an example here, reproduced from the Gleeson et al., 2024 GitHub linked above. The necessary oxides are SiO\(_2\), TiO\(_2\), Al\(_2\)O\(_3\), FeO\(_t\), MnO, MgO, CaO, Na\(_2\)O, K\(_2\)O, Cr\(_2\)O\(_3\), P\(_2\)O\(_5\), and ZrO\(_2\) (if you are aiming to classify zircon). For the oxides not analyzed for specific minerals, the preprocessing will fill in the nan values as 0.

1. Load and prepare data for analysis

Here, we will work with data that are in elemental weight percent. This means that we will have to do a conversion to oxide weight percent. The data directory is Maps/09g3.

[2]:
# Find your directory of mapped mineral data, stored in Maps/09g3.
# This code identifies any file with CSV and appends it to the map.

base = "Maps"
map_dirs = []
for root, subdirs, files in os.walk(base):
    # Skip any path that includes 'Ignore' in its folder names
    if "Ignore" in root.split(os.sep):
        continue

    if any(f.lower().endswith(".csv") for f in files):
        map_dirs.append(root)

print(map_dirs)
['Maps/09g3', 'Maps/MountHood_MH0811b']

2. Apply the trained neural network with mm.run_map

We will use mm.run_map which will return all you need!

[3]:
# Inspect the inputs and outputs of mm.run_map
help(mm.run_map)
Help on function run_map in module mineralML.mapping:

run_map(sample_input, renormalize=False, total_threshold=None, n_iterations=50, min_frac=1e-05, pred_score_threshold=0.6, units='element_wt%', top_k=None, phases=None, exclude_phases=None, phase_colors=None, bar_style='vertical', components_spec=None, remove_islands_flag=False, fill_holes_flag=False, hole_size=10, scalebar_um=None, pixel_size_um=None, scalebar_loc='lower left', scalebar_col='black', show=True)
    Load, convert, predict, and plot for one folder of CSV maps.
    Always computes mineral components and returns a full results dictionary.
    Use ``remove_islands_flag`` and ``fill_holes_flag`` to clean the phase map
    before plotting and downstream analysis.

    Parameters:
        sample_input (str | Path | dict): Directory path or a dict of oxide maps.
        renormalize (bool): If True, scale each pixel so oxides sum to 100 wt%.
            Applied after total masking.
        total_threshold (float | None): Pixels with oxide total below this
            value (wt%) are set to NaN before renormalization and prediction.
            Use this to mask epoxy/background.
        n_iterations (int): MC forward passes for prediction.
        min_frac (float): Minimum pixel fraction required to keep a phase.
        pred_score_threshold (float): Label NaN where max prediction score <
            threshold.
        units (str): Input format — 'element_wt%' or 'oxide_wt%'.
        top_k (int|None): Cap displayed phases after filtering.
        phases (list[str]|None): Explicit phases to plot (overrides auto-pick).
        exclude_phases (list[str]|None): Phases to remove from auto-pick.
        phase_colors (dict|None): Manual color mapping {PhaseName: HexColor}.
        bar_style (str): "vertical" for the default bar chart
            (``plot_phase_counts``), or "stacked" for a stacked horizontal
            bar (``plot_phase_proportions``).
        components_spec (dict|None): Custom mineral formula logic.
        remove_islands_flag (bool): If True, removes isolated pixel clusters
            smaller than 2 pixels (4-connected) from the phase map. Useful
            for cleaning up salt-and-pepper noise in the epoxy region.
        fill_holes_flag (bool): If True, fills enclosed background holes within
            continuous phase regions up to ``hole_size`` pixels. Useful for
            patching small gaps inside large mineral grains.
        hole_size (int): Maximum hole area (in pixels) to fill when
            ``fill_holes_flag`` is True.
        scalebar_um (float, optional): Length of the scale bar in micrometers.
        pixel_size_um (float): Physical size of a single pixel in micrometers.
        scalebar_loc (str): Location of the scale bar (e.g., 'lower left').
        scalebar_col (str): Color of the scale bar text/line.
        show (bool): If True, calls plt.show().

    Returns:
        result (dict): Dictionary with keys 'figs', 'shape', 'oxide_maps',
            'df_pred', 'mineral_map', 'pred_score_map', 'kept_phases',
            'component_maps', 'component_frames'. ``oxide_maps`` includes a
            ``'Total'`` key with the per-pixel oxide sum.

[4]:
# Here is our all in one function! Read the inputs and outputs provided above.

output = mm.run_map(next((s for s in map_dirs if '09g3' in s), None), # provide the directory of interest. alternatively, you can provide the preloaded dictionary of oxides.
                    renormalize=False, # optionally renormalize totals to 100 wt%.
                    total_threshold=None, # optionally filter out SiO2 values below a given value, for when EDS picks up epoxy pixels
                    pred_score_threshold=0.6, # provide a prediction score threshold. here, i only want values with >= 0.6 prediction score.
                    min_frac=0.01, # provide a minimum pixel fraction for the phase to be displayed
                    units='element_wt%', # provide the unit. can choose 'element_wt%' or 'oxide_wt%'
                    phases=['Plagioclase', 'Clinopyroxene', 'Orthopyroxene', 'Oxide', 'Olivine', 'Glass'], # phases of interest
                    scalebar_um=50, # define size of scalebar desired, in microns
                    pixel_size_um=2, # define size of each pixel of scalebar, in microns
                    scalebar_loc='upper right', # specify location for scalebar
                    scalebar_col='white', # specify color for scalebar
                    )
[ok] Si Wt%Montaged Map Data.csv  →  Si  (329, 283)
[ok] Ca Wt%Montaged Map Data.csv  →  Ca  (329, 283)
[ok] Cr Wt%Montaged Map Data.csv  →  Cr  (329, 283)
[ok] Mg Wt%Montaged Map Data.csv  →  Mg  (329, 283)
[ok] Mn Wt%Montaged Map Data.csv  →  Mn  (329, 283)
[ok] Al Wt%Montaged Map Data.csv  →  Al  (329, 283)
[ok] Ti Wt%Montaged Map Data.csv  →  Ti  (329, 283)
[ok] Na Wt%Montaged Map Data.csv  →  Na  (329, 283)
[ok] Fe Wt%Montaged Map Data.csv  →  Fe  (329, 283)
[ok] K Wt%Montaged Map Data.csv  →  K  (329, 283)
mineralML: 93107 rows — 57725 classified by neural network, 7 by empirical rules (Zircon: 0, SiO2 polymorph: 0, Carbonate: 7), 35375 skipped (invalid/empty)
prep_df: 57725 row(s) processed (of 57725 input, 0 dropped).
/home/docs/checkouts/readthedocs.org/user_builds/mineralml/checkouts/stable/src/mineralML/hybrid.py:313: UserWarning: The following columns were missing and have been filled with NaN: ['Mineral']
  df = prep_df(df)
../_images/examples_mineralML_mapping_7_2.png
../_images/examples_mineralML_mapping_7_3.png
../_images/examples_mineralML_mapping_7_4.png
[5]:
# Inspect what is in the outputs
output.keys()
[5]:
dict_keys(['figs', 'shape', 'oxide_maps', 'df_pred', 'mineral_map', 'pred_score_map', 'kept_phases', 'component_maps', 'component_frames'])

Let’s say you now want to work with these data in dataframe form rather than dictionary form. How would you do this? Access output['df_pred'] to retrieve the predictions dataframe.

[6]:
# Pull the dataframe of predictions
df_pred = output['df_pred']
display(df_pred)
SiO2 TiO2 Al2O3 FeOt MnO MgO CaO Na2O K2O Cr2O3 P2O5 ZrO2 Predict_Mineral Prediction_Score Prediction_Score_Sigma Second_Predict_Mineral Second_Prediction_Score Submineral
0 49.263735 0.246671 31.267656 -0.141366 -0.133547 -0.041928 11.384471 3.906129 0.287173 0.206763 NaN NaN Plagioclase 0.998627 0.005443 Muscovite 0.001223 Labradorite
1 52.781465 1.223476 29.213528 1.751936 -0.008407 0.353991 13.811718 3.613949 0.326185 0.009850 NaN NaN Plagioclase 0.999909 0.000345 Titanite 0.000041 Labradorite
2 49.582496 -0.666395 31.217623 0.669667 0.312345 0.135481 13.362425 2.559899 0.404478 -0.008271 NaN NaN Plagioclase 0.999078 0.002773 Muscovite 0.000342 Bytownite
3 49.766286 -0.061016 30.748715 -0.049472 0.052490 -0.063224 13.924789 3.722859 0.031619 -0.244754 NaN NaN Plagioclase 0.987317 0.083828 Leucite 0.007627 Labradorite
4 50.775667 0.283931 29.405951 0.363973 0.161280 0.434312 12.246722 2.495524 0.260420 0.922368 NaN NaN Plagioclase 0.997432 0.005905 Glass 0.001690 Bytownite
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
93102 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 NaN NaN None NaN NaN NaN NaN NaN
93103 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 NaN NaN None NaN NaN NaN NaN NaN
93104 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 NaN NaN None NaN NaN NaN NaN NaN
93105 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 NaN NaN None NaN NaN NaN NaN NaN
93106 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN None NaN NaN NaN NaN NaN

93107 rows × 18 columns

3. Plot oxide concentration maps and prediction score maps

Let’s plot the original oxide maps loaded from the directory. We can examine how well the predicted phase map matches some of the observations made in oxide space. We have a handy function for doing so, with mm.plot_oxide_map.

[7]:
fig, ax = mm.plot_oxide_map(
    output, # take the output from run_map
    oxide_name='SiO2', # specify the oxide of interest
    scalebar_um=50, # define size of scalebar desired, in microns
    pixel_size_um=2, # define size of each pixel of scalebar, in microns
    scalebar_loc='upper right', # specify location for scalebar
    scalebar_col='black', # specify color for scalebar
)
../_images/examples_mineralML_mapping_12_0.png

Let’s plot the prediction scores from the output, in mapped form. This allows for further investigation to determine where predictions are more and less certain.

[8]:
fig, ax = mm.plot_score_map(
    output, # take the output from run_map
    scalebar_um=50, # define size of scalebar desired, in microns
    pixel_size_um=2, # define size of each pixel of scalebar, in microns
    scalebar_loc='upper right', # specify location for scalebar
    scalebar_col='black', # specify color for scalebar
)
../_images/examples_mineralML_mapping_14_0.png

4. Plot compositions of mapped minerals in various classification diagrams (ternary, quadrilateral).

We can do some more with mineralML now. Let’s plot all the feldspars, pyroxenes, and spinels in ternary space.

Identify the phases present.

[9]:
# Here are all our feldspars
fspars = df_pred[df_pred.Predict_Mineral == 'Plagioclase']
display('Feldspars:', fspars)

# Here are all our pyroxenes
pxs_names = ['Clinopyroxene', 'Orthopyroxene']
pxs = df_pred[df_pred.Predict_Mineral.isin(pxs_names)]
display('Pyroxenes:', pxs)

# Here are all our oxides
ox_names = ['Oxide']
oxs = df_pred[df_pred.Predict_Mineral.isin(ox_names)]
display('Oxides:', oxs)
'Feldspars:'
SiO2 TiO2 Al2O3 FeOt MnO MgO CaO Na2O K2O Cr2O3 P2O5 ZrO2 Predict_Mineral Prediction_Score Prediction_Score_Sigma Second_Predict_Mineral Second_Prediction_Score Submineral
0 49.263735 0.246671 31.267656 -0.141366 -0.133547 -0.041928 11.384471 3.906129 0.287173 0.206763 NaN NaN Plagioclase 0.998627 0.005443 Muscovite 0.001223 Labradorite
1 52.781465 1.223476 29.213528 1.751936 -0.008407 0.353991 13.811718 3.613949 0.326185 0.009850 NaN NaN Plagioclase 0.999909 0.000345 Titanite 0.000041 Labradorite
2 49.582496 -0.666395 31.217623 0.669667 0.312345 0.135481 13.362425 2.559899 0.404478 -0.008271 NaN NaN Plagioclase 0.999078 0.002773 Muscovite 0.000342 Bytownite
3 49.766286 -0.061016 30.748715 -0.049472 0.052490 -0.063224 13.924789 3.722859 0.031619 -0.244754 NaN NaN Plagioclase 0.987317 0.083828 Leucite 0.007627 Labradorite
4 50.775667 0.283931 29.405951 0.363973 0.161280 0.434312 12.246722 2.495524 0.260420 0.922368 NaN NaN Plagioclase 0.997432 0.005905 Glass 0.001690 Bytownite
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
92980 50.751835 0.053460 30.892806 0.040494 -0.461759 0.181496 13.219259 4.255093 0.562793 0.125117 NaN NaN Plagioclase 0.998067 0.008614 Glass 0.001712 Labradorite
92981 47.055855 0.435257 28.540332 0.088852 -0.089822 0.027772 10.548025 3.540654 0.550766 0.032374 NaN NaN Plagioclase 0.980982 0.046478 Glass 0.012173 Labradorite
92982 49.572227 0.371584 32.248626 0.873017 -0.285326 0.130899 12.215584 4.380849 0.471066 0.514502 NaN NaN Plagioclase 0.999816 0.000423 Muscovite 0.000078 Labradorite
92983 49.374082 -0.392758 32.780453 0.389758 0.339789 0.275332 13.295722 4.352765 0.428836 0.269782 NaN NaN Plagioclase 0.997028 0.018393 Leucite 0.001778 Labradorite
92984 47.506399 0.326601 30.147186 0.261584 -0.122220 -0.125815 12.209264 4.127070 0.188657 -0.821505 NaN NaN Plagioclase 0.990222 0.040914 Glass 0.007537 Labradorite

32058 rows × 18 columns

'Pyroxenes:'
SiO2 TiO2 Al2O3 FeOt MnO MgO CaO Na2O K2O Cr2O3 P2O5 ZrO2 Predict_Mineral Prediction_Score Prediction_Score_Sigma Second_Predict_Mineral Second_Prediction_Score Submineral
49 46.703956 2.306829 8.091728 7.608155 0.179336 10.411849 18.795262 2.432519 0.532825 0.203853 NaN NaN Clinopyroxene 0.907966 0.130830 Glass 0.059600 Diopside
610 48.659501 1.695958 7.334367 7.926977 -0.333935 10.416438 17.438423 2.285797 1.183322 0.106932 NaN NaN Clinopyroxene 0.921416 0.161371 Glass 0.050355 Diopside
616 48.778790 1.189971 2.368374 9.717480 -0.178262 19.703388 16.359033 0.808957 0.195681 0.046046 NaN NaN Clinopyroxene 0.796175 0.219379 Amphibole 0.191745 Augite
626 43.817565 1.304287 4.129765 5.646358 -0.037404 11.766227 22.258578 1.406237 0.008721 0.322146 NaN NaN Clinopyroxene 0.974739 0.057883 Melilite 0.013015 Wollastonite
900 48.447279 1.397534 3.416259 9.859029 0.064421 16.668941 17.343585 1.357627 0.303317 0.192969 NaN NaN Clinopyroxene 0.955462 0.122916 Amphibole 0.043007 Augite
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
93026 48.531633 1.086635 6.924229 5.679027 0.897636 13.753107 20.414549 0.316232 0.073446 0.035749 NaN NaN Clinopyroxene 0.926149 0.175677 Garnet 0.032151 Diopside
93027 46.290230 1.380040 7.945115 7.235223 0.274338 11.797178 19.396081 0.955456 -0.142047 0.399850 NaN NaN Clinopyroxene 0.887151 0.191542 Glass 0.055837 Diopside
93028 48.117886 0.149082 8.696416 5.671712 0.169030 13.621192 20.402754 1.625494 0.058249 -0.174842 NaN NaN Clinopyroxene 0.971680 0.096162 Melilite 0.015869 Diopside
93029 46.544554 0.287509 7.870030 6.250091 0.117071 12.650849 19.429830 -0.016576 0.135432 -0.335588 NaN NaN Clinopyroxene 0.868953 0.225773 Garnet 0.056096 Diopside
93030 45.316298 0.119567 7.955299 6.887216 0.233471 11.919362 19.708412 0.945937 0.133037 0.141968 NaN NaN Clinopyroxene 0.951828 0.099333 Amphibole 0.025499 Diopside

14067 rows × 18 columns

'Oxides:'
SiO2 TiO2 Al2O3 FeOt MnO MgO CaO Na2O K2O Cr2O3 P2O5 ZrO2 Predict_Mineral Prediction_Score Prediction_Score_Sigma Second_Predict_Mineral Second_Prediction_Score Submineral
596 14.170745 0.458430 47.168928 17.851108 0.157325 8.807434 2.364795 1.613537 0.231962 0.909729 NaN NaN Oxide 0.974216 0.141011 Chlorite 2.158251e-02 Spinel_Group
597 -0.541988 -0.226758 59.577095 22.761509 0.261160 16.543655 0.178530 -0.327176 -0.002519 0.596073 NaN NaN Oxide 0.999999 0.000000 Chlorite 6.135478e-07 Spinel_Group
598 0.328607 0.192199 60.074062 22.531151 -0.581629 16.206175 -0.071793 0.404589 -0.041741 1.762033 NaN NaN Oxide 0.999997 0.000000 Rhombohedral_Oxides 3.225375e-06 Spinel_Group
599 0.419032 -0.416014 59.597162 20.757558 -0.198876 16.481142 -0.157663 0.094932 0.114364 1.412415 NaN NaN Oxide 0.999999 0.000244 Rhombohedral_Oxides 6.114131e-07 Spinel_Group
879 -0.283622 -0.329943 58.807763 21.683161 0.131220 15.814531 -0.270460 0.445707 0.113306 0.450210 NaN NaN Oxide 0.999537 0.003239 Chlorite 4.634696e-04 Spinel_Group
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
92992 -0.972727 0.199933 61.268541 19.730463 0.777305 16.862860 0.416785 0.532657 0.209819 1.072017 NaN NaN Oxide 0.999999 0.000244 Chlorite 5.719100e-07 Spinel_Group
92993 -0.754471 -0.316257 58.986714 21.457833 0.307136 14.984843 -0.049067 -0.382976 -0.506373 0.888524 NaN NaN Oxide 0.961885 0.186700 Chlorite 3.811476e-02 Spinel_Group
92994 -0.476960 0.326008 59.845682 20.725138 0.091979 16.190988 0.066551 0.394945 0.127746 0.985187 NaN NaN Oxide 0.999744 0.001777 Rhombohedral_Oxides 2.553134e-04 Spinel_Group
92995 5.724564 0.254216 55.985948 19.883002 -0.329296 15.163671 0.563598 1.013702 0.281037 1.044170 NaN NaN Oxide 0.996396 0.024116 Chlorite 3.439376e-03 Spinel_Group
92999 -0.771758 -0.311966 61.128154 23.235195 -0.302034 16.418883 0.084923 0.164328 0.299144 1.515729 NaN NaN Oxide 0.980000 0.140000 Nepheline 1.999995e-02 Spinel_Group

1902 rows × 18 columns

Plot these feldspars, pyroxenes, and spinels!

[10]:
# Use FeldsparClassifier to examine at the component space (XAn, XAb, XOr)
fspar_comp = mm.FeldsparClassifier(fspars).calculate_components()
display(fspar_comp)

# Use FeldsparClassifier to plot up these data.
fig = mm.FeldsparClassifier(fspars).plot()
Sample SiO2 TiO2 Al2O3 FeOt MnO MgO CaO Na2O K2O ... Prediction_Score Prediction_Score_Sigma Second_Predict_Mineral Second_Prediction_Score Cation_Sum M_site T_site An Ab Or
0 NaN 49.263735 0.246671 31.267656 0.000000 0.000000 0.000000 11.384471 3.906129 0.287173 ... 0.998627 0.005443 Muscovite 0.001223 4.999206 0.944346 4.038491 0.605725 0.376083 0.018192
1 NaN 52.781465 1.223476 29.213528 1.751936 0.000000 0.353991 13.811718 3.613949 0.326185 ... 0.999909 0.000345 Titanite 0.000041 5.005620 0.989984 3.885500 0.665953 0.315321 0.018726
2 NaN 49.582496 0.000000 31.217623 0.669667 0.312345 0.135481 13.362425 2.559899 0.404478 ... 0.999078 0.002773 Muscovite 0.000342 4.973277 0.918395 4.007258 0.723219 0.250716 0.026065
3 NaN 49.766286 0.000000 30.748715 0.000000 0.052490 0.000000 13.924789 3.722859 0.031619 ... 0.987317 0.083828 Leucite 0.007627 5.019679 1.028596 3.989021 0.672721 0.325460 0.001819
4 NaN 50.775667 0.283931 29.405951 0.363973 0.161280 0.434312 12.246722 2.495524 0.260420 ... 0.997432 0.005905 Glass 0.001690 4.923061 0.851499 3.977005 0.717332 0.264506 0.018162
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
92980 NaN 50.751835 0.053460 30.892806 0.040494 0.000000 0.181496 13.219259 4.255093 0.562793 ... 0.998067 0.008614 Glass 0.001712 5.053574 1.055605 3.977727 0.612308 0.356653 0.031038
92981 NaN 47.055855 0.435257 28.540332 0.088852 0.000000 0.027772 10.548025 3.540654 0.550766 ... 0.980982 0.046478 Glass 0.012173 4.987109 0.940703 4.023037 0.598951 0.363812 0.037237
92982 NaN 49.572227 0.371584 32.248626 0.873017 0.000000 0.130899 12.215584 4.380849 0.471066 ... 0.999816 0.000423 Muscovite 0.000078 5.065717 1.008939 3.983479 0.590014 0.382896 0.027090
92983 NaN 49.374082 0.000000 32.780453 0.389758 0.339789 0.275332 13.295722 4.352765 0.428836 ... 0.997028 0.018393 Leucite 0.001778 5.089961 1.051290 3.982672 0.613189 0.363263 0.023548
92984 NaN 47.506399 0.326601 30.147186 0.261584 0.000000 0.000000 12.209264 4.127070 0.188657 ... 0.990222 0.040914 Glass 0.007537 5.045055 1.026253 3.996449 0.613466 0.375247 0.011287

32058 rows × 58 columns

../_images/examples_mineralML_mapping_19_1.png
[11]:
# Use PyroxeneClassifier to examine at the component space (En, Wo, Fs). If sodic pyroxenes are also within this input, this will plot them up in the sodic pyroxene ternary
pxs_comp = mm.PyroxeneClassifier(pxs).calculate_components()
display(pxs_comp)

# Use PyroxeneClassifier to plot up these data.
fig = mm.PyroxeneClassifier(pxs).plot()
Sample SiO2 TiO2 Al2O3 FeOt MnO MgO CaO Na2O K2O ... EnFs DiHd_2003 Di Fe3_Wang21 Fe2_Wang21 Di_h Hd_h Aeg_h Jd_h En_h
49 NaN 46.703956 2.306829 8.091728 7.608155 0.179336 10.411849 18.795262 2.432519 0.532825 ... 0.086829 0.666407 0.469393 0.089679 0.154568 0.595819 0.009059 0.115772 0.018559 0.034919
610 NaN 48.659501 1.695958 7.334367 7.926977 0.000000 10.416438 17.438423 2.285797 1.183322 ... 0.107573 0.632821 0.443486 0.013317 0.240387 0.594261 0.014598 0.071088 0.104224 0.066707
616 NaN 48.778790 1.189971 2.368374 9.717480 0.000000 19.703388 16.359033 0.808957 0.195681 ... 0.417242 0.575877 0.451074 0.155597 0.150052 0.457241 0.000000 0.033339 0.000000 0.323735
626 NaN 43.817565 1.304287 4.129765 5.646358 0.000000 11.766227 22.258578 1.406237 0.008721 ... 0.015722 0.891255 0.702211 0.187016 0.008697 0.726986 0.114188 0.062239 0.000000 0.000000
900 NaN 48.447279 1.397534 3.416259 9.859029 0.064421 16.668941 17.343585 1.357627 0.303317 ... 0.317609 0.617466 0.462866 0.180335 0.131760 0.522099 0.000000 0.068710 0.000000 0.213817
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
93026 NaN 48.531633 1.086635 6.924229 5.679027 0.897636 13.753107 20.414549 0.316232 0.073446 ... 0.135029 0.681486 0.537139 -0.004870 0.183839 0.683252 0.000000 0.000000 0.000000 0.148472
93027 NaN 46.290230 1.380040 7.945115 7.235223 0.274338 11.797178 19.396081 0.955456 0.000000 ... 0.131225 0.653965 0.481823 0.026500 0.208089 0.634156 0.000000 0.019312 0.000000 0.125825
93028 NaN 48.117886 0.149082 8.696416 5.671712 0.169030 13.621192 20.402754 1.625494 0.058249 ... 0.125932 0.684517 0.551743 0.128591 0.048722 0.597250 0.000000 0.116397 0.000000 0.083585
93029 NaN 46.544554 0.287509 7.870030 6.250091 0.117071 12.650849 19.429830 0.000000 0.135432 ... 0.162218 0.623032 0.485826 -0.043900 0.249511 0.639871 0.000000 0.000000 0.000000 0.155748
93030 NaN 45.316298 0.119567 7.955299 6.887216 0.233471 11.919362 19.708412 0.945937 0.133037 ... 0.124045 0.687473 0.514851 0.084473 0.144554 0.623202 0.000000 0.071634 0.000000 0.092467

14067 rows × 86 columns

/home/docs/checkouts/readthedocs.org/user_builds/mineralml/conda/stable/lib/python3.9/site-packages/ternary/plotting.py:148: UserWarning: No data for colormapping provided via 'c'. Parameters 'vmin', 'vmax' will be ignored
  ax.scatter(xs, ys, vmin=vmin, vmax=vmax, **kwargs)
../_images/examples_mineralML_mapping_20_2.png
[12]:
# Use OxideClassifier to examine at the component space.
oxs_comp = mm.OxideClassifier(oxs).calculate_components()
display(oxs_comp)

# Use OxideClassifier to plot up these data.
fig = mm.OxideClassifier(oxs).plot()
SiO2 TiO2 Al2O3 FeOt MnO MgO CaO Na2O K2O Cr2O3 ... Cation_Sum A_site A_site_expanded B_site A_B_site Fe_Ti Fe3_prop XR2 XR3 XTi
596 14.170745 0.458430 47.168928 17.851108 0.157325 8.807434 2.364795 1.613537 0.231962 0.909729 ... 3.0 0.801846 0.805654 1.619091 2.424745 0.436489 0.000000 0.332263 0.663672 0.004065
597 0.000000 0.000000 59.577095 22.761509 0.261160 16.543655 0.178530 0.000000 0.000000 0.596073 ... 3.0 0.989221 0.995001 2.000000 2.995001 0.497456 0.307035 0.332221 0.667779 0.000000
598 0.328607 0.192199 60.074062 22.531151 0.000000 16.206175 0.000000 0.404589 0.000000 1.762033 ... 3.0 0.971775 0.971775 1.999551 2.971326 0.489140 0.280194 0.327051 0.671696 0.001254
599 0.419032 0.000000 59.597162 20.757558 0.000000 16.481142 0.000000 0.094932 0.114364 1.412415 ... 3.0 0.993664 0.993664 1.986631 2.980295 0.456697 0.239540 0.333411 0.666589 0.000000
879 0.000000 0.000000 58.807763 21.683161 0.131220 15.814531 0.000000 0.445707 0.113306 0.450210 ... 3.0 0.943236 0.946200 2.026900 2.973100 0.483592 0.349607 0.318254 0.681746 0.000000
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
92992 0.000000 0.199933 61.268541 19.730463 0.777305 16.862860 0.416785 0.532657 0.209819 1.072017 ... 3.0 0.909033 0.925878 2.029424 2.955302 0.426036 0.370311 0.313294 0.685404 0.001302
92993 0.000000 0.000000 58.986714 21.457833 0.307136 14.984843 0.000000 0.000000 0.000000 0.888524 ... 3.0 0.992954 1.000000 2.000000 3.000000 0.486031 0.201826 0.333333 0.666667 0.000000
92994 0.000000 0.326008 59.845682 20.725138 0.091979 16.190988 0.066551 0.394945 0.127746 0.985187 ... 3.0 0.953691 0.955739 2.017969 2.973708 0.462154 0.299782 0.321396 0.676435 0.002168
92995 5.724564 0.254216 55.985948 19.883002 0.000000 15.163671 0.563598 1.013702 0.281037 1.044170 ... 3.0 1.017350 1.017350 1.756704 2.774054 0.439204 0.016451 0.366738 0.631462 0.001800
92999 0.000000 0.000000 61.128154 23.235195 0.000000 16.418883 0.084923 0.164328 0.299144 1.515729 ... 3.0 0.962063 0.962063 2.017811 2.979874 0.494272 0.313183 0.322854 0.677146 0.000000

1902 rows × 70 columns

/home/docs/checkouts/readthedocs.org/user_builds/mineralml/conda/stable/lib/python3.9/site-packages/ternary/plotting.py:148: UserWarning: No data for colormapping provided via 'c'. Parameters 'vmin', 'vmax' will be ignored
  ax.scatter(xs, ys, vmin=vmin, vmax=vmax, **kwargs)
../_images/examples_mineralML_mapping_21_2.png
../_images/examples_mineralML_mapping_21_3.png

You might note that the structure of these three ...Classifier classes is identical. That is intentional! mm.FeldsparClassifier, mm.PyroxeneClassifier, and mm.OxideClassifier all have calculate_components and plot methods embedded.

5. Plot chemical variation maps

We know the mineralogy now. What if you now want to inspect the chemical variation within the individual crystals? Pull the component maps created for each sample and plot this up with mm.plot_component_composite.

This function currently does this calculation for feldspars, pyroxenes, olivines, and amphibole. This can easily be expanded with all the stoichiometric mineral functions. Here, I will just show this for these common igneous phases.

[13]:
# Inspect what’s available:
print(sorted(output["component_maps"].keys()))

#  Plot map highlighting internal compositional variation
fig = mm.plot_component_composite(output, # specify output from above
                                  title="09g3", # optionally add a title to this plot
                                  phases=['Plagioclase', 'Clinopyroxene', 'Orthopyroxene', 'Oxide', 'Olivine', 'Glass'], # phases of interest
                                  smooth_sigma=0.25, # add a Gaussian blur to smooth compositional data, usually turned off.
                                  scalebar_um=50, # define size of scalebar desired, in microns
                                  pixel_size_um=2, # define size of each pixel of scalebar, in microns
                                  scalebar_loc='upper right', # specify location for scalebar
                                  scalebar_col='black', # specify color for scalebar
                                  )

['Clinopyroxene.En', 'Clinopyroxene.Fs', 'Clinopyroxene.Wo', 'Feldspar.Ab', 'Feldspar.An', 'Feldspar.Or', 'Orthopyroxene.En', 'Orthopyroxene.Fs', 'Orthopyroxene.Wo']
../_images/examples_mineralML_mapping_24_1.png

One could alternatively use all the functions within mineralML.mapping to do these same things, in a more stepwise manner. Look through the documentation if you would like to use individual bits of this code.