module-7-blank 2025-04-13, 9:52 PM
Analysing VPD Crime Data
We've uploaded a tiny portion of the crime data shared by the Vancouver Police
Department's Open Data initiative. The complete file has well over half a million rows. The
portion we uploaded is all crimes labelled as "break and enter" (in two variants: commercial
and residential) and "theft of" (in two variants: vehicle and bicycle) in 2023.
You can see our information file in this directory named crimedata_subset_2023.csv .
You can also find the license for this information and a PDF file from VPD describing the
information source.
Let's see if we can answer the question: At what time of day does crime of various types
peak in Vancouver?
We'll start from the project final submission template to get good practice both on using
HtDAP and preparing for the project! (We've edited this slightly to note places where we'll
deviate from the project.)
Step 1a: Planning
Identify the information in the file your program will read
Double click this cell to edit.
Step 1b: Planning
Write a description of what your program will produce
Double click this cell to edit.
You must brainstorm at least three ideas for graphs or charts that your program could
produce and choose the one that you'd like to work on. You can choose between a line chart,
histogram, bar chart, scatterplot, or pie chart. Note: we might focus on non-graphs for now,
since we're really studying HtDAP rather than the project.
about:srcdoc Page 1 of 8
module-7-blank 2025-04-13, 9:52 PM
Step 1c: Planning
Write or draw examples of what your program will produce
Double click this cell to edit.
You must include an image that shows what your chart or plot will look like. You can insert an
image using the Insert Image command near the bottom of the Edit menu. Note: we'll
practice using the "insert image" command just for the fun of it, but we are still not focusing
on graphs/charts.
TODO: sketch a graph of crime over the hours of the day for the various types of crime.
Step 2a: Building
Design data definitions
Double click this cell to edit.
Before you design data definitions in the code cell below, you must explicitly document here
which information in the file you chose to represent and why that information is crucial to the
chart or graph that you'll produce when you complete step 2c. Note: we'll skip the "chart or
graph" part!
In [4]:
from cs103 import *
from typing import NamedTuple, List
import csv
##################
# Data Definitions
Consumed = ...
# List[Consumed]
# interp. a list of Consumed
LOC0 = []
@typecheck
def fn_for_loc(loc: List[Consumed]) -> ...:
... # choose which template body to use for List[Consumed]
about:srcdoc Page 2 of 8
module-7-blank 2025-04-13, 9:52 PM
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-ba4c569f038e> in <module>
16
17 @typecheck
---> 18 def fn_for_loc(loc: List[Consumed]) -> ...:
19 ... # choose which template body to use for List[Consumed]
/opt/conda/lib/python3.8/[Link] in inner(*args, **kwds)
259 except TypeError:
260 pass # All real errors (not unhashable args) are raised b
elow.
--> 261 return func(*args, **kwds)
262 return inner
263
/opt/conda/lib/python3.8/[Link] in __getitem__(self, params)
683 params = (params,)
684 msg = "Parameters to generic types must be types."
--> 685 params = tuple(_type_check(p, msg) for p in params)
686 _check_generic(self, params)
687 return _subs_tvars(self, self.__parameters__, params)
/opt/conda/lib/python3.8/[Link] in <genexpr>(.0)
683 params = (params,)
684 msg = "Parameters to generic types must be types."
--> 685 params = tuple(_type_check(p, msg) for p in params)
686 _check_generic(self, params)
687 return _subs_tvars(self, self.__parameters__, params)
/opt/conda/lib/python3.8/[Link] in _type_check(arg, msg, is_argument)
147 return arg
148 if not callable(arg):
--> 149 raise TypeError(f"{msg} Got {arg!r:.100}.")
150 return arg
151
TypeError: Parameters to generic types must be types. Got Ellipsis.
about:srcdoc Page 3 of 8
module-7-blank 2025-04-13, 9:52 PM
In [5]:
# Here are some definitions we'll need later on that aren't particularly interestin
# List[str]
# interp. a list of strings
LOS0 = []
LOS1 = ['hello', 'world']
# template based on arbitrary-sized data
@typecheck
def fn_for_los(los: List[str]) -> ...:
# description of accumulator
acc = ... # type: ...
for s in los:
acc = ...(s, acc)
return ...(acc)
# List[int]
# interp. a list of integers
LOI0 = []
LOI1 = [1, -12]
# template based on arbitrary-sized data
@typecheck
def fn_for_loi(loi: List[int]) -> ...:
# description of accumulator
acc = ... # type: ...
for i in loi:
acc = ...(i, acc)
return ...(acc)
Step 2b: Building
Design a function to read the information and store it as data in your program
about:srcdoc Page 4 of 8
module-7-blank 2025-04-13, 9:52 PM
In [6]:
@typecheck
def read(filename: str) -> List[Consumed]:
"""
reads information from the specified file and returns ...
"""
#return [] #stub
# Template from HtDAP
# loc contains the result so far
loc = [] # type: List[Consumed]
with open(filename) as csvfile:
reader = [Link](csvfile)
next(reader) # skip header line
for row in reader:
# you may not need to store all the rows, and you may need
# to convert some of the strings to other types
c = Consumed(row[0], ... ,row[n])
[Link](c)
return loc
start_testing()
# Examples and tests for read
expect(..., ...)
summary()
about:srcdoc Page 5 of 8
module-7-blank 2025-04-13, 9:52 PM
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-6-1080cb90f176> in <module>
1 @typecheck
----> 2 def read(filename: str) -> List[Consumed]:
3 """
4 reads information from the specified file and returns ...
5 """
/opt/conda/lib/python3.8/[Link] in inner(*args, **kwds)
259 except TypeError:
260 pass # All real errors (not unhashable args) are raised b
elow.
--> 261 return func(*args, **kwds)
262 return inner
263
/opt/conda/lib/python3.8/[Link] in __getitem__(self, params)
683 params = (params,)
684 msg = "Parameters to generic types must be types."
--> 685 params = tuple(_type_check(p, msg) for p in params)
686 _check_generic(self, params)
687 return _subs_tvars(self, self.__parameters__, params)
/opt/conda/lib/python3.8/[Link] in <genexpr>(.0)
683 params = (params,)
684 msg = "Parameters to generic types must be types."
--> 685 params = tuple(_type_check(p, msg) for p in params)
686 _check_generic(self, params)
687 return _subs_tvars(self, self.__parameters__, params)
/opt/conda/lib/python3.8/[Link] in _type_check(arg, msg, is_argument)
147 return arg
148 if not callable(arg):
--> 149 raise TypeError(f"{msg} Got {arg!r:.100}.")
150 return arg
151
TypeError: Parameters to generic types must be types. Got Ellipsis.
Step 2c: Building
Design functions to analyze the data
Complete these steps in the code cell below. You will likely want to rename the analyze
function so that the function name describes what your analysis function does.
NOTE: To make this manageable in class, we will provide some finished helper functions with
the second week's notes.
about:srcdoc Page 6 of 8
module-7-blank 2025-04-13, 9:52 PM
In [7]:
###########
# Functions
@typecheck
def main(filename: str) -> ...:
"""
Reads the file from given filename, analyzes the data, returns the result
"""
# Template from HtDAP, based on function composition
return analyze(read(filename))
@typecheck
def analyze(loc: List[Consumed]) -> Produced:
"""
...
"""
return ...
start_testing()
# Examples and tests for main
expect(..., ...)
summary()
start_testing()
# Examples and tests for analyze
expect(..., ...)
summary()
about:srcdoc Page 7 of 8
module-7-blank 2025-04-13, 9:52 PM
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-73f6cf07f161> in <module>
14
15 @typecheck
---> 16 def analyze(loc: List[Consumed]) -> Produced:
17 """
18 ...
/opt/conda/lib/python3.8/[Link] in inner(*args, **kwds)
259 except TypeError:
260 pass # All real errors (not unhashable args) are raised b
elow.
--> 261 return func(*args, **kwds)
262 return inner
263
/opt/conda/lib/python3.8/[Link] in __getitem__(self, params)
683 params = (params,)
684 msg = "Parameters to generic types must be types."
--> 685 params = tuple(_type_check(p, msg) for p in params)
686 _check_generic(self, params)
687 return _subs_tvars(self, self.__parameters__, params)
/opt/conda/lib/python3.8/[Link] in <genexpr>(.0)
683 params = (params,)
684 msg = "Parameters to generic types must be types."
--> 685 params = tuple(_type_check(p, msg) for p in params)
686 _check_generic(self, params)
687 return _subs_tvars(self, self.__parameters__, params)
/opt/conda/lib/python3.8/[Link] in _type_check(arg, msg, is_argument)
147 return arg
148 if not callable(arg):
--> 149 raise TypeError(f"{msg} Got {arg!r:.100}.")
150 return arg
151
TypeError: Parameters to generic types must be types. Got Ellipsis.
In [ ]:
In [ ]:
about:srcdoc Page 8 of 8