Google Chart Tools

Presenter Notes

Presenting data on the web

  • We have used R to design lots of neat graphs
    • However, these graphs are static
    • Wouldn't it be nice to make the data interactive?
  • Web interfaces and APIs can make this possible
  • We will learn to use Google Chart Tools

Presenter Notes

Architecture overview

  • Requirements for hosting web charts
    • Web server hosting HTML and JavaScript (your team account's public_html directory, hosted on puma)
    • Google Chart Tools JavaScript API
    • (Optional) Use python to convert data files into correctly-encoded JSON (using gviz_api library)
    • (Optional) Use python's cgi library to dynamically render HTML

Presenter Notes

Let's talk about HTML and JavaScript by example

https://google-developers.appspot.com/chart/interactive/docs/quick_start

Presenter Notes

There's lots of guides to different charts

  • Notice that the structure of the data and accepted parameters can vary by chart type
  • Recommended approach to making web-based graphs
    1. Find charts that you would like to create by browsing chart gallery or code playground
    2. Copy the starter code
    3. Tweak the data and parameters to suit you

Presenter Notes

Example: writing a bar chart

We can input the data directly from a contingency table created in R:

> rs<-read.table('regSuperCensusMod.csv',header=T,sep=',')
> rsi<-rs[rs$IndOrg=="IND",]
> ct<-table(rsi[,c('Candidate','RegularSuper')])
> ct
               RegularSuper 
Candidate       Regular Super
barack obama    28864    41
mitt romney     10470   159
newt gingrich    1266    18

Presenter Notes

Example: writing a bar chart

 1 <html>
 2   <head>
 3     <script type="text/javascript" src="https://www.google.com/jsapi"></script>
 4     <script type="text/javascript">
 5       google.load("visualization", "1", {packages:["corechart"]});
 6       google.setOnLoadCallback(drawChart);
 7       function drawChart() {
 8         var data = new google.visualization.DataTable();
 9         data.addColumn('string', 'candidate');
10         data.addColumn('number', 'Regular');
11         data.addColumn('number', 'Super');
12         data.addRows([
13           ["barack obama",28864,41],
14           ["mitt romney", 10470, 159],
15           ["newt gingrich", 1266, 18]
16         ]);
17         var options = {
18           title: 'Regular vs Super PAC # contributions',
19           vAxis: {title: 'Candidate',  titleTextStyle: {color: 'blue'}},
20           hAxis: {title: '# Contributions',  titleTextStyle: {color: 'blue'}}
21         };
22         var chart = new google.visualization.BarChart(document.getElementById('chart_div'));
23         chart.draw(data, options);
24       }
25     </script>
26   </head>
27   <body>
28     <div id="chart_div" style="width: 900px; height: 500px;"></div>
29   </body>
30 </html>

Presenter Notes

Quick exercise to place graph on web server

  1. Download the code from http://cs.wellesley.edu/~qtw/code/exchart1.html
  2. View the code in your browser locally
  3. ssh in to your team account and fetch a copy of the code using wget
  4. Place the code in your ~/public_html/ directory
  5. Set the permissions so that everyone can view the file (chmod a+r exchart1.html)
  6. Go to http://cs.wellesley.edu/~teamname/exchart1.html in your browser to view the file

Presenter Notes

Debugging JavaScript

  • Here is a very similar HTML file to the one you just saw
  • But this one has a bug in it
  • Use the Javascript Error Console to get errors and debug

Presenter Notes

Example: another way to draw a bar chart

  • While inputing your data by hand makes sense when the data set is very small, it can certainly become tedious when data files are large
  • An alternative way to input data is to provide raw JSON as data
  • Google Charts is very particular about how the JSON must be formatted
  • Fortunately, there is a python wrapper library called gviz_api that does most of the hard work

Presenter Notes

Make the bar chart using gviz_api

  1. Download gviz_api.py into the directory where you will execute your python code (e.g., /home/projectname/code/)
  2. Download exchart2.py into a directory where you execute Python code
  3. View the created HTML file in your browser (here's mine)

Presenter Notes

What is still inconvenient here?

  1. We are hard-coding the data directly in Python, rather than JavaScript, but we are still hard-coding the data
  2. We are using the Python to create a separate HTML file. Wouldn't it be nice if the Python code directly generated HTML code on the fly?

Presenter Notes

Reading in data from files

Here is the relevant excerpt from code that reads in data files:

 1 description = [("candidate","string"),("Regular","number"),("Super","number")]
 2 data=[]
 3 for line in open('/home/qtw/public_html/data/regsuper.csv'):
 4     bits=line.split(',')
 5     #skip the header file since that is still hard-coded
 6     if bits[0]=='candidate': continue
 7     data.append((bits[0],int(bits[1]),int(bits[2])))
 8 #create a DataTable object
 9 data_table = gviz_api.DataTable(description)
10 data_table.LoadData(data)

Here's my generated HTML

Presenter Notes

Using Python to generate HTML on the fly

  • Up to now, the code we've looked at could be run on a local machine, and then the resulting HTML copied to the server
  • While this works, it becomes tedious and seems a waste, since our webserver (puma) can run Python code
  • Why don't we instead run the Python code directly on the server?
  • We can using CGI scripting

Presenter Notes

Presenter Notes

CGI design issues

  • CGI programming is a security risk, since you are running arbitrary code on a server
  • Consequently there are restrictions on where you can run the code and what it can access
  • Be sure that your python code uses "import cgitb" and "cgitb.enable()" to view errors
  • Note: to use the gviz_api library in your cgi scripts, you must first download the file into your cgi-bin directory (e.g., /home/projectname/public_html/cgi-bin/)
  • Next, you must ensure that all your cgi scripts and gviz_api.py are not group-writable. To do that, type chmod g-w * at the console when in the cgi-bin directory.

Presenter Notes

More examples

Presenter Notes

Let's make a map

Presenter Notes

Let's make a map

First let's take some starter code from the documentation:

 1 function drawRegionsMap() {
 2     var data = google.visualization.arrayToDataTable([
 3       ['Country', 'Popularity'],
 4       ['Germany', 200],
 5       ['United States', 300],
 6       ['Brazil', 400],
 7       ['Canada', 500],
 8       ['France', 600],
 9       ['RU', 700]
10     ]);
11 
12     var options = {};
13 
14     var chart = new google.visualization.GeoChart(document.getElementById('chart_div'));
15     chart.draw(data, options);
16 };

Presenter Notes

Look at the documentation to figure out how to map states

  • Look at the configuration options, see region has states option and resolution also must be set
  • Note also the format required

We can provide fake data to the map to test that we set the parameters correctly:

 1 function drawRegionsMap() {
 2     var data = google.visualization.arrayToDataTable([
 3       ['State', 'Diversity Index'],
 4       ['US-AL', 0.48],
 5       ['US-AR', 0.42],
 6       ['US-AZ', 0.596],
 7     ]);
 8     var options = {'region':'US','resolution':'provinces'};
 9     var chart = new google.visualization.GeoChart(document.getElementById('chart_div'));
10     chart.draw(data, options);
11 };

Here's the resulting graph

Presenter Notes

Let's now read in the data from a file

  • Data format specifications
    • So we need two columns, one for the state, and one for the numerical variable of interest
  • To use the gviz_api, we need to specify a schema and data separately

Presenter Notes

Back to the map

Code excerpt from Python CGI script to create schema and data:

 1 #first create the schema, explaining the columns and their types
 2 description = [("State","string"),("Diversity Index","number")]
 3 #now make the data, as a list of tuples
 4 data=[]
 5 
 6 for line in open('/home/qtw/public_html/data/statedemo.csv'):
 7     bits=line.split(',')
 8     #skip the header file since that is still hard-coded
 9     if bits[0]=='State': continue
10     data.append(("US-"+bits[0],int(100*float(bits[3].strip()))))
11 
12 #create a DataTable object
13 data_table = gviz_api.DataTable(description)
14 data_table.LoadData(data)

Presenter Notes

Exercise: Create an Intensity Map for 3 Demographic Measures

  • Your job: build an intensity map to showcase all demographic data (the final version will look like this)
  • Copy the starter code to your team account's cgi-bin directory
  • Then modify the starter code in the following 3 ways
    1. Update the schema to include all demographic data from CSV file: fraction white, fraction black, and diversity index
    2. Update the data table to include all demographic data
    3. Set the chart parameters according to the documentation
  • Note: you must have a copy of gviz_api.py in your cgi-bin directory. Please also make sure it is not group-writable by executing the command chmod g-w gviz_api.py.

Presenter Notes

ChartWrapper: another way to make charts

  • Sometimes you may encounter code that creates charts using a ChartWrapper class
  • Don't worry, it's just another way to instantiate Chart objects

Presenter Notes

ChartWrapper: another way to make charts

This code:

1  var chart = new google.visualization.IntensityMap(
2                  document.getElementById('chart_div'));
3  chart.draw(data, {'region':'usa'});

Can also be written like this:

1 var chart = new google.visualization.ChartWrapper({
2         chartType: 'IntensityMap',
3         dataTable: data,
4         options: {'region':'usa'},
5         containerId:'chart_div'
6 });
7 chart.draw();

Presenter Notes

DataViews: read-only DataTables

  • If you provide data of any reasonable size to Google Charts, you will find rendering slow down a lot
  • One way around this is to create a read-only version of your data, called a DataView

Here is some example code using a DataView:

1 var data = new google.visualization.DataTable(%(json_str)s);                                                    
2 var dview = new google.visualization.DataView(data);
3 ...
4 chart.draw(dview, {});

Presenter Notes

Dashboards and Controls

Presenter Notes

Aggregation functions

  • Just as we encountered in R, we often want to aggregate data grouped by some categorical variable
  • Fortunately, Google has a group function
  • Syntax: google.visualization.data.group(data_table, keys, columns)
    • data_table: as expected
    • keys: column(s) for categorical variable to group on (e.g., [0] for first column, [3,5] for fourth and sixth)
    • columns: column(s) of numerical variables to perform function on

Presenter Notes

Aggregation functions

Here is an example from the Google documentation:

 1 // This call will group the table by column 0 values.
 2 // It will also show column 3, which will be a sum of
 3 // values in that column for that row group.
 4 var result = google.visualization.data.group(
 5   dt,
 6   [0],
 7   [{'column': 3, 'aggregation': google.visualization.data.sum, 'type': 'number'}]
 8 );
 9 
10 *Input table*
11 1  'john'  'doe'            10
12 1  'jane'  'doe'           100
13 3  'jill'  'jones'          50
14 3  'jack'  'jones'          75
15 5  'al'    'weisenheimer'  500
16 
17 *Output table*
18 1  110
19 3  125
20 5  500

Presenter Notes

Cheesy aggregation example

  • Returning to our cheese data set, we can tally the total number of cheeses sold per day
  • In this case, the categorical variable for grouping is actually the day
  • We need to sum up the cheese sold on each day
  • Here is the code to do it

Presenter Notes

Aggregation exercise

  • Your task: make a bar chart plotting the total number of cheese sold per store
  • Here is the starter code
  • You need to do two things
    1. Aggregate the total number of cheeses sold per store
    2. Create a ColumnChart plotting the cheeses sold

Presenter Notes

Solution to exercise

Presenter Notes