Visualizing point-based Business Intelligence data on Bing Maps

It is often said that upwards of 80% of business data has some sort of location based context to it. In recently years many companies have learnt the value of unlocking this data and making use of it to make better business decisions. Many companies use Bing Maps to make better sense of their business data by visualizing it on a map. In this blog post we are going to take a look at many of the different ways point based business data can be presented on top of Bing Maps.

All source code for this blog can be found on the MSDN Code Samples Gallery here.

Getting started

To get started open up Visual Studio and create a new ASP.NET Empty Web Application project called CustomBIPushpins.

clip_image002

Screenshot: Creating the project in Visual Studio

Once the project is loaded add a new HTML page called index.html by right clicking on the project and selecting Add → New Item. Then create two folders called js, and images. Inside the js folder create two files called CustomBIPushpins.js and PushpinFactor.js. The CustomBIPushpin.js file will contain all the code required for loading the map and handling button click events from the index.html page. The PushpinFactory.js used to create a reusable set of code for generating useful pushpins for representing business intelligent point based data. The index.html file will consist of a map and several buttons. Update this file with the following HTML:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Custom BI Pushpins</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
    <script type="text/javascript" src="js/CustomBIPushpins.js"></script>
    <script type="text/javascript" src="js/PushpinFactory.js"></script>
</head>
<body onload="GetMap();">
    <div id='myMap' style="position:relative;width:600px;height:400px;"></div><br/>
    <input type="button" value="Colored Image Pushpins" onclick="ShowColoredImagePins();" />
    <input type="button" value="Colored Pushpins" onclick="CreateColoredPins();" />
    <input type="button" value="Font Pins" onclick="CreateFontPins();" />
    <input type="button" value="Scaled Circles" onclick="CreateScaledCircles();"/>
    <input type="button" value="Scaled Pie Charts" onclick="CreatePieCharts();" />    
</body>
</html>

Next open the CustonBIPushpins.js file. In here we will load the map and generate an array of random locations which we will use for creating pushpins. The map will be set to display the road maps as it is much better suited for visualizing business intelligence data. We will create a simple function for generating random colors as it will be useful for testing out our different custom pushpin. Finally we will also create the event handlers for all the buttons on the page. Update the CustomBIPushpins.js file with the following code:

var map;
var randLocations = [],
    maxValue = 5000;

function GetMap() {
    map = new Microsoft.Maps.Map(document.getElementById("myMap"), {
        credentials: "YOUR_BING_MAPS_KEY" ,
        mapTypeId: Microsoft.Maps.MapTypeId.road
    });

    GenerateTestLocations();
}

function GenerateTestLocations() {
    for (var i = 0; i < 50; i++) {
        randLocations.push(new Microsoft.Maps.Location(Math.random() * 170 - 85, Math.random() * 360 - 180));
    }
}

function GetRandomColor(alpha) {
    alpha = alpha || 255;

    return new Microsoft.Maps.Color(alpha,
        Math.round(Math.random() * 255),
        Math.round(Math.random() * 255),
        Math.round(Math.random() * 255));
}

function ShowColoredImagePins() {
}

function CreateColoredPins() {
}

function CreateFontPins() {
}

function CreateScaledCircles() {
}

function CreatePieCharts() {
}

Next, open the PushpinFactory.js file. In here we will create a simple class called PushpinFactory where we will add our code for generating the different types of pushpins. This will make it easy to reuse this code in other projects. In this class we will add two helper functions. The first will merge two simple objects together, and the second will calculate a pixel radius for a value based on its linear relation to some maximum value. We will also add a number of placeholder functions which we will add our code to later in this blog. Add the following code to the PushpinFactor.js fie.

