在MATLAB中为Voronoi图的无界单元格着色

5

我有两组点,用蓝色星号和红色圆点进行绘制。然后使用 voronoi(X,Y) 函数绘制这两组点的 Voronoi 图。我想根据每个细胞所属的点集指定其颜色。我已经通过使用 patch 函数几乎完成了这个任务,方法如下:

     [v,c]=voronoin(D);
     for p=1:TheNumberOfSets
       r=rand()/2+0.5;    % random gray color
       col=[r r r];
       for s=1:PointsInSet(p)
           l=l+1;
           patch(v(c{l},1),v(c{l},2),col);  % color
           axis([0 10 0 10]);
       end
     end

其中D是集合点的坐标,TheNumberOfSets表示我们有多少个集合(在这个特定部分中我们只有两个集合),col指定一个随机灰色,PointsInSet指定每个集合中有多少个点,l用于列举 Voronoi 图的单元格。

以下是结果:enter image description here

现在我的问题(如您所见!)是关于无界单元格。这段代码仅更改有界单元格的颜色,我想用它们指定的集合颜色在轴框范围内(即您可以在图像中看到的框)中着色无界单元格。

有什么建议吗?


1
请问您能否添加TheNumberOfSetsPointsInSetlvccol以及其他可能遗漏的示例信息吗?请参考MCVE上的帮助文件,了解如何制作一个合适的问题示例。 - Franz Hahn
我已经添加了更多的信息。@FranzHahn - pooria haddad
l怎么样? - Franz Hahn
正如您在问题中所读到的,我说:“...并且'l'用于枚举Voronoi图的单元格。” 我使用它逐个着色单元格。 您有任何建议的代码或算法可以告诉我吗?! @FranzHahn - pooria haddad
我非常想帮助你,但我不知道你的变量实际上是什么样子。你能为每个变量添加初始化吗?mcve指南建议您的帖子包含信息,以便您“[确保包含了重现问题所需的所有信息]”。有了初始化,我就可以研究一下了。 - Franz Hahn
1
选择 lcol 与问题无关,因此尽管更好的 MCVE 应该采用更直接的方法来定义它们,这是值得欢迎的,但我的答案忽略了这个示例的这个方面,并且只要 lc 的有效索引,col 是有效的颜色,就可以工作。 - Will
2个回答

2

看起来在Matlab R2018a或之后的版本中(R2014b可以,但我没有测试R2015〜R2016),voronoi函数不会像以前预期的那样返回相同的h值,尽管该函数的文档没有改变。在R2018a中,它返回

最初的回答:

 h(1)

ans = 

 handle to deleted Data

在 R2014b 中它返回"最初的回答"。
h(1)

ans = 

  Line with properties:

              Color: [0 0.4470 0.7410]
          LineStyle: 'none'
          LineWidth: 0.5000
             Marker: '.'
         MarkerSize: 6
    MarkerFaceColor: 'none'
              XData: [1x200 double]
              YData: [1x200 double]
              ZData: [1x0 double]

  Show all properties

我想知道在新版本中有没有提取无界单元格的线条和顶点的方法。

最初的回答:


1
您的示例确实为无界单元格创建了patch对象,但是因为它们包含具有表示无界边的Inf值的顶点,所以它们不会显示。您需要用有限的顶点替换这些顶点才能完成补丁。
通过voronoi生成绘制无界单元格边缘的顶点对于此目的非常有用。在绘制Voronoi图时可以获得这些内容:
h = voronoi(D);
v1 = shiftdim(reshape([h(2).XData;h(2).YData],2,3,[]),2); % Arranged one edge per row, one vertex per slice in the third dimension

未限定的边界最后绘制,因此您可以通过计算c中未限定单元格的数量来将其隔离:
nUnbounded = sum(cellfun(@(ic)ismember(1,ic),c));
v1Unbounded = v1(end-(nUnbounded-1):end,:,:);

这些边的第一个列出的顶点是该单元的有限顶点。由于浮点误差,它们并不总是完全匹配voronoin返回的坐标,因此通过使用pdist2找到最小成对距离来确定它们对应的编号顶点:
[~,iBounded] = min(pdist2(v,v1Unbounded(:,:,1))); % Index of the bounded vertex
vUnbounded = v1Unbounded(:,:,2); % Displayed coordinate of the unbounded end of the cell edge

要替换这些坐标,您可以使用以下内容替换patch(v(c{l},1),v(c{l},2),col);:
cPatch = c{l}; % List of vertex indices
vPatch = v(cPatch,:); % Vertex coordinates which may contain Inf
idx = find(cPatch==1); % Check if cell has unbounded edges
if idx
    cPatch = circshift(cPatch,-idx); % Move the 1 to the end of the list of vertex indices
    vPatch = [vPatch(1:idx-1,:)
              vUnbounded(iBounded == cPatch(end-1),:)
              vUnbounded(iBounded == cPatch(1),:)
              vPatch(idx+1:end,:)]; % Replace Inf values at idx with coordinates from the unbounded edges that meet the two adjacent finite vertices
end
patch(vPatch(:,1),vPatch(:,2),col);

非常感谢您的出色回答(一个月后,您是第一个)。 我只有一个问题无法运行您的代码。 在h = voronoi(D);之后,h只有一列而不是两个图表线,因此我收到错误:h(2).XData的索引矩阵引用不正确。 当然,我使用的是MATLAB R2014a,并看到了mathworks中的注意:h = voronoi(..)的行为已更改。 新行为返回一个包含两个图表线句柄的向量;一个表示点,另一个表示Voronoi边缘。 您有任何想法@Will? 再次感谢 - pooria haddad
哦,亲爱的!看起来在R2014a中,线条坐标仍可通过返回的h句柄访问,但句柄的顺序和线条数据的结构可能不如上述描述,并且您不能使用像.XData这样的点符号来访问它。它根本没有明确记录,因此需要进行一些探索,以确定在哪里找到正确的值以替换为上面的“patch”输入。如果我记得正确,您应该能够使用get(h,{'XData','YData'})访问所有线条数据。 - Will
再次感谢@Will。我尝试了get(h,{'XData','YData'}),得到了一个7个点的14x2单元格类,像这样:第一行:[1x7 double] [1x7 double]第二行:[1x2 double] [1x2 double]第三行:[1x2 double] [1x2 double] ...我会尝试弄清楚并将其适配到我的代码中,我知道你的答案是正确的。谢谢。 - pooria haddad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接