Graphviz4S

2017-01-11 15:23:33来源:oschina作者:Ldpe2G人点击

第七城市

前言

之前需要在Scala中用到类似python的graphviz库的功能,用来在Mxnet中可视化网络结构,


但是在网上搜索了一下,没有找到好用的库,所以就自己去把python的graphviz库中的主要功能


用Scala实现了一下,尽量的保持接口和python库的一致,也方便从python移植相关的代码到


Scala,然后我把这个小项目开源了,地址是Graphviz4S,有兴趣的朋友可以去试用一下。


接下来我会结合代码,用几个例子来介绍如何使用这个小工具。


正文

接下来我会通过几个例子介绍Grapphviz4S,例子参考自这篇博客。


1、简单例子
1.1、简单图例

首先来看第一个例子,Scala代码如下:


import com.liangdp.graphviz4s.Graph
val dot = new Graph(name = "graphname")
dot.edges(Array(
("a", "b"),
("b", "c"),
("b", "d"),
("d", "a")
))println(dot.source())
//graph graphname {
// a -- b
// b -- c
// b -- d
// d -- a
//}dot.render(fileName = "graphname.gv", directory = ".", view = true)

生成的结果如下:



1.2、简单图例2

第二个例子和上面的一样,但是布局不同,Scala代码如下:


import com.liangdp.graphviz4s.Graph
val dot = new Graph(name = "graphname")dot.body += "/t/trankdir=LR//Rank Direction Left to Right"
dot.edges(Array(
("a", "b"),
("b", "c"),
("b", "d"),
("d", "a")
))println(dot.source())
//graph graphname {
// rankdir=LR//Rank Direction Left to Right
// a -- b
// b -- c
// b -- d
// d -- a
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

生成的结果如下:



1.3、简单有向图

第三个例子是一个简单的有向图,Scala代码如下:


import com.liangdp.graphviz4s.Digraph
val dot = new Digraph(name = "graphname")dot.edges(Array(
("a", "b"),
("b", "c"),
("a", "c")
))println(dot.source())
//digraph graphname {
// a -> b
// b -> c
// a -> c
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

生成的结果如下:



1.4、带标签的简单有向图

第四个例子给有向图的边加上标签,对应的Scala代码如下:


import com.liangdp.graphviz4s.Digraph
val dot = new Digraph(name = "graphname")dot.node(name = "T", label = "Teacher")
dot.node(name = "P", label = "Pupil")import scala.collection.mutable.Map
dot.edge(tailName = "T", headName = "P", label = "Instructions",
attrs = Map("fontcolor" -> "darkgreen"))println(dot.source())
//digraph graphname {
// "T" [label="Teacher" ]
// "P" [label="Pupil" ]
// T -> P [label="Instructions"fontcolor=darkgreen]
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

生成的结果如下:



1.5、总结

Scala代码:


import com.liangdp.graphviz4s.Digraph
val dot = new Digraph(name = "summary")dot.node(name = "start", label = "Start with a Node")
import scala.collection.mutable.Map
dot.node(name = "next", label = "Choose your shape", attrs = Map("shape" -> "box"))
dot.node(name = "warning", label = "Don't go overboard",
attrs = Map("color" -> "Blue", "fontcolor" -> "Red", "fontsize" -> "24",
"style" -> "filled", "fillcolor" -> "green", "shape" -> "octagon"))
dot.node(name = "end", label = "Draw your graph!",
attrs = Map("shape" -> "box", "style" -> "filled", "fillcolor" -> "yellow"))
dot.edge(tailName = "start", headName = "next")
dot.edge(tailName = "start", headName = "warning")
dot.edge(tailName = "next", headName = "end", label = "Getting Better...")
println(dot.source())
//digraph summary {
// "start" [label="Start with a Node" ]
// "next" [label="Choose your shape"shape=box]
// "warning" [label="Don't go overboard"fontsize=24 color=Blue fillcolor=green shape=octagon fontcolor=Red style=filled]
// "end" [label="Draw your graph!"fillcolor=yellow shape=box style=filled]
// start -> next []
// start -> warning []
// next -> end [label="Getting Better..." ]
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

生成的结果如下:



2、高级例子
2.1、少写一点代码

单独地去定义每一个节点的属性很浪费时间,下面这个技巧能够让你coding的速度快一点。


Scala代码如下:


import com.liangdp.graphviz4s.Digraph
val dot = new Digraph(name = "hierarchy")// increases the separation between nodes
dot.body += "/tnodesep=1.0"
import scala.collection.mutable.Map
//All nodes will this shape and colour
dot.attr("node", attrs =
Map("color" -> "Red", "fontname" -> "Courier", "shape" -> "box"))
//All the lines look like this
dot.attr("edge", attrs = Map("color" -> "Blue", "style" -> "dashed"))dot.edges("Headteacher", Array("Deputy1", "Deputy2", "BusinessManager"))
dot.edges("Deputy1", Array("Teacher1", "Teacher2"))
dot.edge("BusinessManager", "ITManager")
// Put them on the same level
dot.body += "/t{rank=same;ITManager Teacher1 Teacher2}"println(dot.source())
//digraph hierarchy {
// nodesep=1.0
// node [ fontname=Courier color=Red shape=box]
// edge [ color=Blue style=dashed]
// Headteacher -> Deputy1
// Headteacher -> Deputy2
// Headteacher -> BusinessManager
// Deputy1 -> Teacher1
// Deputy1 -> Teacher2
// BusinessManager -> ITManager []
// {rank=same;ITManager Teacher1 Teacher2}
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

结果如下:



2.2、html

Scala代码如下:


