Archive for the 'javascript' Category

Anonymous Recursive Functions

I learned this “trick” some time ago, while reading the source code for the MooTools JavaScript framework (version 1.1, I think).

I used this “trick” not so long ago, when developing the Spacetree visualization for the JavaScript InfoVis Toolkit library.

When clicking a node, the Spacetree visualization unselects all tree nodes and then selects the nodes in between the root node and the selected node. This can be implemented as a recursive function, since we have to iterate through the clicked node and its ancestors to set those nodes as selected.

I defined an anonymous recursive function that receives a node and a special value as formal parameters, and sets the selected property from this node and its ancestors to the specified value:

  (function(node, val) {
      if(node == null) return;
      node.selected = val;
      return arguments.callee(node.parent, val);
  })

arguments.callee holds a reference to the defined function.
You can check that by copying this code:

  (function(text) {
    alert(arguments.callee);
    alert(text);
  })("some text");

and running it in your Firefox console.

Unfortunately, our anonymous recursive function needs to be called more than once, since we first need to unselect previous selected nodes, and then to select the nodes in between the clicked node and the root node.
Similar to the “return this” trick to chain method calls, we can add “return arguments.callee” to chain function calls.

  (function(node, val) {
      if(node == null) return arguments.callee;
      node.selected = val;
      return arguments.callee(node.parent, val);
  })

This way, we can call our function multiple times. I’ll first pass the previous clicked node in order to unselect the previous selected path, and then I’ll pass the new clicked node in order to select our new path:

  (function(node, val) {
      if(node == null) return arguments.callee;
      node.selected = val;
      return arguments.callee(node.parent, val);
  })(nodePrev, false)(nodeNew, true);

What’s more interesting though, it’s trying to do the same thing in another language, like Lisp or OCaml.
Who knows, you might sumble upon the Y combinator.

Visualizing Linux package dependencies

I’ve been building a Linux package dependency visualizer with Python and the JavaScript Infovis Toolkit that gathers all dependencies for a linux package and displays them in an interactive tree visualization.

So, let’s say your query is wine and you want to see dependencies for that package. The visualization will display wine as the centered node, laying its dependencies on outer concentric circles like this:

rg1

By clicking on xbase-clients you’ll set this node as root:

rg2

Then, the visualization will query for xbase-clients dependencies, morphing its state into the new node’s perspective:

rg3

You can play with the example here.

I’ll explain how to build this in case you want your own at home.
I guess this is going to be also a nice tutorial on how to configure the RGraph visualization to run advanced examples, including the new morphing animations in version 1.0.7a.

Server Side

Server side we need to build a service that can transform the apt-rdepends output for package dependencies into a JSON tree structure.

The apt-rdepends is a linux tool (which you can install with apt-get install apt-rdepends) that displays a hierarchy of package dependencies for a given package. Here’s an example when querying for erlang:

cmd1

You can either use popen2 or commands.getoutput to fetch the output for a system call in Python, I’ll do the latter.
The main function that makes the system call and returns the answer could be something like this:

def get_dependency_tree(package=''):
    out = commands.getoutput("apt-rdepends " + package).split("\n")
    ans = []
    #if dependencies were found for this package.
    if len(out) > 3 and out[3].strip() == package:
        ans = out[3:]
    else:
        ans = [package]
    return make_tree(package=ans[0].strip(), source=ans, level=2)

The make_tree function will create the tree structure that will then be serialized into JSON to be processed client side.

We will first need a make_tree_node function that creates a tree node structure from a package’s name:

#returns a tree node
def make_tree_node(id, node_name):
    node_name = node_name.strip()
    return {
            'id': id,
            'name': node_name,
            'children': [],
            'data': []
    }

As you can see, this is the same tree node as the JSON tree structure defined for the JIT:

var json = {
	"id": "aUniqueIdentifier",
	"name": "usually a nodes name",
	"data": [
	    {key:"some key",       value: "some value"},
		{key:"some other key", value: "some other value"}
	],
	children: [/* other nodes or empty */]
};

Our make_tree function will receive as formal parameters the root package, the response from the apt-rdepends call, an integer that will specify the max depth for the tree (in case we want to prune it to some level) and an id prefix that will be set for each node:

def make_tree(package='', source=[], level=1, prefix=''):
    node = make_tree_node(package + '_' + prefix, package)
    if level > 0:
        deps = get_package_deps(package, source)
        [node['children'].append(make_tree(elem, source, level -1, package)) for elem in deps]
    return node

As you can see, make_tree recursively creates nodes and appends them to their parent children property.

Finally, I also made a get_package_deps function that retrieves all children for a given package, parsing source:

def get_package_deps(package_name='', source=[]):
    ans, found_package_name = [], False
    #test if is a dependency line
    dependency = lambda package: package.strip().startswith('Depends:')
    for line in source:
        #package name line
        if not found_package_name and package_name == line.strip():
            found_package_name = True
        #it's a package dependency, add its name to the answer
        elif found_package_name and dependency(line):
            ans.append(line.split("Depends: ")[1].split("(")[0].strip())
        #end of dependency lines
        elif found_package_name and not dependency(line):
            return ans
    return ans

If you used Django, then you could expose your service in the views.py file like this:

def apt_dependencies(request, mode, package):
    json = aptdependencies.get_dependency_tree(package)
    json_string = simplejson.dumps(json)
    return render_to_response('raw.html', { 'json' : json_string })

Client Side

All the JavaScript Infovis Toolkit visualizations are customizable via controller methods.
If this is the first time you use this library, perhaps it would be better to start with the RGraph quick tutorial first.

First we define a simple Log object, that will write the current state of the graph to a label (like loading… or stuff like that).

I’ll use Mootools, but you can use whatever you want.

var Log = {
	elem: false,
	getElem: function() {
		return this.elem? this.elem : this.elem = $('log');
	},

	write: function(text) {
		var elem = this.getElem();
		elem.set('html', text);
	}
};

Then we can define an init function, that instanciates the RGraph object and returns it.
We will pass a controller to this object, that implements the onBeforeCompute, onAfterCompute, onPlaceLabel and onCreateLabel methods.
I’ll also define some utility methods, like requestGraph and preprocessTree:

function init() {
  //Set node radius to 3 pixels.
  Config.nodeRadius = 3;

  //Create a canvas object.
  var canvas= new Canvas('infovis', '#ccddee', '#772277');

  //Instanciate the RGraph
  var rgraph= new RGraph(canvas,  {
	//Here will be stored the
	//clicked node name and id
  	nodeId: "",
  	nodeName: "",

  	//Refresh the clicked node name
	//and id values before computing
	//an animation.
	onBeforeCompute: function(node) {
  		Log.write("centering " + node.name + "...");
		this.nodeId = node.id;
  		this.nodeName = node.name;
  	},

  //Add a controller to assign the node's name
  //and some extra events to the created label.
  	onCreateLabel: function(domElement, node) {
  		var d = $(domElement);
  		d.setOpacity(0.6).set('html', node.name).addEvents({
  			'mouseenter': function() {
  				d.setOpacity(1);
  			},
  			'mouseleave': function() {
  				d.setOpacity(0.6);
  			},
  			'click': function() {
				if(Log.elem.innerHTML == "done") rgraph.onClick(d.id);
  			}
  		});
  	},

	//Once the label is placed we slightly
	//change the positioning values in order
	//to center or hide the label
  	onPlaceLabel: function(domElement, node) {
		var d = $(domElement);
		d.setStyle('display', 'none');
		 if(node._depth <= 1) {
			d.set('html', node.name).setStyles({
				'width': '',
				'height': '',
				'display':''
			}).setStyle('left', (d.getStyle('left').toInt()
				- domElement.offsetWidth / 2) + 'px');
		}
	},

	//Once the node is centered we
	//can request for the new dependency
	//graph.
	onAfterCompute: function() {
		Log.write("done");
		this.requestGraph();
	},

	//We make our call to the service in order
	//to fetch the new dependency tree for
	//this package.
   	requestGraph: function() {
  		var that = this, id = this.nodeId, name = this.nodeName;
  		Log.write("requesting info...");
  		var jsonRequest = new Request.JSON({
  			'url': '/service/apt-dependencies/tree/'
					+ encodeURIComponent(name) + '/',

  			onSuccess: function(json) {
  				Log.write("morphing...");
				//Once me received the data
				//we preprocess the ids of the nodes
				//received to match existing nodes
				//in the graph and perform a morphing
				//operation.
  				that.preprocessTree(json);
				GraphOp.morph(rgraph, json, {
  					'id': id,
  					'type': 'fade',
  					'duration':2000,
  					hideLabels:true,
  					onComplete: function() {
						Log.write('done');
					},
  					onAfterCompute: $empty,
  					onBeforeCompute: $empty
  				});
  			},

  			onFailure: function() {
  				Log.write("sorry, the request failed");
  			}
  		}).get();
  	},

	//This method searches for nodes that already
	//existed in the visualization and sets the new node's
	//id to the previous one. That way, all existing nodes
	//that exist also in the new data won't be deleted.
 	preprocessTree: function(json) {
  		var ch = json.children;
  		var getNode = function(nodeName) {
  			for(var i=0; i<ch.length; i++) {
  				if(ch[i].name == nodeName) return ch[i];
  			}
  			return false;
  		};
  		json.id = rgraph.root;
		var root = rgraph.graph.getNode(rgraph.root);
  		GraphUtil.eachAdjacency(root, function(elem) {
  			var nodeTo = elem.nodeTo, jsonNode = getNode(nodeTo.name);
  			if(jsonNode) jsonNode.id = nodeTo.id;
  		});
  	}

  });

  return rgraph;
}

I did say advanced example.
You can always go to a simpler example to begin here.

Finally we have to initialize the visualization when the page loads, so we’ll attach an initialization function like this:

window.addEvent('domready', function() {
	var rgraph = init();
	new Request.JSON({
	  	'url':'/service/apt-dependencies/tree/wine/',
	  	onSuccess: function(json) {
			  //load wine dependency tree.
			 rgraph.loadTreeFromJSON(json);
			  //compute positions
			  rgraph.compute();
			  //make first plot
			  rgraph.plot();
			  Log.write("done");
			  rgraph.controller.nodeName = name;
	  	},

	  	onFailure: function() {
	  		Log.write("failed!");
	  	}
	}).get();

HTML and CSS

These are the HTML and CSS files I used to make this example/tutorial.
The HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>

Linux package dependency visualizer

</title>
<link type="text/css" href="/static/css/style.css" rel="stylesheet" />
<script type="text/javascript" src="/static/js/mootools-1.2.js"></script>

<!--[if IE]>
<script language="javascript" type="text/javascript" src="/static/js/excanvas.js"></script>
<![endif]-->
<script language="javascript" type="text/javascript" src="/static/js/core/RGraph.js"></script>
<script language="javascript" type="text/javascript" src="/static/js/example/example-rgraph.js"></script>

</head>

<body onload="">

<canvas id="infovis" width="900" height="500"></canvas>
<div id="label_container"></div>

</body>
</html>
<div id="log"></div>

Note: You’ll probably have to change the path to the CSS and JavaScript files.

and the CSS file:

html,body {
	width:100%;
	height:100%;
	margin:0;padding:0;
	background-color:#333;
	text-align:center;
	font-size:0.94em;
	font-family:"Trebuchet MS",Verdana,sans-serif;
}

#infovis {
	width:900px;
	height:500px;
	background-color:#222;

}

.node {
	color: #fff;
	background-color:#222;
	font-weight:bold;
	padding:1px;
	cursor:pointer;
	font-size:0.8em;
}

.hidden {
	display:none;
}

Remarks

Although still in alpha, the JavaScript Infovis Toolkit can be used to perform advanced animations, customizing your visualization via a controller and not messing with the code.
This example also shows that it can be used to do more advanced things that only plotting static animations, interacting with services and handling pretty well visualizations where the dataset changes over time.
You can download the library here, latest version is 1.0.7a.
You can also go to the main project page to know more.

Hope it was useful.
Feel free to post any comment or questions.
Bye!

Graph Operations

I’ve been working on the JavaScript Infovis Toolkit lately, fixing bugs, working on performance improvements and adding a new feature for Spacetrees, Hyperbolic Trees and RGraphs that I’ve found very interesting.

Mutable data

The JavaScript Infovis Toolkit is a JS Information Visualization library that includes radial layout of trees with animations, Treemaps, Hyperbolic Trees and Spacetrees.

Not so long ago I worked on adapting these tree layouts to support graph layouts as well, also including weighted nodes and edges, as you can see in this example.

However, one of the most challenging features I wanted to add to these visualizations was the possibility of dealing with mutable data. This way visualizations would also be useful to show how data changes over time, and updates to this data would be translated into smooth animations from one state of the graph to another.

The user could also interact at a deeper level with the visualizations, not only exploring the data, but also altering it, making updates to the information and seeing the results in real time.

The GraphOp object

The first thing that came into my mind when thinking on adding support for mutable data was prototyping the addSubtree and removeSubtree methods.
These operations seem suitable for the Spacetree, (and have been implemented for this visualization), but what about applying transformations to graphs?
Since the JIT adds support for graphs and trees in the RGraph and Hyperbolic Tree visualizations, both use cases should be well covered: adding and deleting subtrees as well as adding/deleting nodes, edges, and performing more general binary graph operations, such as graph sum and the one which I’m most proud of, morphing.

So this new release of the library comes with the addSubtree and removeSubtree methods for the Spacetree, and also with the GraphOp object for the Hypertree and RGraph visualizations, which includes unary and binary operations such as:

  • removeNode Multiple nodes can be removed from the visualization. You can choose up to four different animations for doing that.
  • removeEdge Multiple edges can be removed from the visualization. Supports many animations also.
  • sum Performs a sum of two graphs, morphing the result with sequential or concurrent animations of movement and fading.
  • morph A very useful operation in which you specify the resulting graph, and the visualization morphs the current graph state into that one.

Examples

I chose to make two real life examples. With real life I mean small apps that not only show the potential of these graph operations, but can also be actually useful to explore.

1.- Linux module dependency visualizer
It uses the RGraph visualization with the morphing operation to show dependencies between different modules you might find with the apt-get tool.
When clicking on a node you’ll set this node as root. Then the graph will perform a second animation, updating the dependencies for the new centered module.
Many details about the package are also provided under the Details toggler. You can also go to previous visited modules by using the History toggler.

These examples load data dynamically, so please be patient when loading the data.

rgraph

2.- Visualizing relations between artists and bands dinamically
Just as the old demos I made an app that relates bands and artists by common performances on bands, discs, songs, etc.
Clicking on a label will set the node as root. Then a second animation will take place, morphing the tree into the new node’s perspective.

Just as the previous example, you can find some information about the artists in the Details toggler. You can also browse previous visited nodes by clicking in the History toggler.

hypertree

All tutorials and posts have been updated for this new release. You can find more information in the project page and in the google group.

Although this library is still in alpha, some companies and products are already using it, such as OpenCRX and Platform Computing.

I’ll be writing a more technical overview of these features in further posts.

Hope you liked it :)

Memoization in JavaScript

While reading Jason Hickey’s Introduction to Objectve Caml I ran into some memoization examples that I found pretty interesting, and I wondered how memoization could be used/implemented in JavaScript.

What is memoization?
Memoization is a technique that uses side-effects to improve -at runtime- the performance of a function without altering its behavior. Roughly speaking, you can do memoization by storing function values that were returned in previous calls, and returning these values in further calls to the function instead of actually calling the function.

Where can I use memoization?
Not all functions can be memoized. In particular, pure functions can be memoized.
A function is said to be pure when it behaves in a predictable way, in the sense that for each x, the function will always return the same associated y value (i.e a single-valued map).

An example of a function that can be memoized is:

function square(x) {
     return x * x;
}

An example of a function that can’t be memoized could be:

var index = 1;
function not_mem(x) {
     index = index + 1;
     return x + index;
}

By introducing side-effects we alter the inner state of the function, having different return values for the same input. In this particular case, one could say that not_mem(0) != not_mem(0) is always true!

A somewhat generic way to do memoization
In OCaml we can define a higher order function memo that takes a function f as parameter and returns a memoized function that is perhaps faster than the input function.

   let memo f =
      let table = ref [] in
      let rec find_or_apply entries x =
         match entries with
            (x’, y) :: _ when x’ = x -> y
          | _ :: entries -> find_or_apply entries x
          | [] ->
             let y = f x in
             table := (x, y) :: !table;
             y
      in
      (fun x -> find_or_apply !table x)

We can see that the memo function has a table structure where it stores the f function results as (x, y) pairs. For each call to the memoized f function, memo will search in the table structure for an (x, y) pair that matches in x the input value. If found, it will return the associated y value:

         match entries with
            (x’, y) :: _ when x’ = x -> y

If not found, it will partially apply x to the original f function, and store the result in table as an (x, y) pair, to be used on further calls. It will finally return the computed value just as the orginial f function would have done:

             let y = f x in
             table := (x, y) :: !table;
             y

A simple timing shows the performance improvements on further calls for the memoized fibonacci memo_fib function:

#  time memo_fib 40;;
Elapsed time: 14.581937 seconds
- : int = 102334155
# time memo_fib 40;;
Elapsed time: 0.000009 seconds
- : int = 102334155

Achieving the same thing in JavaScript
For unary functions a simple definition of memo could be:

function memo(f) {
  return function (x) {
      f.memo = f.memo || {};
      return (x in f.memo)? f.memo[x] : f.memo[x] = f(x);
  };
}

A couple of differences to notice for this version and the OCaml version are:

  • I’m not using a list of (x, y) pairs. Instead, I’m using a hashtable (or object) {}. This way, response time for the memoized function will not be proportional to the f function domain (as opposed to the OCaml memo function implementation).

  • I’m not using a local table variable to store previous calls. Instead, I’m using a property of the f function, f.memo.
  • In this particular case, the JS memo function behaves like the OCaml memo function for unary functions, since let y = f x for unary functions will evaluate f as opposed to currying the function. However, for (n > 1)-ary functions the OCaml version will return a curried function when called with less formal parameters than “expected”.

Lets do some profiling. For this I’ll be using the console.time and console.timeEnd firebug methods:

function memo(f) {
  return function (x) {
      f.memo = f.memo || {};
      return (x in f.memo)? f.memo[x] : f.memo[x] = f(x);
  };
}

function fib(x) {
    if(x < 2) return 1; else return fib(x-1) + fib(x-2);
}

var memo_fib = memo(fib);
//first call
console.time("first call");
console.log(memo_fib(30));
console.timeEnd("first call");

//console will output:
//first call: 17264ms
//1346269

//second call (memoized)
console.time("memoized call");
console.log(memo_fib(30));
console.timeEnd("memoized call");

//console will output:
//memoized call: 4ms
//1346269

Beyond unary functions memoization in JavaScript
The Ocaml and JavaScript versions of memo lack support for (n>1)-ary functions.
If the OCaml memo function is applied to a binary function, it will only memoize the first partial application for this function.

Lets define a function sum_fib and memo_sum_fib:

# let sum_fib a b = (fib a) + (fib b);;
val sum_fib : int -> int -> int = <fun>
# let memo_sum_fib = memo sum_fib;;
val memo_sum_fib : int -> int -> int = <fun>

Timing the memoized function might lead to some unexpected results:

# time memo_sum_fib 30 40;;
Elapsed time: 18.753172 seconds
- : int = 166926410
# time memo_sum_fib 30 40;;
Elapsed time: 18.753172 seconds
- : int = 166926410

This problem happens because the memoization happens at the first partial application level. That means that the table structure will hold (int, int -> int) elements, as opposed of a mapping from a pair of formal parameters to the returned value: (int * int, int).

In JavaScript we have a bigger problem. Since partial application is not a “natural” feature of the language and the memo function is not designed to handle n-ary functions, this will lead to an error or unexpected results. At least the OCaml version returned the expected values :P.

In JavaScript we can solve this problem by using the arguments object as the key to our f.memo hashtable. Our new memo function would now look like this:

function memo(f) {
  return function () {
      var args = Array.prototype.slice.call(arguments);
      f.memo = f.memo || {};
      return (args in f.memo)? f.memo[args] :
                     f.memo[args] = f.apply(this, args);
  };
}

Not only this function supports n-ary functions to be memoized, but also it performs a correct memoization, in the sense that it will store all formal parameters in f.memo, as the key to the value returned by this function.

Lets do some profiling!

function memo(f) {
  return function () {
      var args = Array.prototype.slice.call(arguments);
      f.memo = f.memo || {};
      return (args in f.memo)? f.memo[args] :
                     f.memo[args] = f.apply(this, args);
  };
}

function fib(x) {
    if(x < 2) return 1; else return fib(x-1) + fib(x-2);
}

function sum_fib(a, b) {
    return fib(a) + fib(b);
}

var memo_sum_fib = memo(sum_fib);
console.time("first call");
console.log(memo_sum_fib(20, 30));
console.timeEnd("first call");

//console will output:
//first call: 17165ms
//1357215

console.time("memoized call");
console.log(memo_sum_fib(20, 30));
console.timeEnd("memoized call");

//console will output:
//memoized call: 5ms
//1357215

Finally, a nice trick you can do is to call the memoized function the same a the function passed in as a formal parameter. Repeating the last example will show a lot of improvements!

function memo(f) {
  return function (x) {
      f.memo = f.memo || {};
      return (x in f.memo)? f.memo[x] : f.memo[x] = f(x);
  };
}

function fib(x) {
    if(x < 2) return 1; else return fib(x-1) + fib(x-2);
}

var fib = memo(fib);
//first call
console.time("first call");
console.log(fib(30));
console.timeEnd("first call");

//console will output:
//first call: 7ms
//1346269

//second call (memoized)
console.time("memoized call");
console.log(fib(30));
console.timeEnd("memoized call");

//console will output:
//memoized call: 5ms
//1346269

Any critique or comment will be well appreciated.
Bye!.

Pattern matching in OCaml (and JavaScript?)

I’ve been trying to learn OCaml lately.
I want to try information visualization for the “dektop” (as opposed to the web), and although I know C++ or Java would be recommended languages for this kind of thing (they have lots of libraries and pretty large communities regarding visualization in general -think about games, OpenGL, etc), I wouldn’t feel very comfortable doing geometric computation in C++ or Java.
Although geometric computation often handles objects, there’s also the “functional side” of it that doesn’t seem to be fulfilled by C++ or Java. Ocaml felt like the right mix in of programming paradigms to do this kind of thing, so I began to read Introduction to Objective Caml by Jason Hickey.

One of the chapters I really enjoyed about this book is Basic pattern maching. I was pretty amazed about the predominance of pattern matching in OCaml. Pattern matching can be applied to (almost) any OCaml primitive type (string, Boolean, char…), it also applies to a variety of syntactic structures (like assignment, function definition, etc) and finally there’s a lot of “syntactic sugar” going on in pattern matching.

The basic syntax for doing pattern matching in Ocaml is:

match expression with
 | pattern1 -> expression1
 | pattern2 -> expression2
 .
 .
 .
  | patternN  -> expressionN

This way you could define a fibonacci fib function like this:

let rec fib i =
   match i with
      0 -> 0
    | 1 -> 1
    | j -> fib (j - 2) + fib (j - 1);;

Since it’s quite common to define functions with match expressions as their body, Ocaml reserved a special keyword function that defines a function with a single argument treated as pattern match. For example the fib function could be re-defined like this:

  let rec fib = function
     0 -> 0
   | 1 -> 1
   | i -> fib (i - 1) + fib (i - 2);;

The pattern match argument is now implicit in the function definition. That’s quite minimalistic.
There’s also the as keyword used to bind a match to a variable. For example:

let rec fib = function
   (0 | 1) as i -> i
 | i -> fib (i - 1) + fib (i - 2);;

The when keyword evaluates a condition after the pattern match. The fib function could now look like this:

let rec fib = function
   i when i < 2 -> i
 | i -> fib (i - 1) + fib (i - 2);;

Pattern matching can also be applied to other Ocaml primitive types, like strings, chars, Booleans. Let’s take an example of the function is_uppercase:

  let is_uppercase = function
   ’A’ | ’B’ | ’C’ | ’D’ | ’E’ | ’F’ | ’G’ | ’H’
 | ’I’ | ’J’ | ’K’ | ’L’ | ’M’ | ’N’ | ’O’ | ’P’
 | ’Q’ | ’R’ | ’S’ | ’T’ | ’U’ | ’V’ | ’W’ | ’X’
 | ’Y’ | ’Z’ ->
    true
 | c ->
    false;;

But that’s not minimalistic. It would be if we used pattern ranges to specify the list of letters like this:

let is_uppercase = function
   ’A’ .. ’Z’ -> true
 | c -> false;;

The c1..c2 notation specifies the letters range.
The c pattern variable acts here like a wildcard to match all non-uppercase symbols. Since this is another commonly occurring structure, Ocaml reserves the _ symbol to match anything:

 let is_uppercase = function
    ’A’ .. ’Z’ -> true
  | _ -> false;;

Pattern matching everywhere
What’s really interesting about pattern matching in Ocaml, is that not only pattern matching can be applied to (almost) any primitive type, but that pattern matching constructions are also allowed in a variety of places:

let    pattern = expression

let    identifier pattern . . . pattern =  expression

fun    pattern -> expression

So, for example, if we define a tuple like this:

let p = 1, "Hello";;

We could access its components using pattern matching:

let x, y = p;;

Another example with lists could be:

let aList = [1; 2; 3];;
let hd :: tl = aList in
  Printf.printf "%d" hd;;

The latter code will print “1″.

What can’t be done…
We can’t do pattern matching with one type in Ocaml, and that’s functions:

  match (fun i -> i + 1) with
     (fun i -> i + 1) -> true;;
      ^^^
Syntax error

What about JavaScript?
Unfortunately JavaScript doesn’t have pattern matching. The closest thing to pattern matching that JavaScript has is, well, the Regexp object. In some sense that can be regarded as string pattern matching.
The funniest thing about that fact, is that “string pattern matching” can be used as “function pattern matching” in JavaScript.

JavaScript functions have a method called toSource, that returns a string of the source code of the function. For example:

(function (formalParam1, formalParam2)
     { return formalParam1; }).toSource();

should return (at least in Firefox) the String:

"(function (formalParam1, formalParam2) {return formalParam1;})"

However, applying this method to the native Function class returns the following:

"function Function() {[native code]}"

You can find function pattern matching examples in JavaScript when browsing the “Class” object implementations for any JS framework. Most frameworks that provide a “Class” object to wrap prototypal inheritance in something more OO have to check all methods for calls on “super” in order to effectively call the superclass method. However, we first have to verify that the browser supports a toSource method that actually returns a string of the entire function body. That check is done with simple function pattern matching:

  /xyz/.test(function(){xyz;});

This code will return true if the “xyz” pattern is found in the anonymous function. If true, then we can “search” for super calls in all body functions in order to replace them with the proper superclass method call. A nice example of simple JavaScript inheritance implementation can be seen in John Resig’s post

Although I know this is still a regexp match, It can also be seen as comparing a function’s body to a given pattern and thus I believe it can be called function pattern matching.

Feeding JSON graph structures to the JIT

Version 1.0.3a of the JIT allows you to load graph structures to the RGraph and Hypertree objects. I chose a different JSON structure for graphs, since JSON tree structures don’t seem conceptually suitable for this task.
Hypertree and RGraph objects have a new method called loadGraphFromJSON(json [,i]) that takes a graph structure (described below) and optionally an index to set a particular node as root for the visualization. Please refer to the documentation for more information.

The graph structure

The JSON graph structure is an array of nodes, each having as properties:

  • id a unique identifier for the node.
  • name a node’s name.
  • data The data property contains a dataset. That is, an array of key-value objects defined by the user. Roughly speaking, this is where you can put some extra information about your node. You’ll be able to access this information at different stages of the computation of the JIT visualizations by using a controller.
  • adjacencies An array of strings each representing a nodes id.

For example,

var json = [
{
	"id": "aUniqueIdentifier",
	"name": "usually a nodes name",
	"data": [
	    {key:"some key",       value: "some value"},
		{key:"some other key", value: "some other value"}
	],
	"adjacencies": ["anotherUniqueIdentifier", "yetAnotherUniqueIdentifier" /* ... */]
} /* ... more nodes here ... */ ];

I did a small example of a K6 rendered with a RGraph. The JSON graph structure used for this example is:

var json= [
    {"id":"node0",
     "name":"node0 name",
     "data":[
        {"key":"some key",
         "value":"some value"},
        {"key":"some other key",
         "value":"some other value"}],
     "adjacencies":["node1","node2","node3","node4","node5"]},
    {"id":"node1",
     "name":"node1 name",
     "data":[
        {"key":"some key",
         "value":"some value"},
        {"key":"some other key",
         "value":"some other value"}],
     "adjacencies":["node0","node2","node3","node4","node5"]},
    {"id":"node2",
     "name":"node2 name",
     "data":[
        {"key":"some key",
         "value":"some value"},
        {"key":"some other key",
         "value":"some other value"}],
     "adjacencies":["node0","node1","node3","node4","node5"]},
    {"id":"node3",
     "name":"node3 name",
     "data":[
        {"key":"some key",
         "value":"some value"},
        {"key":"some other key",
         "value":"some other value"}],
     "adjacencies":["node0","node1","node2","node4","node5"]},
    {"id":"node4",
     "name":"node4 name",
     "data":[
        {"key":"some key",
         "value":"some value"},
        {"key":"some other key",
         "value":"some other value"}],
     "adjacencies":["node0","node1","node2","node3","node5"]},
    {"id":"node5",
     "name":"node5 name",
     "data":[
        {"key":"some key",
         "value":"some value"},
        {"key":"some other key",
         "value":"some other value"}],
     "adjacencies":["node0","node1","node2","node3","node4"]}];

You can post any question at the google group for this project.
Enjoy!

JIT version 1.0.2a

Just dropping by to say I just released version 1.0.2a of the javascript infovis toolkit. You can also download it from the main page.
It fixes some known bugs on the Spacetree and Hyperbolic Tree visualizations.
I’d like to thank OpenCRX and Charles D. Aylward for pointing those errors out.
I also used version 1.4 of Natural Docs to make the docs.
Please let me know if you find more errors.
Bye! :)

RGraph quick tutorial

This tutorial requires you to have read Feeding JSON tree structures to the JIT and on controllers first.

Hi, this is going to be a quick tutorial on how to set the RGraph up and running.

We are going to work with this tree JSON structure:

var json = {"id":"node02",
 "name":"0.2",
 "data":[
    {"key":"key1",
     "value":8},
    {"key":"key2",
     "value":-88}],
 "children":[
    {"id":"node13",
     "name":"1.3",
     "data":[
        {"key":"key1",
         "value":8},
        {"key":"key2",
         "value":74}],
     "children":[
        {"id":"node24",
         "name":"2.4",
         "data":[
            {"key":"key1",
             "value":10},
            {"key":"key2",
             "value":55}],
         "children":[]},
        {"id":"node25",
         "name":"2.5",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":67}],
         "children":[]},
        {"id":"node26",
         "name":"2.6",
         "data":[
            {"key":"key1",
             "value":5},
            {"key":"key2",
             "value":-50}],
         "children":[]},
        {"id":"node27",
         "name":"2.7",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":10}],
         "children":[]},
        {"id":"node28",
         "name":"2.8",
         "data":[
            {"key":"key1",
             "value":2},
            {"key":"key2",
             "value":-69}],
         "children":[]},
        {"id":"node29",
         "name":"2.9",
         "data":[
            {"key":"key1",
             "value":3},
            {"key":"key2",
             "value":98}],
         "children":[]},
        {"id":"node210",
         "name":"2.10",
         "data":[
            {"key":"key1",
             "value":6},
            {"key":"key2",
             "value":12}],
         "children":[]},
        {"id":"node211",
         "name":"2.11",
         "data":[
            {"key":"key1",
             "value":2},
            {"key":"key2",
             "value":-95}],
         "children":[]}]},
    {"id":"node112",
     "name":"1.12",
     "data":[
        {"key":"key1",
         "value":1},
        {"key":"key2",
         "value":96}],
     "children":[
        {"id":"node213",
         "name":"2.13",
         "data":[
            {"key":"key1",
             "value":6},
            {"key":"key2",
             "value":-58}],
         "children":[]},
        {"id":"node214",
         "name":"2.14",
         "data":[
            {"key":"key1",
             "value":9},
            {"key":"key2",
             "value":-42}],
         "children":[]},
        {"id":"node215",
         "name":"2.15",
         "data":[
            {"key":"key1",
             "value":10},
            {"key":"key2",
             "value":92}],
         "children":[]},
        {"id":"node216",
         "name":"2.16",
         "data":[
            {"key":"key1",
             "value":7},
            {"key":"key2",
             "value":-15}],
         "children":[]},
        {"id":"node217",
         "name":"2.17",
         "data":[
            {"key":"key1",
             "value":3},
            {"key":"key2",
             "value":29}],
         "children":[]},
        {"id":"node218",
         "name":"2.18",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":-59}],
         "children":[]},
        {"id":"node219",
         "name":"2.19",
         "data":[
            {"key":"key1",
             "value":3},
            {"key":"key2",
             "value":21}],
         "children":[]},
        {"id":"node220",
         "name":"2.20",
         "data":[
            {"key":"key1",
             "value":2},
            {"key":"key2",
             "value":78}],
         "children":[]}]},
    {"id":"node121",
     "name":"1.21",
     "data":[
        {"key":"key1",
         "value":3},
        {"key":"key2",
         "value":53}],
     "children":[
        {"id":"node222",
         "name":"2.22",
         "data":[
            {"key":"key1",
             "value":5},
            {"key":"key2",
             "value":10}],
         "children":[]},
        {"id":"node223",
         "name":"2.23",
         "data":[
            {"key":"key1",
             "value":10},
            {"key":"key2",
             "value":21}],
         "children":[]},
        {"id":"node224",
         "name":"2.24",
         "data":[
            {"key":"key1",
             "value":6},
            {"key":"key2",
             "value":-32}],
         "children":[]},
        {"id":"node225",
         "name":"2.25",
         "data":[
            {"key":"key1",
             "value":5},
            {"key":"key2",
             "value":-42}],
         "children":[]},
        {"id":"node226",
         "name":"2.26",
         "data":[
            {"key":"key1",
             "value":2},
            {"key":"key2",
             "value":75}],
         "children":[]},
        {"id":"node227",
         "name":"2.27",
         "data":[
            {"key":"key1",
             "value":1},
            {"key":"key2",
             "value":-74}],
         "children":[]},
        {"id":"node228",
         "name":"2.28",
         "data":[
            {"key":"key1",
             "value":2},
            {"key":"key2",
             "value":52}],
         "children":[]},
        {"id":"node229",
         "name":"2.29",
         "data":[
            {"key":"key1",
             "value":10},
            {"key":"key2",
             "value":-49}],
         "children":[]}]},
    {"id":"node130",
     "name":"1.30",
     "data":[
        {"key":"key1",
         "value":9},
        {"key":"key2",
         "value":-29}],
     "children":[
        {"id":"node231",
         "name":"2.31",
         "data":[
            {"key":"key1",
             "value":6},
            {"key":"key2",
             "value":-23}],
         "children":[]},
        {"id":"node232",
         "name":"2.32",
         "data":[
            {"key":"key1",
             "value":10},
            {"key":"key2",
             "value":19}],
         "children":[]},
        {"id":"node233",
         "name":"2.33",
         "data":[
            {"key":"key1",
             "value":1},
            {"key":"key2",
             "value":92}],
         "children":[]}]},
    {"id":"node134",
     "name":"1.34",
     "data":[
        {"key":"key1",
         "value":9},
        {"key":"key2",
         "value":71}],
     "children":[
        {"id":"node235",
         "name":"2.35",
         "data":[
            {"key":"key1",
             "value":5},
            {"key":"key2",
             "value":-65}],
         "children":[]}]},
    {"id":"node136",
     "name":"1.36",
     "data":[
        {"key":"key1",
         "value":3},
        {"key":"key2",
         "value":-11}],
     "children":[
        {"id":"node237",
         "name":"2.37",
         "data":[
            {"key":"key1",
             "value":6},
            {"key":"key2",
             "value":-85}],
         "children":[]},
        {"id":"node238",
         "name":"2.38",
         "data":[
            {"key":"key1",
             "value":3},
            {"key":"key2",
             "value":-13}],
         "children":[]},
        {"id":"node239",
         "name":"2.39",
         "data":[
            {"key":"key1",
             "value":1},
            {"key":"key2",
             "value":80}],
         "children":[]},
        {"id":"node240",
         "name":"2.40",
         "data":[
            {"key":"key1",
             "value":10},
            {"key":"key2",
             "value":-69}],
         "children":[]}]},
    {"id":"node141",
     "name":"1.41",
     "data":[
        {"key":"key1",
         "value":10},
        {"key":"key2",
         "value":-4}],
     "children":[
        {"id":"node242",
         "name":"2.42",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":-27}],
         "children":[]},
        {"id":"node243",
         "name":"2.43",
         "data":[
            {"key":"key1",
             "value":9},
            {"key":"key2",
             "value":-44}],
         "children":[]},
        {"id":"node244",
         "name":"2.44",
         "data":[
            {"key":"key1",
             "value":9},
            {"key":"key2",
             "value":24}],
         "children":[]},
        {"id":"node245",
         "name":"2.45",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":-66}],
         "children":[]}]}]};

Put this HTML in your page:

<html>
	<head>

	<link type="text/css" rel="stylesheet" href="/static/css/example-rgraph.css" />

	<!--[if IE]>
		<script type="text/javascript" src="/static/js/excanvas.js"></script>
	<![endif]-->

	<script type="text/javascript" src="/static/js/rgraph/RGraph.js" ></script>
	<script type="text/javascript" src="/static/js/example/example-rgraph.js" ></script>

	</head>
	<body onload="init();">

         <canvas id="infovis" width="900" height="500"></canvas>
         <div id="label_container"></div>

	</body>
