Repository: scipy/scipy

Issue:
BUG: scipy.interpolate interp1d extrapolate behaviour change from 1.8.1 -> 1.9.0
### Describe your issue.

In scipy 1.9.0 the interp1d method with 'previous' kind and fill_value='extrapolate' seems to use the largest positive value for extrapolation. 

While in 1.8.1 the last value was used for extrapolation (This seems to be the right behaviour)

To reproduce the issue execute the example code with scipy 1.9.0 and 1.8.1

Plot of the below code example in 1.8.1
![interp1dextrapolate_1 8 1](https://user-images.githubusercontent.com/5484864/183686446-2112977f-8cef-49ae-acea-d87a9814db19.png)

And in 1.9.0
![interp1dextrapolate_1 9](https://user-images.githubusercontent.com/5484864/183686468-a30f6592-be10-428a-8499-05b0f96d5a82.png)

### Reproducing Code Example

```python
import numpy as np
from scipy.interpolate import interp1d
from matplotlib.pyplot import figure, show


x = np.arange(5)
y = np.array([0.0, 0.0, 1.0, 0.0, 0.0])

new_x = np.arange(50) / 10.
new_y = interp1d(x, y, 'previous', bounds_error=False, fill_value="extrapolate")(new_x)

f = figure()
s = f.add_subplot(111)
s.plot(x, y, 'x')
s.plot(new_x, new_y)
show()
```


### Error message

```shell
/
```


### SciPy/NumPy/Python version information

1.9.0 1.23.1 sys.version_info(major=3, minor=9, micro=5, releaselevel='final', serial=0)


Discussion:
Cc @AtsushiSakai , what would you say? Also cf https://github.com/scipy/scipy/issues/9591

Ah... I think my PR #16128 looks very bad.
I don't know why I used `max` or ` min` for extrapolation....
https://github.com/scipy/scipy/blob/649932fa64747ef585eabe75cf9a39e3799e3eab/scipy/interpolate/_interpolate.py#L533
https://github.com/scipy/scipy/blob/649932fa64747ef585eabe75cf9a39e3799e3eab/scipy/interpolate/_interpolate.py#L542
I think these should be the right end or left end of `y`
I will fix it soon and the RP should be included in v1.9.1.
I'm sorry for every one and thank you for reporting @TM90 
A case of collective blindness, more like. When you send a fix, could you test both with and without `assume_sorted`.  

Resolving patch:
diff --git a/scipy/interpolate/_interpolate.py b/scipy/interpolate/_interpolate.py
--- a/scipy/interpolate/_interpolate.py
+++ b/scipy/interpolate/_interpolate.py
@@ -530,7 +530,8 @@ def __init__(self, x, y, kind='linear', axis=-1,
                 self._call = self.__class__._call_previousnext
                 if _do_extrapolate(fill_value):
                     self._check_and_update_bounds_error_for_extrapolation()
-                    fill_value = (np.nan, self.y.max(axis=axis))
+                    # assume y is sorted by x ascending order here.
+                    fill_value = (np.nan, np.take(self.y, -1, axis))
             elif kind == 'next':
                 self._side = 'right'
                 self._ind = 1
@@ -539,7 +540,8 @@ def __init__(self, x, y, kind='linear', axis=-1,
                 self._call = self.__class__._call_previousnext
                 if _do_extrapolate(fill_value):
                     self._check_and_update_bounds_error_for_extrapolation()
-                    fill_value = (self.y.min(axis=axis), np.nan)
+                    # assume y is sorted by x ascending order here.
+                    fill_value = (np.take(self.y, 0, axis), np.nan)
             else:
                 # Check if we can delegate to numpy.interp (2x-10x faster).
                 np_types = (np.float_, np.int_)


Test patch:
diff --git a/scipy/interpolate/tests/test_interpolate.py b/scipy/interpolate/tests/test_interpolate.py
--- a/scipy/interpolate/tests/test_interpolate.py
+++ b/scipy/interpolate/tests/test_interpolate.py
@@ -122,6 +122,28 @@ def setup_method(self):
         self.y235 = np.arange(30.).reshape((2, 3, 5))
         self.y325 = np.arange(30.).reshape((3, 2, 5))
 
+        # Edge updated test matrix 1
+        # array([[ 30,   1,   2,   3,   4,   5,   6,   7,   8, -30],
+        #        [ 30,  11,  12,  13,  14,  15,  16,  17,  18, -30]])
+        self.y210_edge_updated = np.arange(20.).reshape((2, 10))
+        self.y210_edge_updated[:, 0] = 30
+        self.y210_edge_updated[:, -1] = -30
+
+        # Edge updated test matrix 2
+        # array([[ 30,  30],
+        #       [  2,   3],
+        #       [  4,   5],
+        #       [  6,   7],
+        #       [  8,   9],
+        #       [ 10,  11],
+        #       [ 12,  13],
+        #       [ 14,  15],
+        #       [ 16,  17],
+        #       [-30, -30]])
+        self.y102_edge_updated = np.arange(20.).reshape((10, 2))
+        self.y102_edge_updated[0, :] = 30
+        self.y102_edge_updated[-1, :] = -30
+
         self.fill_value = -100.0
 
     def test_validation(self):
@@ -386,6 +408,36 @@ def test_previous(self):
                     bounds_error=True)
         assert_raises(ValueError, interp1d, self.x10, self.y10, **opts)
 
+        # Tests for gh-16813
+        interpolator1D = interp1d([0, 1, 2],
+                                  [0, 1, -1], kind="previous",
+                                  fill_value='extrapolate',
+                                  assume_sorted=True)
+        assert_allclose(interpolator1D([-2, -1, 0, 1, 2, 3, 5]),
+                        [np.nan, np.nan, 0, 1, -1, -1, -1])
+
+        interpolator1D = interp1d([2, 0, 1],  # x is not ascending
+                                  [-1, 0, 1], kind="previous",
+                                  fill_value='extrapolate',
+                                  assume_sorted=False)
+        assert_allclose(interpolator1D([-2, -1, 0, 1, 2, 3, 5]),
+                        [np.nan, np.nan, 0, 1, -1, -1, -1])
+
+        interpolator2D = interp1d(self.x10, self.y210_edge_updated,
+                                  kind="previous",
+                                  fill_value='extrapolate')
+        assert_allclose(interpolator2D([-1, -2, 5, 8, 12, 25]),
+                        [[np.nan, np.nan, 5, 8, -30, -30],
+                         [np.nan, np.nan, 15, 18, -30, -30]])
+
+        interpolator2DAxis0 = interp1d(self.x10, self.y102_edge_updated,
+                                       kind="previous",
+                                       axis=0, fill_value='extrapolate')
+        assert_allclose(interpolator2DAxis0([-2, 5, 12]),
+                        [[np.nan, np.nan],
+                         [10, 11],
+                         [-30, -30]])
+
     def test_next(self):
         # Check the actual implementation of next interpolation.
         interp10 = interp1d(self.x10, self.y10, kind='next')
@@ -425,6 +477,36 @@ def test_next(self):
                     bounds_error=True)
         assert_raises(ValueError, interp1d, self.x10, self.y10, **opts)
 
+        # Tests for gh-16813
+        interpolator1D = interp1d([0, 1, 2],
+                                  [0, 1, -1], kind="next",
+                                  fill_value='extrapolate',
+                                  assume_sorted=True)
+        assert_allclose(interpolator1D([-2, -1, 0, 1, 2, 3, 5]),
+                        [0, 0, 0, 1, -1, np.nan, np.nan])
+
+        interpolator1D = interp1d([2, 0, 1],  # x is not ascending
+                                  [-1, 0, 1], kind="next",
+                                  fill_value='extrapolate',
+                                  assume_sorted=False)
+        assert_allclose(interpolator1D([-2, -1, 0, 1, 2, 3, 5]),
+                        [0, 0, 0, 1, -1, np.nan, np.nan])
+
+        interpolator2D = interp1d(self.x10, self.y210_edge_updated,
+                                  kind="next",
+                                  fill_value='extrapolate')
+        assert_allclose(interpolator2D([-1, -2, 5, 8, 12, 25]),
+                        [[30, 30, 5, 8, np.nan, np.nan],
+                         [30, 30, 15, 18, np.nan, np.nan]])
+
+        interpolator2DAxis0 = interp1d(self.x10, self.y102_edge_updated,
+                                       kind="next",
+                                       axis=0, fill_value='extrapolate')
+        assert_allclose(interpolator2DAxis0([-2, 5, 12]),
+                        [[30, 30],
+                         [10, 11],
+                         [np.nan, np.nan]])
+
     def test_zero(self):
         # Check the actual implementation of zero-order spline interpolation.
         interp10 = interp1d(self.x10, self.y10, kind='zero')