Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 36 additions & 13 deletions gap/gv.gi
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,18 @@ function(graph)
return graph;
end);

BindGlobal("GV_Indent", lvl -> ListWithIdenticalEntries(2 * lvl, ' '));

BindGlobal("GV_Depth", function(gv)
local depth;
depth := 0;
while GV_GetParent(gv) <> fail do
gv := GV_GetParent(gv);
depth := depth + 1;
od;
return depth;
end);

InstallMethod(GV_AddNode,
"for a graphviz graph and node",
[IsGraphvizGraphDigraphOrContext, IsGraphvizNode],
Expand Down Expand Up @@ -272,11 +284,17 @@ graph -> StringFormatted("digraph {} {{\n", GraphvizName(graph)));

# @ Return DOT subgraph head line.
BindGlobal("GV_StringifySubgraphHead",
graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph)));
gv -> StringFormatted("{}subgraph {} {{\n", GV_Indent(GV_Depth(gv)), GraphvizName(gv)));

# @ Return DOT subgraph head line.
BindGlobal("GV_StringifyContextHead",
graph -> StringFormatted("// {} context \n{{\n", GraphvizName(graph)));
function(gv)
local indent;
indent := GV_Indent(GV_Depth(gv));
return StringFormatted("{1}{{\n{1} // context \"{2}\" \n",
indent,
GraphvizName(gv));
end);

BindGlobal("GV_StringifyNodeName",
function(node)
Expand All @@ -289,13 +307,7 @@ function(node)
and not StartsWith(name, "\"") then
old := name;
name := StringFormatted("\"{}\"", name);
Info(InfoWarning,
1,
"invalid node name ",
old,
" using ",
name,
" instead");
Info(InfoWarning, 1, "invalid node name ", old, " using ", name, " instead");
fi;
return name;
end);
Expand Down Expand Up @@ -339,7 +351,10 @@ function(node)
local name, attrs;
name := GV_StringifyNodeName(node);
attrs := GraphvizAttrs(node);
return StringFormatted("\t{}{}\n", name, GV_StringifyAttrList(attrs));
return StringFormatted("{}{}{}\n",
GV_Indent(GV_Depth(node)),
name,
GV_StringifyAttrList(attrs));
end);

# @ Return DOT graph edge statement line.
Expand All @@ -353,7 +368,8 @@ function(edge, edge_str)
attrs := GraphvizAttrs(edge);

