The Government of Ontario collects a huge amount of data on provincial programs and infrastructure, and much of it is provided as open data sets for public use. In this assignment, we'll work with a particular dataset that contains information about provincially owned and maintained bridges in Ontario. All bridges in Ontario are reviewed every 2 years, and their information is collected to help determine when bridges need inspection and maintenance. In this assignment, you will write several functions to help explore and process real data about the bridges in Ontario, and simulate how inspectors get assigned to various bridges.
The data you'll be working with is provided by the Ontario government and contains information about all bridges in the Ontario highway network, such as the length of the bridges, their condition over various years, and historical information. We are working with one of the previous versions of this dataset for this assignment, which we slightly cleaned to be more suitable for this assignment, but .
The purpose of this assignment is to give you practice using the programming concepts that you have seen in the course so far, including (but not limited to) strings, lists and list methods, and loops.
This handout explains the problem you are to solve, and the tasks you need to complete for the assignment. Please read it carefully.
Goals of this Assignment
• Continue to use the Function Design Recipe (design recipe.pdf ) to plan, implement, and test functions. • Design and write function bodies using lists and list methods, loops, and file reading. (You can do this whole assignment with only the concepts from Weeks 1 through 6 of CSCA08.) • Practice good programming style.
Files to Download
Please download the Assignment 2 Data Files (a2.zip ) and extract the zip archive. A description of each of the files that we have provided is given in the paragraphs below:
Starter code: bridge_functions.py The bridge_functions.py file contains some constants, and a couple of complete helper functions that you may use. You must not modify the provided helper functions. The Lbridge_functions.py 'file also contains function headers and docstrings for the A2 functions to which you are required to add function bodies. Data: bridge_data.csv The bridge_data.csv file contains bridge data in comma-separated values (CSV) format. You must not modify this file.
For this assignment, you will use data from a Comma Separated Value (CSV) file named (bridge_data.csv). Each row of this file contains the following information about a single bridge:
• bridge label: a label representing the bridge. • bridge name: the name of the bridge. • highway name: the name of the highway (not necessarily unique). • latitude: the latitude of the centre of the bridge. • longitude: the longitude of the centre of the bridge. • year built: the year the bridge was built. • last major rehab: the year the last major rehabilitation was performed on the bridge. • last minor rehab: the year the last minor rehabilitation was performed on the bridge. • number of spans: the number of spans of the bridge. • span details: the detail of each span. 0 This is in the format: [Total=[total length of all spans] (1)=[the length of the first span] ; (2)=[the length of the second span] ; and so on for each span of the bridge. • length: the length of the bridge (this can differ from the total length of all spans). • last inspection date: the date that the bridge was last inspected (in MM/DD/YYYY format). • last inspected index: the bridge condition index (BCI) from the last inspection (Bridge condition indexes (BCI) are numeric scores representing the condition of a bridge. The lower the BCI, the worse the condition of the bridge.) • bridge condition indexes (BCIs): numeric scores representing the condition of the bridge over time.
Imagine that it is your job to manage Ontario's highway network. As the manager, you need to know everything about the bridges. But, there are hundreds of highways and associated bridges, which is way too many to keep track of in your head. To make your life easier, you will write Python functions to help you manage the information.
Your functions will fall into three categories: functions for data formatting, functions for data queries, and functions for data modification. Here are the functions you are required to implement:
• Data formatting functions: format_data (do not start with this!) • Data query functions: • get_bridge o (get_average_bci o (get_total_length_on_highway o (get_distance_between) • find_closest_bridge o (find_bridges_in_radius • get_bridges_with_bci_below o [assign_inspectors'i • get_bridges_containing • Data modification functions: o (inspect_bridges o fadd_rehab9
For each function, read the header and docstring (especially the examples) in the starter code Il';r;idge_functions.py to learn what task the function performs. Doing so will help you to determine what you need to do for each required function. To gain a better understanding of each function, you may want to add another example to the docstring.
For most functions, the description and examples provided in the starter code gives you enough information to get started. We have provided additional information about the I format_data and assign_inspectors functions below.
Formatting the data ( format_dataj) We provided a function named read_data that reads data from a CSV file and returns it in a List[List[str]] . Here is a sample of the type of list returned (we added spacing here for readability that you won't see in Python):
(U1 - 32/', 'Highway 24 Underpass at Highway 403', '403', '43.167233', '-80.275567"1965', '2014', '2009', '4', 'Total=64 (1)=12;(2)=19;(3)=21;
(4)=12;', '65', '04/13/2012', '72.3', ", '72.3', ", '69.5', ", '70', ", '70.3', ' , '70.5', ' ', '70.7', '72.9', "],
- 43/', 'WEST STREET UNDERPASS', '403', '43.164531', '-80.251582', '1963', '2014', '2007', '4', 'Total=60.4 (1)=12.2;(2)=18;(3)=18;(4)=12.2;', '61', '04/13/2012', '71.5', ", '71.5', ", '68.1', ", '69', ' , '69.4', ", '69.4', ' , '70.3', '73.3', "],
'2 - 4/', 'STOKES RIVER BRIDGE', '6', '45.036739', '-81.33579', '1958', '2013', ' '1', 'Total=16 (1)=16;', '18.4', '08/28/2013', '85.1', '85.1', '
'67.8', ", '67.4', ", '69.2', '70', '70.5', ", '75.1', ', '90.1', "]
Notice that all of the data in the inner lists are represented as strings. You are to write the function (format_data , which should make modifications to the list such that it follows this format:
|Format of data to be returned by format_data for A2. Index||Data||Type||Description|
|0||ID||int||The ID of the bridge.|
|1||Name||I str I||The name of the bridge.|
|2||Highway||I str||The name of the bridge's highway.|
|3||Latitude||float||The latitude of the bridge.|
|4||Longitude||The longitude of the bridge. lifloat|
|5||Year Built||1 str||The year the bridge was built. If no year is provided, this will be an empty string.|
|6||Last Major Reha||Lstr||The year of the last major rehab. If no year is provided, this will be an empty string.|
|7||Last Minor Rehab||str I||The year of the last minor rehab. If no year is provided, this will be an empty string.|
|8||Number of Spans||int I||The number of spans on the bridge. A bridge will always have at least 1 span.|
|9||Span Details||List[float]||The length of each of the spans of the bridge. Example: If the Span Details in the unformatted data was: Total=64 (1)=12,(2)=19;(3)=21;(4)=12; And the bridge had 4 spans, then the formatted version should be the following l|
|10||Bridge Length float||The length of the bridge. If no length is provided, this will be ;0.0 .|
|11||Last Inspected Date||(str)||The date of the last inspection (in MM/DD/YYYY format). If no date is provided, this will be an empty string.|
|12||BCIs||List[float]||A list of the BCIs from the most recent to the least.|
If the bridge has no BCIs, then this should be an empty list.
After applying the (format_data) function to the example list, it should look like:
[, 'Highway 24 Underpass at Highway 403', '403', 43.167233, -80.275567, '1965', '2014', '2009', 4, [12.0, 19.0, 21.0, 12.0], 65.0,
'04/13/2012', 72.3, 69.5, 70.0, 70.3, 70.5, 70.7, 72.9]],
[[2, 'WEST STREET UNDERPASS', '403', 43.164531, -80.251582, '1963', '2014', '2007', 4, [12.2, 18.0, 18.0, 12.2], 61.0, '04/13/2012', [71.5, 68.1, 69.0, 69.4, 69.4, 70.3, 73.3]],
[3, 'STOKES RIVER BRIDGE', '6', 45.036739, -81.33579, '1958', '2013', ", 1, [16.0], 18.4, '08/28/2013', [85.1, 67.8, 67.4, 69.2, 70.0, 70.5, 75.1, 90.1]])
Before you write the format_data function body, please note: • you must not use the built-in function eva, and • this function is one of the more challenging functions in A2, so we suggest that you don't start with it.
Assigning Inspectors (function (assign_inspectors
Bridge condition indexes (BCI) represent the condition of a bridge on a past inspection, and we use the most recent BCI to prioritize certain bridges. There are three levels of priorities, with their upper limits represented by the constants HIGH_PRIORITY_BCI), (MEDIUM_PRIORITY_BCI), LOW_PRIORITY_BCI , constrained by HIGH_PRIORITY_BCI < MEDIUM_PRIORITY_BCI < LOW_PRIORITY_BCI .
For example, if (HIGH_PRIORITY_BCI' is 60, then all bridges with their most recent BCI less than or equal to 60 are considered 'high priority'. Similarly, if MEDIUM_PRIORITY_BCf is 70, then all bridges with a BCI less than or equal to 70 (but > 60) are considered 'medium priority'.
When assigning bridges to inspectors, we want to prioritize nearby high priority bridges within a large radius of the inspector over medium priority bridges that are closer, and both of those are prioritized over low priority bridges in an even smaller radius.
The radiuses are specified by the constants [HIGH_PRIORITY_RADIUS1, (MEDIUM_PRIORITY_RADIUS , and [LOW_PRIORITY_RADIUSJ.
You are told the maximum number of bridges to assign per inspector. The way we want to assign bridges to inspectors is as follows:
- High priority bridges with a distance <= HIGH_PRIORITY_RADIUS from the inspector.
- If (1) assigned fewer than the maximum number of bridges, then we go on to assign medium priority bridges with a distance <= MEDIUM_PRIORITY_RADIUS from the inspector.
- If (1) and (2) still assigned fewer than the given maximum number of bridges, then we go on to assign low priority bridges with a distance <= LLOW_PRIORITY_RADIUS j from the inspector.
One inspector at a time, we assign the maximum number of bridges to each inspector (or fewer than the maxiumum number of bridges, if all bridges have already been assigned). Inspectors should be assigned bridges based on the order they appear in the list (e.g., the first inspector in the list should be assigned up to the maximum number of bridges first, the second inspector should be assigned up to the maximum number of bridges next, and so on).
Bridges are assigned to an inspector using as many bridges that fulfill (1) as possible, followed by (2), and then (3) if there are still fewer than the maximum number of bridges assigned to that inspector. If there are multiple bridges with the same priority and radius, we choose the bridge with the lowest ID (e.g., if there are two low priority bridges with IDs 3 and 4, we would assign the bridge with ID 3 first). Each bridge should be assigned to at most one inspector. You may want to use the find_bridges_in_radius and get_bridges_with_bci_below functions to help you with assigning inspectors.
Testing your Code
It is strongly recommended that you test each function as you write it. (You might be tempted to just plow ahead and write all of the functions and hope everything works, but then it will be really difficult to determine whether your program is working correctly.) As usual, follow the Function Design Recipe. Once you've implemented a function, run it on the examples in the docstring. Here are a few tips: • Be careful that you test the right thing. Some functions return values; others modify data in-place. Be clear on what the functions are doing before determining whether your tests work. • Can you think of any special cases for your functions? Will each function always work, or are there special cases to consider? Test each function carefully. • Once you are happy with the behaviour of a function, move to the next function, implement it, and test it. Additional requirements • Do not call print), (input), or (open . • Do not use any (break) or 1continuel statements. Any functions that do will receive a mark of zero. • Do not modify or add to the import statements provided in the starter code. Marking These are the aspects of your work that will be marked for Assignment 2: • Correctness (80%): • Your functions should perform as specified in this assignment handout. Correctness, as measured by our tests, will count for the largest single portion of your marks. Use the constants provided. We may test with different BCI priorities and radiuses. • Once your assignment is submitted, we will run additional tests, not provided in the checker. Passing the checker does not mean that your code will earn full marks for correctness. • Coding style (20%): • Make sure that you follow the Python Style Guidelines that we have introduced and the Python coding conventions that we have been using throughout the semester. • Your program should be broken down into functions, both to avoid repetitive code and to make the program easier to read. If a function body is more than about 20 lines long, introduce helper functions to do some of the work -- even if they will only be called once. • All functions, including helper functions, should have complete docstrings including preconditions when you think they are necessary. • Also, your variable names and names of your helper functions should be meaningful. Your code should be as simple and clear as possible.