使用Python,maplotlib绘制树型有向层级结构图

news2024/11/15 19:37:07

使用Python,maplotlib绘制树型有向层级结构图

  • 1. 效果图
  • 2. 源码
    • 2.1 plotTree.py绘制层级结构及不同样式
    • 2.2 plotArrow.py 支持的所有箭头样式
  • 参考

前俩篇博客介绍了
1. 使用Python,networkx对卡勒德胡赛尼三部曲之《群山回唱》人物关系图谱绘制
2. 使用Python,networkx绘制有向层级结构图
3. 使用Python,maplotlib绘制树型有向层级结构图 这篇博客是绘制层级结构图三部曲最后一篇。

1. 效果图

按父子层级结构绘制图形,并标记之间的关联关系,并根据不同标签绘制不同颜色箭头(hello的蓝色箭头,bad的红色箭头,默认绿色箭头),效果图如下:
在这里插入图片描述

同样是表达层级结构关系,可以很明显的看出来这比上篇博客使用networkx绘制的层级图要清楚很多,一目了然。
在这里插入图片描述

不同箭头样式:
在这里插入图片描述

支持的所有箭头及箭头弯曲程度样式如下:
在这里插入图片描述

2. 源码

2.1 plotTree.py绘制层级结构及不同样式

# python plotTree.py
# 绘制层级结构图,并根据标签值对树绘制不同颜色


import matplotlib.pyplot as plt

plt.rcParams['backend'] = 'TkAgg'
decisionNode = dict(boxstyle="sawtooth", fc="0.8")
leafNode = dict(boxstyle="round4", fc="0.8")


def getNumLeafs(myTree):
    numLeafs = 0
    firstStr = list(myTree.keys())[0]
    secondDict = myTree[firstStr]
    for key in secondDict.keys():
        if type(secondDict[
                    key]).__name__ == 'dict':  # test to see if the nodes are dictonaires, if not they are leaf nodes
            numLeafs += getNumLeafs(secondDict[key])
        else:
            numLeafs += 1
    return numLeafs


def getTreeDepth(myTree):
    maxDepth = 0
    firstStr = list(myTree.keys())[0]
    secondDict = myTree[firstStr]
    for key in secondDict.keys():
        if type(secondDict[
                    key]).__name__ == 'dict':  # test to see if the nodes are dictonaires, if not they are leaf nodes
            thisDepth = 1 + getTreeDepth(secondDict[key])
        else:
            thisDepth = 1
        if thisDepth > maxDepth: maxDepth = thisDepth
    return maxDepth


def plotNode(nodeTxt, centerPt, parentPt, nodeType, color):
    # 分别表示箭头的样式,俩边距离边框的值,以及箭头线的弯曲程度,箭头的颜色
    arrow_args = dict(arrowstyle="<-", shrinkA=10, shrinkB=10, patchA=None, patchB=None, connectionstyle="arc3,rad=0.3",
                      color=color)
    arrow_args = dict(arrowstyle="<-", shrinkA=10, shrinkB=10, patchA=None, patchB=None, connectionstyle="arc3, rad = 0.",
                      color=color)
    createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction',
                            xytext=centerPt, textcoords='axes fraction',
                            va="center", ha="center", bbox=nodeType, arrowprops=arrow_args)


def plotMidText(cntrPt, parentPt, txtString):
    xMid = (parentPt[0] - cntrPt[0]) / 2.0 + cntrPt[0]
    yMid = (parentPt[1] - cntrPt[1]) / 2.0 + cntrPt[1]
    createPlot.ax1.text(xMid, yMid, txtString, va="center", ha="center", rotation=30)


def getArrowColors(parentNode, firstStr, edgeDict):
    key = parentNode + '->' + firstStr
    if not edgeDict.__contains__(key):
        color = 'black'
    elif edgeDict[key].__contains__('hello'):
        color = 'blue'
    elif edgeDict[key].__contains__('bad'):
        color = 'red'
    else:
        color = 'green'
    return color


def getArrowAttrTxt(parentNode, firstStr, edgeDict):
    key = parentNode + '->' + firstStr
    if not edgeDict.__contains__(key):
        return ''
    return edgeDict[key]


