ArchivePage 3 of 6

MultiTrees (Part 1)

I found this CHI 94′ visualization paper on MultiTrees in the internet and I’ve been trying to see what type of applications and ideas I could “borrow” for the JavaScript InfoVis Toolkit.

What are MultiTrees?

A MultiTree is a type of directed acyclic graph (DAG) where each node has a tree both as parent structure and as descendants.

For example, a MultiTree can be created by overlapping different tree structures on a set of nodes, as shown in the picture below:

As you can see MultiTrees can have cycles if they’re not directed.

Laying and Navigating MultiTrees

What’s interesting about this structure is that if we take two nodes x and y such that x <= y and the path connecting them, then we can form a topological tree by adding all descendants and ancestors of each node belonging to that path in the new graph.

Implementation

I recently pushed support for a small subset of MultiTrees: those where x = y.
This is just a centered node and its tree of descendants and ancestors.

The tree navigation is the same as the SpaceTree:

I also implemented a way of changing the current focused node, so that when the clicked node is centered a centrifugal view from that node is adopted.
This way the current selected node is set as root of the visualization.
Hopefully you’ll understand the difference between this navigation and the previous one.

Anyway, as soon as I get this feature fully functional I’ll make another post explaining how to use this stuff in the JavaScript InfoVis Toolkit.

Outside In

While taking a look at some of the talks by Tamara Munzner I found this video/documentary about turning a sphere inside out.
I’ve found this to be very impressive (and pedagogic). The style of the video reminds me the Moebius Transformation video I posted last year.

For those who don’t know Tamara Munzner she’s like a big reference in all InfoVis-related stuff. One of the most inspiring InfoVis talks I’ve found was done by her and can be seen here. This is the talk that started my interest in InfoVis and the making of the JavaScript InfoVis Toolkit.

Drawing Trees

While trying to fix a SpaceTree layout issue for version 1.1.2 of the JavaScript InfoVis Toolkit I found a Microsoft Research paper that describes a functional programming approach for rendering trees in an aesthetically pleasing way.

But what is aesthetically pleasing?

Andrew J. Kennedy takes Radack and Walker rules:

  1. Two nodes at the same level should be placed at least a given distance apart.
  2. A parent should be centred over its offspring.
  3. Tree drawings should be symmetrical with respect to reflection—a tree and
    its mirror image should produce drawings that are reflections of each other. In
    particular, this means that symmetric trees will be rendered symmetrically.
  4. Identical subtrees should be rendered identically—their position in the larger
    tree should not affect their appearance.
  5. Trees should be as narrow as possible without violating these rules

In order to calculate nodes’ positions Kennedy takes a “bottom-up” approach:

Starting from the root node, draw for each node all its subtrees without breaking any rules. Fit these subtrees together without changing their shape, and also without breaking rules 1 and 3 (i.e do not break symmetry and avoid cluttering/overlapping of nodes). Finally, center their parent above them like specified in rule 2.

The “fitting” of the subtrees is calculated by operating on subtrees extents. A subtree extent is a data structure containing the relative coordinates of the boundary of a subtree. One frequent operation between extents is merging:

Other operations involve setting the distance between two extents, translating extents, etc.

Implementation

Kennedy implements this algorithm in Standard ML. I made a JavaScript adaptation. I like the Standard ML version a lot more; in this case rich typing makes very elegant code.

Here’s my code implementation, in case you want to compare it to Kennedy’s.
My version takes into account different tree layouts (left, right, bottom, top), siblings and subtrees offsets and different node sizes as opposed to Kennedy’s version.

 function movetree(node, prop, val, orn) {
   var p = (orn == "left" || orn == "right")? "y" : "x";
   node[prop][p] += val;
 };

 function moveextent(extent, val) {
     var ans = [];
     $each(extent, function(elem) {
         elem = slice.call(elem);
         elem[0] += val;
         elem[1] += val;
         ans.push(elem);
     });
     return ans;
 };

 function merge(ps, qs) {
   if(ps.length == 0) return qs;
   if(qs.length == 0) return ps;
   var p = ps.shift(), q = qs.shift();
   return [[p[0], q[1]]].concat(merge(ps, qs));
 };

 function mergelist(ls, def) {
     def = def || [];
     if(ls.length == 0) return def;
     var ps = ls.pop();
     return mergelist(ls, merge(ps, def));
 };

 function fit(ext1, ext2, subtreeOffset, siblingOffset, i) {
     i = i || 0;
     if(ext1.length <= i ||
        ext2.length <= i) return 0;

     var p = ext1[i][1], q = ext2[i][0];
     return Math.max(fit(ext1, ext2, subtreeOffset, siblingOffset, ++i) + subtreeOffset,
                 p - q + siblingOffset);
 };

 function fitlistl(es, subtreeOffset, siblingOffset) {
   function $fitlistl(acc, es, i) {
       i = i || 0;
       if(es.length <= i) return [];
       var e = es[i], ans = fit(acc, e, subtreeOffset, siblingOffset);
       return [ans].concat($fitlistl(merge(acc, moveextent(e, ans)), es, ++i));
   };
   return $fitlistl([], es);
 };

 function fitlistr(es, subtreeOffset, siblingOffset) {
   function $fitlistr(acc, es, i) {
       i = i || 0;
       if(es.length <= i) return [];
       var e = es[i], ans = -fit(e, acc, subtreeOffset, siblingOffset);
       return [ans].concat($fitlistr(merge(moveextent(e, ans), acc), es, ++i));
   };
   es = slice.call(es);
   var ans = $fitlistr([], es.reverse());
   return ans.reverse();
 };

 function fitlist(es, subtreeOffset, siblingOffset) {
    var esl = fitlistl(es, subtreeOffset, siblingOffset),
        esr = fitlistr(es, subtreeOffset, siblingOffset);
    for(var i = 0, ans = []; i < esl.length; i++) {
        ans[i] = (esl[i] + esr[i]) / 2;
    }
    return ans;
 };

 function design(graph, node, prop, config) {
     var orn = config.orientation;
     var auxp = ['x', 'y'], auxs = ['width', 'height'];
     var ind = +(orn == "left" || orn == "right");
     var p = auxp[ind], notp = auxp[1 - ind];

     var cnode = config.Node;
     var s = auxs[ind], nots = auxs[1 - ind];

     var siblingOffset = config.siblingOffset;
     var subtreeOffset = config.subtreeOffset;

     var GUtil = Graph.Util;
     function $design(node, maxsize, acum) {
         var sval = (cnode.overridable && node.data["$" + s]) || cnode[s];
         var notsval = maxsize || ((cnode.overridable && node.data["$" + nots]) || cnode[nots]);

         var trees = [], extents = [], chmaxsize = false;
         var chacum = notsval + config.levelDistance;
         GUtil.eachSubnode(node, function(n) {
             if(n.exist) {
                 if(!chmaxsize)
                    chmaxsize = getBoundaries(graph, config, n._depth);

                 var s = $design(n, chmaxsize[nots], acum + chacum);
                 trees.push(s.tree);
                 extents.push(s.extent);
             }
         });
         var positions = fitlist(extents, subtreeOffset, siblingOffset);
         for(var i=0, ptrees = [], pextents = []; i < trees.length; i++) {
             movetree(trees[i], prop, positions[i], orn);
             pextents.push(moveextent(extents[i], positions[i]));
         }
         var resultextent = [[-sval/2, sval/2]].concat(mergelist(pextents));
         node[prop][p] = 0;

         if (orn == "top" || orn == "left") {
            node[prop][notp] = acum;
         } else {
            node[prop][notp] = -acum;
         }
         return {
           tree: node,
           extent: resultextent
         };
     };
     $design(node, false, 0);
 };

V8-GL Update

I’ve been quite busy these days.

I’ve been answering questions at the JavaScript InfoVis Toolkit Google Group, fixing a couple of bugs for the JIT and putting a lot of effort in V8-GL.

Oh right, I was almost forgetting that I have a day job also :S

Anyway, V8-GL kind of took another direction. I’ve been working on OpenGL ES 2.0 and OpenGL 2.1 bindings.

OpenGL ES 2.0 bindings are almost complete. Other bindings (like OpenGL 2.1, GLUT and GLU) need some extra work, but they are functional.

Dean helped a lot also. He just translated Vlad’s metatunnel example to work with the new OpenGL ES 2.0 bindings. The result’s pretty impressive:

You can find some videos of “Metatunnel” implemented in Processing or Canvas3D at Youtube.

The good thing about the V8-GL example is that’s a Desktop app coded in JavaScript using V8.

V8-GL

I’ve been doing a couple of changes to the JavaScript InfoVis Tookit lately, which I’ll describe in some other post, but most important I’ve been working on a new project I’m really excited about that’s called V8-GL.

What’s V8-GL?

V8-GL intends to provide a high-level JavaScript API for creating 2D/3D hardware accelerated desktop graphics.

In other words, you can hack some JavaScript code that opens a desktop window and renders some 3D hardware accelerated graphics. Bindings are made using the V8 JavaScript engine.

Example

I wrote a small example that animates a rotating Icosahedron. This example uses timers, colors and lighting among other things:

//Add array iteration method
Array.prototype.each = function(f) {
	var len = this.length;
	for ( var i = 0; i < len; i++) f(this[i]);
};

//Initializes 3D rendering
function initRendering() {
	"DEPTH_TEST COLOR_MATERIAL LIGHTING LIGHT0 NORMALIZE COLOR_MATERIAL"
		.split(" ").each(function(elem) {
		Gl.Enable(Gl[elem]);
	});
}

//angle variable
var angle = 0;

//Draws the 3D scene
function drawScene() {
	//Set global color and drawing properties
	Gl.Clear(Gl.COLOR_BUFFER_BIT | Gl.DEPTH_BUFFER_BIT);
	Gl.MatrixMode(Gl.MODELVIEW);
	Gl.LoadIdentity();
	Gl.Translatef(0.0, 0.0, -5.0);
	//Set diffuse and positioned lights
	Gl.LightModelfv(Gl.LIGHT_MODEL_AMBIENT, [0.3, 0.3, 0.3, 1.0]);
	Gl.Lightfv(Gl.LIGHT0, Gl.DIFFUSE, [0.4, 0.4, 0.4, 1.0]);
	Gl.Lightfv(Gl.LIGHT0, Gl.POSITION, [5.0, 5.0, 5.0, 1.0]);
	//Rotate and plot Icosahedron
	Gl.Rotatef(angle, 1.0, 1.0, 1.0);
	Gl.Color3f(0.5, 0.0, 0.8);
	Glut.SolidIcosahedron(2.5);
	//Render
	Glut.SwapBuffers();
}

(function() {
	//Initialize Glut
	Glut.Init();
	Glut.InitDisplayMode(Glut.DOUBLE | Glut.RGB | Glut.DEPTH);
	Glut.InitWindowSize(400, 400); //Set the window size
	//Create the window
	Glut.CreateWindow("OpenGL on V8 baby!");
	initRendering();
	//Set drawing callback
	Glut.DisplayFunc(drawScene);
	//Set resize window callback
	Glut.ReshapeFunc(function(w, h) {
		var gl = { 'Viewport': [0, 0, w, h], 'MatrixMode': [Gl.PROJECTION], 'LoadIdentity': [] };
		for (var i in gl) Gl[i].apply(this, gl[i]);
		Glu.Perspective(45.0, w / h, 1.0, 200.0);
	});
	//Set timeout callback
	Glut.TimerFunc(25, function() {
		angle += 2.0;
		if (angle > 360) angle -= 360;
		Glut.PostRedisplay();
		Glut.TimerFunc(25, arguments.callee, 0);
	}, 0);
	//Start the main loop.
	Glut.MainLoop();
})();

