Introduction to the usage of Python Tree library to draw multi-fork trees

Introduction to the usage of Python Tree library to draw multi-fork trees

The Tree library is a third-party library for Python. This library is mainly used to generate trees and draw tree graphics.

One, install Tree

pip install Tree

To use the Tree library, you need to cooperate with the PIL library to achieve drawing.

2. Official case

Let's take a look at the demo provided by the Tree library in PyPI. PyPI address: https://pypi.org/project/Tree/

# coding=utf-8
from Tree.core import Tree
from math import radians as rad
from PIL import Image


def main():
    branches = ((.5, rad(-30)), (.6, rad(30)), (.4, rad(60)))
    tree = Tree(pos=(0, 0, 0, -500), branches=branches)
    tree.grow(10)
    tree.move_in_rectangle()
    im = Image.new("RGB", tree.get_size(), (239, 239, 239))
    tree.draw_on(im, (85, 25, 0, 128, 53, 21), (0, 62, 21), 10)
    im.show()


if __name__ == '__main__':
    main()

operation result:

Run the code to generate a trigeminal tree, and then use PIL to display the tree as a picture. Next, introduce the usage of the Tree library.

Three, tree library introduction

The Tree library is divided into three parts, core.py, utils.py and draw.py.

The node class Node and color conversion function are implemented in utils.py.

The class Drawer for drawing graphics is implemented in draw.py.

In core.py, the tree-like tree and the branch-generating function are implemented in core.py.

The three parts are coupled. You don't need to directly call the classes and functions in utils.py and draw.py when you use them, just use the Tree class in core.py directly.

from Tree.core import Tree

In the Tree library, the Python standard library math and the third-party library PIL are used in many places. Not only that, when we call the Tree library, we also need to use the math library and the PIL library to generate a picture of the tree.

For the use of math library, please refer to: https://blog.csdn.net/weixin_43790276/article/details/98476264

For the use of PIL library, please refer to: https://blog.csdn.net/weixin_43790276/article/details/108478270

Fourth, the use of the Tree library

Instantiate an object of the Tree class to generate a tree. When initializing a tree, there are 3 parameters, pos, branches and sigma.

pos is a tuple of length 4 (a list is also possible), representing the horizontal and vertical pixel coordinates (x0, y0, x1, y1) of the starting point and ending point of the tree. The source code will use Pythagorean based on these two coordinates. The theorem calculates the length of the tree (only the trunk when the tree is not growing). The positional relationship between the starting point and the ending point will determine the growth direction of the tree, which can be adjusted by the positive and negative values ​​of the coordinates. If the length of the incoming tuple is less than 4, the index will be reported out of bounds (not enough data can be found). If the length of the tuple is greater than 4, the first 4 values ​​will be taken, and more data will be invalid.

Branches is a list or tuple. As many values ​​as there are in the list, there will be as many branches as the tree grows. The parameter of each branch is also a list or tuple. Two data are required in the parameters. The first represents the length change coefficient of the branch relative to the parent branch (generally less than 1, and the branch is shorter than the trunk), and the second represents the relative branch. The offset angle of the parent branch, the angle is in radians (the digital angle can be converted with the radians in the math library). When initializing a tree, if the value of branches is not passed, the default is None, so that an error will be reported when calculating branches in the source code. If an empty list is passed in the source code, an error will be reported when using PIL to display the tree because it cannot be expanded, so it must be passed in. Empty branches parameter.

sigma is a tuple (a list is also possible, but it will prompt that it does not conform to the PEP specification). There are two values ​​in the tuple, the first is used to adjust the length of the branch, and the second is used to adjust the angle of the branch (multiply the math Pi). It is not easy to control the expected effect using the sigma parameter, so keep the default (0, 0), and generally do not pass the value.

grow(times=1): Used to grow the tree, the default is to grow once, that is, grow once on the basis of the trunk, the last time is the leaves, and the others are the branches. Although it grows once by default, when the draw_on() method is called later, there will be a division by 0 error, so the minimum need to grow twice, the value should be greater than or equal to 2.

The age attribute represents the age of the tree. The age is the number of times the tree has grown().

move_in_rectangle(): Used to move the position of the tree, make the position of the tree adaptive to the canvas (automatically move the picture to the center of the canvas), which is a method of assisting drawing.

get_size(): used to get the size of the tree, the return result is a tuple representing the width and height (width, height) of the tree respectively.

Use the new() function in PIL to create a canvas for drawing, with three parameters. The first parameter indicates the mode of the picture, using "RGB" (abbreviation for the three primary colors of red, green, and blue, representing true color images). The second parameter represents the size of the canvas (calculated in pixels), because the size of the tree will change after it grows from the trunk, so use get_size() to dynamically get the size of the current tree. The third parameter represents the color of the canvas, the default value is 0, and the black canvas can be modified as needed.

draw_on(canvas, stem_color, leaf_color, thickness, ages=None): To draw the structure of the tree onto the canvas, 4 parameters are required.

canvas, canvas. Pass in the canvas that uses the PIL library new() (other drawing libraries can also be used).

stem_color, represents the color of the trunk and the color change gradient of the branches. Pass in a tuple (RGB color can be represented by a tuple of length 3). If the length of the incoming tuple is 3, then all branches will have the same color and no gradient. If the length of the incoming tuple is 6, The color gradient will be performed according to the age of the branch (refer to the _get_color(age) source code in draw.py). If the length of the tuple is less than 6 and not 3, it will report that the index is out of range. If the length is greater than 6, the following data will be invalid .

leaf_color, the color of the leaves. Pass in a tuple with a length of 3. If the length is less than 3, a parameter transmission error will be reported. If the length is greater than 3, the following data will be invalid. Here you can also pass in a hexadecimal color code.

thickness, the thickness of the trunk. Pass in an integer, the larger the value, the thicker the trunk.

Now that the basic methods and properties are introduced, let's look at a simple example.

# coding=utf-8
from Tree.core import Tree
from math import radians
from PIL import Image


pos = [0, 0, 0, -300]
branches = [[0.58, radians(-45)], [0.58, radians(45)]]
tree = Tree(pos=pos, branches=branches)
tree.grow(5)
print('tree age is: ', tree.age)
tree.move_in_rectangle()
image = Image.new("RGB", tree.get_size(), 0)
tree.draw_on(image, (80, 20, 10, 120, 60, 30), '#003E15', 15)
image.show()

operation result:

tree age is:  5

V. Introduction to other methods of the Tree library

print('树干长度:', tree.length)
print('树叶长度:', tree.get_branch_length())
print(tree.get_branch_length(age=1))
print(tree.get_rectangle())

operation result:

树干长度: 300.0
树叶长度: 19.690703039999992
174.0
(0.0, 0.0, 626.4380061192694, 613.2190030596347)

The length attribute indicates the length of the tree trunk.

get_branch_length(): Returns the length of the branch at the specified age, or the length of the leaf if the age is not specified. The specified age can be infinite (the result will be derived based on the coefficient of change).

get_rectangle(): After the tree grows many times, it returns the coordinates of the rectangle occupied by the tree.

print('树的节点数:', tree.get_node_sum())
print(tree.get_node_sum(3))
# print(tree.nodes)
print(tree.get_nodes())
# print(tree.get_branches())
delta = (10, 10, 10, 10)
tree.move(delta)

operation result:

树的节点数: 63
15
[[(313.2190030596347, 313.2190030596347)], [(190.18242313317546, 190.1824231331754), (436.255582986094, 190.1824231331754)], [(89.26242313317545, 190.18242313317535), (190.18242313317543, 89.26242313317539), (436.255582986094, 89.26242313317539), (537.175582986094, 190.1824231331754)], [(47.87291764591453, 231.5719286204362), (47.87291764591458, 148.79291764591443), (148.79291764591454, 47.87291764591453), (231.57192862043632, 47.87291764591453), (394.8660774988331, 47.87291764591453), (477.64508847335486, 47.87291764591453), (578.5650884733549, 148.79291764591449), (578.5650884733549, 231.57192862043632)], [(47.87291764591453, 265.5214166204362), (13.923429645914553, 231.5719286204362), (13.92342964591461, 148.79291764591443), (47.87291764591458, 114.84342964591445), (114.84342964591457, 47.87291764591453), (148.79291764591454, 13.923429645914553), (231.57192862043632, 13.923429645914553), (265.5214166204363, 47.87291764591453), (360.9165894988331, 47.87291764591453), (394.8660774988331, 13.923429645914553), (477.64508847335486, 13.923429645914553), (511.59457647335483, 47.87291764591453), (578.5650884733549, 114.84342964591451), (612.5145764733549, 148.79291764591449), (612.5145764733549, 231.57192862043632), (578.5650884733549, 265.5214166204363)], [(61.79634729182908, 279.44484626635074), (33.949487999999974, 279.44484626635074), (0.0, 245.49535826635076), (0.0, 217.64849897452166), (5.684341886080802e-14, 162.71634729182898), (5.684341886080802e-14, 134.86948799999988), (33.94948800000003, 100.91999999999985), (61.796347291829136, 100.91999999999985), (100.92000000000002, 61.79634729182908), (100.92000000000002, 33.949487999999974), (134.869488, 0.0), (162.7163472918291, 0.0), (217.64849897452174, 0.0), (245.49535826635088, 0.0), (279.44484626635085, 33.949487999999974), (279.44484626635085, 61.79634729182908), (346.99315985291855, 61.79634729182908), (346.99315985291855, 33.949487999999974), (380.9426478529185, 0.0), (408.7895071447477, 0.0), (463.7216588274403, 0.0), (491.5685181192694, 0.0), (525.5180061192693, 33.949487999999974), (525.5180061192693, 61.79634729182908), (564.6416588274403, 100.91999999999996), (592.4885181192694, 100.91999999999996), (626.4380061192694, 134.86948799999993), (626.4380061192694, 162.71634729182904), (626.4380061192694, 217.64849897452177), (626.4380061192694, 245.49535826635088), (592.4885181192694, 279.44484626635085), (564.6416588274403, 279.44484626635085)]]

get_node_sum(): Returns the total number of nodes from the trunk to the specified age. If no age is specified, it returns the number of nodes in the current tree. The specified age can be infinite (the result will be derived based on the number of branches).

The nodes attribute represents all node objects in the current tree, and each age node constitutes a list.

get_nodes(): Returns the coordinates of all nodes in the current tree, and each age node constitutes a list.

get_branches(): Returns the coordinates of all branches in the current tree. The format of the coordinates is (x0, y0, x1, y1), and the branches of each age constitute a list. This method has nothing to do with the branches attribute. The value of branches is the parameter passed in during initialization.

move(delta): Move the tree, pass in a delta parameter, the parameter format is the same as pos (x0, y0, x1, y1), and the four coordinate values ​​are translated according to the delta value.

Six, flexible use of the Tree library

1. Draw a nicer tree

# coding=utf-8
from Tree.core import Tree
from math import radians
from PIL import Image


branches = [[0.7, radians(-50)], [0.45, radians(10)], [0.6, radians(30)]]
tree = Tree(pos=(0, 0, 0, -300), branches=branches)
tree.grow(9)
tree.move_in_rectangle()
image = Image.new("RGB", tree.get_size(), (250, 250, 250))
tree.draw_on(image, (80, 20, 10, 120, 60, 30), '#003E15', 12)
image.show()

operation result:

2. Not limited to trees, other graphics can also be drawn

# coding=utf-8
from Tree.core import Tree
from math import radians
from PIL import Image


tree = Tree(pos=(0, 0, 0, -100), branches=[[1.1, radians(30)]])
tree.grow(24)
tree.move_in_rectangle()
tree.move((100, 100, 100, 100))
size = tuple([s+200 for s in tree.get_size()])
image = Image.new("RGB", size, (250, 250, 250))
tree.draw_on(image, (255, 0, 0), (255, 0, 0), 15)
image.show()

operation result:

Tree growth and drawing are very memory intensive. If the number of tree growth is large, the memory will be insufficient.

 

 

Guess you like

Origin blog.csdn.net/weixin_43790276/article/details/108561960