Happy Birthday America!

Happy Birthday America! Let's create an American Flag using Python and Turtle!

Happy Birthday America!

Drawing an American Flag with Python/Turtle

As we enter another year in the history of America, it seems fitting to have a little fun and celebrate this amazing country and all of its success and opportunities.

Let's grab a cup of coffee, setup a quick python environment and get to coding a small little script that will dynamically draw an American flag by using no graphical assets, but plain code!

Before we get into the coding fun, it is important to understand the proportions, sizes and colors used in the American Flag.  A quick google search led me to this site: https://usflags.design/usa/.  This is great, as it helps us identify the following:

Flag Proportions: 1 x 1.9
All of the flag elements are percentage-based on the proportions above and have the following calculations:

  • Each stripe has a height of: 7.69%
  • The blue background for the stars is 76% W x 53.85% H
  • Each star has a radius of: 6.16%
  • The grid spacing for the stars is: 6.3% horizontally and 5.4% vertically

Primary Flag Colors are:

  • Red: #bb133e
  • White: #ffffff
  • Blue: #002147

Requirements:

  • O/S of choice (Windows/Mac/Linux)
  • Python 3.9+
  • Package manager (we will be using pip, but please use whichever you like)
  • Virtual Environment (we will be using venv, but please use whichever you like)
  • cup of coffee!

Let's Get Started!

Step 1 - Setup our environment

mkdir HBD_America
cd HBD_America
python3 -m venv env

Step 2 - Activate our environment and install black to ensure that our code is always clean!

source ./env/bin/activate
pip install black
Collecting black
  Downloading black-21.6b0-py3-none-any.whl (140 kB)
     |████████████████████████████████| 140 kB 3.3 MB/s
Collecting click>=7.1.2
  Downloading click-8.0.1-py3-none-any.whl (97 kB)
     |████████████████████████████████| 97 kB 6.4 MB/s
Collecting appdirs
  Downloading appdirs-1.4.4-py2.py3-none-any.whl (9.6 kB)
Collecting mypy-extensions>=0.4.3
  Downloading mypy_extensions-0.4.3-py2.py3-none-any.whl (4.5 kB)
Collecting pathspec<1,>=0.8.1
  Downloading pathspec-0.8.1-py2.py3-none-any.whl (28 kB)
Collecting regex>=2020.1.8
  Downloading regex-2021.7.1-cp39-cp39-win_amd64.whl (270 kB)
     |████████████████████████████████| 270 kB 6.8 MB/s
Collecting toml>=0.10.1
  Downloading toml-0.10.2-py2.py3-none-any.whl (16 kB)
Collecting colorama
  Downloading colorama-0.4.4-py2.py3-none-any.whl (16 kB)
Installing collected packages: colorama, toml, regex, pathspec, mypy-extensions, click, appdirs, black
Successfully installed appdirs-1.4.4 black-21.6b0 click-8.0.1 colorama-0.4.4 mypy-extensions-0.4.3 pathspec-0.8.1 regex-2021.7.1 toml-0.10.2

P.S.: black is not required for this project; however, I highly recommend it when coding in Python as it will not only help you keep your code clean and organized, but teach you a few tricks along the way!


Coding Time!

Now that we have our environment setup and activated, open your favorite source code editor (I am a Sublime fan myself) and star a new .py file.  This effort will only require a single file as it is pretty simple.

I have separated my script into six sections, for better readability.  Here they are:

Section 1 - Defining constants

Based on the information above (proportions, colors, etc), we have to define a few constants that we will use throughout the code.  For this example, I am building a flag that measures 1000H x 1900W px, therefore my base_measurement will be 1000.

import turtle


BASE_MEASUREMENT = 1000
FLAG_HEIGHT = BASE_MEASUREMENT
FLAG_WIDTH = round(FLAG_HEIGHT * 1.9)
STARTING_POINT = (FLAG_WIDTH / 2 * -1, FLAG_HEIGHT / 2)
STRIPE_HEIGHT = round(BASE_MEASUREMENT * 0.0769)
STAR_BG_HEIGHT = (STRIPE_HEIGHT * 7) - 1
STAR_BG_WIDTH = round(BASE_MEASUREMENT * 0.76)
STAR_SIZE = round(BASE_MEASUREMENT * 0.0616)
STAR_SPACER_H = round(BASE_MEASUREMENT * 0.063)
STAR_SPACER_V = round(BASE_MEASUREMENT * 0.054)

