# Nearest Neighbor Interpolation on Matrix to Match Another's Non-Zero Structure

**URL:** <https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859>\
**Category:** General Usage\
**Tags:** interpolations\
**Created:** [March 20, 2024, 8:58am UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859 "2024-03-20T08:58:19Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![vivekag7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivekag7/32/202869_2.png) [@vivekag7](https://discourse.julialang.org/u/vivekag7)\
**Post date:** [March 20, 2024, 8:58am UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/1 "2024-03-20T08:58:19Z")

</div>

Hello, Julia Community!

I am working with two matrices: `C_values`, which contains parameter values obtained from an optimization process, and `V`, which represents observed ice surface velocity (please see the attached image for visualization). `C_values` has dimensions that match `V`, but with many `NaN` entries that I would like to fill using nearest neighbor interpolation based on the non-zero structure of `V`.

![image](https://global.discourse-cdn.com/julialang/original/3X/2/d/2d74ce0bf3091f0cdcda98c5f37ebb5434188119.png)

`C_values` is a sparse representation where only a subset of cells have been calculated (left figure), whereas `V` is a dense matrix with varying velocities (right figure).

I am looking for an efficient way to perform nearest neighbor interpolation on `C_values` to ensure that it contains interpolated values at all non-zero points in `V`. Specifically, I need to interpolate `NaN` values in `C_values` only where there are non-zero values in `V`.

My question are:

1. How can I implement nearest neighbor interpolation in this context using Julia?
2. Is there an existing package or function that can handle this selective interpolation directly?

Any pointers or examples would be greatly appreciated!

Thank you in advance!

---

<div class="post-metadata">

**Author:** ![Salmon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/salmon/32/22968_2.png) [@Salmon](https://discourse.julialang.org/u/Salmon)\
**Post date:** [March 22, 2024, 12:05pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/2 "2024-03-22T12:05:08Z")

</div>

> [@vivekag7](#):
>
> `C_values` is a sparse representation where only a subset of cells have been calculated

Do you mean it is a sparse matrix? Or just a regular matrix with `NaN` values? Either way to me it sounds like you could just loop over all indices and insert elements of `V` into `C_values` whenever they are NaN in the latter and nonzero on `V`? afterwards you could probably just interpolate the result using Interpolations.

```julia
for i in eachindex(V, C_values)
   if V[i] != 0 && isnan(C_values[i])
      C_values[i] = V[i]
    end
end
       

```

and then just interpolation the resulting array?

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [March 22, 2024, 12:13pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/3 "2024-03-22T12:13:22Z")

</div>

This is a typical problem that is trivial to solve with the GeoStats.jl framework. Take a look at our `InterpolateNeighbors` transform with the `NN` model. You can define the `CartesianGrid` of interpolation, and run the interpolation in one line.

It is all explained in the GDSJL book:

[https://juliaearth.github.io/geospatial-data-science-with-julia](https://juliaearth.github.io/geospatial-data-science-with-julia)

Many other packages provide alternative interfaces to interpolation. You will benefit from our approach if you need to replace grids by more complicated domains in the future.

---

<div class="post-metadata">

**Author:** ![vivekag7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivekag7/32/202869_2.png) [@vivekag7](https://discourse.julialang.org/u/vivekag7)\
**Post date:** [April 2, 2024, 6:33pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/4 "2024-04-02T18:33:11Z")

</div>

Sorry for my late response, I had some other obligations coming up. I have read through the documents, but I struggle to get the interpolation working. I feel I just do not understand some things good enough.

So I have this matrix `C` from which we would like to sample the data, I should then define `grid = CartesianGrid(size(C))` and somehow geo reference this right and then proceed with the interpolation?

I find it hard to see how this interpolation can be run in one line.  
Could you maybe provide a minimal working example?

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [April 2, 2024, 6:42pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/5 "2024-04-02T18:42:14Z")

</div>

You have to understand two things:

1. The domain of interpolation, which is the `CartesianGrid` with appropriate size, origin, spacing, etc. Check the docstring for details.
2. The geospatial data, which is the `GeoTable` with known values of the variable at specific locations. Check the docstring of `georef` for details.

After you construct these two objects, say `grid` and `geotable`, then you can:

```julia
geotable |> InterpolateNeighbors(grid) # using nearest neighbors

```

or

```julia
geotable |> Interpolate(grid) # using all neighbors

```

You can visualize all these objects with `viz` and `viewer` as explained in the book, to make sure that they are where you expect them to be in the coordinate reference system.

---

<div class="post-metadata">

**Author:** ![vivekag7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivekag7/32/202869_2.png) [@vivekag7](https://discourse.julialang.org/u/vivekag7)\
**Post date:** [April 2, 2024, 6:47pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/6 "2024-04-02T18:47:27Z")

</div>

Okay thanks for the quick response and clarification!

---

<div class="post-metadata">

**Author:** ![vivekag7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivekag7/32/202869_2.png) [@vivekag7](https://discourse.julialang.org/u/vivekag7)\
**Post date:** [April 2, 2024, 7:05pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/7 "2024-04-02T19:05:52Z")

</div>

Okay what I do not understand here, is how can I convert the 2D matrix to a suitable DataFrame for `georef`?

I am running the following, where `C` is a 95x137 matrix.

```julia
using GeoStats, DataFrames
df = DataFrame(C, :auto)
grid = CartesianGrid(size(C))
gt = georef(df, grid)
InterpolateNeighbors(gt, grid)

```

The above code does not work, because the dataframe `df` is not setup right.  
I am to be honest not so familiar with the use of DataFrame structures within Julia…

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [April 2, 2024, 7:25pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/8 "2024-04-02T19:25:51Z")

</div>

Please share a MWE with the data. Have you seen the examples in the docs?

[https://juliaearth.github.io/GeoStatsDocs/stable/#Quick-example](https://juliaearth.github.io/GeoStatsDocs/stable/#Quick-example)

---

<div class="post-metadata">

**Author:** ![vivekag7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivekag7/32/202869_2.png) [@vivekag7](https://discourse.julialang.org/u/vivekag7)\
**Post date:** [April 2, 2024, 7:41pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/9 "2024-04-02T19:41:37Z")

</div>

Yes I have seen this example, but I struggle on how to assign the coordinates to the points in the matrix in an automated way.

It is a bit hard to share the matrix itself, as there is a whole inversion process to obtain it. But this is the shape, where I would like to interpolate the white (NaN) values.

 ![afbeelding_2024-04-02_214113480](https://global.discourse-cdn.com/julialang/original/3X/9/b/9b70bf3a2e7e981191ece9a4cf9c397554ca2f64.png)

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [April 2, 2024, 7:50pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/10 "2024-04-02T19:50:14Z")

</div>

One possible solution is:

```julia
gtable = georef((; C)) # georeference array C into grid

inds = findall(!isnan, gtable.C) # find indices with data

data = gtable[inds, :] # view of geotable

data |> InterpolateNeighbors(gtable.geometry) # interpolate over grid

```

---

<div class="post-metadata">

**Author:** ![vivekag7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivekag7/32/202869_2.png) [@vivekag7](https://discourse.julialang.org/u/vivekag7)\
**Post date:** [April 2, 2024, 7:57pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/11 "2024-04-02T19:57:14Z")

</div>

Okay I think this is exactly what I was looking for, except for the fact that it is mirrored.

![image](https://global.discourse-cdn.com/julialang/original/3X/0/a/0ad16fd2f5b2cdbe5da4056645177d7b6658e22c.png)

My last question is if there is a straightforward way to extract the interpolated matrix as a matrix{Float64}?

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [April 2, 2024, 7:59pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/12 "2024-04-02T19:59:20Z")

</div>

It is mirrored because the convention is that the first dimension of the array is attached to the X axis, the second to the Y axis, etc. This also holds in 3D. You can easily `result |> Rotate(pi/2)` if you need a rotated visualization.

You can extract columns from geotables as arrays with `asarray(result, "C")`

---

<div class="post-metadata">

**Author:** ![vivekag7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivekag7/32/202869_2.png) [@vivekag7](https://discourse.julialang.org/u/vivekag7)\
**Post date:** [April 2, 2024, 8:03pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/13 "2024-04-02T20:03:14Z")

</div>

Perfect, you really helped me a lot! Thanks for all the effort and the quick responses, it is really appreciated 😄

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [April 10, 2024, 2:21pm UTC](https://discourse.julialang.org/t/nearest-neighbor-interpolation-on-matrix-to-match-anothers-non-zero-structure/111859/14 "2024-04-10T14:21:49Z")

</div>

We introduced a new transform in GeoStats.jl v0.56 called `InterpolateNaN` to hide these low-level details from end-users. Here is an updated solution:

```julia
georef((; C)) |> InterpolateNaN()

```
