class PhaseMatcher:
def __init__(self, exp_2theta, exp_int, cif_dict):
self.baseline_cfg = cfg.get("diffraction.baseline")
self.find_cfg = cfg.get("diffraction.find_peaks")
frames = {'exp':DataFrame({X_LABEL:exp_2theta, "int":exp_int}).set_index(X_LABEL)}
# x_min=min(exp_2theta)
# x_max=max(exp_2theta)
for name, cif in cif_dict.items():
engine = cif.new_engine(engine_name='pymatgen')
frames[name] = engine.get_pattern().set_index(X_LABEL)
self.cifs = cif_dict
self.frames = frames
def match_peaks(self):
import numpy as np
from ._utils import match_peaks
from ._utils import rows_to_2th
exp_frame = self.frames['exp']/self.frames['exp'].max()
exp_data = exp_frame['int']
exp_index = exp_frame.index
matchsets = {}
for name, cif in self.cifs.items():
peak_list = cif.get_peaks()
peak_idx = np.searchsorted(exp_index, [x for (x, y) in peak_list])
matches = match_peaks(exp_data, peak_idx)
matches = rows_to_2th(exp_index,matches)
matchsets[name] = matches
return matchsets
def find_peaks(self, interactive=False, ui=None,**interactive_kwargs):
self.find_baseline(interactive=interactive, ui=ui)
interactive = check_for_interactive(interactive, "find_peaks")
exp_corrected = self.frames['exp']['corrected'].to_numpy()
from ._utils import unpack_peaks
find_cfg = self.find_cfg
if not interactive:
return unpack_peaks(exp_corrected, "widths",**find_cfg)
from ..ui.peaks import PeakFinder
interactive_kwargs.setdefault('title', "Baseline-Corrected Peak Finder")
if interactive_kwargs['title'].startswith("+"):
suffix = interactive_kwargs['title'][1:]
interactive_kwargs['title'] = f"Baseline-Corrected Peak Finder\n{suffix}"
peak_finder = PeakFinder(exp_corrected, self.frames['exp'].index, cfg=find_cfg, ui=ui, **interactive_kwargs)
return peak_finder.main_loop()
def plot_matches(self, cif_name, ax=None, show=False):
import numpy as np
from matplotlib import pyplot as plt
from ._utils import plot_stick_at_x
matchset = self.match_peaks()[cif_name]
peak_list = self.cifs[cif_name].get_peaks()
peaks_x = np.array([x for (x, y) in peak_list])
peaks_y = np.array([y for (x, y) in peak_list])
if ax is None:
fig, ax = plt.gcf(), plt.gca()
else:
fig = ax.get_figure()
self.frames['exp'].plot(ax=ax)
for _, x_matches in matchset['matches']:
for x in x_matches:
plot_stick_at_x(x, peaks_x, peaks_y, ax=ax, color='g')
for missing in matchset['missing']:
plot_stick_at_x(missing, peaks_x, peaks_y, ax=ax, color='r')
if show:
plt.show()
return fig, ax
def find_baseline(self, interactive=False, ui=None):
interactive = check_for_interactive(interactive, "baseline")
from pybaselines import Baseline
exp_frame = self.frames['exp']
fitter = Baseline()
baseline_args = convert_baseline_cfg(self.baseline_cfg)
exp_int = exp_frame['int'].to_numpy()
baseline, _ = fitter.arpls(
exp_int,
**baseline_args
)
exp_frame['baseline'] = baseline
exp_frame['corrected'] = exp_int - baseline
if not interactive:
return
from ..ui.baseline import BaselineFinder
exp_2th = exp_frame.index.to_numpy()
finder = BaselineFinder(exp_int, exp_2th, cfg=self.baseline_cfg, ui=ui)
baseline, corrected = finder.main_loop()
exp_frame['baseline'] = baseline
exp_frame['corrected'] = corrected