Draw a Hiking Trail from GeoJSON with Markers and Color Bands
StripeSoftware Engineer · OnsiteLast updated
Parse a hiking trail out of a GeoJSON LineString, build the request payload for a map-snapshot API, save the returned PNG, and add start/finish markers plus alternating-color bands along the route.
A trail-mapping app stores recorded hikes as GeoJSON and renders them with a third-party service called TrailSnap. TrailSnap exposes one endpoint: a POST to /snapshot whose JSON body describes markers and colored path segments, which responds with the rendered map as raw PNG bytes.
You're given a hike as a GeoJSON FeatureCollection whose first feature is a LineString:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [[-121.70, 45.37], [-121.69, 45.38], [-121.68, 45.39], [-121.67, 45.40]]
}
}]
}
GeoJSON coordinates are [longitude, latitude]. TrailSnap instead expects each point as {"lat": ..., "lon": ...}.
Part 1 — Parse the trail
Write extract_latlon(feature_collection) -> list[dict] that returns the trail's points in TrailSnap's {"lat", "lon"} order.
Part 2 — Build the request and save the response
Write build_payload(points, band_size, color_a, color_b) -> dict (used in Part 3) and a function that POSTs a payload to TRAILSNAP_URL + "/snapshot" and writes the binary response to a PNG file.
Part 3 — Markers and alternating color bands
Extend build_payload so the request also:
- Adds a
"start"marker at the trail's first point and a"finish"marker at its last point. - Splits the trail into consecutive bands of
band_sizesegments each (a segment is the line between two consecutive points), coloring bands alternatelycolor_a,color_b,color_a, ... Each band's point list must include the point shared with the next band, so the rendered path has no gaps.
Example
For the 9-point trail above extended to 9 points and band_size=3, the 8 segments split into bands of sizes [3, 3, 2] segments, i.e. point counts [4, 4, 3], colored color_a, color_b, color_a.
Constraints
- A trail has at least 2 points.
1 <= band_size; the last band may be shorter thanband_sizesegments.
Hints
Hint 1
Write down which index is longitude and which is latitude before you touch the dict — it's easy to swap them silently.
Hint 2
A band needs `band_size` segments, which means `band_size + 1` points; the last point of one band is the first point of the next.
Hint 3
Since the response body is binary, open the output file in binary write mode, not text mode.
Hint 4
Keep the network call itself thin — put the payload-building and banding logic in pure functions you can test without hitting TrailSnap.
Follow-up questions
- How would you handle a FeatureCollection with more than one LineString feature?
- What should happen if TrailSnap returns a non-200 status or an empty body?
- How would you avoid re-downloading the same map if the trail hasn't changed since the last render?
- How would you adapt `band_segments` to color bands by elevation gain instead of a fixed segment count?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.