</html>

Note: You’ll probably have to change the paths to the css and javascript files.

Now, create a rgraph-example.css and put this code in it:

html,body {
	width:100%;
	height:100%;
	overflow:hidden;
	margin:0;padding:0;
	background-color:#333;
	text-align:center;
}

#infovis {
	width:900px;
	height:500px;
	background-color:#222;
}

.node {
	color: white;
	background-color:transparent;
	cursor:pointer;
	font-weight:bold;
	opacity:0.9;
	border:1px solid red;
}

.node:hover {
	cursor:pointer;
	color: #222;
	background-color:white;
	font-weight:bold;
	opacity:1;
}

Finally, create an example-rgraph.js file and put this code in it:
Note: I’ll be using the Mootools library to do this tutorial, just because I don’t want to spend time writing low level code that would make the code uglier. You can use any library you want (or none at all) though. You are provided with a Mootools library and excanvas library in the extras folder of the library. You can also download the mootools library here.

function init() {
	//Set node interpolation to linear (can also be 'polar')
	Config.interpolation = "linear";
	//Set distance for concentric circles
	Config.levelDistance = 100;
	//Set number of concentric circles, default's to six.
	Config.drawConcentricCircles = 4;

	var json= //data defined previously

	var canvas= new Canvas('infovis', '#ccddee', '#772277');

	var rgraph= new RGraph(canvas,  {
	  //Add a controller to make the tree move on click.
		onCreateLabel: function(domElement, node) {
			var d = $(domElement);
			d.addEvents({
				'click': function() {
					rgraph.onClick(d.id);
				}
			});
		}
	 });

	  //load tree from tree data.
	  rgraph.loadTreeFromJSON(json);
	  //compute positions
	  rgraph.compute();
	  //make first plot
	  rgraph.plot();
}

You should see a RGraph up and running. Click on the labels and the tree should move.

Some notes:

  • It’s mandatory to put the width and height properties on the canvas html tag.
    You could set those properties dynamically, of course, but what I mean is that setting only width and height style properties (as with CSS) isn’t enough.
  • You could change the label container id by setting the Config.labelContainer property to whatever id you like. Be sure to set that property before making a Canvas instance.
  • The Canvas constructor takes 3 parameters: the canvas id, the fillStyle property and the strokeStyle property. If you don’t know what those properties are, take a look at this section from the canvas tutorial.
  • You can take off the concentric circles by setting Config.drawConcentricCircles to false. Just be sure you do that before making a canvas or RGraph instance.

Customizing the Graph

Let’s add some labels!

First, strip off the border: 1px solid red; line from the .node class in your CSS file.
It should look like this:

.node {
	color: white;
	background-color:transparent;
	cursor:pointer;
	font-weight:bold;
	opacity:0.9;
}

Now we are going to add a javascript controller in order to put the name of the nodes into the labels. Since we only need to do this once, we’ll use the onCreateLabel method. If you don’t know what I’m talking about you should probably read the on controllers post first.

So the JavaScript file should look like this now:

function init() {
	//Set node interpolation to linear (can also be 'polar')
	Config.interpolation = "linear";
	//Set distance for concentric circles
	Config.levelDistance = 100;
	//Set number of concentric circles, default's to six.
	Config.drawConcentricCircles = 4;

	var json= //json data defined previously

	var canvas= new Canvas('infovis', '#ccddee', '#772277');

	var rgraph= new RGraph(canvas,  {
	  //Add a controller to assign a name to the created label.
		onCreateLabel: function(domElement, node) {
			var d = $(domElement);
			d.set('html', node.name).addEvents({
				'click': function() {
					rgraph.onClick(d.id);
				}
			});
		}
	 });

	  //load tree from tree data.
	  rgraph.loadTreeFromJSON(json);
	  //compute positions
	  rgraph.compute();
	  //make first plot
	  rgraph.plot();
}

You should see some labels now.
The thing is that… well, they are not centered. So we’ll just add an onPlaceLabel method to the controller in order to do that, since the onPlaceLabel method is called after labels have been placed.

So the js code should now look like:

function init() {
	//Set node interpolation to linear (can also be 'polar')
	Config.interpolation = "linear";
	//Set distance for concentric circles
	Config.levelDistance = 100;
	//Set number of concentric circles, default's to six.
	Config.drawConcentricCircles = 4;

	var json= //json data defined previously

	var canvas= new Canvas('infovis', '#ccddee', '#772277');

	var rgraph= new RGraph(canvas,  {
	  //Add a controller to assign a name to the label.
		onCreateLabel: function(domElement, node) {
			var d = $(domElement);
			d.set('html', node.name).addEvents({
				'click': function() {
					rgraph.onClick(d.id);
				}
			});
		},

	//Take off previous width and height styles and
	//add half of the *actual* label width to the left position
	// That will center your label (do the math man).
		onPlaceLabel: function(domElement, node) {
			domElement.innerHTML = '';
			domElement.innerHTML = node.name;
			var left = parseInt(domElement.style.left);
			domElement.style.width = '';
			domElement.style.height = '';
			var w = domElement.offsetWidth;
			domElement.style.left = (left - w /2) + 'px';
		}
	});

	  //load tree from tree data.
	  rgraph.loadTreeFromJSON(json);
	  //compute positions
	  rgraph.compute();
	  //make first plot
	  rgraph.plot();
}

You should see some centered labels now!

Labels already have the onclick event handler to move the graph. You set that onCreateLabel.

Remember there are lots of other controller methods!

Remember also that you can change the animation time and the frames per second in the animation with Config.animationTime and Config.fps.
Hope it was helpful.

ST quick tutorial

This tutorial requires you to have read Feeding JSON tree structures to the JIT and on controllers first.

Hi, this is going to be a quick tutorial on how to set the ST up and running.

We are going to work with this tree JSON structure:

