6

在 Mathematica 8 中是否有一种简单的方法可以执行以下操作?

  1. 构建一个图形,并使用一些图形布局显示它。
  2. 稍微修改图形(例如添加或删除边或顶点)。
  3. 从原始布局开始重新计算布局,以或多或少保留对象的“形状”。例如,从先前布局的坐标开始重新运行弹簧电动布局算法。

如果图表在两个显示之间没有改变,那么布局也不应该改变(或者只是最小的改变)。使用新的显示器GraphGraphPlot两者都可以接受。

编辑:本质上我需要类似图形的类似布局。我总是通过修改可能已经布置好的现有图表来获得类似的图表,但任何通用解决方案都是可以接受的。

编辑2:这是这种东西有用的例子。转到http://ccl.northwestern.edu/netlogo/models/GiantComponent并单击“在浏览器中运行”(需要 Java)。单击设置,然后单击开始。您可以看到图表的演变。如果我们在 Mathematica 中这样做,那么每个连续的图看起来都会完全不同,并且很难看出它是在进化的同一个图。在一些应用程序中,能够将图形的微小变化可视化是非常有用的。但是如果做了很多连续的改变,那么重新计算布局是必须的,简单地淡化或突出边缘是不够的。再说一次,这只是一个例子:我不是想使用 Mathematica 来为图形制作动画,或者将巨型组件的出现可视化。

4

4 回答 4

9

以下是在 MMA 8.0 中更改图形的两种基本方法。第一个依赖于HighlightGraph,尤其是依赖于GraphHighlightStyle -> "DehighlightHide". 第二种方法在该图的未来变体中使用该图的顶点坐标。

我们将分别讨论删除和添加,因为它们涉及的方法略有不同。

[PS:我对我的答案进行了几处编辑,以使其更清晰。]

首先是一些数据:

edges={1\[UndirectedEdge]8,1\[UndirectedEdge]11,1\[UndirectedEdge]18,1\[UndirectedEdge]19,1\[UndirectedEdge]21,1\[UndirectedEdge]25,1\[UndirectedEdge]26,1\[UndirectedEdge]34,1\[UndirectedEdge]37,1\[UndirectedEdge]38,4\[UndirectedEdge]11,4\[UndirectedEdge]12,4\[UndirectedEdge]26,4\[UndirectedEdge]27,4\[UndirectedEdge]47,4\[UndirectedEdge]56,4\[UndirectedEdge]57,4\[UndirectedEdge]96,4\[UndirectedEdge]117,5\[UndirectedEdge]11,5\[UndirectedEdge]18,7\[UndirectedEdge]21,7\[UndirectedEdge]25,7\[UndirectedEdge]34,7\[UndirectedEdge]55,7\[UndirectedEdge]76,8\[UndirectedEdge]11,26\[UndirectedEdge]29,26\[UndirectedEdge]49,26\[UndirectedEdge]52,26\[UndirectedEdge]111,27\[UndirectedEdge]28,27\[UndirectedEdge]51,42\[UndirectedEdge]47,49\[UndirectedEdge]97,51\[UndirectedEdge]96}

这是初始图表:

g = Graph[edges, VertexLabels -> "Name", ImagePadding -> 10, 
ImageSize -> 500]

图。1

“删除”图形边缘而不改变图形的整体外观。

让我们开始移除位于图形中心的边 (4,11)。remainingEdgesAndVertices包含除边 (4,11) 之外的所有顶点和初始边。

remainingEdgesAndVertices = 
 Join[VertexList[g],  Complement[EdgeList[g], {4 \[UndirectedEdge] 11}]]

让我们“删除”(即隐藏)边缘(4,11):

 HighlightGraph[g, remainingEdgesAndVertices, VertexLabels -> "Name", 
   ImagePadding -> 10, GraphHighlightStyle -> "DehighlightHide", 
   ImageSize -> 500]

图2

如果我们实际上删除了边 (4, 11),则该图将彻底改变其外观。

 Graph[Complement[edges, {4 \[UndirectedEdge] 11}], 
   VertexLabels -> "Name", ImagePadding -> 10, ImageSize -> 500]