var PushpinFactory = new function () {

    //Function for merging to simple objects
    function mergeObjects(first, second) {
        if (second != null) {
            for (key in second) {
                first[key] = second[key]
            }
        }
        return first;
    }

    //Calculates a pixel radius based on a values linear relation to a maximum value.
    //Radius is bounded by min/max radius values.
    function calculateRadius(value, maxValue, minRadius, maxRadius) {
        value = value || 0;

        var radius = value / maxValue * maxRadius;

        if (radius < minRadius) {
            radius = minRadius;
        } else if (radius > maxRadius) {
            radius = maxRadius;
        }

        return radius;
    }

    this.ColoredPin = function (location, options) {
    };

    this.FontPins = function (fontStyle) {
    };

    this.ScaledCircles = function (minRadius, maxRadius, maxValue) {
    };
    
    this.PieCharts = function (colorMap, minRadius, maxRadius, maxValue) {
    };
};

At this point the base application is all set up. If you run the project you will see a webpage open that consists of a map, and several buttons. Pressing any of the buttons won’t do anything thing as we haven’t yet added any of the logic to them yet. Here is a screenshot of what the application looks like:

clip_image004

Screenshot: Base Webpage

Making use of Color

One of the most common ways to visualize business intelligence data is through the use of color. The three most common colors used are green, yellow, and red which corresponds to the colors of a traffic light and usually have a similar meaning. If a data point is green then things are good, if it is yellow then take warning, if it is red then there is an issue. One method of showing different colored data points on a map is to use different colored images. In Bing Maps you can easily create a custom pushpin using an image. Take the following three images and copy them to the images folder of the project. You can either copy them from this blog post, or from the source code in the MSDN Code Sample Gallery.

clip_image006

clip_image008

clip_image010

green_pin.png

yellow_pin.png

red_pin.png

Open the CustomBIPushpins.js file. In update the ShowColoredImagePins with the following code. This code will create simple pushpins using different colored images.

function ShowColoredImagePins() {
    map.entities.clear();

    for (var i = 0; i < randLocations.length; i++) {
        var color;

        switch (i % 3) {
            case 0:
                color = 'green';
                break;
            case 1:
                color = 'yellow';
                break;
            case 2:
                color = 'red';
                break;
        }

        var pin = new Microsoft.Maps.Pushpin(randLocations[i], {
            icon: 'images/' + color + '_pin.png',
            text: i + ''
        });

        map.entities.push(pin);
    }
}

This code generates pushpins that use a different colored images. A text value is also added to the pushpin that is equal to the index of the location in the random location array. If you run the application and press the Colored Image Pins button you will see a bunch of different colored pushpins appear on the map with a number written on top of them like the image below.

clip_image012

Screenshot: Colored Image Pushpins

This works very well and didn’t take a whole lot of work to implement. However, having the different colored images already created made things easy. What if we wanted to support more colors, or wanted to 3 different colors? We would need to create new images that had the colors we wanted. Developers are not graphic designers and having new images created could require waiting for someone else to create them which is less than ideal.

Another approach to creating colored pushpins is to create one using a combination of custom HTML, and an image that has a transparent area for where the color will appear. What we can do is draw a circle where the color would appear on the image and overlay the image above it. This will allow us to set the color programmatically. Here is the image we will be using for this. Copy it to the images folder.

clip_image014

transparent_pin.png

I showed how to do this same thing using the HTML5 Canvas a while back in a blog post on creating HTML5 Canvas pushpins. The HTML5 Canvas method works well but is a bit clumsy as it requires assigning each canvas with a unique id so we can access it from JavaScript after the pushpin is added to the map, after which we can then draw the require image on the canvas. Another way to create our colored circle is to use Scalar Vector Graphics (SVG). SVG is an XML based format for representing 2 dimensional shapes and is supported in IE 9 and above. Here is an example of using SVG to create a red circle on a webpage:

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <svg height="50" width="50" version="1.0" xmlns="http://www.w3.org/2000/svg">
        <circle cx="25" cy="25" r="25" style="fill:#ff0000;" />
    </svg>
</body>
</html>

We can easily generate the XML required for the circle and the image as a block of HTML and pass that directly into the htmlContent property of a Bing Maps pushpin. In the PushpinFactory.js file, update the ColoredPin function in the PushpinFactory class with the following code:

