7
$\begingroup$

I use Interpolation on unstructured 3-D-Data to visualize different regions via RegionPlot. A problem I run into is that the interpolating function steeply drops to zero beyond my set of data. This is unfortunate, as I with to show the region up to their theoretical boundary (which lies only a little bit beyond the data region).

Is there a way to get Interpolation to perform a proper extrapolation for just a little margin beyond my data?

This image shows the problem pretty well I think. Example for the problem

The data that produced the image can be found here

$\endgroup$
2
  • 1
    $\begingroup$ Please include a sample dataset that reproduces this problem. $\endgroup$
    – rm -rf
    Commented Aug 22, 2013 at 14:18
  • $\begingroup$ Thanks. I added the data, I hope the spoiler works, it's quite a list... $\endgroup$
    – Neuneck
    Commented Aug 22, 2013 at 14:32

3 Answers 3

9
$\begingroup$

I don't know what proper extrapolation you have in mind, but you can specify an extrapolation function, at least in V9, with the option "ExtrapolationHandler" -> {f} (which is experimental according to ruebenko). In this case f should be a function of the form f[x, y].

Examples.

No extrapolation:

ifn = Interpolation[N @ data, 
  "ExtrapolationHandler" -> {(Indeterminate &), "WarningMessage" -> False}];
Plot3D[ifn[x, y], {x, 0.`, 30.`}, {y, 0.`, 20.`}]

Mathematica graphics

Nearest data point:

nf = Nearest[Most /@ data -> Last /@ data];
ifn1 = Interpolation[N @ data, 
  "ExtrapolationHandler" -> {(First@nf[{##}]) &, "WarningMessage" -> False}];
Show[
 Plot3D[ifn1[x, y], {x, 1.725`, 30.`}, {y, 0.`, 20.`}],
 Graphics3D@Point[data]]

Mathematica graphics


I suspect Mathematica is doing a proper extrapolation, and it looks wrong because of the limitations of the data. I would be surprised if it isn't just linear extrapolation. You might consider the relationship of the features to the distribution of the data points, and perhaps the partial derivatives, especially Plot3D[Evaluate@D[ifn[x, y], y], {x, 0., 30.}, {y, 0., 20.}]. The data has a sort of ragged edge near y = 0.9 for 0 < x < 20. To make it look nice might be fudging, and the proper thing to do is to not extrapolate. I'm hedging because I'm probably out of my field here, and there may be special techniques for extrapolating in your case. If so, perhaps the "ExtrapolationHandler" option can be use to solve your problem.

$\endgroup$
2
  • $\begingroup$ Thank you for the elegant solution. +1 $\endgroup$
    – Neuneck
    Commented Aug 23, 2013 at 10:30
  • 2
    $\begingroup$ big +1 from me, this is the first I hear of "ExtrapolationHandler" - when I first saw the answer I thought it was a v9 workaround but it works perfectly in v8! $\endgroup$
    – gpap
    Commented Aug 23, 2013 at 13:21
5
$\begingroup$

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

interpolation

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]
    

interpolation with offsets

  • 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
    

interpolation with bdy

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}]

added boundary

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] ]

boundary fixed

$\endgroup$
1
  • $\begingroup$ Thank you for the amazing effort and the interesting solutions you provided. Absolutely +1. The "ExtrapolationHandler" thing works better with other sets of data I have to plot, though. $\endgroup$
    – Neuneck
    Commented Aug 23, 2013 at 10:29
2
$\begingroup$

Another way is with Nearest. With td set to your data,

mnf = Nearest[{#[[1]], #[[2]]} -> #[[3]] & /@ td]

Show[
 ListPointPlot3D[td,PlotRange->All],
 Plot3D[mnf[{x,y}][[1]],{x,0,30},{y,0,20}]
]

enter image description here

You can smooth some of that lumpiness by averaging the nearest handful of points.

Show[
 ListPointPlot3D[td,PlotRange->All],
 Plot3D[Mean[mnf[{x,y},4]],{x,0,30},{y,0,20}]
]

enter image description here

$\endgroup$
1
  • $\begingroup$ The problem with relying on the nearest function is that it becomes really slow if you increase the plot points. It also, doesn't really go beyond zeroth order. Set the plot points to 60-70 in the plot 3d and you'll see what I mean. $\endgroup$
    – gpap
    Commented Aug 22, 2013 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.