Temperature Gradient Maps with Mapbox GL
Mapbox is a great tool. It’s something that we have been working with for a while and have really enjoyed. However, we came across a situation where we needed to visualize data in a way that Mapbox doesn’t natively support. Normally, when working with mapping libraries a “heatmap” is a gradient displaying “hot spots” based on the density of points plotted on the map. In our case, we are actually trying to create a HEATmap, where we’re showing a gradient based on varying values of those individual points on the maps. We were actually a bit surprised there isn’t a way to do this already, since it would seem like a fairly common use case. However, as we got further into the development of a library to handle this for us, we started to see why it would be more of a niche application. So, given there was no magical library out there to handle our use case, TO THE KEYBOARD!
But First! Our First Iteration and Use Case
A couple years ago, we had a customer ask us to monitor some temperature sensors they put in one of their cold storage warehouses (think a refrigerator the size of a big box store). Their intent was to make sure their operators could effectively monitor temperatures across the facilities at a glance. The existing refrigeration system had a few sensors placed around the building that were used as setpoint inputs to control the system (just like a thermostat in your home). The customer wanted more granular visibility across the entire warehouse filled with highly valuable product. They had installed approximately 74 temperature sensors in a grid at two different heights (4 feet and 36 feet) so they could make sure product at floor level and at the top of the warehouse were both within specification. So we said we could just throw some average, median, and maximum temperatures up on a screen, but that becomes a sea of meaningless numbers at a glance. So we thought out loud to the customer, “Wouldn’t it be nice to see an actual color gradient so operators could quickly see hot spots?” “Why yes, that would be really cool. When can you have that to us?!”, said the customer. Then the real fun began. Of course, we assumed there was probably something out there that could do this automagically….nope. However, there was something similar that we had run across before that visualized wind speeds on a gradient (Null School’s earth wind map). In our first proof of concept for this, we based our implementation on how Null School had done their linear interpolation and drew a canvas on top of a map. We built it in about a month, and it was a very simple implementation built on top of Angular that would do a nice job of getting the point across and giving the operators a quick visual. The first day we released it to the customer, they immediately saw some hot spots and were able to fix the within minutes and hours instead of days or weeks. Also, when we say “hot spot” for these guys, we’re talking about a scorching 3 degrees Fahreinheit.
Building a New and Improved Version
We have been helping that same customer deploy and manage an army of temperature sensors for a different project, and they recently requested to implement the HEATmap at more of their facilities. Since we have made long strides in our architecture from two years ago, we set out to create a more scalable version of the temperature HEATmap from our original proof of concept. The biggest initial challenge was the amount of sensors that needed to be installed and linking those sensors to a physical location in the warehouse. We’ll do a more extensive blog post about the challenges in this specific step later, but it drove us to create a new application called “Dploy” that allows users to quickly provision, locate, and persist linkages between sensors. This linkage provides seamless integration of associated sensor data in our IOT service, the physical geometry of sensor locations, and the labels that are put onto the physical sensor. Without this application, it would take someone an entire week to provision a grid of 1000 sensors (believe us — we know because we did it). It is also a very error-prone process because of all the moving parts. With the Dploy application, the provisioning process is knocked down to just around 20–30 minutes — a MASSIVE improvement.
Now that we have an application to give us the structure for all of the relationships between buildings, rooms, and sensors, we could build a more scalable and flexible version of the temperature gradient map. The creation of a new application became a reality (and we needed a name for the GitHub repo), so we decided to give it a name to make it official: nSight:Mapping. In this new version, we structured the application to easily be able to add other mapping capabilities in the future. The new and improved gradient map provides a Facility-level layer users can apply if other types of data are available for their facility.
The Nitty Gritty
We needed to be able to interact/animate and explore the data deeper than just an image and we could use Mapbox GL to make it more interactive and super pretty. We knew there had been previous implementations of Mapbox in React so we set down that path.
The first thing was to get Mapbox working with React. We started with our custom React starter app and our component library to get it up and running and before you know it, we had Mapbox GL loaded into React.
Next, we needed to get our data loaded from our API (#bigdata, #IoT, #buzzwords) so that we could start visualizing this thing. Our geometries are all stored as GeoJSON, so it dovetails very nicely with Mapbox and we started chugging right along with loading buildings and rooms. In order to properly do what we wanted to do we needed to leverage Mapbox’s ability to embed a <canvas> as a layer. This way we could leverage bilinear interpolation to color the canvas and add all the pretty stuff. Just to prove it was working, we used solid colors and whammo!
Great! We proved that we could load canvases, now we needed to do the heavy lifting. We needed to render gradients based on temperature data for a room and we needed it to calculate (interpolate) the differences between the temperatures to show a smooth gradient. We found this great Github repo that rendered gradients on a canvas, so we forked and modified it to fit with our needs. We did a lot of tinkering, optimizing, tweaking and we started to get close to what we were trying to do, but it was computationally EXPENSIVE! Rendering 7 canvases, calculating their gradients, and then having Mapbox layer them in got the fan on my Macbook Pro whirring pretty fiercely.
We simplified the loops, limited the amount of rendering we were doing and generally optimized the code. It resulted in some modest improvements, but nothing too substantial. Then it dawned on us — since we are blending the gradients already, we can render them at a smaller size and scale them up. Changing the <canvas> dimensions from 1000x1000 to 150x150 resulted in A LOT less computation and the improvements were drastic.
Disclaimer: it is still expensive to run but is a fraction of what it was.
Hit refresh, cross your fingers…….BOOM!
We are now getting color gradients based on data. But from this view, it doesn’t look all that impressive. “I just see mostly blue with some red and purple” you say? Well, that is because the gradient difference is quite large since some rooms are refrigerators and some are blast freezers. Room 1, for example, might be between -2° F and -4° F degrees but the entire facility is between -2° F and 37° F. That large of a range causes the rooms to look like one color. We needed a way to get tighter ranges. By allowing a user to pick a specific room and toggle between Global and Local scale, we are able to get more specific.
Wow, that was exhausting, but we were able to get to a much improved version of the temperature gradient that allowed users and warehouse operators to leverage a massive amount of data and quickly derive valuable meaning out of it. To make it more robust, we added the ability to click on a sensor for more information, rollover to see real-time temperature updates in the legend, and also the ability to show data over time, plus much more.
A lot was learned, a lot of tears shed, and we were forced to be creative in order to serve our customers’ needs to make an awesome new product.
In a few follow-up posts (when we find the time) we’ll write about how exactly we store this information and how other future applications can leverage the same data from our microservice-based APIs. Also, we’ll go into how this could be used for other kinds of data besides just temperature data and the future of nSight:Mapping.