OpenGL devs. might recognize the API exposed through the Gl, Glu and Glut objects.

Status

Currently 80% of the OpenGL API is implemented. OpenGL APIs are exposed through the Gl, Glu and Glut global objects.

However, like I said before, this project is not just about making OpenGL bindings for JavaScript through V8, but to provide a higher level API.

Although this project is in current development you can already clone the repo and follow the Download instructions at the V8-GL project page for creating some cool examples.

Hope you like it :)

The JavaScript InfoVis Toolkit 1.1 is Out!

After several months of hard work I can finally announce version 1.1 of the JavaScript InfoVis Toolkit.

What’s the JavaScript InfoVis Toolkit?

The JavaScript InfoVis Toolkit provides tools for creating Interactive Data Visualizations for the Web.

What’s new in this version?

Code-Related

  • The library has been split into modules for code reuse.
  • All visualizations are packaged in the same file. You can create multiple instances of any visualization. Moreover, you can combine and compose visualizations. If you want to know more take a look at the Advanced Demos.
  • This Toolkit is library agnostic. This means that you can combine this toolkit with your favorite DOM/Events/Ajax framework such as Prototype, MooTools, ExtJS, YUI, JQuery, etc.
  • You can extend this library in many ways by adding or overriding class methods. The JavaScript InfoVis Toolkit has a robust (and private) class system, heavily inspired by MooTools’, that allows you to implement new methods in the same class without having to define any new Class extension. By creating mutable classes you can add new custom Node and Edge rendering functions pretty easily.
  • Custom visualizations are created by adding or changing Node/Edge colors, shapes, rendering functions, etc. You can also implement many controller methods that are triggered at different stages of the animation, like onBefore/AfterPlotLine, onBefore/AfterCompute, onBefore/AfterPlotNode, request, etc.
    You can also add new Animation transitions like Elastic or Back with easeIn/Out transitions.
    If you want to know more about these features please take a look at the Demos code.

As you can see, this new version has been built with four concepts/goals in mind: Modularity, Customization, Composition and Extensibility. I already explained some of these things in the previous post.

Hope you enjoy it.

More about the JavaScript InfoVis Toolkit 1.1

I’ve been putting a lot of effort in the upcoming version of the JavaScript InfoVis Toolkit lately, and I though it would be a good idea to show some of the new features I came up with.

The new version isn’t finished yet, but I’ve come pretty far and wanted to make a sort of checkpoint for the things I’ve done, the things I’ll be doing and the things I’m thinking about doing.

So what have I been working on?

  • A new project page design.
  • A complete documentation. I made an API documentation that is also mixed with some narrative documentation for each Class, so you can learn how the visualizations are implemented and how to use them.
  • Packaging All visualizations will be packaged in the same file, and you’ll be able to make your own build based on what you’re going to use (Treemaps, Hypertrees, RGraphs, Spacetrees or any combination of those). This is a cool aspect of making modular code.
    The other good thing about modular code is that the size of the full package will drop in ~30% compared to version 1.0.8a
  • Examples I’ve been coding some new visualization examples that will be packaged with the library. Some of them are very similar to the ones found in 1.0.8a, but adapted for version 1.1. Other examples show some of the new features of the library, and others try to expose some features of version 1.0.8a that were not properly documented.

Library features

