Day job (Software Tech Lead, Oizom) / 2025

Air-quality heatmaps: 5 seconds per image to 20 images in 30 ms

Rebuilt an hourly Python heatmap cron as an on-request Go service with precomputed weights and JPEG output. Heatmaps are now available for any past time range, with custom settings.

Screenshot: an air-quality heatmap over south-east England, masked to a polygon boundary on a Leaflet map.
Screenshot: an air-quality heatmap over south-east England, masked to a polygon boundary on a Leaflet map.

Result

  • About 5 s per image (hourly cron, 4 GB RAM, 2 CPUs) to 30 ms for 20 images
  • At 5 req/s: average 29 ms in Go with JPEG vs 419 ms in Node.js
  • Any past time range and custom resolution, distance power and wind settings

Stack

GoNode.jsPython (old version)IDW interpolationJPEG encodingLeaflet

Built at my day job, where I lead the software team behind the Envizom platform. The code belongs to the company; this write-up comes from my public blog post.

The problem

Heatmaps were made by a Python cron every hour: IDW interpolation with wind speed and direction over a 1 km grid, stored as Base64 PNGs in a time-series database. It used 4 GB of RAM and 2 CPUs and still wasn't enough, each image took seconds, and only a fixed 1-hour average existed. With three configs it was already not keeping up.

What I built

  1. A weekend proof of concept that rendered the heatmap in the browser, to show it could be done on request.
  2. A Node.js server, then a Go service. It maps the boundary and devices onto a grid once, precomputes each device's weight on every pixel, and then fills each snapshot from those weights.
  3. A time log on every function showed Base64 PNG encoding taking 80% of the time. Switching to JPEG fixed it; the frontend masks the image to the boundary, since JPEG has no transparency, and a 2 px margin keeps low-resolution edges sharp.

Result

Load for 5 s Node.js Go, Base64 PNG Go, JPEG
5 req/s avg 419 ms avg 114 ms avg 29 ms
50 req/s avg 14,687 ms avg 458 ms avg 88 ms

From about 5 seconds per image to 30 ms for 20 images, on request, for any past time range, with custom resolution, distance power and wind settings instead of fixed options.

Read more




You have requested the PDF version of this page!
This page was not designed or optimized for your request.


You have a redirct option for your expected request:



  1. Checkout the PDF version: https://firebasestorage.googleapis.com/v0/b/panth-personal.firebasestorage.app/o/portfolio%2FPanth-Patel-Resume.pdf?alt=media



  2. Back to website: https://panth.vardayinitech.in/