1
$\begingroup$

I have a graph and I want to rank each vertex according to its local clustering coefficient. I have done the following:

g = RandomGraph[BernoulliGraphDistribution[30, 0.25]];
Graph[g, VertexCoordinates -> Transpose[{RandomReal[1,
      VertexCount[g]],N[LocalClusteringCoefficient[g]]}]]

The y coordinate of each vertex is the local clustering coefficient, but I don't have a good way to choose the x coordinate so I use a random number. This creates (unsurprisingly) a cluttered ugly graph.

Is there any build-in way to have such a layout that is less ugly?

$\endgroup$
  • $\begingroup$ Can you rephrase the title? It's hardly understandable. As for the question in the body: I doubt that there is a good way to achieve this. Have you seen any plots which do the same things and look nice? $\endgroup$ – Szabolcs Jul 14 at 15:22
  • $\begingroup$ @Szabolcs I would gladly rephrase the title, but I'm not sure how to make it clearer. Do you have any suggestions? $\endgroup$ – tst Jul 14 at 15:39
  • 1
    $\begingroup$ Do you just mean "How to position vertices according to clustering coefficient in a nice way?" $\endgroup$ – Rahul Jul 15 at 12:04
  • $\begingroup$ I think it's just a typo (what Rahul said). Do you have any reason to believe that a nice layout is possible this way? My guess is that in general it isn't. $\endgroup$ – Szabolcs Jul 15 at 15:14
2
$\begingroup$
SeedRandom[1]
g = RandomGraph[BernoulliGraphDistribution[30, 0.25]]

enter image description here

"MultipartiteEmbedding"

You can sort and split the LocalClusteringCoefficient[g] and use the part lengths as the suboption value for "VertexPartition" in GraphEmbedding[g, {"MultipartiteEmbedding", "VertexPartition" -> vertexpartition}]. Replace the first coordinates with local clustering coefficients and normalize the second coordinates to get a list of VertexCoordinates where the horizontal axis values are local clustering coefficients:

v = SortBy[VertexList[g], LocalClusteringCoefficient[g, #] &];
lcc = Sort @ LocalClusteringCoefficient[g]; 
lengths = Length /@ Split[lcc];

ge = GraphEmbedding[g, {"MultipartiteEmbedding", "VertexPartition" -> lengths}];

ge[[All, 2]] = 2 ge[[All, 2]] / VertexCount[g];
ge[[All, 1]] = LocalClusteringCoefficient[g, #] & /@ v;
ge = Reverse /@ ge;

Graph[v, EdgeList[g], VertexCoordinates -> ge, 
 EdgeShapeFunction -> "CurvedArc", ImageSize -> Medium]

enter image description here

If you care only about the ordering of property values, you can have a less less cluttered picture

ge = Reverse /@ GraphEmbedding[g,
   {"MultipartiteEmbedding", "VertexPartition" -> lengths}];

Graph[v, EdgeList[g], VertexCoordinates -> ge, 
 EdgeShapeFunction -> "CurvedEdge", 
 VertexLabels -> Placed["Name", Center], VertexStyle -> White, 
 VertexSize -> .6, ImageSize -> Medium]

enter image description here

GraphComputation`GraphPropertyChart

An alternative approach is to use GraphComputation`GraphPropertyChart to get a nice visualization of vertex properties in a PieChart with sector sizes proportional to the property values:

gpc = GraphComputation`GraphPropertyChart[Graph[v, EdgeList[g]], 
 Automatic -> lcc /. 0 -> 10^-5, 
 ChartLabels -> {Placed[{v, lcc}, {"RadialCenter", "RadialCallout"}]},
 ChartStyle -> "Rainbow", ImageSize -> Large]

enter image description here

Click on a vertex to highlight the edges incident to that vertex:

enter image description here

Highlight edges incident to selected vertices (using a modified version of explode from this answer by Simon Woods):

highlight[v_][chart_, i : {__}] := ReplacePart[chart, 
  Position[chart, False][[Flatten[Position[v, #] & /@ i]]] -> True]


highlight[v][gpc, {6, 9}]

enter image description here

Update: GraphPlot + VertexCoordinateRules

Before version 12 updates, VertexCoordinateRules option of GraphPlot had the desired feature:

enter image description here

So, if you have access to a version prior to v12, you can do

vcrules = Thread[v -> lcc] /. Rule[a_, b_] :> Rule[a, {Automatic, b}]
vcoords = GraphPlot[Rule @@@ EdgeList[g], VertexLabeling -> False, 
    VertexCoordinateRules -> vcrules][[1, 1, 1]];

Show[Graph[v, EdgeList[g], VertexCoordinates -> vcoords, 
  EdgeShapeFunction -> "CurvedArc", 
  VertexLabels -> Placed["Name", Center], VertexStyle -> White, 
  VertexSize -> .9, ImageSize -> Large], Frame -> True, 
 GridLines -> {None, DeleteDuplicates@lcc}, 
 FrameTicks -> {N[Union[#, SameTest -> (Abs[#2 - #] <= .05 &)] & /@ {lcc, 
      lcc}], {Automatic, Automatic}}]

enter image description here

Note: GridLines and FrameTicks added to show that vertical coordinates are as specified.

$\endgroup$
0
$\begingroup$

It is not the answer to the exact question I asked, because it is not a built-in method, but I think it works pretty well.

Initially I asked mathematica to choose the x coordinates so that it minimizes the total edge lengths. Unsurprisingly it positioned all vertices on the same line.

So, I changed the objective function by adding the sum of the inverse distance between any two vertices and the result is not bad at all.

g = RandomGraph[BernoulliGraphDistribution[30, 0.25]]
gg = AdjacencyGraph[AdjacencyMatrix[g], DirectedEdges -> True];
IM = IncidenceMatrix[gg];
CC = N[LocalClusteringCoefficient[g]];
coords = Transpose[{Table[x[i], {i, 30}], CC}];
eLenght = 
  Sum[e[[1]]^2 + e[[2]]^2, {e, 
    Transpose[{Table[x[i], {i, 30}].IM, CC.IM}]}];
invdists = 
  Total[1/DeleteCases[
     Flatten[Table[(p[[1]] - q[[1]])^2 + (p[[2]] - q[[2]])^2, {p, 
        coords}, {q, coords}]], 0.]];
minsol = Minimize[eLenght + 1/10000 invdists, 
    Table[x[i], {i, 30}]][[2]];
Graph[g, VertexCoordinates -> coords /. minsol]

This turns a graph like this:

enter image description here

to a graph like this:

enter image description here

I suspect that the minimum is not unique, but I am content with the result for now.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.