Generate a DOT (Graphviz) representation of a subgraph.
(nodes: &[KgNode], edges: &[KgEdge])
| 491 | |
| 492 | /// Generate a DOT (Graphviz) representation of a subgraph. |
| 493 | fn emit_dot(nodes: &[KgNode], edges: &[KgEdge]) -> String { |
| 494 | let mut out = String::new(); |
| 495 | out.push_str("digraph query {\n"); |
| 496 | out.push_str(" rankdir=LR;\n"); |
| 497 | out.push_str( |
| 498 | " node [shape=box, style=\"filled,rounded\", fontname=\"Helvetica\", fontsize=10];\n", |
| 499 | ); |
| 500 | out.push_str(" edge [fontname=\"Helvetica\", fontsize=8, color=\"#888888\"];\n"); |
| 501 | out.push('\n'); |
| 502 | |
| 503 | // Nodes |
| 504 | for node in nodes { |
| 505 | let (fillcolor, shape) = node_style(&node.kind); |
| 506 | let label = node_label(node); |
| 507 | out.push_str(&format!( |
| 508 | " \"{}\" [label=\"{}\", fillcolor=\"{}\", shape={}];\n", |
| 509 | dot_escape_id(&node.id), |
| 510 | dot_escape_label(&label), |
| 511 | fillcolor, |
| 512 | shape, |
| 513 | )); |
| 514 | } |
| 515 | |
| 516 | out.push('\n'); |
| 517 | |
| 518 | // Edges |
| 519 | for edge in edges { |
| 520 | out.push_str(&format!( |
| 521 | " \"{}\" -> \"{}\" [label=\"{}\"];\n", |
| 522 | dot_escape_id(&edge.from_id), |
| 523 | dot_escape_id(&edge.to_id), |
| 524 | dot_escape_label(&edge.kind), |
| 525 | )); |
| 526 | } |
| 527 | |
| 528 | out.push_str("}\n"); |
| 529 | out |
| 530 | } |
| 531 | |
| 532 | /// Returns `(fillcolor, shape)` for a given node kind. |
| 533 | fn node_style(kind: &str) -> (&'static str, &'static str) { |
no test coverage detected