title: Find indices of all points downhill in numpy 2D
body: <p>The below 2D numpy array represents a surface height. From any given cell in this matrix, I wish to find the cells which can be reached through continually moving away either flat (same height) or downhill (lower height). We can think of this as modelling where a ball could possibly roll if it is not allowed to roll back up any slope on the other side (no matter how small). Note the area to the left of the heatmap - it is lower than the target square but a trek uphill is still required to get there.</p>
  <pre><code>import numpy as np
  arr_surface_2D = np.array([
      [64, 64, 65, 66, 66, 67, 68, 68, 69, 70, 70, 70, 69],
      [65, 66, 66, 67, 68, 68, 69, 70, 70, 71, 72, 71, 70],
      [64, 65, 66, 66, 67, 68, 68, 69, 70, 70, 71, 70, 70],
      [66, 66, 67, 68, 68, 69, 70, 70, 71, 71, 72, 72, 71],
      [65, 66, 66, 67, 68, 68, 69, 69, 70, 71, 71, 71, 70],
      [63, 64, 65, 65, 66, 66, 67, 68, 68, 69, 70, 69, 68],
      [63, 63, 64, 64, 65, 66, 66, 67, 68, 68, 69, 68, 68],
      [70, 66, 65, 64, 65, 66, 66, 67, 67, 68, 69, 68, 68],
      [68, 65, 63, 62, 63, 63, 64, 65, 65, 66, 67, 66, 65],
      [57, 58, 58, 59, 59, 60, 61, 61, 62, 63, 63, 63, 62],
      [56, 56, 57, 58, 58, 59, 60, 60, 61, 62, 62, 62, 61],
      [55, 56, 57, 57, 58, 59, 59, 60, 61, 61, 62, 61, 61],
      [55, 56, 57, 57, 58, 59, 59, 60, 60, 61, 62, 61, 61]
  ]
  )
  </code></pre>
  <p><a href="https://i.stack.imgur.com/oskS1.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/oskS1.png" alt="2D Downhill example" /></a></p>
  <p>If the array is 1 dimensional, I can come up with a not-very-elegant solution as follows, however I was thinking there is likely to be a more elegant solution which extends to 2D?</p>
  <pre><code>idx_target = 7
  arr_surface_1D = np.array([
      70, 66, 65, 64, 65, 66, 66, 67, # &lt;-&quot;target&quot;
      67, 68, 69, 68, 68])
  
  # Slice array to the left side of idx_target, reverse direction to allow diff in next step
  arr_left = arr_surface_1D[:idx_target][::-1]
  # Determine number of spaces to the left where the values first start increasing
  steps_left = np.argmax((np.diff(arr_left) &gt; 0))
  
  # Slice array to the right side of idx_target
  arr_right = arr_surface_1D[idx_target + 1:]
  # Determine number of spaces to the right where the values first start increasing
  steps_right = np.argmax((np.diff(arr_right) &gt; 0))
  
  arr_downhill = arr_surface_1D[idx_target-(steps_left+1):idx_target+(steps_right)]
  # Result is array array([64, 65, 66, 66])
  </code></pre>