跳转到主要内容

标签(标签)

资源精选(342) Go开发(108) Go语言(103) Go(99) angular(82) LLM(75) 大语言模型(63) 人工智能(53) 前端开发(50) LangChain(43) golang(43) 机器学习(39) Go工程师(38) Go程序员(38) Go开发者(36) React(33) Go基础(29) Python(24) Vue(22) Web开发(20) Web技术(19) 精选资源(19) 深度学习(19) Java(18) ChatGTP(17) Cookie(16) android(16) 前端框架(13) JavaScript(13) Next.js(12) 安卓(11) 聊天机器人(10) typescript(10) 资料精选(10) NLP(10) 第三方Cookie(9) Redwoodjs(9) LLMOps(9) Go语言中级开发(9) 自然语言处理(9) PostgreSQL(9) 区块链(9) mlops(9) 安全(9) 全栈开发(8) ChatGPT(8) OpenAI(8) Linux(8) AI(8) GraphQL(8) iOS(8) 软件架构(7) Go语言高级开发(7) AWS(7) C++(7) 数据科学(7) whisper(6) Prisma(6) 隐私保护(6) RAG(6) JSON(6) DevOps(6) 数据可视化(6) wasm(6) 计算机视觉(6) 算法(6) Rust(6) 微服务(6) 隐私沙盒(5) FedCM(5) 语音识别(5) Angular开发(5) 快速应用开发(5) 提示工程(5) Agent(5) LLaMA(5) 低代码开发(5) Go测试(5) gorm(5) REST API(5) 推荐系统(5) WebAssembly(5) GameDev(5) CMS(5) CSS(5) machine-learning(5) 机器人(5) 游戏开发(5) Blockchain(5) Web安全(5) Kotlin(5) 低代码平台(5) 机器学习资源(5) Go资源(5) Nodejs(5) PHP(5) Swift(5) 智能体(4) devin(4) Blitz(4) javascript框架(4) Redwood(4) GDPR(4) 生成式人工智能(4) Angular16(4) Alpaca(4) 编程语言(4) SAML(4) JWT(4) JSON处理(4) Go并发(4) kafka(4) 移动开发(4) 移动应用(4) security(4) 隐私(4) spring-boot(4) 物联网(4) nextjs(4) 网络安全(4) API(4) Ruby(4) 信息安全(4) flutter(4) 专家智能体(3) Chrome(3) CHIPS(3) 3PC(3) SSE(3) 人工智能软件工程师(3) LLM Agent(3) Remix(3) Ubuntu(3) GPT4All(3) 软件开发(3) 问答系统(3) 开发工具(3) 最佳实践(3) RxJS(3) SSR(3) Node.js(3) Dolly(3) 移动应用开发(3) 低代码(3) IAM(3) Web框架(3) CORS(3) 基准测试(3) Go语言数据库开发(3) Oauth2(3) 并发(3) 主题(3) Theme(3) earth(3) nginx(3) 软件工程(3) azure(3) keycloak(3) 生产力工具(3) gpt3(3) 工作流(3) C(3) jupyter(3) 认证(3) prometheus(3) GAN(3) Spring(3) 逆向工程(3) 应用安全(3) Docker(3) Django(3) R(3) .NET(3) 大数据(3) Hacking(3) 渗透测试(3) C++资源(3) Mac(3) 微信小程序(3) Python资源(3) JHipster(3) 大型语言模型(2) 语言模型(2) 可穿戴设备(2) JDK(2) SQL(2) Apache(2) Hashicorp Vault(2) Spring Cloud Vault(2) Go语言Web开发(2) Go测试工程师(2) WebSocket(2) 容器化(2) AES(2) 加密(2) 输入验证(2) ORM(2) Fiber(2) Postgres(2) Gorilla Mux(2) Go数据库开发(2) 模块(2) 泛型(2) 指针(2) HTTP(2) PostgreSQL开发(2) Vault(2) K8s(2) Spring boot(2) R语言(2) 深度学习资源(2) 半监督学习(2) semi-supervised-learning(2) architecture(2) 普罗米修斯(2) 嵌入模型(2) productivity(2) 编码(2) Qt(2) 前端(2) Rust语言(2) NeRF(2) 神经辐射场(2) 元宇宙(2) CPP(2) 数据分析(2) spark(2) 流处理(2) Ionic(2) 人体姿势估计(2) human-pose-estimation(2) 视频处理(2) deep-learning(2) kotlin语言(2) kotlin开发(2) burp(2) Chatbot(2) npm(2) quantum(2) OCR(2) 游戏(2) game(2) 内容管理系统(2) MySQL(2) python-books(2) pentest(2) opengl(2) IDE(2) 漏洞赏金(2) Web(2) 知识图谱(2) PyTorch(2) 数据库(2) reverse-engineering(2) 数据工程(2) swift开发(2) rest(2) robotics(2) ios-animation(2) 知识蒸馏(2) 安卓开发(2) nestjs(2) solidity(2) 爬虫(2) 面试(2) 容器(2) C++精选(2) 人工智能资源(2) Machine Learning(2) 备忘单(2) 编程书籍(2) angular资源(2) 速查表(2) cheatsheets(2) SecOps(2) mlops资源(2) R资源(2) DDD(2) 架构设计模式(2) 量化(2) Hacking资源(2) 强化学习(2) flask(2) 设计(2) 性能(2) Sysadmin(2) 系统管理员(2) Java资源(2) 机器学习精选(2) android资源(2) android-UI(2) Mac资源(2) iOS资源(2) Vue资源(2) flutter资源(2) JavaScript精选(2) JavaScript资源(2) Rust开发(2) deeplearning(2) RAD(2)

