Answered step by step
Verified Expert Solution
Question
1 Approved Answer
Part 2: ZIP Code Look up and Distance Calculation As part of the Open Data Policy, the U.S. Government released a large number of datasets.
Part 2: ZIP Code Look up and Distance Calculation
As part of the Open Data Policy, the U.S. Government released a large number of datasets. Among these is a dataset that provides geographic coordinates for U.S. 5 digit ZIP Codes which we will be using for this assignment. For each ZIP Code, this dataset lists geographic coordinates (latitude and longitude), city, state, and county. Our goal is to use available data to develop a new data product that would allow users not only to query and search the existing data source but also to access additional functionality such as computing the distance between two locations.
Write a program that would allow users to lookup locations by ZIP Code, lookup ZIP Codes by city and state, and determine the distance between two locations designated by their ZIP Codes. The program interacts with the user by printing a prompt and allowing them to enter commands until they enter 'end' at which point the program prints Done and finishes. If an invalid command is entered, the program prints Invalid command, ignoring and is ready to take the next command. All commands are case insensitive (i.e., can be typed using any case or a mixture of lower and upper case).
The following commands should be recognized:
1. loc allows the user to enter a ZIP Code, then looks up city, state, county, and geographic coordinates that correspond to the ZIP Code and prints this data. If the ZIP Code is invalid or not found in the dataset, the program prints an error message instead. Look at the following sample output:
Command ('loc', 'zip', 'dist', 'end') => loc
loc
Enter a ZIP Code to lookup => 19465
19465
ZIP Code 19465 is in Pottstown, PA, Chester county,
coordinates:(04240'25.32"N,07336'31.65"W)
Note that coordinates are enclosed in parentheses and are separated by a comma; each coordinate is printed in integer degrees (three digits), followed by the symbol, integer minutes (two digits), followed by the ' character, integer and fractional seconds (two integer and two decimal digits), followed by the " character, and a cardinal direction letter (N, S, W, or E) with no spaces anywhere in the coordinate representation.
2. zip allows the user to enter city and state, then looks up the ZIP Code or codes (some cities have more than one) which correspond to this location and prints them; if city and/or state are invalid or not found in the dataset, it prints an error message instead.
Command ('loc', 'zip', 'dist', 'end') => zip
zip
Enter a city name to lookup => troY
troY
Enter the state name to lookup => ny
ny
The following ZIP Code(s) found for Troy, NY: 12179, 12180, 12181, 12182, 12183
3. dist allows the user to enter two ZIP Codes and computes the geodesic distance between the location coordinates; if any of the ZIP Codes entered is invalid or not found in the dataset, it prints a corresponding error message instead.
Command ('loc', 'zip', 'dist', 'end') => dist
dist
Enter the first ZIP Code => 19465 19465
Enter the second ZIP Code => 12180 12180 The distance between 19465 and 12180 is 201.88 miles
4. end stops fetching new commands from the user and ends the program. Utility module hw4_util will give you some help. It provides a function read_zip_all() that returns a list each element of which is, in turn, a list that contains data about one ZIP Code. Try the following:
import hw4_util
zip_codes = hw4_util.read_zip_all() print(zip_codes[0])
print(zip_codes[4108])
and it should output:
['00501', 40.922326, -72.637078, 'Holtsville', 'NY', 'Suffolk']
['12180', 42.673701, -73.608792, 'Troy', 'NY', 'Rensselaer']
Note that the data on a particular ZIP Code has the following fields: ZIP Code (string), latitude (float degrees), longitude (float degrees), city (string), state (string), and county (string).
Implementation Details
When grading your code, we will be importing it as a module and then verifying that it works correctly by calling two functions with specific names and comparing the return values with expected data.
You will need to define these two functions by strictly following specifications outlined below:
1. zip_by_location(zip_codes, location) which finds the ZIP Code for a given location. Parameters: zip_codes a list of ZIP Codes data in the format, returned by read_zip_all(); location a two-element tuple where the first element is the city name and the second element is the state abbreviation, e.g., ('trOy', 'nY'). Both elements are string values. City names and state abbreviations can be typed using any case or a mixture of lower and upper case. Return value: A list which contains the ZIP Code or codes for the specified location. Each ZIP Code is a string value. If the location is invalid, an empty list is returned. E.g., ['12179', '12180', '12181', '12182', '12183'].
2. location_by_zip(zip_codes, code) which finds location information corresponding to the specified ZIP Code. Parameters: zip_codes a list of ZIP Codes and associated data in the format, returned by read_zip_all(); code ZIP Code as a string value, e.g. '12180'. Return value: A five-element tuple (latitude, longitude, city, state, county). Latitude and longitude are in fractional degrees (floating point values). All other elements are string values. If the ZIP Code is invalid, an empty tuple is returned. E.g., (42.673701, -73.608792, 'Troy', 'NY', 'Rensselaer').
It is required that you implement functions according to specifications given above. Remember, if your functions do not follow these requirements (e.g., you named them something else, or they expect an argument or return a value which are different from what is described above), our attempt to call your function might fail, and you will lose points.
You are also expected to define other functions, as necessary. You need to determine which functions to define and to design their specifications yourself, following the example we gave above for the two required functions. Do not forget to include function specifications as a docstring immediately below the functions definition in your code. Avoid copying and pasting repeated pieces of code. Those should be factored out as functions. You may lose points for excessive duplication of code.
Make sure that when your code is imported as a module, it does not print anything and does not attempt to ask the user to input any values. The main body of your program should be behind a corresponding if statement, so that the main code is executed only when your Python file is run directly and is not executed when your module is imported somewhere else.
Hints and Suggestions
Formatting your output is a big part of this program. Here are a few hints.
1. The symbol can be generated using another escape character similar to or \". To generate the , use \xb0. Just like the newline or a double quote, this is a single character.
2. You may find tuple() function useful if you need to convert a list to a tuple, e.g., tuple(["RPI", "Private", 7962]).
3. If you want to print leading 0s before an integer, use the {:0Nd} where N is the total number of character positions you want the integer to occupy. So, a format of :07d will use 7 character positions to print your integer, padding the front of the integer with 0s. I.e., print("{:07d}".format(7)) will give 0000007
4. You will need to manage the latitude and longitude to convert among representations. In particular, you need to convert the fractional degrees in the ZIP Code list to degrees, minutes, and seconds. There are 60 minutes in a degree and 60 seconds in a minute. When you convert, all of your latitudes and longitudes should be positive. Instead, use east (E) and west (W) designators of longitude; and north (N) and south (S) designators for latitude. Negative longitudes are west, positive are east. Negative latitudes are south, positives are north. In both cases, a latitude or longitude of 0 (the equator or the prime meridian, respectively) do not have a designator.
5. The distance between two points on the surface of Earth uses a simplified haversine formula for arc length on a sphere. You should implement Eq. 1 which assumes the Earth to be spherical. This formula gives the shortest surface distance d as-the-crow-flies, ignoring Earths relief.
latitude = latitude2 latitude1
longitude = longitude2 longitude1
a = sin^2(latitude/2) + cos(latitude1) cos(latitude2) sin^2 (longitude 2)
d = 2R arcsin ( a )
Where R = 3959.191 miles is the radius of the Earth and all angle measurements are in radians (the ZIP Code data gives latitude and longitude in degrees). 360 degrees is equivalent to 2 radians.
An example of the program run. We will test your code with the values from the example file as well as a range of other values, including invalid commands and invalid ZIP Codes.
Example:
Command ('loc', 'zip', 'dist', 'end') => loc
loc
Enter a ZIP Code to lookup => 12180
12180
ZIP Code 12180 is in Troy, NY, Rensselaer county,
coordinates: (04240'25.32"N,07336'31.65"W)
Command ('loc', 'zip', 'dist', 'end') => loc
loc
Enter a ZIP Code to lookup => 1946
1946
Invalid or unknown ZIP Code
Command ('loc', 'zip', 'dist', 'end') => loc
loc
Enter a ZIP Code to lookup => 19465
19465
ZIP Code 19465 is in Pottstown, PA, Chester county,
coordinates: (04011'30.87"N,07539'55.12"W)
Command ('loc', 'zip', 'dist', 'end') => loc
loc
Enter a ZIP Code to lookup => 00000
00000
Invalid or unknown ZIP Code
Command ('loc', 'zip', 'dist', 'end') => loc
loc
Enter a ZIP Code to lookup => cairns
cairns
Invalid or unknown ZIP Code
Command ('loc', 'zip', 'dist', 'end') => dist
dist
Enter the first ZIP Code => 19465
19465
Enter the second ZIP Code => 12180
12180
The distance between 19465 and 12180 is 201.88 miles
Command ('loc', 'zip', 'dist', 'end') => dist
dist
Enter the first ZIP Code => 12180
12180
Enter the second ZIP Code => 12180
12180
The distance between 12180 and 12180 is 0.00 miles
Command ('loc', 'zip', 'dist', 'end') => dist
dist
Enter the first ZIP Code => 12180
12180
Enter the second ZIP Code => 55499
55499
The distance between 12180 and 55499 cannot be determined
Command ('loc', 'zip', 'dist', 'end') => zip
zip
Enter a city name to lookup => troY
troY
Enter the state name to lookup => ny
ny
The following ZIP Code(s) found for Troy, NY: 12179, 12180, 12181, 12182, 12183
Command ('loc', 'zip', 'dist', 'end') => zip
zip
Enter a city name to lookup => Amsterdam
Amsterdam
Enter the state name to lookup => NL
NL
No ZIP Code found for Amsterdam, NL
Command ('loc', 'zip', 'dist', 'end') => help
help
Invalid command, ignoring
Command ('loc', 'zip', 'dist', 'end') => END
END
Done
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started