Contents | |
This article shows you how to take data from the Google Analytics Data Export API and visualize it with a variety of different graph types using the Google Charts API. This particular article is going to focus on doing it in Javascript, which allows for things like setting up slick dashboards in your web applications, without having to figure out how to draw charts yourself. However, since requests to the Chart API only use URLs, this can be done in any language you wish.
The code you're going to write will do the following:
You'll get the most out of this article if you have the following:
To pull data from Google Analytics, you'll need the following pieces of information:
The first step is to create two files, analyticsCharts.html and
analyticsCharts.js. The HTML file is almost identical to what you see in the
Setting Up Your HTML File section of the Getting Started guide. You can
start with the code in this example below.
View Full HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- Author: Alexander Lucas (api.alexl@google.com) -->
<html>
<head>
<title>My First Google Analytics Data Export API Script</title>
<script type="text/javascript"
src="https://www.google.com/jsapi"></script>
<script type="text/javascript"
src="analyticsCharts.js"></script>
</head>
<body>
<h1>Analytics Data Export API Script</h1>
<button id="authButton">Loading...</button>
<div id="dataControls" style="display:none">
<p>
For this user, retrieve the first 50 accounts with profile ID and table ID
<button id="getAccount">Get Account Data</button>
</p>
<p>
For this profile, show visitor type and entrance/exit graphs:
<input type="text" id="tableId"/> (insert Table ID)
<button id="getData">Get Report Data</button>
</p>
</div>
<table>
<tr>
<td><div id="visitorsDiv"></div></td>
<td><div id="entrancesDiv"></div></td>
</tr>
</table>
<img src="dummy.gif" style="display:none" alt="required for Google Data"/>
</body>
</html>
For the purposes of this article, we're going to create a query that returns
visits by visitor type, and look at various ways of displaying that data. The
ga:visitorType dimension is unusual in that it only has two
possible values, as opposed to a dimension like ga:keyword, which is
open-ended. These two possible values are "New Visitor" and "Returning
Visitor." It's very useful to graph these over time. For instance, spikes in new visits vs
returning visits can indicate a great new link to your site, or the kickoff of
an effective ad campaign. Let's measure these by day, and grab about 10 days
worth of data. The query looks like this:
var myFeedUri = ['https://www.google.com/analytics/feeds/data',
'?start-date=2010-06-01',
'&end-date=2010-06-10',
'&dimensions=ga:day,ga:visitorType',
'&metrics=ga:visits',
'&sort=ga:day',
'&max-results=20',
'&ids=', document.getElementById('tableId').value].join('');
So far none of this is new territory. This query returns a result object which, because you read the Javascript Data Export API Getting Started Guide, you already know how to manipulate and extract information from in order to produce gorgeous, stunning... rows of tabular data. The next section shows you a better way to visually express that data, in a way that's much easier for people to digest.
Using the Google Chart API, you have the power to create practically any type of chart you could possibly want. But, with great power comes great responsibility. Before you run off to create an entire powerpoint presentation's worth of lines, bars, arrows and pie slices, take a minute to peruse the types of charts available, and think about which one is appropriate for the data relationship you're trying to display. Different types of relationships go best with different types of graphs. Also, remember that it's those relationships that are worth graphing — a number in isolation doesn't actually tell you anything, and shouldn't be graphed at all. Let's take total visits and graph it.
A few ideas to get you started: Line and bar graphs are particularly good at showing trends — whether certain metrics are going up or down over days, weeks, or months. Pie charts, on the other hand, are particularly well suited to comparing values against eachother — showing whether one number totals 2x, 3x, or 4x bigger than the other. While bar/line charts can do this too, pie charts make it easier to express things like "how total number of x is split up by category." However, while pie charts can be great at showing data for snapshots in time, one pie chart can't really express a trend over time the way a bar or line chart can. By way of example:
| Good display of trend | Visually confusing nonsense |
|---|---|
| Here you can see one value is bigger | Here you can see one value is 3x bigger |
|---|---|
Before you can create a graph, the data you get back from the Data Export API needs to be massaged into the right format. That format can vary a little from graph type to graph type, as you'll see, but if you at least pull the data out into a more manageable data structure, it'll be easier to format for specific graph types later on. Two useful places to start are:
Let's start with our "Visits by Visitor Type" query. The pieces you're going to need are:
Keep in mind that for a 10-day span, and two possible visitor types, the result set might not contain 20 entries. For instance, if on day 1 there are 10 new visitors and 0 returning visitors, there won't be an entry that says
ga:day: 1 ga:visitorType: returning visitor ga:visitors: 0
Instead, no entry will be returned at all.
The only time it will ever return 0
for a single metric is if the only dimension in the query is a date. As a result, it's
necessary to make sure, client-side, that your visitor count
arrays are staying in sync with the correct date (assuming you're using date
dimensions). This means we need to make sure our table rows stay in sync, which
we do by adding a zero to the newVisitor or returningVisitor arrays when no entry is
detected for that day/visitor type combo.
The following method grabs the data from the Analytics result, copies it into an object, and returns that object.
function getVisitorChartData(result) {
var entries = result.feed.getEntries();
var returningVisitors = [];
var newVisitors = [];
var days = [];
var maxReturningVisitors = 0;
var maxNewVisitors = 0;
for (var i = 0, entry; entry = entries[i]; ++i) {
var visType = entry.getValueOf('ga:visitorType');
var numVisits = entry.getValueOf('ga:visits');
var day = parseInt(entry.getValueOf('ga:day'), 10);
// At the beginning of each day, check if data was missing for previous
// day. Insert "0" in appropriate visitor's array as necessary, using
// fillToSameSize helper method.
if (!days.length) {
days.push(day);
} else {
var lastDay = days[days.length - 1];
if (day != lastDay) {
days.push(day);
fillToSameSize(newVisitors, returningVisitors);
}
}
if (visType == 'New Visitor') {
newVisitors.push(numVisits);
maxNewVisitors = Math.max(maxNewVisitors, numVisits);
} else {
returningVisitors.push(numVisits);
maxReturningVisitors = Math.max(maxReturningVisitors, numVisits);
}
}
fillToSameSize(newVisitors, returningVisitors);
return {
'returningVisitors': returningVisitors,
'newVisitors': newVisitors,
'maxNewVisitors': maxNewVisitors,
'maxReturningVisitors': maxReturningVisitors,
'days': days
};
}
function fillToSameSize(firstArray, secondArray) {
if (firstArray.length < secondArray.length) {
firstArray.push(fillValue);
} else if (secondArray.length < firstArray.length) {
secondArray.push(fillValue);
}
}
newVisitors.
The days, returningVisitors, and
newVisitors arrays are added to a return
object, along with the max values for new and returning visitors.
In order to keep the visitor arrays "in sync" with the days array, a helper
method fillToSameSize checks at the beginning of each day to make
sure the two arrays are the same size. If not, a "0" is added to the smaller
array, making them the same size.
Now that you've got all the data, it's time start configuring your charts.
Every aspect of the chart you're going to build, from the colors used to the data it displays, is configured with a URL parameter. The number and type parameters depends on what kind of chart you're trying to build. Some are optional, many are required. The complete list of chart types and parameters that can be built are beyond the scope of this article. They're beyond the scope of any article. Seriously, there's a lot of them. If you wish to dive into the complete list, go to the Getting Started With Charts guide, and click on your chart type of choice in the left-hand nav. A detailed reference of the relevant parameters, and how they apply in the context of that chart type can be found there.
Because chart parameters are nothing more than name/value pairs, they lend themselves perfectly to being expressed with Javascript object properties. Also, use of objects instead of a giant concatonated string of parameters makes it easier to modify later. As you'll see, this method makes turning bar chart into a line chart a trivial matter of changing one or two of these parameters. To make things easy, let's create a "wrapper" object for the chart with some helper methods and a basic interface.
Chart Wrapper
function getChartObj() {
var params_ = {
'chs': '', // Image Dimensions
'chtt': '', // Title
'chxt': '', // Axes
'chts': '', // Title Style
'cht': '', // Chart type
'chd': '', // Data
'chdl': '', // Legend
'chco': '', // Colors
'chbh': '', // Width and spacing
'chxl': '', // Axis Labels
'chds': '', // Scaling
'chxr': '', // Axis Scaling
'chm': '' // Chart Markers
};
var baseURL_ = 'http://chart.apis.google.com/chart';
function getParams_() {
return params_;
}
function getParam_(key) {
return params_[key];
}
function setParam_(key, val) {
if (params_[key] !== undefined) {
params_[key] = val;
}
}
function setParams_(obj) {
for (key in obj) {
setParam_(key, obj[key]);
}
}
/**
* Given a base URL and an array of parameters, construct the complete URL.
* @return {string} The complete URL for the chart.
*/
function getURL_() {
paramArray = [];
for (key in params_) {
if (params_[key]) {
pairStr = [key, params_[key]].join('=');
paramArray.push(pairStr);
}
}
paramStr = paramArray.join('&');
url = [baseURL_, paramStr].join('?');
return url;
}
return {
'getParam': getParam_,
'getParams': getParams_,
'setParam': setParam_,
'setParams': setParams_,
'getURL': getURL_
};
}
Here's a method that generates a new chart "object" and populates it with all the necessary parameters for a bar chart. Each parameter is sent as a key/value pair, which will eventually be converted to a URL parameter.
function getBarChart(chartData) {
var chart = getChartObj();
var returningVisitorsStr = chartData.returningVisitors.join();
var newVisitorsStr = chartData.newVisitors.join();
var maxValue = chartData.maxReturningVisitors + chartData.maxNewVisitors;
scaleData = getScaleData(maxValue);
// Set chart meta-data
chart.setParams({
'chs': '500x150', //Image dimensions
'chxt': 'x,y', //Axes
'chts': '000000,15', //Title Style
'cht': 'bvs', //Chart Type (Bar, Vertical, Stacked)
'chco': 'a3d5f7,389ced', //Colors
'chbh': 'a,5,20', //Width & Spacing
'chm': 'N,FF0000,-1,,12', //Markers
'chtt': 'Visitors+By+Type', //Title
'chdl': 'Returning+Visitors|New+Visitors', //Legend
'chd': 't:' + returningVisitorsStr + '|' + newVisitorsStr, //Chart Data
'chxl': '0:|' + chartData.days.join('|'), //Axis Labels
'chds': '0,' + scaleData[0], //Scaling
'chxr': '1,0,' + scaleData[0] + ',' + scaleData[1] //Axis Scaling
});
return chart;
}
Stepping through these parameters:
FF0000,12
would mean red text in 12-point typeAstute readers will have noticed another helper method,
getScaleData. This
is a helper method which recommends a max value and increment values for the chart, based on a
parameter representing the max value of a data point contained within the chart,
in such a way that the following criteria are met:
This very simple algorithm attempts to "guess" the right max value, so
you could have better luck by knowing your data and using a pre-determined max
value based on your own site traffic. For the interested, here's the body of the
getScaleData method.
function getScaleData(currMax) {
var result = [0, 0];
// Determine order of magnitude (number of digits left of decimal).
var magnitude = Math.log(currMax) / Math.LN10;
magnitude = Math.ceil(magnitude);
var newMax = Math.pow(10, magnitude);
if (newMax / 5 > currMax) {
newMax = newMax / 5;
}
while (newMax > (currMax * 2)) {
newMax = newMax / 2;
}
var step = newMax / 5;
result[0] = newMax;
result[1] = step;
return result;
}
You may have noticed that the method responsible for setting all the chart
parameters is called getBarChart. If you want to set
data for the pie chart instead, several of the parameters used are different.
If you think about it, this makes sense— there's no x or y axis that
needs labeling, there's no such thing as spacing between values in a pie chart,
and pie charts aren't meant for displaying multiple data sets simultaneously but
rather for one set of values being compared against eachother.
function getPieChart(chartData) {
var chart = getChartObj();
var newVisitors = getArraySum(chartData.newVisitors);
var returningVisitors = getArraySum(chartData.returningVisitors);
chartData.maxValue = returningVisitors + newVisitors;
chart.setParams({
'chs': '500x150', //Image dimensions
'chts': '000000,15', //Title Style
'cht': 'p3', //Chart Type
'chco': 'a3d5f7,389ced', //Colors
'chtt': 'Visitors+By+Type', //Title
'chdl': 'Returning+Visitors|New+Visitors', //Legend
'chd': 't:' + returningVisitors + ',' + newVisitors, //Chart Data
'chl': returningVisitors + '|' + newVisitors, //Labels
'chds': '0,' + chartData.maxValue //Max Value
});
return chart;
}
//Helper method to get the sum of values in an array.
function getArraySum(input) {
var total = 0;
for (var i = 0; i < input.length; i++) {
total += input[i];
}
return total;
}
Note that unlike the previous set of data, we're using totals for each type of visitor, instead of expressing each data point individually. Also, we need fewer parameters in general.
Now that you've got all that data, how do you create a chart out of it? You need to do two things.
Begin with constructing the URL. A method within the wrapper object called
getURL combines the parameters with the base URL (also defined in
the wrapper object). The resulting URL works as a request to the Chart API for
an image of the chart. For reference, the method looks like this:
function getURL_() {
paramArray = [];
for (key in params_) {
if (params_[key]) {
pairStr = [key, params_[key]].join('=');
paramArray.push(pairStr);
}
}
paramStr = paramArray.join('&');
url = [baseURL_, paramStr].join('?');
return url;
}
Now that you have the URL, use the drawChart
method to embed an image at that URL into the DOM. The drawChart method takes
two parameters, the name of the HTML container element where you want to embed
the image, and the URL location of the image. The drawChart method
can be written like this:
function drawChart(parentElementId, url) {
document.getElementById(parentElementId).innerHTML +=
'<img src="' + url + '" /></br />';
}
When you call the method with your bar/pie chart URLs, you'll have images that look something like this:
| Bar Chart | Pie Chart |
|---|---|
|
|
|
Now that you've come this far, you can actually turn this stacked bar chart into other chart types with relatively little effort. For instance, to change it into a grouped bar chart, just modify the chart type to "bvg," change the markers so there's one for each series, and recompile the URL.
var groupedChart = getChartObj();
groupedChart.setParams(barChart.getParams());
groupedChart.setParam('cht', 'bvg');
groupedChart.setParam('chm', 'N,FF0000,0,,12|N,FF0000,1,,12');
var groupedChartURL = groupedChart.getURL();
drawChart('visitorDiv',groupedChartURL);
The end result will look like this:
Alternatively, you can skip out on bars altogether and convert it into a line chart. Change it to a chart type of "lc," and remove the markers entirely (they don't look good in line charts), like so:
var lineChart = getChartObj();
lineChart.setParams(barChart.getParams());
lineChart.setParam('cht', 'lc');
lineChart.setParam('chm', '');
var lineChartURL = paramsToURL(chartData.chartParams, chartData.baseURL);
drawChart('visitorDiv',lineChartURL);
And voila! Line charts!
| This is why you delete the markers. | Ah... much better. |
|---|---|
Now you can successfully visualize analytics data using the charting API. You know how to create bar, line, and pie charts at a whim. There are TONS of things you can do with this.
But it doesn't stop there. This article only covered 3 chart types, and one single query. There are a hundred dimensions/metrics for you to query against, and a dozen different charts to display your results in. To see what options are available to you, explore these links. Happy coding!