this.ColoredPin = function (location, options) {
    options.icon = options.icon || 'images/transparent_pin.png';
    options.width = options.width || 24;
    options.height = options.height || 37;
    options.fillColor = options.fillColor || new Microsoft.Maps.Color(255, 0, 175, 255);
    options.anchor = options.anchor || new Microsoft.Maps.Point(13, 37);

    var pinHTML = ['<svg height="',
                options.width, '" width="', options.height,
                '" version="1.0" xmlns="http://www.w3.org/2000/svg"><circle cx="13" cy="13" r="11" style="fill:',
                options.fillColor.toHex(),
                ';fill-opacity:1;"/></svg><img style="position:absolute;top:0;left:0;" src="', options.icon, '"/>'];

    if (options.text) {
        pinHTML.push('<span style="position:absolute;left:0px;color:#fff;font-size:12px;text-align:center;width:', options.width, 'px;top:5px;">', options.text, '</span>');
    }

    options.htmlContent = pinHTML.join('');

    return new Microsoft.Maps.Pushpin(location, options);
};

This code generates HTML that consists of an SVG circle with our transparent pushpin image overlaid on top, and a span for rendering text on top of the pushpin. The pushpin class in Bing Maps supports displaying text on the pushpin by default, so it makes sense to maintain this functionality as it is a useful feature to have. This function then returns a Bing Maps pushpin object that contains this custom HTML.

To implement this new pushpin creation function, open the CustomBIPushpin.js file and update the CreateColoredPins function with the following code:

function CreateColoredPins() {
    map.entities.clear();

    for (var i = 0; i < randLocations.length; i++) {
        var pin = new PushpinFactory.ColoredPin(randLocations[i], {
            fillColor: GetRandomColor(),
            text: i + ''
        });

        map.entities.push(pin);
    }
}

If you run the application and press the Colored Pins button you will see a bunch of different colored pushpins appear on the map with a number written on top of them like the image below.

clip_image016

Screenshot: Programmatically Colored Pushpins

Making use of Symbols and Icons

Another great way to represent data on a map is to use different symbols or icons. Some common shapes used in business intelligence dashboards are check mark, an x, circle, triangle, square, diamond, and star. We could use different shapes to distinguish against different types of data.

Let’s take for a moment that we wanted to show how busy hospitals and clinics are on a map. We could use an H symbol to represent the locations of the hospitals and a cross symbol to represent the location of all clinics. We could then use different colors to indicate the how busy each location is.

Similar to the previous section we could create a bunch of images to create custom pushpins, but this could be a nightmare if we need to several different symbols that are in several different colors. Another, more interesting method is to use symbol fonts to create our icons. This is actually something that is often done in Windows Store apps for creating buttons.

To create pushpins using symbol fonts we first need to find a font that we can use across all the web browsers our app will be viewed on. Unfortunately there is not standard symbol font that’s available in all web browsers today. To get around this we can find a symbol font online that has suitable icons in it and host it as part of our application. There are a lot of free symbol fonts available on the web. Doing a quick Bing search and I came across the WebHostingHub Glyphs font which is available as a TrueType Font (TTF) file. TTF files are only supported on Windows devices.

Custom fonts can be used in web pages using the @font-face property. Unfortunately each web browser supports different types of font files. Earlier versions of Internet explorer only support EOT files, while newer versions support TTF. There are a couple of other font file formats that are used by other browsers as well. To accommodate this we can take the TTF file for our symbol font and generate all the other font files using a simple online tool like the web font generator found here. Once you have all the different font files create a new folder in the project called fonts and copy all these files into there. At this point your project should look like this:

clip_image018

Screenshot: Project structure

Tip: Looking in the font folder you will notice there is a demo HTML file. If you open this up it contains all the character codes for all the symbols in the font file. Here are some mapping and business intelligence related icons and there Unicode value:

clip_image020

Image: Mapping related font icons and their Unicode value

Looking in the stylesheet.css file you will see how the @font-fact CSS property is used to create a custom font that falls back on the different font file formats based on browser support like so:

@font-face {
    font-family: 'webhostinghub-glyphsregular';
    src: url('webhostinghub-glyphs.eot');
    src: url('webhostinghub-glyphs.eot?#iefix') format('embedded-opentype'),
         url('webhostinghub-glyphs.woff2') format('woff2'),
         url('webhostinghub-glyphs.woff') format('woff'),
         url('webhostinghub-glyphs.ttf') format('truetype'),
         url('webhostinghub-glyphs.svg#webhostinghub-glyphsregular') format('svg');
    font-weight: normal;
    font-style: normal;
}

To add this new font to the app, open the index.html file and add the following CSS link reference to the head section of the page:

<link rel="stylesheet" href="fonts/stylesheet.css" type="text/css" />

We can now generate HTML that displays a symbol by using a custom font. In the PushpinFactory.js file, update the FontPins function in the PushpinFactory class with the following code:

this.FontPins = function (fontStyle) {
    this.Create = function (location, size, options) {
        size = size || 12;
        options = options || {};
        options.fillColor = options.fillColor || defaultFillColor;

        var html = ['<div style="text-align:center;width:', size, 'px"><span style="font-family:\'', fontStyle, '\';font-size:', size,
            'px;width:', size * 2, 'px;text-align:center;color:', options.fillColor.toHex(), ';">', options.icon, '</span>'];

        if (options.text) {
            html.push('<span style="position:absolute;left:0px;color:#fff;font-size:12px;text-align:center;width:', size, 'px;top:', size / 2 - 6, 'px;">', options.text, '</span>');
        }

        html.push('</div>');

        return new Microsoft.Maps.Pushpin(location, {
            height: size,
            width: size,
            htmlContent: html.join('')
        });
    };
};

To implement this new function, open the CustomBIPushpins.js file and update the CreateFontPins function with the following code:

function CreateFontPins() {
    map.entities.clear();

    var glyphs = ['', '', '', '↸', ''];

    var pinFactory = new PushpinFactory.FontPins('webhostinghub-glyphsregular');

    for (var i = 0; i < randLocations.length; i++) {
        var pin = pinFactory.Create(randLocations[i], 25, {
            fillColor: GetRandomColor(150),
            icon: glyphs[i % glyphs.length],
            text: i + ''
        });

        map.entities.push(pin);
    }
}

This code will draw circles, square, starts, house, and fire icons on the map as pushpins. If you run the application and press the Font Pins button you will see the different symbol icons displayed in different colors on the map with a number written on top of them like the image below.

clip_image022

Screenshot: Map with symbol icons

There are a lot of benefits to creating pushpins in this way:

  • We can easily change the size and color of the pushpins using code.
  • The size of a font file is about the size of a few images, yet it can contain hundreds of images in it.
  • They work great on Retina displays.

Making use of Size and Scale

Another useful way to visualize business intelligence data on a map is to use size and scale. Showing something bigger or smaller can easily be a reference to some metric about the location. Going back to the earlier example of the hospitals and clinics, we could change the size of each icon based on the size of the location. A larger hospital could display a large symbol than a smaller one.

There are a couple of different methods that can be used to scale the size of a pushpin:

  • Create multiple images of the different sized pushpins that are required. This can be a lot of work and hard to maintain if different color, sizes, or shapes are required.
  • Use CSS transforms to scale the pushpin.
  • Use SVG or the HTML5 canvas to draw the required shape at the required scale.

We are going to take a look at that last option and create a function for generating scaled circles. For this function to work we need to have a maximum value to scale all other values against. It is also useful to be able to specify the minimum and maximum pixel radii’s to limit the size of our circles. In the PushpinFactory.js file update the ScaledCircles function with the following code:

this.ScaledCircles = function (minRadius, maxRadius, maxValue) {

    maxValue = maxValue || 100;
    minRadius = minRadius || 1;
    maxRadius = maxRadius || 50;

    var defaultFillColor = new Microsoft.Maps.Color(150, 0, 175, 255),
        defaultStrokeColor = new Microsoft.Maps.Color(150, 130, 130, 130),
        defaultStrokeThickness = 2;

    function createCircleHTML(radius, options) {
        options = options || {};
        options.fillColor = options.fillColor || defaultFillColor;
        options.strokeColor = options.strokeColor || defaultStrokeColor;
        options.strokeThickness = options.strokeThickness || defaultStrokeThickness;

        var circleHTML = ['<div"><svg height="',
                radius * 2, '" width="', radius * 2,
                '" version="1.0" xmlns="http://www.w3.org/2000/svg"><circle cx="',
                radius, '" cy="', radius, '" r="', radius,
                '" style="fill:', options.fillColor.toHex(),
                ';stroke:', options.strokeColor.toHex(),
                ';stroke-width:', options.strokeThickness,
                ';fill-opacity:', options.fillColor.getOpacity(),
                ';stroke-opacity:', options.strokeColor.getOpacity(),
                ';"/></svg>'];

        if (options.text) {
            circleHTML.push('<span style="position:absolute;left:0px;color:#fff;font-size:12px;text-align:center;width:', radius * 2, 'px;top:', radius - 6, 'px;">', options.text, '</span>');
        }

        circleHTML.push('</div>');

        return circleHTML.join('');
    }

    this.Create = function (location, value, options) {
        var radius = calculateRadius(value, maxValue, minRadius, maxRadius);

        var pin = new Microsoft.Maps.Pushpin(location, {
            anchor: new Microsoft.Maps.Point(radius, radius),
            height: radius * 2,
            width: radius * 2,
            htmlContent: createCircleHTML(radius, options)
        });

        pin.setValue = function (val, opt) {
            value = val;
            radius = calculateRadius(value, maxValue, minRadius, maxRadius);
            options = mergeObjects(options, opt);

            pin.setOptions({ htmlContent: createCircleHTML(radius, options) });
        };

        pin.getValue = function(){
            return value;
        };

        return pin;
    };
};

Next open the CustomBIPushpin.js file and update the CreateScaledCircles function with the following code:

function CreateScaledCircles() {
    map.entities.clear();

    var pinFactory = new PushpinFactory.ScaledCircles(10, 40, maxValue);

    for (var i = 0; i < randLocations.length; i++) {
        //create a mock value;
        var val = Math.round(Math.random() * maxValue);

        var pin = pinFactory.Create(randLocations[i], val, {
            fillColor: GetRandomColor(150),
            text: val + ''
        });

        map.entities.push(pin);
    }
}

Looking at this code we can see that we specify a random color as the fill color for the circle. We also pass in a text value which is displayed in the center of the circle. In this case the text value is the number value assigned to the circle which is scaled against a maximum value of 5000. This type of pushpin is a great option for representing clustered pushpins when implementing client side clustering. If you run the application and press the Scaled Circles button you will see a number of circles drawn on the map that are different sizes and color.

clip_image024

Screenshot: Scaled circles on a map

Combining Color and Size as Pie Charts

So far we have looked at Color, Symbol and Scale as ways to display business intelligence data on Bing Maps. A common way of visualizing business intelligence data in general is to use a pie chart. Pie charts make use of color to and size to represent a slice of a circle among a group of values. We can easily create a pie chart icon based on some data and display that as a location on the map. This is a great way to show multiple values for a simple location. Another thing we can do is make use of size to relate the total value within each pie chart on the map such that pie charts that have a smaller value will be smaller in size than those with more value.

The following code generates a pie chart using SVG. It also provides a hover over effect that displays an associated text near the middle of the pie chart when you hover over a slice of the pie. Open the PushpinFactory.js file and update the PieCharts function and add the ShowTooltip and HideTooltip functions to the PushpinFactory class:

this.PieCharts = function (colorMap, minRadius, maxRadius, maxValue) {

    maxValue = maxValue || 100;
    minRadius = minRadius || 1;
    maxRadius = maxRadius || 50;

    var defaultStrokeColor = new Microsoft.Maps.Color(150, 130, 130, 130),
        defaultStrokeThickness = 2;       

    function createArc(cx, cy, r, startAngle, angle, fillColor, strokeColor, strokeThickness, text) {
        var x1 = cx + r * Math.sin(startAngle);
        var y1 = cy - r * Math.cos(startAngle);
        var x2 = cx + r * Math.sin(startAngle + angle);
        var y2 = cy - r * Math.cos(startAngle + angle);

        //Flag for when arcs are larger than 180 degrees
        var big = 0;
        if (angle > 180) {
            big = 1;
        }

        var path = ['<path d="M ', cx, ' ', cy, ' L ', x1, ' ', y1, ' A ', r, ',', r, ' 0 ', big, ' 1 ', x2, ' ', y2,
            ' Z" style="fill:', fillColor.toHex(),
            ';stroke:', strokeColor.toHex(),
            ';stroke-width:', strokeThickness,
            ';fill-opacity:', fillColor.getOpacity(),
            ';stroke-opacity:', strokeColor.getOpacity(),
            ';"'];
              
        if(text){
            path.push('onmouseover="PushpinFactory.ShowTooltip(evt, \'', text, '\');" onmouseout="PushpinFactory.HideTooltip(evt)"');
        }

        path.push('/>');

        return path.join('');
    }

    function createPieChartHTML(values, total, numSlices, radius, options) {
        options = options || {};
        options.strokeColor = options.strokeColor || defaultStrokeColor;
        options.strokeThickness = options.strokeThickness || defaultStrokeThickness;

        var pieChart = ['<div style="overflow:visible;"><svg height="',
                radius * 2, '" width="', radius * 2,
                '" version="1.0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'];

        var cx = radius, cy = radius, startAngle = 0, angle = 0, text;

        for (var i = 0; i < numSlices; i++) {
            angle = (Math.PI * 2 * (values[i] / total));

            text = (options.text && i <= options.text.length) ? options.text[i] : null;

            pieChart.push(createArc(cx, cy, radius, startAngle, angle, colorMap[i], options.strokeColor, options.strokeThickness, text));
            startAngle += angle;
        }
            
        if (options.text) {
            pieChart.push('<rect style="fill:white;stroke:black;stroke-width:1;opacity:0.8;" x="');
            pieChart.push(radius -4, '" y="', radius - 13, '" rx="4" ry="4" width="55" height="17" visibility="hidden"/>');
            pieChart.push('<text style="font-size: 12px;" x="', radius, '" y="', radius, '" visibility="hidden">Tooltip</text>');
        }

        pieChart.push('</svg></div>');

        return pieChart.join('');
    }

    this.Create = function (location, values, options) {
        //Calculate number of slices of pie.
        var numSlices = Math.min(values.length, colorMap.length);

        //Calculate the total of the data in the pie chart
        var total = 0;
        for (var i = 0; i < values.length; i++) {
            total += values[i];
        }

        var radius = calculateRadius(total, maxValue, minRadius, maxRadius);

        var pin = new Microsoft.Maps.Pushpin(location, {
            anchor: new Microsoft.Maps.Point(radius, radius),
            height: radius * 2,
            width: radius * 2,
            htmlContent: createPieChartHTML(values, total, numSlices, radius, options)
        });

        pin.setValues = function (val, opt) {
            values = val;

            numSlices = Math.min(values.length, colorMap.length);

            total = 0;
            for (var i = 0; i < values.length; i++) {
                total += values[i];
            }

            radius = calculateRadius(total, maxValue, minRadius, maxRadius);
            options = mergeObjects(options, opt);

            pin.setOptions({ htmlContent: createPieChartHTML(values, total, numSlices, radius, options) });
        };

        pin.getValues = function () {
            return values;
        };

        return pin;
    };
};
    
this.ShowTooltip = function (evt, mouseovertext) {
    var textNodes = evt.target.parentNode.getElementsByTagName('text');

    if (textNodes && textNodes.length > 0) {
        var tooltip = textNodes[0];
        tooltip.firstChild.data = mouseovertext;
        tooltip.setAttributeNS(null, "visibility", "visible");

        var rectNodes = evt.target.parentNode.getElementsByTagName('rect');

        if (rectNodes && rectNodes.length > 0) {
            var tooltip_bg = rectNodes[0];

            var length = tooltip.getComputedTextLength();
            tooltip_bg.setAttributeNS(null, "width", length + 8);
            tooltip_bg.setAttributeNS(null, "visibility", "visibile");
        }
    }
};