图3

“添加”图形边缘而不改变图形的整体外观。

添加图形边缘稍微更具挑战性。有两种方法浮现在脑海。此处使用的方法向后工作。您首先以隐藏形式包含新边缘,然后再将其发现。具有隐藏的“待添加”边的初始图形的布局将类似于具有“新”边的图形的布局。原因是:它们实际上是同一张图:但是它们显示的边数不同。

g2 = Graph[Append[edges, 42 \[UndirectedEdge] 37], 
 VertexLabels -> "Name", ImagePadding -> 10, ImageSize -> 500]

HighlightGraph[g2, 
   Join[Complement[EdgeList[g2], {42 \[UndirectedEdge] 37}], 
   VertexList[g2]], VertexLabels -> "Name", ImagePadding -> 10, 
   GraphHighlightStyle -> "DehighlightHide"]

图4

现在显示添加了“新边”的图形。 图

这看起来与图 1 非常不同。但它似乎是图 4 的自然延伸。

即时添加新的顶点和边

还有另一种方法可以在保持整体外观的同时添加边(和顶点)。它的灵感来自 Sjoerd 在他的回复中所写的内容。

让我们为未来的顶点 99 保留点 {0,0}。我们只需将该点添加到 VertexCoordinatesfrom g2:

vc = VertexCoordinates -> 
  Append[AbsoluteOptions[g2, VertexCoordinates][[2]], {0, 0}]

现在让我们看看它是什么样子的。g3 只是带有附加顶点 (999) 和边 (4,99) 的 g2。

g3 = Graph[Append[EdgeList [g2], 4 \[UndirectedEdge] 999], vc, 
  VertexLabels -> "Name", ImagePadding -> 10, 
  GraphHighlightStyle -> "DehighlightHide", ImageSize -> 500]

图6

这个过程允许我们在前进时添加新的边和顶点。但是需要一些试验和错误来确保新顶点位于合适的位置。

仅添加另一条边(没有新顶点)要容易得多:只需添加新边并使用VertexCoordinates先前图中的 。

您应该能够使用相同的方法(使用 same VertexCoordinates)从图中删除边。

于 2011-07-01T21:09:16.703 回答
6

如您所知,MMA 中存在多种图形格式。我们有 Combinatorica 封装格式、GraphPlot格式和 M8Graph格式。

GraphPlot
你可以找到GraphPlot节点的坐标如下。

GraphPlot[{1 -> 2, 2 -> 3, 3 -> 1, 3 -> 4}, DirectedEdges -> True,
           VertexLabeling -> True]

在此处输入图像描述

该图可以手动操作。您仍然可以在其中找到旧坐标和新坐标:

在此处输入图像描述

VertexCoordinateRules -> {{0.000196475, 0.}, {0.,0.847539}, 
                          {0.916405, 0.423865}, {2.03143, 0.42382}}

在此处输入图像描述

VertexCoordinateRules -> {{0.000196475, 0.}, {0., 0.847539}, 
                          {1.07187,0.708887}, {1.9537, 0.00924285}}

您可以使用修改后的坐标再次绘制绘图:

GraphPlot[{1 -> 2, 2 -> 3, 3 -> 1, 3 -> 4}, DirectedEdges -> True,
          VertexLabeling -> True, newRules]

在此处输入图像描述

或绘制新图

GraphPlot[{1 -> 2, 2 -> 3, 3 -> 1, 3 -> 4, 1 -> 5, 5 -> 4}, 
          DirectedEdges -> True, VertexLabeling -> True]

默认情况下看起来像这样:

在此处输入图像描述

使用旧坐标:

updatedRules = VertexCoordinateRules -> 
                 Append[VertexCoordinateRules /. newRules, {1, 0}];
GraphPlot[{1 -> 2, 2 -> 3, 3 -> 1, 3 -> 4, 1 -> 5, 5 -> 4}, 
           DirectedEdges -> True, VertexLabeling -> True, updatedRules]

在此处输入图像描述


图形

我认为您不能像操作 aGraph那样操作 a GraphPlot,但是您可以访问它的顶点坐标。

