https://mlln.cn/2018/09/25/python-graphviz%E5%9B%BE%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96%E5%85%A5%E9%97%A8/

安装

graphviz为Graphviz图形绘制软件提供了一个简单的纯Python接口。它在Python 2.7和3.4+下运行。要使用pip安装它,请运行以下命令:

  1. pip install graphviz

或者:
Anaconda下安装Graphviz推荐下面的方法:
在cmd终端运行:

  1. conda install python-graphviz


除此之外,不需要做额外的配置工作。

基本用法

graphviz模块提供两个类:Graph和Digraph。他们使用DOT语言为无向和有向图创建图形描述。他们有相同的API。

通过实例化新的Graph或Digraph对象来创建图形:

  1. from graphviz import Digraph
  2. dot = Digraph(comment='这是一个有向图')
  3. str(dot)

执行结果:

  1. '// 这是一个有向图\ndigraph {\n}'

它们的构造函数允许设置图形的name,DOT代码的filename,源代码行的注释等。

使用node()和edge()或edges()方法将节点和边添加到图形对象:

  • node()方法第一个参数是name, 第二个参数是label
  • edges()方法可以一次添加多个边, 每个边用字符串表示, 比如AB表示从A到B的边
  • edge()方法一次添加一个边
  1. dot = Digraph(comment='这是一个有向图')
  2. dot.node('A', '作者')
  3. dot.node('B', '医生')
  4. dot.node('C', '律师')
  5. dot.edges(['AB', 'AC'])
  6. dot.edge('B', 'C')
  7. print(dot.source)

执行结果:

  1. // 这是一个有向图
  2. digraph {
  3. A [label="作者"]
  4. B [label="医生"]
  5. C [label="律师"]
  6. A -> B
  7. A -> C
  8. B -> C
  9. }

使用render方法将保存dot源码, 并且会渲染图形, 使用view=True参数可以自动打开应用程序以便浏览生成的图:

  1. # 将dot源码保存到文件:output-graph.gv
  2. # 同时会生成一个pdf文件: output-graph.gv.pdf view=True 可以调用本地程序显示
  3. dot.render('output-graph.gv', view=True)

除了PDF, 还可以生成其他格式, 比如png:

  1. dot.format = 'png'
  2. dot.render('output-graph.gv', view=True)

由于这是jupyter notebook环境, 我们直接使用notebook展示生成的图片即可:

  1. from IPython.display import display, Image
  2. Image(dot.render('output-graph.gv'))

piped输出

为了直接获取Graphviz软件渲染结果, 而不是让它保存到文件中, 我们可以使用pipe()方法, 比如我们可以直接获取渲染后的svg源码:

  1. from graphviz import Graph
  2. h = Graph('hello', format='svg')
  3. h.edge('Hello', 'World')
  4. print(h.pipe().decode('utf-8'))

jupyter notebook中显示

因为Graph和Bigraph类都有repr_svg()方法, 因此他们可以直接显示在notebook中, 而不需要做任何处理, 例如, 上面的svg图, 可以直接显示:

  1. h

执行结果:
image.png

显示风格

使用graph_attr, node_attr, edge_attr参数, 你可以更改图中节点和边的显示样式:

  1. ps = Digraph(name='pet-shop', node_attr={'shape': 'plaintext'})
  2. ps.node('parrot')
  3. ps.node('dead')
  4. ps.edge('parrot', 'dead')
  5. ps

image.png
创建完毕以后, 你可以更改这些样式:

  1. ps.graph_attr['rankdir'] = 'LR'
  2. ps.edge_attr.update(arrowhead='vee', arrowsize='2')
  3. ps

image.png

属性

我们可以直接更改图中所有节点和边的属性, 相当于全局配置, 只要使用attr方法即可:

  1. ni = Graph('ni')
  2. # 设置所有节点的形状
  3. ni.attr('node', shape='rarrow')
  4. ni.node('1', 'Ni!')
  5. ni.node('2', 'Ni!')
  6. # 如果单独设置, 优先级更高
  7. ni.node('3', 'Ni!', shape='egg')
  8. ni.node('4', 'Ni!')
  9. ni

image.png

使用引号和HTML作为label

在label中使用引号需要使用转义字符\:

  1. ni.node('5', '\"Ni\"')
  2. ni

image.png
在label中使用html可以使用< >将html内容括起来, 比如, 我们可以使用下标sub:

  1. ni.node('6', '<N<sub>i</sub>>')
  2. ni

image.png

子图和集群

Graph和Bigraph’对象都有subgraph()`方法用于添加子图, 它有两种用法:

  • 可以直接添加一个Graph或者Bigraph对象: ```python p = Graph(name=’parent’) p.edge(‘spam’, ‘eggs’)

c = Graph(name=’child’, node_attr={‘shape’: ‘box’}) c.edge(‘foo’, ‘bar’)

p.subgraph(c) p

  1. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/709883/1587712646329-a88069ba-132e-4a08-8d29-7bc3ea46aa35.png#align=left&display=inline&height=155&margin=%5Bobject%20Object%5D&name=image.png&originHeight=155&originWidth=189&size=6080&status=done&style=none&width=189)
  2. - 使用with代码块:
  3. ```python
  4. p = Graph(name='parent')
  5. p.edge('spam', 'eggs')
  6. with p.subgraph(name='child', node_attr={'shape': 'box'}) as c:
  7. c.edge('foo', 'bar')
  8. p

image.png

引擎

渲染引擎可以选择多种, 而不仅仅是dot, 比如你可以使用neato:

  1. g = Graph(engine='neato')

或者也可以直接更改渲染引擎:

  1. g.engine = 'circo'

添加dot语句

有些应用场景是需要使用已经写好的dot语句的, 这时候我们可以直接调用body.append方法来追加dot语句:

  1. rt = Digraph()
  2. rt.body.append('\t"King Arthur" -> {\n\t\t"Sir Bedevere", "Sir Lancelot"\n\t}')
  3. rt.edge('Sir Bedevere', 'Sir Lancelot', constraint='false')
  4. rt

image.png

使用dot文件和源码

我们可以直接使用Source类来直接实例化一个Source对象, 传入的参数就是dot源码, 然后可以调用render方法渲染成图片:

  1. from graphviz import Source
  2. src = Source('digraph "the holy hand grenade" { rankdir=LR; 1 -> 2 -> 3 -> lob }')
  3. str(src)

执行结果

  1. '<graphviz.files.Source object at 0x104200ad0>'

我们还可以直接使用from_file方法来从一个dot文件实例化:

  1. src = Source.from_file('output-graph-font.gv')
  2. src

image.png

使用临时文件浏览图

很多时候我们要多次浏览绘制的图, 但是又不想保存这个文件, 那么我们可以使用临时文件保存生成的结果:

  1. import tempfile
  2. g = Graph()
  3. g.node('spam')
  4. g.view(tempfile.mktemp('.gv'))