Сложная структура дерева графика

Я пытаюсь создать древовидную структуру с помощью graphviz. Я открыт для написания кода graphviz вручную или с использованием рубина ruby-graphviz для ruby. Учитывая приведенную ниже картинку, может ли кто-нибудь дать представление о необходимом коде? Игнорируйте, что строки не прямые... они должны быть, когда graphviz строит график. Я открыт для того, чтобы иметь точки/точки, когда линии также пересекаются.

Я играл с ruby-graphviz и родословным классом... это заставляет меня участвовать в этом, но мне действительно нужно, чтобы все линии были прямыми и пересекались под прямым углом и из-под коробки код, похоже, не делает этого.

Код должен быть достаточно общим, чтобы в поле "C" также были дети, а также для большего количества детей в разделе "A".

Цвета не имеют значения... примеры могут исключать любую окраску.

http://docs.google.com/drawings/pub?id=1lUTfgKP_LN0x7C3ItbsFjfLBuDTL84AtmoaW7YFn32Y&w=1036&h=713

Ответ 1

Насколько мне известно, для этого требуется небольшая работа; Я буду делать это только на языке Graphviz DOT. Сначала я даю вам решение, а затем объясню, как вы можете его расширить.

Это результат:

outfile.png

Это код Graphviz, создающий рисунок:

graph atree {
  Item1 [shape=none,label="Item 1",pos="2.2,1.1!"];
  Item2 [shape=none,label="Item 2",pos="2.2,0.1!"];
  Item3 [shape=none,label="Item 3",pos="2.9,-0.3!"];
  A [shape=box,color=lightblue,style=filled,pos="2,3!"];
  B [shape=box,color=lightblue,style=filled,pos="1,2.1!"];
  C [shape=box,color=lightblue,style=filled,pos="3,2.1!"];
  D [shape=box,color=lightblue,style=filled,pos="1.5,1.5!"];
  E [shape=box,color=lightblue,style=filled,pos="1.5,0.5!"];
  D0 [style=invisible,fixedsize=true,width=0,height=0,pos="2,2.5!",label=""];
  D1 [style=invisible,fixedsize=true,width=0,height=0,pos="1,2.5!",label=""];
  D2 [style=invisible,fixedsize=true,width=0,height=0,pos="3,2.5!",label=""];
  D3 [style=invisible,fixedsize=true,width=0,height=0,pos="1,1.5!",label=""];
  D4 [style=invisible,fixedsize=true,width=0,height=0,pos="1,0.5!",label=""];
  D5 [style=invisible,fixedsize=true,width=0,height=0,pos="1.5,1.1!",label=""];
  D6 [style=invisible,fixedsize=true,width=0,height=0,pos="1.5,0.1!",label=""];
  D7 [style=invisible,fixedsize=true,width=0,height=0,pos="2.2,-0.3!",label=""];
  A -- D0 -- D1 -- B -- D3 -- D4 -- E [color=blue];
  E -- D6 -- Item2 -- D7 -- Item3 [color=blue];
  D0 -- D2 -- C [color=blue];
  D3 -- D -- D5 -- Item1 [color=blue];
}

Если вы поместите его в файл с именем inputfile.dot, вы можете получить полученный файл изображения с помощью команды neato -Tpng inputfile.dot > outfile.png.

Теперь несколько комментариев о том, как это работает: код, создающий дерево с помощью A, B, C, D, E, Item1, Item2, Item3, прост (атрибуты просто устанавливают цвета и стили полей). Трюк для прямой и ортогональной линии состоит из 1) добавления невидимых узлов с нулевым размером к графику и 2) позиционирования всех объектов в абсолютных координатах на холсте. Вспомогательные узлы D1, D2, D3, D4, D5, D6, D7 необходимы для шага 1), а параметры pos="x,y!" необходимы для шага 2). Обратите внимание, что вам нужен знак ! в конце команды pos, так как иначе позиции не будут считаться окончательными, а макет все равно будет изменен.

Вы можете добавить дополнительные узлы, сначала позиционируя новый node (используя код для узлов A ... Item3 в качестве шаблона), добавляя невидимый вспомогательный node (с pos таким образом, чтобы все соединения с и из него ортогональны), а затем добавление соединения к графику через <StartingNode> -- <AuxiliaryNode> -- <NewNode>.

Ответ 2

Немного поздно, я знаю, но я просто хотел показать другую версию, не указав точные позиции каждого node.

digraph {
    splines=false;
    ranksep=0.05;

    node[shape=box, color=lightblue, style=filled];
    A;B;C;D;E;

    node[shape=none, color=none, style=solid];
    i1[label="Item 1"];
    i2[label="Item 2"];
    i3[label="Item 3"];

    node[label="", width=0, height=0];
    edge[arrowhead=none, color=blue];

    {rank=same; n2; n1; n3;}
    n2; n1; n3;
    A -> n1;
    n2 -> n1 -> n3;

    {rank=same; B; C;}
    n2 -> B;
    n3 -> C;

    {rank=same; n4; D;}
    B -> n4 -> D;

    {rank=same; n6; n5; i1;}
    D -> n5 -> i1;
    n4 -> n6;

    {rank=same; n7; E;}
    n6 -> n7 -> E;

    {rank=same; n8; i2;}
    E -> n8 -> i2;

    {rank=same; n9; i3;}
    i2 -> n9 -> i3;
}

Прямые линии выполняются с помощью:

  • splines=false - скажите "нет" сплайнам
  • невидимые узлы (узлы n1, n2,... n9)
  • размещение узлов в одном ранге с помощью rank=same

По-прежнему некоторая работа, чтобы получить точечный файл правильно, но он бьет imho, вычисляя себе позицию каждого node.

Результат выглядит следующим образом:

graphviz output

Пока C не имеет дочерних узлов, вам нужно будет применить еще несколько обманов (невидимые узлы), чтобы отобразить их полностью справа.

Чтобы получить более общее решение для разных графиков, возможно, понадобится дальнейшая адаптация (примените вес к вертикальным краям или узлам группы, которые должны быть выровнены по вертикали или использовать подграфы,...).

Ответ 3

Еще одна версия с использованием splines=ortho, которая нуждается в меньшем количестве скрытых узлов и дает аналогичный визуальный результат.

digraph example {
    splines=ortho;
    ranksep=0.05;

    node[shape=box, color=lightblue, style=filled];
    A;B;C;D;E;

    node[shape=none, color=none, style=solid];
    i1[label="Item 1"];
    i2[label="Item 2"];
    i3[label="Item 3"];

    node[label="", width=0, height=0];
    edge[arrowhead=none, color=blue];
    n1; n2; n3; n4; n5;

    {rank=same; B; C;}
    A -> n1;
    n1 -> B;
    n1 -> C;

    {rank=same; n2; D;}
    B -> n2;
    n2 -> D;

    {rank=same; n3; i1;}
    D -> n3;
    n3 -> i1;

    {rank=same; n4; E;}
    n2 -> n4;
    n4 -> E;

    {rank=same; n5; i2;}
    E -> n5;
    n5 -> i2;

    {rank=same; n6; i3;}
    i2 -> n6;
    n6 -> i3;
}

dot image drawn via PlantUML.com