The primary goals of this lab are to continue using Top-Down-Design principles in conjunction with linear and binary search techniques to process geographic data.
Please read through the entire lab before starting!
Make sure all programs are saved to your cs21/labs/08
directory. Files outside this directory will not be graded.
$ update21
$ cd ~/cs21/labs/08
Note: This is a one week lab. Last lab you a full week to practice the TDD component and a second week to implement your solution. Since the design should be similar to the previous lab, you will be doing the design and implementation in a single week. If you found the open-ended nature of the last lab challenging, you will want to start this lab early.
Is 12345 a valid ZIP code? What is the ZIP code for Truth or Consequences, NM? Your assignment this week is to create a program zipcodes.py
that allows a user to explore a ZIP code database. ZIP codes are used by the US Postal service to direct mail to cities more efficiently. An Online Interactive Viewer allows you to rapidly see how ZIP codes are distributed nationally (sadly, Alaska and Hawaii are omitted from the demo), and can help you find the names of places associated with any ZIP code.
The file /usr/local/doc/zipcodes.txt
contains ZIP code data for most of the United States (don't copy this file to your 08 directory, just use "/usr/local/doc/zipcodes.txt"
as the file name in your python program). Each line of the file contains the following fields separated by commas:
ZIP code
Latitude
Longitude
City name
County name
State
Population
The entry for Swarthmore is shown here:
19081,39.897562,-075.346584,Swarthmore,Delaware,PA,9907
For this lab, your program should prompt the user with a menu of 5 choices:
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
You program should ask the user for a valid choice and then perform the following queries listed below for each menu option, then return to the main menu again until the user selects option 5. Quit.
For option 1 (Find a ZIP code) you must:
Some examples are shown below:
Welcome to the zipcode program!
Please select one of the following choices:
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
Choice? 1
Enter a 5-digit ZIP code: Corgis
Corgis is not a valid ZIP code. Try again.
Enter a 5-digit ZIP code: 19081
Swarthmore, PA, 19081
Delaware County
Population: 9907
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
Choice? 1
Enter a 5-digit ZIP code: 99709
Fairbanks, AK, 99709
Fairbanks North Star County
Population: 52316
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
Choice? 1
Enter a 5-digit ZIP code: 99999
No info on this ZIP exists.
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
For option 2 you must:
startswith()
may be helpful.1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
Choice? 2
Enter a city prefix: Corgiville
Sorry... I can't find any info about that name...
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
Choice? 2
Enter a city prefix: Swart
Swartswood, NJ 07877 Population: 0
Swarthmore, PA 19081 Population: 9907
Swartz Creek, MI 48473 Population: 19655
Swartz, LA 71281 Population: 0
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
Choice? 2
Enter a city prefix: Pittsburgh
Pittsburgh, PA 15201 Population: 736800
Pittsburgh, PA 15202 Population: 736800
Pittsburgh, PA 15203 Population: 736800
Pittsburgh, PA 15204 Population: 736800
Pittsburgh, PA 15205 Population: 736800
Pittsburgh, PA 15206 Population: 736800
Pittsburgh, PA 15207 Population: 736800
[...Many results omitted from this lab writeup...]
[...Your program should list them all...]
Pittsburgh, PA 15278 Population: 736800
Pittsburgh, PA 15279 Population: 736800
Pittsburgh, PA 15281 Population: 736800
Pittsburgh, PA 15282 Population: 736800
Pittsburgh, PA 15283 Population: 736800
Pittsburgh, PA 15285 Population: 736800
Pittsburgh, PA 15286 Population: 736800
Pittsburgh, PA 15290 Population: 736800
Pittsburgh, PA 15295 Population: 736800
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
Choice?
For option 3 you must:
PA
p
.p
in a different color.1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
Choice? 3
Enter a two-letter state postal code: BC
Enter a population threshold for big cities: 23
No state found for BC
No info for state BC found
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
Choice? 3
Enter a two-letter state postal code: PA
Enter a population threshold for big cities: 100000
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
For option 4 you must:
Choice? 4
Enter a 5-digit ZIP code: 99999
No info on this ZIP exists.
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
Choice? 4
Enter a 5-digit ZIP code: 19801
Wilmington, DE, 19801
New Castle County
Population: 219067
1. Find by ZIP code
2. Find by name
3. Map state
4. Map county
5. Quit
You should practice good top-down design, incrementally implement and test your solution, and document your code with comments. Start with the main menu and get a skeleton of your code working first. Then add each option from the menu one at a time (start with quit as it is easy and will allow you to exit your program when you are testing it). While much of the design is up to you, the requirements below are designed to avoid some headaches in the initial design.
The boundaries
library has some helpful tools for managing the ZIP code data.
from boundaries import *
The first tool is a small ZipCode
class. You can create a new ZipCode
object by providing a ZIP, latitude, longitude, city name, county name, state name, and population to the ZipCode
constructor. It is expected that latitude and longitude are floats
, population is an int
, and all other parameters, including ZIP codes are strings
. The following ZipCode
methods allow you to access the information of a single ZipCode
object
getZip()
return ZIP as stringgetName()
return city namegetState()
return two letter state abbreviationgetCounty()
return county name (or county equivalent, e.g., LA has parishes, AK has boroughs)getLatitude(), getLongitude()
return float positionsgetPopulation()
return estimate of ZIP population as integerlat = 39.897562
long = -075.346584
place = ZipCode("19081", lat, long, "Swarthmore", "Delaware", "PA" , 9907)
print(place.getZip())
To create a list of all the places from a file, you could use a sample function like the one below:
def readData(filename):
"""
Read file of zip data, return list of
zipcode objects
"""
allzips = []
f = open(filename)
for line in f:
line = line.strip().split(",")
place = ZipCode(line[0], float(line[1]), float(line[2]),
line[3], line[4], line[5], int(line[6]))
allzips.append(place)
f.close()
return allzips
The second tool is the getStateGraphWin(state)
function. If you provide this function a valid two letter state abbreviation, the function will create and return a GraphWin
object with the boundary of the state shown in black and the coordinate of the window set to be the minimum and maximum longitudes and latitudes of the state using setCoords
. If the provided state
variable is not a valid abbreviation, a special None
object is returned. The None
type is not a GraphWin
object and you cannot do anything with it besides check if it is None
. Below is a sample use of the function.
state="PA"
win = getStateGraphWin(state)
if win == None:
print("Oops, something went wrong!")
return
# otherwise, window is OK. You can do more drawing here
# wait for mouse click before closing
win.getMouse()
win.close()
ZipCode
objects. Reading the file once will make it faster to process later. Using the ZipCode
list will avoid some list of list headaches. For examples, if your list of all locations is called allzips
, then you should be able to do the following place = allzips[10]
print(place.getName())
split()
only generates a list of strings. Some of the strings may need to be converted to other types.y
-like coordinate. Longitude is x
-like. Mixing these up will likely cause you to not see any cities on your map if everything else is working correctly. from boundaries import *
win = getStateGraphWin("PA")
#Only one of these points will display on the PA map
pt1 = Point(-76, 40)
pt2 = Point(40, -76)
pt1.setFill("black")
pt2.setFill("gold")
pt1.draw(win)
pt2.draw(win)
win.getMouse()
win.close()
The ZIP Code data file we have provided you is by no means complete. Some ZIP codes were missing or did not have lat/long data and were removed. For some cities, we did not have population data, so we set the population arbitrarily to 0.
Each lab has a short questionnaire at the end. Please edit the QUESTIONS-08.txt
file in your cs21/labs/08
directory and answer the questions in that file.
Don't forget to run handin21
to turn in your lab files! You may run handin21
as many times as you want. Each time it will turn in any new work. We recommend running handin21
after you complete each program or after you complete significant work on any one program.