Katkat

Draw a Hiking Trail from GeoJSON with Markers and Color Bands

StripeSoftware Engineer · Onsite

Last 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_size segments each (a segment is the line between two consecutive points), coloring bands alternately color_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 than band_size segments.

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?