# How to find appropriate surface fit?

I have 3d scan data (21 x 21 matrix), which is pretty rough, for which I need to find a smooth surface suitable for use outside Mathematica.

Here's my data:

data={{-70.25, 70.25, -2.26125}, {-63.225, 70.25, -3.73893}, {-56.2,
70.25, -7.10822}, {-49.175, 70.25, -6.36538}, {-42.15,
70.25, -5.57188}, {-35.125, 70.25, -2.86852}, {-28.1, 70.25,
1.41064}, {-21.075, 70.25, 1.76991}, {-14.05, 70.25,
4.57831}, {-7.025, 70.25, 6.14301}, {0, 70.25, 4.202}, {7.025,
70.25, 2.11067}, {14.05, 70.25, 9.1197}, {21.075, 70.25,
15.6646}, {28.1, 70.25, 18.0746}, {35.125, 70.25, 21.61}, {42.15,
70.25, 28.1337}, {49.175, 70.25, 32.7949}, {56.2, 70.25,
36.9224}, {63.225, 70.25, 41.1437}, {70.25, 70.25,
44.6378}, {-70.25, 63.225, -1.21473}, {-63.225,
63.225, -5.07113}, {-56.2, 63.225, -6.86862}, {-49.175,
63.225, -7.23374}, {-42.15, 63.225, -3.97069}, {-35.125,
63.225, -1.44013}, {-28.1, 63.225, -0.0281194}, {-21.075, 63.225,
0.492414}, {-14.05, 63.225, 4.34667}, {-7.025, 63.225, 4.97725}, {0,
63.225, 3.55161}, {7.025, 63.225, 2.49987}, {14.05, 63.225,
9.29554}, {21.075, 63.225, 16.3997}, {28.1, 63.225,
18.5347}, {35.125, 63.225, 22.8615}, {42.15, 63.225,
28.9937}, {49.175, 63.225, 30.6571}, {56.2, 63.225,
36.5483}, {63.225, 63.225, 39.8292}, {70.25, 63.225,
44.2213}, {-70.25, 56.2, -1.5784}, {-63.225, 56.2, -4.8966}, {-56.2,
56.2, -6.60251}, {-49.175, 56.2, -7.09819}, {-42.15,
56.2, -5.81754}, {-35.125, 56.2, -2.11398}, {-28.1, 56.2,
0.907723}, {-21.075, 56.2, 0.623036}, {-14.05, 56.2,
2.8643}, {-7.025, 56.2, 4.41984}, {0, 56.2, 4.35338}, {7.025, 56.2,
3.72083}, {14.05, 56.2, 10.6716}, {21.075, 56.2, 16.6047}, {28.1,
56.2, 18.216}, {35.125, 56.2, 22.2957}, {42.15, 56.2,
27.4019}, {49.175, 56.2, 32.3385}, {56.2, 56.2, 36.0869}, {63.225,
56.2, 39.7043}, {70.25, 56.2, 44.5183}, {-70.25,
49.175, -1.50584}, {-63.225, 49.175, -5.69561}, {-56.2,
49.175, -6.51894}, {-49.175, 49.175, -5.95838}, {-42.15,
49.175, -5.39414}, {-35.125, 49.175, -1.94976}, {-28.1,
49.175, -0.75782}, {-21.075, 49.175, 2.6731}, {-14.05, 49.175,
4.41098}, {-7.025, 49.175, 6.23878}, {0, 49.175, 4.77297}, {7.025,
49.175, 3.09164}, {14.05, 49.175, 10.7106}, {21.075, 49.175,
16.7107}, {28.1, 49.175, 20.0287}, {35.125, 49.175,
24.9024}, {42.15, 49.175, 28.5802}, {49.175, 49.175,
32.7586}, {56.2, 49.175, 37.6919}, {63.225, 49.175,
39.6808}, {70.25, 49.175, 43.0471}, {-70.25,
42.15, -1.76297}, {-63.225, 42.15, -5.302}, {-56.2,
42.15, -6.72977}, {-49.175, 42.15, -6.45725}, {-42.15,
42.15, -6.79277}, {-35.125, 42.15, -1.70798}, {-28.1, 42.15,
0.239834}, {-21.075, 42.15, 1.70829}, {-14.05, 42.15,
2.99274}, {-7.025, 42.15, 6.16783}, {0, 42.15, 3.95188}, {7.025,
42.15, 3.47889}, {14.05, 42.15, 9.38021}, {21.075, 42.15,
16.3166}, {28.1, 42.15, 18.321}, {35.125, 42.15, 22.7626}, {42.15,
42.15, 28.2004}, {49.175, 42.15, 32.8068}, {56.2, 42.15,
37.0724}, {63.225, 42.15, 40.1202}, {70.25, 42.15,
43.0466}, {-70.25, 35.125, -2.52346}, {-63.225,
35.125, -5.87013}, {-56.2, 35.125, -7.04629}, {-49.175,
35.125, -7.69747}, {-42.15, 35.125, -6.46145}, {-35.125,
35.125, -2.95586}, {-28.1, 35.125, 0.0185837}, {-21.075, 35.125,
0.864893}, {-14.05, 35.125, 4.92691}, {-7.025, 35.125, 6.09827}, {0,
35.125, 5.05886}, {7.025, 35.125, 4.53701}, {14.05, 35.125,
8.57999}, {21.075, 35.125, 15.2147}, {28.1, 35.125,
18.7537}, {35.125, 35.125, 22.2113}, {42.15, 35.125,
27.9426}, {49.175, 35.125, 33.1851}, {56.2, 35.125,
36.1284}, {63.225, 35.125, 39.3787}, {70.25, 35.125,
39.9823}, {-70.25, 28.1, -2.72847}, {-63.225,
28.1, -5.90163}, {-56.2, 28.1, -6.64675}, {-49.175,
28.1, -6.14843}, {-42.15, 28.1, -3.91255}, {-35.125,
28.1, -3.41069}, {-28.1, 28.1, -0.145011}, {-21.075,
28.1, -0.450747}, {-14.05, 28.1, 2.27009}, {-7.025, 28.1,
6.61466}, {0, 28.1, 2.99095}, {7.025, 28.1, 3.93525}, {14.05, 28.1,
7.37995}, {21.075, 28.1, 15.2258}, {28.1, 28.1, 18.0952}, {35.125,
28.1, 21.2575}, {42.15, 28.1, 26.4591}, {49.175, 28.1,
30.972}, {56.2, 28.1, 35.3167}, {63.225, 28.1, 37.6114}, {70.25,
28.1, 40.3333}, {-70.25, 21.075, -3.51253}, {-63.225,
21.075, -6.56858}, {-56.2, 21.075, -7.38887}, {-49.175,
21.075, -7.76266}, {-42.15, 21.075, -4.74537}, {-35.125,
21.075, -2.31537}, {-28.1, 21.075, -0.0493893}, {-21.075, 21.075,
1.92402}, {-14.05, 21.075, 3.81285}, {-7.025, 21.075, 6.21732}, {0,
21.075, 4.83328}, {7.025, 21.075, 2.38144}, {14.05, 21.075,
7.86424}, {21.075, 21.075, 14.6374}, {28.1, 21.075,
19.0123}, {35.125, 21.075, 20.9741}, {42.15, 21.075,
25.5909}, {49.175, 21.075, 30.9052}, {56.2, 21.075,
33.3904}, {63.225, 21.075, 37.0928}, {70.25, 21.075,
36.9507}, {-70.25, 14.05, -3.90902}, {-63.225,
14.05, -7.3989}, {-56.2, 14.05, -7.85674}, {-49.175,
14.05, -7.99518}, {-42.15, 14.05, -4.34257}, {-35.125,
14.05, -2.83856}, {-28.1, 14.05, 0.423475}, {-21.075, 14.05,
0.629967}, {-14.05, 14.05, 1.68709}, {-7.025, 14.05, 6.01201}, {0,
14.05, 1.58278}, {7.025, 14.05, 2.34453}, {14.05, 14.05,
6.99784}, {21.075, 14.05, 11.7316}, {28.1, 14.05, 16.7024}, {35.125,
14.05, 20.1577}, {42.15, 14.05, 23.7967}, {49.175, 14.05,
27.0305}, {56.2, 14.05, 33.2427}, {63.225, 14.05, 35.735}, {70.25,
14.05, 36.9396}, {-70.25, 7.025, -4.66209}, {-63.225,
7.025, -7.43719}, {-56.2, 7.025, -8.89191}, {-49.175,
7.025, -8.28581}, {-42.15, 7.025, -8.82358}, {-35.125,
7.025, -5.15505}, {-28.1, 7.025, -1.88733}, {-21.075,
7.025, -1.24725}, {-14.05, 7.025, 0.529528}, {-7.025, 7.025,
3.14648}, {0, 7.025, 2.14229}, {7.025, 7.025, 0.851892}, {14.05,
7.025, 6.23896}, {21.075, 7.025, 11.9833}, {28.1, 7.025,
14.9789}, {35.125, 7.025, 17.7317}, {42.15, 7.025,
22.7858}, {49.175, 7.025, 26.9062}, {56.2, 7.025, 29.381}, {63.225,
7.025, 33.1036}, {70.25, 7.025, 35.7555}, {-70.25,
0, -5.44299}, {-63.225, 0, -8.99154}, {-56.2,
0, -9.19577}, {-49.175, 0, -10.3554}, {-42.15,
0, -9.23156}, {-35.125, 0, -6.15542}, {-28.1,
0, -2.58797}, {-21.075, 0, -2.24676}, {-14.05,
0, -1.29542}, {-7.025, 0, 1.08704}, {0, 0, 0}, {7.025,
0, -1.40633}, {14.05, 0, 4.4588}, {21.075, 0, 10.7105}, {28.1, 0,
12.1979}, {35.125, 0, 16.607}, {42.15, 0, 18.8553}, {49.175, 0,
27.1665}, {56.2, 0, 30.6395}, {63.225, 0, 32.7078}, {70.25, 0,
33.2296}, {-70.25, -7.025, -6.57922}, {-63.225, -7.025, -10.4331}, \
{-56.2, -7.025, -9.31305}, {-49.175, -7.025, -11.2906}, {-42.15, \
-7.025, -10.1935}, {-35.125, -7.025, -6.25366}, {-28.1, -7.025, \
-4.89691}, {-21.075, -7.025, -2.50428}, {-14.05, -7.025, -2.30538}, \
{-7.025, -7.025, -0.74211}, {0, -7.025, -1.56745}, {7.025, -7.025,
1.69366}, {14.05, -7.025, 1.82772}, {21.075, -7.025,
8.61235}, {28.1, -7.025, 13.0684}, {35.125, -7.025,
14.1469}, {42.15, -7.025, 16.3767}, {49.175, -7.025,
23.8378}, {56.2, -7.025, 30.3019}, {63.225, -7.025,
31.9447}, {70.25, -7.025,
33.4267}, {-70.25, -14.05, -7.53985}, {-63.225, -14.05, -11.1067}, \
{-56.2, -14.05, -11.3531}, {-49.175, -14.05, -13.5927}, {-42.15, \
-14.05, -11.0226}, {-35.125, -14.05, -9.08983}, {-28.1, -14.05, \
-6.75024}, {-21.075, -14.05, -5.4674}, {-14.05, -14.05, -4.31102}, \
{-7.025, -14.05, -1.09751}, {0, -14.05, -1.8243}, {7.025, -14.05, \
-4.44589}, {14.05, -14.05, 2.10219}, {21.075, -14.05,
6.14893}, {28.1, -14.05, 10.2451}, {35.125, -14.05,
12.4137}, {42.15, -14.05, 18.8931}, {49.175, -14.05,
22.7164}, {56.2, -14.05, 28.9658}, {63.225, -14.05,
30.6962}, {70.25, -14.05,
31.1461}, {-70.25, -21.075, -10.5404}, {-63.225, -21.075, \
-12.6817}, {-56.2, -21.075, -13.8643}, {-49.175, -21.075, -14.8469}, \
{-42.15, -21.075, -14.1314}, {-35.125, -21.075, -10.8308}, {-28.1, \
-21.075, -7.40475}, {-21.075, -21.075, -7.16254}, {-14.05, -21.075, \
-5.79572}, {-7.025, -21.075, -1.28529}, {0, -21.075, -4.35527}, \
{7.025, -21.075, -3.40737}, {14.05, -21.075, -1.039}, {21.075, \
-21.075, 4.08568}, {28.1, -21.075, 10.0095}, {35.125, -21.075,
11.9082}, {42.15, -21.075, 16.793}, {49.175, -21.075,
20.2181}, {56.2, -21.075, 27.329}, {63.225, -21.075,
28.8499}, {70.25, -21.075,
30.3757}, {-70.25, -28.1, -10.8262}, {-63.225, -28.1, -15.2397}, \
{-56.2, -28.1, -15.9193}, {-49.175, -28.1, -16.774}, {-42.15, -28.1, \
-15.4521}, {-35.125, -28.1, -12.1127}, {-28.1, -28.1, -9.39629}, \
{-21.075, -28.1, -7.93003}, {-14.05, -28.1, -7.00959}, {-7.025, \
-28.1, -3.81162}, {0, -28.1, -5.34031}, {7.025, -28.1, -6.55177}, \
{14.05, -28.1, -1.43782}, {21.075, -28.1, 5.93424}, {28.1, -28.1,
9.01547}, {35.125, -28.1, 11.2629}, {42.15, -28.1,
14.7824}, {49.175, -28.1, 22.4174}, {56.2, -28.1,
27.7759}, {63.225, -28.1, 29.4223}, {70.25, -28.1,
29.9227}, {-70.25, -35.125, -13.1044}, {-63.225, -35.125, \
-16.1545}, {-56.2, -35.125, -16.9191}, {-49.175, -35.125, -18.2035}, \
{-42.15, -35.125, -16.9222}, {-35.125, -35.125, -14.0022}, {-28.1, \
-35.125, -12.1645}, {-21.075, -35.125, -9.84426}, {-14.05, -35.125, \
-7.6307}, {-7.025, -35.125, -4.90611}, {0, -35.125, -5.77962}, \
{7.025, -35.125, -8.07415}, {14.05, -35.125, -5.34047}, {21.075, \
-35.125, 4.96601}, {28.1, -35.125, 9.0764}, {35.125, -35.125,
9.80899}, {42.15, -35.125, 15.9153}, {49.175, -35.125,
21.9226}, {56.2, -35.125, 25.5205}, {63.225, -35.125,
27.9543}, {70.25, -35.125,
28.02}, {-70.25, -42.15, -14.8741}, {-63.225, -42.15, -18.5119}, \
{-56.2, -42.15, -18.686}, {-49.175, -42.15, -18.9576}, {-42.15, \
-42.15, -18.6903}, {-35.125, -42.15, -15.5602}, {-28.1, -42.15, \
-14.0747}, {-21.075, -42.15, -12.249}, {-14.05, -42.15, -9.55734}, \
{-7.025, -42.15, -6.77612}, {0, -42.15, -7.12248}, {7.025, -42.15, \
-9.47618}, {14.05, -42.15, -4.39971}, {21.075, -42.15,
4.24132}, {28.1, -42.15, 8.25018}, {35.125, -42.15,
10.8433}, {42.15, -42.15, 13.35}, {49.175, -42.15,
19.0219}, {56.2, -42.15, 26.2955}, {63.225, -42.15,
26.2803}, {70.25, -42.15,
27.2485}, {-70.25, -49.175, -16.3878}, {-63.225, -49.175, \
-20.6708}, {-56.2, -49.175, -21.0789}, {-49.175, -49.175, -20.3842}, \
{-42.15, -49.175, -20.5354}, {-35.125, -49.175, -16.4344}, {-28.1, \
-49.175, -16.0313}, {-21.075, -49.175, -12.805}, {-14.05, -49.175, \
-10.976}, {-7.025, -49.175, -6.88788}, {0, -49.175, -8.35904}, \
{7.025, -49.175, -8.70405}, {14.05, -49.175, -5.74029}, {21.075, \
-49.175, 2.74255}, {28.1, -49.175, 6.75932}, {35.125, -49.175,
10.6572}, {42.15, -49.175, 14.2083}, {49.175, -49.175,
19.7544}, {56.2, -49.175, 25.3201}, {63.225, -49.175,
25.7703}, {70.25, -49.175,
26.0245}, {-70.25, -56.2, -19.0208}, {-63.225, -56.2, -22.5624}, \
{-56.2, -56.2, -23.815}, {-49.175, -56.2, -22.9836}, {-42.15, -56.2, \
-22.5563}, {-35.125, -56.2, -19.5207}, {-28.1, -56.2, -17.6928}, \
{-21.075, -56.2, -14.6646}, {-14.05, -56.2, -11.5886}, {-7.025, \
-56.2, -8.17307}, {0, -56.2, -9.47397}, {7.025, -56.2, -9.75847}, \
{14.05, -56.2, -5.49651}, {21.075, -56.2, 0.496185}, {28.1, -56.2,
7.00603}, {35.125, -56.2, 9.8561}, {42.15, -56.2,
14.4364}, {49.175, -56.2, 17.8729}, {56.2, -56.2,
24.6927}, {63.225, -56.2, 24.7063}, {70.25, -56.2,
25.2221}, {-70.25, -63.225, -22.4694}, {-63.225, -63.225, \
-25.4452}, {-56.2, -63.225, -26.4798}, {-49.175, -63.225, -25.4398}, \
{-42.15, -63.225, -24.5895}, {-35.125, -63.225, -22.6314}, {-28.1, \
-63.225, -19.5583}, {-21.075, -63.225, -16.7519}, {-14.05, -63.225, \
-13.0518}, {-7.025, -63.225, -9.75556}, {0, -63.225, -10.4287}, \
{7.025, -63.225, -10.996}, {14.05, -63.225, -5.27794}, {21.075, \
-63.225, 0.795511}, {28.1, -63.225, 5.20413}, {35.125, -63.225,
8.83554}, {42.15, -63.225, 12.7182}, {49.175, -63.225,
18.6153}, {56.2, -63.225, 24.1265}, {63.225, -63.225,
24.6969}, {70.25, -63.225,
25.792}, {-70.25, -70.25, -24.266}, {-63.225, -70.25, -28.5245}, \
{-56.2, -70.25, -29.3176}, {-49.175, -70.25, -27.4251}, {-42.15, \
-70.25, -26.6102}, {-35.125, -70.25, -23.0384}, {-28.1, -70.25, \
-22.1094}, {-21.075, -70.25, -18.6816}, {-14.05, -70.25, -15.3735}, \
{-7.025, -70.25, -10.8826}, {0, -70.25, -11.7114}, {7.025, -70.25, \
-13.0119}, {14.05, -70.25, -8.12491}, {21.075, -70.25, -0.993662}, \
{28.1, -70.25, 4.2513}, {35.125, -70.25, 7.15842}, {42.15, -70.25,
11.3076}, {49.175, -70.25, 18.0335}, {56.2, -70.25,
23.8822}, {63.225, -70.25, 25.0456}, {70.25, -70.25, 25.2761}}


