About

Moebio Framework is a JavaScript toolkit for performing data analysis and creating visualizations.

Moebio Framework Demo Reel on Vimeo.

At its core is a set of data types as well as operators to manipulate them and derive meaning from your data. These include include Lists, Tables, Intervals, Networks and many more.

Additonally Moebio framework provides a canvas based drawing framework and a collection of graphics & geometry related functions to empower the creation of data visualizations.

Moebio Framework is being actively developed and is in a Beta status. Please, try it out, and let us know what you think. If you have a question or comment, add the question tag to your issue - and we will answer it!

Features

  • Rich collection of data types and utilities to convert between them
  • Fast canvas based 2D and 3D drawing api with mouse interaction
  • Text Rendering Support
  • Canvas based UI Elements like Color Pickers, Text Boxes and Tooltips
  • Growing collection of tools for Statistics, Prediction, Math, Network Analysis and more!

Browser support

Moebio Framework is designed for modern browsers. Including recent versions of Google Chrome, Mozilla Firefox and Safari.

Download

Moebio Framework is developed on and hosted with GitHub. Head to the GitHub repository for downloads, bug reports, and features requests.

Examples

Click on the examples below to open up a live running version along with the code that generates it.

Simple Shapes
See how to draw simple geometric shapes.

Mouse Movements
Demonstrates mouse interactions.

Cube
Demonstrates drawing 3d shapes and basic animation and mouse interaction.

Network
Demonstrates physics models and network generation and visualization.

Spanning Tree
See how to render and interact with a network include, running network algorithms over the underlying data.

Getting Started

Let's start by making a simple example with the Moebio Framework.

If you like, you can follow along with the code.

Including the script

First add the framework source file and shim to an html page.

<script src="js/moebio_framework.js"></script>

The global_shim adds all the functions and data types in moebio_framework into the global environment.

This should go near the bottom of the page, right before the closing body tag - which allows the rest of the page to load before needing to load this JavaScript.

Setting up the Canvas

Moebio Framework harnesses canvas for much of its visualization capabilities. But the Graphics library will take care of creating the canvas element. We just need to make a div to store it in:

<div id="maindiv">
</div>

Optionally, we might want to add some styling to #maindiv to ensure it is visible:

html, body{
  height:100%;
}
body {
  margin:0;
  padding:0;
  overflow:hidden;
}
#maindiv {
  width: 100%;
  height: 100%;
}

Graphics object

Drawing, initialization, and the render loop of a visualization in Moebio Framework is all controlled by the Graphics object. When creating a Graphics instance, we provide the div or other container for it to render to. We also pass in an init and cycle function (described next). Here is the most basic example of creating a new Graphics instance:

var graphics = new mo.Graphics({
  container: "#maindiv",
  init: init,
  cycle: drawSomething
});

Graphics can take other options like dimensions as well. Here is an example setting the width and height of the canvas to draw into.

