首页 文章

网格化分散数据,无需插值

提问于
浏览
2

我有三个向量, XYZ ,它们表示在矩阵 V 中找到的一些数据的3d坐标(即 V = f(X,Y,Z) ) . 以下是此数据的一些功能(假设/断言,如果您愿意):

  • XY 具有相同的长度,(通常)与 Z 不同 .
numel(X) == numel(Y);
  • X 中的唯一元素数量通常与 Y 中的唯一元素数量不同 .

  • Z 中的所有值都是唯一的 .

numel(unique(Z)) == numel(Z);
  • V 的大小为 [numel(X), numel(Z)] .

在过去,我没有区分 XY ,并且我使用单个索引引用它们,这使得在一个轴上绘制"XY combination number"(即 1:numel(X) )而在另一个轴上绘制 Z 的图表变得容易,因此大小的 V 很好地解决了 .

目前,我想分别看到 XY 的影响,这就是为什么我想在3d中使用scatter3contourslice的混合来想象这个 .

分散部分很容易,因为我可以沿着它们的单个维度 numel(Z)repmat XY ,对于 Z (使用 numel(X) )也是如此 . 这导致:

Result of the scatter

至于轮廓,这些要求数据作为3d数组提供 - 这意味着我必须将点放在结构化网格中 . 使用 meshgrid 创建网格坐标 XXYYZZ 非常简单:

[ XX, YY, ZZ ] = meshgrid( unique(X), unique(Y), unique(Z) );

我正在努力的是创建3d数组 VV .

从上图中我们可以看到大部分音量都不包含点 - 我非常想 keep it that way . 换句话说,理想的 VV 应仅包含与原始数据集对应的点,其余空间应包含 NaN s .

griddatainterp3这样的函数执行插值,这将在点 Cloud 之内"fill holes",这是 extremely undesired . 我认为这里可以使用索引来使用 V 中的值填充 VV ,但我想不出办法来做到这一点 .

我的问题是: how can I generate VV that does not contain any interpolated data

这是一个最小的例子:

%% Generate some data:
X = randi(10,100,1);
Y = randi(15,100,1) - 5;
Z = 1:50;
V = X./Y.*Z;

%% Scatter plot:
nXY = numel(X); nZ = numel(Z);
figure();
scatter3( reshape( repmat(X,[1, nZ]),  [], 1), ...
          reshape( repmat(Y,[1, nZ]),  [], 1), ...
          reshape( repmat(Z,[nXY, 1]), [], 1), ...
          [], V(:), '.');

%% Contours:
% Create the 3d grid:
[XX, YY, ZZ] = meshgrid( unique(X), unique(Y), unique(Z) );

% Preallocate VV:
VV = NaN(size(XX));

% Populate VV: <--------------------------------------------- Help needed with this stage
ind = randperm( numel(XX), numel(V) ); % PLACEHOLDER 
VV(ind) = V;

% Plot:
hold on; contourslice(XX, YY, ZZ, VV, X(2), Y(3), Z(10) );

1 回答

  • 2

    我相信通过将所有网格化索引与所有线性数据点相匹配,可能存在一种过度的方法 . 为此,我们需要注入几个维度,以便将3d数组 XX 等与2d数组 X 等元素进行比较:

    Xbc = reshape(X, [1,1,1,size(X)]);
    Ybc = reshape(Y, [1,1,1,size(Y)]);
    Zbc = reshape(Z, [1,1,1,size(Z)]);
    

    这些数组被重新整形,以便使用大小为 [N,M,K] 的数组 XX 等进行广播("bc"代表广播) . 所以元素比较现在起作用:

    match = reshape((XX == Xbc) & (YY == Ybc) & (ZZ == Zbc), [size(XX), numel(V)]);
    

    如果 V 的大小为 [P,Q] ,则此逻辑数组的大小为 [N,M,K,P,Q] . 它包含任意数量的 true s:

    >> sum(match(:)) == numel(V)
    
    ans =
    
      logical
    
       1
    

    所以现在我们需要从前三个维度中选出相应的索引,并将它们与 V 的正确元素配对 . 我们需要一些线性到多指数的弯头润滑脂:

    [ii,jj,kk,ll] = ind2sub(size(match), find(match));
    

    现在左侧的所有数组都是 [numel(V), 1] ;前三个给你 XX 等索引,最后一个给索引 V .

    V_inds = ll;
    VV_inds = sub2ind(size(VV), ii, jj, kk);
    
    VV(VV_inds) = V(V_inds);
    

    现在,出于某种原因,我在结果中只看到了5000个中的3750个唯一索引:

    >> numel(VV_inds)           
    
    ans =
    
            5000
    
    >> numel(unique(VV_inds))
    
    ans =
    
            3750
    

    我似乎找不到任何其他原因,因为你的一些原始数据点由于 XY 的重复而重叠,所以你实际上不能在3d网格中表示它们的独特点(因为一些3d点包含多个数据点) . 我相信以下证明了这一点:

    >> size(unique([X,Y], 'rows'))
    
    ans =
    
        75     2
    
    >> size([X,Y])
    
    ans =
    
       100     2
    

    有100对 (x,y) 对,但只有75对 . 无论你如何将它们与正交 z 点集合在一起,你最终都会重复你的观点 . 因此,您要么必须剔除原始数据中的冗余,要么需要找到另一种表示(或者采用冲突值的均值) .


    我想我也有一个更有效的版本,使用 unique 在其运行期间生成的索引 . 请注意,我使用 meshgrid 而不是 ndgrid 来生成网格,以便生成的数组(以及 VV )的维度分别对应于 XYZ 的唯一大小 .

    % take the indices
    [uX, ~, iX] = unique(X);
    [uY, ~, iY] = unique(Y);
    [uZ, ~, iZ] = unique(Z);
    
    % generate mesh and allocate result
    [XX, YY, ZZ] = ndgrid(uX, uY, uZ);
    VV = NaN(size(XX));
    
    % switch from `iX`, `iY` and `iZ` to a 2d mesh of size `[P,Q]` where `iX` and `iY` are of size `[P,1]` and `iZ` is of size `[Q,1`]:
    % a.k.a. lazy repmat
    iXbig = iX + 0*iZ.';
    iYbig = iY + 0*iZ.';
    iZbig = iZ.' + 0*iX;
    
    % turn 3d indices into linear index into VV
    VV_inds = sub2ind(size(VV), iXbig, iYbig, iZbig);
    
    % profit
    VV(VV_inds) = V;
    

相关问题