Listplot3d output shows that my data is, indeed, pretty rough:

Here's Graphics3D[BSplineSurface[ArrayReshape[data, {21, 21, 3}]]] view of it:

NB! The curvature in marked area is pretty important!

I attempted to fit a polynomial surface via Fit:

model = Level[
x + y + (x + y)^2 + (x + y)^3 + (x + y)^4 + (x + y)^5 + (x +
y)^6 + (x + y)^7 + (x + y)^8 + (x + y)^9 // Expand, {1}]
surfacefit = Fit[data, model, {x, y}]
Plot3D[surfacefit, {x, -75, 75}, {y, -75, 75}]


This does not seem to work well, no matter how high degree I try to fit with: curvature in important area is not captured.

Please, help me to get a smooth surface fit to my data!

• Can you clarify: do you have a model for the data, or do you want an interpolation? Additionally, does the output need to be a function or can it be a list of points that are on a finer mesh? Aug 10, 2021 at 11:55
• Welcome to Mathematica.SE! I hope you will become a regular contributor. To get started, 1) take the introductory tour now, 2) when you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge, 3) remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign, and 4) give help too, by answering questions in your areas of expertise. Aug 10, 2021 at 14:41
• "Adequate" is in the eye of the beholder. How good a fit do you need? Suppose the measure of adequate is the root mean square error. What value is needed for an adequate fit? (There is no magic formula that is devoid of subject matter knowledge that can give you an adequate fit.) (This, of course, ignores the possibility that the residuals are spatially correlated.)
– JimB
Aug 10, 2021 at 17:26

