wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Aggregating view data for use in d3js graphics


Dashboards are all the rage, so it is natural that your XPages application need a dash of a dashboard. A view makes an excellent source for dashboard data and the ability to categorize views handles the heavy lifting of aggregating the values you want to use e.g. in a bar or pie chart. I've been fallen in love with d3js since she is the ultimate visualization (if in doubt, read the classics ).
D3Js is a harsh mistress of exceptional beauty, so you might want to check out some of her offsprings like RickShaw, NVD3 or xCharts. Indulge in myriads of tutorials and reviews (check part 2 too) and the over 1000 examples.
With just a few lines of JavaScript any categorized view can be used as source for d3js. The script can read a categorized view with one to three categories. If you have one it reads the view, for two you get hierarchical data or provide a key, so you only retrieve the selected category etc.Since I use a viewNavigator performance is quite good:
function getCategoryData(viewName, dataColumn, getChildren, key) {
	var v = database.getView(viewName);
	var nav;
	if (key) {
		nav = v.createViewNavFromCategory(key);
	} else {
	   nav= v.createViewNav();
	}
	var ve = nav.getFirst();
	var isFirst = true;
	var result = "[";
	while (ve) {
		if (!ve.isTotal()) {
			var curData = ve.getColumnValues();
			if (!isFirst) {
				result += ",";
			}
			result += "{label : \"";
			if (key) {
				result += curData[1 ];
			} else {
				result += curData[0 ];	
			}			
			result += "\", value : ";
			result += curData[dataColumn ];
			/* for 2 level categories we fetch additional data */
			if (getChildren) {
				var childve = nav.getChild();
				var firstChild = true;
				result += ", children : [";
				while (childve) {
					var childData = childve.getColumnValues();
					if (!firstChild) {
						result += ",";
					}
					result += "{label : \"";
					result += childData[1 ];
					result += "\", value : ";
					result += childData[dataColumn ];
					result += "}";			
					firstChild = false;
					childve = nav.getNextSibling(childve);
				}
				result += " ]"
			}
			result += "}";			
			isFirst = false;
		}		
		ve = nav.getNextSibling(ve);
	}
	result += " ]";
	return result;
}
A very typical use are year-to-date graphs, that accummulate the values from category to category. Here I use this:
function getCumulativeCategoryData(viewName, key, dataColumn, fetchChildren) {
	var v = database.getView(viewName);
	
	var nav = v.createViewNavFromCategory(key);
	var ve = nav.getFirst();
	var nextVe;
	var isFirst = true;
	var result = "[";
	var runningTotal = 0;
	while (ve) {
		// Prefetch the next entry
		nextVe = nav.getNextSibling(ve);
		if (!ve.isTotal()) {
			var curData = ve.getColumnValues();
			if (!isFirst) {
				result += ",";
			}
			result += "{label : \"";
			result += curData[1 ];
			result += "\", value : ";
			runningTotal += Number(curData[dataColumn ]);
			result += runningTotal;
			/* for 2 level categories we fetch additional data */
			if (fetchChildren) {
				var runningSubTotal = 0;
				var childve = nav.getChild();
				var nextChildVe;
				var firstChild = true;
				result += ", children : [";
				while (childve) {
					nextChildVe = nav.getNextSibling(childve);
					var childData = childve.getColumnValues();
					if (!firstChild) {
						result += ",";
					}
					result += "{label : \"";
					result += childData[2 ];
					result += "\", value : ";
					runningSubTotal += Number(childData[dataColumn ]);
					result += runningSubTotal;
					result += "}";			
					firstChild = false;
					try {
						childve.recycle();
					} catch (e) {
						// No action
					}
					childve = nextChildVe;				
				result += " ]"
				}	
			}
			result += "}";			
			isFirst = false;
		}
		
		// Cleanup view entry
		try {
			ve.recycle();
		} catch (e) {
			// We don't care
		}
		ve = nextVe;
	}
	result += " ]";
	// Cleanup all objects
	try {
		nav.recyle();
		v.recycle();
	} catch (e) {
		// We don't care
	}
	return result;
}


As usual: YMMV
P.S.: for end-users, check out Tableau

Posted by on 24 September 2013 | Comments (2) | categories: XPages

Comments

  1. posted by Patrick Kwinten on Thursday 24 October 2013 AD:
    does not work very well in my IE browser (as more charting solutions do) :-?
  2. posted by Stephan H. Wissel on Thursday 24 October 2013 AD:
    @Patrick: you pick your own level of suffering.