Expand description
§Graphviz Writer
This is an ergonomic library for plotting graphs. It outputs the Graphviz language DOT. Graphs written in DOT can then be easily converted to SVG or other image formats using the Graphviz dot executable.
The structs in this library leverage the Rust type system and lifetimes to ensure that it’s hard
to use them to construct an invalid DOT graph. It’s important to note that this means you need
to make sure that child structs go out of scope before using their parents again. This is to make sure that
the Drop
writes the closing brackets correctly. The compiler will tell you if you forget to do this though.
§Non Goals
This library only writes DOT in a strongly typed way. It doesn’t read DOT or render DOT into image files. For that you’ll need a different library, or the existing Graphviz executable.
§Usage
The end point into using the library is the DotWriter
struct. The DotWriter
, can write to any struct
that implements std::io::Write
, a trait from the standard library. For example, you can write directly to
stdout (std::io::stdout()
) or to a vector of bytes (Vec<u8>
).
To begin usign the library create a DotWriter
struct as like this:
use dot_writer::DotWriter;
let mut output_bytes = Vec::new();
let mut writer = DotWriter::from(&mut output_bytes);
Once a DotWriter
exists you can use .digraph()
or .graph()
to start writing a DOT graph.
Then you can write edges using using .edge()
. See Scope
for more functionality.
Here’s a simple “Hello world!” example:
use dot_writer::DotWriter;
let mut output_bytes = Vec::new();
{
let mut writer = DotWriter::from(&mut output_bytes);
writer.set_pretty_print(false);
writer
.digraph()
.edge("Hello", "World"); // digraph goes out of scope here, writing closing bracket
// writer goes out of scope here, freeing up output_bytes for reading
}
assert_eq!(
String::from_utf8(output_bytes).unwrap(),
"digraph{Hello->World;}"
);
If instead you used std::io::stdout()
or wrote to a file using
File or BufReader,
you could then use the dot executable to create an image file:
$ echo "digraph {Hello->World;}" | dot -Tsvg > mygraph.svg
This generates the following image (you can open in firefox or chrome, or switch the image type to png
and use an image viewer of your choice):
Heres a more complex example, demonstrating clustering, colors, labeling and shapes.
Note that chaining calls to edge()
produces a series of nodes that are all connected.
Also note that there is just one call to .digraph()
, as each call would create a new graph:
use dot_writer::{Color, DotWriter, Attributes, Shape, Style};
let mut output_bytes = Vec::new();
{
let mut writer = DotWriter::from(&mut output_bytes);
writer.set_pretty_print(false);
let mut digraph = writer.digraph();
{
let mut cluster = digraph.cluster();
cluster.set_style(Style::Filled);
cluster.set_color(Color::LightGrey);
cluster.node_attributes()
.set_style(Style::Filled)
.set_color(Color::White);
cluster.edge("a0", "a1").edge("a2").edge("a3");
cluster.set_label("process #1");
// cluster goes out of scope here to write closing bracket
}
{
let mut cluster = digraph.cluster();
cluster.node_attributes()
.set_style(Style::Filled);
cluster.edge("b0", "b1").edge("b2").edge("b3");
cluster.set_label("process #2");
cluster.set_color(Color::Blue);
// cluster goes out of scope here to write closing bracket
}
digraph.edge("start", "a0");
digraph.edge("start", "b0");
digraph.edge("a1", "b3");
digraph.edge("b2", "a3");
digraph.edge("a3", "a0");
digraph.edge("a3", "end");
digraph.edge("b3", "end");
digraph.node_named("start")
.set_shape(Shape::Mdiamond);
digraph.node_named("end")
.set_shape(Shape::Msquare);
// digraph goes out of scope here to write closing bracket
// then writer goes out of scope here to free up output_bytes for reading
}
assert_eq!(
String::from_utf8(output_bytes).unwrap(),
"digraph{subgraph cluster_0{style=\"filled\";color=lightgray;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];}"
);
This produces (after render with dot) the following lovely graph:
Structs§
- Attributes
List - An
AttributesList
sets the attributes of an edge or node. See theAttributes
trait for more information on what fields can be set. - DotWriter
- The entry point struct for writing a DOT graph.
See the examples on the index for how to use it.
This struct must live for the livetime of writing the graph,
and also outlive the
Write
struct it points to, because it’sDrop
trait will finish writing graph. - Edge
List - An
EdgeList
is returned fromScope::edge
and can be used to set the attributes of an edge, or to chain additional nodes onto the edge statement. - Node
- A
Node
is returned fromScope::node_named
orScope::node_auto
, and allows for getting the id of the node for future reference viaNode::id
, - NodeId
- A
NodeId
wraps a string storing the Id of a Node It’s designed for use with theScope::edge
function, and for creatingPortId
usingNodeId::port
. - PortId
- A
PortId
wraps a string referning to the nnode id and port of a specifc record or Mrecord node (for more information see “Record-based Nodes” in the Graphviz documentation). - Port
PosId - A
PortPosId
wraps a string referning to theNodeId
,PortId
andPortPosition
of a specifc record or Mrecord node (for more information see “portPos” in the Graphviz documentation). - Scope
- A
Scope
struct represents either a graph, digraph, subgraph or cluster. Its the workhorse of the DOT writing, and can be used to create new sub-scopes, add nodes, add edges, or adjust default attributes for any of the above.
Enums§
- Arrow
Type - Arrow types, used to set either head or tail, for more information see Graphviz documentation.
- Color
- Color of a line or fill. This list is far from comprehensive, the
full list is visible here,
and can instead be set using
Attributes::set
- Port
Position - Refers the position to add an edge for of a specifc record or Mrecord node (for more information see “portPos” in the Graphviz documentation).
- Rank
- Node rank type, for more information see Graphviz documentation.
- Rank
Direction - Direction to layout graph, for more information see Graphviz documentation.
- Shape
- Shape of a component. This list is not comprehensive, the full list
is visible here
and can instead be set using
Attributes::set
. - Style
- Style of design. Note that some of these or only valid for certain combinations of node, edge and cluster. See documentation here for more information.
Traits§
- Attributes
- Structs that implement
Attributes
are used for writing the attributes of a diagraph, graph, subgraph, subgraph cluster, node or edge.