If all you want is an interpolation function, you'll need a very high order polynomial. Taking just one slice of data for example:

pts = Cases[data, {_, -56.2, _}][[All, 3]];
lm = LinearModelFit[Cases[data, {_, -56.2, _}][[All, 3]],
x^# & /@ Range[0, 11], x];
Plot[lm[x], {x, 1, 21},
Epilog -> {Red, Point@Transpose[{Range@Length@pts, pts}]}]


I arbitrarily chose an 11th order polynomial for this example. Note that I have ignored the x and y axes, so the fitted data does not have the same scale.

LinearModelFit can accept polynomials with 2 variables to fit your surface.

lm = LinearModelFit[
data, (x^# & /@ Range[0, 11]) ~Join ~( y^# & /@ Range[1, 10]), {x,
y}]
lm["RSquared"]
Show[Plot3D[lm[x, y], {x, -70, 70}, {y, -70, 70},
PlotStyle -> Opacity[0.5], Mesh -> None],
Graphics3D@{PointSize[.02], Black, Point@data}]


Here, I've chosen 11th and 10th order polynomials based on the "RSquared" of the fit. RSquared is not terribly useful as a goodness of fit for this type of scenario, but it provides me a single point comparison of different fitting functions. I stopped increasing the polynomial degree once the RSquared valued increased above 0.99.

You can obtain the function to use "outside of mathematica" with Normal@lm. Additionally, you could fiddle with the model by adding terms containing both x and y.

You can visually evaluate the goodness of fit by observing the residuals this way:

ListPlot3D[data /. {x_, y_, z_} :> {x, y, lm[x, y] - z}, Mesh -> None]


Alternatively, lm["FitResiduals"] provides the same information (actually, z - lm[x,y]).

• I guess, the optimal degree of polynomials can be determined by the analysis of residuals (or derivatives of the final function) inside the area of interest for 1D data-strings (as at the beginning of your answer). Just run the variation of polynomial's degree and look onto the corresponding changes of the values Sep 10, 2021 at 3:24