Project: s41467-024-47447-6 | Function: intensity_profiles (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Peak intensity profiling algorithm that extracts and tracks intensity changes of specific spectral features over time by finding local maxima within defined windows for operando spectroscopy analysis

**KEY TERMS:** {
  "window_indices": "spectral region around target peak frequency",
  "local_maxima_indices": "indices of local intensity maxima",
  "max_intensities_dict": "tracking maximum intensities across measurements",
  "argrelextrema": "relative extrema detection algorithm",
  "peak": "target wavenumber for intensity tracking"
}

**CONTEXT CODE:**     subtracted_spectra_dict = copy.deepcopy(spectra_dict)

    # iterate over the spectra in the dictionary
    for spectrum_number, spectrum in spectra_dict.items():
        # Set spectrum type
        spectrum_type = "AB"
        if background:
            spectrum_type = "ScSm"

        # Ensure the spectra are the same size
        if len(spectrum[spectrum_type]) == len(spectrum_to_subtract[spectrum_type]):
            # subtract the spectrum
            subtracted_spectrum = spectrum[spectrum_type] - spectrum_to_subtract[spectrum_type]

            # Update the subtracted spectrum in the subtracted_spectra_dict
            subtracted_spectra_dict[spectrum_number]["AB"] = subtracted_spectrum
        else:
            print(f"Spectrum sizes do not match for spectrum number: {spectrum_number}. Skipping subtraction.")

    return subtracted_spectra_dict



def plot_spectra(spectra_dict, single_channel=False):
    # create a new figure
    plt.figure()

    # check what spectrum type is wanted
    spectrum_type = "AB"

    if single_channel:
        spectrum_type = "ScSm"

    # iterate over the spectra in the dictionary
    for filename, spectrum in spectra_dict.items():
        # get the x-values and y-values
        # here we're assuming that 'AB' block exists in the file and it is what we want to plot
        x_values = spectrum.get_range(spectrum_type)
        y_values = spectrum[spectrum_type][0:len(x_values)]

        # plot the spectrum
        # plt.plot(x_values, y_values, label=filename)
        plt.plot(x_values, y_values)

    # add a legend
    # plt.legend()

    # show the plot
    plt.show()

def intensity_profiles(spectra_dict, peaks, window=16, local_max=True):
    # MASKED: Peak intensity profiling algorithm that extracts and tracks intensity changes of specific spectral features over time by finding local maxima within defined windows for operando spectroscopy analysis
    raise NotImplementedError("This function is masked for testing purposes.")

def plot_intensity_profiles(intensity_profiles, times=None):
    # Create a figure
    plt.figure()

    # Iterate over all peaks in the intensity profiles
    for peak in set(peak for sublist in intensity_profiles.values() for peak in sublist.keys()):
        # Get the spectrum numbers and intensities for this peak
        spectrum_numbers = [spectrum_number for spectrum_number in intensity_profiles.keys() if peak in intensity_profiles[spectrum_number]]
        intensities = [intensity_profiles[spectrum_number][peak][1] for spectrum_number in spectrum_numbers]

        # Set x values either to spectrum number or time in min
        if times is None:
            x_values = spectrum_numbers
            title = "Intensity of Local Maxima over Spectrum Number"
            x_label = "Spectrum Number"
        
        else:
            x_values = [times[spectrum_number] for spectrum_number in spectrum_numbers]
            title = "Intensity of Local Maxima over Time (min)"
            x_label = "Time (min)"

        # Create a scatter plot of the intensities over spectrum number for this peak
        plt.scatter(x_values, intensities, label=f'Peak at {peak}')

    # Add a legend, title, and labels
    plt.legend()
    plt.title(title)
    plt.xlabel(x_label)
    plt.ylabel("Intensity (a.u.)")

    # Display the plot
    plt.show()

def peak_shifts(local_maxima_dict):
    # Create an empty dictionary to hold the peak shifts
    peak_shift_dict = {}

    # Iterate over all peaks in the local maxima dictionary
    for peak in set(peak for sublist in local_maxima_dict.values() for peak in sublist.keys()):
        # Create an empty list to hold the peak shifts for this peak
        peak_shifts = []

        reference_position = None  # Initialize the reference position as None

        # Iterate over all spectra
        for spectrum_number, spectrum_peaks in local_maxima_dict.items():
            # Check if the peak exists in the inner dictionary
            if peak in spectrum_peaks:
                # Use the first available peak position as the reference position
                if reference_position is None:
                    reference_position = spectrum_peaks[peak][0]

                # Calculate the peak shift for this spectrum
                peak_position = spectrum_peaks[peak][0]
                peak_shift = peak_position - reference_position

                # Add the peak shift to the list
                peak_shifts.append(peak_shift)

        # Add the list of peak shifts for this peak to the dictionary
        peak_shift_dict[peak] = peak_shifts

    return peak_shift_dict

def plot_peak_shifts(peak_shift_dict):
    # Iterate over all peaks in the peak shift dictionary
    for peak, peak_shifts in peak_shift_dict.items():
        # Create a scatter plot of the peak shifts over the spectrum number
        plt.scatter(range(len(peak_shifts)), peak_shifts, label=f'Peak at {peak}')

    # Add a legend, title, and labels
    plt.legend()
    plt.title("Peak Shifts over Spectrum Number")
    plt.xlabel("Spectrum Number")
    plt.ylabel("Peak Shift")

    # Display the plot
    plt.show()


def normalize_intensity_profiles(intensity_profiles, normalization='min_max'):
    # MASKED: Multi-method intensity normalization algorithm supporting min-max scaling, maximum normalization, and custom reference normalization for comparative operando spectroscopy analysis
    raise NotImplementedError("This function is masked for testing purposes.")

def times_relative(spectra_dict):
    times_relative = {}

    # Bruker format is 13:40:18.889 (GMT+0) // timezone need to be omitted
    start_time_str = spectra_dict[0]['ScSm Data Parameter']['TIM'].split(" ")[0]
    start_time = datetime.strptime(start_time_str, "%H:%M:%S.%f")

    for spectrum_number, spectrum in spectra_dict.items():
        # Same as above, timezone need to be omitted and str converted
        spectrum_time_str = spectrum['ScSm Data Parameter']['TIM'].split(" ")[0]
        spectrum_time = datetime.strptime(spectrum_time_str, "%H:%M:%S.%f")



Complete the function implementation replacing "raise NotImplementedError".