Easy data visualization with Google Graphs API

Free and easy way to display data on website

Google graph are really easy to use on website for the main reason that you do not need to maintain code and because it is free for use.

Samples and documentation can be found at https://developers.google.com/chart/.

Populating data for charts is pretty easy from ASP.NET by converting .NET objects to JSON using built-in .NET Framework serializers.

For each graph type we can create model classes (POCO), fill them with data, parse with .NET JSON libraries and pass them to function which invokes graph rendering. Because GoogleGraph data is pretty simple, an array of KeyValuePairs will do the thing.

Pie Chart binding with KeyValuePair list

In the following example I will show you how to pump in the data from code behind to Google graph using ASP.NET webforms. I will use some code mentioned in article Handling ajax request in WebForms. Basically it is an upgrade to this solution so I do not have to write everything all over again.

If you check out https://google-developers.appspot.com/chart/interactive/docs/gallery/piechart you can see that graph data structure is pretty simple. You can easily generate same data structure in back-end and return JSON as a result.

Googlegraph Pie

This is generated output of the attached sample solution, pretty nice and very easy.

In this example data is loaded asynchronously after page load. When page is loaded, JS triggers AJAX GET to page it self. This async request is handled in code behind where data is populated.

google.load("visualization", "1", { packages: ["corechart"] });google.setOnLoadCallback(drawChart);
function drawChart() {
    $.get(window.location, {}, function (graphData) {
        var options = {
            title: 'My Daily Activities',
            is3D: true
        };
        var tdata = new google.visualization.DataTable();
        tdata.addColumn('string', 'Task');
        tdata.addColumn('number', 'Hours per Day');
        for (var i = 0; i < graphData.length; i++) {
            tdata.addRow([graphData[i].Key, graphData[i].Value]);
        }
        var chart = new google.visualization.PieChart(document.getElementById('piechart'));
        chart.draw(tdata, options);
    });
}
    

As you can see in code below, I have a check on Page_Init whether request is an AJAX request or not. If it is an AJAX then return JSON data instead of page.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Script.Serialization;
using Asp.Net;

public partial class PieChart : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Request.IsAjaxRequest())
        {
            Response.AddHeader("Content-type", "text/json");
            Response.Clear();
            List<KeyValuePair<string, int>> data = new List<KeyValuePair<string, int>>();

            //Load data
            data.Add(new KeyValuePair<string, int>("Work", 11));
            data.Add(new KeyValuePair<string, int>("Eat", 2));
            data.Add(new KeyValuePair<string, int>("Commute", 5));
            data.Add(new KeyValuePair<string, int>("Watch TV", 4));
            data.Add(new KeyValuePair<string, int>("Sleep", 7));

            //Prepare data for JS and return as JSON response
            string json = new JavaScriptSerializer().Serialize(data);
            Response.Write(json);
            Response.End();
        }
    }
}
    

Whole solution is attached to this article so you can download it and see how the whole thing works.

This was pretty easy because we have simple data structure required for pie chart, but for a bit complicated data structure we will have to use something which has more than key-value pair.

We can either create POCO (Plain Old CLR Object) classes manually and then involve them in code or we can just write anonymous types and use them. In the following example I will show you how to organize data into anonymous type objects because it is a lot faster than creating POCO classes.

Combo Chart binding

If you check Combo Chart example at https://google-developers.appspot.com/chart/interactive/docs/gallery/combochart you will see that there are more than just two columns and previous structure cannot cover this.

Because data structure on the back-end is different we will slightly have to change our script, so it adapts to return type.

        google.load("visualization", "1", { packages: ["corechart"] });
        google.setOnLoadCallback(drawChart);
        function drawChart() {
            $.get(window.location, {}, function (graphData) {

                var options = {
                    title: 'Monthly Coffee Production by Country',
                    vAxis: { title: "Cups" },
                    hAxis: { title: "Month" },
                    seriesType: "bars",
                    series: { 5: { type: "line"} }
                };

                var tdata = new google.visualization.DataTable();
                tdata.addColumn('string', 'Month');
                tdata.addColumn('number', 'Bolivia');
                tdata.addColumn('number', 'Ecuador');
                tdata.addColumn('number', 'Madagascar');
                tdata.addColumn('number', 'Papua New Guinea');
                tdata.addColumn('number', 'Rwanda');
                tdata.addColumn('number', 'Average');

                for (var i = 0; i < graphData.length; i++) {
                    tdata.addRow([graphData[i].Key, graphData[i].Value[0], graphData[i].Value[1], graphData[i].Value[2], graphData[i].Value[3], graphData[i].Value[4], graphData[i].Value[5]]);
                }
                var chart = new google.visualization.ComboChart(document.getElementById('combochart'));
                chart.draw(tdata, options);
            });
        }
    

Because we have an array of values in KeyValuePair structure we need to read every value of returned pair array value.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Script.Serialization;
using Asp.Net;

