How to draw the classic state diagram using Mathematica?
Asked Answered
H

2

20

Is it possible and practical for Mathematica to draw something like this (being created by Graphviz):

enter image description here

This is the best that I can get (but the shape and style are not satisfying):

enter image description here

Code:

GraphPlot[{{A -> C, "go"}, {C -> B, "gone"}, {C -> D, 
   "went"}, {C -> C, "loop"}}, VertexLabeling -> True, 
 DirectedEdges -> True]
Hiramhirasuna answered 13/11, 2011 at 3:24 Comment(5)
There is no reason you cannot use graphics primitives to draw something like this. Are you requesting an automatic layout solution?Rebbecarebbecca
@Rebbecarebbecca Yes, I am looking for some higher level primitives for drawing complicated state diagrams. I don't know whether Mathematica provides that. I searched through the documentation and checked the options of "GraphPlot" function and ended up with the code above.Hiramhirasuna
Why did you accept my answer? The shape it still wrong. I appreciate it, but I think you should wait for a better answer.Rebbecarebbecca
Yes, I think it may inhibit other answers. Again, thank you however.Rebbecarebbecca
@Rebbecarebbecca You are a very nice person to have in a community, thank you!Hiramhirasuna
R
21

You can do something like this using VertexRenderingFunction.

GraphPlot[{{A -> C, "go"}, {C -> B, "gone"}, {C -> D, "went"}, {C -> C, "loop"}}, 
 DirectedEdges -> True, 
 VertexRenderingFunction -> ({{White, Disk[#, 0.15]}, 
     AbsoluteThickness[2], Circle[#, 0.15], 
     If[MatchQ[#2, A | B], Circle[#, 0.12], {}], Text[#2, #]} &)]

enter image description here


Method Updated February 2015

To preserve the ability to interactively rearrange the graph with the drawing tools (double click) one must keep the vertex graphics inside of GraphicsComplex, with indexes rather than coordinates. I believe one could do this from VertexRenderingFunction using an incrementing variable but it seems easier an possibly more robust to do it with post-processing. This works in versions 7 and 10 of Mathematica, presumably 8 and 9 as well:

GraphPlot[
  {{A -> C, "go"}, {C -> B, "gone"}, {C -> D, "went"}, {C -> C, "loop"}},
  DirectedEdges -> True
] /.
 Tooltip[Point[n_Integer], label_] :>
   {{White, Disk[n, 0.15]},
    Black, AbsoluteThickness[2], Circle[n, 0.15], 
    If[MatchQ[label, A | B], Circle[n, 0.12], {}], Text[label, n]}

enter image description here

Rebbecarebbecca answered 13/11, 2011 at 3:46 Comment(2)
Is there a "VertexLabelingFunction"?Hiramhirasuna
@Hiramhirasuna I had an error in my answer; I meant VertexRenderingFunction. I don't believe there is a Vertex*LabelingFuncion. Also, I noticed that I had a flaw in my graphics relative to your original example regarding the circle sizes. I corrected this is the second version I just put up.Rebbecarebbecca
M
5

There's no need for interactive placement to get your vertices at the desired location as mr.Wizard suggests in his answer. You can use VertexCoordinateRules for that:

GraphPlot[{{A -> C, "go"}, {C -> B, "gone"}, {C -> D, "went"}, {C -> C, "loop"}}, 
    DirectedEdges -> True, 
    VertexRenderingFunction -> 
          ({{White, Disk[#, 0.15]}, AbsoluteThickness[2], Circle[#, 0.15], 
           If[MatchQ[#2, A | B], Circle[#, 0.12], {}], Text[#2, #]} &),
    VertexCoordinateRules -> 
          {A -> {0, 0}, C -> {0.75, 0},B -> {1.5, 0.25}, D -> {1.5, -0.25}}
]

enter image description here

Mistymisunderstand answered 13/11, 2011 at 19:48 Comment(2)
I didn't mean that it was necessary to have interactive layout, but I can see how that may be inferred. This method works too. Do you know of any way to preserve the editability besides a variation of the hack I used?Rebbecarebbecca
@Rebbecarebbecca I don't see an easy way out.Mistymisunderstand

© 2022 - 2024 — McMap. All rights reserved.