4

I have a dataset with lat/lon coordinates and a corresponding 0/1 value for each geolocation (4 to 200+ datapoints). Now, I want to interpolate the voids and add colors to the surface of the globe based on the interpolation results. The main problem I have is to interpolate "around the globe", because currently I do in a plane, which obviously does not work.

My data

set.seed(41)
n <- 5
s <- rbind(data.frame(lon = rnorm(n, 0, 180),
                      lat = rnorm(n, 90, 180),
                      value = 0),
           data.frame(lon = rnorm(n, 180, 180),
                      lat = rnorm(n, 90, 180),
                      value = 1))
s$lon <- s$lon %% 360 -180
s$lat <- s$lat %% 180 -90
s_old <- s

Visualize datapoints

library(sp)  
library(rgdal)
library(scales)
library(raster)
library(dplyr)

par(mfrow=c(2,1), mar=c(0,0,0,0))
grd <- expand.grid(lon = seq(-180,180, by = 20), 
                   lat = seq(-90, 90, by=10))
coordinates(grd) <- ~lon + lat
gridded(grd) <- TRUE
plot(grd, add=F, col=grey(.8))

coordinates(s) = ~lon + lat
points(s, col=s$value + 2, pch=16, cex=.6)

enter image description here

Bivariate interpolate in plane

Currently, the bivariate spline interpolation is done directly on the lat/lon coordinates using the akima papckage. This works, but does not take into account that the lat/lon coordinates lie on a sphere.

nx <- 361
ny <- 181
xo <- seq(-180, 179, len=nx)
yo <- seq(-90, 89, len=ny)
xy <- as.data.frame(coordinates(s))
int <- akima:::interp(x = xy$lon, y = xy$lat, z = s$value, 
                      extrap = T, 
                      xo = xo, yo = yo, 
                      nx = nx, ny=100, 
                      linear = F)
z <- int$z
# correct for out of range interpolations values
z[z < 0] <- 0
z[z > 1] <- 1

grd <- expand.grid(lon = seq(-180,180, by = 20), 
                   lat = seq(-90, 90, by=10))
coordinates(grd) <- ~lon + lat
gridded(grd) <- TRUE
plot(grd, add=F, col=grey(.8))

## create raster image
r <- raster(nrows=ny, ncols=nx, crs='+proj=longlat',
            xmn=-180, xmx=180, ymn=-90, ymx=90)
values(r) <- as.vector(z)  

# tweaking of color breaks
colors <- alpha(colorRampPalette(c("red", "yellow", "green"))(21), .4)
br <- seq(0.3, 0.7, len=20)
image(xo, yo, z, add = T, col = colors, breaks=c(-.1, br, 1.1))
points(s, col=s$value + 2, pch=16, cex=.6)

enter image description here

Obviously this does not work for a sphere, as the left side does not match the right side. On a sphere,the interpolation should be seamless.

enter image description here

What approaches can I use do interpolate on a sphere in R?

Sébastien Rochette
  • 6,536
  • 2
  • 22
  • 43
Mark Heckmann
  • 10,943
  • 4
  • 56
  • 88

1 Answers1

4

You can calculate distances between points and grid yourself and then use your own interpolation. For instance, below is a inverse distance interpolation on your data example.

Generate Data

library(sp)
library(rgdal)

# Data
set.seed(41)
n <- 5
s <- rbind(data.frame(lon = rnorm(n, 0, 180),
                      lat = rnorm(n, 90, 180),
                      value = 0),
           data.frame(lon = rnorm(n, 180, 180),
                      lat = rnorm(n, 90, 180),
                      value = 1))
s$lon <- s$lon %% 360 -180
s$lat <- s$lat %% 180 -90
s_old <- s

Create raster for grid interpolation

## create raster image
r <- raster(nrows=ny, ncols=nx, crs='+proj=longlat',
            xmn=-180, xmx=180, ymn=-90, ymx=90)

Calculate distances between points and raster

Function spDists in library sp use the Great Circle Distance when coordinates are not projected. This means that the distance calculated between two points is the shortest.

# Distance between points and raster
s.r.dists <- spDists(x = coordinates(s), y = coordinates(r), longlat = TRUE)

Interpolate on a sphere using inverse distance interpolation

Here I propose to interpolate using the classical inverse distance interpolation with power 2 (idp=2). You can modify yourself the calculation if you want other power or linear interpolation, or if you want to interpolate with a limited number of neighbors.

# Inverse distance interpolation using distances
# pred = 1/dist^idp
idp <- 2
inv.w <- (1/(s.r.dists^idp))
z <- (t(inv.w) %*% matrix(s$value)) / apply(inv.w, 2, sum)

r.pred <- r
values(r.pred) <- z

Then plot the results

# tweaking of color breaks
colors <- alpha(colorRampPalette(c("red", "yellow", "green"))(21), .4)
br <- seq(0.3, 0.7, len=20)
plot(r.pred, col = colors, breaks=c(-.1, br, 1.1), legend=F)
points(s, col=s$value + 2, pch=16, cex=.6)

Inverse distance interpolation on surface of a sphere (ipd=2)

Sébastien Rochette
  • 6,536
  • 2
  • 22
  • 43
  • One question: How can I achieve that the interpolation does not give so much weight to single points, i.e. with one green point surrounded by many red points, the interpolated value for the green point should not be green, but red or only slightly greenish showing that the area is a red one. see http://imgur.com/a/89CqF)? – Mark Heckmann Apr 11 '17 at 21:18
  • 1
    In that case, this would not be an interpolation. With interpolation, the distance is important, so that when dist=0, prediction is almost equal to data. You can reduce the `idp` weight, but what you want is more a model than an interpolation. I can drive you to my other answer with gam or glm here: http://stackoverflow.com/questions/43006045/obtain-function-from-akimainterp-matrix/43064436#43064436 However, this does not solve the problem of sphere interpolation. Maybe you can transform the coordinates into stereographic from north and south, and try on model on it ? And then reproject... – Sébastien Rochette Apr 12 '17 at 06:54