A more realistic use of Google Charts

Presenter Notes

Example: scatter plots from H4

Task 2 incumbent-challenger-open

Presenter Notes

Step 1: create a pared-down CSV

  • Just include the fields you need for plotting or to use in controls
  • R script extracts columns of interest, returns 250 random rows

Presenter Notes

Step 2: create a CGI script

First create the schema, explaining the columns and their types:

1 description = [("Candidate","string"),
2                ("State","string"),
3                ("Party","string"),
4                ("Is Incumbent?","string"),
5                ("Cycle","number"),
6                ("Result","string"),
7                ("In-State Contributions","number"),
8                ("Total $ Contributions","number"),
9                ("Total # Contributions","number")]

Presenter Notes

Read the CSV, convert to JSON

 1 import csv
 2 data=[]
 3 #loop through CSV file        
 4 for record in csv.reader(open('/home/qtw/public_html/data/cont4google.csv'),delimiter=',',quotechar='"'):
 5     #first convert the numerical values from strings to numbers                                            
 6     record[4]=int(record[4])
 7     record[6]=float(record[6])
 8     record[7]=int(record[7])
 9     record[8]=int(record[8])
10     #add a check to skip any fields with blank entries                                                     
11     if "" in record: continue
12     data.append(record)
13 
14 #create a DataTable object                                                                               
15 data_table = gviz_api.DataTable(description)
16 data_table.LoadData(data)
17 
18 #convert to JSON (could also send no parameters, this just demonstrates that you can re-order             
19 json_str=data_table.ToJSon()

Presenter Notes

Build the HTML template

  • Steps to build a dashboard
    1. Instantiate chart objects
    2. Instantiate control objects
    3. Instantiate dashboard object
    4. Link the charts and control objects (using Dashboard's bind() method)
    5. Make sure the HTML includes divs with IDs corresponding to control
  • Google's tutorial on Dashboards and controls is quite helpful

Presenter Notes

Instantiate chart objects

Key point: 'view' parameter selects the x and y columns to plot on the scatter chart (more generally selects which data to pass to the chart object):

 1 wrapper = new google.visualization.ChartWrapper({                                                 
 2     'chartType': 'ScatterChart',                                                                
 3     'dataTable': datav,                                                                         
 4     'options': {                                                                                
 5         'title': '$ Contributions vs. in-state fraction',                                       
 6         'height': 500,                                                                          
 7         'width':800,                                                                            
 8         'vAxis': {title: '$ contribution', minValue: 0},                                        
 9         'hAxis': {title: 'fraction $ from in-state', minValue: 0, maxValue:1}                   
10     },                                                                                          
11     'containerId': 'chart_div',                                                                 
12     //select only the in-state contribution fraction and $ contribution columns for display     
13     'view': {'columns': [6, 7]}                                                                 
14  });

Presenter Notes

Instantiate control objects

  • Key point: Control objects must have the 'filterColumnLabel' parameter set to the label of the column you will be using to filter

Note that the filtered data may be a completely different column than that which appears in the plot:

1 var slidersum = new google.visualization.ControlWrapper({                                         
2     'controlType': 'NumberRangeFilter',                                                          
3     'containerId': 'slidersum_div',                                                              
4     'options': {                                                                                 
5          //select the data to filter by matching column name exactly                            
6               'filterColumnLabel': 'Total $ Contributions',                                          
7         }                                                                                                       });

Presenter Notes

Instantiate dashboard objects, bind and draw

  !javascript
  var dashboard = new google.visualization.Dashboard(                                               
              document.getElementById('dashboard_div'));                                            
  //bind the controls to the graph                                                                  
  dashboard.bind([stringfilter, slidersum, slidernum, slidercyc, catwin, catparty, catinc, catst], wrapper);                                                                                                   
  //render the graph and controls                                                                   
  dashboard.draw(datav);

Presenter Notes

Don't forget the HTML

Just list divs with id's that match the value set by 'containerId':

 1 <div id="dashboard_div">                                                                                
 2     <div id="strname_div"></div>                                                                        
 3     <div id="slidersum_div"></div>                                                                      
 4     <div id="slidernum_div"></div>                                                                      
 5     <div id="slidercyc_div"></div>                                                                      
 6     <div id="catwin_div"></div>                                                                         
 7     <div id="catparty_div"></div>                                                                       
 8     <div id="catinc_div"></div>                                                                         
 9     <div id="catst_div"></div>                                                                          
10     <div id="chart_div"></div>                                                                          
11 </div>

Presenter Notes

Let's take a look at our complete script

Presenter Notes

How to add tooltips

Presenter Notes

Changing the schema

1 description = [("Candidate",'string', "Candidate",{'role':'tooltip'}),
2                ("State","string", "State",{'role':'tooltip'}),
3                ("Party","string"),
4                ("Is Incumbent?","string", "Is Incumbent?",{'role':'tooltip'}),
5                ("Cycle","number", "Cycle",{"role":"tooltip"}),
6                ("Result","string", "Result",{'role':'tooltip'}),
7                ("In-State Contributions","number"),
8                ("Total $ Contributions","number"),
9                ("Total # Contributions","number")]

Presenter Notes

Adding the tooltip columns to the chart

The tooltip columns are listed immedately after the y column (in this case column 7):

1 //select only the in-state contribution fraction and $ contribution columns for display     
2 //plus all the tooltip columns                                                              
3 'view': {'columns': [6, 7, 0, 1, 3, 4, 5]}

Presenter Notes

Let's add some colors

  • Adding colors to the data points requires changes to the structure of the data
  • View script execution
  • View script source
  • Changes required
    • One data column for each categorical variable in the y axis
    • Schema must be updated
    • Data structure must be updated
    • Chart must include the updated columns
    • Add tooltip columns for each category

Presenter Notes

Change the schema

 1 description = [("Candidate",'string', "Candidate",{'role':'tooltip'}),
 2 ("State","string", "State",{'role':'tooltip'}),
 3 ("Party","string"),
 4 ("Is Incumbent?","string", "Is Incumbent?",{'role':'tooltip'}),
 5 ("Cycle","number", "Cycle",{"role":"tooltip"}),
 6 ("Result","string", "Result",{'role':'tooltip'}),
 7 ("In-State Contributions","number"),
 8 ("Total # Contributions","number"),  #re-arranged num contributions                          
 9 ("Total $ Contributions","number"), #one column with everything so filter still works        
10 ("Democrats","number"),  #separate column for Democrats                                      
11 ("Republicans","number") #separate column for Republicans                                    
12 ]

Presenter Notes

Change the data

 1 for record in csv.reader(open('/home/qtw/public_html/data/cont4google.csv'),delimiter=',',quotechar='"'):
 2     #first convert the numerical values from strings to numbers                                             
 3     record[4]=int(record[4])
 4     record[6]=float(record[6])
 5     record[7]=int(record[7])
 6     record[8]=int(record[8])
 7     #add a check to skip any fields with blank entries                                                      
 8     if "" in record: continue
 9     #OK now to rearrange the columns to split by categorical variable                                       
10     numcont=record[-1]
11     sumcont=record[-2]
12     record=record[:-2]
13     #now go through all the possible values for parties                                                     
14     if record[2]=="D":
15         record+=[numcont,sumcont,sumcont,None]
16         data.append(record)
17     elif record[2]=="R":
18         record+=[numcont,sumcont,None,sumcont]
19         data.append(record)

Presenter Notes

Update the data columns for the chart

1 //select only the in-state contribution fraction and $ contribution columns for display     
2 //columns 9 and 10 are $ contributions to R and D respectively                              
3 //plus all the tooltip columns 0,1,3,4,5 (repeated after each Y value)                      
4 'view': {'columns': [6, 9, 0, 1, 3, 4, 5, 10, 0, 1, 3, 4, 5]}

Presenter Notes

Note on debugging

  • With multiple languages, you can get errors in multiple ways
  • Python errors
    • Run-time errors will appear in the browser if you use cgitb.enable()
    • Syntax errors will return an internal server error message
    • To view Syntax errors, run the script from the terminal
      • cd ~/public_html/cgi-bin/
      • ./script-name.cgi
  • Javascript errors
    • If you get an empty web page, check the Javascript console
    • Console lists errors with line numbers and explanationas

Presenter Notes