Skip to content
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ services:
postgres:
container_name: map-postgres
image: postgis/postgis
platform: linux/amd64
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
Expand Down
3 changes: 3 additions & 0 deletions map/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ class RestaurantPermit(models.Model):
street_name = models.CharField(max_length=32, null=True, blank=True)
location = gis_models.PointField(null=True, blank=True)
community_area_id = models.CharField(max_length=2, null=True, blank=True)

def __str__(self):
return f'Permit ID: {self.permit_id}, Area: {self.community_area_id}'
4 changes: 2 additions & 2 deletions map/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ def get_num_permits(self, obj):
}
]
"""

pass
count = RestaurantPermit.objects.filter(community_area_id = obj.area_id, issue_date__year=self.context.get('year')).count()
return count
61 changes: 45 additions & 16 deletions map/static/js/RestaurantPermitMap.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useEffect, useState } from "react"

import React, { useEffect, useState, useCallback } from "react"
import { MapContainer, TileLayer, GeoJSON } from "react-leaflet"

import "leaflet/dist/leaflet.css"
Expand Down Expand Up @@ -45,47 +44,77 @@ export default function RestaurantPermitMap() {
const yearlyDataEndpoint = `/map-data/?year=${year}`

useEffect(() => {
fetch()
fetch(yearlyDataEndpoint)
.then((res) => res.json())
.then((data) => {
/**
* TODO: Fetch the data needed to supply to map with data
*/
setCurrentYearData(data);
})
}, [yearlyDataEndpoint])


function getColor(percentageOfPermits) {
/**
* TODO: Use this function in setAreaInteraction to set a community
* area's color using the communityAreaColors constant above
*/
// Dynamic breaks from current data
const percents = currentYearData.map(d => d.num_permits / totalPermits *
100).sort((a,b)=>a-b);
const q1 = percents[Math.floor(percents.length * 0.25)];
const q2 = percents[Math.floor(percents.length * 0.50)];
const q3 = percents[Math.floor(percents.length * 0.75)];
if (percentageOfPermits >= q3) return communityAreaColors[3];
if (percentageOfPermits >= q2) return communityAreaColors[2];
if (percentageOfPermits >= q1) return communityAreaColors[1];
return communityAreaColors[0];
}

function setAreaInteraction(feature, layer) {
const setAreaInteraction =
/**
* 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("")
layer.openPopup()
})
useCallback((feature, layer) => {
const name = feature.properties.community;
const communityAreaData = currentYearData.find(d => d.name === name);
const countPermits = communityAreaData?.num_permits || 0;
const percentageOfPermits = totalPermits > 0 ? countPermits/totalPermits * 100 : 0;
layer.setStyle({ fillOpacity: 0.9, fillColor: getColor(percentageOfPermits) })
layer.on('mouseover', () => {
layer.bindPopup(`${feature.properties.community}: ${communityAreaData.num_permits} permits`)
layer.openPopup()
})
;} ,[currentYearData]);

function getTotalandMaxNumPermits(currentYearData) {
// This could be two functions instead of one, and that would be nicer from a test/maintenance perspective,
// but it will be faster to compute both results together.
let totalPermits = 0;
// Maximum number of permits held by a single community area in current year data
let maxNumPermits = 0
for (const community_area of currentYearData) {
totalPermits += community_area.num_permits
if (community_area.num_permits > maxNumPermits) {
maxNumPermits = community_area.num_permits
}
}
return { totalPermits, maxNumPermits };
}

const computedTotals = getTotalandMaxNumPermits(currentYearData);
const totalPermits = computedTotals.totalPermits;
const maxNumPermits = computedTotals.maxNumPermits;

return (
<>
<YearSelect filterVal={year} setFilterVal={setYear} />
<p className="fs-4">
Restaurant permits issued this year: {/* TODO: display this value */}
Restaurant permits issued this year: {totalPermits}
</p>
<p className="fs-4">
Maximum number of restaurant permits in a single area:
{/* TODO: display this value */}
{maxNumPermits}
</p>
<MapContainer
id="restaurant-map"
Expand Down
19 changes: 19 additions & 0 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,22 @@ def test_map_data_view():
# TODO: Complete the test by asserting that the /map-data/ endpoint
# returns the correct number of permits for Beverly and Lincoln
# Park in 2021

actual_num_permits_Beverly = 0
actual_num_permits_LincolnPark = 0

for data in response.data:
if data.get('name') == "Beverly":
actual_num_permits_Beverly = data.get('num_permits')
if data.get('name') == "Lincoln Park":
actual_num_permits_LincolnPark = data.get('num_permits')

expected_num_permits_Beverly = 2
assert actual_num_permits_Beverly == expected_num_permits_Beverly

expected_num_permits_LincolnPark = 3
assert actual_num_permits_LincolnPark == actual_num_permits_LincolnPark

assert len(response.data) == 2