Page 2 of 26

Time for R

Here at OU, there are at least 4 or 5 that teach introductory R. You can take a statistics class, an economics class, a biological stats class, or a class just on R as a programming language. R has become one of the most commonly used languages for computational stats and data visualization, so it’s not surprising to see it pop up in a number of different departments. However, it has not yet made its way into the humanities.

For those of us in the humanities then, I wanted to pull together a few online resources that can help you get started.

My favorite introduction is TryR from Code School. This pirate themed introduction is great for people with little coding experience. It walks you through basic expressions, variables, arrays, loops, and graphing in a lightly gamified, campy platform.

Screen Shot of the Try R platform from Chapter 1

In a recent blog post, Jesse Sadler from UCLA, offered a more targeted  ‘Introduction to Network Analysis using R.’ Jesse does a great job of explaining  how nodes and edges come together in network graphs and how various R libraries make it relatively easy to produce these graphs. Jesse’s research involves mapping the correspondence of the 16th-century Dutch merchant, Daniel van der Meulen, which serves as a great example of the promise of R for DH research.

Screen Shot of Jesse Sadler's network graphing research projectLincoln Mullen is currently composing an open textbook called Computational Historical Thinking which uses and teaches R.  The resources he’s already assembled are fantastic, and his book serves as an excellent example of open-writing and review.

Screen Shot of Lincoln Mullen's Computational Historical Thinking Website

Less open but more complete, Matthew Jockers has produced a book and website with Springer called Text Analysis with R for Students of Literature. Taylor Arnold and Lauren Tilton also have a Springer book out called Humanities Data in R.

Last, but certainly not least, are the workshops provided by Software Carpentry. Here at OU and throughout the world. Software Carpentry provides two day workshops that introduce command line programming, versioning (usually with Git and GitHub) and R. These workshops are great because they work from a very introductory level and are meant to ease people into coding and data management. The group on OU’s campus is based out of the library and are particularly eager to help graduate students who are venturing into data analysis for the first time.

If you haven’t tried out R yet, take a minute to poke around at one of the resources above and thinking about how you already use maps, graphs, and tables in your work. Rather than hand-drawing your next map or searching for something to represent a network graph, take the same time to learn a new skill.

Visualizing Connections in the Sea of Information

Between podcasts, newspapers, blogs, journals, books, and video, I have access to far more media than I could possibly consume. Rather than having to search for information, I swim through a vast sea of it. The labor comes in deciding what I want to think about right now and then charting a path through good information.

These pathways through information are big business. Google’s algorithms and personalization through data collection are built to provide a path. Amazon is not so much a store but a service to guide you through the vast array of products to discover the one widget you can’t live without. Now JSTOR, Gale, and the other academic warehouses are investing in algorithms and tools to guide you through their dark waters.

Lately, I’ve been collaborating on a project that builds a visual pathway through the thematic connections between blog posts, creating a map for this cluster of information. ‘Inhabiting the Anthropocene‘ is an interdisciplinary, group blog started here at the University of Oklahoma “in order to understand better how humans’ transform the Earth through their habitation of it, and to imagine how the processes and results of habitation might better contribute to the Earth’s habitability.”

Screen Shot of Inhabiting the Anthropocene

In 2015, this group pulled together a selection of their blog posts and tagged theme with information about the intellectual approaches and thematic content. The project leader, philosophy professor Zev Trachtenberg teamed up with James Adams (at that time an Emerging Technologies Librarian at the University of Oklahoma’s Bizzell Library & now a Data and Visualization Librarian at Dartmouth College) to develop a web app to visualize these connections. ‘Habitation in the Anthropocene: An Interdisciplinary Interaction‘ uses Cytoscape to produce seven graphs illustrating the connections between the blog posts. Selecting any one of these graphs triggers changes throughout the web apps’ three main frames. For each graph there is a description and legend. Within the graph, you can select any of the posts, represented as nodes to pull up the text of the original blog post and information about the author. You can also mouse over the graphs’ edges to pull up more information about the connections being represented.

Screen Shot of Habitation in the Anthropocene

My part in this project was very small. As Zev has been preparing publication of a journal article on the project, I helped him clean up the code and make sure the latest version was available on Github. I updated the Cytoscape library to a slightly more recent version and removed some of the deprecated functions and data from the javascript files. We also stood up a new URL for the site in OU Create.

I find this project exciting because it provides a visual grammar for the traditional humanist’s research strategy of crawling through footnotes. By adding thematic tags, we can transform the traditional bibliography into a map of a research field. We could take the tags and categories from larger sets of blog posts and drop them into similar visualizations. We could use text analysis to create thematic tags for a corpus of primary texts or use Hypothes.is to tag online readings. These curated paths can restore a sense of connectivity between writers and readers. This thematic visualization is one tool for restoring rational choice to the process of information consumption.

Twine Game Data to Google Sheets via Javascript

Using Twine, a free, open-source, text-based game software, you can build choose your own adventure games that explore the untaken paths in literaturepromote empathy through simulated experiences, and provide role-playing adventures in historical scenarios. Twine games are often used in the classroom, because you can quickly build an educational experience about whatever subject you choose. They are also heavily used in the interactive fiction world as a medium for short stories and novels.

In the XP Twine workshop that Keegan and I are leading, several of the faculty members asked how Twine games could be used to track students’ understanding of concepts. One faculty member is building a game that simulates entrepreneurial business investment. In the game, students can try out different investment strategies and equity stakes as they try to become a successful venture capitalist. The professor wanted to be able to track the choices they made in game in order to spur in class discussion.

Twine games take the form of HTML files with embedded CSS and JS. In my latest round of tinkering, I figured out how to use javascript within a Twine game to send an HTTP post message to pass game-play data to a Google Spreadsheet, thereby creating a database that records each game-play.

Google Sheet/Apps Script Code

In order to track this game data, I suggested that we push the data from Twine to a Google Spreadsheet. Following the lead of Tom Woodward, I’ve found that Google Spreadsheets are a relatively easy place to collect and analyze data. I wanted to use Google Scripts, which are mostly javascript and a few custom functions, to receive data and parse it into the cells of the Google Sheet.

Martin Hawksey wrote a blog post a few years ago called “Google Sheets as a Database – INSERT with Apps Script using POST/GET methods (with ajax example).” Martin had set up an Ajax form that could be embedded in any website that would pass data to his Google Script which would then record it in his Google Sheet. Martin’s code (below) receives an HTTP Get or Post call generated by an Ajax form, parses the parameters of that HTTP call, and stores those parameters in a Google Sheet. Martin also provides comments in his code to help users customize the Google script and initiate it as a Web App.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//  1. Enter sheet name where data is to be written below
        var SHEET_NAME = "DATA";
 
//  2. Run > setup
//
//  3. Publish > Deploy as web app 
//    - enter Project Version name and click 'Save New Version' 
//    - set security level and enable service (most likely execute as 'me' and access 'anyone, even anonymously) 
//
//  4. Copy the 'Current web app URL' and post this in your form/script action 
//
//  5. Insert column names on your destination sheet matching the parameter names of the data you are passing in (exactly matching case)
 
var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service
 
// If you don't want to expose either GET or POST methods you can comment out the appropriate function
function doGet(e){
  return handleResponse(e);
}
 
function doPost(e){
  return handleResponse(e);
}
 
function handleResponse(e) {
  // shortly after my original solution Google announced the LockService[1]
  // this prevents concurrent access overwritting data
  // [1] http://googleappsdeveloper.blogspot.co.uk/2011/10/concurrency-and-google-apps-script.html
  // we want a public lock, one that locks for all invocations
  var lock = LockService.getPublicLock();
  lock.waitLock(30000);  // wait 30 seconds before conceding defeat.
 
  try {
    // next set where we write the data - you could write to multiple/alternate destinations
    var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
    var sheet = doc.getSheetByName(SHEET_NAME);
 
    // we'll assume header is in row 1 but you can override with header_row in GET/POST data
    //var headRow = e.parameter.header_row || 1; Hawksey's code parsed parameter data
    var postData = e.postData.contents; //my code uses postData instead
    var data = JSON.parse(postData); //parse the postData from JSON
    var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
    var nextRow = sheet.getLastRow()+1; // get next row
    var row = []; 
    // loop through the header columns
    for (i in headers){
      if (headers[i] == "Timestamp"){ // special case if you include a 'Timestamp' column
        row.push(new Date());
      } else { // else use header name to get data
        row.push(data[headers[i]]);
      }
    }
    // more efficient to set values as [][] array than individually
    sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
    // return json success results
    return ContentService
          .createTextOutput(JSON.stringify({"result":"success", "row": nextRow}))
          .setMimeType(ContentService.MimeType.JSON);
  } catch(e){
    // if error return this
    return ContentService
          .createTextOutput(JSON.stringify({"result":"error", "error": e}))
          .setMimeType(ContentService.MimeType.JSON);
  } finally { //release lock
    lock.releaseLock();
  }
}
 
function setup() {
    var doc = SpreadsheetApp.getActiveSpreadsheet();
    SCRIPT_PROP.setProperty("key", doc.getId());
}

I edited Martin’s original code in lines 39-41. In his code, he’s looking for Post data in a slightly different format than what I generate. Rather than using the parameters from the HTTP Post, my code uses the data from the Post.

Twine Game Code

Rather than using an Ajax form, I wanted to pass variables that had been collected during gameplay in a Twine game. Twine is built on javascript, so I decided to replace Martin’s Ajax form with a javascript HTTP Post function embedded in Twine. Based on research on how Twine works, I decided that the best way to do this would be to write the javascript code directly into a Twine game passage. My passage, called PostData, would presumably come at or very near the end of my game after all interesting variables have been set:

Twine Screen ShotI wrapped Twine’s script syntax <script></script> around the standard xhr XMLHttpRequest() function. This sends an HTTP Post to whatever url is provided (like the url for your Google Script Web App) with a json package defined in the var data line. Here’s this code (please note that you need to add the <script></script> modifiers in Twine:

1
2
3
4
5
6
var xhr = new XMLHttpRequest();
var url = "URL for the Google App";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-type", "application/json; charset=UTF-8");
var data = JSON.stringify({"var1": harlowe.State.variables['var1'], "var2": harlowe.State.variables['var2'], "var3": harlowe.State.variables['var3']});
xhr.send(data);

However, in order to pull variables out of the Harlowe version of Twine that I was using, I also needed to add the following code by editing the Story Javascript:

Twine Javascript Screen Shot

This bit of Javascript passes all variables defined within the Twine game into an array (window.harlowe) that is accessible by Javascript code that is embedded in the game. Here’s the code in case you want to try this out:

1
2
3
if (!window.harlowe){
	window.harlowe = {"State": State};
}

I hope this work will be useful in studying any Twine game to see how players are moving through the game. You could record any variables in the game and also the games ‘history’ to see which passages each player went through. This has obvious uses for educational games in being able to provide feedback to players, but it also has implications for game design more broadly with the increased use metrics.

Implement in your own game

In order to implement this for your own game, I would suggest following these steps:

  1. Copy the Javascript code above (starts with if (!window)) into your Twine game’s Javascript panel
  2. Copy the PostData code above and paste it into a TwinePost passage towards the end of your game
  3. Then replace the variables in the TwinePost passage so that harlowe.State.variables[‘var1’] becomes harlowe.State.variables[‘your variable name here’] for each of the variables you want to track
  4. Click this link to get a copy of my Google Spreadsheet
  5. Make sure the column headers in the spreadsheet match your variable names from the TwinePost passage
  6. In the Google Sheet, click on Tools->Script Editor and follow Martin Hawksey’s instructions for steps 2-5
  7. When you publish your Script as a Web App, it will give you a URL for the Web App. Copy this URL and paste it into the URL variable in your TwinePost passage code.
  8. You’re done. Play your game and see if everything works. If it doesn’t work, tweet at Tom Woodward. He’s good at fixing code and has nothing but free time on his hands.

I am excited about this code because it answers a question for several of our faculty members and makes Twine games more useful as formative assessments. Hawksey did an excellent job in keeping his code very generalized, and I’ve tried to preserve that, so that you can track whatever variables you want.

You could also use the HTTP Post javascript code outside of Twine in any other web site or web app to pass information to your Google Sheet. Tom has blogged a couple of times about using code to send data to Google Forms and autosubmitting into a Google Spreadsheet. I think the process described above denecessitates that Google Form pass through and moves us a step closer to Google sheets as a no-SQL data base alternative.

Page 2 of 26

Powered by WordPress & Theme by Anders Norén

css.php