Repository: scipy/scipy

Issue:
domain of argument of scipy.interpolate.RectSphereBivariateSpline(u, v, r, s=0.0, pole_continuity=False, pole_values=None, pole_exact=False, pole_flat=False)
Hi,

Just realized that I am restating the already reported issue
[https://github.com/scipy/scipy/issues/9704](https://github.com/scipy/scipy/issues/9704)

In the documentation of 
domain of argument of scipy.interpolate.RectSphereBivariateSpline(u, v, r, s=0.0, pole_continuity=False, pole_values=None, pole_exact=False, pole_flat=False)
on page
[https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.RectSphereBivariateSpline.html](https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.RectSphereBivariateSpline.html)
it states that the domain of the 2nd argument v should be [-pi, pi). However, when invoking
RectSphereBivariateSpline.ev(self, theta, phi, dtheta=0, dphi=0)
documented on page
[https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.RectSphereBivariateSpline.ev.html](https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.RectSphereBivariateSpline.ev.html)
the argument phi, which corresponds to the aforementioned v, requires the input within [0, 2pi) rather than [-pi, pi).

Would you double check the domains of the angular arguments and make sure that the functions and their documentations all have consistent domains for the angles? Thanks!


Discussion:

Resolving patch:
diff --git a/scipy/interpolate/fitpack2.py b/scipy/interpolate/fitpack2.py
--- a/scipy/interpolate/fitpack2.py
+++ b/scipy/interpolate/fitpack2.py
@@ -1420,8 +1420,6 @@ def __call__(self, theta, phi, dtheta=0, dphi=0, grid=True):
 
         if theta.size > 0 and (theta.min() < 0. or theta.max() > np.pi):
             raise ValueError("requested theta out of bounds.")
-        if phi.size > 0 and (phi.min() < 0. or phi.max() > 2. * np.pi):
-            raise ValueError("requested phi out of bounds.")
 
         return _BivariateSplineBase.__call__(self, theta, phi,
                                              dx=dtheta, dy=dphi, grid=grid)
@@ -1579,6 +1577,17 @@ def __init__(self, theta, phi, r, w=None, s=0., eps=1E-16):
         self.tck = tt_[:nt_], tp_[:np_], c[:(nt_ - 4) * (np_ - 4)]
         self.degrees = (3, 3)
 
+    def __call__(self, theta, phi, dtheta=0, dphi=0, grid=True):
+
+        theta = np.asarray(theta)
+        phi = np.asarray(phi)
+
+        if phi.size > 0 and (phi.min() < 0. or phi.max() > 2. * np.pi):
+            raise ValueError("requested phi out of bounds.")
+
+        return SphereBivariateSpline.__call__(self, theta, phi, dtheta=dtheta,
+                                              dphi=dphi, grid=grid)
+
 
 class LSQSphereBivariateSpline(SphereBivariateSpline):
     """
@@ -1723,6 +1732,17 @@ def __init__(self, theta, phi, r, tt, tp, w=None, eps=1E-16):
         self.tck = tt_, tp_, c
         self.degrees = (3, 3)
 
+    def __call__(self, theta, phi, dtheta=0, dphi=0, grid=True):
+
+        theta = np.asarray(theta)
+        phi = np.asarray(phi)
+
+        if phi.size > 0 and (phi.min() < 0. or phi.max() > 2. * np.pi):
+            raise ValueError("requested phi out of bounds.")
+
+        return SphereBivariateSpline.__call__(self, theta, phi, dtheta=dtheta,
+                                              dphi=dphi, grid=grid)
+
 
 _spfit_messages = _surfit_messages.copy()
 _spfit_messages[10] = """
@@ -1977,3 +1997,12 @@ def __init__(self, u, v, r, s=0., pole_continuity=False, pole_values=None,
         self.fp = fp
         self.tck = tu[:nu], tv[:nv], c[:(nu - 4) * (nv-4)]
         self.degrees = (3, 3)
+        self.v0 = v[0]
+
+    def __call__(self, theta, phi, dtheta=0, dphi=0, grid=True):
+
+        theta = np.asarray(theta)
+        phi = np.asarray(phi)
+
+        return SphereBivariateSpline.__call__(self, theta, phi, dtheta=dtheta,
+                                              dphi=dphi, grid=grid)


Test patch:
diff --git a/scipy/interpolate/tests/test_fitpack2.py b/scipy/interpolate/tests/test_fitpack2.py
--- a/scipy/interpolate/tests/test_fitpack2.py
+++ b/scipy/interpolate/tests/test_fitpack2.py
@@ -1041,6 +1041,21 @@ def test_array_like_input(self):
         spl2 = RectSphereBivariateSpline(x.tolist(), y.tolist(), z.tolist())
         assert_array_almost_equal(spl1(x, y), spl2(x, y))
 
+    def test_negative_evaluation(self):
+        lats = np.array([25, 30, 35, 40, 45])
+        lons = np.array([-90, -85, -80, -75, 70])
+        mesh = np.meshgrid(lats, lons)
+        data = mesh[0] + mesh[1]  # lon + lat value
+        lat_r = np.radians(lats)
+        lon_r = np.radians(lons)
+        interpolator = RectSphereBivariateSpline(lat_r, lon_r, data)
+        query_lat = np.radians(np.array([35, 37.5]))
+        query_lon = np.radians(np.array([-80, -77.5]))
+        data_interp = interpolator(query_lat, query_lon)
+        ans = np.array([[-45.0, -42.480862],
+                        [-49.0625, -46.54315]])
+        assert_array_almost_equal(data_interp, ans)
+
 
 def _numdiff_2d(func, x, y, dx=0, dy=0, eps=1e-8):
     if dx == 0 and dy == 0: