changeset 32726:d970ec60aa64

griddata: Match output size to vector interpolation points. (bug #65134) * scripts/geometry/griddata.m: Change check for xi and yi so either row-column combination passes them through meshgrid. Remove check that casts all vectors to column vectors. Make size_equal check of xi and yi only if the meshgrid codepath was not used. Add BIST verifying correct output shape for row-column interpolating input combinations. Update expected output orientation in test for bug #65146. Update docstring noting new behavior. * etc/NEWS.10.md: Note change to griddata behavior under Matlab Compatibility.
author Nicholas R. Jankowski <jankowski.nicholas@gmail.com>
date Wed, 10 Jan 2024 17:54:55 -0500
parents 5f1297f61e54
children e36a95093ef6
files etc/NEWS.10.md scripts/geometry/griddata.m
diffstat 2 files changed, 49 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/etc/NEWS.10.md	Wed Jan 10 17:36:53 2024 -0800
+++ b/etc/NEWS.10.md	Wed Jan 10 17:54:55 2024 -0500
@@ -31,6 +31,12 @@
 - All colormaps now default to a size of 256 colors. (The previous default
 size was 64.
 
+- `griddata` output size more consistently matches the input interpolation
+points when they are input as vectors.  When they are same-orientation vectors,
+the outputs will be the same size as those vectors.  When either is a row
+vector and the other is a column vector, the interpolating points are processed
+through meshgrid and the output is a matrix the same size as the meshgrid.
+
 ### Alphabetical list of new functions added in Octave 10
 
 * `rticklabels`
--- a/scripts/geometry/griddata.m	Wed Jan 10 17:36:53 2024 -0800
+++ b/scripts/geometry/griddata.m	Wed Jan 10 17:54:55 2024 -0500
@@ -40,9 +40,10 @@
 ## @code{meshgrid} and @var{z} is a 2-D matrix matching the resulting size of
 ## the X-Y grid.
 ##
-## The interpolation points are (@var{xi}, @var{yi}).  If, and only if,
-## @var{xi} is a row vector and @var{yi} is a column vector, then
-## @code{meshgrid} will be used to create a mesh of interpolation points.
+## The interpolation points are (@var{xi}, @var{yi}).  If either @var{xi} or
+## @var{y} is a row vector and the other is a column vector, then
+## @code{meshgrid (@var{xi}, @var{yi})} will be used to create a mesh of
+## interpolation points.
 ##
 ## For 3-D interpolation, the inputs @var{x}, @var{y}, and @var{z} define the
 ## points where the function @code{@var{v} = f (@var{x}, @var{y}, @var{z})}
@@ -51,6 +52,10 @@
 ## a 3-D grid with @code{meshgrid}.  The size of the input @var{v} must match
 ## the size of the original data, either as a vector or a matrix.
 ##
+## The outputs @var{zi} (for 2-D) or @var{vi} (for 3-D) will contain the
+## interpolated values of @var{z} or @var{v}, respectively, with the output
+## size matching that of the interpolation points.
+##
 ## The optional input interpolation @var{method} can be @qcode{"nearest"},
 ## @qcode{"linear"}, or for 2-D data @qcode{"v4"}.  When the method is
 ## @qcode{"nearest"}, the output @var{vi} will be the closest point in the
@@ -110,18 +115,15 @@
       error ("griddata: lengths of X, Y must match the columns and rows of Z");
     endif
 
-    ## Meshgrid xi and yi if they are a row and column vector, but not
-    ## if they are simply vectors of the same size (for compatibility).
-    if (isrow (xi) && iscolumn (yi))
+    ## Meshgrid xi and yi if one is a row vector and the other is a column
+    ## vector, but not if they are vectors with the same orientation.
+    if ((isrow (xi) && iscolumn (yi)) || (iscolumn (xi) && isrow (yi)))
       [xi, yi] = meshgrid (xi, yi);
-    elseif (isvector (xi) && isvector (yi))
-      ## Otherwise, convert to column vectors
-      xi = xi(:);
-      yi = yi(:);
-    endif
-
-    if (! size_equal (xi, yi))
-      error ("griddata: XI and YI must be vectors or matrices of same size");
+    else
+      ## Ensure vector and matrix query point inputs are identically sized.
+      if (! size_equal (xi, yi))
+        error ("griddata: XI and YI must be vectors or matrices of same size");
+      endif
     endif
 
     if (nargin == 6)
@@ -334,12 +336,36 @@
 %!testif HAVE_QHULL <*65146> # Ensure correct output for 3-point queries.
 %! xi = [1 2 3];
 %! a = griddata (xi, xi, xi .* xi', xi, xi, "linear");
-%! assert (a, [1, 4, 9]', 10*eps);
+%! assert (a, [1, 4, 9], 10*eps);
 %! a = griddata (xi, xi, xi .* xi', xi', xi', "linear");
 %! assert (a, [1, 4, 9]', 10*eps);
 %! a = griddata (xi, xi, xi .* xi', [xi; xi], [xi; xi], "linear");
 %! assert (a, [1, 4, 9; 1, 4, 9], 10*eps);
 
+## Verify output orientation for various input vector shape combinations
+%!testif HAVE_QHULL <*65134>
+%! x = [1:10];
+%! y = [1:10];
+%! z = x .* y';
+%! xi = [1, 5, 10];
+%! yi = [1, 5];
+%! [xx, yy, vv] = griddata (x, y, z, xi, xi, 'nearest'); # Row, Row
+%! assert (xx, xi);
+%! assert (yy, xi);
+%! assert (size (vv), [1, 3]);
+%! [xx, yy, vv] = griddata (x, y, z, xi', xi', 'nearest'); # Col, Col
+%! assert (xx, xi');
+%! assert (yy, xi');
+%! assert (size (vv), [3, 1]);
+%! [xx, yy, vv] = griddata (x, y, z, xi, yi', 'nearest'); # Row, Col
+%! assert (xx, [xi; xi]);
+%! assert (yy, [yi', yi', yi']);
+%! assert (vv, [1, 5, 10; 5, 25, 50]);
+%! [xx, yy, vv] = griddata (x, y, z, xi', yi, 'nearest'); # Col, Row
+%! assert (xx, [xi; xi]);
+%! assert (yy, [yi', yi', yi']);
+%! assert (vv, [1, 5, 10; 5, 25, 50]);
+
 ## Test input validation
 %!error <Invalid call> griddata ()
 %!error <Invalid call> griddata (1)
@@ -354,6 +380,8 @@
 %!error <the columns and rows of Z> griddata (1:4, 1:3, ones (3,5), 1:3, 1:3)
 %!error <XI and YI .* matrices of same size> griddata (1:3, 1:3, 1:3, 1:4, 1:3)
 %!error <XI and YI .* matrices of same size> griddata (1:3, 1:3, 1:3, 1:3, 1:4)
+%!error <XI and YI .* matrices of same size> griddata (1:3, 1:3, 1:3, [1:4]', [1:3]')
+%!error <XI and YI .* matrices of same size> griddata (1:3, 1:3, 1:3, [1:3]', [1:4]')
 %!error <METHOD must be a string> griddata (1,2,3,4,5, {"linear"})
 %!error <"cubic" .* not yet implemented> griddata (1,2,3,4,5, "cubic")
 %!error <"natural" .* not yet implemented> griddata (1,2,3,4,5, "natural")