Repository: scipy/scipy

Issue:
griddata sensible to size of original grid when it should not

I am using scipy.interpolate.griddata in order to interpolate data from an original 2d grid to a target sub-region of that grid but at a higher resolution. In order to speed the computation, instead of using the whole original data I used only the part that contains the target region (with a buffer). To my surprise, I obtain different results on the target grid wether I use the whole original grid or a sub-region of that grid.

The code aims to illustrate this. I am wondering if this is to be expected or if it is a bug in griddata.

Any help/feedback  appreciated.

ps : I posted the same question but with a slightly more complex example on https://stackoverflow.com/questions/46164415/scipy-interpolate-griddata-sensitivity-to-original-grid without success until now.

### Reproducing code example:
```

# modification to expample 1 of 
# http://scipy-cookbook.readthedocs.io/items/Matplotlib_Gridding_irregularly_spaced_data.html
# to show problems with griddata

import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt

# generate inital fields on 2d grid
x = np.arange(1,11)
y = np.arange(1,11)
x2d, y2d = np.meshgrid(x,y)
z = x2d*2 + y2d*3
z = np.abs(x*np.exp(-(x2d/10.)**2-(y2d/10.)**2)) + 1

# define target grid 
# (sub region of initial grid but with finer mesh)
x_target = np.arange(4.5,6.6,0.5)
y_target = np.arange(4.5,6.6,0.5)
x2d_target, y2d_target = np.meshgrid(x_target, y_target)

# define interpolation function
def f_int(data, x, y, xt, yt):
    nj, ni = data.shape
    nij = ni * nj
    zi = data.reshape((nij))
    xi = x.ravel()
    yi = y.ravel()
    xo = xt.ravel()
    yo = yt.ravel()
    zo = griddata((xi, yi), zi, (xo, yo), 
                  method = 'nearest', fill_value = np.nan)
    zo = zo.reshape(xt.shape)
    return zo

# interpolate on target grid using the whole initial field
z_int_full = f_int(z, x2d, y2d, x2d_target, y2d_target)

# interpolate on taget grid using a subset of initial field
buffer = 1
x2d_sub = x2d[buffer:-buffer, buffer:-buffer]
y2d_sub = y2d[buffer:-buffer, buffer:-buffer]
z_sub = z[buffer:-buffer, buffer:-buffer]
z_int_sub = f_int(z_sub, x2d_sub, y2d_sub, x2d_target, y2d_target)

fig = plt.figure()
fig.set_size_inches(fig.get_size_inches() * 2)
ax1 = fig.add_subplot(221)
plt.pcolormesh(x2d, y2d, z)
plt.colorbar()
plt.title('initial data')

ax2 = fig.add_subplot(222)
plt.pcolormesh(x2d_target, y2d_target, z_int_full)
plt.colorbar()
plt.title('interpolate from full grid')

ax3 = fig.add_subplot(223)
plt.pcolormesh(x2d_target, y2d_target, z_int_sub)
plt.colorbar()
plt.title('interpolate from sub grid')

ax4 = fig.add_subplot(224)
diff = (z_int_full - z_int_sub)
rel = diff / z_int_full * 100
plt.pcolormesh(x2d_target, y2d_target, rel)
plt.colorbar()
plt.title('relative difference between \n interpolated data [%]')

plt.show()


<<A short code example that reproduces the problem. It should be self-contained, i.e., possible to run as-is via 'python myproblem.py'>>
```

### Error message:
```
no error message
```

### Scipy/Numpy/Python version information:
```
sys.version_info(major=2, minor=7, micro=11, releaselevel='final', serial=0)
numpy : '1.10.2'
scipy : '0.16.1'
```




Discussion:
I do see no indications of a problem in griddata.

The differences are a question of how the *triangle-based* interpolation 
aligns with the target grid. Use a denser x_target, y_target to see it.

Also, if you are interpolating data that's already on a grid, griddata 
is the wrong tool (inefficient), should use interpn.

Ah sorry, the code is using method='nearest' so it's voronoi-based. But 
I think the explanation is still that the target points happen to be 
exactly on the voronoi cell boundaries --- in this case which cell they 
belong to is ill-defined so you can get different answers depending of 
the precise input points, e.g., change '4.5' to '4.50001'.

Thanks for the feedback.
I understand the sensitivity for the 'nearest option' but the value of the point for the input grid are identical ... Notice that I am also surprised by the results when I use "linear" interpolation. The differences are of the order of 0.1%.

I would expect that if I do a nearest or linear interpolation the closer points would be used to make the interpolation. I do not expect the choice of those points to be sensible to the size of the input grid as long as they do not contain any points close enough to the target points.

The whole problem was revealed when I tried to interpolate temperature data on a regular global lat/lon grid to an irregular (in lat/lon coord) grid (that's why I used griddate). The interpolation  was long so I tried to trim the input global grid to make the code run faster. It changed the results by up to 1 deg C for some points, which does not make sense to me.
For the nearest mode, your problem is that 0.5 is equally close to 0 and 1, and for scattered data it is ill-defined which point is closer.

For linear mode, the Delaunay triangulation can differ for different input points when it is not unique (the case of rectangular grids). If your data is sparse, linear interpolation can of course differ significantly for different triangulations.

If the original data is on a rectangular grid, as you write above, then interpn is the right tool.
At this point, the behavior of the code example above is now explained and it does not appear there is something that needs to be addressed. For the other issues you discuss, it would be necessary to have a second code example illustrating them.
I made a test moving my target grid by 0.01 and it takes care of the differences using the 'nearest' option. I still have differences with the 'linear' option.

I will work on a code to illustrate my initial problem. This said I still am surprised to say the least by this "sensitivity" of the interpolation to the presence/absence of points relatively far from the target points.

Regarding the interpn/griddata choice, does this imply that one should not use griddata with a regular input grid or just that interpn would be faster?

interpn likely is faster, and it's not triangle-based.

Anyway, as I understand, the issue you have is that your data is so sparse that it's possible to construct several quite different but still equally good interpolations --- and moreover, you the data is on a grid, which is degenerate problem for triangulation. Because you are using a scattered data interpolation method, which has no idea the data is actually on a square grid, it has to construct the locality structure first. The locality structure construction is a global process, but it only depends on coordinates and not on data values, so global effects can occur in the way geometrical degeneracies are split. This is expected behavior, so if this is the issue, this issue can be closed.
I will come back with an example of my problem.
I confirm that the problem mentioned is not present when using interpn instead of griddata. I also got rid of the problem by using random numbers in order to render the regular grid irregular.

So if I understand, I should try to use interpn if possible and griddata if it is not. It still bugs me that something that work on an irregular grid is showing faulty sensitivity when used on a regular grid. Preliminary results using matlab did not show this kind of behaviour from its implementation of griddata.
I confirm : tests done with matlab show their implementation of griddata is not sensible to the size of the input grid as scipy.griddata seens to be.
Perhaps Matlab checks whether the data is on a regular grid and in that case uses a more appropriate algorithm? Could do that, but maybe it would be better to just make a note in the docs that the user should pick `interpn` if they have a regular grid?

Resolving patch:
diff --git a/scipy/interpolate/_ndgriddata.py b/scipy/interpolate/_ndgriddata.py
--- a/scipy/interpolate/_ndgriddata.py
+++ b/scipy/interpolate/_ndgriddata.py
@@ -172,6 +172,8 @@ def griddata(points, values, xi, method='linear', fill_value=np.nan,
 
     .. versionadded:: 0.9
 
+    For data on a regular grid use `interpn` instead.
+
     Examples
     --------
 


Test patch: