【问题标题】:VertexCoordinate Rules and VertexList from GraphPlot GraphicGraphPlot Graphic 中的 VertexCoordinate 规则和 VertexList
【发布时间】:2010-11-22 13:36:52
【问题描述】:

有没有什么方法可以从 GraphPlot 生成的图形(FullForm 或 InputForm)中抽象出 GraphPlot 应用于 VertexCoordinate 规则的顶点顺序?我不想使用 GraphUtilities 函数 VertexList。我也知道 GraphCoordinates,但是这两个函数都适用于图形,而不是 GraphPlot 的图形输出。

例如,

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

Last@(gp1 /. Graphics[Annotation[x___], ___] :>  {x})

给出以下六个坐标对的列表:

VertexCoordinateRules -> {{2., 0.866025}, {1.5, 1.73205}, {0.5, 1.73205}, {0., 0.866025}, {0.5, 1.3469*10^-10}, {1.5, 0.}}

我怎么知道哪个规则适用于哪个顶点,我可以确定这是 和 VertexList[gr1] 给出的一样吗?

例如

 Needs["GraphUtilities`"];
gr2 = SparseArray@ 
      Map[# -> 1 &, EdgeList[{2 -> 3, 3 -> 4, 4 -> 5, 5 -> 6}]];

    VertexList[gr2]

给出 {1, 2, 3, 4, 5}

但是....

    gp2 = GraphPlot[gr2, VertexLabeling -> True, 
      VertexCoordinateRules -> 
       Thread[VertexList[gr1] -> 
         Last@(gp1 /. Graphics[Annotation[x___], ___] :>  {x})[[2]]]];
Last@(gp2 /. Graphics[Annotation[x___], ___] :>  {x})

给出六个坐标集:

VertexCoordinateRules -> {{2., 0.866025}, {1.5, 1.73205}, {0.5, 1.73205}, {0., 0.866025}, {0.5, 1.3469*10^-10}, {1.5, 0.}}

例如,如何为 gr2 的 VertexCoordinateRules 抽象出正确的 VertexList?

(我知道我可以通过在生成 gr2 后获取 VertexList 来纠正问题,例如)

VertexList@
 SparseArray[
  Map[# -> 1 &, EdgeList[{2 -> 3, 3 -> 4, 4 -> 5, 5 -> 6}]], {6, 6}]

{1、2、3、4、5、6}

但我需要的信息似乎出现在 GraphPlot 图形中:我怎样才能获得它?

(我将图形转换为邻接矩阵的原因是,正如 Wolfram 的 Carl Woll 所指出的,它允许我包含一个“孤儿”节点,如 gp2 中)

【问题讨论】:

  • 顺便说一句,用边列表表示断开连接图的另一种方法是为每个节点设置 i->i 边。绘图期间可能需要 SelfLoopStyle->None
  • 是的,这是真的!在我了解 Carl Woll 的方法之前,我曾经使用过它。我有时需要展示自循环并且(目前)更喜欢邻接矩阵方法。
  • 我认为两者都有用——如果您正在检查图形或进行不改变顶点数量的修改,则邻接矩阵更方便,而当您需要执行诸如拆分之类的操作时,edgelist 会更好图形一分为二

标签: wolfram-mathematica


【解决方案1】:

使用顶点标签,一种方法是获取标签的坐标。请注意,GraphPlot 的输出位于 GraphicsComplex 中,其中坐标别名的坐标作为第一个标签,您可以将其作为

points = Cases[gp1, GraphicsComplex[points_, __] :> points, Infinity] // First

查看FullForm,您会看到标签在文本对象中,将它们提取为

labels = Cases[gp1, Text[___], Infinity]

实际标签似乎有两层深,所以你得到

actualLabels = labels[[All, 1, 1]];

坐标别名是第二个参数,所以你得到它们

 coordAliases = labels[[All, 2]]

实际坐标是在 GraphicsComplex 中指定的,所以我们得到它们

 actualCoords = points[[coordAliases]]

坐标列表和标签列表之间存在1-1对应关系,因此您可以使用Thread将它们作为“标签”列表返回->坐标对。

这是一个功能,所有这些都在一起

getLabelCoordinateMap[gp1_] := 
 Module[{points, labels, actualLabels, coordAliases, actualCoords},
  points = 
   Cases[gp1, GraphicsComplex[points_, __] :> points, Infinity] // 
    First;
  labels = Cases[gp1, Text[___], Infinity];
  actualLabels = labels[[All, 1, 1]];
  coordAliases = labels[[All, 2]];
  actualCoords = points[[coordAliases]];
  Thread[actualLabels -> actualCoords]
  ];
getLabelCoordinateMap[gp1]

并不是说这只适用于带标签的 GraphPlot。对于没有标签的对象,您可以尝试从其他图形对象中提取,但您可能会得到不同的结果,具体取决于您从中提取映射的对象,因为似乎存在有时将线端点和顶点标签分配给不同顶点的错误。我已经举报了。解决该错误的方法是始终使用显式顶点-> 坐标指定 VertexCoordinateList,或始终使用“邻接矩阵”表示。这是一个差异的例子

graphName = {"Grid", {3, 3}};
gp1 = GraphPlot[Rule @@@ GraphData[graphName, "EdgeIndices"], 
  VertexCoordinateRules -> GraphData[graphName, "VertexCoordinates"], 
  VertexLabeling -> True]
gp2 = GraphPlot[GraphData[graphName, "AdjacencyMatrix"], 
  VertexCoordinateRules -> GraphData[graphName, "VertexCoordinates"], 
  VertexLabeling -> True]

顺便说一句,这里是我用来在邻接矩阵和边缘规则表示之间转换的实用函数

edges2mat[edges_] := Module[{a, nodes, mat, n},
   (* custom flatten to allow edges be lists *)

   nodes = Sequence @@@ edges // Union // Sort;
   nodeMap = (# -> (Position[nodes, #] // Flatten // First)) & /@ 
     nodes;
   n = Length[nodes];
   mat = (({#1, #2} -> 1) & @@@ (edges /. nodeMap)) // 
     SparseArray[#, {n, n}] &
   ];
mat2edges[mat_List] := Rule @@@ Position[mat, 1];
mat2edges[mat_SparseArray] := 
 Rule @@@ (ArrayRules[mat][[All, 1]] // Most)

【讨论】:

  • 谢谢!我感谢您的帮助。我从你的回答中学到了很多东西。你的edges2mat 也是个好东西。
【解决方案2】:

如果你执行FullForm[gp1] 你会得到一堆我不会在这里发布的输出。在输出的开头附近,您会发现GraphicsComplex[]。这本质上是一个点列表,然后是这些点的使用列表。因此,对于您的图形gp1,GraphicsComplex 的开头是:

GraphicsComplex[
 List[List[2., 0.866025], List[1.5, 1.73205], List[0.5, 1.73205], 
  List[0., 0.866025], List[0.5, 1.3469*10^-10], List[1.5, 0.]], 
 List[List[RGBColor[0.5, 0., 0.], 
   Line[List[List[1, 2], List[2, 3], List[3, 4], List[4, 5], 
     List[5, 6], List[6, 1]]]],

第一个最外面的列表定义了 6 个点的位置。第二个最外面的列表使用第一个列表中的点数定义了这些点之间的一堆线。如果你玩这个可能更容易理解。

编辑:响应 OP 的评论,如果我执行:

FullForm[GraphPlot[{3 -> 4, 4 -> 5, 5 -> 6, 6 -> 3}]]

我明白了

    Graphics[Annotation[GraphicsComplex[List[List[0.`,0.9997532360813222`],
List[0.9993931236462025`,1.0258160108662504`],List[1.0286626995939243`,
0.026431169015735057`],List[0.02872413637035287`,0.`]],List[List[RGBColor[0.5`,0.`,0.`],
Line[List[List[1,2],List[2,3],List[3,4],List[4,1]]]],List[RGBColor[0,0,0.7`],
Tooltip[Point[1],3],Tooltip[Point[2],4],Tooltip[Point[3],5],Tooltip[Point[4],6]]],
List[]],Rule[VertexCoordinateRules,List[List[0.`,0.9997532360813222`],
List[0.9993931236462025`,1.0258160108662504`],
List[1.0286626995939243`,0.026431169015735057`],List[0.02872413637035287`,0.`]]]],
Rule[FrameTicks,None],Rule[PlotRange,All],Rule[PlotRangePadding,Scaled[0.1`]],
Rule[AspectRatio,Automatic]]

顶点位置列表是 GraphicsComplex 中的第一个列表。稍后在 FullForm 中,您可以看到 Mathematica 添加工具提示的列表,以使用您在原始边列表中提供的标识符标记顶点。由于您现在正在查看的是描述图形的代码,因此您的顶点与将要绘制的内容之间只有间接关系;信息都在那里,但解包并不完全简单。

【讨论】:

  • 试试Transpose@{First /@ #[[1, 1, 2, 1, 2, 1]], #[[1, 1, 1]]} &[gp1]
  • 这仅适用于标签对应于 GraphicsComplex 对象中的坐标别名位置,它不适用于图形 {2->1}
  • 好的,我明白你的意思了。但是如果我尝试 FullForm[GraphPlot[{3 -> 4, 4 -> 5, 5 -> 6, 6 -> 3}]] 我看到 List[1, 2], List[2, 3], List[3 , 4], List[4, 1] 而不是顶点列表。
【解决方案3】:
p2 = Normal@gp1 // Cases[#, Line[points__] :> points, Infinity] &;
p3 = Flatten[p2, 1];
ListLinePlot[p3[[All, 1 ;; 2]]]

V12.0.0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 2012-06-21
    • 2021-11-01
    • 2017-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多