BLACK = "#000000"
RED = "#bb133e"
WHITE = "#ffffff"
BLUE = "#002147"

Section 2 - Function to Draw Rectangle

We will be using a few rectangles (stripes and blue background for stars), so defining a function that can draw any rectangle is very beneficial for us.  #CodeReusability, anyone?

def draw_rectangle(pen, starting_position, color, width, height):
    pen.penup()
    pen.goto(starting_position)
    pen.color(color)
    pen.pendown()
    pen.begin_fill()
    for i in range(4):
        pen.fd(width if i % 2 == 0 else height)
        pen.rt(90)
    pen.setheading(0)
    pen.end_fill()

Section 3 - Function to Draw Stars

We have to draw 50 stars for our flag, therefore a function that can draw a star based on a being provided a central position for the star is very helpful.  Please note that the position given is the middle of the drawing for the star, so in order to start sketching we first need to move to one of the star points (in our case, we are going north) and then point the cursor to the right direction and get drawing!

def draw_star(pen, position):
    pen.penup()
    pen.goto(position[0], position[1] + (STAR_SIZE / 2))
    pen.setheading(288)
    pen.color(WHITE)
    pen.pendown()
    pen.begin_fill()
    for i in range(5):
        pen.forward(STAR_SIZE)
        pen.right(144)
    pen.end_fill()

Section 4 - Function to Draw Stripes

Since we have 13 stripes to draw in alternating colors (RED/WHITE), it made sense to combine all of the executions into a single function that in turn calls draw_rectangle.

def draw_stripes(pen):
    position = STARTING_POINT
    for i in range(13):
        color = RED if i % 2 == 0 else WHITE
        draw_rectangle(pen, position, color, FLAG_WIDTH, STRIPE_HEIGHT)
        position = (position[0], position[1] - STRIPE_HEIGHT)

Section 5 - Function to Draw Stars

This is the more challenging part of the script, as we need to space the stars per our regulations, as well as ensure that we draw all 50 stars perfectly aligned.  In this case, it helps to break the effort to its own function, with two sections internally.  We have two sets of stars to draw, separated into two distinct row configurations:

  1. 6 stars per row - we have five of these rows and we will be drawing them first.
  2. 5 stars per row - we have four of these rows and will be drawing them second.
def draw_stars(pen):
    # Draw 5 rows of 6 stars
    star_location = (
        STARTING_POINT[0] + (STAR_SPACER_H),
        STARTING_POINT[1] - (STAR_SPACER_V),
    )
    for i in range(5):
        for i in range(6):
            draw_star(pen, star_location)
            star_location = (star_location[0] + (STAR_SPACER_H * 2), star_location[1])
        star_location = (
            STARTING_POINT[0] + (STAR_SPACER_H),
            star_location[1] - (STAR_SPACER_V * 2),
        )

    # Draw 4 rows of 5 stars
    star_location = (
        STARTING_POINT[0] + (STAR_SPACER_H * 2),
        STARTING_POINT[1] - (STAR_SPACER_V * 2),
    )
    for i in range(4):
        for i in range(5):
            draw_star(pen, star_location)
            star_location = (star_location[0] + (STAR_SPACER_H * 2), star_location[1])
        star_location = (
            STARTING_POINT[0] + (STAR_SPACER_H * 2),
            star_location[1] - (STAR_SPACER_V * 2),
        )

Section 6 - Our main entry point for the script

This function is the main thread for executing our script.  It also includes (out of habit) a if __name__... check in order to ensure that the script executes as we expect.

def main():
    # Setup screen, and cursor
    turtle.title("Happy Birthday America! 2021!")
    canvas = turtle.Screen()
    canvas.setup(height=FLAG_HEIGHT * 1.1, width=FLAG_WIDTH * 1.1)
    canvas.bgcolor(BLACK)
    cursor = turtle.Turtle()
    cursor.shape("turtle")
    cursor.speed(0)

    # Draw Stripes
    draw_stripes(cursor)

    # Draw Blue Background (stars)
    draw_rectangle(cursor, STARTING_POINT, BLUE, STAR_BG_WIDTH, STAR_BG_HEIGHT)

    # Draw Stars
    draw_stars(cursor)

    # Hide cursor and Leave screen open until closed by user
    cursor.ht()
    turtle.done()