category

使用graphviz和Pydot包创建有向图

In the first part of this series, I shared how to create a flowchart using the SchemDraw package. In the second part, I described creating a directed acyclic graph with NetworkX package while exploring the characteristics, centrality concept and retrieving all possible paths from root node to the leaves. This part will focus on constructing directed acyclic graphs using the graphviz and pydot packages. I shall also explain a bit about the styling and attribute options with the graphviz. Let’s get started.

Image by Schweizer from Unsplash

graphviz package

Graphviz is an open-source graph visualisation software. The graphviz package, which works under Python 3.7+ in Python, provides a pure-Python interface to this software. This package allows to create both undirected and directed graphs using the DOT language.

Constructing the Graph or DiGraph object using graphviz is similar to that using NetworkX in the sense that one needs to simply define the nodes and edges of the graph object and assign the attributes accordingly. However, there are some key differences as well. For example, in the NetworkX package, the node can be defined as any hashable object (except None). But in graphviz, a node can only be defined as a string.

In my previous post, I pointed out the different limitations of graph visualisation with the NetworkX package, such as limited options for node shapes, limitation for getting unique shape and bounding box (bbox) attributes for individual nodes, etc. In this post, I am going to share how the graphviz package not only overcomes those limitations, but also offers much more flexibility options for graph visualisation. I am going to depict this by reconstructing the organogram created using NetworkX in the previous post, but using graphviz in this post.

Plotting Organogram using graphviz

To create a plain organogram using graphviz package, I start with initializing a graph object say f as graphviz.Digraph(filename) , where filename is the name of the output file created. I created a list of eight names starting from A to H, and the list of all the positions held in the company. Next, by going through a for loop, I created eight nodes for each name and added the corresponding position of the individual in the organisation as labels. I specified the edges between the CEO and two team leads, and team leads and their corresponding staff. The code for the same is as given below:

import graphvizf = graphviz.Digraph(filename = “output/plain organogram 1.gv”)names = [“A”,”B”,”C”,”D”,”E”,”F”,”G”,”H”]positions = [“CEO”,”Team A Lead”,”Team B Lead”, “Staff A”,”Staff B”, “Staff C”, “Staff D”, “Staff E”]for name, position in zip(names, positions):
     f.node(name, position)
 
#Specify edges
f.edge(“A”,”B”); f.edge(“A”,”C”) #CEO to Team Leads
f.edge(“B”,”D”); f.edge(“B”,”E”) #Team A relationship
f.edge(“C”,”F”); f.edge(“C”,”G”); f.edge(“C”,”H”) #Team B relationship
 
f

As a result, I get a plain organogram graph as shown below:

Plain organogram created using graphviz. Image by Author.

In the graph above, the size of each node is adapted automatically to fit the labels within the node. This was not the case with the NetworkX package.

Styling and attributes with the graphviz package

As mentioned earlier, the graphviz package offers various styling options and attributes to customise the graphs. Some of these possibilities are described below in detail:

Node shapes

The default shape of node in the graph created using graphviz is ellipse. It is possible to get a wide variety of shapes for nodes using graphviz, which can be found here. These shapes could be polygon-based, record-based, or user-defined. Moreover, it is also possible to get different shape for different nodes. In the code below, I changed the shape of node for the CEO to oval, box shape for the two team leads, and just plaintext for the staff.

import graphvizf = graphviz.Digraph(filename = "output/plain organogram 2.gv")names = ["A","B","C","D","E","F","G","H"]positions = ["CEO","Team A Lead","Team B Lead", "Staff A","Staff B", "Staff C", "Staff D", "Staff E"]for name, position in zip(names, positions):
    if name == "A":
        f.node(name, position, shape = "oval")
        
    elif name in ["B","C"]:
        f.node(name, position, shape = "box")
    else:
        f.node(name, position, shape = "plaintext")#Specify edges
