locate_item_change

mdtools.numpy_helper_functions.locate_item_change(a, axis=-1, pin='after', discard_neg=None, change_type=None, rtol=1e-05, atol=1e-08, wrap=False, tfic=False, tlic=False, mic=False, amin=None, amax=None)[source]

Locate the positions of item changes in an array.

Get a boolean array of the same shape as a that indicates at which positions the elements of a change their value.

Todo

  • Probably, this function should be split into several smaller functions, e.g.

    • locate_item_change_start(a, axis, wrap, tfic, tlic, mic, amin, amax) corresponds to pin="before", change_type="None".

    • locate_item_change_start_pos(a, axis, wrap, tfic, tlic, mic, amin, amax) corresponds to pin="before", change_type="higher".

    • locate_item_change_start_neg(a, axis, wrap, tfic, tlic, mic, amin, amax) corresponds to pin="before", change_type="lower".

    • locate_item_change_end(a, axis, wrap, tfic, tlic, mic, amin, amax) corresponds to pin="after", change_type="None".

    • locate_item_change_end_pos(a, axis, wrap, tfic, tlic, mic, amin, amax) corresponds to pin="after", change_type="higher".

    • locate_item_change_end_neg(a, axis, wrap, tfic, tlic, mic, amin, amax) corresponds to pin="after", change_type="lower".

  • Write examples/test cases for mic=True.

Parameters:
  • a (array_like) – Array for which to get the positions where its elements change.

  • axis (int, optional) – The axis along which to search for changing elements. By default, the search is performed along the last axis.

  • pin ({"after", "before", "both"}) – Whether to return the last position "before" an item change or the first position "after" an item change. If set to "both", two output arrays will be returned, one for "before" and one for "after".

  • discard_neg ({None, "start", "end", "both"}, optional) – Whether to locate all item changes (None) or whether to discard item changes starting from a negative item ("start") or ending at a negative item ("end"). If set to "both", all item changes starting from or ending at a negative item will be discarded.

  • change_type ({None, "higher", "lower", "both"} or float or iterable of floats, optional) – Whether to locate all item changes without discriminating between different change types (None) or whether to locate only item changes to higher values ("higher") or to lower values ("lower"). If set to "both", two output arrays will be returned, one for "higher" and one for "lower". If pin is set to "both", too, a 2x2 tuple will be returned. The first index addresses pin, the second index addresses change_type. If change_type is a float, locate only item changes where the difference between the final and first item of the change is equal to the given float value within a certain tolerance. The tolerance is set by rtol and atol. If change_type is an iterable of floats, one output array for each given float will be returned.

  • rtol, atol (float, optional) – The relative and absolute tolerance for comparing floating point numbers. If change_type is a float, locate only those item changes that satisfy absolute((final_value - initial_value) - change_type) <= (atol + rtol * absolute(change_type)) (see numpy.isclose()). Has no effect if change_type is not a float.

  • wrap (bool, optional) – If True, the array a is assumed to be continued after the last element along axis by a itself, like when using periodic boundary conditions. Consequently, if the first and the last element of a do not match, this is interpreted as item change. In this case, the last element of a is considered to be the last position before an item change and the first element of a is considered to be the first position after an item change.

  • tfic (bool, optional) – Treat First Item as Change. If True, treat the first item as the first position after an item change. Has no effect if pin is set to "before". Must not be used together with discard_neg, change_type, wrap or mic.

  • tlic (bool, optional) – Treat Last Item as Change. If True, treat the last item as the last position before an item change. Has no effect if pin is set to "after". Must not be used together with discard_neg, change_type, wrap or mic.

  • mic (bool, optional) – If True, respect the Minimum Image Convention when calculating the difference between the elements of a. Has no effect if change_type is None.

  • amin, amax (scalar or array_like, optional) – The lower and upper bound(s) for the minimum image convention. See mdtools.numpy_helper_functions.diff_mic(). Has no effect if mic is False or change_type is None.

Returns:

  • item_change_before (numpy.ndarray) – Boolean array of the same shape as a. Elements that evaluate to True indicate the last positions before an item change in a. Can be used to index a and get its values right before the item change. Is not returned if pin is "after". If change_type is "both", item_change_before will be a tuple containing two boolean arrays of the same shape as a. The first array indicates the last positions before item changes to higher values, the second array indicates the last positions before item changes to lower values.

  • item_change_after (numpy.ndarray) – Boolean array of the same shape as a. Elements that evaluate to True indicate the first positions after an item change in a. Can be used to index a and get its values right after the item change. Is not returned if pin is "before". If change_type is "both", item_change_after will be a tuple containing two boolean arrays of the same shape as a. The first array indicates the first positions after item changes to higher values, the second array indicates the first positions after item changes to lower values.

See also

mdtools.numpy_helper_functions.item_change_ix()

Get the indices of item changes in an array

mdtools.dtrj.locate_trans()

Same function but specifically for discrete trajectories

Notes

To get the indices of the item changes, apply numpy.nonzero() to the output array(s) of this function. If you are only interested in the indices but not in the boolean arrays returned by this function, you can use mdtools.numpy_helper_functions.item_change_ix() instead.

If mic is True, this function uses mdtools.numpy_helper_functions.diff_mic() to calculate the difference between consecutive array elements. Otherwise, numpy.diff() is used.

Examples

