Editor

Christmas Tree in Python Turtle

Intermediate · Festivals · 111 lines · draws in about 15 seconds

This program draws a Christmas tree from three stacked triangles, then decorates it with ornaments from a list, a gold star and presents under a snowy sky.

Christmas Tree in Python Turtle: the finished drawing
import random
import turtle
random.seed(25)
screen = turtle.Screen()
screen.title("Christmas Tree")
screen.bgcolor("midnightblue")
t = turtle.Turtle()
def rectangle(x, y, width, height, color):
"""A filled rectangle with its bottom-left corner at (x, y)."""
t.penup()
t.goto(x, y)
t.setheading(0)
t.pendown()
t.color(color)
t.begin_fill()
for side in range(2):
t.forward(width)
t.left(90)
t.forward(height)
t.left(90)
t.end_fill()
def triangle(base_y, width, height, color):
"""One layer of the tree: a triangle standing on y = base_y."""
t.penup()
t.goto(-width / 2, base_y)
t.pendown()
t.color(color)
t.begin_fill()
t.goto(width / 2, base_y)
t.goto(0, base_y + height)
t.goto(-width / 2, base_y)
t.end_fill()
def present(x, y, size, box_color, ribbon_color):
"""A square present with a ribbon both ways and a bow on top."""
rectangle(x, y, size, size, box_color)
rectangle(x + size / 2 - 4, y, 8, size, ribbon_color)
rectangle(x, y + size / 2 - 4, size, 8, ribbon_color)
t.penup()
t.goto(x + size / 2 - 8, y + size + 6)
t.dot(16)
t.goto(x + size / 2 + 8, y + size + 6)
t.dot(16)
# Falling snow. Speed 0 puts every flake down at once, instead of
# making the turtle walk across the sky to each one.
t.speed(0)
t.penup()
for flake in range(60):
t.goto(random.randint(-300, 300), random.randint(-180, 215))
t.dot(random.randint(3, 7), "white")
# Snowy ground: a gentle hill made from a slice of a very big circle
t.speed(7)
t.goto(-285, -215)
t.setheading(15)
t.pendown()
t.color("white")
t.begin_fill()
t.circle(-1100, 30, steps=30)
t.goto(-285, -215)
t.end_fill()
# Trunk, then three layers of branches from the bottom up
rectangle(-22, -175, 44, 60, "saddlebrown")
triangle(-130, 300, 150, "#1d6b35")
triangle(-50, 240, 140, "#238a43")
triangle(30, 170, 130, "#2ea356")
# Ornaments in rows, taking the colours in turn
colors = ["red", "gold", "deepskyblue", "hotpink", "orange"]
ornaments = [
(-110, -112), (-55, -100), (0, -112), (55, -100), (110, -112),
(-85, -32), (-30, -20), (30, -32), (85, -20),
(-50, 48), (0, 60), (50, 48),
(-20, 115), (20, 115),
]
t.penup()
for number, (x, y) in enumerate(ornaments):
t.goto(x, y)
t.dot(18, colors[number % len(colors)])
# A gold star on top
t.goto(0, 185)
t.setheading(288)
t.pendown()
t.color("gold")
t.begin_fill()
for point in range(5):
t.forward(19)
t.left(72)
t.forward(19)
t.right(144)
t.end_fill()
# Presents under the tree
present(-170, -190, 70, "crimson", "gold")
present(95, -190, 60, "royalblue", "white")
present(-75, -200, 40, "darkorchid", "lightpink")
t.hideturtle()
turtle.done()

How the code works

Layers of the tree

Each layer is a triangle standing on the line y = base_y, centred on x = 0. Three calls with narrower, higher triangles stack into a tree.

def triangle(base_y, width, height, color):
    """One layer of the tree: a triangle standing on y = base_y."""
    t.penup()
    t.goto(-width / 2, base_y)
    t.pendown()
    t.color(color)
    t.begin_fill()
    t.goto(width / 2, base_y)
    t.goto(0, base_y + height)
    t.goto(-width / 2, base_y)
    t.end_fill()

Presents from rectangles

A present is three rectangles: the box and two thin ribbon strips across the middle. Two dots on top make the bow.

def present(x, y, size, box_color, ribbon_color):
    """A square present with a ribbon both ways and a bow on top."""
    rectangle(x, y, size, size, box_color)
    rectangle(x + size / 2 - 4, y, 8, size, ribbon_color)
    rectangle(x, y + size / 2 - 4, size, 8, ribbon_color)
    t.penup()
    t.goto(x + size / 2 - 8, y + size + 6)
    t.dot(16)
    t.goto(x + size / 2 + 8, y + size + 6)
    t.dot(16)

Snow in random places

random.randint() picks a place and a size for each of 60 flakes. random.seed(25) at the top makes the same numbers come out on every run, so the picture never changes.

for flake in range(60):
    t.goto(random.randint(-300, 300), random.randint(-180, 215))
    t.dot(random.randint(3, 7), "white")

Ornaments that take turns

enumerate() numbers the ornaments 0, 1, 2 and so on, and number % len(colors) turns that number into a place in the colour list, so the colours repeat in order.

for number, (x, y) in enumerate(ornaments):
    t.goto(x, y)
    t.dot(18, colors[number % len(colors)])

Make it yours

Change the code above and press Run. Some ideas:

  • Add more ornaments by adding (x, y) pairs to the ornaments list, for example (0, 0).
  • Change range(60) to range(200) for a heavier snowfall.
  • Add a fourth present with present(30, -205, 45, "darkorange", "white") before t.hideturtle().

What it uses

Every turtle command the site supports is listed on Python turtle online.