Skip to main content

Cloud

Creating a Heat Map for Virtual Earth Polygons

Over the past six months, I’ve been experimenting a lot with the Virtual Earth Map Control. I must say that I’ve been really impressed with the great community out there contributing guidance and code examples to help folks learn what this stuff is all about. There is a tangible level of excitement for this kind of technology.

So in this spirit, I thought I’d throw in a few bits of my own work. My particular area of focus has involved loading shape data via an ETL process and plotting them as polygons on maps. That in itself isn’t a big deal, but devising a process to shade these polygons based on some kind of metric took a bit of thinking. And I don’t mind saying a bit more JavaScript than I’d like to be involved with. 😉 Here is what the end-result is:

image

Here is the JavaScript function I wrote to achieve it:

   1: function AddShades(measureIndex) {
   2:  
   3:             var shadeCount;
   4:             var colorGroup;         // Determines the shade
   5:             var sequenceNum;
   6:             var lastMbrNmbr = 0;    //set default value to zero.
   7:             var shape;
   8:             var shapeLayer = map.GetShapeLayerByIndex(0);   // Get the current shape layer
   9:             var shapeCount = shapeLayer.GetShapeCount();
  10:             var geoEntityCount = arrGeoEntityData.length;
  11:             var arrGeoEntityColorGroup = new Array();
  12:  
  13:             shadeCount = 6;         // To be dynamically retrieved from web.config in a future rev.
  14:             colorGroup = 0;         // Set initial color modification
  15:                         
  16:             // Calcualte the size of a shade group
  17:             var groupSize = ((geoEntityCount / shadeCount) | 0) + 1;
  18:  
  19:             // Sort GeoEntityData (ascending).  This uses the second column of the multi-dimensional array
  20:             arrGeoEntityData.sort(function(a, b) { return a[measureIndex] - b[measureIndex] });
  21:             
  22:             /********************************************************
  23:               Assign color group to GeoEntity
  24:             *********************************************************/
  25:             for (var i = 0; i < arrGeoEntityData.length; i++) {
  26:                 
  27:                 sequenceNum = i % groupSize;
  28:  
  29:                 // Increment group ID if necessary. When a shape's sequence number is smaller than
  30:                 // its predecessor, it means the shape needs to be assigned to a different color group.
  31:                 if (sequenceNum < lastMbrNmbr) {
  32:                     colorGroup = colorGroup + 1;
  33:                 }
  34:                 lastMbrNmbr = sequenceNum;
  35:  
  36:                 // Assign the Geo Entity to a color group.
  37:                 arrGeoEntityColorGroup[i] = new Array(2);
  38:                 arrGeoEntityColorGroup[i][0] = arrGeoEntityData[i][0];
  39:                 arrGeoEntityColorGroup[i][1] = colorGroup;
  40:             }
  41:  
  42:             /*********************************************************
  43:              Iterate though all VEShapes in shape layer, match with GeoEntities,
  44:              and assign the shade based on the color group
  45:             **********************************************************/
  46:             for (var i = 0; i < shapeLayer.GetShapeCount(); i++) {
  47:  
  48:                 shape = shapeLayer.GetShapeByIndex(i);
  49:
               var VEShapeLabel = shape.GetTitle();
  50:  
  51:                 for (var j = 0; j < arrGeoEntityColorGroup.length; j++) {
  52:  
  53:                     var geoEntityLabel = arrGeoEntityColorGroup[j][0];
  54:                     var colorGroup = arrGeoEntityColorGroup[j][1];
  55:  
  56:                     if (VEShapeLabel == geoEntityLabel) {
  57:                         shape.SetFillColor(new VEColor(colorGroup * 51, 0, (51 - (colorGroup * 10)), .5));
  58:                     }
  59:                 }
  60:             }
  61:         } // End Function

Here are some important points about my implementation:

The heat map colors are always relative. There are no hard-coded variables to determine a particular color. Instead, a list of geographic entities is populated and stored as a globally-scoped, multi-dimensional array. The size of this list (line 10) and the number of color groups (line 13) determines the size of each color "bucket" into which the geographic entities will be assigned.

The multi-dimensional array I mention in the previous paragraph is important. In my design, I make a distinction between shapes on the map and a particular geographic entity (zip code in this case). This is important because a given geographic entity can be composed of more than one distinct shape. This is certainly true with zip codes. In this design, information about each entity is stored arrGeoEntityData in the following format:

0 1 2
0 60640 502 17,342
1 60606 562 74,144
2 60525 807 45,348

…where the first index represents the entity label or name. For matching, the same value is stored in the Virtual Earth shape’s Title attribute. The following indexes represent business metrics which will be used to generate the heat map. These indexes are used as the parameter (Line 1) for the overall function and allows for a user to potentially change to a different heat map. The array is sorted (Line 20) based on the index of the metric and the color assignment process begins.

Since the array is sorted, I’m then able to use the calculation in Line 27 to place shapes into their respective color buckets. The following screenshot illustrates the process.

image

The rest is fairly academic. There are way too many FOR loops than I would like, but I attribute a lot of that to my relatively amateurish JavaScript skills (I’m not a web developer).

So it looks like the next step for me would be to build a legend based on this data. Hopefully, I’ll be able to get to that shortly in a follow-up installment.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Travis Nielsen

More from this Author

Follow Us