Alumpath
Dartmouth College Logo

Dartmouth College - COSC 1 – Intro to Programming & Computation

Fractal Tree Drawer with Turtle Graphics

Assignment Problem:

Write a Python program using the turtle graphics library to draw a fractal tree recursively. The tree should branch out, with each branch being smaller and potentially at a different angle than its parent branch. Allow parameters for initial branch length, branching angle, and recursion depth. Save the output as an SVG or image file.

Our Suggested Approach

1. Understand Fractal Trees and Recursion:

  • Fractal: A self-similar pattern, meaning it looks roughly the same at different scales. A fractal tree is made of smaller trees branching off larger ones.
  • Recursion: A programming technique where a function calls itself to solve smaller instances of the same problem. Ideal for drawing fractals because the structure of a branch is similar to the structure of the whole tree.

2. Python turtle Graphics Library:

  • Provides a simple way to draw graphics by controlling a 'turtle' (cursor) on a screen.
  • Key commands: forward(distance), backward(distance), left(angle_degrees), right(angle_degrees), penup(), pendown(), speed(), color(), hideturtle(), done() (or screen.mainloop() if using Screen object explicitly).

3. Recursive draw_tree Function Design:

The core function will be something like draw_tree(turtle_pen, branch_len, angle, depth, scale_factor):

  1. Base Case (Stopping Condition): If depth is 0 (maximum recursion level reached) or if branch_len becomes too small (e.g., less than 5 pixels), the function should simply return to stop the recursion for that path.
  1. Draw Current Branch:
  1. turtle_pen.forward(branch_len): Draw the main stem of the current (sub)tree.
  1. Recursive Calls for Sub-Branches (e.g., two branches):
  1. First (e.g., Left) Branch:
  1. turtle_pen.left(angle): Turn the turtle left by the specified branching angle.
  1. Recursively call draw_tree(turtle_pen, branch_len * scale_factor, angle, depth - 1, scale_factor). The scale_factor (e.g., 0.7 or 0.8) makes sub-branches shorter than the parent.
  1. turtle_pen.right(angle): Crucially, turn the turtle back by the same angle to restore its orientation relative to the direction of the parent branch it just came from.
  1. Second (e.g., Right) Branch:
  1. turtle_pen.right(angle): Turn right from the (restored) parent branch's direction.
  1. Recursively call draw_tree(turtle_pen, branch_len * scale_factor, angle, depth - 1, scale_factor).
  1. turtle_pen.left(angle): Turn the turtle back to restore orientation.

*(Optional: For more natural trees, one might vary the angles or scale factors slightly for left/right branches, or add a third middle branch.)*

  1. Return to Starting Position of the Current Branch:
  1. turtle_pen.backward(branch_len): Move the turtle back down the current branch to the point where this draw_tree call started. This is essential so that when the function returns to its caller, the turtle is positioned correctly at the end of the *caller's* branch, ready for other operations (like drawing another sibling branch).

4. Main Program Setup:

  1. Import the turtle module.
  1. Create a Screen object: screen = turtle.Screen() and set its properties (e.g., screen.bgcolor("lightblue"), screen.setup(width, height)).
  1. Create a Turtle object: my_turtle = turtle.Turtle().
  1. Set up initial turtle properties: my_turtle.speed(0) (0 is fastest), my_turtle.hideturtle() (so only the drawing is seen), my_turtle.left(90) (to orient the turtle to point upwards initially).
  1. Set initial turtle position (e.g., bottom center of the screen): my_turtle.penup(), my_turtle.goto(0, -screen_height / 2.5), my_turtle.pendown().
  1. Define parameters for the tree: initial_branch_len, branching_angle, recursion_depth, branch_scale_factor.
  1. Make the initial call to the draw_tree function.
  1. screen.tracer(0) at the start and screen.update() at the end can significantly speed up complex drawings by only updating the screen once.
  1. screen.mainloop() (or turtle.done()): Keeps the graphics window open until it's manually closed.

5. Saving the Output (SVG/Image):

  • The turtle module can save its drawing to a PostScript file using screen.getcanvas().postscript(file="fractal_tree.eps", colormode='color').
  • This .eps file can then be converted to SVG or other image formats (PNG, JPG) using external tools like Inkscape (command-line), ps2pdf followed by pdf2svg, or online converters. Python libraries like svglib might also help convert EPS to SVG directly within Python if needed.

Illustrative Code Snippet

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import turtle
# import random # For potential variations in angle or length

# --- Recursive function to draw the fractal tree ---
def draw_fractal_tree(t, branch_len, angle, depth, scale_factor=0.75, pen_size_factor=0.8):
    if depth == 0 or branch_len < 2: # Base case for recursion
        return

    original_pen_size = t.pensize()
    current_pen_size = max(1, int(branch_len / 10 * pen_size_factor)) # Thicker base, thinner branches
    t.pensize(current_pen_size)

    # Draw the current branch
    t.forward(branch_len)

    # Recursive call for the left sub-branch
    t.left(angle)
    draw_fractal_tree(t, branch_len * scale_factor, angle, depth - 1, scale_factor, pen_size_factor)
    t.right(angle) # Return turtle to original orientation relative to parent branch

    # Recursive call for the right sub-branch
    t.right(angle)
    draw_fractal_tree(t, branch_len * scale_factor, angle, depth - 1, scale_factor, pen_size_factor)
    t.left(angle) # Return turtle to original orientation relative to parent branch
    
    # Optional: Add a third, slightly different branch for more asymmetry
    # if depth > 1 and depth % 2 != 0: # Example condition
    #     t.left(angle / 2) 
    #     draw_fractal_tree(t, branch_len * scale_factor * 0.9, angle * 0.8, depth - 1, scale_factor, pen_size_factor)
    #     t.right(angle / 2)

    # Return turtle to the starting point of this branch
    t.pensize(original_pen_size) # Restore pensize before moving back
    t.backward(branch_len)


