comparison scripts/geometry/griddatan.m @ 28211:289882040316

griddatan.m: Rewrite docstring and redo input validation. * griddatan.m: Rewrite docstring. Redo input validation to make it more strict and error messages more specific. Add BIST tests for new input validation.
author Rik <rik@octave.org>
date Sun, 12 Apr 2020 18:14:05 -0700
parents bb929d5a34cb
children bb50407f9c60
comparison
equal deleted inserted replaced
28210:bb929d5a34cb 28211:289882040316
26 ## -*- texinfo -*- 26 ## -*- texinfo -*-
27 ## @deftypefn {} {@var{yi} =} griddatan (@var{x}, @var{y}, @var{xi}) 27 ## @deftypefn {} {@var{yi} =} griddatan (@var{x}, @var{y}, @var{xi})
28 ## @deftypefnx {} {@var{yi} =} griddatan (@var{x}, @var{y}, @var{xi}, @var{method}) 28 ## @deftypefnx {} {@var{yi} =} griddatan (@var{x}, @var{y}, @var{xi}, @var{method})
29 ## @deftypefnx {} {@var{yi} =} griddatan (@var{x}, @var{y}, @var{xi}, @var{method}, @var{options}) 29 ## @deftypefnx {} {@var{yi} =} griddatan (@var{x}, @var{y}, @var{xi}, @var{method}, @var{options})
30 ## 30 ##
31 ## Generate a regular mesh from irregular data using interpolation. 31 ## Interpolate irregular source data @var{x}, @var{y} at points specified by
32 ## @var{xi}.
32 ## 33 ##
33 ## The function is defined by @code{@var{y} = f (@var{x})}. 34 ## The input @var{x} is an MxN matrix representing M points in an N-dimensional
34 ## The interpolation points are all @var{xi}. 35 ## space. The input @var{y} is a single-valued column vector (Mx1)
36 ## representing a function evaluated at the points @var{x}, i.e.,
37 ## @code{@var{y} = fcn (@var{x})}. The input @var{xi} is a list of points
38 ## for which the function output @var{yi} should be approximated through
39 ## interpolation. @var{xi} must have the same number of columns (@var{N})
40 ## as @var{x} so that the dimensionality matches.
35 ## 41 ##
36 ## The interpolation method can be @qcode{"nearest"} or @qcode{"linear"}. 42 ## The optional input interpolation @var{method} can be @qcode{"nearest"} or
37 ## If method is omitted it defaults to @qcode{"linear"}. 43 ## @qcode{"linear"}. When the method is @qcode{"nearest"}, the output @var{yi}
44 ## will be the closest point in the original data @var{x} to the query point
45 ## @var{xi}. When the method is @qcode{"linear"}, the output @var{yi} will
46 ## be a linear interpolation between the two closest points in the original
47 ## source data. If @var{method} is omitted or empty, it defaults to
48 ## @qcode{"linear"}.
38 ## 49 ##
39 ## The optional argument @var{options} is passed directly to Qhull when 50 ## The optional argument @var{options} is passed directly to Qhull when
40 ## computing the Delaunay triangulation used for interpolation. See 51 ## computing the Delaunay triangulation used for interpolation. See
41 ## @code{delaunayn} for information on the defaults and how to pass different 52 ## @code{delaunayn} for information on the defaults and how to pass different
42 ## values. 53 ## values.
54 ##
55 ## Example
56 ##
57 ## @example
58 ## @group
59 ## ## Evaluate sombrero() function at irregular data points
60 ## x = 16*gallery ("uniformdata", [200,1], 1) - 8;
61 ## y = 16*gallery ("uniformdata", [200,1], 11) - 8;
62 ## z = sin (sqrt (x.^2 + y.^2)) ./ sqrt (x.^2 + y.^2);
63 ## ## Create a regular grid and interpolate data
64 ## [xi, yi] = ndgrid (linspace (-8, 8, 50));
65 ## zi = griddatan ([x, y], z, [xi(:), yi(:)]);
66 ## zi = reshape (zi, size (xi));
67 ## ## Plot results
68 ## clf ();
69 ## plot3 (x, y, z, "or");
70 ## hold on
71 ## surf (xi, yi, zi);
72 ## legend ("Original Data", "Interpolated Data");
73 ## @end group
74 ## @end example
75 ##
76 ## Programming Notes: If the input is complex the real and imaginary parts
77 ## are interpolated separately. For 2-D and 3-D data additional interpolation
78 ## methods are available by using the @code{griddata} function.
43 ## @seealso{griddata, griddata3, delaunayn} 79 ## @seealso{griddata, griddata3, delaunayn}
44 ## @end deftypefn 80 ## @end deftypefn
45 81
46 function yi = griddatan (x, y, xi, method = "linear", varargin) 82 function yi = griddatan (x, y, xi, method = "linear", varargin)
47 83
48 if (nargin < 3) 84 if (nargin < 3)
49 print_usage (); 85 print_usage ();
50 endif 86 endif
51 87
52 if (ischar (method))
53 method = tolower (method);
54 endif
55
56 [m, n] = size (x); 88 [m, n] = size (x);
57 [mi, ni] = size (xi); 89 [mi, ni] = size (xi);
58 90
59 if (n != ni || rows (y) != m || columns (y) != 1) 91 if (m < n + 1)
60 error ("griddatan: dimensional mismatch"); 92 error ("griddatan: number of points in X (rows of X) must be greater than dimensionality of data + 1 (columns of X + 1)");
93 endif
94 if (! iscolumn (y) || rows (y) != m)
95 error ("griddatan: Y must be a column vector with the same number of points (rows) as X");
96 endif
97 if (n != ni)
98 error ("griddatan: dimension of query data XI (columns) must match X");
99 endif
100
101 if (nargin > 3)
102 if (isempty (method))
103 method = "linear";
104 elseif (! ischar (method))
105 error ("griddatan: METHOD must be a string");
106 endif
107
108 method = tolower (method);
109 if (strcmp (method, "linear") || strcmp (method, "nearest"))
110 ## Do nothing, these are implemented methods
111 elseif (any (strcmp (method, {"cubic", "v4"})))
112 error ('griddatan: "%s" METHOD is available for 2-D inputs by using "griddata"', method);
113
114 elseif (strcmp (method, "natural"))
115 ## FIXME: Remove when griddata.m supports "natural" method.
116 error ('griddatan: "natural" interpolation METHOD not yet implemented');
117
118 else
119 error ('griddatan: unknown interpolation METHOD: "%s"', method);
120 endif
121
61 endif 122 endif
62 123
63 ## triangulate data 124 ## triangulate data
64 tri = delaunayn (x, varargin{:}); 125 tri = delaunayn (x, varargin{:});
65 126
66 yi = NaN (mi, 1); 127 yi = NaN (mi, 1);
67 128
68 if (strcmp (method, "nearest")) 129 if (strcmp (method, "linear"))
69 ## search index of nearest point
70 idx = dsearchn (x, tri, xi);
71 valid = ! isnan (idx);
72 yi(valid) = y(idx(valid));
73
74 elseif (strcmp (method, "linear"))
75 ## search for every point the enclosing triangle 130 ## search for every point the enclosing triangle
76 [tri_list, bary_list] = tsearchn (x, tri, xi); 131 [tri_list, bary_list] = tsearchn (x, tri, xi);
77 132
78 ## only keep the points within triangles. 133 ## only keep the points within triangles.
79 valid = ! isnan (tri_list); 134 valid = ! isnan (tri_list);
87 yi(valid) = sum (y(tri(tri_list,:)).' .* bary_list, 2); 142 yi(valid) = sum (y(tri(tri_list,:)).' .* bary_list, 2);
88 else 143 else
89 yi(valid) = sum (y(tri(tri_list,:)) .* bary_list, 2); 144 yi(valid) = sum (y(tri(tri_list,:)) .* bary_list, 2);
90 endif 145 endif
91 146
92 elseif (any (strcmp (method, {"cubic", "v4"}))) 147 else
93 error ('griddata: "%s" METHOD only valid for 2-D inputs using "griddata"', method); 148 ## search index of nearest point
149 idx = dsearchn (x, tri, xi);
150 valid = ! isnan (idx);
151 yi(valid) = y(idx(valid));
94 152
95 elseif (strcmp (method, "natural"))
96 ## FIXME: implement missing interpolation method 'natural' for 3-D inputs.
97 error ('griddatan: "natural" interpolation METHOD not yet implemented');
98
99 else
100 error ('griddatan: unknown interpolation METHOD: "%s"', method);
101 endif 153 endif
102 154
103 endfunction 155 endfunction
104 156
105 157
107 %! [xx,yy] = meshgrid (linspace (-1,1,32)); 159 %! [xx,yy] = meshgrid (linspace (-1,1,32));
108 %! xi = [xx(:), yy(:)]; 160 %! xi = [xx(:), yy(:)];
109 %! x = 2*rand (100,2) - 1; 161 %! x = 2*rand (100,2) - 1;
110 %! x = [x;1,1;1,-1;-1,-1;-1,1]; 162 %! x = [x;1,1;1,-1;-1,-1;-1,1];
111 %! y = sin (2 * sum (x.^2,2)); 163 %! y = sin (2 * sum (x.^2,2));
112 %! zz = griddatan (x,y,xi,"linear"); 164 %! zz = griddatan (x,y,xi, "linear");
113 %! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2),"linear"); 165 %! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2), "linear");
114 %! assert (zz, zz2, 1e-10); 166 %! assert (zz, zz2, 1e-10);
115 167
116 %!testif HAVE_QHULL 168 %!testif HAVE_QHULL
117 %! [xx,yy] = meshgrid (linspace (-1,1,32)); 169 %! [xx,yy] = meshgrid (linspace (-1,1,32));
118 %! xi = [xx(:), yy(:)]; 170 %! xi = [xx(:), yy(:)];
119 %! x = 2*rand (100,2) - 1; 171 %! x = 2*rand (100,2) - 1;
120 %! x = [x;1,1;1,-1;-1,-1;-1,1]; 172 %! x = [x;1,1;1,-1;-1,-1;-1,1];
121 %! y = sin (2*sum (x.^2,2)); 173 %! y = sin (2*sum (x.^2,2));
122 %! zz = griddatan (x,y,xi,"nearest"); 174 %! zz = griddatan (x,y,xi, "nearest");
123 %! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2),"nearest"); 175 %! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2), "nearest");
124 %! assert (zz, zz2, 1e-10); 176 %! assert (zz, zz2, 1e-10);
125 177
126 %!testif HAVE_QHULL <*56515> 178 %!testif HAVE_QHULL <*56515>
127 %! x = [ 0, 0; 1, 1; 0, 1; 1, 0 ]; 179 %! x = [ 0, 0; 1, 1; 0, 1; 1, 0 ];
128 %! y = [ 1; 2; 3; 4 ]; 180 %! y = [ 1; 2; 3; 4 ];
131 183
132 ## Test input validation 184 ## Test input validation
133 %!error griddatan () 185 %!error griddatan ()
134 %!error griddatan (1) 186 %!error griddatan (1)
135 %!error griddatan (1,2) 187 %!error griddatan (1,2)
136 %!error griddatan (1,2,3) 188 %!error <number of points in X> griddatan (1,2,3)
137 %!error <OPTIONS argument must be a string> griddatan (1,2,3,4,5) 189 %!error <Y must be a column vector> griddatan ([1;2],[3,4], 1)
138 %!error <unknown interpolation METHOD> griddatan (1,2,3,4) 190 %!error <Y must .* same number of points .* as X> griddatan ([1;2],[3;4;5], 1)
139 %!#error <"v4" METHOD only valid for 2-D inputs> 191 %!error <dimension of .* XI .* must match X> griddatan ([1;2],[3;4], [1, 2])
140 %! griddatan (ones(2,2,2), 2*ones(2,2,2), 3, "v4") 192 %!error <METHOD must be a string> griddatan ([1;2],[3;4], 1, 5)
141 %!error <"cubic" METHOD only valid for> griddatan (1, 2, 3, "cubic") 193 %!error <"v4" METHOD is available for 2-D> griddatan ([1;2],[3;4], 1, "v4")
142 %!error <"natural" .* not yet implemented> griddatan (1, 2, 3, "natural") 194 %!error <"cubic" METHOD is available> griddatan ([1;2],[3;4], 1, "cubic")
143 %!error <unknown interpolation METHOD: "foobar"> griddatan (1, 2, 3, "foobar") 195 %!error <"natural" .* not yet implemented> griddatan ([1;2],[3;4], 1, "natural")
196 %!error <unknown .* METHOD: "foobar"> griddatan ([1;2],[3;4], 1, "foobar")