Макет древовидной структуры с Dot/GraphViz
Я пытаюсь создать семейное дерево с Dot и GraphViz.
Это то, что у меня есть:
# just graph set-up
digraph simpsons {
ratio = "auto"
mincross = 2.0
# draw some nodes
"Abraham" [shape=box, regular=1, color="blue"] ;
"Mona" [shape=box, regular=1, color="pink"] ;
"Clancy" [shape=box, regular=1, color="blue"] ;
"Jackeline" [shape=box, regular=1, color="pink"] ;
"Herb" [shape=box, regular=1, color="blue"] ;
"Homer" [shape=box, regular=1, color="blue"] ;
"Marge" [shape=box, regular=1, color="pink"] ;
"Patty" [shape=box, regular=1, color="pink"] ;
"Selma" [shape=box, regular=1, color="pink"] ;
"Bart" [shape=box, regular=1, color="blue"] ;
"Lisa" [shape=box, regular=1, color="pink"] ;
"Maggie" [shape=box, regular=1, color="pink"] ;
"Ling" [shape=box, regular=1, color="blue"] ;
# creating tiny nodes w/ no label, no color
"ParentsHomer" [shape=diamond,style=filled,label="",height=.1,width=.1] ;
"ParentsMarge" [shape=diamond,style=filled,label="",height=.1,width=.1] ;
"ParentsBart" [shape=diamond,style=filled,label="",height=.1,width=.1] ;
# draw the edges
"Abraham" -> "ParentsHomer" [dir=none, weight=1] ;
"Mona" -> "ParentsHomer" [dir=none, weight=1] ;
"ParentsHomer" -> "Homer" [dir=none, weight=2] ;
"ParentsHomer" -> "Herb" [dir=none, weight=2] ;
"Clancy" -> "ParentsMarge" [dir=none, weight=1] ;
"Jackeline" -> "ParentsMarge" [dir=none, weight=1] ;
"ParentsMarge" -> "Marge" [dir=none, weight=2] ;
"ParentsMarge" -> "Patty" [dir=none, weight=2] ;
"ParentsMarge" -> "Selma" [dir=none, weight=2] ;
"Homer" -> "ParentsBart" [dir=none, weight=1] ;
"Marge" -> "ParentsBart" [dir=none, weight=1] ;
"ParentsBart" -> "Bart" [dir=none, weight=2] ;
"ParentsBart" -> "Lisa" [dir=none, weight=2] ;
"ParentsBart" -> "Maggie" [dir=none, weight=2] ;
"Selma" -> "Ling" [dir=none, weight=2] ;
}
Если я запустил это через точку (dot simpsons.dot -Tsvg > simpsons.svg
),
Я получаю следующий макет:
![Original, made by dot/graphviz]()
Тем не менее, я бы хотел, чтобы кромки были более "родословными": например, T-соединение между двумя женатыми лицами с вертикальной линией T, снова разветвляющейся в перевернутом T-узле с небольшими подразделениями для каждый из детей, как этот макет, выполнен в KolourPaint:
![what I would like to achieve]()
Каков синтаксис точки, который я должен использовать для достижения этого?
Ответы
Ответ 1
Вот другое решение:
digraph simpsons {
subgraph Generation0 {
rank = same
Abraham [shape = box, color = blue]
Mona [shape = box, color = pink]
AbrahamAndMona [shape = point]
Abraham -> AbrahamAndMona [dir = none]
AbrahamAndMona -> Mona [dir = none]
Clancy [shape = box, color = blue]
Jackeline [shape = box, color = pink]
ClancyAndJackeline [shape = point]
Clancy -> ClancyAndJackeline [dir = none]
ClancyAndJackeline -> Jackeline [dir = none]
}
subgraph Generation0Sons {
rank = same
AbrahamAndMonaSons [shape = point]
HerbSon [shape = point]
HomerSon [shape = point]
HerbSon -> AbrahamAndMonaSons [dir = none]
HomerSon -> AbrahamAndMonaSons [dir = none]
MargeSon [shape = point]
PattySon [shape = point]
SelmaSon [shape = point]
MargeSon -> PattySon [dir = none]
PattySon -> SelmaSon [dir = none]
}
AbrahamAndMona -> AbrahamAndMonaSons [dir = none]
ClancyAndJackeline -> PattySon [dir = none]
subgraph Generation1 {
rank = same
Herb [shape = box, color = blue]
Homer [shape = box, color = blue]
Marge [shape = box, color = pink]
Patty [shape = box, color = pink]
Selma [shape = box, color = pink]
HomerAndMarge [shape = point]
Homer -> HomerAndMarge [dir = none]
Marge -> HomerAndMarge [dir = none]
}
HerbSon -> Herb [dir = none]
HomerSon -> Homer [dir = none]
MargeSon -> Marge [dir = none]
PattySon -> Patty [dir = none]
SelmaSon -> Selma [dir = none]
subgraph Generation1Sons {
rank = same
BartSon [shape = point]
LisaSon [shape = point]
MaggieSon [shape = point]
BartSon -> LisaSon [dir = none]
LisaSon -> MaggieSon [dir = none]
}
HomerAndMarge -> LisaSon [dir = none]
subgraph Generation2 {
rank = same
Bart [shape = box, color = blue]
Lisa [shape = box, color = pink]
Maggie [shape = box, color = pink]
Ling [shape = box, color = blue]
}
Selma -> Ling [dir = none]
BartSon -> Bart [dir = none]
LisaSon -> Lisa [dir = none]
MaggieSon -> Maggie [dir = none]
}
И результат:
![http://dl.dropbox.com/u/72629/simpsons.png]()
Ответ 2
Gramps (www.gramps-project.org) генерирует точечные файлы для семейных деревьев, с или без узлов брака.
Существует также способ увидеть это в самом интерфейсе Gramps. http://gramps-project.org/wiki/index.php?title=Graph_View
Поэтому я бы сказал, посмотрите на выход вашего генеалогического древа, созданный Gramps
Ответ 3
Я не думаю, что вы можете взять произвольное генеалогическое дерево и автоматически сгенерировать точечный файл, где он всегда хорошо выглядит в GraphViz.
Но я думаю, вы всегда можете сделать так, чтобы вы выглядели хорошо, если вы:
- Используйте ранг = те же самые другие упомянутые ответы, чтобы получить соединения 'T', требуемые ОП
- Используйте трюк с упорядочением, который сделал Брайан Бланк, чтобы предотвратить странные строки
- Предположим, нет второго брака и наполовину братьев и сестер
- Нарисуйте только подмножество дерева, которое подчиняется следующим правилам:
- Пусть S будет "центром" человека
- Если у S есть братья и сестры, убедитесь, что S справа от всех.
- Если у S есть супруг, а у супруга есть братья и сестры, убедитесь, что супруг находится слева от всех своих братьев и сестер.
- Не показывайте племянников, племянниц, тетей или дядюшек супругов S или Ss
- Не показывать супругам братьев и сестер
- Не показывать супругам супругов братьев и сестер
- Покажите детям S, но не их супругам или детям
- Показать родителей S и родителей супруга
В результате будет отображаться не более 3 поколений одновременно с S в среднем поколении.
На рисунке ниже S = Гомер (немного измененный по сравнению с версией Брайана Бланка):
digraph G {
edge [dir=none];
node [shape=box];
graph [splines=ortho];
"Herb" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Homer" [shape=box, regular=0, color="blue", style="bold, filled" fillcolor="lightblue"] ;
"Marge" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Clancy" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Jackeline" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Abraham" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Mona" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Patty" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Selma" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Bart" [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
"Lisa" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
"Maggie" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
a1 [shape=diamond,label="",height=0.25,width=0.25];
b1 [shape=circle,label="",height=0.01,width=0.01];
b2 [shape=circle,label="",height=0.01,width=0.01];
b3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Abraham -> a1 -> Mona};
{rank=same; b1 -> b2 -> b3};
{rank=same; Herb; Homer};
a1 -> b2
b1 -> Herb
b3 -> Homer
p1 [shape=diamond,label="",height=0.25,width=0.25];
q1 [shape=circle,label="",height=0.01,width=0.01];
q2 [shape=circle,label="",height=0.01,width=0.01];
q3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Homer -> p1 -> Marge};
{rank=same; q1 -> q2 -> q3};
{rank=same; Bart; Lisa; Maggie};
p1 -> q2;
q1 -> Bart;
q2 -> Lisa;
q3 -> Maggie;
x1 [shape=diamond,label="",height=0.25,width=0.25];
y1 [shape=circle,label="",height=0.01,width=0.01];
y2 [shape=circle,label="",height=0.01,width=0.01];
y3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Clancy -> x1 -> Jackeline};
{rank=same; y1 -> y2 -> y3};
{rank=same; Patty; Selma; Marge};
x1 -> y2;
y1 -> Marge;
y2 -> Patty;
y3 -> Selma;
}
Это дает следующее дерево GraphViz (с аннотациями, которые я добавил с помощью Power Point): ![enter image description here]()
Ответ 4
Хотя вы не можете управлять размещением node, я обнаружил, что вы можете помочь в размещении node, заказав узлы в другом порядке. Я повторно заказал некоторые из узлов, как показано ниже, и получил график, в котором не было перекрестных переходов.
Следующий код:
digraph G {
edge [dir=none];
node [shape=box];
"Herb" [shape=box, regular=1, color="blue"] ;
"Homer" [shape=box, regular=1, color="blue"] ;
"Marge" [shape=box, regular=1, color="pink"] ;
"Clancy" [shape=box, regular=1, color="blue"] ;
"Jackeline" [shape=box, regular=1, color="pink"] ;
"Abraham" [shape=box, regular=1, color="blue"] ;
"Mona" [shape=box, regular=1, color="pink"] ;
"Patty" [shape=box, regular=1, color="pink"] ;
"Selma" [shape=box, regular=1, color="pink"] ;
"Bart" [shape=box, regular=1, color="blue"] ;
"Lisa" [shape=box, regular=1, color="pink"] ;
"Maggie" [shape=box, regular=1, color="pink"] ;
"Ling" [shape=box, regular=1, color="blue"] ;
a1 [shape=circle,label="",height=0.01,width=0.01];
b1 [shape=circle,label="",height=0.01,width=0.01];
b2 [shape=circle,label="",height=0.01,width=0.01];
b3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Abraham -> a1 -> Mona};
{rank=same; b1 -> b2 -> b3};
{rank=same; Herb; Homer};
a1 -> b2
b1 -> Herb
b3 -> Homer
p1 [shape=circle,label="",height=0.01,width=0.01];
q1 [shape=circle,label="",height=0.01,width=0.01];
q2 [shape=circle,label="",height=0.01,width=0.01];
q3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Homer -> p1 -> Marge};
{rank=same; q1 -> q2 -> q3};
{rank=same; Bart; Lisa; Maggie};
p1 -> q2;
q1 -> Bart;
q2 -> Lisa;
q3 -> Maggie;
x1 [shape=circle,label="",height=0.01,width=0.01];
y1 [shape=circle,label="",height=0.01,width=0.01];
y2 [shape=circle,label="",height=0.01,width=0.01];
y3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Clancy -> x1 -> Jackeline};
{rank=same; y1 -> y2 -> y3};
{rank=same; Marge; Patty; Selma};
{rank=same; Bart; Ling}
x1 -> y2;
y1 -> Marge;
y2 -> Patty;
y3 -> Selma;
Selma -> Ling;
}
теперь производит это:
![family tree layout]()
Я не совсем понимаю, почему он работает, но вот мыслительный процесс в тех изменениях, которые я сделал.
- Я положил Клэнси/Джеклайн, прежде чем Абрахам/Мона подумал, что они были на неправильной стороне. Это изменило картину, но все еще не было совершенным.
- Я помещал Гомера/Мардж сначала, думая, что программное обеспечение должно сначала рассмотреть эти части и, возможно, разместить все другие узлы относительно Гомера/Марджа. Это еще больше помогло, но все еще не было совершенным.
- Трава все еще была неправильно размещена, поэтому я сначала положил Herb так, чтобы Graphviz мог сначала рассмотреть размещение травы.
Это сработало, но я до сих пор не могу разработать алгоритм, который обеспечивал бы согласованные деревья без перекрывающихся ребер. Я чувствую, что Graphviz должен делать лучшую работу без этих намеков. Я не знаю, какой алгоритм используется, но если они рассматривают объективную функцию для минимизации или устранения перекрывающихся ребер, то должно быть возможно разработать лучший алгоритм.
Ответ 5
Сделать это в графвизе довольно просто; Есть несколько синтаксических шаблонов, которые вам нужны: (i) синтаксис для представления межстрочного соединения ("T" -junction на ваших графиках выше); (ii) синтаксис для обеспечения иерархической структуры (т.е. узлы одного поколения на одной плоскости на вертикальной оси). Это проще показать:
digraph G {
nodesep=0.6;
edge [arrowsize=0.3];
"g1" -> "g2" -> "g3" -> "g4"
{ rank = same;
"g1"; "King"; "ph1"; "Queen";
};
{ rank = same;
"g2"; "ph2"; "ph2L"; "ph2R"; "ph2LL"; "ph2RR"
};
{ rank = same;
"g3"; "ps1"; "ps2"; "pr1"; "pr2"
};
"King" -> "ph1" [arrowsize=0.0];
"ph1" -> "Queen" [arrowsize=0.0];
"ph1" -> "ph2" [arrowsize=0.0];
"ph2LL" -> "ph2L" [arrowsize=0.0];
"ph2L" -> "ph2" [arrowsize=0.0];
"ph2" -> "ph2R" [arrowsize=0.0];
"ph2R" -> "ph2RR" [arrowsize=0.0];
"ph2LL" -> "ps1" [arrowsize=0.0];
"ph2L"-> "pr1" [arrowsize=0.0];
"ph2R" -> "ps2" [arrowsize=0.0];
"ph2RR" -> "pr2" [arrowsize=0.0];
}
Код выше создаст график ниже (я пропустил код, который я использовал для окраски узлов). Я оставил видимым "проводник" слева (g1-> g2....) просто чтобы показать вам, как я усилил позиции среди узлов равного ранга, вы, вероятно, захотите сделать его невидимым на ваших собственных графиках. Наконец, узлы с метками, начинающимися с "ph", являются узлами-заполнителями для "T -junction s".
![alt text]()
Ответ 6
Я почти там, вдохновленный старый ответ в списке рассылки graphviz-interest и ответ doug.
Следующий код:
digraph G {
edge [dir=none];
node [shape=box];
"Abraham" [shape=box, regular=1, color="blue"] ;
"Mona" [shape=box, regular=1, color="pink"] ;
"Clancy" [shape=box, regular=1, color="blue"] ;
"Jackeline" [shape=box, regular=1, color="pink"] ;
"Herb" [shape=box, regular=1, color="blue"] ;
"Homer" [shape=box, regular=1, color="blue"] ;
"Marge" [shape=box, regular=1, color="pink"] ;
"Patty" [shape=box, regular=1, color="pink"] ;
"Selma" [shape=box, regular=1, color="pink"] ;
"Bart" [shape=box, regular=1, color="blue"] ;
"Lisa" [shape=box, regular=1, color="pink"] ;
"Maggie" [shape=box, regular=1, color="pink"] ;
"Ling" [shape=box, regular=1, color="blue"] ;
a1 [shape=circle,label="",height=0.01,width=0.01];
b1 [shape=circle,label="",height=0.01,width=0.01];
b2 [shape=circle,label="",height=0.01,width=0.01];
b3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Abraham -> a1 -> Mona};
{rank=same; b1 -> b2 -> b3};
{rank=same; Herb; Homer};
a1 -> b2
b1 -> Herb
b3 -> Homer
p1 [shape=circle,label="",height=0.01,width=0.01];
q1 [shape=circle,label="",height=0.01,width=0.01];
q2 [shape=circle,label="",height=0.01,width=0.01];
q3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Homer -> p1 -> Marge};
{rank=same; q1 -> q2 -> q3};
{rank=same; Bart; Lisa; Maggie};
p1 -> q2;
q1 -> Bart;
q2 -> Lisa;
q3 -> Maggie;
x1 [shape=circle,label="",height=0.01,width=0.01];
y1 [shape=circle,label="",height=0.01,width=0.01];
y2 [shape=circle,label="",height=0.01,width=0.01];
y3 [shape=circle,label="",height=0.01,width=0.01];
{rank=same; Clancy -> x1 -> Jackeline};
{rank=same; y1 -> y2 -> y3};
{rank=same; Marge; Patty; Selma};
{rank=same; Bart; Ling}
x1 -> y2;
y1 -> Marge;
y2 -> Patty;
y3 -> Selma;
Selma -> Ling;
}
теперь производит это:
![alt text]()
Итак, хорошо выглядит, за исключением того странного края вокруг Гомера. Если бы я мог найти способ переместить Абрахама, Мона и Херба в левую сторону картины, тогда у меня была бы идеально выровненная картина.
Любые идеи о том, как этого достичь?