Как нарисовать классическую диаграмму состояний с помощью Mathematica?

Возможно ли и практично ли для Mathematica нарисовать что-то вроде этого (созданного Graphviz):

введите здесь описание изображения

Это лучшее, что я могу получить (но форма и стиль не удовлетворяют):

введите здесь описание изображения

Код:

GraphPlot[{{A -> C, "go"}, {C -> B, "gone"}, {C -> D, 
   "went"}, {C -> C, "loop"}}, VertexLabeling -> True, 
 DirectedEdges -> True]

person Ning    schedule 13.11.2011    source источник
comment
Нет никаких причин, по которым вы не можете использовать графические примитивы для рисования чего-то подобного. Вы запрашиваете решение для автоматической компоновки?   -  person Mr.Wizard    schedule 13.11.2011
comment
@Mr.Wizard Да, я ищу примитивы более высокого уровня для рисования сложных диаграмм состояний. Я не знаю, предоставляет ли Mathematica это. Я просмотрел документацию и проверил параметры функции GraphPlot и получил приведенный выше код.   -  person Ning    schedule 13.11.2011
comment
Почему вы приняли мой ответ? Форма все равно неправильная. Я ценю это, но я думаю, что вам следует подождать лучшего ответа.   -  person Mr.Wizard    schedule 13.11.2011
comment
Да, я думаю, это может помешать другим ответам. Однако еще раз спасибо.   -  person Mr.Wizard    schedule 13.11.2011
comment
@Mr.Wizard Вы очень приятный человек в сообществе, спасибо!   -  person Ning    schedule 13.11.2011


Ответы (2)


Вы можете сделать что-то подобное, используя 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, #]} &)]

введите здесь описание изображения


Метод обновлен в феврале 2015 г.

Чтобы сохранить возможность интерактивно перестраивать граф с помощью инструментов рисования (двойной щелчок), необходимо хранить графику вершин внутри GraphicsComplex с индексами, а не координатами. Я считаю, что это можно сделать из VertexRenderingFunction, используя увеличивающуюся переменную, но кажется проще и, возможно, более надежно сделать это с постобработкой. Это работает в версиях 7 и 10 Mathematica, предположительно также в 8 и 9:

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]}

введите здесь описание изображения

person Mr.Wizard    schedule 13.11.2011
comment
Существует ли VertexLabelingFunction? - person Ning; 13.11.2011
comment
@Ning У меня была ошибка в ответе; Я имел в виду VertexRenderingFunction. Я не верю, что существует Vertex*LabelingFuncion. Кроме того, я заметил, что у меня есть недостаток в моей графике по сравнению с вашим исходным примером в отношении размеров круга. Я исправил, это вторая версия, которую я только что выложил. - person Mr.Wizard; 13.11.2011

Нет необходимости в интерактивном размещении, чтобы получить ваши вершины в нужном месте, как предлагает mr.Wizard в его ответ. Вы можете использовать VertexCoordinateRules для этого:

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}}
]

введите здесь описание изображения

person Sjoerd C. de Vries    schedule 13.11.2011
comment
Я не имел в виду, что интерактивный макет был необходим, но я понимаю, как это можно сделать. Этот метод тоже работает. Знаете ли вы какой-либо способ сохранить редактируемость, кроме варианта хака, который я использовал? - person Mr.Wizard; 14.11.2011
comment
@Mr.Wizard, я не вижу простого выхода. - person Sjoerd C. de Vries; 14.11.2011