>>> a = np.array([1, 2, 2, 3, 3, 3])
>>> before, after = mdt.nph.locate_item_change(a, pin="both")
>>> before
array([ True, False,  True, False, False, False])
>>> after
array([False,  True, False,  True, False, False])
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, pin="both", change_type="both"
... )
>>> before_type[0]  # Changes to higher values
array([ True, False,  True, False, False, False])
>>> before_type[1]  # Changes to lower values
array([False, False, False, False, False, False])
>>> np.array_equal(np.sum(before_type, axis=0), before)
True
>>> after_type[0]  # Changes to higher values
array([False,  True, False,  True, False, False])
>>> after_type[1]  # Changes to lower values
array([False, False, False, False, False, False])
>>> np.array_equal(np.sum(after_type, axis=0), after)
True
>>> mdt.nph.locate_item_change(a, pin="before", change_type=1)
array([ True, False,  True, False, False, False])
>>> before_type_float, after_type_float = mdt.nph.locate_item_change(
...     a, pin="both", change_type=(1, -1)
... )
>>> before_type_float[0]  # Changes where final-initial=1
array([ True, False,  True, False, False, False])
>>> before_type_float[1]  # Changes where final-initial=-1
array([False, False, False, False, False, False])
>>> after_type_float[0]  # Changes where final-initial=1
array([False,  True, False,  True, False, False])
>>> after_type_float[1]  # Changes where final-initial=-1
array([False, False, False, False, False, False])
>>> before_wrap, after_wrap = mdt.nph.locate_item_change(
...     a, pin="both", wrap=True
... )
>>> before_wrap
array([ True, False,  True, False, False,  True])
>>> after_wrap
array([ True,  True, False,  True, False, False])
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap[0]
array([ True, False,  True, False, False, False])
>>> before_type_wrap[1]
array([False, False, False, False, False,  True])
>>> np.array_equal(np.sum(before_type_wrap, axis=0), before_wrap)
True
>>> after_type_wrap[0]
array([False,  True, False,  True, False, False])
>>> after_type_wrap[1]
array([ True, False, False, False, False, False])
>>> np.array_equal(np.sum(after_type_wrap, axis=0), after_wrap)
True
>>> before_type_float_wrap, after_type_float_wrap = mdt.nph.locate_item_change(
...     a, pin="both", change_type=(1, -1), wrap=True
... )
>>> before_type_float_wrap[0]
array([ True, False,  True, False, False, False])
>>> before_type_float_wrap[1]
array([False, False, False, False, False, False])
>>> after_type_float_wrap[0]
array([False,  True, False,  True, False, False])
>>> after_type_float_wrap[1]
array([False, False, False, False, False, False])
>>> before_tfic, after_tfic = mdt.nph.locate_item_change(
...     a, pin="both", tfic=True
... )
>>> before_tfic
array([ True, False,  True, False, False, False])
>>> after_tfic
array([ True,  True, False,  True, False, False])
>>> before_tlic, after_tlic = mdt.nph.locate_item_change(
...     a, pin="both", tlic=True
... )
>>> before_tlic
array([ True, False,  True, False, False,  True])
>>> after_tlic
array([False,  True, False,  True, False, False])
>>> before_tfic_tlic, after_tfic_tlic = mdt.nph.locate_item_change(
...     a, pin="both", tfic=True, tlic=True
... )
>>> before_tfic_tlic
array([ True, False,  True, False, False,  True])
>>> after_tfic_tlic
array([ True,  True, False,  True, False, False])
>>> a = np.array([1, 2, 2, 3, 3, 3, 1])
>>> before, after = mdt.nph.locate_item_change(a, pin="both")
>>> before
array([ True, False,  True, False, False,  True, False])
>>> after
array([False,  True, False,  True, False, False,  True])
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, pin="both", change_type="both"
... )
>>> before_type[0]
array([ True, False,  True, False, False, False, False])
>>> before_type[1]
array([False, False, False, False, False,  True, False])
>>> np.array_equal(np.sum(before_type, axis=0), before)
True
>>> after_type[0]
array([False,  True, False,  True, False, False, False])
>>> after_type[1]
array([False, False, False, False, False, False,  True])
>>> np.array_equal(np.sum(after_type, axis=0), after)
True
>>> before_type_float, after_type_float = mdt.nph.locate_item_change(
...     a, pin="both", change_type=(1, -1)
... )
>>> before_type_float[0]
array([ True, False,  True, False, False, False, False])
>>> before_type_float[1]
array([False, False, False, False, False, False, False])
>>> after_type_float[0]
array([False,  True, False,  True, False, False, False])
>>> after_type_float[1]
array([False, False, False, False, False, False, False])
>>> before_wrap, after_wrap = mdt.nph.locate_item_change(
...     a, pin="both", wrap=True
... )
>>> before_wrap
array([ True, False,  True, False, False,  True, False])
>>> after_wrap
array([False,  True, False,  True, False, False,  True])
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap[0]
array([ True, False,  True, False, False, False, False])
>>> before_type_wrap[1]
array([False, False, False, False, False,  True, False])
>>> np.array_equal(np.sum(before_type_wrap, axis=0), before_wrap)
True
>>> after_type_wrap[0]
array([False,  True, False,  True, False, False, False])
>>> after_type_wrap[1]
array([False, False, False, False, False, False,  True])
>>> np.array_equal(np.sum(after_type_wrap, axis=0), after_wrap)
True
>>> before_type_float_wrap, after_type_float_wrap = mdt.nph.locate_item_change(
...     a, pin="both", change_type=(1, -1), wrap=True
... )
>>> before_type_float_wrap[0]
array([ True, False,  True, False, False, False, False])
>>> before_type_float_wrap[1]
array([False, False, False, False, False, False, False])
>>> after_type_float_wrap[0]
array([False,  True, False,  True, False, False, False])
>>> after_type_float_wrap[1]
array([False, False, False, False, False, False, False])
>>> before_tfic_tlic, after_tfic_tlic = mdt.nph.locate_item_change(
...     a, pin="both", tfic=True, tlic=True
... )
>>> before_tfic_tlic
array([ True, False,  True, False, False,  True,  True])
>>> after_tfic_tlic
array([ True,  True, False,  True, False, False,  True])

