This is my completion of DataMade's public code challenge. I'm not in an application window right now, I just wanted to do the work because civic data tooling is the kind of thing I want to build. The original brief is below, unchanged.
What I did
The challenge ships skeletons in
map/serializers.py,map/views.py,map/static/js/RestaurantPermitMap.js, andtests/test_views.py. I filled them in and pushed iteratively, so the commit log walks through the work:
- Implemented
get_num_permitsfirst as a per-area filter inside the serializer. Realized that was 77 SELECTs per map load and refactored: the view runs oneGROUP BYquery and hands the serializer a{community_area_id: count}dict to look up.- Filled in the existing test, then added two more cases (no-year request, area with zero permits) plus a different-year permit in the original test so the year filter is actually exercised.
- Wired the React component end-to-end. Year filter, fetch on change, choropleth shaded by quartile of the year's max, total + max above the map, hover popup with the area name and count.
- Hit two bugs while clicking around: same-max years didn't re-style (the GeoJSON layer is keyed on
maxNumPermits, which was stable across some year switches — fixed by keying on${year}-${maxNumPermits}), and fast year-changes were letting stale fetches race the new one — fixed withAbortControlleron cleanup.- Added polish that turns the map into something readable on its own: a legend that spells out the permit-count range for each shade, a top-5 list under the map, and a visible error message when
/map-data/fails instead of swallowing.Files changed:
map/serializers.py,map/views.py,map/static/js/RestaurantPermitMap.js,tests/test_views.py,README.md.After the basics worked I went further:
- Added a
populationcolumn onCommunityArea, a loader, and a CSV of 2023 5-year ACS totals per community area (sourced from the City of Chicago'st68z-cikkdataset). The API now returnspermits_per_10kalongside the raw count.- Added a toggle on the page between raw counts and per-capita. Per-capita re-ranks the map: Lincoln Park and Loop drop, smaller dense neighborhoods rise.
- Composite index on
(issue_date, community_area_id)so the aggregate runs as a bitmap index scan instead of seq scan. Before/afterEXPLAIN ANALYZEin the commit body./map-data/?year=2021&format=csvreturns the same rows as CSV, for journalists who want the dataset without a JSON parser.- Break the per-area count out by
permit_type. The popup now shows the top two categories under the count, so a heavy-renovation neighborhood reads different from a heavy-new-construction one.- Title-cased the community area names at load time (with manual overrides for O'Hare and McKinley Park). Used to be a regex in the React component.
- Loading and empty-state messages so a year outside the dataset's range doesn't render a blank map without an explanation.
- Switched
load_restaurant_permitsfrom per-row saves tobulk_createwithbatch_size=500. Same change madepermit_typestrings pretty at load time, so the API now ships"Renovation / Alteration"instead of"PERMIT - RENOVATION/ALTERATION"and the React component lost a regex helper.- URL state:
?year=2023&mode=per_capitadeep-links to a specific view.history.replaceStateso back-button isn't littered.- New
/map-data/trends/endpoint returns{trends: {area_id: {year: count}}}from one GROUP BY. The frontend uses it to draw an inline-SVG sparkline beside each top-5 area, no charting library needed.- Mobile pass: gave
#restaurant-mapaheightrule (it was rendering at 0 without one), shrunk the form select and the headline paragraphs at the 575px breakpoint, sized the metric-toggle buttons so both fit on iPhone SE width.- Added
refresh_population_from_acsmanagement command. Pulls tract-level total population from the Census Bureau via DataMade'scensuslibrary, sums by community area using thetract_to_community_area.csvcrosswalk, writes the same shape the shipped CSV uses. Optional, the shipped CSV is the rolled-up version of the same query.- New
/data/page: server-rendered Django template with an inline-SVG bar chart of permits per year, the all-time top 10 community areas, and per-year CSV download buttons hitting the existing?format=csvendpoint. Works without JS.- Wrote
METHODOLOGY.mdcovering sources, joins, the per-capita formula, and what the map doesn't see (closures, permit type, denominator quirks like the Loop's daytime-population problem).Running the tests:
docker compose -f docker-compose.yml -f tests/docker-compose.yml run --rm app→7 passed.Loading the data:
docker compose run --rm app python manage.py loaddata \ map/fixtures/community_areas.json map/fixtures/restaurant_permits.json docker compose run --rm app python manage.py load_community_area_population \ data/raw/community_area_population_acs2023.csv
Welcome to the 2026 DataMade code challenge! 👋
Your task is to complete the following programming exercise to show us some of your code! This exercise is based on work that DataMade does every day: pulling data from the web, debugging tricky code, and presenting information to the world.
Submissions should be submitted as a pull request against your fork of this original repository. Make sure to make your pull request against your own fork of the repository, not the original DataMade repository.
There’s no time limit, but don’t feel the need to go over the top with your submission. We expect this task to take about two hours to complete, but it could take more or less time depending on your familiarity with Django and React. When you’re all set, share your code with us as a repository on GitHub.
We’ll be evaluating whether the code works, as well as its quality. Before submitting, make sure that your code does what you expect it to do, that it’s clean and neat enough to meet your standards, and that you’ve provided us some instructions on how to run it.
Development requires a local installation of Docker and Docker Compose. These are the only two system-level dependencies you should need.
Once you have Docker and Docker Compose installed, build the application containers from the project's root directory:
docker compose buildLoad in the data:
docker compose run --rm app python manage.py loaddata map/fixtures/restaurant_permits.json map/fixtures/community_areas.jsonAnd finally, run the app:
docker compose upThe app will log to the console, and you should be able to visit it at http://localhost:8000
Once you have the app up and running on your computer, you'll need to flesh out certain code blocks to make the map functional. You'll be using Django and React-Leaflet to complete this task. By the end of this challenge, you should have:
- a map that displays Chicago's community areas, shaded depending on how many new restaurant permits were issued in a given year
- community area shapes that show some light details on that community area when a user interacts with them
- a filter that allows users to request permits that were issued in a given year
- UI components that display the total number of permits and max number of permits in one community area for that year
This way you go about completing these goals is meant to be open-ended, so tackle the following steps in whatever way you're most comfortable!
In map/serializers.py, supplement each community area with data on the amount of permits issued in each area during the currently filtered year. From here, the view will pass that data to the front end.
In tests/test_views.py implement a test to validate the data that your endpoint produces. You will want to create some test CommunityArea and RestaurantPermit objects and then assert that the expected values are returned when querying the endpoint.
Use this command to run tests:
docker compose -f docker-compose.yml -f tests/docker-compose.yml run --rm appIn map/static/js/RestaurantPermitMap.js, create a filter that allows users to send a request for a specific year to the backend. The options shoulds be any year between 2016 and 2026, inclusive. Then, use the fetch api in the map component to make a request and receive that data.
In the map component, process the community area and use it to display shapes for all areas on the map. Then, display the total number of restaurant permits that year as well as the maximum number of permits in any one area.
Start displaying some data! Use the setAreaInteraction() method to shade the map according to how many permits it has in a year, making sure that it updates automatically when a new year is selected. In this same method, have each area display a popup during some kind of user interaction. The popup should have some light details to help the user understand what they're looking at.
To submit your work, create a feature branch for your code, commit your changes, push your commits up to your fork, and open up a pull request against main. Finally, drop a link to your pull request in your application.
Note: If you would prefer to keep your code challenge private, please share access with the following members of DataMade on GitHub:
| Member | GitHub Account |
|---|---|
| Hannah | https://github.com/hancush |
| Derek | https://github.com/derekeder |
| Monkruman | https://github.com/antidipyramid |
| Xavier | https://github.com/xmedr |
| Hayley | https://github.com/haowens |
Keep in mind that you cannot create a private fork of a public repository on GitHub, so you’ll need to follow these instructions to create a private copy of the repo.
