Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VertexCoordinate Rules and VertexList from GraphPlot Graphic

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)

alt text

like image 298
681234 Avatar asked Nov 22 '10 13:11

681234


1 Answers

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)
like image 50
Yaroslav Bulatov Avatar answered Sep 22 '22 06:09

Yaroslav Bulatov