2-dimensional example:

>>> a = np.array([[1, 3, 3, 3],
...               [3, 1, 3, 3],
...               [3, 3, 1, 3]])
>>> ax = 0
>>> before, after = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both"
... )
>>> before
array([[ True,  True, False, False],
       [False,  True,  True, False],
       [False, False, False, False]])
>>> after
array([[False, False, False, False],
       [ True,  True, False, False],
       [False,  True,  True, False]])
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both"
... )
>>> before_type[0]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False, False, False]])
>>> before_type[1]
array([[False,  True, False, False],
       [False, False,  True, False],
       [False, False, False, False]])
>>> np.array_equal(np.sum(before_type, axis=0), before)
True
>>> after_type[0]
array([[False, False, False, False],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> after_type[1]
array([[False, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> np.array_equal(np.sum(after_type, axis=0), after)
True
>>> before_type_float, after_type_float = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type=(2, -2)
... )
>>> before_type_float[0]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False, False, False]])
>>> before_type_float[1]
array([[False,  True, False, False],
       [False, False,  True, False],
       [False, False, False, False]])
>>> after_type_float[0]
array([[False, False, False, False],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> after_type_float[1]
array([[False, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_wrap, after_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", wrap=True
... )
>>> before_wrap
array([[ True,  True, False, False],
       [False,  True,  True, False],
       [ True, False,  True, False]])
>>> after_wrap
array([[ True, False,  True, False],
       [ True,  True, False, False],
       [False,  True,  True, False]])
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap[0]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_type_wrap[1]
array([[False,  True, False, False],
       [False, False,  True, False],
       [ True, False, False, False]])
>>> np.array_equal(np.sum(before_type_wrap, axis=0), before_wrap)
True
>>> after_type_wrap[0]
array([[False, False,  True, False],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> after_type_wrap[1]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> np.array_equal(np.sum(after_type_wrap, axis=0), after_wrap)
True
>>> before_type_float_wrap, after_type_float_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type=(2, -2), wrap=True
... )
>>> before_type_float_wrap[0]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_type_float_wrap[1]
array([[False,  True, False, False],
       [False, False,  True, False],
       [ True, False, False, False]])
>>> after_type_float_wrap[0]
array([[False, False,  True, False],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> after_type_float_wrap[1]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_tfic_tlic, after_tfic_tlic = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", tfic=True, tlic=True
... )
>>> before_tfic_tlic
array([[ True,  True, False, False],
       [False,  True,  True, False],
       [ True,  True,  True,  True]])
>>> after_tfic_tlic
array([[ True,  True,  True,  True],
       [ True,  True, False, False],
       [False,  True,  True, False]])
>>> ax = 1
>>> before, after = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both"
... )
>>> before
array([[ True, False, False, False],
       [ True,  True, False, False],
       [False,  True,  True, False]])
>>> after
array([[False,  True, False, False],
       [False,  True,  True, False],
       [False, False,  True,  True]])
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both"
... )
>>> before_type[0]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_type[1]
array([[False, False, False, False],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> np.array_equal(np.sum(before_type, axis=0), before)
True
>>> after_type[0]
array([[False,  True, False, False],
       [False, False,  True, False],
       [False, False, False,  True]])
>>> after_type[1]
array([[False, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> np.array_equal(np.sum(after_type, axis=0), after)
True
>>> before_type_float, after_type_float = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type=(2, -2)
... )
>>> before_type_float[0]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_type_float[1]
array([[False, False, False, False],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> after_type_float[0]
array([[False,  True, False, False],
       [False, False,  True, False],
       [False, False, False,  True]])
>>> after_type_float[1]
array([[False, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_wrap, after_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", wrap=True
... )
>>> before_wrap
array([[ True, False, False,  True],
       [ True,  True, False, False],
       [False,  True,  True, False]])
>>> after_wrap
array([[ True,  True, False, False],
       [False,  True,  True, False],
       [False, False,  True,  True]])
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap[0]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_type_wrap[1]
array([[False, False, False,  True],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> np.array_equal(np.sum(before_type_wrap, axis=0), before_wrap)
True
>>> after_type_wrap[0]
array([[False,  True, False, False],
       [False, False,  True, False],
       [False, False, False,  True]])
>>> after_type_wrap[1]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> np.array_equal(np.sum(after_type_wrap, axis=0), after_wrap)
True
>>> before_type_float_wrap, after_type_float_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type=(2, -2), wrap=True
... )
>>> before_type_float_wrap[0]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_type_float_wrap[1]
array([[False, False, False,  True],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> after_type_float_wrap[0]
array([[False,  True, False, False],
       [False, False,  True, False],
       [False, False, False,  True]])
>>> after_type_float_wrap[1]
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_tfic_tlic, after_tfic_tlic = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", tfic=True, tlic=True
... )
>>> before_tfic_tlic
array([[ True, False, False,  True],
       [ True,  True, False,  True],
       [False,  True,  True,  True]])
>>> after_tfic_tlic
array([[ True,  True, False, False],
       [ True,  True,  True, False],
       [ True, False,  True,  True]])

3-dimensional example:

>>> a = np.array([[[1, 2, 2],
...                [2, 2, 1]],
...
...               [[2, 2, 1],
...                [1, 2, 2]]])
>>> ax = 0
>>> before, after = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both"
... )
>>> before
array([[[ True, False,  True],
        [ True, False,  True]],

       [[False, False, False],
        [False, False, False]]])
>>> after
array([[[False, False, False],
        [False, False, False]],

       [[ True, False,  True],
        [ True, False,  True]]])
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both"
... )
>>> before_type[0]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False, False],
        [False, False, False]]])
>>> before_type[1]
array([[[False, False,  True],
        [ True, False, False]],

       [[False, False, False],
        [False, False, False]]])
>>> np.array_equal(np.sum(before_type, axis=0), before)
True
>>> after_type[0]
array([[[False, False, False],
        [False, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_type[1]
array([[[False, False, False],
        [False, False, False]],

       [[False, False,  True],
        [ True, False, False]]])
>>> np.array_equal(np.sum(after_type, axis=0), after)
True
>>> before_type_float, after_type_float = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type=(1, -1)
... )
>>> before_type_float[0]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False, False],
        [False, False, False]]])
>>> before_type_float[1]
array([[[False, False,  True],
        [ True, False, False]],

       [[False, False, False],
        [False, False, False]]])
>>> after_type_float[0]
array([[[False, False, False],
        [False, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_type_float[1]
array([[[False, False, False],
        [False, False, False]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_wrap, after_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", wrap=True
... )
>>> before_wrap
array([[[ True, False,  True],
        [ True, False,  True]],

       [[ True, False,  True],
        [ True, False,  True]]])
>>> after_wrap
array([[[ True, False,  True],
        [ True, False,  True]],

       [[ True, False,  True],
        [ True, False,  True]]])
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap[0]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_type_wrap[1]
array([[[False, False,  True],
        [ True, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> np.array_equal(np.sum(before_type_wrap, axis=0), before_wrap)
True
>>> after_type_wrap[0]
array([[[False, False,  True],
        [ True, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_type_wrap[1]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> np.array_equal(np.sum(after_type_wrap, axis=0), after_wrap)
True
>>> before_type_float_wrap, after_type_float_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type=(1, -1), wrap=True
... )
>>> before_type_float_wrap[0]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_type_float_wrap[1]
array([[[False, False,  True],
        [ True, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_type_float_wrap[0]
array([[[False, False,  True],
        [ True, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_type_float_wrap[1]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_tfic_tlic, after_tfic_tlic = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", tfic=True, tlic=True
... )
>>> before_tfic_tlic
array([[[ True, False,  True],
        [ True, False,  True]],

       [[ True,  True,  True],
        [ True,  True,  True]]])
>>> after_tfic_tlic
array([[[ True,  True,  True],
        [ True,  True,  True]],

       [[ True, False,  True],
        [ True, False,  True]]])
>>> ax = 1
>>> before, after = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both"
... )
>>> before
array([[[ True, False,  True],
        [False, False, False]],

       [[ True, False,  True],
        [False, False, False]]])
>>> after
array([[[False, False, False],
        [ True, False,  True]],

       [[False, False, False],
        [ True, False,  True]]])
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both"
... )
>>> before_type[0]
array([[[ True, False, False],
        [False, False, False]],

       [[False, False,  True],
        [False, False, False]]])
>>> before_type[1]
array([[[False, False,  True],
        [False, False, False]],

       [[ True, False, False],
        [False, False, False]]])
>>> np.array_equal(np.sum(before_type, axis=0), before)
True
>>> after_type[0]
array([[[False, False, False],
        [ True, False, False]],

       [[False, False, False],
        [False, False,  True]]])
>>> after_type[1]
array([[[False, False, False],
        [False, False,  True]],

       [[False, False, False],
        [ True, False, False]]])
>>> np.array_equal(np.sum(after_type, axis=0), after)
True
>>> before_type_float, after_type_float = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type=(1, -1)
... )
>>> before_type_float[0]
array([[[ True, False, False],
        [False, False, False]],

       [[False, False,  True],
        [False, False, False]]])
>>> before_type_float[1]
array([[[False, False,  True],
        [False, False, False]],

       [[ True, False, False],
        [False, False, False]]])
>>> after_type_float[0]
array([[[False, False, False],
        [ True, False, False]],

       [[False, False, False],
        [False, False,  True]]])
>>> after_type_float[1]
array([[[False, False, False],
        [False, False,  True]],

       [[False, False, False],
        [ True, False, False]]])
>>> before_wrap, after_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", wrap=True
... )
>>> before_wrap
array([[[ True, False,  True],
        [ True, False,  True]],

       [[ True, False,  True],
        [ True, False,  True]]])
>>> after_wrap
array([[[ True, False,  True],
        [ True, False,  True]],

       [[ True, False,  True],
        [ True, False,  True]]])
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap[0]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_type_wrap[1]
array([[[False, False,  True],
        [ True, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> np.array_equal(np.sum(before_type_wrap, axis=0), before_wrap)
True
>>> after_type_wrap[0]
array([[[False, False,  True],
        [ True, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_type_wrap[1]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> np.array_equal(np.sum(after_type_wrap, axis=0), after_wrap)
True
>>> before_type_float_wrap, after_type_float_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type=(1, -1), wrap=True
... )
>>> before_type_float_wrap[0]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_type_float_wrap[1]
array([[[False, False,  True],
        [ True, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_type_float_wrap[0]
array([[[False, False,  True],
        [ True, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_type_float_wrap[1]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_tfic_tlic, after_tfic_tlic = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", tfic=True, tlic=True
... )
>>> before_tfic_tlic
array([[[ True, False,  True],
        [ True,  True,  True]],

       [[ True, False,  True],
        [ True,  True,  True]]])
>>> after_tfic_tlic
array([[[ True,  True,  True],
        [ True, False,  True]],

       [[ True,  True,  True],
        [ True, False,  True]]])
>>> ax = 2
>>> before, after = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both"
... )
>>> before
array([[[ True, False, False],
        [False,  True, False]],

       [[False,  True, False],
        [ True, False, False]]])
>>> after
array([[[False,  True, False],
        [False, False,  True]],

       [[False, False,  True],
        [False,  True, False]]])
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both"
... )
>>> before_type[0]
array([[[ True, False, False],
        [False, False, False]],

       [[False, False, False],
        [ True, False, False]]])
>>> before_type[1]
array([[[False, False, False],
        [False,  True, False]],

       [[False,  True, False],
        [False, False, False]]])
>>> np.array_equal(np.sum(before_type, axis=0), before)
True
>>> after_type[0]
array([[[False,  True, False],
        [False, False, False]],

       [[False, False, False],
        [False,  True, False]]])
>>> after_type[1]
array([[[False, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [False, False, False]]])
>>> np.array_equal(np.sum(after_type, axis=0), after)
True
>>> before_type_float, after_type_float = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type=(1, -1)
... )
>>> before_type_float[0]
array([[[ True, False, False],
        [False, False, False]],

       [[False, False, False],
        [ True, False, False]]])
>>> before_type_float[1]
array([[[False, False, False],
        [False,  True, False]],

       [[False,  True, False],
        [False, False, False]]])
>>> np.array_equal(np.sum(before_type, axis=0), before)
True
>>> after_type_float[0]
array([[[False,  True, False],
        [False, False, False]],

       [[False, False, False],
        [False,  True, False]]])
>>> after_type_float[1]
array([[[False, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [False, False, False]]])
>>> before_wrap, after_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", wrap=True
... )
>>> before_wrap
array([[[ True, False,  True],
        [False,  True,  True]],

       [[False,  True,  True],
        [ True, False,  True]]])
>>> after_wrap
array([[[ True,  True, False],
        [ True, False,  True]],

       [[ True, False,  True],
        [ True,  True, False]]])
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap[0]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_type_wrap[1]
array([[[False, False,  True],
        [False,  True, False]],

       [[False,  True, False],
        [False, False,  True]]])
>>> np.array_equal(np.sum(before_type_wrap, axis=0), before_wrap)
True
>>> after_type_wrap[0]
array([[[False,  True, False],
        [ True, False, False]],

       [[ True, False, False],
        [False,  True, False]]])
>>> after_type_wrap[1]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> np.array_equal(np.sum(after_type_wrap, axis=0), after_wrap)
True
>>> before_type_float_wrap, after_type_float_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type=(1, -1), wrap=True
... )
>>> before_type_float_wrap[0]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_type_float_wrap[1]
array([[[False, False,  True],
        [False,  True, False]],

       [[False,  True, False],
        [False, False,  True]]])
>>> np.array_equal(np.sum(before_type_wrap, axis=0), before_wrap)
True
>>> after_type_float_wrap[0]
array([[[False,  True, False],
        [ True, False, False]],

       [[ True, False, False],
        [False,  True, False]]])
>>> after_type_float_wrap[1]
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_tfic_tlic, after_tfic_tlic = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", tfic=True, tlic=True
... )
>>> before_tfic_tlic
array([[[ True, False,  True],
        [False,  True,  True]],

       [[False,  True,  True],
        [ True, False,  True]]])
>>> after_tfic_tlic
array([[[ True,  True, False],
        [ True, False,  True]],

       [[ True, False,  True],
        [ True,  True, False]]])

Examples for using discard_neg:

>>> a = np.array([ 1, -2, -2,  3,  3,  3])
>>> before_start, after_start = mdt.nph.locate_item_change(
...     a, pin="both", discard_neg="start"
... )
>>> before_start
array([ True, False, False, False, False, False])
>>> after_start
array([False,  True, False, False, False, False])
>>> before_end, after_end = mdt.nph.locate_item_change(
...     a, pin="both", discard_neg="end"
... )
>>> before_end
array([False, False,  True, False, False, False])
>>> after_end
array([False, False, False,  True, False, False])
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, pin="both", discard_neg="both"
... )
>>> before_both
array([False, False, False, False, False, False])
>>> after_both
array([False, False, False, False, False, False])
>>> before_start = mdt.nph.locate_item_change(
...     a, pin="before", discard_neg="start"
... )
>>> before_start
array([ True, False, False, False, False, False])
>>> after_end = mdt.nph.locate_item_change(
...     a, pin="after", discard_neg="end"
... )
>>> after_end
array([False, False, False,  True, False, False])
>>> before_end_type, after_end_type = mdt.nph.locate_item_change(
...     a, pin="both", discard_neg="end", change_type="both"
... )
>>> before_end_type[0]  # Changes to higher values
array([False, False,  True, False, False, False])
>>> before_end_type[1]  # Changes to lower values
array([False, False, False, False, False, False])
>>> after_end_type[0]  # Changes to higher values
array([False, False, False,  True, False, False])
>>> after_end_type[1]  # Changes to lower values
array([False, False, False, False, False, False])
>>> before_strt_wrap, after_strt_wrap = mdt.nph.locate_item_change(
...     a, pin="both", discard_neg="start", wrap=True
... )
>>> before_strt_wrap
array([ True, False, False, False, False,  True])
>>> after_strt_wrap
array([ True,  True, False, False, False, False])
>>> before_end_typ_w, after_end_typ_w = mdt.nph.locate_item_change(
...     a,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
...     wrap=True,
... )
>>> before_end_typ_w[0]  # Changes to higher values
array([False, False,  True, False, False, False])
>>> before_end_typ_w[1]  # Changes to lower values
array([False, False, False, False, False,  True])
>>> after_end_typ_w[0]  # Changes to higher values
array([False, False, False,  True, False, False])
>>> after_end_typ_w[1]  # Changes to lower values
array([ True, False, False, False, False, False])
>>> before_both_wrap, after_both_wrap = mdt.nph.locate_item_change(
...     a, pin="both", discard_neg="both", wrap=True
... )
>>> before_both_wrap
array([False, False, False, False, False,  True])
>>> after_both_wrap
array([ True, False, False, False, False, False])
>>> a = np.array([ 1, -2, -2,  3,  3,  3,  1])
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, pin="both", discard_neg="both"
... )
>>> before_both
array([False, False, False, False, False,  True, False])
>>> after_both
array([False, False, False, False, False, False,  True])
>>> before_end_type, after_end_type = mdt.nph.locate_item_change(
...     a, pin="both", discard_neg="end", change_type="both"
... )
>>> before_end_type[0]  # Changes to higher values
array([False, False,  True, False, False, False, False])
>>> before_end_type[1]  # Changes to lower values
array([False, False, False, False, False,  True, False])
>>> after_end_type[0]  # Changes to higher values
array([False, False, False,  True, False, False, False])
>>> after_end_type[1]  # Changes to lower values
array([False, False, False, False, False, False,  True])
>>> before_strt_wrap, after_strt_wrap = mdt.nph.locate_item_change(
...     a, pin="both", discard_neg="start", wrap=True
... )
>>> before_strt_wrap
array([ True, False, False, False, False,  True, False])
>>> after_strt_wrap
array([False,  True, False, False, False, False,  True])
>>> before_end_typ_w, after_end_typ_w = mdt.nph.locate_item_change(
...     a,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
...     wrap=True,
... )
>>> before_end_typ_w[0]  # Changes to higher values
array([False, False,  True, False, False, False, False])
>>> before_end_typ_w[1]  # Changes to lower values
array([False, False, False, False, False,  True, False])
>>> after_end_typ_w[0]  # Changes to higher values
array([False, False, False,  True, False, False, False])
>>> after_end_typ_w[1]  # Changes to lower values
array([False, False, False, False, False, False,  True])
>>> before_both_wrap, after_both_wrap = mdt.nph.locate_item_change(
...     a, pin="both", discard_neg="both", wrap=True
... )
>>> before_both_wrap
array([False, False, False, False, False,  True, False])
>>> after_both_wrap
array([False, False, False, False, False, False,  True])

2-dimensional example for using discard_neg:

>>> a = np.array([[-1,  3,  3,  3],
...               [ 3, -1,  3,  3],
...               [ 3,  3, -1,  3]])
>>> ax = 0
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both"
... )
>>> before_both
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> after_both
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> before_end_type, after_end_type = mdt.nph.locate_item_change(
...     a,
...     axis=ax,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
... )
>>> before_end_type[0]  # Changes to higher values
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False, False, False]])
>>> before_end_type[1]  # Changes to lower values
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> after_end_type[0]  # Changes to higher values
array([[False, False, False, False],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> after_end_type[1]  # Changes to lower values
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> before_strt_wrap, after_strt_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="start", wrap=True
... )
>>> before_strt_wrap
array([[False,  True, False, False],
       [False, False,  True, False],
       [ True, False, False, False]])
>>> after_strt_wrap
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_end_typ_w, after_end_typ_w = mdt.nph.locate_item_change(
...     a,
...     axis=ax,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
...     wrap=True,
... )
>>> before_end_typ_w[0]  # Changes to higher values
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_end_typ_w[1]  # Changes to lower values
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> after_end_typ_w[0]  # Changes to higher values
array([[False, False,  True, False],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> after_end_typ_w[1]  # Changes to lower values
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> before_both_wrap, after_both_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both", wrap=True
... )
>>> before_both_wrap
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> after_both_wrap
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> ax = 1
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both"
... )
>>> before_both
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> after_both
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> before_end_type, after_end_type = mdt.nph.locate_item_change(
...     a,
...     axis=ax,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
... )
>>> before_end_type[0]  # Changes to higher values
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_end_type[1]  # Changes to lower values
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> after_end_type[0]  # Changes to higher values
array([[False,  True, False, False],
       [False, False,  True, False],
       [False, False, False,  True]])
>>> after_end_type[1]  # Changes to lower values
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> before_strt_wrap, after_strt_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="start", wrap=True
... )
>>> before_strt_wrap
array([[False, False, False,  True],
       [ True, False, False, False],
       [False,  True, False, False]])
>>> after_strt_wrap
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_end_typ_w, after_end_typ_w = mdt.nph.locate_item_change(
...     a,
...     axis=ax,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
...     wrap=True,
... )
>>> before_end_typ_w[0]  # Changes to higher values
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]])
>>> before_end_typ_w[1]  # Changes to lower values
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> after_end_typ_w[0]  # Changes to higher values
array([[False,  True, False, False],
       [False, False,  True, False],
       [False, False, False,  True]])
>>> after_end_typ_w[1]  # Changes to lower values
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> before_both_wrap, after_both_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both", wrap=True
... )
>>> before_both_wrap
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])
>>> after_both_wrap
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False]])

3-dimensional example for using discard_neg:

>>> a = np.array([[[-1,  2,  2],
...                [ 2,  2,  1]],
...
...               [[ 2,  2,  1],
...                [-1,  2,  2]]])
>>> ax = 0
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both"
... )
>>> before_both
array([[[False, False,  True],
        [False, False,  True]],

       [[False, False, False],
        [False, False, False]]])
>>> after_both
array([[[False, False, False],
        [False, False, False]],

       [[False, False,  True],
        [False, False,  True]]])
>>> before_end_type, after_end_type = mdt.nph.locate_item_change(
...     a,
...     axis=ax,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
... )
>>> before_end_type[0]  # Changes to higher values
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False, False],
        [False, False, False]]])
>>> before_end_type[1]  # Changes to lower values
array([[[False, False,  True],
        [False, False, False]],

       [[False, False, False],
        [False, False, False]]])
>>> after_end_type[0]  # Changes to higher values
array([[[False, False, False],
        [False, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_end_type[1]  # Changes to lower values
array([[[False, False, False],
        [False, False, False]],

       [[False, False,  True],
        [False, False, False]]])
>>> before_strt_wrap, after_strt_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="start", wrap=True
... )
>>> before_strt_wrap
array([[[False, False,  True],
        [ True, False,  True]],

       [[ True, False,  True],
        [False, False,  True]]])
>>> after_strt_wrap
array([[[ True, False,  True],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False,  True]]])
>>> before_end_typ_w, after_end_typ_w = mdt.nph.locate_item_change(
...     a,
...     axis=ax,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
...     wrap=True,
... )
>>> before_end_typ_w[0]  # Changes to higher values
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_end_typ_w[1]  # Changes to lower values
array([[[False, False,  True],
        [False, False, False]],

       [[False, False, False],
        [False, False,  True]]])
>>> after_end_typ_w[0]  # Changes to higher values
array([[[False, False,  True],
        [ True, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_end_typ_w[1]  # Changes to lower values
array([[[False, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [False, False, False]]])
>>> before_both_wrap, after_both_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both", wrap=True
... )
>>> before_both_wrap
array([[[False, False,  True],
        [False, False,  True]],

       [[False, False,  True],
        [False, False,  True]]])
>>> after_both_wrap
array([[[False, False,  True],
        [False, False,  True]],

       [[False, False,  True],
        [False, False,  True]]])
>>> ax = 1
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both"
... )
>>> before_both
array([[[False, False,  True],
        [False, False, False]],

       [[False, False,  True],
        [False, False, False]]])
>>> after_both
array([[[False, False, False],
        [False, False,  True]],

       [[False, False, False],
        [False, False,  True]]])
>>> before_end_type, after_end_type = mdt.nph.locate_item_change(
...     a,
...     axis=ax,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
... )
>>> before_end_type[0]  # Changes to higher values
array([[[ True, False, False],
        [False, False, False]],

       [[False, False,  True],
        [False, False, False]]])
>>> before_end_type[1]  # Changes to lower values
array([[[False, False,  True],
        [False, False, False]],

       [[False, False, False],
        [False, False, False]]])
>>> after_end_type[0]  # Changes to higher values
array([[[False, False, False],
        [ True, False, False]],

       [[False, False, False],
        [False, False,  True]]])
>>> after_end_type[1]  # Changes to lower values
array([[[False, False, False],
        [False, False,  True]],

       [[False, False, False],
        [False, False, False]]])
>>> before_strt_wrap, after_strt_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="start", wrap=True
... )
>>> before_strt_wrap
array([[[False, False,  True],
        [ True, False,  True]],

       [[ True, False,  True],
        [False, False,  True]]])
>>> after_strt_wrap
array([[[ True, False,  True],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False,  True]]])
>>> before_end_typ_w, after_end_typ_w = mdt.nph.locate_item_change(
...     a,
...     axis=ax,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
...     wrap=True,
... )
>>> before_end_typ_w[0]  # Changes to higher values
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_end_typ_w[1]  # Changes to lower values
array([[[False, False,  True],
        [False, False, False]],

       [[False, False, False],
        [False, False,  True]]])
>>> after_end_typ_w[0]  # Changes to higher values
array([[[False, False,  True],
        [ True, False, False]],

       [[ True, False, False],
        [False, False,  True]]])
>>> after_end_typ_w[1]  # Changes to lower values
array([[[False, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [False, False, False]]])
>>> before_both_wrap, after_both_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both", wrap=True
... )
>>> before_both_wrap
array([[[False, False,  True],
        [False, False,  True]],

       [[False, False,  True],
        [False, False,  True]]])
>>> after_both_wrap
array([[[False, False,  True],
        [False, False,  True]],

       [[False, False,  True],
        [False, False,  True]]])
>>> ax = 2
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both"
... )
>>> before_both
array([[[False, False, False],
        [False,  True, False]],

       [[False,  True, False],
        [False, False, False]]])
>>> after_both
array([[[False, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [False, False, False]]])
>>> before_end_type, after_end_type = mdt.nph.locate_item_change(
...     a,
...     axis=ax,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
... )
>>> before_end_type[0]  # Changes to higher values
array([[[ True, False, False],
        [False, False, False]],

       [[False, False, False],
        [ True, False, False]]])
>>> before_end_type[1]  # Changes to lower values
array([[[False, False, False],
        [False,  True, False]],

       [[False,  True, False],
        [False, False, False]]])
>>> after_end_type[0]  # Changes to higher values
array([[[False,  True, False],
        [False, False, False]],

       [[False, False, False],
        [False,  True, False]]])
>>> after_end_type[1]  # Changes to lower values
array([[[False, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [False, False, False]]])
>>> before_strt_wrap, after_strt_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="start", wrap=True
... )
>>> before_strt_wrap
array([[[False, False,  True],
        [False,  True,  True]],

       [[False,  True,  True],
        [False, False,  True]]])
>>> after_strt_wrap
array([[[ True, False, False],
        [ True, False,  True]],

       [[ True, False,  True],
        [ True, False, False]]])
>>> before_end_typ_w, after_end_typ_w = mdt.nph.locate_item_change(
...     a,
...     axis=ax,
...     pin="both",
...     discard_neg="end",
...     change_type="both",
...     wrap=True,
... )
>>> before_end_typ_w[0]  # Changes to higher values
array([[[ True, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [ True, False, False]]])
>>> before_end_typ_w[1]  # Changes to lower values
array([[[False, False, False],
        [False,  True, False]],

       [[False,  True, False],
        [False, False, False]]])
>>> after_end_typ_w[0]  # Changes to higher values
array([[[False,  True, False],
        [ True, False, False]],

       [[ True, False, False],
        [False,  True, False]]])
>>> after_end_typ_w[1]  # Changes to lower values
array([[[False, False, False],
        [False, False,  True]],

       [[False, False,  True],
        [False, False, False]]])
>>> before_both_wrap, after_both_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both", wrap=True
... )
>>> before_both_wrap
array([[[False, False, False],
        [False,  True,  True]],

       [[False,  True,  True],
        [False, False, False]]])
>>> after_both_wrap
array([[[False, False, False],
        [ True, False,  True]],

       [[ True, False,  True],
        [False, False, False]]])

Edge cases:

>>> a = np.array([[1, 2, 2]])
>>> ax = 0
>>> before, after = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both"
... )
>>> before
array([[False, False, False]])
>>> after
array([[False, False, False]])
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both"
... )
>>> before_both
array([[False, False, False]])
>>> after_both
array([[False, False, False]])
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both"
... )
>>> before_type
(array([[False, False, False]]), array([[False, False, False]]))
>>> after_type
(array([[False, False, False]]), array([[False, False, False]]))
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap
(array([[False, False, False]]), array([[False, False, False]]))
>>> after_type_wrap
(array([[False, False, False]]), array([[False, False, False]]))
>>> mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", tfic=True, tlic=True
... )
(array([[ True,  True,  True]]), array([[ True,  True,  True]]))
>>> ax = 1
>>> before, after = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both"
... )
>>> before
array([[ True, False, False]])
>>> after
array([[False,  True, False]])
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both"
... )
>>> before_both
array([[ True, False, False]])
>>> after_both
array([[False,  True, False]])
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both"
... )
>>> before_type
(array([[ True, False, False]]), array([[False, False, False]]))
>>> after_type
(array([[False,  True, False]]), array([[False, False, False]]))
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap
(array([[ True, False, False]]), array([[False, False,  True]]))
>>> after_type_wrap
(array([[False,  True, False]]), array([[ True, False, False]]))
>>> mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", tfic=True, tlic=True
... )
(array([[ True, False,  True]]), array([[ True,  True, False]]))
>>> before_tfic_tlic, after_tfic_tlic = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", tfic=True, tlic=True
... )
>>> before_tfic_tlic
array([[ True, False,  True]])
>>> after_tfic_tlic
array([[ True,  True, False]])
>>> a = np.array([]).reshape(2,0)
>>> ax = 0
>>> before, after = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both"
... )
>>> before
array([], shape=(2, 0), dtype=bool)
>>> after
array([], shape=(2, 0), dtype=bool)
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both"
... )
>>> before_both
array([], shape=(2, 0), dtype=bool)
>>> after_both
array([], shape=(2, 0), dtype=bool)
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both"
... )
>>> before_type
(array([], shape=(2, 0), dtype=bool), array([], shape=(2, 0), dtype=bool))
>>> after_type
(array([], shape=(2, 0), dtype=bool), array([], shape=(2, 0), dtype=bool))
>>> before_wrap, after_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", wrap=True
... )
>>> before_wrap
array([], shape=(2, 0), dtype=bool)
>>> after_wrap
array([], shape=(2, 0), dtype=bool)
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap
(array([], shape=(2, 0), dtype=bool), array([], shape=(2, 0), dtype=bool))
>>> after_type_wrap
(array([], shape=(2, 0), dtype=bool), array([], shape=(2, 0), dtype=bool))
>>> before_tfic_tlic, after_tfic_tlic = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", tfic=True, tlic=True
... )
>>> before_tfic_tlic
array([], shape=(2, 0), dtype=bool)
>>> after_tfic_tlic
array([], shape=(2, 0), dtype=bool)
>>> ax = 1
>>> before, after = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both"
... )
>>> before
array([], shape=(2, 0), dtype=bool)
>>> after
array([], shape=(2, 0), dtype=bool)
>>> before_both, after_both = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", discard_neg="both"
... )
>>> before_both
array([], shape=(2, 0), dtype=bool)
>>> after_both
array([], shape=(2, 0), dtype=bool)
>>> before_type, after_type = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both"
... )
>>> before_type
(array([], shape=(2, 0), dtype=bool), array([], shape=(2, 0), dtype=bool))
>>> after_type
(array([], shape=(2, 0), dtype=bool), array([], shape=(2, 0), dtype=bool))
>>> before_wrap, after_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", wrap=True
... )
>>> before_wrap
array([], shape=(2, 0), dtype=bool)
>>> after_wrap
array([], shape=(2, 0), dtype=bool)
>>> before_type_wrap, after_type_wrap = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", change_type="both", wrap=True
... )
>>> before_type_wrap
(array([], shape=(2, 0), dtype=bool), array([], shape=(2, 0), dtype=bool))
>>> after_type_wrap
(array([], shape=(2, 0), dtype=bool), array([], shape=(2, 0), dtype=bool))
>>> before_tfic_tlic, after_tfic_tlic = mdt.nph.locate_item_change(
...     a, axis=ax, pin="both", tfic=True, tlic=True
... )
>>> before_tfic_tlic
array([], shape=(2, 0), dtype=bool)
>>> after_tfic_tlic
array([], shape=(2, 0), dtype=bool)
>>> a = np.array(0)
>>> mdt.nph.locate_item_change(a, pin="both")
Traceback (most recent call last):
...
ValueError: The input array must be at least one dimensional
>>> mdt.nph.locate_item_change(a, pin="both", wrap=True, tfic=True)
Traceback (most recent call last):
...
ValueError: 'wrap' must not be used together with 'tfic' of 'tlic'