var json = {"id":"node02",
 "name":"0.2",
 "data":[
    {"key":"key1",
     "value":2},
    {"key":"key2",
     "value":-86}],
 "children":[
    {"id":"node13",
     "name":"1.3",
     "data":[
        {"key":"key1",
         "value":7},
        {"key":"key2",
         "value":73}],
     "children":[
        {"id":"node24",
         "name":"2.4",
         "data":[
            {"key":"key1",
             "value":2},
            {"key":"key2",
             "value":-49}],
         "children":[
            {"id":"node35",
             "name":"3.5",
             "data":[
                {"key":"key1",
                 "value":8},
                {"key":"key2",
                 "value":-10}],
             "children":[
                {"id":"node46",
                 "name":"4.6",
                 "data":[
                    {"key":"key1",
                     "value":10},
                    {"key":"key2",
                     "value":74}],
                 "children":[]},
                {"id":"node47",
                 "name":"4.7",
                 "data":[
                    {"key":"key1",
                     "value":3},
                    {"key":"key2",
                     "value":-37}],
                 "children":[]}]},
            {"id":"node38",
             "name":"3.8",
             "data":[
                {"key":"key1",
                 "value":8},
                {"key":"key2",
                 "value":88}],
             "children":[
                {"id":"node49",
                 "name":"4.9",
                 "data":[
                    {"key":"key1",
                     "value":2},
                    {"key":"key2",
                     "value":-67}],
                 "children":[]},
                {"id":"node410",
                 "name":"4.10",
                 "data":[
                    {"key":"key1",
                     "value":10},
                    {"key":"key2",
                     "value":38}],
                 "children":[]},
                {"id":"node411",
                 "name":"4.11",
                 "data":[
                    {"key":"key1",
                     "value":5},
                    {"key":"key2",
                     "value":-77}],
                 "children":[]}]}]},
        {"id":"node212",
         "name":"2.12",
         "data":[
            {"key":"key1",
             "value":3},
            {"key":"key2",
             "value":-99}],
         "children":[
            {"id":"node313",
             "name":"3.13",
             "data":[
                {"key":"key1",
                 "value":9},
                {"key":"key2",
                 "value":48}],
             "children":[
                {"id":"node414",
                 "name":"4.14",
                 "data":[
                    {"key":"key1",
                     "value":8},
                    {"key":"key2",
                     "value":-19}],
                 "children":[]},
                {"id":"node415",
                 "name":"4.15",
                 "data":[
                    {"key":"key1",
                     "value":10},
                    {"key":"key2",
                     "value":61}],
                 "children":[]},
                {"id":"node416",
                 "name":"4.16",
                 "data":[
                    {"key":"key1",
                     "value":2},
                    {"key":"key2",
                     "value":83}],
                 "children":[]}]},
            {"id":"node317",
             "name":"3.17",
             "data":[
                {"key":"key1",
                 "value":4},
                {"key":"key2",
                 "value":-18}],
             "children":[
                {"id":"node418",
                 "name":"4.18",
                 "data":[
                    {"key":"key1",
                     "value":9},
                    {"key":"key2",
                     "value":-58}],
                 "children":[]},
                {"id":"node419",
                 "name":"4.19",
                 "data":[
                    {"key":"key1",
                     "value":6},
                    {"key":"key2",
                     "value":-35}],
                 "children":[]},
                {"id":"node420",
                 "name":"4.20",
                 "data":[
                    {"key":"key1",
                     "value":1},
                    {"key":"key2",
                     "value":84}],
                 "children":[]},
                {"id":"node421",
                 "name":"4.21",
                 "data":[
                    {"key":"key1",
                     "value":1},
                    {"key":"key2",
                     "value":19}],
                 "children":[]}]}]},
        {"id":"node222",
         "name":"2.22",
         "data":[
            {"key":"key1",
             "value":7},
            {"key":"key2",
             "value":-3}],
         "children":[
            {"id":"node323",
             "name":"3.23",
             "data":[
                {"key":"key1",
                 "value":9},
                {"key":"key2",
                 "value":-53}],
             "children":[
                {"id":"node424",
                 "name":"4.24",
                 "data":[
                    {"key":"key1",
                     "value":4},
                    {"key":"key2",
                     "value":63}],
                 "children":[]},
                {"id":"node425",
                 "name":"4.25",
                 "data":[
                    {"key":"key1",
                     "value":8},
                    {"key":"key2",
                     "value":38}],
                 "children":[]},
                {"id":"node426",
                 "name":"4.26",
                 "data":[
                    {"key":"key1",
                     "value":5},
                    {"key":"key2",
                     "value":84}],
                 "children":[]}]}]}]},
    {"id":"node127",
     "name":"1.27",
     "data":[
        {"key":"key1",
         "value":4},
        {"key":"key2",
         "value":34}],
     "children":[
        {"id":"node228",
         "name":"2.28",
         "data":[
            {"key":"key1",
             "value":6},
            {"key":"key2",
             "value":-8}],
         "children":[
            {"id":"node329",
             "name":"3.29",
             "data":[
                {"key":"key1",
                 "value":4},
                {"key":"key2",
                 "value":-48}],
             "children":[
                {"id":"node430",
                 "name":"4.30",
                 "data":[
                    {"key":"key1",
                     "value":3},
                    {"key":"key2",
                     "value":-64}],
                 "children":[]},
                {"id":"node431",
                 "name":"4.31",
                 "data":[
                    {"key":"key1",
                     "value":6},
                    {"key":"key2",
                     "value":-79}],
                 "children":[]},
                {"id":"node432",
                 "name":"4.32",
                 "data":[
                    {"key":"key1",
                     "value":2},
                    {"key":"key2",
                     "value":18}],
                 "children":[]}]},
            {"id":"node333",
             "name":"3.33",
             "data":[
                {"key":"key1",
                 "value":1},
                {"key":"key2",
                 "value":96}],
             "children":[
                {"id":"node434",
                 "name":"4.34",
                 "data":[
                    {"key":"key1",
                     "value":4},
                    {"key":"key2",
                     "value":32}],
                 "children":[]},
                {"id":"node435",
                 "name":"4.35",
                 "data":[
                    {"key":"key1",
                     "value":3},
                    {"key":"key2",
                     "value":-52}],
                 "children":[]}]},
            {"id":"node336",
             "name":"3.36",
             "data":[
                {"key":"key1",
                 "value":6},
                {"key":"key2",
                 "value":81}],
             "children":[
                {"id":"node437",
                 "name":"4.37",
                 "data":[
                    {"key":"key1",
                     "value":4},
                    {"key":"key2",
                     "value":-51}],
                 "children":[]},
                {"id":"node438",
                 "name":"4.38",
                 "data":[
                    {"key":"key1",
                     "value":9},
                    {"key":"key2",
                     "value":14}],
                 "children":[]},
                {"id":"node439",
                 "name":"4.39",
                 "data":[
                    {"key":"key1",
                     "value":8},
                    {"key":"key2",
                     "value":18}],
                 "children":[]},
                {"id":"node440",
                 "name":"4.40",
                 "data":[
                    {"key":"key1",
                     "value":7},
                    {"key":"key2",
                     "value":-3}],
                 "children":[]}]},
            {"id":"node341",
             "name":"3.41",
             "data":[
                {"key":"key1",
                 "value":9},
                {"key":"key2",
                 "value":-56}],
             "children":[
                {"id":"node442",
                 "name":"4.42",
                 "data":[
                    {"key":"key1",
                     "value":10},
                    {"key":"key2",
                     "value":56}],
                 "children":[]},
                {"id":"node443",
                 "name":"4.43",
                 "data":[
                    {"key":"key1",
                     "value":6},
                    {"key":"key2",
                     "value":-90}],
                 "children":[]},
                {"id":"node444",
                 "name":"4.44",
                 "data":[
                    {"key":"key1",
                     "value":10},
                    {"key":"key2",
                     "value":-64}],
                 "children":[]},
                {"id":"node445",
                 "name":"4.45",
                 "data":[
                    {"key":"key1",
                     "value":7},
                    {"key":"key2",
                     "value":-82}],
                 "children":[]}]}]},
        {"id":"node246",
         "name":"2.46",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":-16}],
         "children":[
            {"id":"node347",
             "name":"3.47",
             "data":[
                {"key":"key1",
                 "value":8},
                {"key":"key2",
                 "value":-41}],
             "children":[
                {"id":"node448",
                 "name":"4.48",
                 "data":[
                    {"key":"key1",
                     "value":7},
                    {"key":"key2",
                     "value":17}],
                 "children":[]},
                {"id":"node449",
                 "name":"4.49",
                 "data":[
                    {"key":"key1",
                     "value":7},
                    {"key":"key2",
                     "value":24}],
                 "children":[]},
                {"id":"node450",
                 "name":"4.50",
                 "data":[
                    {"key":"key1",
                     "value":6},
                    {"key":"key2",
                     "value":-11}],
                 "children":[]},
                {"id":"node451",
                 "name":"4.51",
                 "data":[
                    {"key":"key1",
                     "value":1},
                    {"key":"key2",
                     "value":-77}],
                 "children":[]}]},
            {"id":"node352",
             "name":"3.52",
             "data":[
                {"key":"key1",
                 "value":8},
                {"key":"key2",
                 "value":20}],
             "children":[
                {"id":"node453",
                 "name":"4.53",
                 "data":[
                    {"key":"key1",
                     "value":5},
                    {"key":"key2",
                     "value":20}],
                 "children":[]},
                {"id":"node454",
                 "name":"4.54",
                 "data":[
                    {"key":"key1",
                     "value":6},
                    {"key":"key2",
                     "value":77}],
                 "children":[]},
                {"id":"node455",
                 "name":"4.55",
                 "data":[
                    {"key":"key1",
                     "value":2},
                    {"key":"key2",
                     "value":52}],
                 "children":[]},
                {"id":"node456",
                 "name":"4.56",
                 "data":[
                    {"key":"key1",
                     "value":3},
                    {"key":"key2",
                     "value":41}],
                 "children":[]}]},
            {"id":"node357",
             "name":"3.57",
             "data":[
                {"key":"key1",
                 "value":2},
                {"key":"key2",
                 "value":-17}],
             "children":[
                {"id":"node458",
                 "name":"4.58",
                 "data":[
                    {"key":"key1",
                     "value":2},
                    {"key":"key2",
                     "value":4}],
                 "children":[]}]},
            {"id":"node359",
             "name":"3.59",
             "data":[
                {"key":"key1",
                 "value":10},
                {"key":"key2",
                 "value":-79}],
             "children":[
                {"id":"node460",
                 "name":"4.60",
                 "data":[
                    {"key":"key1",
                     "value":10},
                    {"key":"key2",
                     "value":-55}],
                 "children":[]},
                {"id":"node461",
                 "name":"4.61",
                 "data":[
                    {"key":"key1",
                     "value":4},
                    {"key":"key2",
                     "value":92}],
                 "children":[]},
                {"id":"node462",
                 "name":"4.62",
                 "data":[
                    {"key":"key1",
                     "value":10},
                    {"key":"key2",
                     "value":-40}],
                 "children":[]},
                {"id":"node463",
                 "name":"4.63",
                 "data":[
                    {"key":"key1",
                     "value":4},
                    {"key":"key2",
                     "value":57}],
                 "children":[]}]}]},
        {"id":"node264",
         "name":"2.64",
         "data":[
            {"key":"key1",
             "value":3},
            {"key":"key2",
             "value":91}],
         "children":[
            {"id":"node365",
             "name":"3.65",
             "data":[
                {"key":"key1",
                 "value":5},
                {"key":"key2",
                 "value":-51}],
             "children":[
                {"id":"node466",
                 "name":"4.66",
                 "data":[
                    {"key":"key1",
                     "value":6},
                    {"key":"key2",
                     "value":50}],
                 "children":[]},
                {"id":"node467",
                 "name":"4.67",
                 "data":[
                    {"key":"key1",
                     "value":2},
                    {"key":"key2",
                     "value":16}],
                 "children":[]}]},
            {"id":"node368",
             "name":"3.68",
             "data":[
                {"key":"key1",
                 "value":9},
                {"key":"key2",
                 "value":50}],
             "children":[
                {"id":"node469",
                 "name":"4.69",
                 "data":[
                    {"key":"key1",
                     "value":10},
                    {"key":"key2",
                     "value":-22}],
                 "children":[]},
                {"id":"node470",
                 "name":"4.70",
                 "data":[
                    {"key":"key1",
                     "value":5},
                    {"key":"key2",
                     "value":-71}],
                 "children":[]}]}]},
        {"id":"node271",
         "name":"2.71",
         "data":[
            {"key":"key1",
             "value":3},
            {"key":"key2",
             "value":-40}],
         "children":[
            {"id":"node372",
             "name":"3.72",
             "data":[
                {"key":"key1",
                 "value":7},
                {"key":"key2",
                 "value":-7}],
             "children":[
                {"id":"node473",
                 "name":"4.73",
                 "data":[
                    {"key":"key1",
                     "value":8},
                    {"key":"key2",
                     "value":-35}],
                 "children":[]},
                {"id":"node474",
                 "name":"4.74",
                 "data":[
                    {"key":"key1",
                     "value":8},
                    {"key":"key2",
                     "value":92}],
                 "children":[]},
                {"id":"node475",
                 "name":"4.75",
                 "data":[
                    {"key":"key1",
                     "value":2},
                    {"key":"key2",
                     "value":64}],
                 "children":[]},
                {"id":"node476",
                 "name":"4.76",
                 "data":[
                    {"key":"key1",
                     "value":7},
                    {"key":"key2",
                     "value":-95}],
                 "children":[]}]},
            {"id":"node377",
             "name":"3.77",
             "data":[
                {"key":"key1",
                 "value":3},
                {"key":"key2",
                 "value":-46}],
             "children":[
                {"id":"node478",
                 "name":"4.78",
                 "data":[
                    {"key":"key1",
                     "value":6},
                    {"key":"key2",
                     "value":56}],
                 "children":[]},
                {"id":"node479",
                 "name":"4.79",
                 "data":[
                    {"key":"key1",
                     "value":2},
                    {"key":"key2",
                     "value":-40}],
                 "children":[]},
                {"id":"node480",
                 "name":"4.80",
                 "data":[
                    {"key":"key1",
                     "value":2},
                    {"key":"key2",
                     "value":-88}],
                 "children":[]}]},
            {"id":"node381",
             "name":"3.81",
             "data":[
                {"key":"key1",
                 "value":6},
                {"key":"key2",
                 "value":-81}],
             "children":[
                {"id":"node482",
                 "name":"4.82",
                 "data":[
                    {"key":"key1",
                     "value":7},
                    {"key":"key2",
                     "value":-14}],
                 "children":[]}]},
            {"id":"node383",
             "name":"3.83",
             "data":[
                {"key":"key1",
                 "value":4},
                {"key":"key2",
                 "value":32}],
             "children":[
                {"id":"node484",
                 "name":"4.84",
                 "data":[
                    {"key":"key1",
                     "value":6},
                    {"key":"key2",
                     "value":36}],
                 "children":[]},
                {"id":"node485",
                 "name":"4.85",
                 "data":[
                    {"key":"key1",
                     "value":9},
                    {"key":"key2",
                     "value":96}],
                 "children":[]},
                {"id":"node486",
                 "name":"4.86",
                 "data":[
                    {"key":"key1",
                     "value":10},
                    {"key":"key2",
                     "value":13}],
                 "children":[]},
                {"id":"node487",
                 "name":"4.87",
                 "data":[
                    {"key":"key1",
                     "value":4},
                    {"key":"key2",
                     "value":96}],
                 "children":[]}]}]}]}]};

Put this HTML in your page:

<html>
	<head>

	<link type="text/css" rel="stylesheet" href="/static/css/example-spacetree.css" />

	<script type="text/javascript" src="/static/js/spacetree/Spacetree.js" ></script>
	<script type="text/javascript" src="/static/js/example/example-spacetree.js" ></script>

	</head>
	<body onload="init();">

<canvas id="infovis" width="900" height="500"></canvas>
<div id="label_container" />

	</body>
</html>

Note: You’ll probably have to change the paths to the css and javascript files.

Now, create a spacetree-example.css and put this code in it:

html, body {
	width:100%;
	height:100%;
	background-color:#444;
	text-align:center;
	overflow:hidden;
	font-size:9px;
	font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
	margin:0;padding:0;
}

#infovis {
	background-color:#222;
	position:relative;
	width:900px;
	height:500px;
}

a, a:link, a:visited {
	color:#343439;
}

.node {
	background-color:transparent;
	font-weight:bold;
	overflow:hidden;
	text-decoration:none;
	position:absolute;
	text-align:center;
	padding:4px 1px 1px 1px;
}

.node:hover {
	color:#393434;
}

.hidden{
	display:none;
}

Note: the margin:0;padding:0; on html,body is pretty important to place well the ST labels.

Finally, create an example-spacetree.js file and put this code in it:

function init() {
	  var json= //data defined previously
	  //Create a new canvas instance.
	  var canvas= new Canvas('infovis');
	  //Create a new ST instance
	  st= new ST(canvas);
	  //load json data
	  st.loadFromJSON(json);
	  //compute node positions and layout
	  st.compute();
	  //optional: make a translation of the tree
	  Tree.Geometry.translate(st.tree, new Complex(-200, 0), "startPos");
	  //Emulate a click on the root node.
	  st.onClick(st.tree.id);
}

You should see a spacetree up and running (it may take a few seconds to load).

Some notes:

  • It’s mandatory to put the width and height properties on the canvas html tag.
    You could set those properties dynamically, of course, but what I mean is that setting only width and height style properties (as with CSS) isn’t enough.
  • You could change the label container id by setting the Config.labelContainer property to whatever id you like. Be sure to set that property before making a Canvas instance.
  • The Canvas constructor takes 1 parameter: the canvas id. To set the fillStyle and strokeStyle properties for nodes which are in path to root or nodes which aren’t you should refer to Config.Node.(strokeStyle|fillStyle|strokeStyleInPath|fillStyleInPath).
  • You can define how many levels to expand by setting Config.levelsToShow. However, if the expanded subtree height is greater than the canvas height, the spacetree might not show all levels. Unfortunately, this doesn’t happen when the width of the subtree expanded is greater than the canvas width (divided by two).

Customizing the Spacetree

The default layout for the spacetree is “left”. That means that the root node always lies at the left of the visualization. You can set the tree layout to “top” though.
So, put a checkbox in your HTML. Your HTML should look like this:

<html>
	<head>

	<link type="text/css" rel="stylesheet" href="/static/css/example-spacetree.css" />

	<script type="text/javascript" src="/static/js/spacetree/Spacetree.js" ></script>
	<script type="text/javascript" src="/static/js/example/example-spacetree.js" ></script>

	</head>
	<body onload="init();">

<input type="checkbox" id="switch"/>
<canvas id="infovis" width="900" height="500"></canvas>
<div id="label_container" />

	</body>
</html>

Note: You can add some style to the checkbox to put it somewhere else.

Now change the JS file to put a handler on the onchange event. It should look like this:

function init() {
	  var json= //data defined previously
	  //Create a new canvas instance.
	  var canvas= new Canvas('infovis');
	  //Create a new ST instance
	  st= new ST(canvas);
	  //load json data
	  st.loadFromJSON(json);
	  //compute node positions and layout
	  st.compute();
	  //optional: make a translation of the tree
	  Tree.Geometry.translate(st.tree, new Complex(-200, 0), "startPos");
	  //Emulate a click on the root node.
	  st.onClick(st.tree.id);

	//Add input handler to switch spacetree orientation.
  var checkbox = document.getElementById('switch');
  	checkbox.onchange = function () {
    	checkbox.disabled = true;
    	st.switchPosition({onComplete: function() {
        checkbox.disabled = false;
    }});
  };
}

Now if you click on the checkbox you should be able to switch the Spacetree orientation. Hows that!

Remember that you can also add controlers to the spacetree!. Take a look at the on controllers section and some examples with the hypertree.

Hope it was helpful!

Treemap quick tutorial

This tutorial requires you to have read Feeding JSON tree structures to the JIT and on controllers first.

Hi, this is going to be a quick tutorial on how to set the treemap up and running.

Note: You could change all calls to TM.Squarified to TM.SliceAndDice and it should also work.

We are going to work with this tree JSON structure:

var json = {"id":"node02",
 "name":"0.2",
 "data":[
    {"key":"key1",
     "value":195},
    {"key":"key2",
     "value":5}],
 "children":[
    {"id":"node13",
     "name":"1.3",
     "data":[
        {"key":"key1",
         "value":23},
        {"key":"key2",
         "value":8}],
     "children":[
        {"id":"node24",
         "name":"2.4",
         "data":[
            {"key":"key1",
             "value":6},
            {"key":"key2",
             "value":-75}],
         "children":[]},
        {"id":"node25",
         "name":"2.5",
         "data":[
            {"key":"key1",
             "value":9},
            {"key":"key2",
             "value":-48}],
         "children":[]},
        {"id":"node26",
         "name":"2.6",
         "data":[
            {"key":"key1",
             "value":1},
            {"key":"key2",
             "value":-1}],
         "children":[]},
        {"id":"node27",
         "name":"2.7",
         "data":[
            {"key":"key1",
             "value":7},
            {"key":"key2",
             "value":25}],
         "children":[]}]},
    {"id":"node18",
     "name":"1.8",
     "data":[
        {"key":"key1",
         "value":17},
        {"key":"key2",
         "value":28}],
     "children":[
        {"id":"node29",
         "name":"2.9",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":-28}],
         "children":[]},
        {"id":"node210",
         "name":"2.10",
         "data":[
            {"key":"key1",
             "value":9},
            {"key":"key2",
             "value":-83}],
         "children":[]}]},
    {"id":"node111",
     "name":"1.11",
     "data":[
        {"key":"key1",
         "value":25},
        {"key":"key2",
         "value":-82}],
     "children":[
        {"id":"node212",
         "name":"2.12",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":-27}],
         "children":[]},
        {"id":"node213",
         "name":"2.13",
         "data":[
            {"key":"key1",
             "value":3},
            {"key":"key2",
             "value":-80}],
         "children":[]},
        {"id":"node214",
         "name":"2.14",
         "data":[
            {"key":"key1",
             "value":7},
            {"key":"key2",
             "value":-73}],
         "children":[]},
        {"id":"node215",
         "name":"2.15",
         "data":[
            {"key":"key1",
             "value":7},
            {"key":"key2",
             "value":26}],
         "children":[]}]},
    {"id":"node116",
     "name":"1.16",
     "data":[
        {"key":"key1",
         "value":17},
        {"key":"key2",
         "value":91}],
     "children":[
        {"id":"node217",
         "name":"2.17",
         "data":[
            {"key":"key1",
             "value":7},
            {"key":"key2",
             "value":48}],
         "children":[]},
        {"id":"node218",
         "name":"2.18",
         "data":[
            {"key":"key1",
             "value":10},
            {"key":"key2",
             "value":-86}],
         "children":[]}]},
    {"id":"node119",
     "name":"1.19",
     "data":[
        {"key":"key1",
         "value":52},
        {"key":"key2",
         "value":-77}],
     "children":[
        {"id":"node220",
         "name":"2.20",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":64}],
         "children":[]},
        {"id":"node221",
         "name":"2.21",
         "data":[
            {"key":"key1",
             "value":5},
            {"key":"key2",
             "value":84}],
         "children":[]},
        {"id":"node222",
         "name":"2.22",
         "data":[
            {"key":"key1",
             "value":6},
            {"key":"key2",
             "value":81}],
         "children":[]},
        {"id":"node223",
         "name":"2.23",
         "data":[
            {"key":"key1",
             "value":1},
            {"key":"key2",
             "value":25}],
         "children":[]},
        {"id":"node224",
         "name":"2.24",
         "data":[
            {"key":"key1",
             "value":4},
            {"key":"key2",
             "value":18}],
         "children":[]},
        {"id":"node225",
         "name":"2.25",
         "data":[
            {"key":"key1",
             "value":10},
            {"key":"key2",
             "value":37}],
         "children":[]},
        {"id":"node226",
         "name":"2.26",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":83}],
         "children":[]},
        {"id":"node227",
         "name":"2.27",
         "data":[
            {"key":"key1",
             "value":10},
            {"key":"key2",
             "value":-62}],
         "children":[]}]},
    {"id":"node128",
     "name":"1.28",
     "data":[
        {"key":"key1",
         "value":37},
        {"key":"key2",
         "value":-40}],
     "children":[
        {"id":"node229",
         "name":"2.29",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":-67}],
         "children":[]},
        {"id":"node230",
         "name":"2.30",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":46}],
         "children":[]},
        {"id":"node231",
         "name":"2.31",
         "data":[
            {"key":"key1",
             "value":4},
            {"key":"key2",
             "value":-99}],
         "children":[]},
        {"id":"node232",
         "name":"2.32",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":-38}],
         "children":[]},
        {"id":"node233",
         "name":"2.33",
         "data":[
            {"key":"key1",
             "value":1},
            {"key":"key2",
             "value":-3}],
         "children":[]},
        {"id":"node234",
         "name":"2.34",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":82}],
         "children":[]}]},
    {"id":"node135",
     "name":"1.35",
     "data":[
        {"key":"key1",
         "value":24},
        {"key":"key2",
         "value":63}],
     "children":[
        {"id":"node236",
         "name":"2.36",
         "data":[
            {"key":"key1",
             "value":10},
            {"key":"key2",
             "value":8}],
         "children":[]},
        {"id":"node237",
         "name":"2.37",
         "data":[
            {"key":"key1",
             "value":8},
            {"key":"key2",
             "value":63}],
         "children":[]},
        {"id":"node238",
         "name":"2.38",
         "data":[
            {"key":"key1",
             "value":6},
            {"key":"key2",
             "value":46}],
         "children":[]}]}]};

Note: remember that the Treemap takes the first dataset object value to calculate the rectangles dimensions. That means that the values you setted on the first dataset object for all nodes must be coherent. Coherent means that, for example, if node A has nodes B and C as children, B having 3 as its first dataset object value and C having 2 as its first dataset value, then A must have 5 as its first dataset object value.

Put this HTML in your page:

<html>
	<head>

	<link type="text/css" rel="stylesheet" href="/static/css/example-treemap.css" />

	<script type="text/javascript" src="/static/js/mootools-1.2.js"></script>
	<script type="text/javascript" src="/static/js/treemap/Treemap.js" ></script>
	<script type="text/javascript" src="/static/js/example/example-treemap.js" ></script>

	</head>

	<body onload="init();">

<div id="infovis" />

	</body>
</html>

Note: You’ll probably have to change the paths to the css and javascript files.
Note2: This is the only visualization that requires Mootools 1.2+ to run. I use version 1.2 which comes packaged with the library (in the extras folder). You can also download it from here.

Now, create a treemap-example.css and put this code in it:

html, body {
	width:100%;
	height:100%;
	background-color:#222;
	text-align:center;
	overflow:hidden;
	font-size:10px;
	font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
}

#infovis {
	position:relative;
	width:900px;
	height:500px;
	margin:auto;
	background-color:#1D1D20;
}

#infovis div {
	position:absolute;
	overflow:hidden;
}

#infovis .content {
	background-color:#333;
	border:0px solid #111;
}

#infovis .head {
	height:12px;
	color:white;
	background-color:#444;
}

#infovis .head.in-path {
	background-color:#655;
}

#infovis .body {
	background-color:black;
}

#infovis .leaf {
	color:white;
	background-color:#111;
	display:table-cell;
	vertical-align:middle;
}

#infovis .over-leaf {
	border:1px solid #9FD4FF;
}

#infovis .over-content {
	background-color: #9FD4FF;
}

#infovis .over-head { /* ...boy i'm funny */
	background-color:#A4D9FF;
	color:black;
}

/*TOOLTIPS*/
.tool-tip {
	color: #fff;
	width: 139px;
	z-index: 13000;
	background-color: black;
}

.tip-title {
	font-weight: bold;
	font-size: 11px;
	margin: 0;
	color: #9FD4FF;
	padding: 8px 8px 4px;
	background-color: black;
}

.tip-text {
	font-size: 11px;
	padding: 4px 8px 8px;
	background-color: black;
}

Note: I won’t explain all CSS classes, they are pretty much self explainable. However, you must put a position:relative; in the infovis container (the visualization container), just as specified on the CSS stylesheet.

Finally, create an example-treemap.js file and put this code in it:

function init() {
	var json = //json data specified above...
	var tm = new TM.Squarified();
	tm.loadFromJSON(json);

}

You should see a treemap up and running.

Some notes:

  • It’s mandatory to put the width and height style properties on the main div container, just as specified on the CSS stylesheet.
  • You could change the main container id by setting the Config.rootId property to whatever id you like. Be sure to set that property before making a TM instance.

Customizing the Treemap

Let’s add some colors!
In order to add colors you must know three things:

  • Colors are calculated by taking the second dataset object value. You must also know the range of this value. In this example the second value ranges between [-100, 100]. You can change these values by setting the Config.Color.minValue and Config.Color.maxValue parameters. Remember to do this before instanciating the TM.
  • You can also choose the color range for your visualization, this is done by setting the Config.Color.minColorValue and Config.Color.maxColorValue parameters. These properties take an array of 3 integers each describing an RGB value. Remember to do this before instanciating the TM.
  • Finally, to enable treemap coloring you must set the property Config.Color.allow to true.

So the init javascript function would now look like:

function init() {
	var json = //..json data
	//Allow coloring
	Config.Color.allow = true;
//Set min value and max value for the second *dataset* object values.
//Default's to -100 and 100.
	Config.Color.minValue = -100;
	Config.Color.maxValue = 100;
//Set color range. Default's to reddish and greenish. It takes an array of three
//integers as R, G and B values.
	Config.Color.minColorValue = [255, 0, 50];
	Config.Color.maxColorValue = [0, 255, 50];

	var tm = new TM.Squarified();
	tm.loadFromJSON(json);
}

You should see a colored treemap now.

This part of the tutorial has been updated for the new 1.0.7a library spec. If you have any questions please feel free to post them at the google group

Finally, let’s put nice tooltips! We’ll do this by using the Tip Mootools class.
First, we’ll define an onAfterCompute controller method to query for all nodes that will be displaying information (like .head and .leaf nodes) and assign the information to be displayed. To know more about this please check the docs for the Tips Mootools plug in
I also define some extra methods that convert the dataset to HTML.
I also allow tooltips by setting Config.tips to true.

So the JavaScript file should now look like this:

function init() {
	var json = //...same json data as before...
	//Allow coloring
	Config.Color.allow = true;
//Set min value and max value for the second *dataset* object values.
//Default's to -100 and 100.
	Config.Color.minValue = -100;
	Config.Color.maxValue = 100;
//Set color range. Default's to reddish and greenish. It takes an array of three
//integers as R, G and B values.
	Config.Color.minColorValue = [255, 0, 50];
	Config.Color.maxColorValue = [0, 255, 50];

	//Allow tips for treemap
	Config.tips = true;

	var tm = new TM.Squarified({
		onAfterCompute: function() {
			var that = this, parent;
			$$('#infovis .leaf', '#infovis .head').each(function(elem, i) {
				//get the JSON tree node element having the same id
				//as the dom element queried and makeTip.
				if(p = elem.getParent()) {
					var sTree = TreeUtil.getSubtree(tm.tree, p.id);
					if(sTree) that.makeTip(elem, sTree);
				}
			});
		},
//Tooltip content is setted by setting the *title* of the element to be *tooltiped*.
//Read the mootools docs for further understanding.
		makeTip: function(elem, json) {
			var title = json.name;
			var html = this.makeHTMLFromData(json.data);
			elem.store('tip:title', title).store('tip:text', html);
		},
//Take each dataset object key and value and make an HTML from it.
		makeHTMLFromData: function(data) {
			var html = '';
			for(var i=0; i<data.length; i++) {
				html += data[i].key + ': ' + data[i].value + '<br />';
			}
			return html;
		}

	});

	tm.loadFromJSON(json);
}

You should see some tooltips now!

Remember that you have more controller methods to customize your visualization just as you want! Hope it was helpful.