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)
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With