Repository: scipy/scipy

Issue:
TypeError for RegularGridInterpolator with big-endian data
I ran into this `TypeError` with the `RegularGridInterpolator` for some big-endian data:

``` python
>>> import numpy as np
>>> from scipy import interpolate
>>> 
>>> values = np.ones((10, 20 , 30), dtype='>f4')
>>> points = map(np.arange, values.shape)
>>> xi = [(1, 1, 1)]
>>> interpolator = interpolate.RegularGridInterpolator(points, values)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/interpolate/interpolate.py", line 1495, in __init__
    raise ValueError("fill_value must be either 'None' or "
ValueError: fill_value must be either 'None' or of a type compatible with values
>>> interpolator = interpolate.RegularGridInterpolator(points, values, fill_value=0.)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/interpolate/interpolate.py", line 1495, in __init__
    raise ValueError("fill_value must be either 'None' or "
ValueError: fill_value must be either 'None' or of a type compatible with values
```

I think this is a small bug because the Python float `0.` should be compatible with a dtype of `>f4`, no?

cc @andreas-h @pv 



Discussion:
Also it took me a few minutes to figure out what to pass for `points` ... I guess using "pixel coordinates" is a very common use case and this could be shown in an example?

```
points = map(np.arange, values.shape)
```

Am I correct that there is no 3-dim spline interpolation available in scipy?

thanks for reporting, christoph!

@pv I'm by no means a dtype expert ... can you give me a hint how to tackle this?

Maybe `can_cast(..., casting='same_kind')`. This may be need to be
guarded with Numpy version checks, as the kwarg is added only in Numpy
1.6 (i.e. don't make any checks at all for Numpy < 1.6). The intent is
just to catch early errors due to assigning floats to integers or
complexes to floats.

Do version check by adding a global variable `NUMPY_LT_160 =
NumpyVersion(np.__version__) < '1.6.0'` (needs to be global as
NumpyVersion is a slow operation).


Resolving patch:
diff --git a/scipy/interpolate/interpolate.py b/scipy/interpolate/interpolate.py
--- a/scipy/interpolate/interpolate.py
+++ b/scipy/interpolate/interpolate.py
@@ -19,6 +19,7 @@
 import functools
 import operator
 
+from scipy.lib._version import NumpyVersion
 from scipy.lib.six import xrange, integer_types
 
 from . import fitpack
@@ -30,6 +31,9 @@
 from .interpnd import _ndim_coords_from_arrays
 
 
+NUMPY_LT_160 = NumpyVersion(np.__version__) < '1.6.0'
+
+
 def reduce_sometrue(a):
     all = a
     while len(shape(all)) > 1:
@@ -1507,9 +1511,13 @@ def __init__(self, points, values, method="linear", bounds_error=True,
         self.fill_value = fill_value
         if fill_value is not None:
             fill_value_dtype = np.asarray(fill_value).dtype
-            if hasattr(values, 'dtype') and not np.can_cast(fill_value_dtype, values.dtype):
-                raise ValueError("fill_value must be either 'None' or "
-                                 "of a type compatible with values")
+            if not NUMPY_LT_160:
+                if (hasattr(values,
+                            'dtype') and not np.can_cast(fill_value_dtype,
+                                                         values.dtype,
+                                                         casting='same_kind')):
+                    raise ValueError("fill_value must be either 'None' or "
+                                     "of a type compatible with values")
 
         for i, p in enumerate(points):
             if not np.all(np.diff(p) > 0.):


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
@@ -1445,8 +1445,17 @@ def test_invalid_fill_value(self):
         RegularGridInterpolator((x, y), values, fill_value=1)
 
         # complex values cannot
-        assert_raises(ValueError, RegularGridInterpolator,
-                      (x, y), values, fill_value=1+2j)
+        if NumpyVersion(np.__version__) >= '1.6.0':
+            assert_raises(ValueError, RegularGridInterpolator,
+                          (x, y), values, fill_value=1+2j)
+
+    def test_fillvalue_type(self):
+        # from #3703; test that interpolator object construction succeeds
+        values = np.ones((10, 20, 30), dtype='>f4')
+        points = [np.arange(n) for n in values.shape]
+        xi = [(1, 1, 1)]
+        interpolator = RegularGridInterpolator(points, values)
+        interpolator = RegularGridInterpolator(points, values, fill_value=0.)
 
 
 class MyValue(object):