# --- Main setup and function call ---
def main():
    screen = turtle.Screen()
    screen.setup(width=800, height=700)
    screen.bgcolor("sky blue")
    screen.tracer(0) # Turn off screen updates for faster drawing

    artist_turtle = turtle.Turtle()
    artist_turtle.speed(0)      # 0 is fastest, 1-10 are slow to fast
    artist_turtle.hideturtle()
    artist_turtle.left(90)      # Point turtle upwards
    artist_turtle.penup()
    artist_turtle.goto(0, -screen.window_height() / 2 + 50) # Start near bottom-center
    artist_turtle.pendown()
    artist_turtle.pencolor("brown") # Trunk color

    # Tree parameters
    initial_length = 100
    initial_angle = 30
    recursion_level = 8
    branch_reduction_factor = 0.70
    pensize_reduction_factor = 0.85


    draw_fractal_tree(artist_turtle, initial_length, initial_angle, recursion_level, 
                      branch_reduction_factor, pensize_reduction_factor)
    
    screen.update() # Update the screen once drawing is complete
    
    # Save to EPS (then convert to SVG/PNG externally if needed)
    try:
        ts = screen.getcanvas()
        ts.postscript(file="fractal_tree_output.eps", colormode='color')
        print("Tree saved as fractal_tree_output.eps")
    except Exception as e:
        print(f"Error saving to EPS: {e}. This might require Tkinter.")

    screen.mainloop() # Keep window open

# if __name__ == "__main__":
#     main()

Explanation & Key Points

Recursive Tree Drawing Function (draw_fractal_tree)

The core of the program is a recursive function. It takes the turtle object, current branch length, branching angle, remaining recursion depth, and scaling factors as parameters. This function is responsible for drawing one segment of the tree (a branch) and then calling itself to draw smaller sub-branches.

Base Case for Recursion

Every recursive function needs a base case to terminate. For the fractal tree, the recursion stops when the depth parameter reaches 0 or when the branch_len becomes too small (e.g., less than 2 pixels) to be meaningfully drawn. This prevents infinite recursion and an overly cluttered image.

Drawing a Branch and Recursive Calls

Inside the recursive function: 1. The turtle moves forward() by the current branch_len. 2. To create a sub-branch, the turtle turns left() (or right()) by the specified angle. 3. A recursive call is made with a reduced branch_len (multiplied by scale_factor) and a decremented depth. 4. Crucially, after the recursive call for a sub-branch returns, the turtle must turn back by the same angle (e.g., right() after left()) to restore its orientation relative to the parent branch before attempting to draw another sibling branch or returning.

Returning to Branch Origin (Backtracking)

After a branch and all its sub-branches are drawn, the turtle moves backward() by the length of the current branch. This action returns the turtle to the point where this particular call to draw_fractal_tree started. This 'backtracking' is essential for the recursive structure, ensuring that when the function returns to its caller, the turtle is positioned correctly at the *end* of the caller's branch, ready for subsequent operations.

Turtle and Screen Initialization

The main part of the script sets up the drawing environment. This includes creating a turtle.Screen(), setting its background color and size, and creating a turtle.Turtle() object (the 'pen'). Initial turtle properties like speed (0 for fastest), visibility (hideturtle()), initial orientation (usually pointing upwards with left(90)), and starting position (e.g., bottom-center of the screen) are configured.

Customizable Tree Parameters

The visual appearance of the fractal tree is controlled by several parameters: initial_branch_length, branching_angle (the angle between sibling branches), recursion_depth (how many levels of branching), and scale_factor (determining how much shorter each subsequent level of branches becomes). Varying these parameters can create a wide variety of tree-like fractal patterns.

Performance and Saving

For complex drawings, screen.tracer(0) is called at the beginning to turn off automatic screen updates, and screen.update() is called once at the end. This significantly speeds up the drawing process. The drawing can be saved to an Encapsulated PostScript (.eps) file using screen.getcanvas().postscript(), which can then be converted to SVG or other raster image formats using external tools.

Key Concepts to Master

Recursion (Recursive Functions)Fractals (Self-Similarity)Python turtle Graphics LibraryBase Cases in RecursionAlgorithmic Thinking (Divide and Conquer)Geometric Transformations (Angles, Scaling)Parameterization for CustomizationProcedural Art/Drawing

How Our Tutors Elevate Your Learning

  • Mastering Recursion: Clearly explaining how the recursive calls stack and unstack, and how the base case prevents infinite loops. Visualizing the call stack for a small depth can be very helpful.
  • Turtle Graphics State: Emphasizing the importance of managing the turtle's state (position, orientation, pen state) meticulously. For example, ensuring the turtle returns to its previous orientation after drawing a sub-branch so the next sibling branch starts correctly.
  • Backtracking Logic: Clarifying why moving backward() at the end of each recursive step (after sub-branches are drawn) is crucial for the overall structure of the tree.
  • Debugging Turtle Graphics: Helping to identify common issues like branches going in wrong directions, the turtle not returning to the correct spot, or the recursion not terminating properly. This often involves adding print() statements to trace turtle position/heading or simplifying the recursion depth.
  • Experimenting with Parameters: Encouraging experimentation with different angles, lengths, scale factors, and depths to understand their impact on the final fractal shape.
  • Saving and Exporting: Explaining how to save the turtle drawing as an EPS file and discussing options for converting it to more common formats like SVG or PNG.

Need Personalized Help with Your Assignment?

Our human experts provide tailored guidance for your specific course assignments, helping you understand concepts and succeed.