Can you use the graph! macro from a vec of nodes! macro ?
I'm trying to build a graph programmatically.
I tried to create a list of Stmt using a map like this:
let nodes : Vec<_> = some_collection.map(|n| {
let id = ...
let label = ...
node!(id; attr!("label",label))
}).collect();
let g = graph!(strict di id!("t"); nodes);
However it does not work, as node! returns () and not a Stmt.
Is there a way to do what I'm trying ?
Hi there!
The given code should be working fine but with two small changes.
- The macros
graph!expects a collection of statements andNodeis only one subtype of the statement thus the node in nodes needs to be wrapped withstmt!like from the aforementioned example:
stmt!(node!(id; attr!("label",label)))
Another change regards the graph! macros itself. It can accept either a collection of statements or varargs of statements:
graph!(strict di id!("t"), stmts); //<- collection
graph!(strict di id!("t"); stmt1, stmt2,stmt3); // <- varargs
As you can see, the first example has the sep as a comma and the second is a semicolon. The complete example:
let nodes:Vec<_> = vec![(1,"a"),(2,"b")].iter().map(|(id,label)| {
stmt!(node!(id; attr!("label",label))) // wrapped with stmt!
}).collect();
let g = graph!(strict di id!("t"), nodes); // changed to comma
let res = g.print(&mut PrinterContext::default());
print!("{}",res)
which constructs the following graph:
strict digraph t {
1[label=a]
2[label=b]
}
I will update the documentation for the macros to make it more explicit.
Thanks, this work ! However, I keep getting into issues where my labels seem to be invalid, and breaks the generation. So, two follow-up:
- is there a way to print the generated .dot to check where are errors ?
- are there guidelines for generating / escaping node labels ?
For example, this works:
node!("x"; attr!("label", "add"))
But this breaks:
node!("x"; attr!("label", "+"))
called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "Error: /tmp/.tmp0bKQlI: syntax error in line 2 near '+'\n" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
I generate svg with :
let mut context = PrinterContext::default();
exec(
g,
&mut context,
vec![
Format::Svg.into(),
CommandArg::Output("graph.svg".to_string()),
],
).unwrap();
Yeah, that is a valid point. I have created an issue to provide the docs for the macroses but for now, you can find some examples in the sources here
Speaking about questions:
is there a way to print the generated .dot to check where are errors ?
Yeah, sure. As I showed in the example previously you can just invoke print from the graph before the dot gets generated:
let g = graph!(strict di id!("t"), nodes);
let res = g.print(&mut PrinterContext::default());
print!("{}",res)
are there guidelines for generating / escaping node labels ?
Again, unfortunately, I did not add the docs for macroses and therefore the only way is to scrutinize the the file
Also, You always can ask me here and I can try to look into.
For example, if you want to escape something you can use the prefix esc in macros like that:
#[test]
fn issue_with_node_test() {
let nodes:Vec<_> = vec![(1,"a"),(2,"+")].iter().map(|(id,label)| {
stmt!(node!(id; attr!("label", esc label))) // <- use esc for escaping strings or html for add html tags
}).collect();
let g = graph!(strict di id!("t"), nodes);
let res = g.print(&mut PrinterContext::default());
print!("{}",res)
}
that will give :
strict digraph t {
1[label="-"]
2[label="+"]
}