Katkat

Render a Sailing Voyage from GeoJSON with a Map Snapshot API

StripeSoftware Engineer · Onsite

Last updated

Parse a GPS voyage from a GeoJSON file, POST it to a map snapshot service, save the returned PNG, then add start and finish markers and color bands of fixed segment counts. Tests careful JSON navigation, coordinate order, binary HTTP handling, and off-by-one-free chunking.

A sailing club wants a quick image of each member's voyage for its newsletter. You have:

  • voyage.json: a GeoJSON FeatureCollection exported from a GPS plotter. It may contain several features (for example a Point marking the home harbor), but exactly one feature has a LineString geometry: the voyage, in travel order. Positions follow the GeoJSON convention [longitude, latitude] and may include a third elevation value.
  • A snapshot renderer HTTP service at RENDER_URL. You POST a JSON body describing the map, and the response body is the PNG bytes of the image (Content-Type: image/png). On bad input it returns a 4xx status with a short text explanation.
{
  "width": 800, "height": 600,
  "markers": [{"lat": 36.14, "lng": -5.35, "label": "S", "color": "green"}],
  "lines":   [{"color": "#d62728", "width": 3,
               "points": [{"lat": 36.14, "lng": -5.35}, {"lat": 36.144, "lng": -5.34}]}]
}

Note that the renderer wants lat/lng objects, while GeoJSON stores longitude first. Use only the Python standard library.

Part 1: Extract the track

Write load_track(path) -> list[dict] returning the voyage as {"lat", "lng"} dicts. Find the LineString by geometry type instead of assuming its index, and fail clearly if there isn't exactly one. Print the first point and the count.

Part 2: Render the route

Send the whole voyage as a single red line and save the response to voyage.png. Handle non-2xx responses with a useful error, check that you actually got a PNG, and write the file in binary mode.

Part 3: Markers and banded colors

Add an S marker (green) at the first point and an F marker (red) at the last. Draw the route as consecutive bands of 8 segments each, cycling through the colors #1f77b4, #ff7f0e, #2ca02c. A segment joins two consecutive points. Adjacent bands must touch, with no visible gaps.

Example

For a 20-point voyage starting at [-5.35, 36.14] and ending at [-5.16, 36.216]:

first: {'lat': 36.14, 'lng': -5.35} count: 20
segments per band: [8, 8, 3]
colors: ['#1f77b4', '#ff7f0e', '#2ca02c']
markers: S at (36.14, -5.35), F at (36.216, -5.16)

Constraints

  • Tracks have up to 5,000 points. Assume the renderer accepts payloads up to 2 MB.
  • Test your client without the real service by running a small mock HTTP server on 127.0.0.1.

Hints

Hint 1

Look at the GeoJSON nesting and remember which number in each position is longitude.

Hint 2

Don't assume the track is the first feature. Filter by geometry type.

Hint 3

The response is an image. Read raw bytes, check status and content type, and write in binary mode.

Hint 4

n points make n - 1 segments. For bands to touch, consecutive bands must share an endpoint.

Follow-up questions

  • The renderer rejects payloads over 2 MB and a member uploads a 60,000-point track. What do you do?
  • How would you color the route by boat speed instead of by fixed segment count?
  • How would you unit-test the client without any network at all?
  • The renderer is slow and you need images for 10,000 voyages overnight. How do you parallelize safely?