Python使用graphviz绘制模块间数据流

graphviz官方参考链接:
http://www.graphviz.org/documentation/
https://graphviz.readthedocs.io/en/stable/index.html


文章目录

    • 需求描述
    • 环境配置
    • 实现思路
    • 代码实现


需求描述

根据各模块之间的传参关系绘制出数据流,如下图所示:
在这里插入图片描述
并且生成对应的graphviz代码:

digraph my_graph {
        Input [fillcolor=gray70 shape=box style=filled]
        Output [fillcolor=gray70 shape=box style=filled]
        NodeA
        NodeB
        NodeC
        Input -> NodeA [label=0]
        Input -> NodeA [label=1]
        NodeA -> NodeB [label=0]
        NodeA -> NodeC [label=1]
        NodeB -> Output [label=0]
        NodeC -> Output [label=0]
}

环境配置

  • 安装Python中需要使用的graphviz包:
pip install graphviz
  • 安装graphviz工具(可选,如果不安装无法直接使用Python的graphviz包导出图片),例如ubuntu系统安装指令如下,其他系统可参考官方文档https://www.graphviz.org/download/:
sudo apt install graphviz
  • VSCODE安装Graphviz Interactive Preview插件(可选,如果使用vscode开发建议安装此插件,通过此插件可以直接可视化graphviz代码,并保存图片)
    在这里插入图片描述

实现思路

实现一个Node基类,所有的模块实现都继承自该基类。再实现一个Message基类,模块之间传递的数据都继承自该基类。然后在数据传递过程中记录流经的每个模块的名称以及数据的传递方向即可绘制出想要的数据流。


代码实现

下面给出了一个简易的实现方式:

import os
from graphviz import Digraph


__graph_dict__ = {}


class Message:
    def __init__(self, node_name: str, idx: int):
        self.node_name = node_name
        self.idx = idx


class EdgeInfo:
    def __init__(self, start_node_name: str, end_node_name: str, label: str) -> None:
        self.start_node_name = start_node_name
        self.end_node_name = end_node_name
        self.label = label

    def __str__(self):
        return f'{self.start_node_name} -> {self.end_node_name} [label="{self.label}"];'


class Node:
    input_num: int
    output_num: int
    node_name: str

    def __call__(self, *args):
        global __graph_dict__
        assert len(args) == self.input_num

        if self.node_name not in __graph_dict__:
            __graph_dict__[self.node_name] = []

        for input_ in args:
            __graph_dict__[input_.node_name].append(EdgeInfo(input_.node_name,
                                                             self.node_name,
                                                             str(input_.idx)))

        res = tuple(Message(self.node_name, i) for i in range(self.output_num))
        if self.output_num == 1:
            return res[0]
        return res


def export_graphviz(graph, num_input: int, save_path: str):
    base_name = os.path.basename(save_path)
    name, _ = base_name.split(".")
    global __graph_dict__
    __graph_dict__.clear()
    __graph_dict__.update({"Input": [], "Output": []})

    # infer and collect flow info
    input_args = tuple(Message("Input", i) for i in range(num_input))
    outputs = graph(*input_args)
    for ouput_ in outputs:
        if ouput_.node_name not in __graph_dict__:
            __graph_dict__[ouput_.node_name] = []

        __graph_dict__[ouput_.node_name].append(EdgeInfo(ouput_.node_name,
                                                         "Output",
                                                         str(ouput_.idx)))

    # create graph code
    digraph = Digraph(name=name, format="jpg")

    # add nodes
    keys = list(__graph_dict__.keys())
    for k in keys:
        if k in ["Input", "Output"]:
            digraph.node(k, **{"shape": "box", "style": "filled", "fillcolor": "gray70"})
        else:
            digraph.node(k)

    # add edges
    for k in keys:
        for edge_info in __graph_dict__[k]:
            digraph.edge(edge_info.start_node_name,
                         edge_info.end_node_name,
                         edge_info.label)

    # print digraph code
    print(digraph.source)

    # export gv and jpg file
    try:
        digraph.render(directory=os.path.dirname(save_path))
    except Exception as e:
        print(f"export digraph failed, {e}")


class NodeA(Node):
    def __init__(self):
        self.input_num = 2
        self.output_num = 2
        self.node_name = "NodeA"


class NodeB(Node):
    def __init__(self):
        self.input_num = 1
        self.output_num = 1
        self.node_name = "NodeB"


class NodeC(Node):
    def __init__(self):
        self.input_num = 1
        self.output_num = 1
        self.node_name = "NodeC"


class Graph:
    def __init__(self):
        self.node_a = NodeA()
        self.node_b = NodeB()
        self.node_c = NodeC()

    def __call__(self, x0, x1):
        y0, y1 = self.node_a(x0, x1)
        z0 = self.node_b(y0)
        z1 = self.node_c(y1)

        return z0, z1


if __name__ == "__main__":
    graph = Graph()
    export_graphviz(graph, num_input=2, save_path="./my_graph.gv")

执行上述代码后会生成my_graph.gv以及my_graph.gv.jpg两个文件(如果没有安装graphviz工具是不会生成的),其中my_graph.gv是graphviz的代码形式,my_graph.gv.jpg是可视化后的结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/338390.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW扫描探针显微镜系统开发

在纳米技术对高精度材料特性测量的需求日益增长。介绍了基于LabVIEW开发的扫描探针显微镜(SPM)系统。该系统不仅可以高效地测量材料的热物性,还能在纳米尺度上探究热电性质,为材料研究提供了强大的工具。 系统基于扫描探针显微技…

自我摸索:如何运营并玩转CSDN?

自注册CSDN以来已有七年之久,但真正运营CSDN也是最近一年的事情,大概就是22年底,参加2022 博客之星 的竞选。接触了很多大佬,也学习模仿着开始玩转CSDN,虽然没有同期运营的大佬们玩的6,但也有一些经验可以来…

【JavaEE进阶】实现验证码

文章目录 🌲实现说明🍃Kaptcha插件介绍🚩插件原理🚩引入依赖🚩⽣成验证码🚩Kaptcha详细配置 🍀准备⼯作🌴约定前后端交互接⼝🚩需求分析🚩接⼝定义&#x1f6…

【算法练习Day50】下一个更大元素II接雨水

​📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:练题 🎯长路漫漫浩浩,万事皆有期待 文章目录 下一个更大元素II接雨水单调…

Java毕业设计第90期-基于springboot的学习英语管理系统

获取源码资料,请移步从戎源码网:从戎源码网_专业的计算机毕业设计网站 项目介绍 基于springboot的学习英语管理系统:前端 thymeleaf、jquery,后端 maven、springmvc、spring、mybatis,角色分为管理员、用户&#xff…

小程序进阶学习(音乐首页-轮播图)

轮播图 样式 轮播图的重点是轮播图的大小&#xff0c;因为每个手机的屏幕大小不一样&#xff0c;但是轮播图的大小是固定的就需要一些技术获取到手机的轮播图大小&#xff0c;然后再设置图片的大小和轮播图边框的大小。 页面代码 <van-searchvalue"{{ value }}"s…

PID笔记

Improving the Beginner’s PID 参考资料 Improving the Beginner’s PID – Introduction The Beginner’s PID 以下是每个人第一次学习的PID方程&#xff1a; 这导致几乎每个人都编写了以下PID控制器&#xff1a; /*working variables*/ unsigned long lastTime; double…

【c++函数重载】

文章目录 一. 命名空间二 .全缺省参数和半缺省参数三 . 函数重载 一. 命名空间 1.不指定域&#xff1a;先在局部找&#xff0c;再全局。 2. 指定域&#xff1a;到指定的命名空间去找。 3. 当把指定命名空间放开时&#xff0c;即using namespace std&#xff1b;例如放开标准c库…

聊聊Java虚拟机(一)—— 类加载子系统

1. 前言 ​ 虚拟机就是一款用来执行虚拟计算机指令的计算机软件。它相当于一台虚拟计算机。大体上&#xff0c;虚拟机分为系统虚拟机和程序虚拟机。系统虚拟机就相当于一台物理电脑&#xff0c;里面可以安装操作系统&#xff1b;程序虚拟机是为了执行单个计算机程序而设计出来…