# handle : syntax
return StringFormatted("\t{} {} {}{}\n",
return StringFormatted("{}{} {} {}{}\n",
GV_Indent(GV_Depth(edge)),
head,
edge_str,
tail,
Expand Down Expand Up @@ -413,7 +429,11 @@ function(graph, is_subgraph)
for type in ["graph", "node", "edge"] do
record := GraphvizAttrs(graph).(type);
if Length(RecNames(record)) > 0 then
Append(result, StringFormatted("{} {}\n", type, GV_StringifyAttrList(record)));
Append(result,
StringFormatted("{}{}{}\n",
GV_Indent(GV_Depth(graph) + 1),
type,
GV_StringifyAttrList(record)));
fi;
od;

Expand All @@ -432,7 +452,10 @@ function(graph, is_subgraph)
fi;
od;

Append(result, "}\n");
Append(result, StringFormatted("{}}}", GV_Indent(GV_Depth(graph))));
if GV_Depth(graph) > 0 then
Append(result, "\n");
fi;
return result;
end);

Expand Down
128 changes: 84 additions & 44 deletions tst/dot.tst
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ rec( edge := rec( ),
gap> g := GraphvizGraph();;
gap> n := GraphvizAddNode(g, "test");;
gap> GraphvizSetAttrs(n, rec(color := "red", label := "lab"));;
gap> AsString(g);
"//dot\ngraph {\n\ttest [color=\"red\", label=\"lab\"]\n}\n"
gap> Print(AsString(g), "\n");
//dot
graph {
test [color="red", label="lab"]
}
gap> GraphvizRemoveNode(g, "banana");
Error, the 2nd argument (node name string) "banana" is not a node of the 1st a\
rgument (a graphviz (di)graph/context)
Expand All @@ -52,9 +55,13 @@ gap> GraphvizSetAttrs(a, rec(color := "blue"));;
gap> GraphvizSetAttrs(b, rec(color := "red"));;
gap> e := GraphvizAddEdge(g, a, b);;
gap> GraphvizSetAttrs(e, rec(color := "green"));;
gap> AsString(g);
"//dot\ndigraph {\n\ta [color=\"blue\"]\n\tb [color=\"red\"]\n\ta -> b [color\
=\"green\"]\n}\n"
gap> Print(AsString(g), "\n");
//dot
digraph {
a [color="blue"]
b [color="red"]
a -> b [color="green"]
}

# Test stringify with edge (graph)
gap> g := GraphvizGraph();;
Expand All @@ -64,14 +71,20 @@ gap> GraphvizSetAttrs(a, rec(color := "blue"));;
gap> GraphvizSetAttrs(b, rec(color := "red"));;
gap> e := GraphvizAddEdge(g, a, b);;
gap> GraphvizSetAttrs(e, rec(color := "green"));;
gap> AsString(g);
"//dot\ngraph {\n\ta [color=\"blue\"]\n\tb [color=\"red\"]\n\ta -- b [color=\
\"green\"]\n}\n"
gap> Print(AsString(g), "\n");
//dot
graph {
a [color="blue"]
b [color="red"]
a -- b [color="green"]
}

# Test stringify empty
gap> g := GraphvizGraph();;
gap> AsString(g);
"//dot\ngraph {\n}\n"
gap> Print(AsString(g), "\n");
//dot
graph {
}

# Test unknown attributes (node)
gap> g := GraphvizGraph();;
Expand All @@ -88,25 +101,41 @@ gap> GraphvizSetAttr(g, "test", "false");
gap> g := GraphvizGraph();;
gap> n := GraphvizAddNode(g, "node");;
gap> GraphvizSetAttr(n, "label", ">>hello");;
gap> AsString(g);
"//dot\ngraph {\n\tnode [label=\">>hello\"]\n}\n"
gap> Print(AsString(g), "\n");
//dot
graph {
node [label=">>hello"]
}
gap> g := GraphvizGraph();;
gap> n := GraphvizAddNode(g, "node");;
gap> GraphvizSetAttr(n, "label", "before>>hello");;
gap> AsString(g);
"//dot\ngraph {\n\tnode [label=\"before>>hello\"]\n}\n"
gap> Print(AsString(g), "\n");
//dot
graph {
node [label="before>>hello"]
}

# Test strngifying labels with ">>" inside (edge attrs)
gap> g := GraphvizGraph();;
gap> e := GraphvizAddEdge(g, "a", "b");;
gap> GraphvizSetAttr(e, "label", ">>hello");;
gap> AsString(g);
"//dot\ngraph {\n\ta\n\tb\n\ta -- b [label=\">>hello\"]\n}\n"
gap> Print(AsString(g), "\n");
//dot
graph {
a
b
a -- b [label=">>hello"]
}
gap> g := GraphvizGraph();;
gap> e := GraphvizAddEdge(g, "a", "b");;
gap> GraphvizSetAttr(e, "label", "before>>hello");;
gap> AsString(g);
"//dot\ngraph {\n\ta\n\tb\n\ta -- b [label=\"before>>hello\"]\n}\n"
gap> Print(AsString(g), "\n");
//dot
graph {
a
b
a -- b [label="before>>hello"]
}

# Test GraphvizSetNodeLabels
gap> gv := GraphvizGraph("xxx");
Expand All @@ -119,21 +148,21 @@ gap> GraphvizAddNode(gv, 3);
<graphviz node "3">
gap> GraphvizSetNodeLabels(gv, ["i", "ii", "iii"]);
<graphviz graph "xxx" with 3 nodes and 0 edges>
gap> Print(AsString(gv));
gap> Print(AsString(gv), "\n");
//dot
graph xxx {
1 [label="i"]
2 [label="ii"]
3 [label="iii"]
1 [label="i"]
2 [label="ii"]
3 [label="iii"]
}
gap> GraphvizSetNodeLabels(gv, ["a", "b", "c"]);
<graphviz graph "xxx" with 3 nodes and 0 edges>
gap> Print(AsString(gv));
gap> Print(AsString(gv), "\n");
//dot
graph xxx {
1 [label="a"]
2 [label="b"]
3 [label="c"]
1 [label="a"]
2 [label="b"]
3 [label="c"]
}
gap> GraphvizSetNodeLabels(gv, ["i", "ii"]);
Error, the 2nd argument (list of node labels) has incorrect length, expected 3\
Expand All @@ -157,30 +186,30 @@ Error, invalid color "i" (list (string)), valid colors are RGB values or names\
.html
gap> GraphvizSetNodeColors(gv, ["red", "green", "blue"]);
<graphviz graph "xxx" with 3 nodes and 0 edges>
gap> Print(AsString(gv));
gap> Print(AsString(gv), "\n");
//dot
graph xxx {
1 [color="red", style="filled"]
2 [color="green", style="filled"]
3 [color="blue", style="filled"]
1 [color="red", style="filled"]
2 [color="green", style="filled"]
3 [color="blue", style="filled"]
}
gap> GraphvizSetNodeColors(gv, ["red", "#00FF00", "blue"]);
<graphviz graph "xxx" with 3 nodes and 0 edges>
gap> Print(AsString(gv));
gap> Print(AsString(gv), "\n");
//dot
graph xxx {
1 [color="red", style="filled"]
2 [color="#00FF00", style="filled"]
3 [color="blue", style="filled"]
1 [color="red", style="filled"]
2 [color="#00FF00", style="filled"]
3 [color="blue", style="filled"]
}
gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00", "#0000FF"]);
<graphviz graph "xxx" with 3 nodes and 0 edges>
gap> Print(AsString(gv));
gap> Print(AsString(gv), "\n");
//dot
graph xxx {
1 [color="#FF0000", style="filled"]
2 [color="#00FF00", style="filled"]
3 [color="#0000FF", style="filled"]
1 [color="#FF0000", style="filled"]
2 [color="#00FF00", style="filled"]
3 [color="#0000FF", style="filled"]
}
gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00", "#0000FG"]);
Error, invalid color "#0000FG" (list (string)), valid colors are RGB values or\
Expand All @@ -206,14 +235,14 @@ gap> n := GraphvizSetAttr(n, "probably not ok", 1);
gap> Print(AsString(gv : invalidDOT := "unquoted attribute name with spaces"), "\n");
//dot
graph xxx {
1 [probably not ok="1"]
1 [probably not ok="1"]
}
gap> GraphvizSetAttr(n, "label", "<<>>");
<graphviz node "1">
gap> Print(AsString(gv : invalidDOT := "unquoted attribute name with spaces"), "\n");
//dot
graph xxx {
1 [label="<<>>", probably not ok="1"]
1 [label="<<>>", probably not ok="1"]
}

# Issue 68
Expand All @@ -223,14 +252,25 @@ gap> a := GraphvizAddNode(g, "a");
<graphviz node "a">
gap> e := GraphvizAddEdge(g, a, "b");
<graphviz edge (a, b)>
gap> GraphvizNodes(g); AsString(g);
gap> GraphvizNodes(g); Print(AsString(g), "\n");
rec( a := <graphviz node "a">, b := <graphviz node "b"> )
"//dot\ndigraph unexpected {\n\ta\n\tb\n\ta -> b\n}\n"
//dot
digraph unexpected {
a
b
a -> b
}
gap> e := GraphvizAddEdge(g, "b", a);
<graphviz edge (b, a)>
gap> GraphvizNodes(g); AsString(g);
gap> GraphvizNodes(g); Print(AsString(g), "\n");
rec( a := <graphviz node "a">, b := <graphviz node "b"> )
"//dot\ndigraph unexpected {\n\ta\n\tb\n\ta -> b\n\tb -> a\n}\n"
//dot
digraph unexpected {
a
b
a -> b
b -> a
}

#
gap> STOP_TEST("graphviz package: dot.tst", 0);
Loading
Loading