GraphData["AGraph"]

在此处输入图像描述

oldCoords = AbsoluteOptions[GraphData["AGraph"], VertexCoordinates]

(* ==>  VertexCoordinates -> {{1., 2.}, {2., 3.}, {2., 1.}, {1.,1.}, 
                       {1., 3.}, {2., 2.}} *)

拥有这些旧坐标很好,因为如果我们使用它的邻接矩阵重新创建这个图,它的布局会略有不同。这可以使用旧坐标恢复。

在此处输入图像描述

于 2011-07-01T20:14:36.317 回答
0

您可能想检查该GraphLayout选项是否有助于解决您的图表问题。

我用一个示例图检查了所有可能值的组合ComponentLayout(在下面的代码中删除了一条边)。某些组合对于您的目的肯定看起来更有用(删除边缘时更改图形布局的次数更少。我发现PackingLayoutgraph0graph1graph0

"ComponentLayout" -> "CircularEmbedding"
"ComponentLayout" -> "LayeredDrawing"
"ComponentLayout" -> "SpiralEmbedding"

保持布局最好。

显示所有组合的代码是

In[5]:= Quit
In[12]:= $COMPONENTLAYOUTS={(*Automatic,None,*)"CircularEmbedding","HighDimensionalEmbedding","LayeredDrawing","LinearEmbedding","RadialEmbedding","RandomEmbedding","SpiralEmbedding","SpringElectricalEmbedding","SpringEmbedding"};
$PACKINGLAYOUTS={"ClosestPacking","ClosestPackingCenter","Layered","LayeredLeft","LayeredTop","NestedGrid"};
layoutopt[c_,p_]:=GraphLayout-> {"ComponentLayout"->$COMPONENTLAYOUTS[[ c]],"PackingLayout"-> $PACKINGLAYOUTS[[p]]};
In[4]:= words=DictionaryLookup["*zz"];
In[5]:= graph0=Flatten[Map[(Thread[#\[DirectedEdge]DeleteCases[Nearest[words,#,3],#]])&,words]];
i=RandomInteger[{1,Length[graph0]}];
graph0[[i]]
graph1=Drop[graph0,{i}];
Out[7]= tizz\[DirectedEdge]fizz
In[18]:= g0[i_,j_]:=Graph[graph0,VertexLabels->"Name",ImagePadding->20,ImageSize->200,layoutopt[i,j]];
g1[i_,j_]:=Graph[graph1,VertexLabels->"Name",ImagePadding->20,ImageSize->200,layoutopt[i,j]]

Column[Grid/@Table[
{
$COMPONENTLAYOUTS[[c]],
$PACKINGLAYOUTS[[p]],
g0[c,p],
g1[c,p]
},
{c,1,Length[$COMPONENTLAYOUTS]},
{p,1,Length[$PACKINGLAYOUTS]}
]]
于 2011-07-01T16:45:24.887 回答
0

这充其量只是部分答案。另外,我正在使用 Mma 7。

如果我修改一个图,使其现在包含一个“孤儿”顶点(没有连接边),但我仍然想在新图上显示该顶点,这可以通过转换为一个来完成adjacency matrix(如 Carl Woll 最初指出的那样)

例如:

gr1 = {1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5, 5 -> 6, 6 -> 1};
gplot1 = GraphPlot[gr1, Method -> "CircularEmbedding", 
  VertexLabeling -> True]

定义一个新图 gr2,如下所示:

gr2 = {2 -> 3, 3 -> 4, 4 -> 5, 5 -> 6}

可以按如下方式生成显示顶点 1 的新图,例如:

Needs["GraphUtilities`"];

 gplot2 = 
 GraphPlot[SparseArray@Map[# -> 1 &, EdgeList[gr2]], 
  VertexLabeling -> True, 
  VertexCoordinateRules -> 
   Thread[VertexList[gr1] -> 
     First@Cases[gp1, GraphicsComplex[points_, __] :> points, 
       Infinity]]]

给予

在此处输入图像描述

于 2011-07-01T22:53:47.780 回答