Creating Google Motion Charts from Excel data

There are a growing number of visualizations available from Google. Users of GoogleDocs have easy access to these new capabilities, whereas it's rather more complicated for Excel users. This article shows how to create .Html files from your excel data that can be embedded in your workbook or published as required. It is accompanied by a fully functional workbook containing an example application and custom classes for you to use in your own application.

What are Google Visualization Charts
Google provides a growing number of cool charts that are not available in Excel. For this article we are going to focus on the the Google Motion Visualizations. Please take a look here to become familiar with what they are.

    There are a number of ways to create a google chart, some which are;

  • Create a web page that contains the calls to the google visualization API, as well as the data to initialize the chart.
  • Embed it as a gadget in a googledocs spreadsheet
  • Embed as a gadget in a web page, and get the data as a feed from a website, usually from a googledocs spreadsheet

In this article we will look at how to create a web page directly from Excel, and embed it in your excel spreadsheet. The web page created can also be loaded on to a web site, as per this example here. A fully functional workbook with all the code is available here.

Important
If you are going straight to the download before reading this article, then at least read the note on Flash below, since it will not work until you have followed those instructions.


Using Excel data to populate Google Motion Charts
Google Motion is one of a family of visualization capabilities available through the Google Visualization API. If you are using googledocs, it is quite straightforward to include in your spreadsheet, just as it is simple to create a webpage with an embedded chart that takes it data from your googledocs spreadsheet.

If you don't use googledocs though, you either have to convert your data to feed a web page embedded visualization gadget, or you have to write some JavaScript that calls the Google API, and includes the data as part of the code. In this article we will write a complete web page directly from your selected excel data, and display the Google chart embedded in a form in your excel spreadsheet. Since we are creating a temporary html file,. you can of course load that directly on your website or open locally with a browser.

Before we start - a note about Flash
Google uses Flash to display these interactive charts. By default the Flash player is not able to access files that are held locally. Since you will be embedding these charts in your workbook, the .html file will be created locally and will need to be accessed locally . To get round this you need to first follow the instructions on the macromedia website for creating a trusted location for local, flash enabled files. The excel form in the downloadable example gives you the opportunity to define where that is so that all .html files are created there.

What does the generated html code look like
We are going to write a handler in excel that will convert spreadsheet data, that looks like this in our example


... repeat many times...

....to an html file that looks like this


<html>
<head>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load('visualization', '1', {packages: ['motionchart']});
function funmotion() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Function');
data.addColumn('date', 'Load Date');
data.addColumn('number', 'Differentiator');
data.addColumn('number', 'Complexity');
data.addColumn('number', 'Volume');

data.addRows(730);
data.setValue(0, 0, 'Box C');
data.setValue(0, 1, new Date(2009,8,7));
data.setValue(0, 2, 40.34);
data.setValue(0, 3, 1.35);
data.setValue(0, 4, 47);
data.setValue(1, 0, 'Box F');
data.setValue(1, 1, new Date(2009,8,7));
data.setValue(1, 2, 32.05);
data.setValue(1, 3, 0.95);
data.setValue(1, 4, 120);

.... repeat many times...
;
data.setValue(729, 0, 'Box S');
data.setValue(729, 1, new Date(2012,11,31));
data.setValue(729, 2, 49.98);
data.setValue(729, 3, 0.85);
data.setValue(729, 4, 151);
var motionchart = new google.visualization.MotionChart(document.getElementById('divmotion'));
motionchart.draw(data, {width: 696, height:480}); }
google.setOnLoadCallback(funmotion);</script></head>
<body>
<div id="divmotion" style="width: 696px; height: 480px;"></div>
</body>
</html>

A note on the requirements for the Google motion chart
At least 3 columns of data are required, the first being what's called the entity, the second a date, and the third would likely be a number. Subsequent fields would also be numbers and would be available interactively through the chart. The downloadable example does not validate this but a production example probably should, otherwise you could leave it to the chart to complain about the data type if there is a problem.

The downloadable tool
To get you started a downloadable workbook will provide all the necessary code, including a form to control the process and display the finished product. This is the tool in action. You simply select the range where the column headings are and push the make the chart button. If you need to load the result to a web page, the temporary file (googMot.html) can be found in the directory you specify on the form as being trusted to Flash (and for which you have previously followed the instructions on Flash trusted locations above)


How does it work
You will find a number of classes in the workbook that you should just be able to use as is in whatever application you plan to develop, and which I'll go into later. For the example, the main module is pretty straightforward, and yours should be too.

Public Sub showChart()
  Dim GoogMot As cGoogleChartInput, rHeadings As Range
'create the chart
   Set GoogMot = New cGoogleChartInput
    If Len(fGoogleChart.RefEdit1.Text) > 0 Then
       Set rHeadings = Range(fGoogleChart.RefEdit1.Text)
      With fGoogleChart.WebBrowser1
        If GoogMot.init(fGoogleChart.tbTrusted.Value & "googmot.html", rHeadings, , _
          .Width, .Height) Then
          GoogMot.createmotionFile
' show the chart
        .Navigate GoogMot.htmlName
        Do
          DoEvents
        Loop Until .ReadyState = READYSTATE_COMPLETE
      End If
    End With
Else
    MsgBox ("Please supply a range where the column titles are")
End If
End Sub

