# Two Gaussian curve alignment¶

This notebook showcases how `msalign` performs when dealing with multiple curves in the signal. The algorithm performs pretty well when aliging clean and noisy data, especially when the ratio of the two curves is the same (or very similar)

The algoritm is a little less capable when dealing with two curves and the alignment is performed towards the smaller curve.

``````import numpy as np
from scipy import signal
from scipy.ndimage import shift
import matplotlib.pyplot as plt
from msalign import Aligner
from msalign.utilities import find_nearest_index

plt.style.use('ggplot')
``````

# Utility functions¶

First, let's make a couple of functions that will generate data for us, as well as, show the results

``````def overlay_plot(ax, x, array, peak):
"""Generate overlay plot, showing each signal and the alignment peak(s)"""
for i, y in enumerate(array):
y = (y / y.max()) + (i * 0.2)
ax.plot(x, y, lw=3)
ax.axes.get_yaxis().set_visible(False)
ax.set_xlabel("Index", fontsize=18)
ax.set_xlim((x, x[-1]))
ax.vlines(peak, *ax.get_ylim())

def plot_peak(ax, x, y, peak, window=100):
peak_idx = find_nearest_index(x, peak)
_x = x[peak_idx-window:peak_idx+window]
_y = y[peak_idx-window:peak_idx+window]
ax.plot(_x, _y)

ax.axes.get_yaxis().set_visible(False)
ax.set_xlim((_x, _x[-1]))
ax.vlines(peak, *ax.get_ylim())

def zoom_plot(axs, x, array, aligned_array, peaks):
for i, y in enumerate(array):
for j, peak in enumerate(peaks):
plot_peak(axs[0, j], x, y, peak)

for i, y in enumerate(aligned_array):
for j, peak in enumerate(peaks):
plot_peak(axs[1, j], x, y, peak)
``````

# Alignment of the mass spectrometry example¶

Here is the example used in the MATLAB documentation. Here, the dataset contains 8 signals that differ from each other a little. The alignment is performed by using 4 individual peaks that are common (or mostly common) between the signals

In first instance, we simply align the signals (without rescaling `only_shift=True`). As you can see, the alignment did relatively good job of shifting each signal near its correct position, but 2/3 of the signals could be slightly improved.

``````# load data
filename = r"D:\GitHub\msalign\example_data\msalign_test_data.csv"

data = np.genfromtxt(filename, delimiter=",")
x = data[1:, 0]
array = data[1:, 1:].T
peaks = [3991.4, 4598, 7964, 9160]
weights = [60, 100, 60, 100]

# instantiate aligner object
aligner = Aligner(
x,
array,
peaks,
weights=weights,
return_shifts=True,
align_by_index=True,
only_shift=True,
method="pchip",
)
aligner.run()
aligned_array, shifts_out = aligner.align()

# display before and after shifting
fig, ax = plt.subplots(nrows=2, ncols=1, figsize=(12, 10))
overlay_plot(ax, x, array, peaks)
overlay_plot(ax, x, aligned_array, peaks)

# zoom-in on each peak
fig, ax = plt.subplots(nrows=2, ncols=4, figsize=(12, 10))
zoom_plot(ax, x, array, aligned_array, peaks)
``````  # Alignment improvement¶

We can improve the alignment performance by switching the `only_shift` keyword parameter to `True`. This will ensure that each signal is shifted and rescaled which in practice means the `x` array is slightly altered on each iteration.

``````# instantiate aligner object
aligner = Aligner(
x,
array,
peaks,
weights=weights,
return_shifts=True,
align_by_index=True,
only_shift=False,
method="pchip",
)
aligner.run()
aligned_array, shifts_out = aligner.align()

# display before and after shifting
fig, ax = plt.subplots(nrows=2, ncols=1, figsize=(12, 10))
overlay_plot(ax, x, array, peaks)
overlay_plot(ax, x, aligned_array, peaks)

# zoom-in on each peak
fig, ax = plt.subplots(nrows=2, ncols=4, figsize=(12, 10))
zoom_plot(ax, x, array, aligned_array, peaks)
``````  