In this lab, we are going to write a function, scatterplot, which takes a list of [x, y] lists, and which uses the turtle library to draw a scatter plot like the one below. There are several goals:

Image of scatter plot

Note some of the features of this scatter plot:

Top-down and bottom-up problem solving

Top-down problem solving (sometimes called decomposition) involves taking a hard problem (like drawing a scatter plot), and breaking it into smaller, more manageable, problems. Bottom-up problem solving goes the other direction: starting with small pieces you know how to do (like drawing a line for an axis on the plot), and using these to create more powerful tools you can use to solve bigger problems.

You probably already used these strategies in the drawing project, but it's a good time to mention them explicitly.

Transforming data with functions

Now that you have done some top-down thinking, we are going to work from the bottom-up, writing some simple functions which transform data in useful ways. First, we need a few new tools for writing functions.

πŸ’» Open and skim the contents. Each of these functions currently raises an error which will intentionally crash your program with an error message saying the function isn't finished. Delete these error messages, and instead write the functions so that they return the correct values.



>>> minimum([1, 2, 3])
>>> minimum([-40, -60, -80])
>>> minimum(range(1000))

The simplest strategy for finding the minimum value is to create a variable to store the lowest number. Then iterate through data, checking to see whether each number is lower than the previous lowest. If so, then it's the new lowest number:

1def minimum(data):
2 lowest = None
3 for number in data:
4 if lowest is None:
5 lowest = number
6 if number < lowest:
7 lowest = number
8 return lowest

A few points to note:



>>> maximum([1, 2, 3])
>>> maximum([-40, -60, -80])
>>> maximum(range(1000))

This function is almost exactly the same as minimum, but instead of lowest, you should keep track of the highest number in the list and return it at the end.



>>> bounds([1, 2, 3])
[1, 3]
>>> bounds([-40, -60, -80])
[-80, -40]
>>> bounds(range(1000))
[0, 999]

Now that you have minimum and maximum, this function will be easy to write.

clamp(value, low, high)


>>> clamp(10, 0, 100)
>>> clamp(-10, 0, 100)
>>> clamp(104, 0, 100)

ratio(value, low, high)


>>> ratio(5, 0, 10)
>>> ratio(167, 100, 200)
>>> ratio(8, 10, 0)
>>> ratio(4, 10, 20)

The formula for ratio is simple. We divide the distance traveled (value - start) by the total distance to be traveled (end - start). Don't forget to clamp value, so that the return is always between 0.0 and 1.0.

(value - start)/(end - start)

scale(value, domain_min, domain_max, range_min, range_max)


>>> scale(4, 0, 10, 0, 100)
>>> scale(160, 120, 240, 0, 100)

In the scatter plot, we will use scale to figure out where points should be drawn on the screen. The x- and y-ranges of the data need to be scaled to the size of the plot on the screen. To scale a value, find its ratio in the domain (using ratio) and then find the equivalent value in the range. If r is the ratio, then the scaled value will be:

range_min + r * (range_max - range_min)



>>> get_x_values([[0, 5], [1, 5], [2, 5]])
[0, 1, 2]

This function is pretty straightforward--given a list of 2-item lists, returns a list of just the first item from each list. Here are a few useful tools for interacting with lists:



>>> get_x_values([[0, 5], [1, 5], [2, 5]])
[5, 5, 5]

Building the scatter plot

Now we will use these functions to create a scatter plot.

πŸ’» Open and skim the code. Also open and, as you will need to use functions provided in these modules. (They have already been imported into for you.) Then, using the plan below, implement the scatterplot function and its sub-functions.

Drawing a scatterplot

This function is completed for you. All it does is call other functions:

Drawing the axes

draw_axes is responsible for drawing the scatter plot's axes. Here's the plan for drawing the x-axis:

Here's what that plan looks like in code:

x_values = get_x_values(data)
xmin, xmax = bounds(x_values)
ticks = get_tick_values(xmin, xmax)
for tick in ticks:
    screen_x_position = scale(tick, xmin, xmax, 0, constants.PLOT_WIDTH)
    draw_x_tick(screen_x_position, tick)

You'll need similar code for the y-axis.

Drawing the points

Drawing the points is a bit easier than drawing the axes. Here's the plan: