Saturday, December 18, 2010

Basic Time Slider in Closure

Earlier this month I was playing with a the Google Closure library and using the slider. I wanted to play with it for developing a time slider too. Since I'm going to History Hack Day at the end of January in London, I thought I'd show off some samples there and this was a perfect hack for that.

Anyway, it's pretty simple. You set minimum and maximum values on the slider that correspond to the millisecond values used by JavaScript to represent time. Then use the JS Date object to convert those to readable date and time for display under the slider. You can see the sample here. I set the slider to between Wed Dec 31 2003 23:59:59 and Fri Jan 01 2010 00:00:00 since I knew all dates in the underlying table fell between them. I used another Wikileaks table, the Afghan War Diary, 2004-2010 table.

The tricky part is that Fusion Tables doesn't document the date formats that it accepts for queries. We just haven't gotten around to changing the docs, but I happen to know that we accept these formats:

MM/dd/yy
MM-dd-yy
MMM-dd-yy
yyyy.MM.dd
dd-MMM-yy
MMM/yy
MMM yy
dd/MMM/yy
yyyy

Monday, December 13, 2010

AGU 2010: Data Visualization

So, this was the first year without a digital globes track. I think two things happened:


  1. Organizers got tired of doing it every year
  2. More important: Digital globes are now all over the American Geophysical Union's annual meeting. There's really no need to separately call it out.
So this year, I presented to Visualization Aided Data Analysis: Tools and Techniques for the Geophysical Sciences. Smaller than my other years at AGU, this was still a vital record of the different tools needed for data analysis. I was particularly impressed by Hank Childs' presentation on VisIt: A Tool for Visualizing and Analyzing Very Large Data, which really seemed to be a tool for visualizing anything in any possible way. Wow, awesome tool. I was also really impressed by Vis Research: Advances in Visualization Research by Ken Joy, U.C. Davis. He had really impressive visualizations of flow patterns.

My own discussions of Fusion Tables, Earth, and Earth Engine seemed a bit more basic, but perhaps that's the point I've been trying to make, that visualization tools can be powerful and hard to use, putting incredible versatility and detail in the hands or professionals, or easy to use and basic for everyone. And when they are easy and basic, everyone can use them effectively.
 Anyway, here's my slides:


Thursday, December 9, 2010

Freebase Meetup and JSONP

So, I was invited to speak at a Freebase meetup by Kirrily Roberts. I thought "Cool, Freebase. Oh, I should learn that!" Especially now that Freebase is part of Google! So apologies if you're looking for my intended next sample which was closure as a time slider, that will come.

I did a couple of maps mashups to try and learn the query language. But at the same time, I wanted to learn more about Google Closure. So, here's a couple of samples that I did. Let me explain in further detail:

<link href="http://code.google.com/apis/maps/documentation/javascript/examples/standard.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script src="goog/base.js"></script>
<script>
   
goog.require('goog.net.Jsonp');
var obj;
var map;
 
function initialize() {
  var latlng = new google.maps.LatLng(0,0);
  var mapOptions = {
        zoom: 2,
        center: latlng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
  };
 
 
  map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
  getEvents(); 
} 

function getEvents() {
  var envelope = 'http://www.freebase.com/api/service/mqlread?query={%20%22query%22:%20[{%20
        %22type%22:%20%22/time/event%22,%20%22id%22:%20null,%20%22name%22:%20null,
        %20%22included_in_event%22:%20[{%20%22name%22:%20%22world%20war%20ii%22%20}],
        %20%22locations%22:%20[{%20%22geolocation%22:%20{%20%22latitude%22:%20null,
        %20%22longitude%22:%20null%20}%20}]%20}]%20}';
  getData(envelope,'');
} 

function getData(dataUrl,data) {
  var jsonp=new goog.net.Jsonp(dataUrl);
  jsonp.setRequestTimeout(100000);
  jsonp.send('',setObject);
}

function setObject(response){
  obj = response['result'];
  addMarkers();
}
function addMarkers(){
  for(var i in obj){
    for(var j in obj[i].locations){
      var latLng = new google.maps.LatLng(obj[i].locations[j].
            geolocation.latitude,obj[i].locations[j].geolocation.longitude);
      var marker = new google.maps.Marker({
          map: map,
          position: latLng,
          title: obj[i].name
      });}
      console.log(obj[i].name);
  }
}

So what I did there was use goog.net.jsonp from Closure to load the JSON from the query results and then create markers. The first sample finds events during World War II and find their geolocation. Since some events have more than one geolocation, it gives each location a marker with the same title, which will show up as a tool tip on hovering over the marker. In this case, the event contains a /location/location node which has /location/location/geolocation nodes. Someone comment if I'm not getting that quite right.

For those that don't know, I used the JSONP utility to get around the same domain policy of browsers, which prevents you from loading scripts directly from domains other than the one you are loading from. Server side scripting would have solved that issue for me easily, but I decided to set myself the additional challenge of finding that workaround. JSONP takes advantage of the caveat to the same domain policy that allows you to load scripts into <script> tags in HTML. In the case of the Closure library, it creates a temporary <script> tag, uses it to get the JSON object, and then gets rid of the script tag. One must exercise caution when using this approach, of course, that the source of your JSON is trusted to prevent attacks on visitors to your site.

My second sample took a /location/location, in this case Berkeley California (where I grew up) and found all /location/location nodes that had a containedby relationship to Berkeley California. And then mapped them. Then I added in animation to, so if you click on one place it bounces. Just for fun.

It was pretty basic. Figuring out the query language is not easy. Actually, before I spoke at the meetup, Jamie Taylor did a great talk about the schema which really cleared up some things for me. Unfortunately, we experienced a complete A/V failure in the room the meetup was in> Jaime did his talk with a white board, which I think made him happy. I jokingly referred to my talk as interpretive dance. I described my approach, why I was using JSONP, what tools were available, and then we went and had a beer.

Update

I should have credited this article on JQuery and JSONP with part of my inspiration.

Friday, December 3, 2010

Playing with Closure UI Library: Slider

For Google Developer Day in SaƵ Paulo, my colleague Ossama Alami created this sample, which allows you to select between three different Google Fusion Tables layers and play with queries against them. I looked at that and decided that I would use it to play with the Closure Library. Specifically, I wanted to play with the UI library. So for the GDD events in Munich, Moscow, and Prague, I decided to add a slider. The results were fun, and instructional for me. The code to add a slider was pretty simple. Here's my sample, and here's the slider code:


<script>

var el = document.getElementById('s1');
s = new goog.ui.Slider;
s.decorate(el);
s.addEventListener(goog.ui.Component.EventType.CHANGE, function() {
document.getElementById('out1').innerHTML = s.getValue();
});

goog.events.listen(
s.getContentElement(),
[goog.events.EventType.MOUSEOUT,
goog.events.EventType.KEYUP,
goog.events.EventType.MOUSEUP],
function() {
var preset = document.getElementById("preset").selectedIndex;
var query = presets[preset].sampleQuery + s.getValue();
document.getElementById('query').value = query;
layer.setTableId(parseInt(document.getElementById('preset').value));
layer.setQuery(query);
});
</script>


I just took that from the documentation. Of course, there's a an HTML element for the slider, and some CSS to style it, and loading the library itself. Well, you can view source. The instructional bit was that of course as soon as you move the slider, events start firing. If you listen for a CHANGE event, as you slide the slider, it'll fire too fast. Each tick, it'll try to grab a new layer from Fusion Tables. That'll consume lots of bandwidth as FT tries to return a layer with each tick. So instead, I listen for MOUSEOUT, KEYUP, and MOUSEUP events, which fire when the user is done moving the slider, either moving off it or releasing the mouse.

Next up, I'm going to try to use it to simulate a timeslider.