├── Generic ├── base_tree.py ├── forest_path.py └── line_of_trees.py ├── README.md ├── Recursive ├── base_recursive.py └── realistic_tree_recursive.py └── tree_drawing.gif /Generic/base_tree.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | import random 3 | 4 | class Tree: 5 | def __init__(self, turt, x=0, y=0, scale=1, speed=3): 6 | self.scale = scale 7 | self.trunk_width = 10*scale # width in pixels (default is 10 pixels) 8 | self.trunk_height = 20*scale 9 | 10 | self.turt = turt 11 | self.turt.speed(speed) 12 | 13 | # Move turtle into position 14 | self.turt.penup() 15 | self.turt.goto(x,y) 16 | self.turt.pendown() 17 | 18 | def draw_tree(self): 19 | self.draw_trunk() 20 | self.draw_leafs() 21 | 22 | def draw_trunk(self): 23 | self.turt.color('brown') 24 | self.turt.begin_fill() 25 | self.turt.setheading(0) # Head to the right 26 | self.turt.forward(self.trunk_width) 27 | self.turt.right(90) 28 | self.turt.forward(self.trunk_height) 29 | self.turt.right(90) 30 | self.turt.forward(self.trunk_width) 31 | self.turt.right(90) 32 | self.turt.forward(self.trunk_height) 33 | self.turt.end_fill() 34 | 35 | def draw_leafs(self, color='green', triangles=3): 36 | self.turt.color(color) 37 | for i in range(triangles): 38 | self.draw_triangle() 39 | height_increase = 10*self.scale 40 | self.turt.sety(self.turt.ycor() + height_increase) 41 | 42 | def draw_triangle(self): 43 | branch_overhang = self.trunk_height # length branches overhang from trunk (setting it to the same value as our trunk height seemed to look good) 44 | triangle_height = 2*self.trunk_height # A single triangle is 2 times as tall as the trunk 45 | 46 | self.turt.begin_fill() 47 | 48 | x_init, y_init = (self.turt.xcor(), self.turt.ycor()) 49 | x_middle = x_init + self.trunk_width/2.0 50 | x_bottom_left = x_init - branch_overhang 51 | x_bottom_right = x_init + self.trunk_width + branch_overhang 52 | y_top = y_init + triangle_height 53 | 54 | self.turt.goto(x_bottom_left, y_init) 55 | self.turt.goto(x_middle, y_top) 56 | self.turt.goto(x_bottom_right, y_init) 57 | self.turt.goto(x_init, y_init) 58 | 59 | self.turt.end_fill() 60 | 61 | if __name__ == '__main__': 62 | turtle.speed(0) 63 | tree = Tree(turtle, x=3, y=200, scale=5, speed=4) 64 | tree.draw_tree() 65 | turtle.done() -------------------------------------------------------------------------------- /Generic/forest_path.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | import random 3 | 4 | from base_tree import Tree 5 | 6 | class Nature: 7 | def __init__(self, turt=turtle, WIDTH=1200, HEIGHT=800): 8 | self.WIDTH = WIDTH 9 | self.HEIGHT = HEIGHT 10 | self.turt = turt 11 | 12 | self.y_intercept = self.HEIGHT/4 # Where on the y-axis we start drawing the path 13 | self.slope = (self.y_intercept - (-self.HEIGHT/2))/(0 - (-self.WIDTH/2)) 14 | 15 | # When plant_trees is called, these are the y_coordinates a row of trees are planted on 16 | self.tree_rows = [175, 100, -10, -210] 17 | 18 | turtle.setup(WIDTH, HEIGHT) 19 | turtle.colormode(255) 20 | 21 | def draw_background(self): 22 | self.draw_grass() 23 | self.draw_path() 24 | self.draw_sky() 25 | 26 | def draw_grass(self): 27 | self.turt.penup() 28 | self.turt.begin_fill() 29 | self.turt.width(5) 30 | self.turt.color('#147a00','#5ba14d') 31 | self.turt.goto((0,self.y_intercept)) 32 | self.turt.pendown() 33 | self.turt.begin_fill() 34 | self.turt.goto((self.WIDTH/2, self.y_intercept)) 35 | self.turt.goto((self.WIDTH/2,-self.HEIGHT/2)) 36 | self.turt.goto((0,self.y_intercept)) 37 | self.turt.end_fill() 38 | self.turt.begin_fill() 39 | self.turt.goto((-self.WIDTH/2, self.y_intercept)) 40 | self.turt.goto((-self.WIDTH/2,-self.HEIGHT/2)) 41 | self.turt.goto((0,self.y_intercept)) 42 | self.turt.end_fill() 43 | 44 | def draw_path(self): 45 | self.turt.penup() 46 | self.turt.begin_fill() 47 | self.turt.width(5) 48 | self.turt.color('#a15c0d','#bf9a6f') 49 | self.turt.goto((0,self.y_intercept)) 50 | self.turt.pendown() 51 | self.turt.goto((-self.WIDTH/2, -self.HEIGHT/2)) 52 | self.turt.goto((self.WIDTH/2,-self.HEIGHT/2)) 53 | self.turt.goto((0,self.y_intercept)) 54 | self.turt.end_fill() 55 | 56 | def draw_sky(self): 57 | self.turt.penup() 58 | self.turt.begin_fill() 59 | self.turt.width(5) 60 | self.turt.color('#4d85a1','#7db0c9') 61 | self.turt.goto((0,self.y_intercept)) 62 | self.turt.pendown() 63 | self.turt.begin_fill() 64 | self.turt.goto((self.WIDTH/2, self.y_intercept)) 65 | self.turt.goto((self.WIDTH/2,self.HEIGHT/2)) 66 | self.turt.goto((-self.WIDTH/2,self.HEIGHT/2)) 67 | self.turt.goto((-self.WIDTH/2,self.y_intercept)) 68 | self.turt.goto((0,self.y_intercept)) 69 | self.turt.end_fill() 70 | 71 | def plant_trees(self): 72 | self.turt.width(2) 73 | size = 1 74 | for y_value in self.tree_rows: 75 | self.create_forest(size, y_value) 76 | size *= 1.75 77 | 78 | def create_forest(self, size, y_value): 79 | iterations = int(36/size) 80 | for i in range(iterations): 81 | self.turt.penup() 82 | x_value = (i*self.WIDTH/iterations)-self.WIDTH/2 83 | path_offset = 35*size # Used as an additional buffer so that trees don't get planted on dirt path 84 | on_dirt_path = (x_value > ((y_value-self.y_intercept)/self.slope)-path_offset and x_value < ((self.y_intercept-y_value)/self.slope)+path_offset) 85 | if not on_dirt_path: 86 | x_specific = x_value+random.randint(-50,0) # Add a little randomness so trees aren't too evenly spaced out 87 | scale = size*random.randint(95,100)/100.0 # Add slight, random variances in size 88 | y_specific = y_value-(size-1.25)*20+random.randint(-5,5) # Add slight, random offsets in y position for a given row 89 | tree = RandomGreenTree(self.turt, scale=scale, x=x_specific, y=y_specific, speed=0) 90 | tree.draw_tree() 91 | 92 | # Override base Tree class and give a random green color to any tree that is created 93 | class RandomGreenTree(Tree): 94 | def __init__(self, turt, x=0, y=0, scale=1, speed=3): 95 | super().__init__(turt, x, y, scale, speed) 96 | 97 | # Random green color (r, g, b) 98 | green_value = random.randint(50,150) 99 | self.color = (0, green_value, 0) 100 | 101 | def draw_tree(self): 102 | self.draw_trunk() 103 | self.draw_leafs(color = self.color) 104 | 105 | if __name__ == '__main__': 106 | random.seed(99) 107 | nature = Nature() 108 | nature.draw_background() 109 | nature.plant_trees() 110 | turtle.done() -------------------------------------------------------------------------------- /Generic/line_of_trees.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | import random 3 | 4 | from base_tree import Tree 5 | 6 | def create_forest(size, turt, y_value): 7 | for i in range(15): 8 | scale = random.random()*size 9 | x = i*100-600 10 | y = y_value + (size-1.25)*20 11 | tree = Tree(turt, x=x, y=y, scale=scale, speed=6) 12 | tree.draw_tree() 13 | 14 | if __name__ == '__main__': 15 | random.seed(50) 16 | turt = turtle.Turtle() 17 | starty = 0 18 | create_forest(2, turt, starty) 19 | turtle.done() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TeamTrees 2 | Visualizations of trees in Python created for the #TeamTrees movement to plant 20 million trees by 2020. 3 | 4 | 5 | 6 | YouTube Video for code in Generic folder: https://youtu.be/WG42fyCMsD0 7 | 8 | YouTube Video for code in Recursive folder: https://youtu.be/VUYPWxTe4Nw 9 | 10 | ## Setup 11 | 12 | To play with the code I recommend you fork this repo and then clone it locally. Instructions on how to do this can be found here: https://help.github.com/en/github/getting-started-with-github/fork-a-repo 13 | 14 | Both Python 2 & 3 should work to execute the code. 15 | 16 | If you are running forest_path.py or line_of_trees.py, make sure you also have base_tree.py saved in the same folder locally. 17 | -------------------------------------------------------------------------------- /Recursive/base_recursive.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | 3 | BRANCH_COUNT = 1 4 | TURN_ANGLE = 30 5 | INITIAL_BRANCH_SIZE = 100 6 | SHRINK_FACTOR = 0.8 7 | 8 | SPEED = 1 9 | UP = 90 10 | 11 | def tree(size, depth=0): 12 | if depth <= BRANCH_COUNT: 13 | turt.forward(size) 14 | turt.right(TURN_ANGLE) 15 | tree(size*SHRINK_FACTOR, depth+1) 16 | turt.left(2*TURN_ANGLE) 17 | tree(size*SHRINK_FACTOR, depth+1) 18 | turt.right(TURN_ANGLE) 19 | turt.backward(size) 20 | 21 | if __name__ == '__main__': 22 | turt = turtle.Turtle() 23 | turt.setheading(UP) 24 | turt.width(4) 25 | turt.speed(SPEED) 26 | 27 | tree(INITIAL_BRANCH_SIZE) 28 | turtle.done() -------------------------------------------------------------------------------- /Recursive/realistic_tree_recursive.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | import random 3 | 4 | BRANCH_COUNT = 7 5 | TURN_ANGLE = 10 6 | SHRINK_FACTOR = 0.8 7 | 8 | def tree(size, depth): 9 | if depth >= 1: 10 | if random.random() > 0.33: 11 | turt.width(depth) 12 | turt.color(get_color(depth)) 13 | turt.forward(size) 14 | turt.right(TURN_ANGLE) 15 | tree(size*SHRINK_FACTOR, depth-1) 16 | turt.right(TURN_ANGLE) 17 | tree(size*SHRINK_FACTOR, depth-1) 18 | turt.left(3*TURN_ANGLE) 19 | tree(size*SHRINK_FACTOR, depth-1) 20 | turt.left(TURN_ANGLE) 21 | tree(size*SHRINK_FACTOR, depth-1) 22 | turt.right(2*TURN_ANGLE) 23 | turt.color(get_color(depth)) 24 | turt.backward(size) 25 | 26 | def get_color(depth): 27 | if BRANCH_COUNT - depth < 3: 28 | return 'brown' 29 | else: 30 | return 'green' 31 | 32 | if __name__ == '__main__': 33 | random.seed(46) 34 | turt = turtle.Turtle() 35 | turt.setheading(90) 36 | turt.speed(0) 37 | turtle.colormode(255) 38 | tree(100, BRANCH_COUNT) 39 | turtle.done() -------------------------------------------------------------------------------- /tree_drawing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KeithGalli/TeamTrees/a279102d0eccd4fd22d7102cf1d5b7c8399ca833/tree_drawing.gif --------------------------------------------------------------------------------