# Buggy code
def align_zero_loss_peak(
    self,
    calibrate=True,
    also_align=[],
    print_stats=True,
    subpixel=True,
    mask=None,
    signal_range=None,
    show_progressbar=None,
    **kwargs,
):
    """Align the zero-loss peak.

    This function first aligns the spectra using the result of
    `estimate_zero_loss_peak_centre` and afterward, if subpixel is True,
    proceeds to align with subpixel accuracy using `align1D`. The offset
    is automatically correct if `calibrate` is True.

    Parameters
    ----------
    calibrate : bool
        If True, set the offset of the spectral axis so that the
        zero-loss peak is at position zero.
    also_align : list of signals
        A list containing other spectra of identical dimensions to
        align using the shifts applied to the current spectrum.
        If `calibrate` is True, the calibration is also applied to
        the spectra in the list.
    print_stats : bool
        If True, print summary statistics of the ZLP maximum before
        the aligment.
    subpixel : bool
        If True, perform the alignment with subpixel accuracy
        using cross-correlation.
    mask : Signal1D of bool data type.
        It must have signal_dimension = 0 and navigation_shape equal to the
        current signal. Where mask is True the shift is not computed
        and set to nan.
    signal_range : tuple of integers, tuple of floats. Optional
        Will only search for the ZLP within the signal_range. If given
        in integers, the range will be in index values. If given floats,
        the range will be in spectrum values. Useful if there are features
        in the spectrum which are more intense than the ZLP.
        Default is searching in the whole signal.
    show_progressbar : None or bool
        If True, display a progress bar. If None the default is set in
        `preferences`.

    Examples
    --------
    >>> s_ll = hs.signals.EELSSpectrum(np.zeros(1000))
    >>> s_ll.data[100] = 100
    >>> s_ll.align_zero_loss_peak()

    Aligning both the lowloss signal and another signal
    >>> s = hs.signals.EELSSpectrum(np.range(1000))
    >>> s_ll.align_zero_loss_peak(also_align=[s])

    Aligning within a narrow range of the lowloss signal
    >>> s_ll.align_zero_loss_peak(signal_range=(-10.,10.))


    See Also
    --------
    estimate_zero_loss_peak_centre, align1D, estimate_shift1D.

    Notes
    -----
    Any extra keyword arguments are passed to `align1D`. For
    more information read its docstring.

    """
    signal_range = signal_range_from_roi(signal_range)

    def substract_from_offset(value, signals):
        if isinstance(value, da.Array):
            value = value.compute()
        for signal in signals:
            signal.axes_manager[-1].offset -= value

    def estimate_zero_loss_peak_centre(s, mask, signal_range):
        if signal_range:
            zlpc = s.isig[
                signal_range[0] : signal_range[1]
            ].estimate_zero_loss_peak_centre(mask=mask)
        else:
            zlpc = s.estimate_zero_loss_peak_centre(mask=mask)
        return zlpc

    zlpc = estimate_zero_loss_peak_centre(self, mask, signal_range)
    mean_ = without_nans(zlpc.data).mean()
    if print_stats is True:
        print()
        print(underline("Initial ZLP position statistics"))
        zlpc.print_summary_statistics()

    for signal in also_align + [self]:
        signal.shift1D(-zlpc.data + mean_, show_progressbar=show_progressbar)

    if calibrate is True:
        zlpc = estimate_zero_loss_peak_centre(self, mask, signal_range)
        substract_from_offset(without_nans(zlpc.data).mean(), also_align + [self])

    if subpixel is False:
        return
    left, right = -3.0, 3.0
    if calibrate is False:
        mean_ = without_nans(
            estimate_zero_loss_peak_centre(self, mask, signal_range).data
        ).mean()
        left += mean_
        right += mean_

    left = (
        left if left > self.axes_manager[-1].axis[0] else self.axes_manager[-1].axis[0]
    )
    right = (
        right
        if right < self.axes_manager[-1].axis[-1]
        else self.axes_manager[-1].axis[-1]
    )
    if self.axes_manager.navigation_size > 1:
        self.align1D(
            left,
            right,
            also_align=also_align,
            show_progressbar=show_progressbar,
            **kwargs,
        )
    zlpc = self.estimate_zero_loss_peak_centre(mask=mask)
    if calibrate is True:
        substract_from_offset(without_nans(zlpc.data).mean(), also_align + [self])


