VertexCoordinate Rules and VertexList from GraphPlot Graphic

微笑、不失礼 提交于 2019-11-27 06:14:35

问题


Is there any way of abstracting the vertex order that GraphPlot applies to VertexCoordinate Rules from the (FullForm or InputForm) of the graphic produced by GraphPlot? I do not want to use the GraphUtilities function VertexList. I am also aware of GraphCoordinates, but both of these functions work with the graph, NOT the graphics output of GraphPlot.

For example,

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})

gives the following list of six coordinate pairs:

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

How do I know which rule applies to which vertex, and can I be certain that this is the same as that given by VertexList[gr1]?

For example

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

    VertexList[gr2]

gives {1, 2, 3, 4, 5}

But ....

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

gives SIX coordinate sets:

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

How can I abstract the correct VertexList for VertexCoordinateRules for gr2, for example?

(I am aware that I can correct things by taking the VertexList after generating gr2 as follows, for example)

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

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

but the information I need appears to be present in the GraphPlot graphic: how can I obtain it?

(The reason I convert the graph to an adjacency matrix it that, as pointed out by Carl Woll of Wolfram, it allows me to include an 'orphan' node, as in gp2)


回答1:


With vertex labeling, one way is to get coordinates of the labels. Notice that output of GraphPlot is in GraphicsComplex where coordinates of coordinate aliases are as first label, you can get it as

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

Looking at FullForm you'll see that labels are in text objects, extract them as

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

The actual label seems to be two levels deep so you get

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

Coordinate alias is the second parameter so you get them as

 coordAliases = labels[[All, 2]]

Actual coordinates were specified in GraphicsComplex, so we get them as

 actualCoords = points[[coordAliases]]

There a 1-1 correspondence between list of coordinates and list of labels, so you can use Thread to return them as list of "label"->coordinate pairs.

here's a function that this all together

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]

Not that this only works on labelled GraphPlot. For ones without labels you could try to extract from other graphics objects, but you may get different results depending on what objects you extract the mapping from because there seems to be a bug which sometimes assigns line endpoints and vertex labels to different vertices. I've reported it. The way to work around the bug is to either always use explicit vertex->coordinate specification for VertexCoordinateList, or always use "adjacency matrix" representation. Here's an example of discrepancy

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]

BTW, as an aside, here are the utility functions I use for converting between adjacency matrix and edge rule representation

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)



回答2:


If you execute FullForm[gp1] you'll get a bunch of output which I won't post here. Near the start of the output you'll find a GraphicsComplex[]. This is, essentially, a list of points and then a list of uses of those points. So, for your graphic gp1 the beginning of the GraphicsComplex is:

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]]]],

The first outermost list defines the positions of 6 points. The second outermost list defines a bunch of lines between those points, using the numbers of the points within the first list. It's probably easier to understand if you play around with this.

EDIT: In response to OP's comment, if I execute:

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

I get

    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]]

The list of vertex positions is the first list inside the GraphicsComplex. Later in the FullForm you can see the list where Mathematica adds tooltips to label the vertices with the identifiers you supplied in the original edge list. Since what you are now looking at is the code describing a graphic there's only an indirect relationship between your vertices and what will be plotted; the information is all there but not entirely straightforward to unpack.



来源:https://stackoverflow.com/questions/4245946/vertexcoordinate-rules-and-vertexlist-from-graphplot-graphic

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!