This is called from the form as follows on the appropriate command button click.

Private Sub cbShowChart_Click()
  showChart
End Sub

What's happening here is

  • Instantiation of a cGoogleChartInput custom class
  • Identification of the spreadsheet range that contains the column titles (all data up till the first blank line will be plotted)
  • Initialization of the cGoogleChartinput class with the appropriate parameters
  • Creation of the html file with the .createmotionFile method
  • Navigation to the newly created html file using the embedded web-browser object.

The classes provided in the workbook
There are a number of classes provided, one of which is the topic of this article namely cGoogleChartInput. This makes use of a set of other custom classes, cCell, CDataColumn, cDataRow, cDataSet, cDataSets and cHeadingRow. These are a suite of classes that allow the separation of physical spreadsheet location and data manipulation to be separated and encapsulated, thus simplifying the coding for this and other processes. They are not the subject of this article but you can read about them here.

cGoogleChartInput
This is the class that does all the work. For future articles I will be extending it to deal with other google visualization capabilities, but in this example only the motion chart has been implemented. All the code for this in the example workbook. We will just look at selected methods.

Lets take a look at the .init method of this class. You will notice an optional argument headOrderArray. This is to allow you to vary the order of the columns as supplied by the range rWhere. If you recall, Google has rules about the first 3 columns, so if your data doesn't happen to be in the right order, this allows you to modify the order, or omit columns, without re-arranging your spreadsheet. A typical argument might be Array("Function","Load Date","Volume"). If it is omitted then all the columns in the range will be used in the natural order.

Another item of interest here is that we are reading in the data here, as well as setting up the parameters, using the .getdata method.

Public Function init(fn As String, rWhere As Range, Optional headOrderArray As Variant = Empty, _
Optional gwidth As Long = cWidth, Optional gheight = cHeight) As Boolean
Dim hcell As cCell
Dim nHeads As Long, s As String
Set pWhere = rWhere
pWidth = gwidth
pHeight = gheight
phtmlName = fn
init = False
nHeads = 0
s = ""
If getData Then
    init = True
' we got the data ok
    If IsEmpty(headOrderArray) Then
' all columns are required
      Set pHeadOrder = pdSet.Headings
    Else
' a subset or reordering is required
      Set pHeadOrder = New Collection
      For nHeads = LBound(headOrderArray) To UBound(headOrderArray)
        Set hcell = pdSet.HeadingRow.Exists(CStr(headOrderArray(nHeads)))
        If Not hcell Is Nothing Then
          pHeadOrder.Add hcell, pdSet.HeadingRow.makekey(hcell.Value)
       Else
          s = s & headOrderArray(nHeads) & ","
       End If
     Next nHeads
     If Len(s) > 0 Then
       MsgBox "These fields do not exist " & s
        init = False
     End If
   End If

  End If
End Function

The getdata method uses the data manipluation classes mentioned earlier, so collecting the data to be transformed is a simple matter of instantiation of a cDataSet class, followed by a call to its .populateData method.

Private Function getData() As Boolean
  Set pdSet = New cDataSet
' just need to provide the range where data headings are
  With pdSet
    .populateData pWhere
    If .Where Is Nothing Then
      MsgBox ("No data to process")
      getData = False
   Else
      getData = True
   End If
  End With
End Function

The only other Public method, aside from .init is .createmotionFile, which actually generates the html and javasscript required to execute the google chart. Again you will see the use of the cDataSet, cCell and cDataRow class to traverse the data previously read by .populateData.

Public Sub createmotionFile()
  Dim s As String, hcell As cCell, dcell As cCell, nr As Long, nc As Long, dr As cDataRow
' generate html file as input to google chart
  If createHtmlFile Then
    Print #phtmlHandle, htmlPreamble & googleScriptPreamble
    Print #phtmlHandle, motionScriptStart
' column headings
    For Each hcell In pHeadOrder
      Print #phtmlHandle, _
          "data.addColumn('" & getColTextforType(hcell) & "', '" & hcell.toString & "');"
    Next hcell
' row values
    Print #phtmlHandle, _
         "data.addRows(" & pdSet.Rows.Count & ");"
    nr = 0
    For Each dr In pdSet.Rows
      nc = 0
      For Each hcell In pHeadOrder
        Set dcell = dr.Cell(hcell.Column)
        Print #phtmlHandle, _
          "data.setValue(" & CStr(nr) & ", " & CStr(nc) & ", " & getTextforType(dcell) & ");"
        nc = nc + 1
      Next hcell
      nr = nr + 1
    Next dr
    Print #phtmlHandle, motionScriptFinish & googleScriptWrapup & motionscriptBody
    Close #phtmlHandle
  End If
End Sub

The only public property available is htmlName, which returns the name of the file that has been generated by .createmotionFile.

Public Property Get htmlName() As String
  htmlName = phtmlName
End Property

Summary and next steps
This kind of technique opens the growing world of google charts and visualizations to excel users who do not want to use googledocs. Watch this space for future articles that serialize Excel data so it can be used as input to embedded google gadgets, as well as further implementations of additional google visualization. You can download the workbook associated with this code and other useful items here. All code is freely available for non commercial use. Please feel free to contact me with suggestions, updates, comments, bug fixes or code enhancements.

By bruce mcpherson   Popularity  (5025 Views)