In the late 60s, Seymour Papert at MIT developed a robot "turtle" to help teach young children to program. This robot has a small pen attached to it, which would draw a trail (a line) on a piece of paper as the robot moved and turned. Children could then program the robot's movement in order to have it draw a particular picture. This method of producing drawings is known as turtle graphics, versions of which can be found in pretty much every programming language.
For this assignment, you will be writing a Python program that uses a virtual turtle to produce a simple data visualization (a bar chart based on the contents of a user-specified data file:
By completing this assignment you will practice and master the following skills:
- Creating and running stand-alone Python scripts
- Processing data from external files and user input
- Using loops and conditionals to structure program instructions
- Abstracting algorithms into reusable, compose-able functions
- Reading documentation to discover and learn new functions
Follow the below link to create your private code repo for this assignment. You will need to accept this assignment to create your code repo. Do not fork this repository!
fork this repository!
After you've accepted the assignment,
clone the repo to your local machine so you can edit the files. Make sure you don't clone it inside another repo!
This repo contains a
data/ folder containing some sample data files that you can use to develop and test your program:
sample_data.txt contains arbitrary names and numbers, while
huskies2016.txt contains scores for the 2016 UW football season (the first number is how many points UW scored, the second is how many points their opponent scored).
Your program for this assignment should be written in a Python script file named
turtle_charter.py. You will need to create the file and write its contents using an editor such as VS Code.
Your script should be able to act as both an importable module and as a top-level script. Your program should be implemented as a set of standalone functions;
if the module is run as a script, then you can call these functions in order to provide interactive input and output.
You should be able to test your program by running the script from the command-line:
Your program will be visualizing information contained in an external text file. Each file contains observations that include a text label and two data features (values). Labels and data values are each placed on individual lines; see the provided data files for an example.
When run as a script, your program should prompt the user (at the command-line) for which data file to visualize: the user will enter the path to the file (e.g.,
data/sample_data.txt), which the program will then be able to open, as well as a title for the chart.
- Note that for testing and development I recommend you "hard-code" the file path and title into your code (e.g., by commenting out the prompting code). This will save you from having to type the file name over and over again! (You could alternatively use the command-line to pipe the correct inputs into the Python program).
In order to make your visualization be dynamically sized and labeled, you will need to do some simple processing on the data in the file before you draw the chart. You should define the following functions for your program to use:
count_observations() should take as a parameter which file to analyze and return the number of observations within that file (e.g.,
sample_data.txt has 6 observations). Note that each observation takes 3 lines (a label and 2 values).
get_max_value() should take in which file to analyze and which of the two data features to consider. It will return the maximum value of that feature across the observations (e.g.,
sample_data.txt has a maximum "feature 1" of 12; all the values for "feature 2" are -1).
To find the maximum, think about reading through the file one observation at a time, keeping track of the "biggest" value you've found so far. At each observation, check whether the feature of interest is greater than the current biggest, and if so make it become the new biggest!
- This is an example of a "king-of-the-hill" search algorithm; we will discuss this and similar approaches later in the course.
Note that using the programming techniques we have so far, each of these functions requires reading through the entire data file from start to finish. This is relatively inefficient, though with such small data it doesn't matter (and gives you a chance to practice with loops!). We will learn about more effective ways to process and store files in the future.
You can test each of these functions by calling them when the script is run and printing out the returned result.
The biggest part of your program will involve drawing the visualization. The visualization should be a bar chart with the following features (as illustrated in the above example):
The chart should appear in an appropriately sized window. The example shown at the top of the page has a window 800 by 500 pixels; please make sure your window will fit on a small laptop screen!
The chart includes a bar for each observation illustrating at least one data feature in the data file (probably the first feature, e.g., UW points scored).
- The second data feature is included for extensions, but is not required to be used for the assignment.
Each bar is filled in with a different color; how you decide to color the bars is up to you (see below for details).
The chart includes both an x- and y-axis. The x-axis shows the observation label (as text), while the y-axis shows the data value (ranging from 0 to the maximum data value) and "tick marks". Including 10 tick marks produces a nice labeling for arbitrary data.
As long as you meet these requirements, you are welcome to add any further details or customizations that you wish!
You should draw the chart using Python's Turtle Graphics module. This module provides all the functionality needed to create a graphical window and draw visual content to it (via commands to the turtle). Look at the summary list of methods, and then click on the links to see more details about how to use that method. You can also check out this tutorial for further examples and information.
You will need to create a new
Screen (window) for the turtle to draw in. You will need to specify the size and title for this screen.
It's useful to define the screen width and height as global constants, so that you can easily reference and change them.
setworldcoordinates() function can be useful for moving the "origin" of the coordinate system, allowing you to draw everything relative to the bottom corner of the chart (rather than the middle of the window).
You will also need to create a
Turtle object to draw with. You can then call methods on this value in order to tell it how to move and draw.
Pro Tip: If you make the turtle move faster, you won't have to wait as long for it to draw your chart as you run and re-run your program while developing and testing it.
Drawing even this simple chart using the turtle will take many, many instructions (lines of code). Thus in order to keep your program clear and to avoid repetition, you should abstract your drawing "algorithm" into a number of reusable functions. These functions can then be called by your script in order to have the turtle draw individual components of the chart. Do not just write a giant list of instructions! Break them up into functions instead!
Try to think about what "actions" you need your program to perform, and create a function for each of those actions. If a function becomes longer than 20 or so instructions, you should think about breaking it up into separate actions and then composing those functions (calling one functions from inside another).
Additionally, since you are designing these functions on your own, you must be sure to document them effectively. Every function in your program should include a doc string. The doc string should include descriptions of (1) what the function does, (2) the expected arguments, (3) the returned value if any.
At a minimum, your code should include the following functions. Note that each of these functions should take in a
turtle as a one of their parameters, so that you can theoretically have multiple turtles draw your chart (and to avoid global variables).
draw_axes() should draw the axes for the chart, including the tick marks and labels on on the y-axis (the labels on the x-axis can possibly be drawn as part of the bars themselves; see below).
Use a loop to draw the labels and tick marks; do not write the same code 10 times!
The default font that the turtle draws text with is rather small. You can make it more readable by passing in a triple to the appropriate method. This is a set of 3 values separated by commas and surrounded by parentheses. For example:
("Arial",14,"normal") represents 14pt Arial. We'll talk about triples more later in the course.
You can calculate the height of the y-axis "tick" marks, by dividing the height of the chart in pixels by the maximum data value (e.g., calculated using your previously written function). Be sure that you only rely on global variables if they are CONSTANTS; otherwise values should be passed in as arguments.
You will likely want to break this function up further. For example,
This section intentionally doesn't tell you which functions to create or what parameters they should take; making those decisions are part of the challenge of the assignment!
draw_rectangle() should draw a single rectangle on the screen. The function should be abstract enough that it can be used to draw rectangles at different locations, of different widths and heights, and of different colors. Have your function take appropriate arguments!
draw_bars() should draw all the bars for the chart on the screen. This function can read through the data file, determine the size and position of rectangles that need to be drawn, and then call the
draw_rectangle() function to draw each one.
Note that you should think about looping through the number of observations, reading three lines from the file for each observation (the third line, data feature 2, you will likely discard).
You can calculate the width of each rectangle by dividing the width of the chart by the number of observations (e.g., calculated using your previously written function). Note that you will want to reduce that width by some amount in order to include some space between each bar. Include space between the bars and the y-axis.
This function can be also used to draw the x-axis labels, positioning them below each of the bars (once those locations have been determined). You will likely want to create a separate function (e.g.,
draw_x_axis_label()) for that.
choose_color() should return an appropriate color for the bar based on some set of criteria. How you choose the color of the bar is up to you: the example above uses the "index" of the observation to choose the color, but you can also have the color be based on the data values, the labels, or some other condition. Your function should perform the logic to make that decision.
You can use whatever colors you want, but you should find an appealing color palette. Color Brewer has a nice set of options, as does Adobe (and many other sites).
It is up to you to determine exactly what functions to include and what their parameters should be. Think about how you can make the functions reusable, such as for drawing a different kind of chart (e.g., a scatterplot, or a horizontal bar chart). If you get stuck or have questions, ask for help!
Once you've met the core requirements, there are a number of extra extensions or features you can consider adding to your program.
Add additional elements to your chart to also illustrate the second data feature. This can either be by creating a stacked bar chart, or by putting two bars side by side. Alternatively you can add in an entire additional chart (so your turtle draws two of them); I'm convinced that drawing a pie chart would be fun.
Add extra decorations to your chart to help with its readability. For example, draw a dotted line across the chart starting at each tick mark.
Prompt the user for different color palettes for the chart (e.g., a "light" or "dark" theme). This information could then be used by your
In order to submit this assignment
Confirm that you've successfully completed the assignment. We should be able to run your script, specify an appropriate data file, and see the drawn bar chart.
Make sure that you've filled out the Submission form for this assignment, answering all the questions.
commit the final version of your work, and
push your code to your GitHub repository.
Submit the URL of your GitHub Repository as your assignment submission on Canvas (this page, at the top).