I have a program that autogenerates a graphviz .dot file, the contents of which are a tree of subgraphs. When I observe how this file is rendered, the tree seems to be 'flattened', poorly displaying the hierarchical structure. I would like to know how to correct this issue, and properly render this tree.
In the past, I have used the fdp layout program to render this graph. It was able to show the hierarchical structure of the tree, but the contents of the nodes, which are subgraphs, were not very readable. I want to use the dot layout program since it does a better job layering the nodes of the subgraphs, and is said to be ideal for hierarchical graphs.
Please see the image below for a sample graph that shows the poorly rendered tree.
The code that generates this figure is:
digraph G {
compound=true
subgraph cluster_649 {label = EPISODE649count3
subgraph cluster_STATE650 {
label = State_1;
EPISODE649HEIGHT643[label="HEIGHT",shape=oval,color=blue];
EPISODE649LEN642[label="LEN",shape=oval,color=blue];
EPISODE649Y641[label="Y",shape=oval,color=blue];
EPISODE649X640[label="X",shape=oval,color=blue];
EPISODE649BLOCK639[label="BLOCK",shape=oval,color=blue];
EPISODE649HEIGHT638[label="HEIGHT",shape=oval,color=blue];
EPISODE649LEN637[label="LEN",shape=oval,color=blue];
EPISODE649Y636[label="Y",shape=oval,color=blue];
EPISODE649X635[label="X",shape=oval,color=blue];
EPISODE649TRIANGLE634[label="TRIANGLE",shape=oval,color=blue];
EPISODE649ON645[label="ON",shape=oval,color=blue];
EPISODE649ON555[label="ON",shape=oval,color=blue];
EPISODE649CLEAR647[label="CLEAR",shape=oval,color=blue];
EPISODE649CLEAR557[label="CLEAR",shape=oval,color=blue];
EPISODE649CLEAR558[label="CLEAR",shape=oval,color=blue];
EPISODE649ON556[label="ON",shape=oval,color=blue];
EPISODE649BLOCK545[label="BLOCK",shape=oval,color=blue];
EPISODE649X546[label="X",shape=oval,color=blue];
EPISODE649Y547[label="Y",shape=oval,color=blue];
EPISODE649LEN548[label="LEN",shape=oval,color=blue];
EPISODE649HEIGHT549[label="HEIGHT",shape=oval,color=blue];
EPISODE649BLOCK550[label="BLOCK",shape=oval,color=blue];
EPISODE649X551[label="X",shape=oval,color=blue];
EPISODE649Y552[label="Y",shape=oval,color=blue];
EPISODE649LEN553[label="LEN",shape=oval,color=blue];
EPISODE649HEIGHT554[label="HEIGHT",shape=oval,color=blue];
EPISODE649BLOCK639 -> EPISODE649HEIGHT643;
EPISODE649BLOCK639 -> EPISODE649LEN642;
EPISODE649BLOCK639 -> EPISODE649Y641;
EPISODE649BLOCK639 -> EPISODE649X640;
EPISODE649TRIANGLE634 -> EPISODE649HEIGHT638;
EPISODE649TRIANGLE634 -> EPISODE649LEN637;
EPISODE649TRIANGLE634 -> EPISODE649Y636;
EPISODE649TRIANGLE634 -> EPISODE649X635;
EPISODE649ON645 -> EPISODE649HEIGHT643;
EPISODE649ON645 -> EPISODE649LEN642;
EPISODE649ON645 -> EPISODE649Y641;
EPISODE649ON645 -> EPISODE649X640;
EPISODE649ON645 -> EPISODE649BLOCK639;
EPISODE649ON645 -> EPISODE649HEIGHT638;
EPISODE649ON645 -> EPISODE649LEN637;
EPISODE649ON645 -> EPISODE649Y636;
EPISODE649ON645 -> EPISODE649X635;
EPISODE649ON645 -> EPISODE649TRIANGLE634;
EPISODE649ON555 -> EPISODE649ON645;
EPISODE649ON555 -> EPISODE649ON556;
EPISODE649CLEAR647 -> EPISODE649HEIGHT638;
EPISODE649CLEAR647 -> EPISODE649LEN637;
EPISODE649CLEAR647 -> EPISODE649Y636;
EPISODE649CLEAR647 -> EPISODE649X635;
EPISODE649CLEAR647 -> EPISODE649TRIANGLE634;
EPISODE649CLEAR557 -> EPISODE649CLEAR647;
EPISODE649CLEAR557 -> EPISODE649CLEAR558;
EPISODE649CLEAR558 -> EPISODE649BLOCK545;
EPISODE649CLEAR558 -> EPISODE649X546;
EPISODE649CLEAR558 -> EPISODE649Y547;
EPISODE649CLEAR558 -> EPISODE649LEN548;
EPISODE649CLEAR558 -> EPISODE649HEIGHT549;
EPISODE649ON556 -> EPISODE649BLOCK545;
EPISODE649ON556 -> EPISODE649X546;
EPISODE649ON556 -> EPISODE649Y547;
EPISODE649ON556 -> EPISODE649LEN548;
EPISODE649ON556 -> EPISODE649HEIGHT549;
EPISODE649ON556 -> EPISODE649BLOCK550;
EPISODE649ON556 -> EPISODE649X551;
EPISODE649ON556 -> EPISODE649Y552;
EPISODE649ON556 -> EPISODE649LEN553;
EPISODE649ON556 -> EPISODE649HEIGHT554;
EPISODE649BLOCK545 -> EPISODE649X546;
EPISODE649BLOCK545 -> EPISODE649Y547;
EPISODE649BLOCK545 -> EPISODE649LEN548;
EPISODE649BLOCK545 -> EPISODE649HEIGHT549;
EPISODE649BLOCK550 -> EPISODE649X551;
EPISODE649BLOCK550 -> EPISODE649Y552;
EPISODE649BLOCK550 -> EPISODE649LEN553;
EPISODE649BLOCK550 -> EPISODE649HEIGHT554;
}
649[shape=point style=invis]
}
subgraph cluster_559 {label = EPISODE559count1
subgraph cluster_STATE651 {
label = State_1;
EPISODE559CLEAR557[label="CLEAR",shape=oval,color=blue];
EPISODE559CLEAR558[label="CLEAR",shape=oval,color=blue];
EPISODE559ON555[label="ON",shape=oval,color=blue];
EPISODE559ON556[label="ON",shape=oval,color=blue];
EPISODE559BLOCK545[label="BLOCK",shape=oval,color=blue];
EPISODE559X546[label="X",shape=oval,color=blue];
EPISODE559Y547[label="Y",shape=oval,color=blue];
EPISODE559LEN548[label="LEN",shape=oval,color=blue];
EPISODE559HEIGHT549[label="HEIGHT",shape=oval,color=blue];
EPISODE559BLOCK550[label="BLOCK",shape=oval,color=blue];
EPISODE559X551[label="X",shape=oval,color=blue];
EPISODE559Y552[label="Y",shape=oval,color=blue];
EPISODE559LEN553[label="LEN",shape=oval,color=blue];
EPISODE559HEIGHT554[label="HEIGHT",shape=oval,color=blue];
EPISODE559CLEAR557 -> EPISODE559CLEAR558;
EPISODE559CLEAR558 -> EPISODE559BLOCK545;
EPISODE559CLEAR558 -> EPISODE559X546;
EPISODE559CLEAR558 -> EPISODE559Y547;
EPISODE559CLEAR558 -> EPISODE559LEN548;
EPISODE559CLEAR558 -> EPISODE559HEIGHT549;
EPISODE559ON555 -> EPISODE559ON556;
EPISODE559ON556 -> EPISODE559BLOCK545;
EPISODE559ON556 -> EPISODE559X546;
EPISODE559ON556 -> EPISODE559Y547;
EPISODE559ON556 -> EPISODE559LEN548;
EPISODE559ON556 -> EPISODE559HEIGHT549;
EPISODE559ON556 -> EPISODE559BLOCK550;
EPISODE559ON556 -> EPISODE559X551;
EPISODE559ON556 -> EPISODE559Y552;
EPISODE559ON556 -> EPISODE559LEN553;
EPISODE559ON556 -> EPISODE559HEIGHT554;
EPISODE559BLOCK545 -> EPISODE559X546;
EPISODE559BLOCK545 -> EPISODE559Y547;
EPISODE559BLOCK545 -> EPISODE559LEN548;
EPISODE559BLOCK545 -> EPISODE559HEIGHT549;
EPISODE559BLOCK550 -> EPISODE559X551;
EPISODE559BLOCK550 -> EPISODE559Y552;
EPISODE559BLOCK550 -> EPISODE559LEN553;
EPISODE559BLOCK550 -> EPISODE559HEIGHT554;
}
559[shape=point style=invis]
}
649 -> 559 [ltail=cluster_649 lhead=cluster_559];
subgraph cluster_625 {label = EPISODE625count1
subgraph cluster_STATE652 {
label = State_1;
EPISODE625CLEAR623[label="CLEAR",shape=oval,color=blue];
EPISODE625CLEAR624[label="CLEAR",shape=oval,color=blue];
EPISODE625ON621[label="ON",shape=oval,color=blue];
EPISODE625ON622[label="ON",shape=oval,color=blue];
EPISODE625BLOCK611[label="BLOCK",shape=oval,color=blue];
EPISODE625X612[label="X",shape=oval,color=blue];
EPISODE625Y613[label="Y",shape=oval,color=blue];
EPISODE625LEN614[label="LEN",shape=oval,color=blue];
EPISODE625HEIGHT615[label="HEIGHT",shape=oval,color=blue];
EPISODE625BLOCK616[label="BLOCK",shape=oval,color=blue];
EPISODE625X617[label="X",shape=oval,color=blue];
EPISODE625Y618[label="Y",shape=oval,color=blue];
EPISODE625LEN619[label="LEN",shape=oval,color=blue];
EPISODE625HEIGHT620[label="HEIGHT",shape=oval,color=blue];
EPISODE625CLEAR623 -> EPISODE625CLEAR624;
EPISODE625CLEAR624 -> EPISODE625BLOCK611;
EPISODE625CLEAR624 -> EPISODE625X612;
EPISODE625CLEAR624 -> EPISODE625Y613;
EPISODE625CLEAR624 -> EPISODE625LEN614;
EPISODE625CLEAR624 -> EPISODE625HEIGHT615;
EPISODE625ON621 -> EPISODE625ON622;
EPISODE625ON622 -> EPISODE625BLOCK611;
EPISODE625ON622 -> EPISODE625X612;
EPISODE625ON622 -> EPISODE625Y613;
EPISODE625ON622 -> EPISODE625LEN614;
EPISODE625ON622 -> EPISODE625HEIGHT615;
EPISODE625ON622 -> EPISODE625BLOCK616;
EPISODE625ON622 -> EPISODE625X617;
EPISODE625ON622 -> EPISODE625Y618;
EPISODE625ON622 -> EPISODE625LEN619;
EPISODE625ON622 -> EPISODE625HEIGHT620;
EPISODE625BLOCK611 -> EPISODE625X612;
EPISODE625BLOCK611 -> EPISODE625Y613;
EPISODE625BLOCK611 -> EPISODE625LEN614;
EPISODE625BLOCK611 -> EPISODE625HEIGHT615;
EPISODE625BLOCK616 -> EPISODE625X617;
EPISODE625BLOCK616 -> EPISODE625Y618;
EPISODE625BLOCK616 -> EPISODE625LEN619;
EPISODE625BLOCK616 -> EPISODE625HEIGHT620;
}
625[shape=point style=invis]
}
649 -> 625 [ltail=cluster_649 lhead=cluster_625];
subgraph cluster_648 {label = EPISODE648count1
subgraph cluster_STATE653 {
label = State_1;
EPISODE648CLEAR646[label="CLEAR",shape=oval,color=blue];
EPISODE648CLEAR647[label="CLEAR",shape=oval,color=blue];
EPISODE648ON644[label="ON",shape=oval,color=blue];
EPISODE648ON645[label="ON",shape=oval,color=blue];
EPISODE648TRIANGLE634[label="TRIANGLE",shape=oval,color=blue];
EPISODE648X635[label="X",shape=oval,color=blue];
EPISODE648Y636[label="Y",shape=oval,color=blue];
EPISODE648LEN637[label="LEN",shape=oval,color=blue];
EPISODE648HEIGHT638[label="HEIGHT",shape=oval,color=blue];
EPISODE648BLOCK639[label="BLOCK",shape=oval,color=blue];
EPISODE648X640[label="X",shape=oval,color=blue];
EPISODE648Y641[label="Y",shape=oval,color=blue];
EPISODE648LEN642[label="LEN",shape=oval,color=blue];
EPISODE648HEIGHT643[label="HEIGHT",shape=oval,color=blue];
EPISODE648CLEAR646 -> EPISODE648CLEAR647;
EPISODE648CLEAR647 -> EPISODE648TRIANGLE634;
EPISODE648CLEAR647 -> EPISODE648X635;
EPISODE648CLEAR647 -> EPISODE648Y636;
EPISODE648CLEAR647 -> EPISODE648LEN637;
EPISODE648CLEAR647 -> EPISODE648HEIGHT638;
EPISODE648ON644 -> EPISODE648ON645;
EPISODE648ON645 -> EPISODE648TRIANGLE634;
EPISODE648ON645 -> EPISODE648X635;
EPISODE648ON645 -> EPISODE648Y636;
EPISODE648ON645 -> EPISODE648LEN637;
EPISODE648ON645 -> EPISODE648HEIGHT638;
EPISODE648ON645 -> EPISODE648BLOCK639;
EPISODE648ON645 -> EPISODE648X640;
EPISODE648ON645 -> EPISODE648Y641;
EPISODE648ON645 -> EPISODE648LEN642;
EPISODE648ON645 -> EPISODE648HEIGHT643;
EPISODE648TRIANGLE634 -> EPISODE648X635;
EPISODE648TRIANGLE634 -> EPISODE648Y636;
EPISODE648TRIANGLE634 -> EPISODE648LEN637;
EPISODE648TRIANGLE634 -> EPISODE648HEIGHT638;
EPISODE648BLOCK639 -> EPISODE648X640;
EPISODE648BLOCK639 -> EPISODE648Y641;
EPISODE648BLOCK639 -> EPISODE648LEN642;
EPISODE648BLOCK639 -> EPISODE648HEIGHT643;
}
648[shape=point style=invis]
}
649 -> 648 [ltail=cluster_649 lhead=cluster_648];
}
Observe that in order to draw edges from cluster to cluster, I've created invisible nodes in each cluster, like: 625[shape=point style=invis] and connected two invisible nodes if there is a parent/child relation between the two clusters, like: 649 -> 625 [ltail=cluster_649 lhead=cluster_625];
Thanks for your help!
Your invisible nodes were a good idea, but you got caught by dot's (unwritten?) rule that all nodes should be on the same rank unless there is a command the "forces" a new rank. If you change "invisible" to "dotted", you will see what happened to those nodes.
I tried to find a straightforward way to get dot to play nicely with those extra nodes, but failed.
Eventually I used some of the existing nodes to accomplish what I assume is the goal.
I left these edges visible so you could easily see what I changed.
I also added peripheries and margin attributes.
A cut-down version of the program:
digraph G {
compound = true
// a dummy cluster to pad the left side
subgraph cluster_dummy{
label="" ; peripheries=0;node[style=invis]; {rank=same _a; _b }
}
peripheries=0
subgraph cluster_649 {
label = EPISODE649count3
subgraph cluster_STATE650 {
graph [ margin=30]
label = State_1;
// unmodified nodes go here
}
}
subgraph cluster_559 {
label = EPISODE559count1
subgraph cluster_STATE651 {
graph [ margin=30]
label = State_1;
// unmodified nodes go here
}
}
subgraph cluster_625 {
label = EPISODE625count1
subgraph cluster_STATE652 {
graph [ margin=30]
label = State_1;
// unmodified nodes go here
}
}
subgraph cluster_648 {
label = EPISODE648count1
subgraph cluster_STATE653 {
graph [ margin=30]
label = State_1;
// unmodified nodes go here
}
}
EPISODE649HEIGHT638 -> EPISODE559ON555 [weight=0 style=dotted]
EPISODE649HEIGHT638 -> EPISODE625ON621 [weight=0 style=dotted]
EPISODE649HEIGHT638 -> EPISODE648ON644 [weight=0 style=dotted]
}
is there a way to eliminate the crossing of edges?
I tried many ways, nothing helped.
digraph graphname {
graph [splines=ortho,];
node [shape=box,];
l;
l_a [shape=diamond,label="",height=0.20,width=0.20];
l_a_s [shape=point];
l_a_i [shape=point];
l_a_ii [shape=point];
l_a -> l_a_s;
{rank=same; a -> l_a -> l}
{rank=same; l_a_i -> l_a_s -> l_a_ii}
l_a_i -> i;
l_a_ii -> ii;
l_c [shape=diamond,label="",height=0.20,width=0.20];
l_c_s [shape=point];
l_c_t [shape=point];
l_c_n [shape=point];
l_c -> l_c_s;
{rank=same; l -> l_c -> c}
{rank=same; l_c_t -> l_c_s -> l_c_n}
l_c_t -> t;
l_c_n -> n;
}
some more details:
All you need to do is to reorganize your node/edge definitions a little bit, no additional edges needed.
for example:
digraph graphname {
graph [splines=ortho,];
node [shape=box,];
a;
l_a [shape=diamond,label="",height=0.20,width=0.20];
l;
l_c [shape=diamond,label="",height=0.20,width=0.20];
c;
{rank=same; a -> l_a -> l -> l_c -> c}
l_a_s [shape=point];
l_c_s [shape=point];
l_a -> l_a_s;
l_c -> l_c_s;
l_a_i [shape=point];
l_a_ii [shape=point];
l_c_t [shape=point];
l_c_n [shape=point];
{rank=same;
l_a_i -> l_a_s -> l_a_ii;
l_c_t -> l_c_s -> l_c_n;}
l_a_i -> i;
l_a_ii -> ii;
l_c_t -> t;
l_c_n -> n;
}
Adding this invisible edge solves your problem:
l_a_i -> l_c_s [constraint=false style=invis]
I can't prove mathematically why this works, but in such situation it usually helps to play with order in which nodes/edges are defined, or try adding invisible adges to nudge the layout in the direction you need
Consider the following graphviz file - is it possible to draw a graph for it? I experimented with sfdp, K, repulsiveforce, overlap, but I couldn't find any decent setup:
digraph {
"setup_dirs_fds" -> "snprintf"
"setup_dirs_fds" -> "fdopen"
"setup_dirs_fds" -> "mkdir"
"setup_dirs_fds" -> "__errno_location"
"setup_dirs_fds" -> "strerror"
"setup_dirs_fds" -> "DFL_ck_alloc"
"setup_dirs_fds" -> "DFL_ck_free"
"setup_dirs_fds" -> "exit"
"setup_dirs_fds" -> "printf"
"setup_dirs_fds" -> "fprintf"
"setup_dirs_fds" -> "fflush"
"setup_dirs_fds" -> "maybe_delete_out_dir"
"setup_dirs_fds" -> "open"
"setup_dirs_fds" -> "flock"
"afl_main" -> "setup_dirs_fds"
"afl_main" -> "sscanf"
"afl_main" -> "write_bitmap"
"afl_main" -> "get_qemu_argv"
"afl_main" -> "perform_dry_run"
"afl_main" -> "check_cpu_governor"
"afl_main" -> "fclose"
"afl_main" -> "get_cur_time"
"afl_main" -> "check_if_tty"
"afl_main" -> "destroy_queue"
"afl_main" -> "setup_signal_handlers"
"afl_main" -> "sleep"
"afl_main" -> "find_start_position"
"afl_main" -> "printf"
"afl_main" -> "check_crash_handling"
"afl_main" -> "get_core_count"
"afl_main" -> "fflush"
"afl_main" -> "DFL_ck_alloc"
"afl_main" -> "fix_up_sync"
"afl_main" -> "sync_fuzzers"
"afl_main" -> "write_stats_file"
"afl_main" -> "save_cmdline"
"afl_main" -> "detect_file_args"
"afl_main" -> "show_init_stats"
"afl_main" -> "access"
"afl_main" -> "setup_post"
"afl_main" -> "DFL_ck_free"
"afl_main" -> "exit"
"afl_main" -> "usage"
"afl_main" -> "getopt"
"afl_main" -> "setup_stdio_file"
"afl_main" -> "read_bitmap"
"afl_main" -> "destroy_extras"
"afl_main" -> "read_testcases"
"afl_main" -> "pivot_inputs"
"afl_main" -> "fix_up_banner"
"afl_main" -> "getenv"
"afl_main" -> "setup_shm"
"afl_main" -> "cull_queue"
"afl_main" -> "save_auto"
"afl_main" -> "show_stats"
"afl_main" -> "find_timeout"
"afl_main" -> "load_extras"
"afl_main" -> "load_auto"
"afl_main" -> "check_binary"
"afl_main" -> "check_asan_opts"
"afl_main" -> "fuzz_one"
"afl_main" -> "init_G"
"afl_main" -> "strcmp"
"write_bitmap" -> "snprintf"
"write_bitmap" -> "__errno_location"
"write_bitmap" -> "strerror"
"write_bitmap" -> "DFL_ck_free"
"write_bitmap" -> "exit"
"write_bitmap" -> "printf"
"write_bitmap" -> "close"
"write_bitmap" -> "fflush"
"write_bitmap" -> "open"
"write_bitmap" -> "DFL_ck_alloc"
"get_qemu_argv" -> "snprintf"
"get_qemu_argv" -> "memcpy"
"get_qemu_argv" -> "getenv"
"get_qemu_argv" -> "access"
"get_qemu_argv" -> "DFL_ck_free"
"get_qemu_argv" -> "exit"
"get_qemu_argv" -> "printf"
"get_qemu_argv" -> "strrchr"
"get_qemu_argv" -> "DFL_ck_strdup"
"get_qemu_argv" -> "DFL_ck_alloc"
"perform_dry_run" -> "calibrate_case"
"perform_dry_run" -> "DFL_ck_alloc_nozero"
"perform_dry_run" -> "check_map_coverage"
"perform_dry_run" -> "__errno_location"
"perform_dry_run" -> "strerror"
"perform_dry_run" -> "getenv"
"perform_dry_run" -> "DFL_ck_free"
"perform_dry_run" -> "exit"
"perform_dry_run" -> "DMS"
"perform_dry_run" -> "printf"
"perform_dry_run" -> "close"
"perform_dry_run" -> "strrchr"
"perform_dry_run" -> "fflush"
"perform_dry_run" -> "open"
"check_cpu_governor" -> "strncmp"
"check_cpu_governor" -> "fscanf"
"check_cpu_governor" -> "fclose"
"check_cpu_governor" -> "__errno_location"
"check_cpu_governor" -> "strerror"
"check_cpu_governor" -> "getenv"
"check_cpu_governor" -> "exit"
"check_cpu_governor" -> "printf"
"check_cpu_governor" -> "fgets"
"check_cpu_governor" -> "fflush"
"check_cpu_governor" -> "fopen"
"nuke_resume_dir" -> "snprintf"
"nuke_resume_dir" -> "__errno_location"
"nuke_resume_dir" -> "DFL_ck_free"
"nuke_resume_dir" -> "exit"
"nuke_resume_dir" -> "delete_files"
"nuke_resume_dir" -> "printf"
"nuke_resume_dir" -> "DFL_ck_alloc"
"nuke_resume_dir" -> "rmdir"
"maybe_update_plot_file" -> "fflush"
"maybe_update_plot_file" -> "fprintf"
"maybe_update_plot_file" -> "get_cur_time"
"check_if_tty" -> "ioctl"
"check_if_tty" -> "__errno_location"
"check_if_tty" -> "printf"
"destroy_queue" -> "DFL_ck_free"
"setup_signal_handlers" -> "sigemptyset"
"setup_signal_handlers" -> "sigaction"
"save_if_interesting" -> "calibrate_case"
"save_if_interesting" -> "snprintf"
"save_if_interesting" -> "get_cur_time"
"save_if_interesting" -> "open"
"save_if_interesting" -> "has_new_bits"
"save_if_interesting" -> "add_to_queue"
"save_if_interesting" -> "__errno_location"
"save_if_interesting" -> "hash32"
"save_if_interesting" -> "write_crash_readme"
"save_if_interesting" -> "strerror"
"save_if_interesting" -> "simplify_trace"
"save_if_interesting" -> "DFL_ck_free"
"save_if_interesting" -> "exit"
"save_if_interesting" -> "printf"
"save_if_interesting" -> "close"
"save_if_interesting" -> "fflush"
"save_if_interesting" -> "describe_op"
"save_if_interesting" -> "DFL_ck_alloc"
"find_start_position" -> "strstr"
"find_start_position" -> "snprintf"
"find_start_position" -> "DFL_ck_free"
"find_start_position" -> "exit"
"find_start_position" -> "printf"
"find_start_position" -> "close"
"find_start_position" -> "atoi"
"find_start_position" -> "open"
"find_start_position" -> "DFL_ck_alloc"
"check_crash_handling" -> "close"
"check_crash_handling" -> "open"
"check_crash_handling" -> "printf"
"load_auto" -> "snprintf"
"load_auto" -> "maybe_add_auto"
"load_auto" -> "__errno_location"
"load_auto" -> "strerror"
"load_auto" -> "DFL_ck_free"
"load_auto" -> "exit"
"load_auto" -> "printf"
"load_auto" -> "close"
"load_auto" -> "fflush"
"load_auto" -> "open"
"load_auto" -> "DFL_ck_alloc"
"link_or_copy" -> "__errno_location"
"link_or_copy" -> "strerror"
"link_or_copy" -> "DFL_ck_free"
"link_or_copy" -> "link"
"link_or_copy" -> "printf"
"link_or_copy" -> "close"
"link_or_copy" -> "exit"
"link_or_copy" -> "fflush"
"link_or_copy" -> "open"
"link_or_copy" -> "DFL_ck_alloc"
"DFL_ck_alloc" -> "memset"
"DFL_ck_alloc" -> "DFL_ck_alloc_nozero"
"read_testcases" -> "strstr"
"read_testcases" -> "snprintf"
"read_testcases" -> "lstat"
"read_testcases" -> "add_to_queue"
"read_testcases" -> "__errno_location"
"read_testcases" -> "strerror"
"read_testcases" -> "free"
"read_testcases" -> "access"
"read_testcases" -> "DFL_ck_free"
"read_testcases" -> "exit"
"read_testcases" -> "DMS"
"read_testcases" -> "printf"
"read_testcases" -> "fflush"
"read_testcases" -> "DFL_ck_alloc"
"read_testcases" -> "scandir"
"mark_as_redundant" -> "snprintf"
"mark_as_redundant" -> "__errno_location"
"mark_as_redundant" -> "strerror"
"mark_as_redundant" -> "DFL_ck_free"
"mark_as_redundant" -> "exit"
"mark_as_redundant" -> "printf"
"mark_as_redundant" -> "close"
"mark_as_redundant" -> "strrchr"
"mark_as_redundant" -> "fflush"
"mark_as_redundant" -> "unlink"
"mark_as_redundant" -> "open"
"mark_as_redundant" -> "DFL_ck_alloc"
"DFL_ck_realloc" -> "realloc"
"DFL_ck_realloc" -> "DFL_ck_free"
"DFL_ck_realloc" -> "abort"
"DFL_ck_realloc" -> "memset"
"DFL_ck_realloc" -> "printf"
"load_extras_file" -> "strchr"
"load_extras_file" -> "DMS"
"load_extras_file" -> "tolower"
"load_extras_file" -> "DFL_ck_realloc_block"
"load_extras_file" -> "fclose"
"load_extras_file" -> "__errno_location"
"load_extras_file" -> "strerror"
"load_extras_file" -> "__ctype_b_loc"
"load_extras_file" -> "atoi"
"load_extras_file" -> "exit"
"load_extras_file" -> "printf"
"load_extras_file" -> "fgets"
"load_extras_file" -> "fflush"
"load_extras_file" -> "fopen"
"load_extras_file" -> "strlen"
"load_extras_file" -> "DFL_ck_alloc"
"sync_fuzzers" -> "show_stats"
"sync_fuzzers" -> "fstat"
"sync_fuzzers" -> "sscanf"
"sync_fuzzers" -> "snprintf"
"sync_fuzzers" -> "save_if_interesting"
"sync_fuzzers" -> "write_to_testcase"
"sync_fuzzers" -> "__errno_location"
"sync_fuzzers" -> "strerror"
"sync_fuzzers" -> "readdir"
"sync_fuzzers" -> "DFL_ck_alloc"
"sync_fuzzers" -> "closedir"
"sync_fuzzers" -> "opendir"
"sync_fuzzers" -> "DFL_ck_free"
"sync_fuzzers" -> "exit"
"sync_fuzzers" -> "sprintf"
"sync_fuzzers" -> "printf"
"sync_fuzzers" -> "close"
"sync_fuzzers" -> "fflush"
"sync_fuzzers" -> "run_target"
"sync_fuzzers" -> "open"
"sync_fuzzers" -> "strcmp"
"write_stats_file" -> "snprintf"
"write_stats_file" -> "fdopen"
"write_stats_file" -> "fclose"
"write_stats_file" -> "__errno_location"
"write_stats_file" -> "strerror"
"write_stats_file" -> "get_cur_time"
"write_stats_file" -> "DFL_ck_free"
"write_stats_file" -> "exit"
"write_stats_file" -> "getpid"
"write_stats_file" -> "printf"
"write_stats_file" -> "fprintf"
"write_stats_file" -> "fflush"
"write_stats_file" -> "open"
"write_stats_file" -> "DFL_ck_alloc"
"check_binary" -> "strchr"
"check_binary" -> "strncmp"
"check_binary" -> "stat"
"check_binary" -> "snprintf"
"check_binary" -> "memcmp"
"check_binary" -> "__errno_location"
"check_binary" -> "strerror"
"check_binary" -> "memcpy"
"check_binary" -> "getenv"
"check_binary" -> "DFL_ck_free"
"check_binary" -> "exit"
"check_binary" -> "printf"
"check_binary" -> "close"
"check_binary" -> "fflush"
"check_binary" -> "DFL_ck_strdup"
"check_binary" -> "open"
"check_binary" -> "DFL_ck_alloc"
"detect_file_args" -> "strstr"
"detect_file_args" -> "snprintf"
"detect_file_args" -> "__errno_location"
"detect_file_args" -> "strerror"
"detect_file_args" -> "free"
"detect_file_args" -> "DFL_ck_free"
"detect_file_args" -> "exit"
"detect_file_args" -> "printf"
"detect_file_args" -> "fflush"
"detect_file_args" -> "DFL_ck_alloc"
"show_init_stats" -> "DMS"
"show_init_stats" -> "DI"
"show_init_stats" -> "printf"
"check_term_size" -> "ioctl"
"mark_as_det_done" -> "snprintf"
"mark_as_det_done" -> "__errno_location"
"mark_as_det_done" -> "strerror"
"mark_as_det_done" -> "DFL_ck_free"
"mark_as_det_done" -> "exit"
"mark_as_det_done" -> "printf"
"mark_as_det_done" -> "close"
"mark_as_det_done" -> "strrchr"
"mark_as_det_done" -> "fflush"
"mark_as_det_done" -> "open"
"mark_as_det_done" -> "DFL_ck_alloc"
"setup_post" -> ""
"setup_post" -> "dlsym"
"setup_post" -> "getenv"
"setup_post" -> "exit"
"setup_post" -> "dlerror"
"setup_post" -> "printf"
"setup_post" -> "dlopen"
"DFL_ck_free" -> "abort"
"DFL_ck_free" -> "free"
"DFL_ck_free" -> "printf"
"add_to_queue" -> "DFL_ck_alloc"
"add_to_queue" -> "get_cur_time"
"usage" -> "exit"
"usage" -> "printf"
"setup_stdio_file" -> "snprintf"
"setup_stdio_file" -> "__errno_location"
"setup_stdio_file" -> "strerror"
"setup_stdio_file" -> "DFL_ck_free"
"setup_stdio_file" -> "exit"
"setup_stdio_file" -> "printf"
"setup_stdio_file" -> "fflush"
"setup_stdio_file" -> "unlink"
"setup_stdio_file" -> "open"
"setup_stdio_file" -> "DFL_ck_alloc"
"describe_op" -> "strlen"
"describe_op" -> "sprintf"
"describe_op" -> "strcat"
"read_bitmap" -> "__errno_location"
"read_bitmap" -> "strerror"
"read_bitmap" -> "exit"
"read_bitmap" -> "printf"
"read_bitmap" -> "close"
"read_bitmap" -> "fflush"
"read_bitmap" -> "open"
"destroy_extras" -> "DFL_ck_free"
"fix_up_sync" -> "snprintf"
"fix_up_sync" -> "exit"
"fix_up_sync" -> "printf"
"fix_up_sync" -> "__ctype_b_loc"
"fix_up_sync" -> "strlen"
"fix_up_sync" -> "DFL_ck_alloc"
"save_cmdline" -> "strlen"
"save_cmdline" -> "DFL_ck_alloc"
"save_cmdline" -> "memcpy"
"DFL_ck_memdup_str" -> "malloc"
"DFL_ck_memdup_str" -> "abort"
"DFL_ck_memdup_str" -> "memcpy"
"DFL_ck_memdup_str" -> "printf"
"pivot_inputs" -> "strncmp"
"pivot_inputs" -> "strchr"
"pivot_inputs" -> "sscanf"
"pivot_inputs" -> "snprintf"
"pivot_inputs" -> "nuke_resume_dir"
"pivot_inputs" -> "mark_as_det_done"
"pivot_inputs" -> "strstr"
"pivot_inputs" -> "DFL_ck_free"
"pivot_inputs" -> "exit"
"pivot_inputs" -> "printf"
"pivot_inputs" -> "strrchr"
"pivot_inputs" -> "link_or_copy"
"pivot_inputs" -> "DFL_ck_alloc"
"fix_up_banner" -> "strrchr"
"fix_up_banner" -> "strlen"
"fix_up_banner" -> "DFL_ck_alloc"
"fix_up_banner" -> "sprintf"
"find_timeout" -> "strstr"
"find_timeout" -> "snprintf"
"find_timeout" -> "DFL_ck_free"
"find_timeout" -> "exit"
"find_timeout" -> "printf"
"find_timeout" -> "close"
"find_timeout" -> "atoi"
"find_timeout" -> "open"
"find_timeout" -> "DFL_ck_alloc"
"cull_queue" -> "mark_as_redundant"
"cull_queue" -> "memset"
"save_auto" -> "snprintf"
"save_auto" -> "__errno_location"
"save_auto" -> "strerror"
"save_auto" -> "DFL_ck_free"
"save_auto" -> "exit"
"save_auto" -> "printf"
"save_auto" -> "close"
"save_auto" -> "fflush"
"save_auto" -> "open"
"save_auto" -> "DFL_ck_alloc"
"show_stats" -> "get_runnable_processes"
"show_stats" -> "count_bits"
"show_stats" -> "memset"
"show_stats" -> "write_bitmap"
"show_stats" -> "write_stats_file"
"show_stats" -> "DI"
"show_stats" -> "DF"
"show_stats" -> "printf"
"show_stats" -> "check_term_size"
"show_stats" -> "maybe_update_plot_file"
"show_stats" -> "get_cur_time"
"show_stats" -> "strcat"
"show_stats" -> "DTD"
"show_stats" -> "strcpy"
"show_stats" -> "sprintf"
"show_stats" -> "count_non_255_bytes"
"show_stats" -> "save_auto"
"show_stats" -> "getenv"
"show_stats" -> "strlen"
"show_stats" -> "fflush"
"DFL_ck_alloc_nozero" -> "malloc"
"DFL_ck_alloc_nozero" -> "abort"
"DFL_ck_alloc_nozero" -> "printf"
"DFL_ck_realloc_block" -> "DFL_ck_realloc"
"DFL_ck_realloc_block" -> "abort"
"DFL_ck_realloc_block" -> "printf"
"write_crash_readme" -> "DMS"
"write_crash_readme" -> "snprintf"
"write_crash_readme" -> "fdopen"
"write_crash_readme" -> "fprintf"
"write_crash_readme" -> "fclose"
"write_crash_readme" -> "DFL_ck_free"
"write_crash_readme" -> "exit"
"write_crash_readme" -> "printf"
"write_crash_readme" -> "close"
"write_crash_readme" -> "open"
"write_crash_readme" -> "DFL_ck_alloc"
"check_map_coverage" -> "count_bytes"
"check_map_coverage" -> "printf"
"write_to_testcase" -> "lseek"
"write_to_testcase" -> "__errno_location"
"write_to_testcase" -> "strerror"
"write_to_testcase" -> "exit"
"write_to_testcase" -> "printf"
"write_to_testcase" -> "close"
"write_to_testcase" -> "ftruncate"
"write_to_testcase" -> "fflush"
"write_to_testcase" -> "unlink"
"write_to_testcase" -> "open"
"handle_timeout" -> "kill"
"load_extras" -> "strchr"
"load_extras" -> "load_extras_file"
"load_extras" -> "DMS"
"load_extras" -> "DFL_ck_realloc_block"
"load_extras" -> "snprintf"
"load_extras" -> "lstat"
"load_extras" -> "__errno_location"
"load_extras" -> "strerror"
"load_extras" -> "readdir"
"load_extras" -> "access"
"load_extras" -> "closedir"
"load_extras" -> "opendir"
"load_extras" -> "atoi"
"load_extras" -> "exit"
"load_extras" -> "printf"
"load_extras" -> "close"
"load_extras" -> "DFL_ck_free"
"load_extras" -> "fflush"
"load_extras" -> "open"
"load_extras" -> "DFL_ck_alloc"
"DFL_ck_strdup" -> "malloc"
"DFL_ck_strdup" -> "abort"
"DFL_ck_strdup" -> "strlen"
"DFL_ck_strdup" -> "memcpy"
"DFL_ck_strdup" -> "printf"
"DFL_ck_memdup" -> "malloc"
"DFL_ck_memdup" -> "abort"
"DFL_ck_memdup" -> "memcpy"
"DFL_ck_memdup" -> "printf"
"check_asan_opts" -> "exit"
"check_asan_opts" -> "printf"
"check_asan_opts" -> "strstr"
"check_asan_opts" -> "getenv"
"maybe_delete_out_dir" -> "rename"
"maybe_delete_out_dir" -> "unlink"
"maybe_delete_out_dir" -> "time"
"maybe_delete_out_dir" -> "snprintf"
"maybe_delete_out_dir" -> "flock"
"maybe_delete_out_dir" -> "fclose"
"maybe_delete_out_dir" -> "fscanf"
"maybe_delete_out_dir" -> "__errno_location"
"maybe_delete_out_dir" -> "strerror"
"maybe_delete_out_dir" -> "localtime"
"maybe_delete_out_dir" -> "DFL_ck_free"
"maybe_delete_out_dir" -> "exit"
"maybe_delete_out_dir" -> "delete_files"
"maybe_delete_out_dir" -> "printf"
"maybe_delete_out_dir" -> "fflush"
"maybe_delete_out_dir" -> "fopen"
"maybe_delete_out_dir" -> "open"
"maybe_delete_out_dir" -> "DFL_ck_alloc"
"maybe_delete_out_dir" -> "rmdir"
"handle_stop_sig" -> "kill"
"mark_as_variable" -> "snprintf"
"mark_as_variable" -> "__errno_location"
"mark_as_variable" -> "strerror"
"mark_as_variable" -> "symlink"
"mark_as_variable" -> "DFL_ck_free"
"mark_as_variable" -> "exit"
"mark_as_variable" -> "printf"
"mark_as_variable" -> "close"
"mark_as_variable" -> "strrchr"
"mark_as_variable" -> "fflush"
"mark_as_variable" -> "open"
"mark_as_variable" -> "DFL_ck_alloc"
"delete_files" -> "strncmp"
"delete_files" -> "snprintf"
"delete_files" -> "__errno_location"
"delete_files" -> "strerror"
"delete_files" -> "readdir"
"delete_files" -> "closedir"
"delete_files" -> "opendir"
"delete_files" -> "DFL_ck_free"
"delete_files" -> "exit"
"delete_files" -> "rmdir"
"delete_files" -> "printf"
"delete_files" -> "fflush"
"delete_files" -> "unlink"
"delete_files" -> "strlen"
"delete_files" -> "DFL_ck_alloc"
}
I wouldn't mind spending a lot of RAM / time calculating this result, I'd just like it to look nice.
Without knowing anything about the desired structure or layout of this graph, it's difficult to know what you would consider to be nice output. But with large graph with few ranks like this one, using the graph attribute rankdir=LR can improve the output significantly. You could also try experimenting with (cluster) subgraphs and the splines attribute.
In the graph below the two subgraphs are not visible, but instead all nodes seem to be placed randomly. How can I create the visible subgraphs, like one box with my PlayerChars inside, and the other with the NonPlayerChars inside?
digraph "All Characters" {
subgraph PlayerChars {
label = "Player Characters";
node [style=filled,color=yellow];
Char1 -> Char2 [ label = "is sister of" ];
Char1 -> Char2 [ label = "is brother of" ];
label = "PCs";
}
subgraph NonPlayerChars {
label = "Non-Player Characters";
Person1 -> Char2 [label="hates"];
Char2 -> Person1 [label="is indifferent"];
Person2 -> Char2 [label="stole from"];
Person1 -> Person2 [label="is father of"];
Person2 -> Person1 [label="is daughter of"];
Char1 -> Person2 [label="is in love with"];
Person2 -> Char1 [label="is annoyed by"];
}
}
What you are looking for is called a "cluster" in Graphviz. Use the special subgraph names cluster_ to draw the subgraphs in rectangular regions. E.g. from http://www.graphviz.org/Gallery/directed/cluster.html
digraph G {
subgraph cluster_0 {
style=filled;
color=lightgrey;
node [style=filled,color=white];
a0 -> a1 -> a2 -> a3;
label = "process #1";
}
subgraph cluster_1 {
node [style=filled];
b0 -> b1 -> b2 -> b3;
label = "process #2";
color=blue
}
start -> a0;
start -> b0;
a1 -> b3;
b2 -> a3;
a3 -> a0;
a3 -> end;
b3 -> end;
start [shape=Mdiamond];
end [shape=Msquare];
}
I'm trying to achieve a visualization of a specific graph (a Cayley graph of a symmetric permutation group) as the one done here but using Graphviz 2.28 with Dot.
(source: euclideanspace.com)
digraph cayley {
i -> x [color=red];
i -> y [color=blue];
x -> xx [color=red];
x -> xy [color=blue];
y -> yx [color=red];
y -> yy [color=blue];
xx -> xxx [color=red];
xx -> xxy [color=blue];
xy -> xyx [color=red];
xy -> xyy [color=blue];
yx -> yxx [color=red];
yx -> xyx [color=blue];
yy -> yyx [color=red];
yy -> yyy [color=blue];
xxx -> i [color=red];
xxx -> xxxy [color=blue];
xxy -> xxyx [color=red];
xxy -> xxyy [color=blue];
xyx -> xyxx [color=red];
xyx -> xxyx [color=blue];
xyy -> yy [color=red];
xyy -> xyyy [color=blue];
yxx -> yxxx [color=red];
yxx -> xx [color=blue];
yyx -> xxyy [color=red];
yyx -> xyxx [color=blue];
yyy -> yyyx [color=red];
yyy -> i [color=blue];
xxxy -> xxxyx [color=red];
xxxy -> yyx [color=blue];
xxyx -> yyy [color=red];
xxyx -> xxxyx [color=blue];
xxyy -> xyy [color=red];
xxyy -> yxx [color=blue];
xyxx -> xyxxx [color=red];
xyxx -> xxx [color=blue];
xyyy -> xyyyx [color=red];
xyyy -> x [color=blue];
yxxx -> y [color=red];
yxxx -> xyyyx [color=blue];
yyyx -> xxy [color=red];
yyyx -> xyxxx [color=blue];
xxxyx -> xyyy [color=red];
xxxyx -> yx [color=blue];
xyxxx -> xy [color=red];
xyxxx -> yxxx [color=blue];
xyyyx -> xxxy [color=red];
xyyyx -> yyyx [color=blue];
}
My Dot generates the following layout: which is a pretty huge graph compared with the previous one. Is there any attribute that can compact the graph as close as possible to the first one ?
I modified the codes such as graph, node and edge default attributes to make the layout as compacted as possible. Maybe there is a more perfect approach. By the way, the node i is located at the left but not right.
digraph cayley {
graph[rankdir=LR, center=true, margin=0.2, nodesep=0.1, ranksep=0.3]
node[shape=circle, fontname="Courier-Bold", fontsize=10, width=0.4, height=0.4, fixedsize=true]
edge[arrowsize=0.6, arrowhead=vee]
i -> x [color=red];
i -> y [color=blue];
x -> xx [color=red];
x -> xy [color=blue];
y -> yx [color=red];
y -> yy [color=blue];
xx -> xxx [color=red];
xx -> xxy [color=blue];
xy -> xyx [color=red];
xy -> xyy [color=blue];
yx -> yxx [color=red];
yx -> xyx [color=blue];
yy -> yyx [color=red];
yy -> yyy [color=blue];
xxx -> i [color=red];
xxx -> xxxy [color=blue];
xxy -> xxyx [color=red];
xxy -> xxyy [color=blue];
xyx -> xyxx [color=red];
xyx -> xxyx [color=blue];
xyy -> yy [color=red];
xyy -> xyyy [color=blue];
yxx -> yxxx [color=red];
yxx -> xx [color=blue];
yyx -> xxyy [color=red];
yyx -> xyxx [color=blue];
yyy -> yyyx [color=red];
yyy -> i [color=blue];
xxxy -> xxxyx [color=red];
xxxy -> yyx [color=blue];
xxyx -> yyy [color=red];
xxyx -> xxxyx [color=blue];
xxyy -> xyy [color=red];
xxyy -> yxx [color=blue];
xyxx -> xyxxx [color=red];
xyxx -> xxx [color=blue];
xyyy -> xyyyx [color=red];
xyyy -> x [color=blue];
yxxx -> y [color=red];
yxxx -> xyyyx [color=blue];
yyyx -> xxy [color=red];
yyyx -> xyxxx [color=blue];
xxxyx -> xyyy [color=red];
xxxyx -> yx [color=blue];
xyxxx -> xy [color=red];
xyxxx -> yxxx [color=blue];
xyyyx -> xxxy [color=red];
xyyyx -> yyyx [color=blue];
{ rank=same; x; y }
{ rank=same; xx; xy; yx; yy }
{ rank=same; xxx; xxy; xyx; xyy; yxx; yyx; yyy }
{ rank=same; xxxy; xxyx; xxyy; xyxx; xyyy; yxxx; yyyx }
{ rank=same; xxxyx; xyxxx; xyyyx }
}
The image is shown as following.