def plotTree(myTree, parentPt, parentNode, nodeTxt):
    numLeafs = getNumLeafs(myTree)
    depth = getTreeDepth(myTree)
    firstStr = list(myTree.keys())[0]
    cntrPt = (plotTree.xOff + (1.0 + float(numLeafs)) / 2.0 / plotTree.totalW, plotTree.yOff)
    plotMidText(cntrPt, parentPt, getArrowAttrTxt(parentNode, firstStr, edgeDict))
    plotNode(firstStr, cntrPt, parentPt, decisionNode, getArrowColors(parentNode, firstStr, edgeDict))
    secondDict = myTree[firstStr]
    plotTree.yOff = plotTree.yOff - 1.0 / plotTree.totalD
    for key in secondDict.keys():
        if type(secondDict[key]).__name__ == 'dict':
            print("++++++++++++: ", key, firstStr)
            plotTree(secondDict[key], cntrPt, firstStr, str(key))  # recursion
        else:
            print('----: ', secondDict[key], firstStr, key)
            plotTree.xOff = plotTree.xOff + 1.0 / plotTree.totalW
            plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode,
                     getArrowColors(firstStr, secondDict[key], edgeDict))
            plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, getArrowAttrTxt(firstStr, secondDict[key], edgeDict))
    plotTree.yOff = plotTree.yOff + 1.0 / plotTree.totalD


def createPlot(inTree):
    fig = plt.figure(1, facecolor='white')
    fig.clf()
    axprops = dict(xticks=[], yticks=[])
    createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)  # no ticks
    # createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses
    plotTree.totalW = float(getNumLeafs(inTree))
    plotTree.totalD = float(getTreeDepth(inTree))
    plotTree.xOff = -0.5 / plotTree.totalW;
    plotTree.yOff = 1.0;
    plotTree(inTree, (0.5, 1.0), 'A', '')
    plt.show()


def retrieveTree(i):
    listOfTrees = [{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}},
                   {'no surfacing': {0: 'no', 1: {'flippers': {0: {'head': {0: 'no', 1: 'yes'}}, 1: 'no'}}}}
                   ]
    return listOfTrees[i]


def getTree(treeDict, nood):
    retrieveTree = {}
    for i, val in enumerate(treeDict[nood]):
        print(i, nood, val)
        if (treeDict.__contains__(val)):
            subTree = {}
            subTree[val] = getTree(treeDict, val)
            retrieveTree[i] = subTree
        else:
            retrieveTree[i] = val
    return retrieveTree


def getRetrieveTree():
    treeDict = {}
    edgeDict = {}
    with open("res/tree.txt", 'r', encoding='utf-8', errors='ignore') as f:
        data = f.readlines()

        for i, line in enumerate(data):
            parentNode = line.split(",")[0]
            childNode = line.split(",")[1]
            edgeDict[parentNode + "->" + childNode] = line.split(",")[2]
            # print(parentNode, childNode)
            if not treeDict.__contains__(parentNode):
                treeDict[parentNode] = set()
            treeDict[parentNode].add(childNode)

    print(treeDict)
    treeDict0 = {}
    treeDict0['A'] = getTree(treeDict, 'A')

    # print(treeDict0)
    return (treeDict0, edgeDict)


# treeDemo = retrieveTree(1)
# print(treeDemo)
# createPlot(treeDemo)
(treeDict, edgeDict) = getRetrieveTree()
print(treeDict)
createPlot(treeDict)

2.2 plotArrow.py 支持的所有箭头样式

# python plotArrow.py
from matplotlib import pyplot as plt

print(plt.rcParams['backend'])  # module://backend_interagg
plt.rcParams['backend'] = 'TkAgg'


def demo_con_style(ax, connectionstyle):
    x1, y1 = 0.3, 0.2
    x2, y2 = 0.8, 0.6

    ax.plot([x1, x2], [y1, y2], ".")
    ax.annotate("", xy=(x1, y1), xycoords='data',
                xytext=(x2, y2), textcoords='data',
                arrowprops=dict(arrowstyle="->", color="0.5",
                                shrinkA=5, shrinkB=5,
                                patchA=None, patchB=None,
                                connectionstyle=connectionstyle,
                                ),
                )

    ax.text(.05, .95, connectionstyle.replace(",", ",\n"),
            transform=ax.transAxes, ha="left", va="top")


