4
$\begingroup$

I have a directed graph based on a Markov Chain. First I would like to know: how can I place the node name/number inside the circle?

Second, the graph is frequently displayed asymmetrically even though it is a symmetric graph. By symmetric, I mean that there is a main (shortest) path 1->2->3->4->5 (where 5 is the terminal node/state) and vertices 1,2 and 3 each have 4 nodes. This is the code I used:

g = Graph[{Style[DirectedEdge[1, 2], Green], DirectedEdge[1, 6], 
DirectedEdge[1, 8], DirectedEdge[1, 7], DirectedEdge[1, 9], 
Style[DirectedEdge[2, 3], Green], DirectedEdge[2, 10], 
DirectedEdge[2, 12], DirectedEdge[2, 11], DirectedEdge[2, 13], 
Style[DirectedEdge[6, 1], Green], DirectedEdge[6, 8], 
Style[DirectedEdge[8, 1], Green], Style[DirectedEdge[7, 1], Green],
DirectedEdge[7, 9], Style[DirectedEdge[9, 1], Green], 
Style[DirectedEdge[3, 4], Green], DirectedEdge[3, 14], 
DirectedEdge[3, 16], DirectedEdge[3, 15], DirectedEdge[3, 17], 
Style[DirectedEdge[10, 2], Green], DirectedEdge[10, 12], 
Style[DirectedEdge[12, 2], Green], 
Style[DirectedEdge[11, 2], Green], DirectedEdge[11, 13], 
Style[DirectedEdge[13, 2], Green], 
Style[DirectedEdge[4, 5], Green], DirectedEdge[4, 18], 
DirectedEdge[4, 20], DirectedEdge[4, 19], DirectedEdge[4, 21], 
Style[DirectedEdge[14, 3], Green], DirectedEdge[14, 16], 
Style[DirectedEdge[16, 3], Green], 
Style[DirectedEdge[15, 3], Green], DirectedEdge[15, 17], 
Style[DirectedEdge[17, 3], Green], 
Style[DirectedEdge[5, 5], Green], 
Style[DirectedEdge[18, 4], Green], DirectedEdge[18, 20], 
Style[DirectedEdge[20, 4], Green], 
Style[DirectedEdge[19, 4], Green], DirectedEdge[19, 21], 
Style[DirectedEdge[21, 4], Green]}, VertexLabels -> "Name", 
VertexStyle -> Yellow, EdgeStyle -> Red, VertexSize -> .5]

enter image description here

Node 1 looks good where there are two possible nodes on each side. Node 2 reverses the direction of arrows in the child nodes relative to node 1. Node 3 is screwed up, though as the symmetry is lost. Nodes 15 and 17 are reversed as well so the arrow between them points the wrong way relative to the other edge arrows. Additionally, the length of arrows between main nodes is too large.

To summarize:

  1. How to put node name/number inside circle?
  2. How to ensure symmetry in display. Can I choose arrangement of nodes?
  3. Can I shorten or lengthen arrows with styling?

These are all directly related issues, so I didn't make separate questions. I can break it up as needed.

$\endgroup$
  • 1
    $\begingroup$ Strongly suggest you look at the articles that Graph Drawing Overview gives links to. Also my own experience is that it is easier to control the look and layout of graphs with GraphPlot than by direct manipulation of Graph expressions. $\endgroup$ – m_goldberg Jan 4 '17 at 3:52
  • 2
    $\begingroup$ Using VertexLabels -> Placed["Name", Center] will put the name inside the circle. $\endgroup$ – Carl Woll Jan 4 '17 at 3:57
  • $\begingroup$ @m_goldberg, is there a way, using GraphPlot or LayeredGraphPlot, to replicate the above graph in a similar fashion to what I have just using Graph? If you make that an answer, I'll accept it. Thanks! $\endgroup$ – Gene Jan 5 '17 at 0:33
4
$\begingroup$

As Carl mentioned in a comment, you can use VertexLabels -> Placed["Name", Center] to put the labels in the centers of the vertices. By using Range[21] as the first argument of Graph we get some symmetry:

ga = Graph[Range[21], EdgeList[g], VertexLabels -> Placed["Name", Center], Options[g]]

enter image description here

Using GraphLayout -> "MultipartiteEmbedding"

We need to (1) identify the set of vertices in each of the three layers and use an appropriately ordered vertex list as the first argument, and (2) use the number of vertices in each layer as the value of the suboption 'VertexPartition":

layers = {Range[6, VertexCount[g], 2], Range[5], Range[7, VertexCount[g], 2]};
orderedvertices = Join @@ layers;
vertexpartition = Length /@ layers;

gb = Graph[orderedvertices, EdgeList[g], 
   VertexLabels -> Placed["Name", Center], Options[g], 
   GraphLayout -> {"MultipartiteEmbedding", "VertexPartition" -> vertexpartition}]

enter image description here

If you want to change the orientation, you can use

SetProperty[gb, VertexCoordinates -> Thread[VertexList[gb] -> ({1.5, 1} # & /@ 
      RotationTransform[-Pi/2][GraphEmbedding[gb]])]]

enter image description here

Using GraphLayout -> "LayeredEmbedding"

In this particular case, using the suboption "RootVertex" -> 5 happens to give a symmetric layout:

SetProperty[gb, {VertexSize -> {"Scaled", .05}, 
  GraphLayout -> {"LayeredEmbedding", "RootVertex" -> 5, "Orientation" -> Right}}]

enter image description here

Setting VertexCoordinates directly:

top = Thread[layers[[1]] -> Thread[{Range@Length@layers[[1]], 2}]];
middle = Thread[layers[[2]] -> Thread[{Range[1.5, .5 + 2 Length@layers[[2]], 2], 0}]];
bottom = Thread[layers[[3]] -> Thread[{Range@Length@layers[[3]], -2}]];
vcoords = Join[top, middle, bottom];

SetProperty[ga, {VertexSize -> {"Scaled", .04}, VertexCoordinates -> vcoords}]

enter image description here

$\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.