The following code reproduces your problem minimally I think:
grid = RandomReal[{0, 20}, {500, 2}];
trigrid = Select[gr, #[[1]] < #[[2]] &];
vals = {Sequence @@ ##, Sin[ #[[1]]/3 - #[[2]]/2]} & /@ trigrid;
in = Interpolation[vals] // Quiet;
Show[{Plot3D[in[x, y], {x, 0, 20}, {y, 0, 20},
RegionFunction -> Function[{x, y, z}, x < y]],
Graphics3D[Point[vals]]}] // Quiet
And you ask: "Is there a way to get Interpolation
to perform a proper extrapolation for just a little margin beyond my data?"
My guess is no and I would be happily contradicted on this. Regardless, you still have a couple of options.
Add offsets as part of your RegionFunction
and manually adjust them to get a satisfactory result:
With[{offx = .3, offy = .4},
Show[{Plot3D[in[x, y], {x, 0, 20}, {y, 0, 20},
RegionFunction ->
Function[{x, y, z}, x < y && x > offx && 20 - offy > y]],
Graphics3D[Point[vals]]}] // Quiet]
Manually extrapolate yourself by adding extra points at the problematic boundaries. You can assign values to these points based on a Nearest
function. The success of this greatly depends on how far from the data your boundaries are. Here, my problematic boundaries are at $ x=0 $ and at $ y=20 $ so I will create a nearest function that spits out $ z $ coordinates based on nearest values of $ x,y $ coordinates and then I will apply it to values of the $ x-y $ grid where the problems show up. Then I will re-interpolate with the added points:
nf = Nearest[Thread[vals[[All, 1 ;; 2]] -> vals[[All, 3]]]];
bdyX = Flatten[{##, nf@#}] & /@ Array[{0, #} &, 20 ];
bdyY = Flatten[{##, nf@#}] & /@ Array[{#, 20} &, 20 ];
in2 = Interpolation[vals~Join~bdyX~Join~bdyY];
Show[{Plot3D[in2[x, y], {x, 0, 20}, {y, 0, 20},
RegionFunction -> Function[{x, y, z}, x < y]], Graphics3D[Point[vals]]}] // Quiet
You updated the question by adding data while I was writing this but I suggest that if you are satisfied with the minimal example I constructed, you replace your data with that. Assuming your actual data is stored in yourdata
, the problem is for $ x = 30 $ and (mostly) for $ y = 0. $ So the nearest function and added boundaries should be
nf = Nearest[Thread[N@yourdata[[All, 1 ;; 2]] -> N@yourdata[[All, 3]]]]
bdyX = Flatten[{##, nf@#}] & /@ Array[{30, #} &, 20 ]
bdyY = Flatten[{##, nf@#}] & /@ Array[{#, 0} &, 30 ]
Now your data is in red and the added boundary points in blue:
ListPointPlot3D[{yourdata, bdyX~Join~bdyY}, PlotStyle -> {Red, Blue}]
and your interpolation behaves better at the said boundaries(where I filter through DeleteDuplicates
because there are overlapping values somewhere):
in3 = Interpolation[DeleteDuplicates[yourdata~Join~bdyX~Join~bdyY]]
Plot3D[in3[x, y], {x, 0, 30}, {y, 0, 20},
RegionFunction -> Function[{x, y, z}, x > y] ]