Just two questions this week! Question 1 on this problem set is about using lists for tabulation and working with GCompound
s. Question 2 is about working with multidimensional arrays. Files are provided in the starting template linked before for both questions. Make sure you fill out the top metadata on each problem please!
Problem 1
A common form of tabulation is that of creating a “histogram”, wherein the different elements of the histogram array represent the counts of how many times a particular value (or range of values) showed up in a certain collection. For example, the first 16 digits of \pi look like:
= [ 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 5, 8, 9, 7, 9 ] PI_DIGITS
If we are dealing with single digits, then there are 10 possible values that we could want to count: the digits 0 through 9. It turns out that these digits map nicely to the index values of an array! So we could store how many times a 0 appears in PI_DIGITS
(0 times) in the index 0 element of our histogram, and the number of times the digit 1 appears (2 times) in the index 1 element, and so on. The entire histogram array, once populated, might look like:
showing that there are no 0s, two 1s, one 2, two 3s, etc. in the first sixteen digits of \pi.
Part A
Write a function called create_histogram_array(imax, data)
which takes two values as arguments:
- A maximum index
imax
, which represents the total number of possible things you would like to count. This would have been 10 in our above example. - A list of integers
data
, which represents the items for which you would like to tabulate a histogram.
This function should return a new list which has the histogram counts as each element. For example, your function should be able to mimic:
>>> create_histogram_array(5, [1, 0, 3, 2, 4, 2, 2, 1, 3, 0])
[2, 2, 3, 2, 1]
where imax
was chosen to be 5 since there were 5 different values appearing in the data
list (0 through 4). Note though that if your value of imax
is smaller than the variety of digits in data
, the later digits will not be counted. Only the first imax
digits will be counted. If imax
is larger than the number of different digits in data
, 0’s will be counted for those extra digits. So, for instance:
>>> create_histogram_array(3, [1, 0, 3, 2, 4, 2, 2, 1, 3, 0])
[2, 2, 3]
>>> create_histogram_array(8, [1, 0, 3, 2, 4, 2, 2, 1, 3, 0])
[2, 2, 3, 2, 1, 0, 0, 0]
Part B
Now that you can use your function from Part A to compute a histogram array, how about displaying it nicely to the screen? For this part, write a new function called print_histogram(array)
that take a histogram counts list (of the exact sort returned by create_histogram_array
!) as an argument. This function should print to the console a rotated histogram using asterisks to indicate the count of values in each index. For example, if you call print_histogram
with the histogram formed by the first 16 digits of \pi, you should see the following:
>>> print_histogram(create_histogram_array(PI_DIGITS))
0:
1: **
2: *
3: **
4: *
5: ****
6: *
7: *
8: *
9: ***
Your function should mimic this printing exactly. This should not be particularly complicated, as you have all the necessary tools with string formatting and the repetition operator for strings.
Part C
While printing to the console is one way to visualize a histogram, it is not the classical graphical way. So for this part, you should write a function called create_histogram_graph(array, width, height)
which will use PGL to create a histogram GCompound
. The array
parameter represents the same input array as from Part B (or the returned output from Part A), and the width
and height
parameters represent the desired size of the GCompound
. You will need to use these values to figure out how wide and tall each of your histogram rectangles should be. The function should return a GCompound
object that contains filled GRect
objects arranged to produce a traditional bar graph histogram, where the height of a particular box reflects the proportional number of items in that index in the histogram array. The scaling of the bars should be chosen so that the largest bar in the graph completely fills the desired height, and all the bars arranged next to one another should completely fill the desired width. The reference point of the GCompound
should be the upper left corner.
To illustrate how this part should work, it may help to consider the following simple test program, which is included in the code template:
def test_create_histogram_graph():
= 800, 600
WIDTH, HEIGHT = GWindow(WIDTH, HEIGHT)
gw = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 5, 8, 9, 7, 9]
PI_DIGITS = create_histogram_array(10, PI_DIGITS)
array = test_create_histogram_graph(array, WIDTH, HEIGHT)
graph gw.add(graph)
which should display the following graph so that it fills the graphics window:
Note that because create_histogram_graph
just returns to you a GCompound
, if you made 4 of them with half the width and height of the window, you could also display multiple across the screen by adding them at the correct coordinates:
Problem 2
A magic square is a two-dimensional array of integers in which the rows, columns, and diagonals all add up to the same value. One of the most famous magic squares appears in the 1514 engraving Melencolia I by Albrecht Dürer shown below, in which a 4x4 magic square appears in the upper right, just under the bell. In Dürer’s square, all four rows, all four columns, and both diagonals add up to 34.