'How to synchronize to curves on matplotlib?

I have two curves that have their maximum roughly at the same time, but I'd like to match them exactly. The first function, maxind, determines where the maximum is on my temporal list. The 2nd function, synchro (where I need help), should synchronize them.

import numpy as np
import matplotlib.pyplot as plt


def generate_examples(shift=+1.0):
    # Generate two curves with different maximum
    xa = np.linspace(start=0, stop=6, num=1000)
    xb = np.linspace(start=0, stop=6, num=2000)

    ya = np.sin(xa)
    yb = np.sin(xb+shift)**3
    return (xa, ya), (xb, yb)


def maxind(T, L):
    n = len(L)
    M = - np.inf
    ind = 0
    for i in range(n):
        if L[i] > M:
            ind = i
            M = L[i]
    return ind, M, T[ind]


def synchro(xs, ys, TC, XT):
    indth, maxth, tth = maxind(xs, ys)
    indexp, maxexp, texp = maxind(TC, XT)
    L = []
    Tsync = []
    if indexp < indth:
        I = indth - indexp
        for i in range(I):
            xs.pop(0)
            ys.pop(0)
    else:
        I = indexp - indth
        for i in range(I, len(XT)):
            L.append(XT[i])
            Tsync.append(TC[i])

    return Tsync, L


(xa, ya), (xb, yb) = generate_examples(shift=+1.0)
Tsync, L = synchro(ys=xa, xs=ya, XT=xb, TC=yb)
fig, ax = plt.subplots()
ax.plot(xa, ya, color='blue', label='a')
ax.plot(xb, yb, color='red', ls=':', label='b')
ax.plot(L, Tsync, color='red', label='synced')

ax.legend()

I want to put the max of the red curve at the same point in time as the max of the blue curve.

img



Solution 1:[1]

I tried to construct a working example from the code you provided.

My solution uses numpy as this makes some things easier, for example you can use directly the argmax function instead of coding your own maxind function. See the comments in the code to understand the logic behind calculating the index shift for the curve b.

import numpy as np
import matplotlib.pyplot as plt


def generate_examples(shift=+1.0):
    # Generate two curves with different maximum
    xa = np.linspace(start=0, stop=6, num=1000)
    xb = np.linspace(start=0, stop=6, num=2000)
    # note that this is a general case where the two curves have different x values,
    # if we assume that they are the same some calculations would become simpler

    ya = np.sin(xa)
    yb = np.sin(xb+shift)**3  # shift maximum by defined value
    return (xa, ya), (xb, yb)


def calculate_shift(xa, ya, xb, yb):
    # Get (first) maximum for a and b
    iya = np.argmax(ya)
    iyb = np.argmax(yb)

    # Get the shift in terms of x
    dx = xb[iyb] - xa[iya]
    print('Shift', dx)  # should be roughly +/-1, as we build the examples this way

    # Find the shift in xb | find the index of xb which is closest to the shift in x
    xb0 = xb - xb[0]  # shift xb to ensure it starts with 0
    dxb = np.abs(dx) - xb0
    ixb = np.argmin(np.abs(dxb))

    # returned the signed shift in indices of xb
    return int(ixb * np.sign(dx))


def plot(xa, ya, xb, yb,
         ixb):
    fig, ax = plt.subplots()
    ax.plot(xa, ya, color='blue', label='a')
    ax.plot(xb, yb, color='red', ls=':', label='b')
    if ixb > 0:
        ax.plot(xb[:-ixb], yb[ixb:], color='red', label='b - shifted')
    else:
        ax.plot(xb[-ixb:], yb[:ixb], color='red', label='b - shifted')

    ax.legend()


(xa, ya), (xb, yb) = generate_examples(shift=-1.0)
ixb = calculate_shift(xa, ya, xb, yb)
plot(xa, ya, xb, yb, ixb)

Two Shifts

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1