Open NicolasRouquette opened 3 years ago
I have tried the following:
import guru.nidi.graphviz.attribute.{Attributes,Label,Shape}
import guru.nidi.graphviz.engine.{Format, Graphviz}
import guru.nidi.graphviz.model.{Factory,MutableGraph}
import java.io.File
object ConstructNestedGraphExample:
def main(args: Array[String]): Unit =
val g: MutableGraph = Factory
.graph("Q")
.directed()
.nodeAttr()
.`with`(Shape.RECTANGLE)
.toMutable
val cr: MutableGraph = Factory
.graph("cluster_R")
.directed()
.toMutable()
.setCluster(true)
g.add(cr)
val nd1 = Factory.mutNode("nd_1").add(Label.of("Node 1"))
g.add(nd1)
val nd2 = Factory.mutNode("nd_2").add(Label.of("Node 2"))
g.add(nd2)
val nd3a = Factory.mutNode("nd_3_a").add(Label.of( "Above Right Node 3"))
g.add(nd3a)
val nd3l = Factory.mutNode("nd_3_l").add(Label.of("Left of Node 3"))
cr.add(nd3l)
val nd3 = Factory.mutNode("nd_3").add(Label.of("Node 3"))
cr.add(nd3)
val nd3r = Factory.mutNode("nd_3_r").add(Label.of("Right of Node 3"))
cr.add(nd3r)
val nd4 = Factory.mutNode("nd_4").add(Label.of("Node 4"))
g.add(nd4)
// nd_3_a -> nd_3_r;
nd3a.links().add(nd3a.linkTo(nd3r))
// nd_1 -> nd_2 -> nd_3 -> nd_4;
nd1.links().add(nd1.linkTo(nd2))
nd2.links().add(nd2.linkTo(nd3))
nd3.links().add(nd3.linkTo(nd4))
// how to add links within the cluster?
// nd_3_l -> nd_3 -> nd_3_r [color=grey arrowhead=none];
nd3l.links().add(nd3l.linkTo(nd3))
nd3.links().add(nd3.linkTo(nd3r))
val gv = Graphviz.fromGraph(g)
gv.render(Format.DOT).toFile(new File("ConstructNestedGraphExample.dot"))
gv.render(Format.SVG_STANDALONE).toFile(new File("ConstructNestedGraphExample.svg"))
I get a duplication of edges in the dot and svg only (with the debugger, I see that the links are not duplicated):
digraph "Q" {
node ["shape"="rectangle"]
"nd_1" ["label"="Node 1"]
"nd_2" ["label"="Node 2"]
"nd_3" ["label"="Node 3"]
"nd_4" ["label"="Node 4"]
"nd_3_r" ["label"="Right of Node 3"]
"nd_3_a" ["label"="Above Right Node 3"]
subgraph "cluster_cluster_R" {
"nd_3_l" ["label"="Left of Node 3"]
"nd_3" ["label"="Node 3"]
"nd_4" ["label"="Node 4"]
"nd_3_r" ["label"="Right of Node 3"]
"nd_3_l" -> "nd_3"
"nd_3" -> "nd_4"
"nd_3" -> "nd_3_r"
}
"nd_1" -> "nd_2"
"nd_2" -> "nd_3"
"nd_3" -> "nd_4"
"nd_3" -> "nd_3_r"
"nd_3_a" -> "nd_3_r"
}
In the above, nd_4
ends up in the cluster even though it was not assigned to it.
Edges nd_3 -> nd_4
and nd_3 -> nd_3_r
are duplicated even though they are created and added only once.
With the immutable API, I managed to construct the desired topology with the following:
import guru.nidi.graphviz.attribute.{Attributes, Label, Shape}
import guru.nidi.graphviz.engine.{Format, Graphviz}
import guru.nidi.graphviz.model.{Factory, Graph}
import java.io.File
object ConstructNestedGraphExample:
def main(args: Array[String]): Unit =
val g1: Graph = Factory
.graph("Q")
.directed()
.nodeAttr()
.`with`(Shape.RECTANGLE)
.`with`(Factory.node("nd_1").`with`(Label.of("Node 1")))
.`with`(Factory.node("nd_2").`with`(Label.of("Node 2")))
.`with`(Factory.node("nd_3_a").`with`(Label.of("Above Right Node 3")))
.`with`(Factory.node("nd_4").`with`(Label.of("Node 4")))
.`with`(Factory.node("nd_1").link(Factory.node("nd_2")))
.`with`(Factory.node("nd_2").link(Factory.node("nd_3")))
.`with`(Factory.node("nd_3").link(Factory.node("nd_4")))
.`with`(Factory.node("nd_3_a").link(Factory.node("nd_3_r")))
val cr: Graph = Factory
.graph("cluster_R")
.directed()
.cluster()
.`with`(Factory.node("nd_3_l").`with`(Label.of("Left of Node 3")))
.`with`(Factory.node("nd_3").`with`(Label.of("Node 3")))
.`with`(Factory.node("nd_3_r").`with`(Label.of("Right of Node 3")))
.`with`(Factory.node("nd_3_l").link(Factory.node("nd_3")))
.`with`(Factory.node("nd_3").link(Factory.node("nd_3_r")))
val g2 = g1
.`with`(cr)
val gv = Graphviz.fromGraph(g2)
gv.render(Format.DOT).toFile(new File("ConstructNestedGraphExample.dot"))
gv.render(Format.SVG_STANDALONE).toFile(new File("ConstructNestedGraphExample.svg"))
This produces the following graph in dot:
digraph "Q" {
node ["shape"="rectangle"]
"nd_1" ["label"="Node 1"]
"nd_2" ["label"="Node 2"]
"nd_3_a" ["label"="Above Right Node 3"]
"nd_4" ["label"="Node 4"]
subgraph "cluster_cluster_R" {
"nd_3_l" ["label"="Left of Node 3"]
"nd_3" ["label"="Node 3"]
"nd_3_r" ["label"="Right of Node 3"]
"nd_3_l" -> "nd_3"
"nd_3" -> "nd_3_r"
}
"nd_1" -> "nd_2"
"nd_2" -> "nd_3"
"nd_3_a" -> "nd_3_r"
"nd_3" -> "nd_4"
}
I use the graphviz-java library from Scala.
I would like to construct a graph like the following instead of parsing it from dot.
The following example is adapted from this: https://renenyffenegger.ch/notes/tools/Graphviz/examples/index
The above produces the following dot result:
It is unclear to me how to programmatically construct such a graph.
I can create a subgraph with nodes and edges within the subgraph OK. However, as soon as I add an edge between nodes in different subgraphs or between a subgraph node and a toplevel node, I get some strange behavior where the dot output has many duplicated edges.