Graphviz是一款开源图形可视化软件。图形可视化(Graph visualization)是一种将图形的结构信息表示为网络图的方法。它在网络、生物信息学、软件工程、数据库和网页设计、机器学习以及其他技术领域的可视化界面中有着重要的应用。
安装Graphviz的方法如下:
- Linux系统:
sudo apt install graphviz
或者
sudo dnf install graphviz
- Windows系统:
采用官网提供的安装包安装,或者采用如下pip安装
pip install graphviz
成功安装graphviz后,可利用其中的Digraph库生成有向图。使用graphviz的基本操作见文档,这里介绍几个可以修改的图形属性:
- 布局引擎(Layout Engines):本代码中为ENGINENAME,是图形可视化的算法名称。dot 将有向图里的每个节点分层,画出的图像有较为严格的层次。fdp(Force-Directed Placement) 为力导向布局,画出的图像有类似放射发散性的布局。circo 为环形布局。
- 布局方向(Rankdir):本代码中为RANKDIR,其中TB代表Top to Bottom,LR代表Left to Right。
- 节点形状:本代码中为SHAPE
- 字体:本代码中为FONTNAME
- 输出格式:本代码中为FORMAT
- 红楼梦家族:本代码中为FAMILYNAME
具体代码如下,其中图形属性部分包含可以修改的参数。红楼梦家族成员关系信息用列表存储,generateRelations函数将列表转化为树。
from graphviz import Digraph
#图形属性
FAMILYNAME = 'all' # 'all', 'jia', 'wang', 'xue', 'shi'
ENGINENAME = 'dot' # 'dot', 'circo', 'fdp', 'neato', 'osage', 'patchwork', 'sfdp', 'twopi'
RANKDIR = 'LR' # 'LR', 'RL', 'TB', 'BT'
SHAPE = 'box' # 'box', 'ellipse', 'diamond', ...
FONTNAME = 'FangSong' # 'FangSong', 'SimSun', 'KaiTi', ...
FORMAT = 'pdf' # 'pdf', 'jpeg', 'png', ...
#家族成员关系(用列表表示树)
RELATION_JIA = [u"贾太公", [[u"贾代儒之父", [[u"贾代儒", [[u"贾瑞父", [u"贾瑞"]]]]]], [u"贾演", [[u"贾代化", [u"贾敷", [u"贾敬", [[u"贾珍", [u"贾蓉", u"贾蔷(侄子)"]], u"贾惜春"]]]]]], [u"贾源", [[u"贾代善", [[u"贾赦", [[u"贾琏", [u"巧姐"]], u"贾琮", u"贾迎春"]], [u"贾政", [[u"贾珠", [u"贾兰"]], u"贾元春", u"贾宝玉", u"贾探春", u"贾环"]], [u"贾敏", [u"林黛玉"]]]]]]]]
RELATION_WANG = [u"王公", [[u"王夫人之父", [[u"熙凤父", [u"王熙凤", u"王仁"]], u"王子腾", u"王夫人", u"薛姨妈"]]]]
RELATION_XUE = [u"薛公", [[u"宝钗祖父", [[u"宝琴父", [u"薛蝌", u"薛宝琴"]], [u"宝钗父", [u"薛蟠", u"薛宝钗"]]]]]]
RELATION_SHI = [u"史公", [[u"湘云祖父", [[u"湘云父", [u"史湘云"]], u"史鼐", u"史鼎"]], u"贾母"]]
RELATION_ALL = [u"四大家族", [RELATION_JIA, RELATION_WANG, RELATION_XUE, RELATION_SHI]]
#添加图形元素和关系
def generateRelations(graph_lst : list, current_relation : list) -> None:
current_person = current_relation[0]
for next_relation in current_relation[1]:
isEnd = type(next_relation) != type([])
next_person = next_relation if isEnd else next_relation[0]
graph_lst[0].node(next_person, fontname=FONTNAME, shape=SHAPE)
graph_lst[0].edge(current_person, next_person)
if not isEnd:
generateRelations(graph_lst, next_relation)
#获取家族列表
def getFamily(name : str) -> list:
match name.lower():
case 'all':
return RELATION_ALL
case 'jia':
return RELATION_JIA
case 'wang':
return RELATION_WANG
case 'xue':
return RELATION_XUE
case 'shi':
return RELATION_SHI
assert False
#创建有向图
graph = Digraph(engine=ENGINENAME, encoding='utf-8')
graph.attr(rankdir=RANKDIR)
#创建第一个顶点
graph.node(getFamily(FAMILYNAME)[0], fontname=FONTNAME, shape=SHAPE)
#添加节点和边
generateRelations([graph], getFamily(FAMILYNAME))
#生成图像
graph.render(f'relationship_{FAMILYNAME}_{ENGINENAME}_{RANKDIR}_{FONTNAME}', format=FORMAT, view=True)
运行代码后,会在代码存放的目录下生成指定格式的文件。
采用dot布局算法生成的四大家族关系图如下

采用fdp布局算法生成的四大家族关系图如下

采用circo布局算法生成的王家关系图如下

其他的布局算法可以自己尝试一下,graphviz的功能还是很强大的。
结语:最近在温习一些图论相关的知识时偶然发现了这个功能强大的Graphviz库,又想起高中时自己画过的《红楼梦》关系图,遂尝试了一番,敲了敲代码,弄出了文章中的几个图像。不过阅读《红楼梦》不应死记这些名字,有时候就算不给出某个人物的名字,其说话方式也能让大部分读者知晓其身份。Graphviz的功能远不止这些,有兴趣可以看下官网的介绍,希望你能有些收获。
发表回复