diff --git a/PackageInfo.g b/PackageInfo.g
index cfb5046..1e9d83f 100644
--- a/PackageInfo.g
+++ b/PackageInfo.g
@@ -31,6 +31,8 @@ Persons := [
rec(
FirstNames := "Matthew",
LastName := "Pancer",
+ WWWHome := "https://github.com/mpan322",
+ # TODO make personal website
Email := "mp322@st-andrews.ac.uk",
IsAuthor := true,
IsMaintainer := true,
@@ -55,8 +57,6 @@ ArchiveURL := Concatenation(~.PackageWWWHome,
~.Version),
ArchiveFormats := ".tar.gz",
-AbstractHTML := "TODO",
-
PackageDoc := rec(
BookName := "graphviz",
ArchiveURLSubset := ["doc"],
@@ -75,4 +75,30 @@ Dependencies := rec(
AvailabilityTest := ReturnTrue,
-TestFile := "tst/testall.g"));
+TestFile := "tst/testall.g",
+
+AutoDoc := rec(
+ TitlePage := rec(
+ Copyright := """©right; by J. D. Mitchell and M. Pancer.
+ &GAPGraphviz; is free software; you can redistribute it and/or modify
+ it, under the terms of the GNU General Public License, version 3 of
+ the License, or (at your option) any later, version.""",
+ Abstract := """
+ This package facilitates the creation and rendering of graph
+ descriptions in the ˙ language of the &Graphviz; graph drawing
+ software from ⪆.
+
+
+ Create a graphviz object, assemble the graph by adding nodes and edges,
+ and retrieve its ˙ source code string. Save the source code to a file
+ and render it with the &Graphviz; installation of your system.
+
+
+ Use the function to directly inspect the resulting
+ graph.
+
+
+ This package was inspired by the python package of the same name
+ &PyGraphviz;.""")),
+
+AbstractHTML := ~.AutoDoc.TitlePage.Abstract));
diff --git a/README.md b/README.md
index 7242a81..8b0cb2c 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,126 @@
-# The GAP package graphviz
+## README
-TODO: add a description of your package; perhaps also instructions how how to
-install and use it, resp. where to find out more
+### Graphviz package for GAP
-## Contact
+#### Copyright (C) 2024 by J. D. Mitchell and M. Pancer
-TODO: add info on how to contact you and/or how to report issues with your
-package
+## Graphviz for GAP
+
+This package facilitates the creation and rendering of graph
+descriptions in the [DOT][] language of the [Graphviz][] graph drawing
+software from [GAP][].
+
+You can create a graphviz object, assemble the graph by adding nodes and
+edges, attributes, labels, colours, subgraphs, and clusters, and
+retrieve its [DOT][] source code string. Save the source code to a file
+and render it with the [Graphviz] installation on your system.
+
+You can use the [Splash] function to directly inspect the resulting
+graph.
+
+This package was inspired by the python package of the same name
+[Python Graphviz][].
## License
-TODO: Provide information on the license of your package. A license is
-important as it determines who has a right to distribute your package. The
-"default" license to consider is GNU General Public License v2 or later, as
-that is the license of GAP itself.
+This package is distributed under the GNU General Public License v2 or later.
+See the `LICENSE` file for more details.
+
+## Links
+
+- GitHub: [https://github.com/digraphs/graphviz](https://github.com/digraphs/graphviz)
+- Documentation: TODO
+- Changelog: TODO
+- Issue Tracker: [https://github.com/digraphs/graphviz/issues](https://github.com/digraphs/graphviz/issues)
+- Download: TODO
+
+## Installation
+
+This package requires [GAP][] version 4.11.0 or higher. The most
+up-to-date version of GAP, and instructions on how to install it, can be
+obtained from the [main GAP webpage](https://www.gap-system.org). This
+package has no further dependencies!
+
+### From sources
+
+To get the latest version of the package, download the archive file
+`graphviz-x.x.x.tar.gz` from the [Graphviz package for GAP webpage][].
+Then, inside the `pkg` subdirectory of your GAP installation, unpack the
+archive `graphviz-x.x.x.tar.gz` in your `gap/pkg` directory, using
+
+ gunzip graphviz-x.x.x.tar.gz; tar xvf graphviz-x.x.x.tar
+
+for example. This will create a subdirectory `graphviz-x.x.x`.
+
+### Using the [PackageManager][]
+
+Start GAP in the usual way, then type:
+
+ LoadPackage("PackageManager");
+ InstallPackage("graphviz");
+
+## Quickstart
+
+Create a graph object:
+
+ gap> LoadPackage("graphviz");
+ ───────────────────────────────────────────────────────────────────────────────────
+ Loading graphviz 0.0.0 (TODO)
+ by James D. Mitchell (https://jdbm.me) and
+ Matthew Pancer (mp322@st-andrews.ac.uk).
+ Homepage: https://digraphs.github.io/graphviz
+ Report issues at https://github.com/digraphs/graphviz/issues
+ ───────────────────────────────────────────────────────────────────────────────────
+ true
+ gap> dot := GraphvizDigraph("The Round Table");
+
+
+Add nodes and edges:
+
+ gap> GraphvizSetAttr(GraphvizAddNode(dot, "A"), "label", "King Arthur");
+
+ gap> GraphvizSetAttr(GraphvizAddNode(dot, "B"), "label", "Sir Bedevere the Wise");
+
+ gap> GraphvizSetAttr(GraphvizAddNode(dot, "L"), "label", "Sir Lancelot the Brave");
+
+ gap> GraphvizAddEdge(dot, "A", "B");
+
+ gap> GraphvizAddEdge(dot, "A", "L");
+
+ gap> GraphvizSetAttr(GraphvizAddEdge(dot, "B", "L"), "constraint", false);
+
+Check the generated source code:
+
+ gap> Print(AsString(dot));
+ //dot
+ digraph {
+ A [label="King Arthur"]
+ B [label="Sir Bedevere the Wise"]
+ L [label="Sir Lancelot the Brave"]
+ A -> B
+ A -> L
+ B -> L [constraint=false]
+ }
+
+Save the source code:
+
+ gap> FileString("round-table.gv", AsString(dot));
+ 134
+
+Render and view the result:
+
+ gap> Splash(dot);
+
+
+
+## Issues
+
+For questions, remarks, suggestions, and issues please use the
+[issue tracker](https://github.com/digraphs/graphviz/issues).
+
+[DOT]: https://www.graphviz.org/doc/info/lang.html
+[GAP]: https://www.gap-system.org
+[Graphviz]: https://www.graphviz.org
+[Graphviz webpage]: https://digraphs.github.io/Digraphs
+[PackageManager]: https://gap-packages.github.io/PackageManager
+[Python Graphviz]: https://pypi.org/project/graphviz/
diff --git a/gap/dot.gd b/gap/dot.gd
index b91b7f8..1320241 100644
--- a/gap/dot.gd
+++ b/gap/dot.gd
@@ -9,85 +9,310 @@
##
#! @Chapter
-#! @ChapterTitle An introduction to the DOT language and Graphviz.
-#! This chapter explains what the DOT and graphviz are,
-#! key basic concepts relating to them, and how this package interacts with them.
-
-#! @Section A Brief Introduction
-#! DOT is a language for descrbing to a computer how to display a visualization
-#! for a graph or digraph. Graphviz is a graph visualization software which can
-#! consume DOT and produce visual outputs. This package is designed to allow
-#! users to programmatically construct objects in GAP which can then be
-#! converted into DOT. That DOT can then be inputted into the graphviz software
-#! to produce a visual output. As DOT is central to the design of this package
+#! @ChapterTitle Getting started
+#! This chapter very briefly explains what ˙ and &Graphviz; are, provides
+#! some key basic concepts relating to them, and how this package interacts
+#! with them.
+
+#! @Section A brief introduction
+#! ˙ is a language for descrbing to a computer how to display a visualization
+#! of a graph or digraph. &Graphviz; is a graph visualization software which can
+#! consume ˙ and produce visual outputs. This package is designed to allow
+#! users to programmatically construct objects in ⪆ which can then be
+#! converted into ˙. That ˙ can then be input to the &Graphviz; software
+#! to produce a visual output. As ˙ is central to the design of this package
#! it will likely be helpful to have a basic understanding of the language.
-#! For more information about DOT see
+#! For more information about ˙ see
#! https://graphviz.org/doc/info/lang.html.
-
-#! @Chapter
-#! @ChapterTitle The Graphviz Package
+#!
+#!
+#! The &GAPGraphviz; package for ⪆ is intended to facilitate the creation
+#! and rendering of graph descriptions in the ˙ language of the &Graphviz;
+#! graph drawing software.
+#!
+#!
+#! You can create a &GAPGraphviz; object, assemble the graph by adding nodes
+#! and edges, setting attributes, labels and so on, and retrieve its ˙
+#! source code string. You can save the source code
+#! to a file (using ) and render it
+#! with the &Graphviz; installation of your system; or you can
+#! use the function to directly inspect the resulting
+#! graph (depending on your system and the software installed).
+
+#! @Section What this package is not
+#!
+#! This package does not implement a parser of the ˙ language and does only
+#! minimal checks when assembling a graph. In particular, if you set attributes
+#! which don't exist in ˙, then the resulting string might not be valid,
+#! and might not render correctly using &Graphviz;.
+
+#! @Section A first example
+#! Here's an example of how to use the &GAPGraphviz; package, to construct a
+#! ˙ representation of a finite state automata. This example is taken from
+#! https://graphviz.readthedocs.io/en/stable/examples.html or
+#! https://graphviz.org/Gallery/directed/fsm.html.
+#!
+#! @BeginLogSession
+#! gap> LoadPackage("graphviz");;
+#! gap> f := GraphvizDigraph("finite_state_machine");
+#!
+#! gap> GraphvizSetAttr(f, "rankdir=LR");
+#!
+#! gap> GraphvizSetAttr(f, "size=\"8,5\"");
+#!
+#! gap> terminals := GraphvizAddContext(f, "terminals");
+#!
+#! gap> GraphvizSetAttr(terminals, "node [shape=doublecircle]");
+#!
+#! gap> GraphvizAddNode(terminals, "LR_0");
+#!
+#! gap> GraphvizAddNode(terminals, "LR_3");
+#!
+#! gap> GraphvizAddNode(terminals, "LR_4");
+#!
+#! gap> GraphvizAddNode(terminals, "LR_8");
+#!
+#! gap> nodes := GraphvizAddContext(f, "nodes");
+#!
+#! gap> GraphvizSetAttr(nodes, "node [shape=circle]");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_0", "LR_2"),
+#! > "label", "\"SS(B)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_0", "LR_1"),
+#! > "label", "\"SS(S)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_1", "LR_3"),
+#! > "label", "\"S($end)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_2", "LR_6"),
+#! > "label", "\"SS(b)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_2", "LR_5"),
+#! > "label", "\"SS(a)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_2", "LR_4"),
+#! > "label", "\"S(A)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_5", "LR_7"),
+#! > "label", "\"S(b)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_5", "LR_5"),
+#! > "label", "\"S(a)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_6", "LR_6"),
+#! > "label", "\"S(b)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_6", "LR_5"),
+#! > "label", "\"S(a)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_7", "LR_8"),
+#! > "label", "\"S(b)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_7", "LR_5"),
+#! > "label", "\"S(a)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_8", "LR_6"),
+#! > "label", "\"S(b)\"");
+#!
+#! gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_8", "LR_5"),
+#! > "label", "\"S(a)\"");
+#!
+#! gap> Print(AsString(f), "\n");
+#! //dot
+#! digraph finite_state_machine {
+#! rankdir=LR size="8,5"
+#! // terminals context
+#! node [shape=doublecircle]
+#! LR_0
+#! LR_3
+#! LR_4
+#! LR_8
+#! rankdir=LR size="8,5"
+#!
+#! // nodes context
+#! node [shape=circle]
+#! LR_2
+#! LR_0 -> LR_2 [label="SS(B)"]
+#! LR_1
+#! LR_0 -> LR_1 [label="SS(S)"]
+#! LR_1 -> LR_3 [label="S($end)"]
+#! LR_6
+#! LR_2 -> LR_6 [label="SS(b)"]
+#! LR_5
+#! LR_2 -> LR_5 [label="SS(a)"]
+#! LR_2 -> LR_4 [label="S(A)"]
+#! LR_7
+#! LR_5 -> LR_7 [label="S(b)"]
+#! LR_5 -> LR_5 [label="S(a)"]
+#! LR_6 -> LR_6 [label="S(b)"]
+#! LR_6 -> LR_5 [label="S(a)"]
+#! LR_7 -> LR_8 [label="S(b)"]
+#! LR_7 -> LR_5 [label="S(a)"]
+#! LR_8 -> LR_6 [label="S(b)"]
+#! LR_8 -> LR_5 [label="S(a)"]
+#! rankdir=LR size="8,5"
+#!
+#! }
+#! gap> Splash(f);
+#! @EndLogSession
+#!
+#! Provided that you have &Graphviz; installed on your computer, the last line
+#! of the example Splash(f) would produce the following picture:
+#!
+#!
+#!
+#!
+#!
+#! ]]>
+#!
+#!
+#! There are lots more examples in the examples directory within the
+#! &Graphviz; package for ⪆ directory.
+
+#! @Chapter Full Reference
+#! This chapter contains all of the gory details about the functionality of the
+#! &GAPGraphviz; package for ⪆.
#! @Section Graphviz Categories
-
-#! @BeginGroup Filters
-#! @Description Every object in graphviz belongs to the IsGraphvizObject
+#! @BeginGroup
+#! Every object in graphviz belongs to the IsGraphvizObject
#! category. The categories following it are for further specificity on the
-#! type of objects. These are graphs, digraphs, nodes and edges respectively.
-#! All are direct subcategories of IsGraphvizObject excluding IsGraphvizDigraph
-#! which is a subcategory of is IsGraphvizGraph.
-
+#! type of objects. These are graphs, digraphs, contexts, nodes, and
+#! edges, and combinations of these that have some common features.
DeclareCategory("IsGraphvizObject", IsObject);
-
DeclareCategory("IsGraphvizGraphDigraphOrContext", IsGraphvizObject);
DeclareCategory("IsGraphvizGraph", IsGraphvizGraphDigraphOrContext);
DeclareCategory("IsGraphvizDigraph", IsGraphvizGraphDigraphOrContext);
DeclareCategory("IsGraphvizContext", IsGraphvizGraphDigraphOrContext);
-
DeclareCategory("IsGraphvizNodeOrEdge", IsGraphvizObject);
DeclareCategory("IsGraphvizNode", IsGraphvizNodeOrEdge);
DeclareCategory("IsGraphvizEdge", IsGraphvizNodeOrEdge);
+#! The names of these categories are fairly descriptive, where a graph
+#! has undirected edges, a digraph has directed edges, and a context is
+#! a part of a &Graphviz; file/string consisting of objects (nodes,
+#! edges, further contexts, subgraphs etc) that share some common
+#! attributes.
#! @EndGroup
#! @Section Constructors
#! @BeginGroup
-#! @GroupTitle Constructors for Graphs
+#! @GroupTitle Creating a new &GAPGraphviz; graphs
#! @Arguments name
-#! @Returns a new graphviz graph
-#! @Description Creates a new graphviz graph optionally with the provided name.
+#! @Returns A new &GAPGraphviz; graph.
+#! @Description These operations create a new &GAPGraphviz; graph objects.
+#!
+#! In the first form, the created &GAPGraphviz; graph object has name
+#! name. In the second form, the constructed &GAPGraphviz; graph
+#! object has an empty string as a name.
+#!
+#! The argument name can be any ⪆ object for which there is a
+#! method, and the name of the
+#! created object will be equal to String(name).
+#!
+#! A "graph" in &Graphviz; has undirected edges that are represented
+#! using the string "--" in the ˙ language.
+#!
+#! See also:
+#! *
+#! *
+#! *
+#!
+#! @BeginExampleSession
+#! gap> gv := GraphvizGraph("GraphyMcGraphFace");
+#!
+#! gap> GraphvizName(gv);
+#! "GraphyMcGraphFace"
+#! gap> GraphvizGraph(666);
+#!
+#! gap> gv := GraphvizGraph();
+#!
+#! gap> GraphvizName(gv);
+#! ""
+#! @EndExampleSession
DeclareOperation("GraphvizGraph", [IsObject]);
DeclareOperation("GraphvizGraph", []);
#! @EndGroup
#! @BeginGroup
-#! @GroupTitle Constructors for Digraphs
+#! @GroupTitle Creating a new &GAPGraphviz; digraphs
#! @Arguments name
-#! @Returns a new graphviz digraph
-#! @Description Creates a new graphviz digraph optionally with the provided name.
+#! @Returns A new &GAPGraphviz; digraph.
+#! @Description These operations create a new &GAPGraphviz; digraph objects.
+#!
+#! In the first form, the created &GAPGraphviz; digraph object has name
+#! name. In the second form, the constructed &GAPGraphviz; digraph
+#! object has an empty string as a name.
+#!
+#! The argument name can be any ⪆ object for which there is a
+#! method, and the name of the
+#! created object will be equal to String(name).
+#!
+#! A "digraph" in &Graphviz; has directed edges that are represented
+#! using the string "->" in the ˙ language.
+#!
+#! See also:
+#! *
+#! *
+#! *
+#!
+#! @BeginExampleSession
+#! gap> gv := GraphvizDigraph("GraphyMcGraphFace");
+#!
+#! gap> GraphvizName(gv);
+#! "GraphyMcGraphFace"
+#! gap> GraphvizDigraph(666);
+#!
+#! gap> gv := GraphvizDigraph();
+#!
+#! gap> GraphvizName(gv);
+#! ""
+#! @EndExampleSession
DeclareOperation("GraphvizDigraph", [IsObject]);
DeclareOperation("GraphvizDigraph", []);
#! @EndGroup
-#! @Section Get Operations
-#! This section covers the operations for getting information about graphviz
-#! objects.
-
-#! @Subsection For all graphviz objects.
+#! @Section Getters for any object
+#! This section covers the operations for getting information about
+#! &GAPGraphviz; any object.
#! @Arguments obj
-#! @Returns the name of the provided graphviz object
-#! @Description Gets the name of the provided graphviz object.
+#! @Returns A string.
+#! @Description If the argument obj is a &GAPGraphviz; object
+#! (), then this
+#! function returns the name of the &Graphviz; object obj.
+#!
+#! @BeginExampleSession
+#! gap> dot := GraphvizDigraph("The Round Table");;
+#! gap> GraphvizName(dot);
+#! "The Round Table"
+#! gap> n := GraphvizSetAttr(GraphvizAddNode(dot, "A"), "label", "King Arthur");
+#! gap> GraphvizName(n);
+#! "A"
+#! gap> e := GraphvizAddEdge(dot, "A", "B");;
+#! gap> GraphvizName(e);
+#! "(A, B)"
+#! @EndExampleSession
DeclareOperation("GraphvizName", [IsGraphvizObject]);
#! @Arguments obj
#! @Returns the attributes of the provided graphviz object
#! @Description Gets the attributes of the provided graphviz object.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
+# HERE
DeclareOperation("GraphvizAttrs", [IsGraphvizObject]);
-#! @Subsection For only graphs and digraphs.
+#! @Section Getters for graphs and digraphs
#! @Arguments graph
-#! @Returns the nodes of the provided graphviz graph.
+#! @Returns the nodes of the provided graphviz graph
+#! as a mapping from node ids to names.
#! @Description Gets the nodes of the provided graphviz graph.
# From https://graphviz.org/doc/info/lang.html
# An ID is one of the following:
@@ -97,17 +322,26 @@ DeclareOperation("GraphvizAttrs", [IsGraphvizObject]);
# any double-quoted string ("...") possibly containing escaped quotes (\")¹;
# an HTML string (<...>).
# TODO specify
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizNodes", [IsGraphvizGraphDigraphOrContext]);
#! @Arguments graph
#! @Returns the subgraphs of the provided graphviz graph.
#! @Description gets the subgraphs of a provided graphviz graph.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraphDigraphOrContext]);
#! @Arguments graph
#! @Returns the contexts of the provided graphviz graph, digraph or context.
#! @Description gets the contexts of a provided graphviz graph, digraph
#! or context.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizContexts", [IsGraphvizGraphDigraphOrContext]);
#! @Arguments graph, name
@@ -116,43 +350,69 @@ DeclareOperation("GraphvizContexts", [IsGraphvizGraphDigraphOrContext]);
#! Searches through the tree of subgraphs connected to this subgraph for a graph
#! with the provided name.
#! It returns the graph if it exists.
-#! If no such graph exists then it will return fail.
+#! If no such graph exists then it will return fail.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizFindSubgraphRecursive",
[IsGraphvizGraphDigraphOrContext, IsObject]);
+#! @BeginGroup
+#! @GroupTitle Getting Graphviz Edges
#! @Arguments graph
#! @Returns the edges of the provided graphviz graph.
#! @Description Gets the edges of the provided graphviz graph.
+#! If a head and tail are provided will only return edges
+#! between those two nodes.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizEdges", [IsGraphvizGraphDigraphOrContext]);
+#! @Arguments graph, head, tail
DeclareOperation("GraphvizEdges",
[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]);
+#! @EndGroup
#! @Subsection For only edges.
+#! This section contains getters only applicable to graphviz edges.
#! @Arguments edge
#! @Returns the head of the provided graphviz edge.
#! @Description Gets the head of the provided graphviz graph.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizHead", [IsGraphvizEdge]);
#! @Arguments edge
#! @Returns the head of the provided graphviz tail.
#! @Description Gets the tail of the provided graphviz graph.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizTail", [IsGraphvizEdge]);
#! @Section Set Operations
#! This section covers operations for modifying graphviz objects.
#! @Subsection For modifying graphs.
+#! Operations below only pertain to graphs, digraphs and contexts.
#! @Arguments graph, name
#! @Returns the modified graph.
#! @Description Sets the name of a graphviz graph or digraph.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizSetName", [IsGraphvizGraphDigraphOrContext, IsObject]);
#! @Arguments graph, node
#! @Returns the modified graph.
#! @Description Adds a node to the graph.
#! If a node with the same name is already present the operation fails.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizAddNode", [IsGraphvizGraphDigraphOrContext, IsObject]);
#! @Arguments graph, edge
@@ -163,44 +423,93 @@ DeclareOperation("GraphvizAddNode", [IsGraphvizGraphDigraphOrContext, IsObject])
#! then the operation fails.
#! TODO I dont believe this is accurate - think it will connect existing ones
#! underlying private function would fail though - TODO double check.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizAddEdge",
[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]);
-#! @Arguments graph, filter, name
+#! @BeginGroup
+#! @GroupTitle Adding Subgraphs
+#! @Arguments graph, name
#! @Returns the new subgraph.
#! @Description Adds a subgraph to a graph.
+#! The type of structure (graph or digraph) will be the same as the parent graph.
+#! At the moment it is not possible to add an existing graph as a
+#! subgraph of another graph.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizAddSubgraph",
[IsGraphvizGraphDigraphOrContext, IsObject]);
+#! @Arguments graph
DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraphDigraphOrContext]);
+#! @EndGroup
-#! @Arguments graph, filter, name
+#! @BeginGroup
+#! @GroupTitle Adding Contexts
+#! @Arguments graph, name
#! @Returns the new context.
#! @Description Adds a context to a graph.
+#! A context can be thought as being similar to a subgraph
+#! when manipulating it in this package.
+#! However, when rendered contexts do not
+#! create a subgraph in outputted DOT code.
+#! Instead their nodes are rendered inline within the parent graph.
+#! This allows for scoping node and edge attributes
+#! without modifying the rendering behaviour.
+#! The type of graph edge (directed or undirected)
+#! will be the same as the parent graph.
+#! At the moment it is not possible to add an existing context to
+#! a new graph.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizAddContext",
[IsGraphvizGraphDigraphOrContext, IsObject]);
+#! @Arguments graph
DeclareOperation("GraphvizAddContext", [IsGraphvizGraphDigraphOrContext]);
+#! @EndGroup
#! @Arguments graph, node
#! @Returns the modified graph.
#! @Description Removes the node from the graph.
+#! The node attribute may be an object, string or graphviz node.
+#! Objects will be converted to strings.
+#! Strings are then interpreted as the id of the node to remove.
+#! All edges containing the node are also removed.
+#! If no such node exists the operation fails.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizRemoveNode",
[IsGraphvizGraphDigraphOrContext, IsObject]);
#! @Arguments graph, predicate
#! @Returns the modified graph.
#! @Description Filters the graph's edges using the provided predicate.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizFilterEdges",
[IsGraphvizGraphDigraphOrContext, IsFunction]);
-#! @Arguments graph, head_name, tail_name
+#! @Arguments graph, head_id, tail_id
#! @Returns the modified graph.
#! @Description Filters the graph's edges, removing edges between nodes with
#! the specified names.
+#! If no edges exist between the two nodes, the operation fails.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizRemoveEdges",
[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]);
-#! @Subsection For modifying object attributes.
+#! @Subsection Modifying object attributes
+#! Operations for modifying attributes.
+#! @BeginGroup
+#! @GroupTitle Setting Attributes
#! @Arguments obj, attrs
#! @Returns the modified object.
#! @Description
@@ -208,18 +517,34 @@ DeclareOperation("GraphvizRemoveEdges",
#! All current attributes remain.
#! If an attribute already exists and a new value is provided, the old value
#! will be overwritten.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizSetAttrs", [IsGraphvizObject, IsRecord]);
+#! @Arguments obj, name, value
DeclareOperation("GraphvizSetAttr", [IsGraphvizObject, IsObject, IsObject]);
+#! @Arguments obj, name
DeclareOperation("GraphvizSetAttr", [IsGraphvizObject, IsObject]);
+#! @EndGroup
#! @Arguments obj, attr
#! @Returns the modified object.
#! @Description Removes an attribute from the object provided.
+#! If no attributes are removed then the operation fails.
+#! Attributes may be removed by key or by
+#! key-value pair eg. "label" or "label=\"test\"".
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizRemoveAttr", [IsGraphvizObject, IsObject]);
#! @Section Outputting
#! @Arguments graph
#! @Returns the dot representation of the graphviz object.
+#! @Description TODO
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("AsString", [IsGraphvizGraphDigraphOrContext]);
#! @Arguments obj
@@ -227,24 +552,81 @@ DeclareOperation("AsString", [IsGraphvizGraphDigraphOrContext]);
#! @Description
#! Unimplemented operation which depending packages can implement.
#! Should output the graphviz package representation of the object.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("Graphviz", [IsObject]);
+#! @Section Shortcuts
+#! @Arguments graph, colours
+#! @Returns the modified object
+#! @Description
+#! Sets the colors of the nodes in the (di)graph.
+#! If there are a different number of colours than nodes the operation fails.
+#! Also sets the node style to filled.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizSetNodeColors",
[IsGraphvizGraphDigraphOrContext, IsList]);
+
+#! @Arguments graph, labels
+#! @Returns the modified object
+#! @Description
+#! Sets the labels of the nodes in the (di)graph.
+#! If there are fewer labels than nodes the operation fails.
+#! If there is an invalid label the operation halts there and fails.
+#! What constitutes a valid label can be found here,
+#! "https://graphviz.org/doc/info/lang.html".
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("GraphvizSetNodeLabels",
[IsGraphvizGraphDigraphOrContext, IsList]);
+#! @Arguments color
+#! @Returns true or false
+#! @Description
+#! Determines if the color provided is a valid graphviz color.
+#! Valid graphviz colors are described here,
+#! "http://graphviz.org/doc/info/colors.html".
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareGlobalFunction("ErrorIfNotValidColor");
-# TODO doc
+#! @BeginGroup
+#! @GroupTitle Getting attributes
+#! @Arguments edge, attr
+#! @Returns the value associated with the provided attribute.
+#! @Description
+#! Gets the value associated with the attribute attr.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
+DeclareOperation("\[\]", [IsGraphvizEdge, IsObject]);
+#! @Arguments node, attr
DeclareOperation("\[\]", [IsGraphvizNode, IsObject]);
-# TODO doc
-DeclareOperation("\[\]\:\=", [IsGraphvizNode, IsObject, IsObject]);
+#! @EndGroup
-# TODO doc
-DeclareOperation("\[\]", [IsGraphvizEdge, IsObject]);
-# TODO doc
+#! @BeginGroup
+#! @GroupTitle Setting attributes
+#! @Arguments node, attr
+#! @Description
+#! Sets the value associated with the attribute attr.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
+DeclareOperation("\[\]\:\=", [IsGraphvizNode, IsObject, IsObject]);
+#! @Arguments edge, attr
DeclareOperation("\[\]\:\=", [IsGraphvizEdge, IsObject, IsObject]);
+#! @EndGroup
-# TODO doc
+#! @Arguments graph, node_name
+#! @Returns The associated node or fail if no such node exists.
+#! @Description
+#! Gets a node from a (di)graph by id.
+#! @BeginExampleSession
+#! gap>
+#! @EndExampleSession
DeclareOperation("\[\]", [IsGraphvizGraphDigraphOrContext, IsObject]);
diff --git a/gap/dot.gi b/gap/dot.gi
index f3be316..6766cae 100644
--- a/gap/dot.gi
+++ b/gap/dot.gi
@@ -27,6 +27,9 @@ function(name)
Counter := 1));
end);
+InstallMethod(GraphvizGraph, "for an object", [IsObject],
+obj -> GraphvizGraph(String(obj)));
+
InstallMethod(GraphvizGraph, "for no args", [], {} -> GraphvizGraph(""));
InstallMethod(GraphvizDigraph, "for a string", [IsString],
@@ -46,6 +49,9 @@ end);
InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph(""));
+InstallMethod(GraphvizDigraph, "for an object", [IsObject],
+obj -> GraphvizDigraph(String(obj)));
+
#############################################################################
# ViewString
#############################################################################
@@ -54,15 +60,7 @@ InstallMethod(PrintString, "for a graphviz node", [IsGraphvizNode],
n -> StringFormatted("", GraphvizName(n)));
InstallMethod(PrintString, "for a graphviz edge", [IsGraphvizEdge],
-function(e)
- local head, tail;
- head := GraphvizHead(e);
- tail := GraphvizTail(e);
-
- return StringFormatted("",
- GraphvizName(head),
- GraphvizName(tail));
-end);
+e -> StringFormatted("", GraphvizName(e)));
InstallMethod(PrintString, "for a graphviz (di)graph or context",
[IsGraphvizGraphDigraphOrContext],
diff --git a/gap/gv.gi b/gap/gv.gi
index 4d52941..7cba024 100644
--- a/gap/gv.gi
+++ b/gap/gv.gi
@@ -147,9 +147,12 @@ InstallMethod(GV_Edge, "for two graphviz nodes",
[IsGraphvizGraphDigraphOrContext, IsGraphvizNode, IsGraphvizNode],
function(graph, head, tail)
local out;
+
out := Objectify(GV_EdgeType,
rec(
- Name := "",
+ Name := StringFormatted("({}, {})",
+ GraphvizName(head),
+ GraphvizName(tail)),
Head := head,
Tail := tail,
Attrs := GV_Map(),
diff --git a/gap/splash.gd b/gap/splash.gd
index 919a68a..22e9857 100644
--- a/gap/splash.gd
+++ b/gap/splash.gd
@@ -12,4 +12,88 @@
# function was written by A. Egri-Nagy and Manuel Delgado, with some minor
# modifications by J. Mitchell.
+#! @ChapterInfo Full Reference, Outputting
+#! @Arguments x[, opts]
+#! @Returns Nothing.
+#! @Description
+#! This function attempts to convert the string str into a pdf
+#! document and open this document, i.e. to splash it all over your monitor.
+#!
+#! The argument x must be one of: TODO
+#!
+#! must correspond to a valid dot or
+#! LaTeX text file and you must have have GraphViz and
+#! pdflatex installed on your computer. For details about these file
+#! formats, see https://www.latex-project.org and
+#! https://www.graphviz.org.
+#!
+#! The optional second argument opts should be a record with
+#! components corresponding to various options, given below.
+#!
+#!
+#! path
+#! -
+#! this should be a string representing the path to the directory where
+#! you want Splash to do its work. The default value of this
+#! option is "~/".
+#!
+#!
+#! directory
+#! -
+#! this should be a string representing the name of the directory in
+#! path where you want Splash to do its work. This function
+#! will create this directory if does not already exist.
+#!
+#! The default value of this option is "tmp.viz" if the option
+#! path is present, and the result of
+#!
is used otherwise.
+#!
+#!
+#! filename
+#! -
+#! this should be a string representing the name of the file where
+#! str will be written. The default value of this option is
+#! "vizpicture".
+#!
+#!
+#! viewer
+#! -
+#! this should be a string representing the name of the program which
+#! should open the files produced by GraphViz or pdflatex.
+#!
+#!
+#! type
+#! -
+#! this option can be used to specify that the string str contains
+#! a &LaTeX; or dot document. You can specify this option in
+#! str directly by making the first line "%latex" or
+#! "//dot". There is no default value for this option, this
+#! option must be specified in str or in opt.type.
+#!
+#!
+#! engine
+#! -
+#! this option can be used to specify the GraphViz engine to use
+#! to render a dot document. The valid choices are "dot",
+#! "neato", "circo", "twopi", "fdp",
+#! "sfdp", and "patchwork". Please refer to the
+#! GraphViz documentation for details on these engines.
+#! The default value for this option is "dot", and it
+#! must be specified in opt.engine.
+#!
+#!
+#! filetype
+#! -
+#! this should be a string representing the type of file which
+#! Splash should produce. For &LaTeX; files, this option is
+#! ignored and the default value "pdf" is used.
+#!
+#!
+#!
+#! This function was originally written by Attila Egri-Nagy and Manuel Delgado,
+#! the present version incorporates some minor changes.
+#! @BeginLogSession
+#! gap> TODO
+#! gap> Splash();
+#! @EndLogSession
DeclareGlobalFunction("Splash");
diff --git a/gap/splash.gi b/gap/splash.gi
index 9d3c67e..41a3da2 100644
--- a/gap/splash.gi
+++ b/gap/splash.gi
@@ -32,7 +32,7 @@ function(arg...)
file[i] := '_';
fi;
od;
- arg[1] := String(arg[1]);
+ arg[1] := AsString(arg[1]);
else
file := "vizpicture";
fi;
@@ -42,7 +42,7 @@ function(arg...)
if IsBound(arg[2]) and IsRecord(arg[2]) then
opt := arg[2];
elif IsBound(arg[2]) then
- ErrorNoReturn("the 2nd argument must be a record,");
+ ErrorNoReturn("the 2nd argument must be a record");
fi;
path := UserHomeExpand("~/");
diff --git a/makedoc.g b/makedoc.g
index a04d383..b18c2fe 100644
--- a/makedoc.g
+++ b/makedoc.g
@@ -10,9 +10,39 @@
## This file is a script which compiles the package manual.
+UrlEntity := function(name, url)
+ return StringFormatted("""{2}
+ {1}""", name, url);
+end;
+
+PackageEntity := function(name)
+ if TestPackageAvailability(name) <> fail then
+ return UrlEntity(PackageInfo(name)[1].PackageName,
+ PackageInfo(name)[1].PackageWWWHome);
+ fi;
+ return StringFormatted("{1}", name);
+end;
+
if fail = LoadPackage("AutoDoc", "2022.10.20") then
Error("AutoDoc version 2022.10.20 or newer is required.");
fi;
-AutoDoc(rec(scaffold := true, autodoc := true));
+XMLEntities := rec();
+
+XMLEntities.GAPGraphviz := PackageEntity("Graphviz");
+XMLEntities.PyGraphviz := UrlEntity("graphviz",
+ "https://pypi.org/project/graphviz/");
+XMLEntities.DOT := UrlEntity("DOT",
+ "https://www.graphviz.org/doc/info/lang.html");
+XMLEntities.Graphviz := UrlEntity("Graphviz", "https://www.graphviz.org");
+
+AutoDoc("graphviz",
+rec(scaffold := rec(entities := XMLEntities),
+ autodoc := true,
+ extract_examples := true,
+));
+
+Unbind(PackageEntity);
+Unbind(UrlEntity);
+Unbind(XMLEntities);
QUIT;
diff --git a/tst/graphviz01.tst b/tst/graphviz01.tst
new file mode 100644
index 0000000..8fa4ba4
--- /dev/null
+++ b/tst/graphviz01.tst
@@ -0,0 +1,49 @@
+# graphviz, chapter 2
+#
+# DO NOT EDIT THIS FILE - EDIT EXAMPLES IN THE SOURCE INSTEAD!
+#
+# This file has been generated by AutoDoc. It contains examples extracted from
+# the package documentation. Each example is preceded by a comment which gives
+# the name of a GAPDoc XML file and a line range from which the example were
+# taken. Note that the XML file in turn may have been generated by AutoDoc
+# from some other input.
+#
+gap> START_TEST("graphviz01.tst");
+
+# doc/_Chapter_Full_Reference.xml:78-89
+gap> gv := GraphvizGraph("GraphyMcGraphFace");
+
+gap> GraphvizName(gv);
+"GraphyMcGraphFace"
+gap> GraphvizGraph(666);
+
+gap> gv := GraphvizGraph();
+
+gap> GraphvizName(gv);
+""
+
+# doc/_Chapter_Full_Reference.xml:131-142
+gap> gv := GraphvizDigraph("GraphyMcGraphFace");
+
+gap> GraphvizName(gv);
+"GraphyMcGraphFace"
+gap> GraphvizDigraph(666);
+
+gap> gv := GraphvizDigraph();
+
+gap> GraphvizName(gv);
+""
+
+# doc/_Chapter_Full_Reference.xml:167-177
+gap> dot := GraphvizDigraph("The Round Table");;
+gap> GraphvizName(dot);
+"The Round Table"
+gap> n := GraphvizSetAttr(GraphvizAddNode(dot, "A"), "label", "King Arthur");;
+gap> GraphvizName(n);
+"A"
+gap> e := GraphvizAddEdge(dot, "A", "B");;
+gap> GraphvizName(e);
+"(A, B)"
+
+#
+gap> STOP_TEST("graphviz01.tst", 1);
diff --git a/tst/testall.g b/tst/testall.g
index a5ad9d1..e737bce 100644
--- a/tst/testall.g
+++ b/tst/testall.g
@@ -4,6 +4,6 @@
LoadPackage("graphviz");
TestDirectory(DirectoriesPackageLibrary("graphviz", "tst"),
- rec(exitGAP := true));
+ rec(exitGAP := true, compareFunction := "uptowhitespace"));
FORCE_QUIT_GAP(1); # if we ever get here, there was an error