f.edge("A","B"); f.edge("A","C")   #CEO to Team Leads
f.edge("B","D"); f.edge("B","E")   #Team A relationship
f.edge("C","F"); f.edge("C","G"); f.edge("C","H")   #Team B relationship
    
f
Plain organogram with different shaped nodes for different employees. Images by Author.

Node color and edge color

It is also possible to assign different color to different nodes and edges using graphviz. I created a list of colors and then assigned a color for each node using the for loop in the code below. I assigned black color to the CEO, blue color to team A, and red color to team B. In the same fashion, I assigned blue color to the edges connecting team A, and red color to the edges connecting team B.

import graphvizf = graphviz.Digraph(filename = "output/colorful organogram 1.gv")names = ["A","B","C","D","E","F","G","H"]positions = ["CEO","Team A Lead","Team B Lead", "Staff A","Staff B", "Staff C", "Staff D", "Staff E"]colors = ["black", "blue", "red", "blue", "blue", "red", "red", "red"]for name, position, color in zip(names, positions, colors):
    f.node(name, position, color = color)
    
#Specify edges
#CEO to Team Leads
f.edge("A","B", color = "blue", label = "A"); f.edge("A","C", color = "red", label = "B")   
#Team A
f.edge("B","D", color = "blue"); f.edge("B","E", color = "blue")   
#Team B 
f.edge("C","F", color = "red"); f.edge("C","G", color = "red"); f.edge("C","H", color = "red")   
    
f
Organogram with specified node and edge colors created using graphviz. Image by Author.

Fill nodes with colors

In this step, I customised the graph further by filling the color inside the nodes. It is done simply by stating style = “filled" while defining the nodes and assigning the color.

import graphvizf=graphviz.Digraph(filename='output/filled_colorful_organogram.gv')names = ["A","B","C","D","E","F","G","H"]positions = ["CEO","Team A Lead","Team B Lead", "Staff A","Staff B", "Staff C", "Staff D", "Staff E"]colors = ["black", "skyblue", "mistyrose", "skyblue", "skyblue", "mistyrose", "mistyrose", "mistyrose"]for name, position, color in zip(names, positions, colors):
    if name== "A":
        f.node(name, position, color = color)
    else:
        f.node(name, position, style = "filled", color = color)
    
#Specify edges
f.edge("A","B"); f.edge("A","C")   #CEO to Team Leads
f.edge("B","D"); f.edge("B","E")   #Team A relationship
f.edge("C","F"); f.edge("C","G"); f.edge("C","H")   #Team B relationship
    
f
Nodes filled with specified color in the organogram. Image by Author.

Running gv file from the terminal

The digraph object f can be displayed in the output Graphviz DOT file of the gv extension and saved using f.view(). It is also possible to print the source code of this digraph object written in the DOT language, simply by using f.source in the notebook.

Source code of the digraph object above in the DOT language. Image by Author.

The txt file above contains the source code of the digraph in the DOT language. I have specified the x and y position of the nodes manually using pos. This file can be run in the terminal using the following code:

dot -Kfdp -n -Tjpeg -Gdpi=300 -O example_digraph.txt

It generates the digraph object as a jpeg file with 300 dpi resolution.

Pydot package

The pydot package is an interface to Graphviz. It is written in pure Python, and it can parse and dump into the DOT language used by Graphviz. A folder tree structure in a computer comprising of a directory, sub-directory, files, etc. is also an example of a directed graph. In the following section, I am going to explain how the pydot package can be used to get the folder tree structure.

Folder tree using Pydot package

I start with creating a directed graph object called G. The os module in Python provides a portable way of using operating system-dependent functionalities. os.getcwd() returns the current working directory including the path, which I assign as rootDir. From the rootDir, I get the name of the directory only (graph_visualisation_basics) and pass it as currentDir. I add a node for currentDir and fill it with green color. By using a for loop, I define the nodes for each subdirectory and file and add edges between them. Next, I fill the nodes for subdirectory with yellow color and the files with orange color. At the same time, I ignore the hidden folders whose name starts with a ..

The image of the graph object is created using Image(G.create_jpeg() and displayed by passing it through IPython.display.display(). The image file is saved in jpeg format using G.write_jpeg(filename), where filename is the name of the file saved.

Folder tree structure comprising hierarchy of root directory, sub directory and files created using the code above. Image by Author.

Conclusion

This is the third part of the series on graph visualisation basics with Python. The motivation behind this series was to share the simple techniques I learned while creating flowcharts, and graph objects in Python using packages such as SchemDraw, NetworkX, and graphviz. In this post, I described how a directed graph object could be created using the graphviz package using the example of an organogram. I also showcased the various options for styling and adding attributes to the graph components offered by graphviz. Towards the end, I shared how the folder tree structure in a system could be constructed as a graph using the Pydot package.

The notebooks for the posts in this series are available in this repository. Thank you for reading!