import com.liangdp.graphviz4s.Digraph
val dot = new Digraph(name = "structs")import scala.collection.mutable.Map
dot.attr("node", attrs = Map("shape" -> "record"))
dot.node("struct1", label = """" left| mid/ dle| right"""")
dot.node("struct2", label = """"{ one| two/n/n/n}"""",
attrs = Map("shape" -> "Mrecord"))
dot.node("struct3", label = """"hello/nworld |{ b |{c| d|e}| f}| g | h"""")dot.edge("struct1:f1", "struct2:f0")
dot.edge("struct1:f0", "struct3:here")
println(dot.source())
//digraph structs {
// node [ shape=record]
// "struct1" [label=" left| mid/ dle| right" ]
// "struct2" [label="{ one| two/n/n/n}"shape=Mrecord]
// "struct3" [label="hello/nworld |{ b |{c| d|e}| f}| g | h" ]
// struct1:f1 -> struct2:f0 []
// struct1:f0 -> struct3:here []
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

结果如下:



2.3、有限状态机

Scala代码如下:


import com.liangdp.graphviz4s.Digraph
val dot = new Digraph(name = "structs")dot.body += "/trankdir=LR"
dot.body += s"""${"/t"}size="8,5""""import scala.collection.mutable.Map
dot.attr("node", attrs = Map("shape" -> "circle"))
dot.edge(tailName = "S0", headName = "S1", label = """"Lift Nozzle"""")
dot.edge(tailName = "S1", headName = "S0", label = """"Replace Nozzle"""")
dot.edge(tailName = "S1", headName = "S2", label = """"Authorize Pump"""")
dot.edge(tailName = "S2", headName = "S0", label = """"Replace Nozzle"""")
dot.edge(tailName = "S2", headName = "S3", label = """"Pull Trigger"""")
dot.edge(tailName = "S3", headName = "S2", label = """"Release Trigger"""")
println(dot.source())
//digraph structs {
// rankdir=LR
// size="8,5"
// node [ shape=circle]
// S0 -> S1 [label="Lift Nozzle" ]
// S1 -> S0 [label="Replace Nozzle" ]
// S1 -> S2 [label="Authorize Pump" ]
// S2 -> S0 [label="Replace Nozzle" ]
// S2 -> S3 [label="Pull Trigger" ]
// S3 -> S2 [label="Release Trigger" ]
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

结果如下:



2.4、数据流示意图

Scala代码如下:


import com.liangdp.graphviz4s.Digraph
val dot = new Digraph(name = "dfd")import scala.collection.mutable.Map
dot.attr("node", attrs = Map("shape" -> "record"))
dot.node("store1", label = """" left| Some data store"""")
dot.node("proc1", label = """"{ 1.0| Some process here/n/n/n}"""",
attrs = Map("shape" -> "Mrecord"))
dot.node("enti1", label = "Customer",
attrs = Map("shape" -> "box"))
dot.edge(tailName = "store1:f1", headName = "proc1:f0")
dot.edge(tailName = "enti1", headName = "proc1:f0")
println(dot.source())
//digraph dfd {
// node [ shape=record]
// "store1" [label=" left| Some data store" ]
// "proc1" [label="{ 1.0| Some process here/n/n/n}"shape=Mrecord]
// "enti1" [label="Customer"shape=box]
// store1:f1 -> proc1:f0 []
// enti1 -> proc1:f0 []
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

结果如下:



2.5、数据流示意图2

Scala代码如下:


import com.liangdp.graphviz4s.Digraph
val dot = new Digraph(name = "dfd2")import scala.collection.mutable.Map
dot.attr("node", attrs = Map("shape" -> "record"))val subgraph0 = new Digraph(name = "level0")
subgraph0.node("enti1", label = "Customer", Map("shape" -> "box"))
subgraph0.node("enti2", label = "Manager", Map("shape" -> "box"))val subgraph1 = new Digraph(name = "cluster_level1")
subgraph1.body += s"""${"/t"}label ="Level 1""""
subgraph1.node("proc1", label = """"{ 1.0| One process here/n/n/n}"""",
attrs = Map("shape" -> "Mrecord"))
subgraph1.node("proc2", label = """"{ 2.0| Other process here/n/n/n}"""",
attrs = Map("shape" -> "Mrecord"))
subgraph1.node("store1", label = """"| Data store one"""")
subgraph1.node("store2", label = """" | Data store two"""")
subgraph1.body += "/t{rank=same; store1, store2}"dot.subGraph(subgraph0)
dot.subGraph(subgraph1)dot.edge("enti1", "proc1")
dot.edge("enti2", "proc2")
dot.edge("store1", "proc1")
dot.edge("store2", "proc2")
dot.edge("proc1", "store2")
dot.edge("store2", "proc1")
println(dot.source())
//digraph dfd2 {
// node [ shape=record]
// subgraph level0 {
// "enti1" [label="Customer"shape=box]
// "enti2" [label="Manager"shape=box]
// }
// subgraph cluster_level1 {
// label ="Level 1"
// "proc1" [label="{ 1.0| One process here/n/n/n}"shape=Mrecord]
// "proc2" [label="{ 2.0| Other process here/n/n/n}"shape=Mrecord]
// "store1" [label="| Data store one" ]
// "store2" [label=" | Data store two" ]
// {rank=same; store1, store2}
// }
// enti1 -> proc1 []
// enti2 -> proc2 []
// store1 -> proc1 []
// store2 -> proc2 []
// proc1 -> store2 []
// store2 -> proc1 []
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

结果如下:



2.6、对象继承

Scala代码如下:


import com.liangdp.graphviz4s.Digraph
val dot = new Digraph(name = "obj")import scala.collection.mutable.Map
dot.attr("node", attrs = Map("shape" -> "record"))
dot.body += s"""${"/t"}rankdir="BT""""dot.node("teacher", label = """"{ Teacher| /n| /n }"""")
dot.node("course", label = """"{ Course| /n| /n }"""")
dot.node("student", label = """"{ Student| /n| /n }"""")
dot.node("lesson", label = """"{ Lesson | /n| /n }"""")
dot.node("tutorial", label = """"{ Tutorial| /n| /n }"""")
dot.node("assessment", label = """"{ Assessment| /n| /n }"""")
dot.node("coursework", label = """"{ Coursework| /n| /n }"""")
dot.node("exam", label = """"{ Exam| /n| /n }"""")
dot.body += "/t{rank=same; teacher course student}"dot.edge("teacher", "course", attrs = Map("dir" -> "forward", "arrowhead" -> "none",
"arrowtail" -> "normal", "headlabel" -> """"1"""", "taillabel" -> """"1..""""))
dot.edge("student", "course", attrs = Map("dir" -> "forward", "arrowhead" -> "none",
"arrowtail" -> "normal", "headlabel" -> """"1"""", "taillabel" -> """"1..""""))
dot.edge("lesson", "course", attrs = Map("dir" -> "forward", "arrowhead" -> "diamond",
"arrowtail" -> "normal"))
dot.edge("tutorial", "course", attrs = Map("dir" -> "forward", "arrowhead" -> "diamond",
"arrowtail" -> "normal"))
dot.edge("assessment", "course", attrs = Map("dir" -> "forward", "arrowhead" -> "diamond",
"arrowtail" -> "normal"))
dot.edge("coursework", "assessment")
dot.edge("exam", "assessment")
println(dot.source())
//digraph obj {
// node [ shape=record]
// rankdir="BT"
// "teacher" [label="{ Teacher| /n| /n }" ]
// "course" [label="{ Course| /n| /n }" ]
// "student" [label="{ Student| /n| /n }" ]
// "lesson" [label="{ Lesson | /n| /n }" ]
// "tutorial" [label="{ Tutorial| /n| /n }" ]
// "assessment" [label="{ Assessment| /n| /n }" ]
// "coursework" [label="{ Coursework| /n| /n }" ]
// "exam" [label="{ Exam| /n| /n }" ]
// {rank=same; teacher course student}
// teacher -> course [ arrowtail=normal dir=forward taillabel="1.." arrowhead=none headlabel="1"]
// student -> course [ arrowtail=normal dir=forward taillabel="1.." arrowhead=none headlabel="1"]
// lesson -> course [ arrowtail=normal dir=forward arrowhead=diamond]
// tutorial -> course [ arrowtail=normal dir=forward arrowhead=diamond]
// assessment -> course [ arrowtail=normal dir=forward arrowhead=diamond]
// coursework -> assessment []
// exam -> assessment []
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

结果如下:



2.7、关系型实体

Scala代码如下:


import com.liangdp.graphviz4s.Digraph
val dot = new Digraph(name = "ER")import scala.collection.mutable.Map
dot.attr("node", attrs = Map("shape" -> "box"))
dot.node("Book")
dot.node("Customer")
dot.node("Loan")dot.body += "/t{rank=same;Book,Customer,Loan}"
dot.edge("Book", "Loan", attrs = Map("dir" -> "forward",
"arrowhead" -> "crow", "arrowtail" -> "normal"))
dot.edge("Customer", "Loan", attrs = Map("dir" -> "forward",
"arrowhead" -> "crow", "arrowtail" -> "normal"))

println(dot.source())
//digraph ER {
// node [ shape=box]
// "Book" []
// "Customer" []
// "Loan" []
// {rank=same;Book,Customer,Loan}
// Book -> Loan [ arrowtail=normal dir=forward arrowhead=crow]
// Customer -> Loan [ arrowtail=normal dir=forward arrowhead=crow]
//}
dot.render(fileName = "graphname.gv", directory = ".", view = true)

结果:



结尾

通过以上例子的介绍,相信读者都能够了解如何使用这个小工具了,不过这个小工具还有很多


需要完善的地方,也欢迎感兴趣的朋友一起来完善它。

第七城市

相关文章

    无相关信息

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台