if __name__ == "__main__":
    main()

Once you combine all of the sections above into a single script, your source code should be similar to this:

import turtle


BASE_MEASUREMENT = 1000
FLAG_HEIGHT = BASE_MEASUREMENT
FLAG_WIDTH = round(FLAG_HEIGHT * 1.9)
STARTING_POINT = (FLAG_WIDTH / 2 * -1, FLAG_HEIGHT / 2)
STRIPE_HEIGHT = round(BASE_MEASUREMENT * 0.0769)
STAR_BG_HEIGHT = (STRIPE_HEIGHT * 7) - 1
STAR_BG_WIDTH = round(BASE_MEASUREMENT * 0.76)
STAR_SIZE = round(BASE_MEASUREMENT * 0.0616)
STAR_SPACER_H = round(BASE_MEASUREMENT * 0.063)
STAR_SPACER_V = round(BASE_MEASUREMENT * 0.054)

BLACK = "#000000"
RED = "#bb133e"
WHITE = "#ffffff"
BLUE = "#002147"


def draw_rectangle(pen, starting_position, color, width, height):
    pen.penup()
    pen.goto(starting_position)
    pen.color(color)
    pen.pendown()
    pen.begin_fill()
    for i in range(4):
        pen.fd(width if i % 2 == 0 else height)
        pen.rt(90)
    pen.setheading(0)
    pen.end_fill()


def draw_star(pen, position):
    pen.penup()
    pen.goto(position[0], position[1] + (STAR_SIZE / 2))
    pen.setheading(288)
    pen.color(WHITE)
    pen.pendown()
    pen.begin_fill()
    for i in range(5):
        pen.forward(STAR_SIZE)
        pen.right(144)
    pen.end_fill()


def draw_stripes(pen):
    position = STARTING_POINT
    for i in range(13):
        color = RED if i % 2 == 0 else WHITE
        draw_rectangle(pen, position, color, FLAG_WIDTH, STRIPE_HEIGHT)
        position = (position[0], position[1] - STRIPE_HEIGHT)


def draw_stars(pen):
    # Draw 5 rows of 6 stars
    star_location = (
        STARTING_POINT[0] + (STAR_SPACER_H),
        STARTING_POINT[1] - (STAR_SPACER_V),
    )
    for i in range(5):
        for i in range(6):
            draw_star(pen, star_location)
            star_location = (star_location[0] + (STAR_SPACER_H * 2), star_location[1])
        star_location = (
            STARTING_POINT[0] + (STAR_SPACER_H),
            star_location[1] - (STAR_SPACER_V * 2),
        )

    # Draw 4 rows of 5 stars
    star_location = (
        STARTING_POINT[0] + (STAR_SPACER_H * 2),
        STARTING_POINT[1] - (STAR_SPACER_V * 2),
    )
    for i in range(4):
        for i in range(5):
            draw_star(pen, star_location)
            star_location = (star_location[0] + (STAR_SPACER_H * 2), star_location[1])
        star_location = (
            STARTING_POINT[0] + (STAR_SPACER_H * 2),
            star_location[1] - (STAR_SPACER_V * 2),
        )


def main():
    # Setup screen, and cursor
    turtle.title("Happy Birthday America! 2021!")
    canvas = turtle.Screen()
    canvas.setup(height=FLAG_HEIGHT * 1.1, width=FLAG_WIDTH * 1.1)
    canvas.bgcolor(BLACK)
    cursor = turtle.Turtle()
    cursor.shape("turtle")
    cursor.speed(0)

    # Draw Stripes
    draw_stripes(cursor)

    # Draw Blue Background (stars)
    draw_rectangle(cursor, STARTING_POINT, BLUE, STAR_BG_WIDTH, STAR_BG_HEIGHT)

    # Draw Stars
    draw_stars(cursor)

    # Hide cursor and Leave screen open until closed by user
    cursor.ht()
    turtle.done()


if __name__ == "__main__":
    main()

And you can run it by calling python3 to run the code, like this:

python american_flag.py

You will then see turtle drawing the flag right in front of you, similar to this:

Once turtle is done, the end result should look something like this:

Happy Birthday America!

the entire script can be found in the moshpit repo within my github account, directly linked here.

Featured image created by Stephanie McCabe, downloaded from unsplash, licensed under the unsplash license.