imgaug库图像增强指南(32):塑造【雪景】效果的视觉魔法

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…

蓝桥杯练习题(十二)

&#x1f4d1;前言 本文主要是【算法】——蓝桥杯练习题&#xff08;十二&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他…

【蓝桥杯日记】复盘篇一:深入浅出顺序结构

&#x1f680;前言 本期是一篇关于顺序结构的题目的复盘,通过复盘基础知识&#xff0c;进而把基础知识学习牢固&#xff01;通过例题而进行复习基础知识。 &#x1f6a9;目录 前言 1.字符三角形 分析&#xff1a; 知识点&#xff1a; 代码如下 2. 字母转换 题目分析: 知…

加固密码安全:保护您的个人信息

一、引言 在数字化时代&#xff0c;密码安全是保护个人信息和数据的重要环节。然而&#xff0c;许多人在创建和管理密码时存在一些常见的安全漏洞&#xff0c;如使用弱密码、重复使用密码等。本文将详细介绍密码安全的重要性&#xff0c;并提供一些有效的方法和技巧&#xff0…

使用DALL-E 3模型模拟AI女友的一天 |【人人都是算法专家】

Rocky Ding 公众号&#xff1a;WeThinkIn 知乎&#xff1a;Rocky Ding 写在前面 【人人都是算法专家】栏目专注于分享AI行业中业务/竞赛/研究/产品维度的思考与感悟。欢迎大家一起交流学习&#x1f4aa; 大家好&#xff0c;我是Rocky。 我们都知道DALL-E 3是和Stable Diffusio…

Windows ssh登录eNSP交换机

目录 1. Cloud IO配置1.1 创建UDP端口1.2 创建本地连接1.3 端口映射设置 2. 交换机配置2.1 配置vlanif2.2 配置vty2.3 配置ssh用户2.4 配置aaa2.5 使用Xshell工具登录2.6 用户和密码2.7 登录成功 3. 使用cmd 登录报错提示3.1 手动指定加密算法&#xff0c;提示密码长度无效3.2 …

自定义注解与拦截器实现不规范sql拦截(拦截器实现篇)

最近考虑myBatis中sql语句使用规范的问题&#xff0c;如果漏下条件或者写一些不规范语句会对程序性能造成很大影响。最好的方法就是利用代码进行限制&#xff0c;通过拦截器进行sql格式的判断在自测环节就能找到问题。写了个简单情景下的demo&#xff0c;并通过idea插件来将myB…

Twisted Circuit洛谷绿题题解

Twisted Circuit 题面翻译 读入四个整数 0 0 0 或者 1 1 1&#xff0c;作为如图所示的电路图的输入。请输出按照电路图运算后的结果。 感谢PC_DOS 提供的翻译 题目描述 输入格式 The input consists of four lines, each line containing a single digit 0 or 1. 输出格…

编译和链接详解

文章目录 前言翻译环境和运行环境翻译环境和运行环境图解 翻译环境编译预处理&#xff08;预编译&#xff09;阶段编译汇编 链接 运行环境总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 在软件开发的世界中&#xff0c;编译和链接是构建程序的两个…

【GitHub项目推荐-开源的任务管理工具】【转载】

推荐一个开源的任务管理工具&#xff0c;该工具会提供各类文档协作功能、在线思维导图、在线流程图、项目管理、任务分发、即时 IM&#xff0c;文件管理等等。该开源项目使用到 Vue、Element-UI、ECharts 等技术栈。 开源地址&#xff1a;www.github.com/kuaifan/dootask 预览地…

5G_系统同步机制(八)

BBU和RRU的同步机制 为什么要做到系统同步 在TDD模式下工作时&#xff0c;为了避免相邻小区之间的干扰&#xff0c;近距离的所有gNB在任何时间点都必须具有相同的传输方向(DL或UL)。这样做的必要条件是在BTS之间同步SFN (System Frame number)和time Slot。此外&#xff0c;由…