Python Tree库绘制多叉树的用法介绍
Tree 库是一个 Python 的第三方库。这个库主要用于生成树和绘制树的图形。
一、安装Tree
使用 Tree 库需要配合 PIL 库来实现绘图。
二、官方案例
先看一下 PyPI 里 Tree 库提供的 demo 。PyPI地址:https://pypi.org/project/Tree/
运行结果:
运行代码,生成了一棵三叉树,然后用 PIL 将这棵树展示成了一张图片。接下来介绍 Tree 库的用法。
三、Tree库介绍
Tree 库分为三个部分,core.py,utils.py和draw.py。
utils.py中实现了节点类Node和颜色转换函数。
draw.py中实现了绘制图形的类Drawer。
core.py中实现了生成树的类Tree和生成分支的函数。
三个部分是耦合的,使用时不需要直接调用utils.py和draw.py中的类和函数,直接使用core.py中的Tree类就行了。
在 Tree 库中,多处使用到了Python标准库 math 和第三方库 PIL。不仅如此,当我们调用 Tree 库时,也需要借助 math 库和 PIL 库来生成树的图片。
四、Tree库的使用
实例化一个Tree类的对象,即可生成一棵树。在初始化一棵树时,有3个参数,pos,branches和sigma。
pos是一个长度为4的元组(列表也可以),分别表示树的起始点和结束点的横纵像素坐标(x0, y0, x1, y1),源码中会根据这两个坐标用勾股定理计算出树的长度(在树没有生长时只有树干),起始点和结束点的位置关系会决定树的生长方向,可以通过坐标的正负值来调整。如果传入的元组长度小于4会报索引越界(找不到足够的数据),如果元组长度大于4则取前4个值,多的数据无效。
branches是一个列表或元组,列表中有多少个值,树生长时就有多少个分支。每一个分支的参数也是一个列表或元组,参数中需要两个数据,第一个表示树枝相对于父枝干的长度变化系数(一般小于1,树枝比树干短),第二个表示树枝相对于父枝干的偏移角度,角度是弧度制(数字角度可以用math库中的radians转换)。在初始化一棵树时,branches如果不传值默认是None,这样源码中计算分支时会报错,如果branches传一个空列表,则使用PIL展示树时会因无法扩展而报错,所以必须传入非空的branches参数。
sigma是一个元组(列表也可以,不过会提示不符合PEP规范),元组中有两个值,第一个用于调整分支的长度,第二个用于调整分支的角度(乘math中的pi)。使用sigma参数不易控制预期效果,所以保持默认的(0, 0)即可,一般不传值。
grow(times=1): 用于使树生长,默认生长1次,即在树干的基础上生长一次,最后一次是树叶,其他的是枝干。虽然默认生长1次,但在后面调用draw_on()方法绘图时,会有除0报错,所以最小需要生长两次,传值应该大于等于2。
age属性表示树的年龄,树grow()了多少次,age就是多少。
move_in_rectangle(): 用于移动树的位置,使树的位置自适应画布(自动将图片移动到画布中心),是一个辅助绘图的方法。
get_size(): 用于获取树的尺寸,返回结果是一个元组,分别表示树的宽和高(width, height)。
使用PIL中的new()函数创建一块画布,用于绘图,有三个参数。第一个参数表示图片的模式,使用“RGB”(red,green,blue三原色的缩写,表示真彩色图像)即可。第二个参数表示画布的大小(按像素计算),因为树从树干生长后,尺寸会变化,所以使用get_size()动态获取当前树的尺寸。第三个参数表示画布的颜色,默认值为0,黑色画布,可以根据需要修改。
draw_on(canvas, stem_color, leaf_color, thickness, ages=None): 将树的结构绘制到画布上,需要4个参数。
canvas, 画布。传入使用PIL库new()出来的画布(也可以使用其他绘图的库)。
stem_color, 表示树干的颜色和枝干的颜色变换梯度。传入一个元组(RGB颜色可以用长度为3的元组表示),如果传入的元组长度为3,则所有枝干的颜色一样,没有渐变,如果传入的元组长度为6,则会根据枝干的年龄age来进行颜色渐变(参考draw.py中的_get_color(age)源码),元组的长度小于6且不为3会报索引越界,长度大于6则后面的数据无效。
leaf_color, 树叶的颜色。传入一个长度为3的元组,长度小于3会报传参错误,大于3则后面的数据无效,这里也可以传入一个16进制的颜色编码。
thickness, 树干的粗细。传入一个整数,值越大,树干越粗。
基本的方法和属性介绍完了,现在看一个简单的例子。
运行结果:
五、Tree库的其他方法介绍
运行结果:
length属性表示树干的长度。
get_branch_length(): 返回指定年龄的枝干长度,不指定年龄则返回树叶的长度。指定的年龄可以无限大(会根据变化系数推导结果)。
get_rectangle(): 树经过多次生长后,返回树占用的矩形坐标。
运行结果:
get_node_sum(): 返回从树干到指定年龄的节点总数,不指定年龄则返回当前树的节点数。指定的年龄可以无限大(会根据分支数推导结果)。
nodes属性表示当前树中的所有节点对象,每个年龄的节点构成一个列表。
get_nodes(): 返回当前树中的所有节点坐标,每个年龄的节点构成一个列表。
get_branches(): 返回当前树中的所有枝干坐标,坐标的格式为(x0, y0, x1, y1),每个年龄的枝干构成一个列表。此方法与branches属性没有关系,branches的值是初始化时传入的参数。
move(delta): 移动树,传入一个delta参数,参数格式与pos相同(x0, y0, x1, y1),四个坐标值按delta的值进行平移。
六、Tree库的灵活使用
1. 画一棵好看一点的树
运行结果:
2. 不受限于树,也可以绘制其他图形
运行结果:
树的生长和绘图很耗内存,树生长的次数较大的话,内存就不够了。