var graphics = new mo.Graphics({
  container: "#maindiv",

  dimensions: {
    width: 500,
    height: 500,
  },

  init: function() {
    //...
  },

  cycle: function() {
    //...
  });

init and cycle

Moebio Framework is built around the concept of a drawing loop. The drawing loop is called over and over again, and it is responsible for drawing the visualization for each frame. If you have worked with something like Processing, then this will look familiar.

In Moebio there are two main functions to implement: init which gets called before the looping starts, and cycle which draws the visualization for each iteration of the loop.

In a basic visualization, there may be nothing to setup. In which case, init is optional.

In both, this is set to the current Graphics instance. So we can pull out information about the current state of the Graphics instance easily.

The Moebio Framework provides access to a number of useful attributes that let you reason about the current state of the visualization and handle various types of interactions.

These attributes are accessible at any point in your code. Lets use console.log to monitor some of them.

In cycle, add the following logging:

cycle: function() {
  console.log("graphics width: " + this.cW + " graphics height: " + this.cH);
  console.log("mouse x: " + this.mX + " mouse y: " + this.mY);
}

Now open up this page in a web browser and also open the browser's console.

You should see a bunch of logs scrolling past in the console. Mousing over the window will show the change in the mX and mY, the mouse X and Y position. Resizing the window will change cW and cH, the canvas's width and height.

We will look at some of the other attributes later, but these should be enough to get us started.

Drawing Functions

Part of what makes Moebio Framework a powerful tool is its collection of drawing functions. We can think of these as helper functions that simplify the canvas API to allow for quickly displaying common shapes.

Let's use just one of these functions, fRect, to draw a rectangle. We will also use setFill to provide the rectangle's color.

Modify the cycle function to look like this:

cycle: function() {
  this.setFill('steelblue');
  this.fRect(this.cW / 2, this.cH / 2, (this.mX / 2), (this.mY / 2));
}

Reloading the page gives us a blue rectangle in the middle of the visualization, with dimensions based on the current location of the mouse.

blue square

Basic Interaction

Let's start again with an empty cycle function, and this time add some interactive circles.

We can take advantage of Moebio Framework's Point class to create and store x / y positions to be where we render our circles.

Outside of the cycle function, create an array to store these Points.

var points = [ new mo.Point(250,250) ];

We add a single point, just to get started. Don't worry, we will add more in a bit.

Now in our cycle function, we can display each Point in points. We will use fCircleM to draw the circle, while also calculating if the mouse is hovering over that point during this iteration of the cycle function.

cycle: function() {
  var radius = 20;

  for(var i = 0; i < points.length; i++) {
    var point = points[i];
    this.setFill('grey');
    var over = this.fCircleM(point.x, point.y, radius);
  }
}

grey circle

Right now, this is just a grey circle, but drawing functions that end in M return true if the mouse is hovering over the drawn shape during the current iteration of cycle.

We can use this returned value to visually update the shape when it is moused over (again remember that this is the graphics instance):

// if mouse over, change color to orange
  if(over) {
    this.setFill('orange');
    this.fCircle(point.x, point.y, radius);
    this.setStroke('grey');
    this.sCircle(point.x, point.y, radius + 10);
    this.setCursor('pointer');
  }

Now, if over is true, meaning this circle is currently being moused over, we change the fill and re-draw an orange circle on top of our original grey circle. We also add a ring around this circle using sCircle.

orange circle

As an aside, the use of sCircle hints that there are a number of different draw functions available to us for each type of basic shape. Functions that start with f, like fRect and fCircle draw a filled in shape. Those starting with s draw just a stroke. And those that start with fs, like fsRect draw the shape both filled in and with an outline. Check out the documentation to find out more!

Finally, let's add a basic mouse click interaction. Moebio Framework indicates mouse interactions by setting a few globally accessible variables:

  • MOUSE_DOWN - true if the current cycle has a mouse down event.
  • MOUSE_UP - true if the current cycle has a mouse up event.
  • MOUSE_PRESSED - true if the mouse is currently being pressed.

Let's change the color of the circle to be red if the mouse clicks on it. For this, we will want to handle both MOUSE_DOWN and MOUSE_PRESSED to ensure it stays red if the mouse is held down.

Add this to the end of the cycle function:

   // if mouse pressed, change color to orange
   if((this.MOUSE_DOWN || this.MOUSE_PRESSED) && over) {
     this.setFill('red');
     this.fCircle(point.x, point.y, radius);
   }

Now, if the mouse is over the circle, and it is being pressed down, the circle will turn red.

One little addition, as the circles are drawn every time cycle is called, we can easily animate their shape, position, or size based on data or other parameters.

We can see this by tweaking our radius value. Let's make it proportional to the x/y location of the mouse. Change our radius code to match the following:

  var radius = (this.mX + this.mY) / 30;
  if(radius < 10) {
    radius = 10;
  }
  if(radius > 50) {
    radius = 50;
  }

And now our circles pulse with our mouse movements.

Just to see it all together, here is our complete cycle function:

cycle: function() {
  // The size of the circles will be controlled by the mouse position
  // mX & mY is mouse X & Y
  var radius = (this.mX + this.mY) / 30;
  if(radius < 10) {
    radius = 10;
  }
  if(radius > 50) {
    radius = 50;
  }

  // When drawing shapes we can get information as to whether the mouse
  // is over them, or whether the mouse is pressed.
  for(var i = 0; i < points.length; i++) {
    var point = points[i];
    // add a circle that can detect mouse over
    this.setFill('grey');
    var over = this.fCircleM(point.x, point.y, radius);

    // if mouse over, change color to orange
    if(over) {
      this.setFill('orange');
      this.fCircle(point.x, point.y, radius);
      this.setStroke('grey');
      this.sCircle(point.x, point.y, radius + 10);
      this.setCursor('pointer');
    }
    // if mouse pressed, change color to orange
    if((this.MOUSE_DOWN || this.MOUSE_PRESSED) && over) {
      this.setFill('red');
      this.fCircle(point.x, point.y, radius);
    }
  }
}

Mouse Events

In our cycle function, the current mouse position and interaction is available through the Graphics instance. We can also bind callback functions to particular mouse actions, as you might be familiar with from something like jQuery.

For this example, we can add new Points to wherever we've clicked:

graphics.on('click', function(){
  points.push( new mo.Point(graphics.mX, graphics.mY));
});

Now clicking around will give us a cohort of circles that shrink and grow.

Check out the full example and the framework's documentation to see what else you can try!

Working With Data Tables

Ok! We have seen how to use Moebio Framework to work with the canvas to make graphics, but there is another side to the framework: working with data.

Data Types and Functions

A core philosophy of Moebio Framework is that the type of data you are looking at determines the operations and manipulations you can perform on that data. Another way to say this is that if we get our data into the right data type, then we will have access to all the methods and functions in the framework that work on that data type.

And in Moebio Framework, there are a lot of data types and functions to work with them! From the documentation, you can get a sense for how these data types are arranged. There are the normal basic types you would expect, like Strings and Numbers, but also ones like Rectangle, Point, and Polygon.

Typically in a data set you are dealing with more then just one of these values, and that is where List and Table come in. Most of the basic data types have an associated list type that provides specific methods and functions to that type. NumberList for example has getMax, getMin, getAverage, and many other methods that are specific to working with a list of numbers.

In addition to these methods callable on an instance of a list or basic data type, Moebio Framework provides a host of customized functions that work on and transform these data types. These functions are organized into namespaces by what types of operations they perform.

  • Operators work on a particular data type to derive insights or details.
  • Conversions convert between different data types.
  • Generators generates artificial data using a number of algorithms.
  • Encodings serialize and deserialize the data types.

Not all data types have each of these namespaces, but most have some to explore for additional capabilities of the framework. NumberList for example, has NumberListOperators, NumberListConversions, and NumberListGenerators. The namespaces attempt to partition up the frameworks functionality in a consistent manner.

Knowing more about the structure and the capabilities of the data types and their helper functions, let's dive in to using these functions to get an understanding into a particular data set!

Loading Data

The full source code for this project is in the examples directory.

We will start by loading a basic CSV file. In this example, we have included the framework script in our web page, and along side it we have a directory, data with iris.csv. This is the iris dataset that has measurements of sepals and petals for three species of iris flowers. We are going to try to explore this data set using console.log and functions from the framework.

First, load the dataset using the loadData Loader function. Here we pass in the path to the file we want load, and the local function loaded that will get called once the data is ready.

window.onload = function() {
  mo.Loader.loadData('data/iris.csv', loaded, this);
};

Now in loaded, we can get to the contents of the file by accessing the result of the input variable of loaded:

function loaded(data) {
// work with data.result here...
}

The result of loading a file starts out as just a long string, but we know it is a CSV and thus we can convert it into a Table. The Moebio Framework has a TableEncodings.CSVtoTable function that does just that. You pass in a string, and get out a Table. Let's use that inside our loaded function:

  var table = mo.TableEncodings.CSVtoTable(data.result, true);

Looking At Tables and Lists

The second parameter indicates that the first row should be considered the names of the columns. In Moebio Framework, Tables are built up as a list of Lists. Each List represents a column, and can hold a different data type. Lists are just like arrays, but with additional capabilities. We can see the names of these lists using getNames.

  console.log(table.getNames());

These as we expect are the same names in the CSV:

0: "Sepal.Length"
1: "Sepal.Width"
2: "Petal.Length"
3: "Petal.Width"
4: "Species"

When Moebio Framework converted the CSV into a Table, it was nice enough to convert each List inside that table into one tailored for storing the type of data in that column. As Table is derived from List, we can use List's getTypes method to see these types:

  console.log(table.getTypes());
0: "NumberList"
1: "NumberList"
2: "NumberList"
3: "NumberList"
4: "StringList"

So each of our columns contains Numbers in a NumberList, except for the last column, Species, which is a StringList. Not too surprising, but good to know.

Summary Statistics and Counts

To get a better feel for the contents of these lists, we can look at some summary statistics. NumberList includes many such methods, like getMin, getMax, and getAverage.

To access an individual List in the Table, we simply index into the Table like an Array. Here we get the average of the values in the first List:

  console.log("average: " + table[0].getAverage());

If we want to get the averages of all the NumberLists, one way would be to simply loop through them:

  for(var i = 0; i < table.length - 1; i++) {
    console.log("average of " + table.getNames()[i] + ": " + table[i].getAverage());
    console.log("max of " + table.getNames()[i] + ": " + table[i].getMax());
  }

Alternatively, we can use the getReport function in TableOperators or ListOperators to get a handy summary of a Table or List automatically.

  console.log(mo.TableOperators.getReport(table));

Here is what part of the report looks like currently for our Table.

///////////report of instance of Table//////////
name:
type: Table
number of lists: 5
all lists have same length: true
lists length: 150
--
0: Sepal.Length [#L]
1: Sepal.Width [#L]
2: Petal.Length [#L]
3: Petal.Width [#L]
4: Species [sL]
--
types: NumberList, NumberList, NumberList, NumberList, StringList
names: Sepal.Length, Sepal.Width, Petal.Length, Petal.Width, Species

--------lists reports---------

(0/0-4)
  ////report of instance of List////
  name: Sepal.Length
  type: NumberList
  length: 150
  first element: [5.1]
  min: 4.3
  max: 7.9
  average: 5.843333333333335
...

Another great tool in Lists is the getFrequenciesTable method. You can use this to tabulate counts of unique items in a List. Here, we use it to check out how many entries for each species there are:

  var freqTable = table[4].getFrequenciesTable();
  console.log('Species Counts');
  console.log(mo.TableEncodings.TableToCSV(freqTable));

We use TableToCSV to convert the resulting table back into a string just for printing purposes. It shows up like this:

"setosa",50
"versicolor",50
"virginica",50

So now we know we have 50 of each species. Great!

Data Mining and Information Gain

Now that we have looked a bit at the shape of our data, let's try digging in a little deeper with some more advanced features of the framework.

Information Gain is a popular tool used in data mining, especially in the construction of decision trees. It represents the ability of a particular variable to divide the data set into known categories. While it isn't typically used outside of building a decision tree, we can try it out here to get a feeling for how well these variables might perform independent of one another in assigning a particular row of data to a particular species.

Moebio Framework's TableOperators includes the getVariablesInformationGain function which calculates information gain for each column in a Table, given a list of categories. As all our variables are numerical except for Species, we can use getNumberTableFromTable to extract our NumberList columns into a new table for operation:

  var infoGain = mo.TableOperators.getVariablesInformationGain(
    mo.TableOperators.getNumberTableFromTable(table), table[4]);

  console.log(infoGain);
0: 0.3609711886232146
1: 0.20214839918573171
2: 0.8613540229246439
3: 0.8509353379542857

We see that the last two variables, Petal.Length and Petal.Width have much higher information gain then the first two, thus they contain the most information in terms of splitting this data up based on its species.

Let's use this knowledge to go one step further and look at building a very simple classification system with one of these variables.

K-Means Clustering

K-means Clustering is a simple but effective unsupervised learning clustering technique. It is a simple clustering technique that puts data elements into a given number of buckets. You tell it how many buckets, and the algorithm attempts to split up the data into these buckets - as best it can.

The Moebio Framework includes the ability to generate a K-means clustering from a NumberList. Let's try it out!

From the experimentation above, we can guess that the 3rd attribute, Petal.Length might be our best bet for clustering this particular dataset (as we are limiting ourselves to just one variable). linearKMeans, part of NumberListOperators gives us the ability to generate clusters.

  var kMeans = mo.NumberListOperators.linearKMeans(table[2], 3, true);

The 3 indicates the number of clusters to use (here we are cheating as we know there are only 3 species). The 3rd parameter indicates the algorithm should return the indexes associated with each cluster. So our returned value is a NumberTable that stores the indexes of the rows in our original table associated with each of the 3 clusters.

Now, to see how effective the cluster is, a simplistic approach would be to see how many of the Species value in the rows associated with a cluster match the most prevalent Species. As there are 3 species, we can see how well the data were binned into 3 distinct clusters.

Here is a bit of code that will calculate that, and we can walk through it line by line:

  for(i = 0; i < kMeans.length; i++) {
    var cluster = table.getSubListsByIndexes(kMeans[i]);
    var clusterFreqTable = cluster[4].getFrequenciesTable();
    var mismatch =  clusterFreqTable[1].getSum() - clusterFreqTable[1].getMax();
    console.log('cluster: ' + i + ', mismatch: ' + mismatch);
  }

First we pull out all the rows associated with a cluster using getSubListsByIndexes, and store them in a new Table, cluster. Then, we build a frequency table of the cluster's Species column (column 4), using getFrequenciesTable again. This frequency table has the value in it's first List and the count of that value as its second List. Finally, our mismatch for the cluster is calculated as the total values in the cluster minus the count of the Species with the most values for that cluster.

cluster: 0, mismatch: 0
cluster: 1, mismatch: 6
cluster: 2, mismatch: 2

Not too bad. Only a few mismatches for each cluster! We can try the same for just Sepal.Width, to see a much worse mismatch rate:

cluster: 0, mismatch: 20
cluster: 1, mismatch: 50
cluster: 2, mismatch: 3

So there you have it. We have seen how the Moebio Framework deals with data. How different data types expose different functionality, and how we can use that functionality to explore our data and even get basic answers out of it. Hopefully this gives you a good head start on where to dive into the docs to find out more of what Moebio Framework can do for your data.

The full source code for this project is in the examples directory. Check it out and get started!