如何使用MATLAB绘制邻接矩阵图

8
我想创建一个图表,显示类似下面这样的邻接矩阵中节点之间的连接关系。

enter image description here

gplot 似乎是最好的工具。然而,为了使用它,我需要传递每个节点的坐标。问题是我不知道坐标应该在哪里,我希望函数能够为我找到一个良好的布局。

例如,以下是使用任意坐标的输出:

 A = [1 1 0 0 1 0;
      1 0 1 0 1 0;
      0 1 0 1 0 0;
      0 0 1 0 1 1;
      1 1 0 1 0 0;
      0 0 0 1 0 0];

 crd = [0 1;
        1 1;
        2 1;
        0 2;
        1 2;
        2 2];

 gplot (A, crd, "o-");

enter image description here

这段话有些难以理解,但是如果我稍微调整一下坐标并将其更改为以下内容,它就变得更加易读了。

   crd = [0.5 0;
         0 1;
         0 2;
         1 2;
         1 1;
         1.5 2.5];

enter image description here

我不需要完美优化的坐标,但我该如何让MATLAB自动找出一组看起来不错的坐标,以便使用某种算法绘制类似于顶部图片的图形。
提前致谢。
3个回答

5
自R2015b版本开始,MATLAB现在具有一套图形和网络算法。对于这个例子,您可以创建一个无向图对象,然后使用重载的plot函数绘制它:
% Create symmetric adjacency matrix
A = [1 1 0 0 1 0;
     1 0 1 0 1 0;
     0 1 0 1 0 0;
     0 0 1 0 1 1;
     1 1 0 1 0 0;
     0 0 0 1 0 0];
% Create undirected graph object
G = graph(A);
% Plot
plot(G);

Layout created using MATLAB's graph/plot function


谢谢!我在R2016b上测试了这个,它正如我在发帖时想要的那样工作。很高兴看到问题得到解决,而不需要第三方解决方案。 - Charles Clayton

5
一种方法是编写自己的算法,使用某种静电斥力,就像你链接的论文中所述。可以在不到40行Matlab代码中完成(似乎其他人也尝试过)。但有时候,使用外部工具比在Matlab中完成所有工作更好。绘制图形的最佳工具可能是Graphviz,它带有一套用于绘制不同样式图形的工具。对于无向图,要使用的是neato。我不知道它使用哪个算法来分配节点,但我猜它与你的论文中的算法类似(其中一篇参考文献甚至提到了Graphviz!)。
这些工具的输入是非常简单的文本格式,使用Matlab生成足够容易。例如(在Linux上运行,您可能需要在Windows上稍微更改一下):
% adjacency matrix
A = [1 1 0 0 1 0;
     1 0 1 0 1 0;
     0 1 0 1 0 0;
     0 0 1 0 1 1;
     1 1 0 1 0 0;
     0 0 0 1 0 0];

% node labels, these must be unique
nodes = {'A', 'B', 'C', 'D', 'E', 'F'};

n = length(nodes);
assert(all(size(A) == n))

% generate dot file for neato
fid = fopen('test.dot', 'w');
fprintf(fid, 'graph G {\n');
for i = 1:n
    for j = i:n
        if A(i, j)
            fprintf(fid, '    %s -- %s;\n', nodes{i}, nodes{j});
        end
    end
end
fprintf(fid, '}\n');
fclose(fid);

% render dot file
system('neato -Tpng test.dot -o test.png')

这将生成文件test.dot

graph G {
    A -- A;
    A -- B;
    A -- E;
    B -- C;
    B -- E;
    C -- D;
    D -- E;
    D -- F;
}

最后,一个图片test.png(请注意,你的邻接矩阵列出了第一个项目与自身的连接,这在节点A处显示为循环):

enter image description here

作为一个更复杂的例子,您可以像gplot文档中所示绘制一个bucky-ball。
[A, XY] = bucky;
nodes = arrayfun(@(i) num2str(i), 1:size(A,1), 'uni', 0);

结果如下(请注意布局是由 neato 提供的,不使用 XY):

enter image description here


1
如果你的图是连通的,构造传递给gplot的数组xy的方法是v(:,[2 3]),其中v是拉普拉斯矩阵的特征向量矩阵,按从最小特征值到最大特征值排序。因此我们可以这样做:
L=diag(sum(A))-A;
[v,~]=eig(L);
xy=v(:,[2 3])
gplot(A,xy)

或者这样做:
L=diag(sum(A))-A;
[v,~]=eigs(L,3,'SM')
xy=v(:,[2 1])
gplot(A,xy)

第二个方法应该更有效率,特别是当A很大的时候。
在正常情况下,这将创建一个漂亮的图。不能保证一定会成功;特别是不能保证为不同的节点分配不同的坐标。但通常情况下,它表现得相当不错。
可以在https://arxiv.org/pdf/1311.2492.pdf找到相关理论。

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