Skip to content
Snippets Groups Projects
Commit 32fa6523 authored by Anna Meyer's avatar Anna Meyer
Browse files

p3 and lab3

parent 10b7ffad
No related branches found
No related tags found
No related merge requests found
Showing
with 5047 additions and 0 deletions
# lab3: Learning an API and some functions
### Corrections/Clarifications
- None yet.
**Find any issues?** Talk to your TA or peer mentor in lab, or create a Piazza post.
------------------------------
## Learning Objectives
In this lab, you will practice...
* Writing functions with return statements
* Importing a module and using its functions
* Using parameters' default values when calling functions
* Avoiding hardcoding by using a `get_id` function
* Working with the index of a row of data
------------------------------
## Note on Academic Misconduct
You may do these lab exercises only with your project partner; you are not allowed to start working on lab3 with one person, then do the project with a different partner. Now may be a good time to review [our course policies](https://canvas.wisc.edu/courses/355767/pages/syllabus?module_item_id=6048035).
------------------------------
## Project partner
We strongly recommend students find a project partner. Pair programming is a great way to learn from a fellow student. Project difficulty increases exponentially in this course. Finding a project partner early on during the semester is a good idea.
If you are still looking for a project partner, take a moment now to ask around the room if anyone would like to partner with you on this project. Then you can work with them on this lab as well as the project.
------------------------------
## Description
For many projects this semester, we'll provide you with a *module* (a collection of functions) named `project`, in a file named `project.py`. This module will provide functions that will help you complete the project. In the lab, we will introduce the module `project.py` which you will need to use in `p3`.
When using an unfamiliar module, the first thing you should do is study the module's *API*. API stands for "Application Programming Interface".
The API descibes everything a programmer needs to know about a piece of the module in order to use it. Understanding the API will involve learning about each function and the arguments it takes, and what functions might need to be called before you can use other functions.
There are two ways you can learn about an API. First, the person who created the API may have provided written directions, called *documentation*. Second, there are ways you can write code to learn about a collection of functions; this approach is called *inspection*.
------------------------------
## Segment 1: Setup
Create a `lab3` directory and download the following files into the `lab3` directory:
* `lab.csv`
* `project.py`
* `practice.ipynb`
* `practice_test.py`
Once you have downloaded the files, open a terminal and navigate to your `lab3` directory. Run `ls` to make sure the above files are available.
**Note:** If you accidentally downloaded the file as a `.txt` instead of `.csv` (say `lab.txt`), you can execute `mv lab.txt lab.csv` on a Terminal/PowerShell window. Recall that the `mv` (move) command lets you rename a source file (first argument, example: `lab.txt`) to the destination file (second argument, example: `lab.csv`).
------------------------------
## Segment 2: Learning the `project.py` API
The file `project.py` contains certain *functions* that will be useful for you when you are solving `p3`. It is not necessary to understand *how* these functions work (although you will learn how they work within a few weeks), but to use this module, you need to know *what* these functions do.
When dealing with an unfamiliar module, the best way to learn what its functions are, and how to use them, is to study the module's API. In this segment, we will be learning how to do exactly that.
First, open a new Terminal/PowerShell window, and navigate to the `lab3` folder which contains `project.py`. From here, type `python` (or `python3` if that is what worked for you in [lab2](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab2)) to enter the Interactive Mode. It is also recommended that you review [lab2](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab2#task-16-exit-interactive-mode) on how to exit Interactive mode.
### Task 2.1: Using `dir`
From the Interactive mode, type the following command:
```python
>>> import project
```
This line *imports* the `project` module, so you can use the functions inside it. If you want to use any of the functions inside any module, you will have to import it first. But before we can use the functions inside this module, we need to find out *what* functions are inside this module. To do that, type the following command in Interactive mode:
```python
>>> dir(project)
```
You should see the following output:
```
['__builtins__', '__cached__', '__csv__', '__doc__', '__file__', '__id_to_data__', '__loader__', '__name__', '__name_to_id__', '__package__', '__spec__', '__years__', 'dump', 'get_id', 'get_sales', 'init']
```
The functions inside this module that will be relevant to us are the ones that do **not** begin and end with two underscores.
### Task 2.2: Inspecting `project.py`
Now that we know the functions inside the module that we can call, we need to figure out *what* these functions do. One way to do that is to just try and call them. Try the following on Interactive mode:
```python
>>> project.dump()
```
You will likely see the following error message:
```
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\myname\Documents\cs220\lab3", line 49, in dump
raise Exception("you did not call init first")
Exception: you did not call init first
```
This tells us that before we can call `project.dump`, we will need to call the `project.init` function.
### Task 2.3: Using `help`
We can continue to try and inspect the other functions in the `project` module to figure out what they do. However, most modules come with *documentation* explaining what each of the functions does, and it can save us time if we read this documentation. Try the following on Interactive mode:
```python
>>> help(project.init)
```
You should see the following output:
```
Help on function init in module project:
init(path)
init(path) must be called to load data before other calls will work. You should call it like this: init("car_sales_data.csv") or init("lab.csv")
```
**Note:** If you are using Mac OS, you **may** enter **Python help mode** when you type `help(project.init)`. You can recognize that you are in help mode if you no longer see the prompt `>>>` appearing on your screen. You will not be able to execute other Python commands from this mode. In order to *exit* the help mode, you need to type `q` and hit the `RETURN` key. If you do not enter Python help mode, this is unnecessary.
The documentation here tells us that the function `init` takes in a `path` such as `lab.csv`, or `car_sales_data.csv` (which you will work with in p3) as its argument, and loads the data from the file into the Python program. Can you now understand what the Traceback was telling us when we called `project.dump` earlier?
Let us now load the data from `lab.csv`. Execute the following command on Interactive mode.
```python
>>> project.init('lab.csv')
```
**Note:** If you load the file `lab.csv` correctly, you will see the following warning message:
```
WARNING! Opening a path other than car_sales_data.csv. That's fine for testing your code yourself, but car_sales_data.csv will be the only file around when we test your code for grading.
```
That is to be expected. It is warning you that for the project `p3`, you will not be working with the data in `lab.csv`, but instead, the data in `car_sales_data.csv`, and that you should be careful not to load in the wrong file when working on `p3`.
Now that we have loaded in our data, let us now see what `project.dump` does. Execute the following command on Interactive mode.
```python
>>> help(project.dump)
```
You should see the following output:
```
Help on function dump in module project:
dump()
prints all the data to the screen
```
Can you figure out what this function does, and how to call it? Call the function yourself. You should see the following output:
```
Chevy Bolt [ID: 21]
2019: 16313 cars sold
2020: 20754 cars sold
2021: 24828 cars sold
Chrysler Pacifica Plug-in Hybrid [ID: 3664]
2019: 5811 cars sold
2020: 9165 cars sold
2021: 28747 cars sold
Honda Clarity Plug-in [ID: 426]
2019: 10728 cars sold
2020: 4157 cars sold
2021: 2366 cars sold
Porsche Cayenne S E-Hybrid [ID: 6273]
2019: 1140 cars sold
2020: 1758 cars sold
2021: 1783 cars sold
Tesla Model 3 [ID: 850]
2019: 154840 cars sold
2020: 122700 cars sold
2021: 121877 cars sold
```
This is data on the number of a few select models of electric cars sold between 2019 and 2021. If you manually open `lab.csv` using Microsoft Excel or some other Spreadsheet software, you will find this data stored there.
We now need to figure out how to use the other functions in the module. Read the *documentation* using `help` to figure out what the following functions do:
- `project.get_id`
- `project.get_sales`
------------------------------
## Segment 3: Solving `practice.ipynb`
You will be finishing the rest of your lab on `practice.ipynb`. Exit Python Interactive mode on your Terminal/PowerShell (using the `exit` function, as in [lab2](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab2#task-16-exit-interactive-mode)), and run the command `jupyter notebook`. Remember not to close this terminal window while Jupyter is running, and open a new Terminal window if necessary.
**Note:** For `p3`, you will be working on `p3.ipynb` which is very similar to `practice.ipynb`. It is strongly recommended that you finish working on this notebook during the lab, so you can ask your TA/PM any questions about the notebook that may arise.
**Note:** Unlike `p3.ipynb`, you do **not** have to submit `practice.ipynb`. This notebook is solely for your practice.
------------------------------
## Project 3
Great, now you're ready to start [P3](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/projects/p3)! Remember to only work with your partner from this lab on p3 from this point on. Have fun!
id,vehicle,2019,2020,2021
21,Chevy Bolt,16313,20754,24828
3664,Chrysler Pacifica Plug-in Hybrid,5811,9165,28747
850,Tesla Model 3,154840,122700,121877
426,Honda Clarity Plug-in,10728,4157,2366
6273,Porsche Cayenne S E-Hybrid,1140,1758,1783
\ No newline at end of file
This diff is collapsed.
#!/usr/bin/python
import os, json, math
REL_TOL = 6e-04 # relative tolerance for floats
ABS_TOL = 15e-03 # absolute tolerance for floats
PASS = "PASS"
TEXT_FORMAT = "text" # question type when expected answer is a str, int, float, or bool
expected_json = {"1": (TEXT_FORMAT, 850),
"2": (TEXT_FORMAT, 426),
"3": (TEXT_FORMAT, 3664),
"4": (TEXT_FORMAT, 154840),
"5": (TEXT_FORMAT, 154840),
"6": (TEXT_FORMAT, 1758),
"7": (TEXT_FORMAT, 24828),
"8": (TEXT_FORMAT, 220),
"9": (TEXT_FORMAT, 200),
"10": (TEXT_FORMAT, 400),
"11": (TEXT_FORMAT, 19.0),
"12": (TEXT_FORMAT, 42.5),
"13": (TEXT_FORMAT, 50),
"14": (TEXT_FORMAT, 30),
"15": (TEXT_FORMAT, -8.0),
"16": (TEXT_FORMAT, 1.0),
"17": (TEXT_FORMAT, -0.2857142857142857),
"18": (TEXT_FORMAT, -1.25),
"19": (TEXT_FORMAT, -0.1111111111111111),
"20": (TEXT_FORMAT, -0.6666666666666666)}
def check_cell(qnum, actual):
format, expected = expected_json[qnum[1:]]
try:
if format == TEXT_FORMAT:
return simple_compare(expected, actual)
else:
if expected != actual:
return "expected %s but found %s " % (repr(expected), repr(actual))
except:
if expected != actual:
return "expected %s" % (repr(expected))
return PASS
def simple_compare(expected, actual, complete_msg=True):
msg = PASS
if type(expected) == type:
if expected != actual:
if type(actual) == type:
msg = "expected %s but found %s" % (expected.__name__, actual.__name__)
else:
msg = "expected %s but found %s" % (expected.__name__, repr(actual))
elif type(expected) != type(actual) and not (type(expected) in [float, int] and type(actual) in [float, int]):
msg = "expected to find type %s but found type %s" % (type(expected).__name__, type(actual).__name__)
elif type(expected) == float:
if not math.isclose(actual, expected, rel_tol=REL_TOL, abs_tol=ABS_TOL):
msg = "expected %s" % (repr(expected))
if complete_msg:
msg = msg + " but found %s" % (repr(actual))
else:
if expected != actual:
msg = "expected %s" % (repr(expected))
if complete_msg:
msg = msg + " but found %s" % (repr(actual))
return msg
def check(qnum, actual):
msg = check_cell(qnum, actual)
if msg == PASS:
return True
print("<b style='color: red;'>ERROR:</b> " + msg)
import csv as __csv__
__id_to_data__ = None
__name_to_id__ = None
__years__ = None
def init(path):
"""init(path) must be called to load data before other calls will work. You should call it like this: init("car_sales_data.csv") or init("lab.csv")"""
global __id_to_data__
global __name_to_id__
global __years__
if path != 'car_sales_data.csv':
print("WARNING! Opening a path other than car_sales_data.csv. " +
"That's fine for testing your code yourself, but car_sales_data.csv " +
"will be the only file around when we test your code " +
"for grading.")
__id_to_data__ = {}
__name_to_id__ = {}
__years__ = []
f = open(path, encoding='utf-8')
raw_data = list(__csv__.reader(f))
f.close()
id_i = raw_data[0].index('id')
vehicle_i = raw_data[0].index('vehicle')
for head in raw_data[0]:
if head not in ('id', 'vehicle'):
__years__.append(int(head))
for car in raw_data[1:]:
__name_to_id__[car[vehicle_i]] = car[id_i]
__id_to_data__[car[id_i]] = {}
for i in range(len(car)):
if i == id_i:
continue
elif i == vehicle_i:
__id_to_data__[car[id_i]][raw_data[0][i]] = car[i]
else:
__id_to_data__[car[id_i]][raw_data[0][i]] = int(car[i])
def dump():
"""prints all the data to the screen"""
if __id_to_data__ == None:
raise Exception("you did not call init first")
for car in sorted(__name_to_id__.keys()):
car_id = __name_to_id__[car]
print("%s [ID: %s]" % (car, car_id))
for year in __years__:
print(" %s: %d cars sold" % (year, __id_to_data__[car_id][str(year)]))
print()
def get_id(car):
"""get_id(car) returns the id of the specified car model."""
if __name_to_id__ == None:
raise Exception("you did not call init first")
if not car in __name_to_id__:
raise Exception("No car '%s', only these: %s" %
(str(car), ', '.join(list(__name_to_id__.keys()))))
return int(__name_to_id__[car])
def get_sales(car_id, year=2019):
"""get_sales(car_id, year) returns the number of cars of the specified model sold in the specified year."""
if __id_to_data__ == None:
raise Exception("you did not call init first")
if str(car_id) not in list(__id_to_data__.keys()):
raise Exception("%s is not an id of any car in the dataset. Did you call get_id?" % (str(car_id)))
if not str(car_id) in __id_to_data__ or str(year) not in __id_to_data__[str(car_id)]:
raise Exception("No data for car %s, in year %s" %
(str(car_id), str(year)))
return __id_to_data__[str(car_id)][str(year)]
File added
# Project 3 (P3): Electric Vehicle Sales
## Clarifications/Corrections:
* None yet.
**Find any issues?** Talk to Jane or Adi in lab, or make a post on Piazza.
## Note on Academic Misconduct:
You are **allowed** to work with a partner on your projects. While it is not required that you work with a partner, it is **recommended** that you find a project partner as soon as possible as the projects will get progressively harder. Be careful **not** to work with more than one partner. If you worked with a partner on lab3, you are **not** allowed to finish your project with a different partner. You may either continue to work with the same partner, or work on P3 alone. Now may be a good time to review our [course policies](https://canvas.wisc.edu/courses/355767/pages/syllabus?module_item_id=6048035).
## Instructions:
In this project, we will focus on function calls, function definitions, default arguments, and simple arithmetic operations. To start, create a `p3` directory, and download `p3.ipynb`, `project.py`, `p3_test.py`, and `car_sales_data.csv`.
**Note:** Please go through [lab3](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/tree/main/sum23/labs/lab3) before you start the project. The lab contains some very important information that will be necessary for you to finish the project.
You will work on `p3.ipynb` and hand it in. You should follow the provided directions for each question. Questions have **specific** directions on what **to do** and what **not to do**.
After you've downloaded the file to your `p3` directory, open a terminal window and use `cd` to navigate to that directory. To make sure you're in the correct directory in the terminal, type `pwd`. To make sure you've downloaded the notebook file, type `ls` to ensure that `p3.ipynb`, `project.py`, `p3_test.py`, and `car_sales_data.csv` are listed. Then run the command `jupyter notebook` to start Jupyter, and get started on the project! Make sure to run the initial cells in the notebook before proceeding.
**IMPORTANT**: You should **NOT** terminate/close the session where you run the `jupyter notebook` command. If you need to use any other Terminal/PowerShell commands, open a new window instead. Keep constantly saving your notebook file, by either clicking the "Save and Checkpoint" button (floppy disk) or using the appropriate keyboard shortcut.
------------------------------
## IMPORTANT Submission instructions:
- Review the [Grading Rubric](https://git.doit.wisc.edu/cdis/cs/courses/cs220/cs220-lecture-material/-/blob/main/sum23/projects/p3/rubric.md), to ensure that you don't lose points during code review.
- Login to [Gradescope](https://www.gradescope.com/) and upload the zip file into the P3 assignment.
- If you completed the project with a **partner**, make sure to **add their name** by clicking "Add Group Member"
in Gradescope when uploading the P3 zip file.
<img src="images/add_group_member.png" width="400">
**Warning:** You will have to add your partner on Gradescope even if you have filled out this information in your `p3.ipynb` notebook.
- It is **your responsibility** to make sure that your project clears auto-grader tests on the Gradescope test system. Otter test results should be available in a few minutes after your submission. You should be able to see both PASS / FAIL results for the 20 test cases and your total score, which is accessible via Gradescope Dashboard (as in the image below):
<img src="images/gradescope.png" width="400">
Note that you can only see your score as `-/100.0` since it has not yet been reviewed by a TA. However, you should confirm that your tests have all passed the autograder.
id,vehicle,2017,2018,2019,2020,2021
958,Tesla Model S,26500,25745,15090,10125,17653
10,Chevy Volt,20349,18306,4915,67,16
64,Nissan Leaf,11230,14715,12365,9564,14239
977,Toyota Prius PHEV,20936,27595,23630,43525,59010
332,Ford Fusion Energi,9632,8074,7476,19402,3342
951,Tesla Model X,208,26100,19425,7375,22546
# Images
Images from p3 are stored here.
sum23/projects/p3/images/add_group_member.png

157 KiB

sum23/projects/p3/images/gradescope.png

150 KiB

This diff is collapsed.
#!/usr/bin/python
import os, json, math
MAX_FILE_SIZE = 500 # units - KB
REL_TOL = 6e-04 # relative tolerance for floats
ABS_TOL = 15e-03 # absolute tolerance for floats
PASS = "PASS"
TEXT_FORMAT = "text" # question type when expected answer is a str, int, float, or bool
expected_json = {"1": (TEXT_FORMAT, 977),
"2": (TEXT_FORMAT, 11230),
"3": (TEXT_FORMAT, 26500),
"4": (TEXT_FORMAT, 43525),
"5": (TEXT_FORMAT, 10125),
"6": (TEXT_FORMAT, 16),
"7": (TEXT_FORMAT, 34939.2),
"8": (TEXT_FORMAT, 8730.6),
"9": (TEXT_FORMAT, 2292.3999999999996),
"10": (TEXT_FORMAT, 116806),
"11": (TEXT_FORMAT, 289765),
"12": (TEXT_FORMAT, -1572.5),
"13": (TEXT_FORMAT, -6096.666666666667),
"14": (TEXT_FORMAT, 2389.0),
"15": (TEXT_FORMAT, 17248.0),
"16": (TEXT_FORMAT, 91315.0),
"17": (TEXT_FORMAT, -41541.5),
"18": (TEXT_FORMAT, 32092.5),
"19": (TEXT_FORMAT, -406.5),
"20": (TEXT_FORMAT, 2.090140253191154)}
def check_cell(qnum, actual):
format, expected = expected_json[qnum[1:]]
try:
if format == TEXT_FORMAT:
return simple_compare(expected, actual)
else:
if expected != actual:
return "expected %s but found %s " % (repr(expected), repr(actual))
except:
if expected != actual:
return "expected %s" % (repr(expected))
return PASS
def simple_compare(expected, actual, complete_msg=True):
msg = PASS
if type(expected) == type:
if expected != actual:
if type(actual) == type:
msg = "expected %s but found %s" % (expected.__name__, actual.__name__)
else:
msg = "expected %s but found %s" % (expected.__name__, repr(actual))
elif type(expected) != type(actual) and not (type(expected) in [float, int] and type(actual) in [float, int]):
msg = "expected to find type %s but found type %s" % (type(expected).__name__, type(actual).__name__)
elif type(expected) == float:
if not math.isclose(actual, expected, rel_tol=REL_TOL, abs_tol=ABS_TOL):
msg = "expected %s" % (repr(expected))
if complete_msg:
msg = msg + " but found %s" % (repr(actual))
else:
if expected != actual:
msg = "expected %s" % (repr(expected))
if complete_msg:
msg = msg + " but found %s" % (repr(actual))
return msg
def check(qnum, actual):
msg = check_cell(qnum, actual)
if msg == PASS:
return True
print("<b style='color: red;'>ERROR:</b> " + msg)
def check_file_size(path):
size = os.path.getsize(path)
assert size < MAX_FILE_SIZE * 10**3, "Your file is too big to be processed by Gradescope; please delete unnecessary output cells so your file size is < %s KB" % MAX_FILE_SIZE
import csv as __csv__
__id_to_data__ = None
__name_to_id__ = None
__years__ = None
def init(path):
"""init(path) must be called to load data before other calls will work. You should call it like this: init("car_sales_data.csv") or init("lab.csv")"""
global __id_to_data__
global __name_to_id__
global __years__
if path != 'car_sales_data.csv':
print("WARNING! Opening a path other than car_sales_data.csv. " +
"That's fine for testing your code yourself, but car_sales_data.csv " +
"will be the only file around when we test your code " +
"for grading.")
__id_to_data__ = {}
__name_to_id__ = {}
__years__ = []
f = open(path, encoding='utf-8')
raw_data = list(__csv__.reader(f))
f.close()
id_i = raw_data[0].index('id')
vehicle_i = raw_data[0].index('vehicle')
for head in raw_data[0]:
if head not in ('id', 'vehicle'):
__years__.append(int(head))
for car in raw_data[1:]:
__name_to_id__[car[vehicle_i]] = car[id_i]
__id_to_data__[car[id_i]] = {}
for i in range(len(car)):
if i == id_i:
continue
elif i == vehicle_i:
__id_to_data__[car[id_i]][raw_data[0][i]] = car[i]
else:
__id_to_data__[car[id_i]][raw_data[0][i]] = int(car[i])
def dump():
"""prints all the data to the screen"""
if __id_to_data__ == None:
raise Exception("you did not call init first")
for car in sorted(__name_to_id__.keys()):
car_id = __name_to_id__[car]
print("%s [ID: %s]" % (car, car_id))
for year in __years__:
print(" %s: %d cars sold" % (year, __id_to_data__[car_id][str(year)]))
print()
def get_id(car):
"""get_id(car) returns the id of the specified car model."""
if __name_to_id__ == None:
raise Exception("you did not call init first")
if not car in __name_to_id__:
raise Exception("No car '%s', only these: %s" %
(str(car), ', '.join(list(__name_to_id__.keys()))))
return int(__name_to_id__[car])
def get_sales(car_id, year=2019):
"""get_sales(car_id, year) returns the number of cars of the specified model sold in the specified year."""
if __id_to_data__ == None:
raise Exception("you did not call init first")
if str(car_id) not in list(__id_to_data__.keys()):
raise Exception("%s is not an id of any car in the dataset. Did you call get_id?" % (str(car_id)))
if not str(car_id) in __id_to_data__ or str(year) not in __id_to_data__[str(car_id)]:
raise Exception("No data for car %s, in year %s" %
(str(car_id), str(year)))
return __id_to_data__[str(car_id)][str(year)]
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment