热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

递归树的显示

目标:显示每层节点数不定的递归树,不同的类别用不同的颜色表示所用python库:matplotlib1.初始化窗口步骤:

目标:显示每层节点数不定的递归树,不同的类别用不同的颜色表示

所用python库:matplotlib


1. 初始化窗口 

步骤:


  • 计算所需画面大小,包括图幅高度height 和图幅宽度width。图幅宽度主要取决于叶子节点数目。a. 首先需要计算叶子节点的数目,b. 然后需要定义node的半径radius和同一层级两个node之间的距离nodeInterval,本次设置nodeInterval为radius的n倍,n可以自己给定。最后图幅所需要的宽度width=(treeWidth + 1) * nodeInterval。默认使用正方形画布,则height = width。最后用计算出来的height, width设置画布x轴和y轴的范围。
  • 计算层间距disVec。首先计算树的深度maxDeepth,然后用图幅高度height除以树的深度即可得出每层之间的纵向距离,即disVec = height/(maxDeepth+1);
  • 最后计算root的xy坐标:xStart, yStart。root 位于图幅正中心,距离页面顶部一个 disVec 距离。 
  • 函数返回值:返回根节点坐标、node的半径radius 和 树的纵向深度间隔disVec(用于递归画下一层节点)。因为是递归构建,所以当前子树也就是当前父节点一直在变化,所以需要事先计算好根节点,作为递归的传入参数。

def creatWindow(self, radius = 300):'''———————— O ————————————O———— ————O————-O--O--O- -O--O--O- radius = 2 #节点的半径nodeInterval = 4 * radius #定义为两个节点之间的距离,即--'''#定义节点间距n = 1nodeInterval = n * radius# 定义图幅长宽,默认为正方形图幅,height=widthtree = self.treetreeWidth = self.getNumLeafs(tree)treeDepth = self.getMaxDepth(tree)width = (treeWidth + 1) * nodeIntervalheight = widthaspect = height/widthfig = plt.figure(figsize=(11, 11*aspect))plt.xlim(0, width)plt.ylim(0, height)#定义层间距disVec = height/(treeDepth+1)#给定根节点坐标xStart = int(width/2)yStart = height - disVec return fig, xStart, yStart, radius, width, disVec

重点:计算树的宽度和深度。


  • 计算树的宽度:只要存在children,就进入下一层,直到遇到叶子节点. 每遇到一个叶子节点计数就加1,即numLeafs +=1. 遍历完整棵树之后,numLeafs就是树的宽度。

def getNumLeafs(self, tree):numLeafs = 0children = tree.childrennumChildren = len(children)if numChildren > 0:for childNode in children:branchNumLeafs = self.getNumLeafs(childNode)numLeafs += branchNumLeafselse:numLeafs += 1return numLeafs

  • 计算树的深度:只要存在children,就进入一下层,同时深度值加1,即:深度 = 1 + 子树深度。当遇到叶子节点是,返回深度值1。同一个parent下面的每个child, 遍历计算深度后,只取他们中最大的深度值。

def getMaxDepth(self, tree):''' 如果只有根节点,最大深度为1;如果有子节点,maxDepth = 1 + getHeight(child), 1 为根节点自身深度遍历所有子节点,取最深的那个深度'''maxDepth = 0children = tree.childrennumChildren = len(children)if numChildren > 0:for childNode in children:branchDepth = 1 + self.getMaxDepth(childNode)if branchDepth > maxDepth:maxDepth = branchDepthelse:maxDepth = 1return maxDepth

2. 画递归树

思路:

        整个递归树包含 节点 和 边 两类。当我们把每个节点看作一棵小树,一颗只包含边的小树。这个问题就简化为如何画出一个节点及其存在可能的边。依然是递归的方法。

过程:


  • 画当前节点;
  • 判断当前是否存在children,如果存在就画边,负责就是叶子节点,不画边。
  • 更新节点,直到叶节点。

难点:确定子节点位置坐标。

'''

                          O

                 O               O

           -O--O--O-   -O--O--O- 

'''

如上红色父节点存在三个子节点,每个节点占据父节点空间的1/3, 即:

childWidth = parentWidth/numChildren,则它们x轴坐标分别为:

childWidth *(0+1/2);

childWidth *(1 + 1/2),;

childWidth *(2+1/2)。

因此可以得出,子节点位置坐标为childWidth *(i+1/2) =parentWidth/i * *(i+1/2) , i为子节点个数。

对于左子树,按照上述计算即可。但是对于右子树,要根据父节点的左侧范围计算坐标,上述例子右侧节点的左侧范围为图幅的1/2处,所以子节点的坐标为:parentWidth *1 + childWidth *(i+1/2).

最后综合左、右子树,最终的子节点的坐标计算公式为:parentWidth * j + parentWidth / i*(i+1/2)。其中,j为上一层父节点的编号, i为子节点个数。

画递归树的函数draw 一定要单独写一个函数,因为当前节点一直在变。

def draw(self, tree, xStart, yStart, radius, width, disVec, j=0):#先画当前节点 self.drawNode(tree, xStart, yStart, radius)#如果有子节点,递归画子节点children = tree.childrennumChildren = len(children) if numChildren > 0: childBrachWidth = width/numChildrenfor i, childNode in enumerate(children):xEnd = width * j + childBrachWidth * (i + 0.5)yEnd = yStart - disVecself.drawEdge(xStart, yStart, xEnd,yEnd)self.draw(childNode, xEnd, yEnd, radius, childBrachWidth, disVec, i)def drawNode(self, node, x, y, radius=20):name = node.data.componentNamecolor = self.colors[node.data.label]plt.scatter(x,y,s = radius, c=color, edgecolors=color, marker="o")plt.text(x-radius/3, y-radius, name, fontsize=13)def drawEdge(self, xStart, yStart, xEnd, yEnd):x = (xStart, xEnd)y = (yStart, yEnd)plt.plot(x,y,'g-')

3. 最后将上述函数整理到show_Tree类中,并用showTree函数调用


class show_Tree:def __init__(self, tree, colors = None):self.tree = treeself.colors = colors def showTree(self):tree = self.tree#1. 构建窗口_, xStart, yStart, radius, width, disVec = self.creatWindow()#2. 画树self.draw(tree, xStart, yStart, radius, width, disVec)#3. 保存即显示f = plt.gcf()plt.legend()#窗口最大化再保存比较清楚plt.show()f.savefig('splitTree.png')plt.close()def get_colour_name(requested_colour):try:closest_name = actual_name = webcolors.rgb_to_name(requested_colour)except ValueError:closest_name = closest_colour(requested_colour)actual_name = Nonereturn actual_name, closest_namedef randomColor(labels):num = len(labels)colors = [colorsys.hsv_to_rgb(i/num, 1, 1) for i in range(num)]colors = [(int(c[0]) *255, int(c[1]) *255, int(c[2]) *255) for c in colors]return colorslabels = []#### the category of component
colors = randomColor(labels)
colorDict = {key:get_colour_name(value)[0] for key,value in zip(labels, colors)}
p = show_Tree(tree, colorDict)
p.showTree()

 结果展示:

          

    


推荐阅读
  • 20210304力扣 根据前序遍历和中序遍历确定二叉树 快速排序思想
    力扣根据前序遍历和中序遍历确定二叉树基本思路前序遍历确定根节点是哪个(第一个就是根节点)中序遍历根据已知根节点确定左右子树的元素组成根节点左左子树根节点右右子树再根据前序遍历确定左 ... [详细]
  • vue使用
    关键词: ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了游标的使用方法,并以一个水果供应商数据库为例进行了说明。首先创建了一个名为fruits的表,包含了水果的id、供应商id、名称和价格等字段。然后使用游标查询了水果的名称和价格,并将结果输出。最后对游标进行了关闭操作。通过本文可以了解到游标在数据库操作中的应用。 ... [详细]
  • 本文讨论了如何使用IF函数从基于有限输入列表的有限输出列表中获取输出,并提出了是否有更快/更有效的执行代码的方法。作者希望了解是否有办法缩短代码,并从自我开发的角度来看是否有更好的方法。提供的代码可以按原样工作,但作者想知道是否有更好的方法来执行这样的任务。 ... [详细]
  • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
    文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • EzPP 0.2发布,新增YAML布局渲染功能
    EzPP发布了0.2.1版本,新增了YAML布局渲染功能,可以将YAML文件渲染为图片,并且可以复用YAML作为模版,通过传递不同参数生成不同的图片。这个功能可以用于绘制Logo、封面或其他图片,让用户不需要安装或卸载Photoshop。文章还提供了一个入门例子,介绍了使用ezpp的基本渲染方法,以及如何使用canvas、text类元素、自定义字体等。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • 花瓣|目标值_Compose 动画边学边做夏日彩虹
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Compose动画边学边做-夏日彩虹相关的知识,希望对你有一定的参考价值。引言Comp ... [详细]
  • 颜色迁移(reinhard VS welsh)
    不要谈什么天分,运气,你需要的是一个截稿日,以及一个不交稿就能打爆你狗头的人,然后你就会被自己的才华吓到。------ ... [详细]
  • Opencv提供了几种分类器,例程里通过字符识别来进行说明的1、支持向量机(SVM):给定训练样本,支持向量机建立一个超平面作为决策平面,使得正例和反例之间的隔离边缘被最大化。函数原型:训练原型cv ... [详细]
  • 资源总是有限的,程序运行如果对同一个对象进行操作,则有可能造成资源的争用,甚至导致死锁也可能导致读写混乱锁提供如下方法: ... [详细]
  • 记录一些 Latex 的技巧
    Latex一些技巧:1.如何创建不浮动的的figure和table\makeatletter\newcommand{\figcaption}{\def\captyp ... [详细]
  • Highcharts翻译系列之二十:曲线图例子(二)
    Highcharts翻译系列之二十:曲线图例子(二)代码 ... [详细]
author-avatar
手机用户2602906647
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有