I’ve been building this library with four things in mind:

  • Extensibility The library has multiple access points where it can be extended in different ways. For example, all main Classes are mutable objects, so you can extend or implement any method of any class in-place, like for example re-implement the nodes coloring method in the Squarified treemap:

       //TM.Strip, TM.SliceAndDice also work
       TM.Squarified.implement({
         'setColor': function(json) {
           return json.data.$color;
         }
       });
    

    …or adding new node/edge plotting methods in the Hypertree, ST or RGraph:

    Hypertree.Plot.NodeTypes.implement({
      'my-node-rendering-method': function(node, canvas) {
        //implement node rendering here
      }
    });
    

    etc.

  • Customization The library provides many ways for customizing the visualizations. There are controller methods that determine the behavior of the visualization, and configuration parameters like node and edge types, color and dimensions. Node shapes can be square, rectangle, circle, ellipse, etc. and edge shapes: line, hyperline and arrow. I also added transition effects like Quart, Bounce, Elastic, Back, etc. for the animations.
  • Modularity As explained above, the code has been divided into modules, providing a way for making custom builds of the library. Modularity also takes care of namespacing: I only add Classes that are meant to be accessed by the user and I don’t pollute the window object with unnecessary global objects.
  • Composition A major improvement in this version is that all visualizations can co-exist in the same namespace. That means that multiple instances of different visualizations can be used and composed to make new visualizations. I haven’t explored this feature of the library yet, but this would mean that for example I can make a Treemap that has Hypertrees rendered as leaves, or a Spacetree that has Treemaps as nodes, or… well, any other combination of things.

Examples

As you might know, I don’t have the most suited computer for making screencasts, so sorry if you see some performance problems.

This is a short video I made of a RGraph example.

The main idea behind this example is Customization.
That can be seen for example in the different node types, edge types and colors used, as well as in the Elastic transition effect for the animation.

This is just an example to expose as much features as I can in one visualization, so don’t take this as a “useful” visualization example please.

Here is another short video: it illustrates how Graph Operations can be made with the Hypertree visualization.

You’ll see 4 consecutive operations:

  1. Removing a subtree The bottom right subtree will be removed with an animation.
  2. Removing edges Edges from the top left subtree will be removed with an animation.
  3. Adding a graph A graph will be added with an animation
  4. Morphing The graph will transform into another graph -with an animation

Enjoy.

Interactive Visualization of Genealogical Graphs

It’s been a while since I last bumped into a nice visualization project like this one.
It offers an advanced interface for exploring Genealogical graphs.

I personally like how nodes are hidden/shown in demand, how the subtree widget is implemented and how you can easily switch between different layouts.

On a side note, I’ve been screencasting the artist/band visualization project I made some time ago with the JavaScript InfoVis Toolkit, hope you find it interesting: it shows relations between artists and bands by collaborations in albums/songs/bands, etc.

You can access a live example here. I think its better rendered with Firefox, Safari, Opera and Chrome 2 (version 1.0.x has a bug).

The left menu offers some navigation options to choose a band as starting point. You can also find details about the focused band under the Details toggler.

Here’s a short video of what you should be able to see:

Taking a look at Groovy

While at work last week I decided to make a small program in the Groovy programming language. I needed to build a small file processing program that used some Java libraries built at work, but I didn’t want to code five or six Java classes to do so. Since performance wasn’t a big concern, I decided to take a look at some JVM based languages.

There are lots of programming languages targetting the JVM, so why Groovy?

Why Groovy?

Groovy is a highly dynamic language, that takes things from Python, Ruby and Smalltalk. Since these are programming languages I used before and I’m quite comfortable with, Groovy seemed like a good match.

Also, Groovy is very easy to learn, having an almost-zero learning curve. Since I had to do this in a couple of days, I didn’t want to spend a lot of time learning a programming language’s syntax and semantics. I know how to use Python and I know how to use Ruby/Smalltalk, I just want to do the same things in the JVM.

Another very interesting thing (that doesn’t concern the language itself, but it’s quite helpful) is that Groovy, along with OCaml and Perl, has a 100% completness score at PLEAC. That means that you can find complete examples of: Strings, Numbers, Arrays, Hashes, Dates and Times, Pattern Matching, File Access, File Contents, Directories, Subroutines, References and Records, Packages, Libraries and Modules, Classes and Objects, Database Access, User Interfaces and a lot more here.

Features I like about the language

Some of the features I used and liked about Groovy:

List and Hash literals
As opposed to Java, Groovy provides List and Hash literals:

//Create an empty List
emptyList = []
//Create an empty Hash
emptyHash = [:]
//Create a List
somePeople = ["John", "Jack", "Sarah"]
//Create a Hash
ext = [
  Ruby: 'rb',
  Python: 'py',
  C: 'c',
  Groovy: 'groovy'
]

List and Hash traversing and manipulation

In terms of List and Hash manipulation, Groovy offers the same expressiveness as Python and Smalltalk:

//Create a List
somePeople = ["John", "Jack", "Sarah"]

//Copy first two List elements
copy = somePeople[0..1] //["John", "Jack"]

//Grab last list element
lastElem = somePeople[-1] //"Sarah"

//Closures are first class values in Groovy, their syntax is {}.
//For unary lambdas an implicit 'it' variable is created

//Any element starting with capital letters?
somePeople.any { it[0] in 'A'..'Z' } //true

//We can also use regex a la Perl
somePeople.any { it =~ /[A-Z].*/ } //true

//Print names with new lines
somePeople.each { println it }

//Create a Hash
ext = [
  Ruby: 'rb',
  Python: 'py',
  C: 'c',
  Groovy: 'groovy'
]

//print an element
println ext.'Ruby' //rb
println ext['Ruby']//rb

//iterate through a hash elements
ext.each { key, value -> println key + ': ' + value }
//will print Ruby: rb, etc

Defining functions
Functions are defined like this:

//Define a square function
def square(val) {
 val * val
}

//Or assign a closure to a square variable:
square = { it * it }

Simple.

Java classes extensions
One of the things I find really nice about Groovy, is that it extends Java SE with useful functions.
You can find the extensions here.

Java File class extensions are pretty cool:

//Print dir file names
new File("/some/dir/").eachFile { println it.name }

//Print file text content
println new File("/some/file.txt").getText()

//Print file content with line numbers
new File("otherfile.txt").eachLine { it, line -> println line + ": " + it }

Other libraries

At work I had to deal with XML data, and found a very interesting and high level XML manipulation library called XmlSlurper:

xml = ‘‘‘
<root>
<artist name="Pearl Jam">
  <album>Ten</album>
  <album>Vs.</album>
  <album>Vitalogy</album>
  <album>Riot Act</album>
</artist>
<artist name="Soundgarden">
  <album>Down on the Upside</album>
  <album>Superunknown</album>
</artist>
</root>
‘‘‘
root = new XmlSlurper().parseText(xml)
root.artist.each {
  println it.@name.text() + ': ' +
        it.album.collect({ it.text() }).join(', ')
}
//Will print
//Pearl Jam: Ten, Vs., Vitalogy, Riot Act
//Soundgarden: Down on the Upside, Superunknown

Conclusion

Groovy is a versatile scripting language built on top of the JVM.
It provides useful features taken from Ruby, Python and Smalltalk, with full access to all Java libraries.
It also extends Java classes with useful methods and iterators.
If you aren’t that worried about performance (still runs faster than Ruby, Python 3 and Perl), I’d recommend you to take a look at it.
Hope this was helpful enough to get a feeling of the language.

JavaScript InfoVis Toolkit 1.1 Preview

In case you’re wondering what I’m up to…

I’ve been adding more features to the JavaScript InfoVis Toolkit, to be released I-don’t-know-when-yet (still a lot of work to do regarding documentation, hosting, scripts, etc.).

Anyway, this video shows only some of the features to be included:

  • Custom nodes: built-in shapes are none, circle, square, rectangle, ellipse, among others
  • Custom edges: built-in shapes are none, line, quadratic, bezier, arrow, among others
  • Custom Animations: linear, Quart, Bounce, Elastic, Back, etc.
  • Change tree orientation: already possible in 1.0.8a.

Unfortunately my video card isn’t very good, so the video quality and fps aren’t as good as I’d wanted.
Animations are pretty smooth though, as you can see for yourself, so don’t blame the library, blame my computer!

Anyway, here’s the video:

Another cool thing is that you can also create custom node and edge rendering functions :)

Stay tuned, there are more features to come!