我有三个向量X
,Y
和Z
,它们代表在矩阵V
(即V = f(X,Y,Z)
)中找到的某些数据的3d坐标。以下是此数据的一些功能(假设/断言,如果需要的话):
X
和Y
的长度相同,(通常)与Z
的长度不同。
numel(X) == numel(Y);
X
中唯一元素的数量通常与Y
中唯一元素的数量不同。
Z
中的所有值都是唯一的。
numel(unique(Z)) == numel(Z);
V
的大小为[numel(X), numel(Z)]
。
过去,我没有区分X
和Y
,而是使用单个索引来引用它们,这使得绘制具有“ XY组合数字”的图表(例如1:numel(X)
)在一个轴上,Z
在另一个轴上,因此V
的大小很合适。
目前,我想分别查看X
和Y
的效果,这就是为什么我想使用scatter3
和{{3的混合物}}。
散点很容易,因为我可以repmat
X
和Y
沿其单例维度numel(Z)
次,Z
(使用numel(X)
)。结果是:
对于轮廓,这些要求将数据提供为3d阵列-这意味着我必须将这些点放置在结构化网格中。使用XX
创建网格坐标YY
,ZZ
,meshgrid
很简单:
[ XX, YY, ZZ ] = meshgrid( unique(X), unique(Y), unique(Z) );
我正在努力创建3d数组VV
。
从上图可以看出,大部分体积都不包含点-我非常想保持这种状态。换句话说,理想的VV
应该只包含与原始数据集相对应的点,其余的空间应该包含NaN
s。
诸如和
griddata
之类的函数执行插值,这将“填充”点云内部-这是极其不希望的。我认为这里可以使用索引来填充VV
中的值来填充V
,但我想不出一种方法。
我的问题是:如何生成不包含任何内插数据的VV
?
这是一个最小的例子:
%% 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) );
答案 0 :(得分: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)]);
这些数组的形状经过了调整,以使其与大小为XX
的数组[N,M,K]
等一起广播(“ bc”代表广播)。因此,逐元素比较现在可以工作了:
match = reshape((XX == Xbc) & (YY == Ybc) & (ZZ == Zbc), [size(XX), numel(V)]);
如果[N,M,K,P,Q]
的大小为V
,则此逻辑数组的大小为[P,Q]
。它包含所需的true
个数量完全相同:
>> 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);
现在,由于某种原因,我在结果中只看到3750个唯一索引:
>> numel(VV_inds)
ans =
5000
>> numel(unique(VV_inds))
ans =
3750
除了X
和Y
的值重复,您的某些原始数据点重叠外,我似乎找不到其他原因。因此,您实际上无法用唯一点的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
)对应于唯一的大小分别沿X
,Y
和Z
。
% 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;