public partial class ComboChart : System.Web.UI.Page
{
    protected void Page_Init(object sender, EventArgs e)
    {
        if (Request.IsAjaxRequest())
        {
            Response.AddHeader("Content-type", "text/json");
            Response.Clear();
            List<KeyValuePair<string, List<double>>> data = new List<KeyValuePair<string, List<double>>>();

            //Load data
            data.Add(new KeyValuePair<string, List<double>>("2004/05", new List<double>() { 165, 938, 522, 998, 450, 614.6 }));
            data.Add(new KeyValuePair<string, List<double>>("2004/06", new List<double>() { 135, 1120, 599, 1268, 288, 682 }));
            data.Add(new KeyValuePair<string, List<double>>("2004/07", new List<double>() { 157, 1167, 587, 807, 397, 623 }));
            data.Add(new KeyValuePair<string, List<double>>("2004/08", new List<double>() { 139, 1110, 615, 968, 215, 609.4 }));
            data.Add(new KeyValuePair<string, List<double>>("2004/09", new List<double>() { 136, 691, 629, 1026, 366, 569.6 }));

            //Prepare data for JS and return as JSON response
            string json = new JavaScriptSerializer().Serialize(data);
            Response.Write(json);
            Response.End();
        }
    }
}
    

This is the result of code snippets above.

 Combochart

Presented solutions might not be out of the box solutions because they are not working with actual data and columns are static, but should give you a nice head start in case you need to deal with chart data vizualization in GoogleGraphs.

In the next example we will make everything dynamic (graph title, axis titles, columns, data...) and have a complete solution which is pretty much reusable.

ComboChart completely driven by data

To achieve to send all data which is used to generate graph we need to enrych our KeyValuePair lists with some additional data. We can create custom classes and include them in response, but much easier way to do this is by using anonymus types. This will not require to generate any additional class file as we are going to create object structure in runtime.

First we need to adapt our JavaScript as following

        google.load("visualization", "1", { packages: ["corechart"] });
        google.setOnLoadCallback(drawChart);
        function drawChart() {
            $.get(window.location, {}, function (graphData) {

                var options = {
                    title: graphData.Options.title,
                    vAxis: { title: graphData.Options.vAxisTitle },
                    hAxis: { title: graphData.Options.hAxisTitle },
                    seriesType: "bars",
                    series: { 5: { type: "line"} }
                };

                var tdata = new google.visualization.DataTable();
                for (var i = 0; i < graphData.DataColumns.length; i++) {
                    tdata.addColumn(graphData.DataColumns[i].Key, graphData.DataColumns[i].Value);
                }
                for (var i = 0; i < graphData.DataRows.length; i++) {
                    var rows = new Array();
                    rows[0] = graphData.DataRows[0].Key;

                    for (var j = 1; j <= graphData.DataRows[i].Value.length; j++) {
                        rows[j] = graphData.DataRows[i].Value[j]
                    }
                    tdata.addRow(rows);
                }
                var chart = new google.visualization.ComboChart(document.getElementById('combochart'));
                chart.draw(tdata, options);
            });
        }
    

After that we need to pump-in all data and return it back. Here is a code behing code how to do it.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Script.Serialization;
using Asp.Net;

public partial class ComboChartDynamic : System.Web.UI.Page
{
    protected void Page_Init(object sender, EventArgs e)
    {
        if (Request.IsAjaxRequest())
        {
            Response.AddHeader("Content-type", "text/json");
            Response.Clear();
            List<KeyValuePair<string, string>> columns = new List<KeyValuePair<string, string>>();

            //Generate columns
            columns.Add(new KeyValuePair<string, string>("string", "Month"));
            columns.Add(new KeyValuePair<string, string>("number", "Bolivia"));
            columns.Add(new KeyValuePair<string, string>("number", "Ecuador"));
            columns.Add(new KeyValuePair<string, string>("number", "Madagascar"));
            columns.Add(new KeyValuePair<string, string>("number", "Papua New Guinea"));
            columns.Add(new KeyValuePair<string, string>("number", "Rwanda"));
            columns.Add(new KeyValuePair<string, string>("number", "Average"));

            List<KeyValuePair<string, List<double>>> data = new List<KeyValuePair<string, List<double>>>();
            //Load data
            data.Add(new KeyValuePair<string, List<double>>("2004/05", new List<double>() { 165, 938, 522, 998, 450, 614.6 }));
            data.Add(new KeyValuePair<string, List<double>>("2004/06", new List<double>() { 135, 1120, 599, 1268, 288, 682 }));
            data.Add(new KeyValuePair<string, List<double>>("2004/07", new List<double>() { 157, 1167, 587, 807, 397, 623 }));
            data.Add(new KeyValuePair<string, List<double>>("2004/08", new List<double>() { 139, 1110, 615, 968, 215, 609.4 }));
            data.Add(new KeyValuePair<string, List<double>>("2004/09", new List<double>() { 136, 691, 629, 1026, 366, 569.6 }));

            //Prepare data for JS and return as JSON response
            string json = new JavaScriptSerializer().Serialize(new {
                Options = new { title = "Monthly Coffee Production by Country", vAxisTitle = "Cups", hAxisTitle="Months" },
                    DataColumns = columns,
                    DataRows = data
            });
            Response.Write(json);
            Response.End();
        }
    }
}
    

As you can see, graph options are sent back along with columns and rows data without creating additional types.

This sample is available in download as ComboChartDynamic.aspx

If you find this article useful and like it please share the knowledge with others.

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

PowerShell

read more

Comments for this article