The xamWebMap is a powerful and highly adaptable mapping control that is included with NetAdvantage for Data Visualization. It can be used to add powerful visualizations of geo-spatial data to your application. This article will walk you through the different options for binding and mapping data to the xamWebMap, as well as how you can create maps that reflect this data.
To get started working with data in the xamWebMap, you first need to load in some geographic data for the map to render. To do this, the xamWebMap reads and import data from the popular shape file format.
For more information on shape files see my blog post Explaining shape files and the xamWebMap
For the samples in this article, I am going create a single map layer which imports a shape file containing a map of the United States. This shape file contains polygons which represent the boundaries of state in the US. The code below shows how to, using XAML, import the shape file into the map layer using the ShapeFileReader class.
<UserControl x:Class="DataMappingDemo.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:igMap="clr-namespace:Infragistics.Silverlight.Map; assembly=Infragistics.Silverlight.DataVisualization.Map.v9.1"> <Grid x:Name="LayoutRoot" Background="White"> <igMap:XamWebMap x:Name="xamWebMap1"> <igMap:XamWebMap.Layers> <igMap:MapLayer x:Name="usa_st"> <igMap:MapLayer.Reader> <igMap:ShapeFileReader Uri="usa_st" /> </igMap:MapLayer.Reader> </igMap:MapLayer> </igMap:XamWebMap.Layers> </igMap:XamWebMap> </Grid> </UserControl>
Once the shape file is loaded, you can run the application and you should see the map now is displayed, and by default the map has selected a random Brush for each State.
To get started adding some data to this map lets look the ways you can get data into the xamWebMap. The first way is via the dbf files that normally accompany a shape file. These dbf files are dBase III format data files. They are structured in a fairly standard columnar format, and in fact you can even open then in Excel to examine their column structure. Open the dbf that accompanies the the shape file I loaded earlier reveals that there are quite a few columns of data available for us. When the xamWebMap loads the .shp file containing the shape files polygon data, it also automatically attempts to import a corresponding dbf file. If the dbf loads successfully, then you can map columns contained in the dbf, to properties exposed by the individual map elements created by the map when it loaded the shp file. For example, in the USA shape file I loaded, there are columns containing the states name, its FIPS code and its population. I can map these values to properties of the map elements by specifying a list of semicolon delimited key value pairs in the ShapeFileReaders DataMapping property (where the Key is the map element property name, and the value is the dbf column name):
<igMap:MapLayer.Reader> <igMap:ShapeFileReader Uri="usa_st" DataMapping="Name=STATE_FIPS;Caption=STATE_NAME;Value=POP1997" /> </igMap:MapLayer.Reader>
So in this case, I am mapping the map elements Name, Caption and Value properties from three columns in the dbf file. If I run the project now, see this is working because each Map Element now displays a caption:
Another cool thing about the DataMappings property is its ability to map data source columns to new properties on the Map Element. This means that I am not limited to mapping values from my data source to just existing properties, but can treat the Map Element essentially like a property bag, dumping all types of information (including complex objects like entire controls) into it that I might want to use later in my application. To map new properties, you simply provide a unique property name as the Key in a DataMappings Key/Value pair:
<igMap:MapLayer.Reader> <igMap:ShapeFileReader Uri="usa_st" DataMapping="Name=STATE_FIPS;Caption=STATE_NAME;Value=POP1997; Abbreviation=STATE_ABBR;Area=AREA;SubRegion=SUB_REGION" /> </igMap:MapLayer.Reader>
Now not only am I mapping columns in the dbf to existing map element properties, but I am adding three new ‘properties’ to the map element, mapping the states Abbreviation, Area and Sub-region. Later if I want to retrieve these values from a map element, I can simply use the objects GetProperty method and pass it the Key of the property value I want.
The second means of getting data into the xamWebMap is by using standard Silverlight data binding on the MapLayer object, which exposes a DataSource property. Like the ShapeFileReader, the MapLayer object also exposes its own DataMapping property which allows you to map values from an arbitrary data source such as a collection, to properties of the MapElement object.
To bind data to MapElements using the MapLayers DataSource property, you can simply assign some object that implements IEnumerable to the property, either in XAML or in code, then define the appropriate mappings using the MapLayers DataMappings property.
As an example, I have defined a class called StateUsage, which will contain data about the energy consumption per person for each state in the year 2001.
(The data is from the US Energy Information Administration, available on the US Census bureaus website)
public class StateUsage { public string State {get;set;} public int Units {get;set;} public int Rank {get;set;} }
I expose a simple List collection of StateUsage objects which I can them assign to the MapLayers data source property:
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e) { this.xamWebMap1.Layers["usa_st"].DataSource = EnergyUse.EnergyUseByState; }
I next set up a DataMapping on the layer. In this case I am mapping the three properties exposed by the StateUsage class to properties of the Map Element:
<igMap:MapLayer x:Name="usa_st" DataMapping="Name=State;Value=Units;Caption=Rank;">
Finally, I reconfigured the ShapeFileReaders data mappings so that I can associate the MapElement with StateUsage objects by using the state name value:
<igMap:ShapeFileReader Uri="usa_st" DataMapping="Name=STATE_NAME" />
Now when I run the sample, you can see that the MapElement captions have changed to show each states energy usage rank.
Once I have data mapped to a shape element, the map allows me to use these properties as tokens when setting other map properties. For example, in the previous sample we replaced the MapElements original string captions with the state energy usage Rank, but it would be nice if I could display both the state name and energy usage rank in the caption. To do this, I can set the Caption property on the map layer as shown below:
<igMap:MapLayer x:Name="usa_st" DataMapping="Name=State;Value=Units;Rank=Rank;" Caption="{}{Name} ({Rank})">
<igmap:maplayer datamapping="Name=State;Value=Units;Rank=Rank;" caption="{}{Name} ({Rank})" x:name="usa_st">Notice that a couple of things have changed in the MapLayer. First, I altered the MapLayers DataMapping property so that instead of the Rank property exposed by the StateUseage object is being mapped to the Caption, it is now mapped to a property of the MapElement called Rank. Next I define the MapLayers Caption property and for its value am using two data tokens which represent properties of the MapElement. The extra empty set of leading brackets is required in order to escape the use of the property token brackets in XAML. </igmap:maplayer>
Running this, you can see that the MapElements Caption is now shown as both the state name, and its rank (in parenthesis).
Now that we’ve looked at how you can bind data to the map, let’s look at actually using that data to create a chloropleth map. A chloropleth map is a thematic map in which areas of the map are shaded or patterned in proportion to the measurement of the statistical variable being displayed on the map, such as population density or per-capita income. In this sample I will show you how to use color shading to display the data of a chloropleth map.
To start creating the map, the first thing I have to do is tell the MapLayer that I want to change the way it fills its MapElements with color. By default, map layers are configured to fill their MapElements by randomly selecting colors from a the layers Brushes collection, but in the case of a chloropleth map I want the map layer to use MapElement fill color to visual represent its value, so selecting colors randomly is not appropriate. To change MapLayers default fill behavior, I can set its FillMode property. While I am there I can also provide it with a collection of brushes that it should use when calculating the MapElements fill colors.
<igMap:MapLayer x:Name="usa_st" FillMode="Chloropleth" Brushes="Green yellow Red" DataMapping="Name=State;Value=Units;Rank=Rank;" Caption="{}{Name} ({Rank})">
Next I need to add a scale to the map layer so that the map can calculate how each value in my data set is related proportionally to other values. The xamWebMap includes three different scale types, Linear, Logarithmic and Distribution. I can add a LinearScale to the MapLayer by assigning it to the ValueScale property:
<igMap:MapLayer.ValueScale> <igMap:LinearScale /> </igMap:MapLayer.ValueScale>
By default the LinearScale automatically determines the range of the map layers values, and calculates an appropriate number of value stops. You can also use the scales properties to configure these options manually.
Thats it. Running the sample results in a chloropleth map being generated which shows via color, how states energy usage is proportionally related to one another:
Viewing the data in the chloropleth map makes it quite easy to evaluate the data visually, rather than having to resort to a tabular grid view.
Finally in this article, I will look at how you can customize the appearance of a MapElement using the MapLayers ValueTemplate. The ValueTemplate exposes a DataTemplate that allows you to customize the contents of a MapElement. To demonstrate the use of the ValueTemplate, I will show you how you can use it to display an icon whose size is indicates the value of the MapElement.
The ValueTemplate property is a member of the MapLayer and accepts a data template. Within the data template, the data context is set to the map element, so its easy to bind to map element properties like the Value. In this sample we are using a special gauge control included with the map called the BubbleGauge. The BubbleGauge control will scale its contents based on the Value assigned to it. In this case we want to render an image that will grow or shrink based on the value of the MapElement, so I will bind the BubbleGauges Value property to the MapElements ScaledValue property. The ScaledValue property is a value from 0-1 that represents the proportional element value after being calculated by the map layers scale.
<igMap:MapLayer.ValueTemplate> <DataTemplate x:Key="ImageGaugeTemplate"> <igMap:BubbleGauge Value="{Binding ScaledValue}" Width="48" Height="48" IsHitTestVisible="True"> <Rectangle HorizontalAlignment="Center" VerticalAlignment="Center" ToolTipService.ToolTip="{Binding Value}"> <Rectangle.Fill> <ImageBrush ImageSource="Population.png"/> </Rectangle.Fill> </Rectangle> </igMap:BubbleGauge> </DataTemplate> </igMap:MapLayer.ValueTemplate>
If I wanted to, I could access any other property of the MapElement that has a getter, such as its Caption.
I also removed the caption mapping from the Map Layer just so that the map does not appear overly cluttered by having both Icons and Captions in each Map Element.
Running the sample, I now see icons added to the map in each MapElement, and he size of the icon indicates the MapElements value.
In this article I showed you how simple it is to integrate data into the xamWebMap using two different techniques. First I showed how to integrate data from the shapefile data files, and how you can use the data mapping capbilities of the map to bind columns in the data source to properties of Map Element. Next I looked at how you can bind data from an enternal data source, such as a database, to the Map. Finally I demonstrated using the data to create a chloropleth style map.