MSDN Magazine - December 2007 - (Page 57) Fill and Points properties to the appropriate properties on the underlying element. The LoadData method shown in Figure 13 is responsible for loading the primary map data into an instance of the Map class, setting it up as the DataContext for MasterCanvas, constructing the heat map, and then binding DataLayer to it. The portion of the method that is particularly interesting is the query, which is used to build the heat map. It works by joining the set of states displayed on the map, the set of counties loaded from disk, and XML population data. It joins the set of states with the set of counties in order to filter out counties that are defined in states that are not shown on the map. The key for the join, on both sides, is each region’s first FIPS code. In the case of a State, this will correspond to its numeric ID. In the case of a County, it corresponds to the counties containing a state’s numeric ID. The XML population data is then joined with results in order to associate each county’s population value with the MapRegion instance defining the county. The results of the join are then filtered to include population data only for the year 2006. This is necessary because the XML population data contains data for multiple years, and in this case I am only interested in showing one particular year on the map. Failing to filter based on year will also result in multiple overlapping polygons with different values being drawn on the map for the same region. The filtered results are cross-joined with the Polygons collection for each county. This effectively expands a collection of county regions into a collection of polygons. The final portion of the query is a Select statement that extracts the point collection from each polygon, calculates the color it should be displayed in based on its associated population value, and then constructs a SolidColorBrush that will render the region in that color. The color values are calculated using the colorMapEntries array, which defines a mapping between population values and colors. Essentially, each entry in the array defines a color and an associated upper-bound population value. The particular color used for a county is then interpolated from the two color map entries between which its population sits. The interpolation is implemented by the Interpolate extension method defined in Figure 14. It works by doing a binary search through the colorMapEntries array, looking for the smallest entry that has a population value greater than the provided value. It then takes that entry and the preceding entry and uses them to interpolate the appropriate color value. The way this is done is Figure 14 Interpolate Extension Method _ Function Interpolate(ByVal entries() As ColorMapEntry, ByVal value As _ Double) As Color Dim upperBound = entries.LeastUpperBound(value) Dim c As Color = Nothing If upperBound >= entries.Length Then c = entries(upperBound - 1).FillColor() ElseIf upperBound = 0 Then c = entries(0).FillColor Else c = entries(upperBound - 1).Interpolate(entries( _ upperBound), value) End If Return c End Function _ Function LeastUpperBound(ByVal entries() As ColorMapEntry, ByVal v As _ Double) As Integer Dim ret = Array.BinarySearch(entries, v, _ New ColorMapEntryToValueComparer) If ret < 0 Then ret = ret Xor -1 End If Return ret End Function by calling the Interpolate instance method that is defined on the ColorMapEntry class. Final Thoughts The great thing about my app is that it was easy to write. In particular, I made extensive use of Expression Blend to define its interface, thus making it a breeze to add stunning visual effects. I also used XML to store all the data the application uses to run. This enabled me to use the new integrated XML features in Visual Basic, along with LINQ, to painlessly implement all of the data manipulation logic. I also designed the interface to be built on top of the WPF data-binding infrastructure, thereby creating a cleanly separated, well-architected application that was built on top of a rich object model. Essentially, by using Visual Basic, WPF, Expression Blend, and LINQ, I was able to quickly and effectively throw together an application that makes relatively sophisticated visualizations from an existing body of data. This application could be easily extended to view data from different years, or manipulate the data in various ways. All of the code is available in the download for this article, so feel free to experiment and see what is possible. ■ 57 msdnmagazine Map LINQ Map LINQ december2007 57
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.