this.HideTooltip = function (evt) {
    var textNodes = evt.target.parentNode.getElementsByTagName('text');

    if (textNodes && textNodes.length > 0) {
        var tooltip = textNodes[0];
        tooltip.setAttributeNS(null, "visibility", "hidden");
    }

    var rectNodes = evt.target.parentNode.getElementsByTagName('rect');

    if (rectNodes && rectNodes.length > 0) {
        var tooltip_bg = rectNodes[0];
        tooltip_bg.setAttributeNS(null, "visibility", "hidden");
    }
};

To implement the pie charts open the CustomBIPushpins.js file. In the CreatePieChart function we will generate 5 random values for coloring the pie charts. For each pie chart we will generate 5 random values and will also create text values to be used when hovering over a slice of the pie chart. Update the CreatePieChart function with the following code:

function CreatePieCharts() {
    map.entities.clear();

    var colorMap = [];

    //Generate 5 random colors for the pie chart.
    for (var j = 0; j < 5; j++) {
        colorMap.push(GetRandomColor(255));
    }

    var pinFactory = new PushpinFactory.PieCharts(colorMap, 15, 50, maxValue);

    for (var i = 0; i < randLocations.length; i++) {
        //Create mock value data;
        var vals = [], textVals = [];

        for (var j = 0; j < 5; j++) {
            var val = Math.round(Math.random() * maxValue / 5);
            vals.push(val);
            textVals.push(val + '');
        }

        var pin = pinFactory.Create(randLocations[i], vals, { text: textVals });
        map.entities.push(pin);
    }
}

If you run the application and press the Create Pie Charts button you will see a bunch of different sized pie charts displayed on the map like the following image.

clip_image026

Screenshot: Pie charts on a map

If you hover over one of the slices of a pie chart you will also see the associated text for that piece of pie. In this case I’m showing the value associated with that slice, but we could just as easily show a different label if we wanted to.

clip_image028

Screenshot: Hover over of a pie chart on the map

Other Visualization Methods

At this point we have seen a number of different ways to visualizing point based business data on Bing Maps. Here are a couple of other ideas for visualizing point based business data.

Density based Heat Maps

Heat maps are an effective means of visualizing geography-based trends by showing the relative density of location-based data. We can see where we have ‘hot spots’ in our data, and use this insight to drive better decisions for application users. A heat map module for Bing Maps is available on the Bing Maps V7 modules CodePlex project here. Here is a screenshot of what these heat maps look like:

clip_image030

Screenshot: Heat Map module example

We have blogged about using the heat map module a number of times on the Bing Maps blog. Here are some of the more recent blog posts:

3D Bar Charts

View data as a 3D bar chart can be useful, especially if you have a 3D map. If you have Office 2013 with the Power BI tools you can make use of Power Map. Power Map is a three-dimensional (3D) data visualization tool that lets you view your data in a number of different ways on a map, such as 3D charts, heat maps, and timelines.

clip_image032

Screenshot: Excel Power Map displaying 3D bar charts on a map

If you are working with business data in Excel I also recommend at taking a look at a previous blog post I wrote on 4 Easy Ways to Visualize Excel Data on Bing Maps.

If you are doing custom development and need a 3D map that works in the web browser and can easily display 3D bar charts then take a look at the open source CesiumJS map control. Bing Maps is the default map layer in the control. We wrote about visualizing bringing your data to life in 3D here.

Best Practices

While doing some research for this blog post I came across a great set of best practices for visualizing BI data on one of our MSDN blogs which you can find here.

As mentioned at the start of this blog post all source code for this blog can be found on the MSDN Code Samples Gallery here.

– Ricky Brundritt, Bing Maps Program Manager