fig, axs = plt.subplots(3, 5, figsize=(8, 4.8))
demo_con_style(axs[0, 0], "angle3, angleA = 90, angleB = 0")
demo_con_style(axs[1, 0], "angle3, angleA = 0, angleB = 90")
demo_con_style(axs[0, 1], "arc3, rad = 0.")
demo_con_style(axs[1, 1], "arc3, rad = 0.3")
demo_con_style(axs[2, 1], "arc3, rad = -0.3")
demo_con_style(axs[0, 2], "angle, angleA = -90, angleB = 180, rad = 0")
demo_con_style(axs[1, 2], "angle, angleA = -90, angleB = 180, rad = 5")
demo_con_style(axs[2, 2], "angle, angleA = -90, angleB = 10, rad = 5")
demo_con_style(axs[0, 3], "arc, angleA = -90, angleB = 0, armA = 30, armB = 30, rad = 0")
demo_con_style(axs[1, 3], "arc, angleA = -90, angleB = 0, armA = 30, armB = 30, rad = 5")
demo_con_style(axs[2, 3], "arc, angleA = -90, angleB = 0, armA = 0, armB = 40, rad = 0")
demo_con_style(axs[0, 4], "bar, fraction = 0.3")
demo_con_style(axs[1, 4], "bar, fraction = -0.3")
demo_con_style(axs[2, 4], "bar, angle = 180, fraction = -0.2")

for ax in axs.flat:
    ax.set(xlim=(0, 1), ylim=(0, 1), xticks=[], yticks=[], aspect=1)
fig.tight_layout(pad=0.2)

plt.show()

参考

  • https://blog.csdn.net/weixin_42915773/article/details/111566041
  • https://blog.csdn.net/TQCAI666/article/details/103689182

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

江科大stm32学习笔记——【5-2】对射式红外传感器计次旋转编码计次

一.对射式红外传感器计次 1.原理 2.硬件连接 3.程序 CountSensor.c: #include "stm32f10x.h" // Device header #include "Delay.h"uint16_t CountSensor_Count;void CountSensor_Init(void) {//配置RCC时钟&#xff1a;RCC_APB2Perip…

房贷计算器微信小程序原生语言

微信小程序: 房贷计算器 效果: 输入 300万 结果 还款明细 一共有3个页面 1、输入页面 2、结果页面 3、详情页面 1 index页面 index.wxml文件 <view class="text-black"><!--房屋总价--><view class="cu-bar bg-white solid-bottom"&…

Redis--事务机制的详解及应用

Redis事务的概念&#xff1a; Redis事务就是将一系列命令包装成一个队列&#xff0c;在执行时候按照添加的顺序依次执行&#xff0c;中间不会被打断或者干扰&#xff0c;在执行事务中&#xff0c;其他客户端提交的命令不可以插入到执行事务的队列中&#xff0c;简单来说Redis事…

Vue之监测数据的原理(对象)

大家有没有想过&#xff0c;为什么vue可以监测到数据发生改变&#xff1f;其实底层借助了Object.defineProperty&#xff0c;底层有一个Observer的构造函数 让我为大家简单的介绍一下吧&#xff01; 我用对象为大家演示一下 const vm new Vue({el: "#app",data: {ob…

Harbor 的安装及使用

Harbor 安装官网手册&#xff1a; https://goharbor.io/docs/2.10.0/install-config/download-installer/ Harbor 发布包地址&#xff1a; https://github.com/goharbor/harbor/releases 在部署harbor的前提下先安装docker 和 docker-compose 安装docker&#xff1a;https://d…

Opencv基础与学习路线

Opencv Opencv每一篇目具体&#xff1a; Opencv(1)读取与图像操作 Opencv(2)绘图与图像操作 Opencv(3)详解霍夫变换 Opencv(4)详解轮廓 Opencv(5)平滑处理 具体Opencv相关demo代码欢迎访问我的github仓库&#xff08;包含python和c代码&#xff09; demo代码 文章目录 Opencv一…

<专利>机器人3D视觉快速定位抓取方法及系统

摘要&#xff0c;此专利无可用的关键技术信息&#xff0c;基本都是下面几句话反复说。。。 本发明提供了一种机器人3D快速定位抓取方法及系统&#xff0c; 包括&#xff1a; 通过高速的3D结构光成像对目标物体的表面轮廓进行扫描&#xff0c; 形成点云数据&#xff1b;对所述点…

idea 手动打 jar 包

1.在 File 中找到并点击 Project Structure 2.按图中高亮的部分依次点击 3.在 Main Class 处设置要打包的类&#xff0c;记得在 Directory for ... 处设置目录为根目录&#xff0c;设置好以后点击两次 OK 回到首页 4.在页面上方找到 Build &#xff0c;点击 Build Artifacts...…

蓝桥杯练习系统(算法训练)ALGO-993 RP大冒险

资源限制 内存限制&#xff1a;64.0MB C/C时间限制&#xff1a;200ms Java时间限制&#xff1a;600ms Python时间限制&#xff1a;1.0s 问题描述 请尽情使用各种各样的函数来测试你的RP吧~~~ 输入格式 一个数N表示测点编号。 输出格式 一个0~9的数。 样例输入 0 样…

基于React全栈Sora AI视频案例展示项目

花了一天时间基于React Next全栈开发的Sora AI 演示项目 Preview: https://sora.langchat.cn/ Github&#xff1a;https://github.com/tycoding/lang-sora 欢迎大家star、fork呀&#xff01; 这是一套完整的React & Next.js项目&#xff0c;包含前后端交互、路由、数据库…

Android14之解决编译报错:bazel: no such file or directory(一百八十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

企业微信变更主体怎么改?

企业微信变更主体有什么作用&#xff1f;做过企业运营的小伙伴都知道&#xff0c;很多时候经常会遇到现有的企业需要注销&#xff0c;切换成新的企业进行经营的情况&#xff0c;但是原来企业申请的企业微信上面却积累了很多客户&#xff0c;肯定不能直接丢弃&#xff0c;所以这…

靶机渗透之sar

Name: Sar: 1Date release: 15 Feb 2020Author: LoveSeries: Sar Download: https://drive.google.com/open?id1AFAmM21AwiAEiVFUA0cSr_GeAYaxd3lQ 对于vulnhub中的靶机&#xff0c;我们都需先下载镜像&#xff0c;然后导入VM&#xff0c;并将网络连接改为NAT模式。首先我们…

uniapp实战:父子组件对象数组传参

需求说明 1.父组件传参给子组件 1.1子组件中定义属性unitList 1.2 父组件中将data中的unitList传递给子组件 2.子组件向父组件传参 2.1子组件设置用户名文本框以及切换操作属性 2.2 子组件对应操作(文本输入以及按钮切换)添加自…

【学习笔记】深度学习实战 | LeNet

简要声明 学习相关网址 [双语字幕]吴恩达深度学习deeplearning.aiPapers With CodeDatasets 深度学习网络基于PyTorch学习架构&#xff0c;代码测试可跑。本学习笔记单纯是为了能对学到的内容有更深入的理解&#xff0c;如果有错误的地方&#xff0c;恳请包容和指正。 参考文献…

C# 获取类型 Type.GetType()

背景 C#是强类型语言&#xff0c;任何对象都有Type&#xff0c;有时候需要使用Type来进行反射、序列化、筛选等&#xff0c;获取Type有Type.GetType, typeof()&#xff0c;object.GetType() 等方法&#xff0c;本文重点介绍Type.GetType()。 系统类型/本程序集内的类型 对于系…

C++——模板详解

目录 模板 函数模板 显示实例化 类模板 模板特点 模板 模板&#xff0c;就是把一个本来只能对特定类型实现的代码&#xff0c;变成一个模板类型&#xff0c;这个模板类型能转换为任何内置类型&#xff0c;从而让程序员只需要实现一个模板&#xff0c;就能对不同的数据进行操…

2024年 前端JavaScript Web APIs 第二天 笔记

Web APIs 第二天 2.1 -事件监听以及案例 2.2 -随机点名案例 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><t…

Git分布式版本控制系统——git学习准备工作

一、Git仓库介绍 开发者可以通过Git仓库来存储和管理文件代码&#xff0c;Git仓库分为两种&#xff1a; 本地仓库&#xff1a;开发人员自己电脑上的Git仓库 远程仓库&#xff1a;远程服务器上的Git仓库 仓库之间的运转如下图&#xff1a; commit&#xff1a;提交&#xff…

Pytorch 复习总结 4

Pytorch 复习总结&#xff0c;仅供笔者使用&#xff0c;参考教材&#xff1a; 《动手学深度学习》Stanford University: Practical Machine Learning 本文主要内容为&#xff1a;Pytorch 深度学习计算。 本文先介绍了深度学习中自定义层和块的方法&#xff0c;然后介绍了一些…