From 805280690c5b10a98f1dc771fbb40bd72600674d Mon Sep 17 00:00:00 2001 From: Grant Russell Date: Mon, 16 Mar 2026 09:29:54 -0500 Subject: [PATCH 1/3] supplement each community area obj with number of permits in given year --- map/serializers.py | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/map/serializers.py b/map/serializers.py index 03dd912..09135b4 100644 --- a/map/serializers.py +++ b/map/serializers.py @@ -6,29 +6,13 @@ class CommunityAreaSerializer(serializers.ModelSerializer): class Meta: model = CommunityArea - fields = ["name", "num_permits"] + fields = ["name", "area_id", "num_permits"] num_permits = serializers.SerializerMethodField() def get_num_permits(self, obj): - """ - TODO: supplement each community area object with the number - of permits issued in the given year. - - e.g. The endpoint /map-data/?year=2017 should return something like: - [ - { - "ROGERS PARK": { - area_id: 17, - num_permits: 2 - }, - "BEVERLY": { - area_id: 72, - num_permits: 2 - }, - ... - } - ] - """ - - pass + year = self.context.get("year") + permits = RestaurantPermit.objects.filter(community_area_id=obj.area_id) + if year: + permits = permits.filter(issue_date__year=year) + return permits.count() From fb4c74c895182183d0d42fc8285ca9f455345c98 Mon Sep 17 00:00:00 2001 From: Grant Russell Date: Mon, 16 Mar 2026 10:27:20 -0500 Subject: [PATCH 2/3] complete test for map-data endpoint --- tests/test_views.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/test_views.py b/tests/test_views.py index 24cc64e..f8eb3b4 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -36,6 +36,13 @@ def test_map_data_view(): client = APIClient() response = client.get(reverse("map_data", query={"year": 2021})) - # TODO: Complete the test by asserting that the /map-data/ endpoint - # returns the correct number of permits for Beverly and Lincoln - # Park in 2021 + assert response.status_code == 200 + + expected_response = [ + {"name": "Beverly", "area_id": 1, "num_permits": 2}, + {"name": "Lincoln Park", "area_id": 2, "num_permits": 3}, + ] + + assert ( + response.json() == expected_response + ), "Should return the correct number of permits for each community area" From c45bae9cf7a5a48e46a91a93687953a63b771301 Mon Sep 17 00:00:00 2001 From: Grant Russell Date: Mon, 16 Mar 2026 13:37:45 -0500 Subject: [PATCH 3/3] fetch and display permit data with with percentage shading --- map/static/js/RestaurantPermitMap.js | 47 ++++++++++++++++------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/map/static/js/RestaurantPermitMap.js b/map/static/js/RestaurantPermitMap.js index 57f8ea0..a5c7deb 100644 --- a/map/static/js/RestaurantPermitMap.js +++ b/map/static/js/RestaurantPermitMap.js @@ -40,39 +40,46 @@ export default function RestaurantPermitMap() { const communityAreaColors = ["#eff3ff", "#bdd7e7", "#6baed6", "#2171b5"] const [currentYearData, setCurrentYearData] = useState([]) + const [areaDataMap, setAreaDataMap] = useState({}) const [year, setYear] = useState(2026) const yearlyDataEndpoint = `/map-data/?year=${year}` + const totalNumPermits = currentYearData.reduce((sum, { num_permits}) => sum + num_permits, 0) + const maxNumPermits = currentYearData.reduce((max, { num_permits }) => Math.max(max, num_permits), 0) useEffect(() => { - fetch() + fetch(yearlyDataEndpoint) .then((res) => res.json()) .then((data) => { - /** - * TODO: Fetch the data needed to supply to map with data - */ + setCurrentYearData(data) + const map = data.reduce((acc, area) => { + acc[area.area_id] = area + return acc + }, {}) + setAreaDataMap(map) }) }, [yearlyDataEndpoint]) function getColor(percentageOfPermits) { - /** - * TODO: Use this function in setAreaInteraction to set a community - * area's color using the communityAreaColors constant above - */ + if (percentageOfPermits > 0.75) return communityAreaColors[3] + if (percentageOfPermits > 0.5) return communityAreaColors[2] + if (percentageOfPermits > 0.25) return communityAreaColors[1] + return communityAreaColors[0] } function setAreaInteraction(feature, layer) { - /** - * TODO: Use the methods below to: - * 1) Shade each community area according to what percentage of - * permits were issued there in the selected year - * 2) On hover, display a popup with the community area's raw - * permit count for the year - */ - layer.setStyle() - layer.on("", () => { - layer.bindPopup("") + const areaId = feature.properties.area_num_1 + const areaData = areaDataMap[areaId] + const percentage = maxNumPermits > 0 ? areaData.num_permits / maxNumPermits : 0 + layer.setStyle({ + fillColor: getColor(percentage), + fillOpacity: 0.7, + color: "#808080", + weight: 1, + }) + layer.on("mouseover", () => { + layer.bindPopup(`${areaData.name}
Permits: ${areaData.num_permits}`) layer.openPopup() }) } @@ -81,11 +88,11 @@ export default function RestaurantPermitMap() { <>

- Restaurant permits issued this year: {/* TODO: display this value */} + Restaurant permits issued this year: {totalNumPermits}

Maximum number of restaurant permits in a single area: - {/* TODO: display this value */} + {maxNumPermits}