# Traceback (IndexError)
s
<LazyEELSSpectrum, title: EELS Spectrum Image 0eV, dimensions: (3, 3|2048)>
s.align_zero_loss_peak(True) # Or False
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-4-8925d1fde6ab> in <module>()
----> 1 s.align_zero_loss_peak(True) # or False

c:\users\thomasaar\documents\hyperspy\hyperspy\_signals\eels.py in align_zero_loss_peak(self, calibrate, also_align, print_stats, subpixel, mask, signal_range, show_progressbar, **kwargs)
266
267         zlpc = estimate_zero_loss_peak_centre(self, mask, signal_range)
--> 268         mean_ = without_nans(zlpc.data).mean()
269         if print_stats is True:
270             print()

c:\users\thomasaar\documents\hyperspy\hyperspy\misc\utils.py in without_nans(data)
756
757 def without_nans(data):
--> 758     return data[~np.isnan(data)]
759
760

C:\Users\thomasaar\AppData\Local\Continuum\Anaconda3\lib\site-packages\dask\array\core.py in __getitem__(self, index)
1239             return self
1240
-> 1241         dsk, chunks = slice_array(out, self.name, self.chunks, index)
1242
1243         dsk2 = sharedict.merge(self.dask, (out, dsk))

C:\Users\thomasaar\AppData\Local\Continuum\Anaconda3\lib\site-packages\dask\array\slicing.py in slice_array(out_name, in_name, blockdims, index)
137
138     # Pass down to next function
--> 139     dsk_out, bd_out = slice_with_newaxes(out_name, in_name, blockdims, index)
140
141     bd_out = tuple(map(tuple, bd_out))

C:\Users\thomasaar\AppData\Local\Continuum\Anaconda3\lib\site-packages\dask\array\slicing.py in slice_with_newaxes(out_name, in_name, blockdims, index)
159
160     # Pass down and do work
--> 161     dsk, blockdims2 = slice_wrap_lists(out_name, in_name, blockdims, index2)
162
163     if where_none:

C:\Users\thomasaar\AppData\Local\Continuum\Anaconda3\lib\site-packages\dask\array\slicing.py in slice_wrap_lists(out_name, in_name, blockdims, index)
200         raise IndexError("Too many indices for array")
201     for bd, i in zip(blockdims, index):
--> 202         check_index(i, sum(bd))
203
204     # Change indices like -1 to 9

C:\Users\thomasaar\AppData\Local\Continuum\Anaconda3\lib\site-packages\dask\array\slicing.py in check_index(ind, dimension)
711         x = np.array(ind)
712         if (x >= dimension).any() or (x <= -dimension).any():
--> 713             raise IndexError("Index out of bounds %s" % dimension)
714     elif isinstance(ind, slice):
715         return

IndexError: Index out of bounds 200

# Fixed code
def align_zero_loss_peak(
    self,
    calibrate=True,
    also_align=[],
    print_stats=True,
    subpixel=True,
    mask=None,
    signal_range=None,
    show_progressbar=None,
    **kwargs,
):
    """Align the zero-loss peak.

    This function first aligns the spectra using the result of
    `estimate_zero_loss_peak_centre` and afterward, if subpixel is True,
    proceeds to align with subpixel accuracy using `align1D`. The offset
    is automatically correct if `calibrate` is True.

    Parameters
    ----------
    calibrate : bool
        If True, set the offset of the spectral axis so that the
        zero-loss peak is at position zero.
    also_align : list of signals
        A list containing other spectra of identical dimensions to
        align using the shifts applied to the current spectrum.
        If `calibrate` is True, the calibration is also applied to
        the spectra in the list.
    print_stats : bool
        If True, print summary statistics of the ZLP maximum before
        the aligment.
    subpixel : bool
        If True, perform the alignment with subpixel accuracy
        using cross-correlation.
    mask : Signal1D of bool data type.
        It must have signal_dimension = 0 and navigation_shape equal to the
        current signal. Where mask is True the shift is not computed
        and set to nan.
    signal_range : tuple of integers, tuple of floats. Optional
        Will only search for the ZLP within the signal_range. If given
        in integers, the range will be in index values. If given floats,
        the range will be in spectrum values. Useful if there are features
        in the spectrum which are more intense than the ZLP.
        Default is searching in the whole signal.
    show_progressbar : None or bool
        If True, display a progress bar. If None the default is set in
        `preferences`.

    Examples
    --------
    >>> s_ll = hs.signals.EELSSpectrum(np.zeros(1000))
    >>> s_ll.data[100] = 100
    >>> s_ll.align_zero_loss_peak()

    Aligning both the lowloss signal and another signal
    >>> s = hs.signals.EELSSpectrum(np.range(1000))
    >>> s_ll.align_zero_loss_peak(also_align=[s])

    Aligning within a narrow range of the lowloss signal
    >>> s_ll.align_zero_loss_peak(signal_range=(-10.,10.))


    See Also
    --------
    estimate_zero_loss_peak_centre, align1D, estimate_shift1D.

    Notes
    -----
    Any extra keyword arguments are passed to `align1D`. For
    more information read its docstring.

    """
    signal_range = signal_range_from_roi(signal_range)

    def substract_from_offset(value, signals):
        if isinstance(value, da.Array):
            value = value.compute()
        for signal in signals:
            signal.axes_manager[-1].offset -= value

    def estimate_zero_loss_peak_centre(s, mask, signal_range):
        if signal_range:
            zlpc = s.isig[
                signal_range[0] : signal_range[1]
            ].estimate_zero_loss_peak_centre(mask=mask)
        else:
            zlpc = s.estimate_zero_loss_peak_centre(mask=mask)
        return zlpc

    zlpc = estimate_zero_loss_peak_centre(self, mask=mask, signal_range=signal_range)

    mean_ = np.nanmean(zlpc.data)

    if print_stats is True:
        print()
        print(underline("Initial ZLP position statistics"))
        zlpc.print_summary_statistics()

    for signal in also_align + [self]:
        shift_array = -zlpc.data + mean_
        if zlpc._lazy:
            shift_array = shift_array.compute()
        signal.shift1D(shift_array, show_progressbar=show_progressbar)

    if calibrate is True:
        zlpc = estimate_zero_loss_peak_centre(
            self, mask=mask, signal_range=signal_range
        )
        substract_from_offset(np.nanmean(zlpc.data), also_align + [self])

    if subpixel is False:
        return
    left, right = -3.0, 3.0
    if calibrate is False:
        mean_ = np.nanmean(
            estimate_zero_loss_peak_centre(self, mask, signal_range).data
        )
        left += mean_
        right += mean_

    left = (
        left if left > self.axes_manager[-1].axis[0] else self.axes_manager[-1].axis[0]
    )
    right = (
        right
        if right < self.axes_manager[-1].axis[-1]
        else self.axes_manager[-1].axis[-1]
    )

    if self.axes_manager.navigation_size > 1:
        self.align1D(
            left,
            right,
            also_align=also_align,
            show_progressbar=show_progressbar,
            mask=mask,
            **kwargs,
        )
    if calibrate is True:
        zlpc = estimate_zero_loss_peak_centre(
            self, mask=mask, signal_range=signal_range
        )
        substract_from_offset(np.nanmean(zlpc.data), also_align + [self])