annotate analysis/analysis.js @ 2314:cbc26d0f104a

Merge branch 'master' of https://github.com/BrechtDeMan/WebAudioEvaluationTool
author www-data <www-data@sucuk.dcs.qmul.ac.uk>
date Fri, 29 Apr 2016 15:21:00 +0100
parents 0141cbd1169b
children 464c6c6692d6
rev   line source
nickjillings@2131 1 /*
nickjillings@2131 2 * Analysis script for WAET
nickjillings@2131 3 */
nickjillings@2131 4
nickjillings@2192 5 // Firefox does not have an XMLDocument.prototype.getElementsByName
nickjillings@2192 6 // and there is no searchAll style command, this custom function will
nickjillings@2192 7 // search all children recusrively for the name. Used for XSD where all
nickjillings@2192 8 // element nodes must have a name and therefore can pull the schema node
nickjillings@2192 9 XMLDocument.prototype.getAllElementsByName = function(name)
nickjillings@2192 10 {
nickjillings@2192 11 name = String(name);
nickjillings@2192 12 var selected = this.documentElement.getAllElementsByName(name);
nickjillings@2192 13 return selected;
nickjillings@2192 14 }
nickjillings@2192 15
nickjillings@2192 16 Element.prototype.getAllElementsByName = function(name)
nickjillings@2192 17 {
nickjillings@2192 18 name = String(name);
nickjillings@2192 19 var selected = [];
nickjillings@2192 20 var node = this.firstElementChild;
nickjillings@2192 21 while(node != null)
nickjillings@2192 22 {
nickjillings@2192 23 if (node.getAttribute('name') == name)
nickjillings@2192 24 {
nickjillings@2192 25 selected.push(node);
nickjillings@2192 26 }
nickjillings@2192 27 if (node.childElementCount > 0)
nickjillings@2192 28 {
nickjillings@2192 29 selected = selected.concat(node.getAllElementsByName(name));
nickjillings@2192 30 }
nickjillings@2192 31 node = node.nextElementSibling;
nickjillings@2192 32 }
nickjillings@2192 33 return selected;
nickjillings@2192 34 }
nickjillings@2192 35
nickjillings@2192 36 XMLDocument.prototype.getAllElementsByTagName = function(name)
nickjillings@2192 37 {
nickjillings@2192 38 name = String(name);
nickjillings@2192 39 var selected = this.documentElement.getAllElementsByTagName(name);
nickjillings@2192 40 return selected;
nickjillings@2192 41 }
nickjillings@2192 42
nickjillings@2192 43 Element.prototype.getAllElementsByTagName = function(name)
nickjillings@2192 44 {
nickjillings@2192 45 name = String(name);
nickjillings@2192 46 var selected = [];
nickjillings@2192 47 var node = this.firstElementChild;
nickjillings@2192 48 while(node != null)
nickjillings@2192 49 {
nickjillings@2192 50 if (node.nodeName == name)
nickjillings@2192 51 {
nickjillings@2192 52 selected.push(node);
nickjillings@2192 53 }
nickjillings@2192 54 if (node.childElementCount > 0)
nickjillings@2192 55 {
nickjillings@2192 56 selected = selected.concat(node.getAllElementsByTagName(name));
nickjillings@2192 57 }
nickjillings@2192 58 node = node.nextElementSibling;
nickjillings@2192 59 }
nickjillings@2192 60 return selected;
nickjillings@2192 61 }
nickjillings@2192 62
nickjillings@2192 63 // Firefox does not have an XMLDocument.prototype.getElementsByName
nickjillings@2192 64 if (typeof XMLDocument.prototype.getElementsByName != "function") {
nickjillings@2192 65 XMLDocument.prototype.getElementsByName = function(name)
nickjillings@2192 66 {
nickjillings@2192 67 name = String(name);
nickjillings@2192 68 var node = this.documentElement.firstElementChild;
nickjillings@2192 69 var selected = [];
nickjillings@2192 70 while(node != null)
nickjillings@2192 71 {
nickjillings@2192 72 if (node.getAttribute('name') == name)
nickjillings@2192 73 {
nickjillings@2192 74 selected.push(node);
nickjillings@2192 75 }
nickjillings@2192 76 node = node.nextElementSibling;
nickjillings@2192 77 }
nickjillings@2192 78 return selected;
nickjillings@2192 79 }
nickjillings@2192 80 }
nickjillings@2192 81
nickjillings@2192 82 var chartContext, testData;
nickjillings@2131 83 window.onload = function() {
nickjillings@2131 84 // Load the Visualization API and the corechart package.
nickjillings@2192 85 google.charts.load('current', {'packages':['corechart']});
nickjillings@2131 86 chartContext = new Chart();
nickjillings@2192 87 testData = new Data();
nickjillings@2192 88 }
nickjillings@2192 89
nickjillings@2192 90 function get(url) {
nickjillings@2192 91 // Return a new promise.
nickjillings@2192 92 return new Promise(function(resolve, reject) {
nickjillings@2192 93 // Do the usual XHR stuff
nickjillings@2192 94 var req = new XMLHttpRequest();
nickjillings@2192 95 req.open('GET', url);
nickjillings@2192 96 req.onload = function() {
nickjillings@2192 97 // This is called even on 404 etc
nickjillings@2192 98 // so check the status
nickjillings@2192 99 if (req.status == 200) {
nickjillings@2192 100 // Resolve the promise with the response text
nickjillings@2192 101 resolve(req.response);
nickjillings@2192 102 }
nickjillings@2192 103 else {
nickjillings@2192 104 // Otherwise reject with the status text
nickjillings@2192 105 // which will hopefully be a meaningful error
nickjillings@2192 106 reject(Error(req.statusText));
nickjillings@2192 107 }
nickjillings@2192 108 };
nickjillings@2192 109
nickjillings@2192 110 // Handle network errors
nickjillings@2192 111 req.onerror = function() {
nickjillings@2192 112 reject(Error("Network Error"));
nickjillings@2192 113 };
nickjillings@2192 114
nickjillings@2192 115 // Make the request
nickjillings@2192 116 req.send();
nickjillings@2192 117 });
nickjillings@2131 118 }
nickjillings@2131 119
nickjillings@2135 120 function arrayMean(values) {
nickjillings@2135 121 var mean = 0;
nickjillings@2135 122 for (var value of values) {
nickjillings@2135 123 mean += value;
nickjillings@2135 124 }
nickjillings@2135 125 mean /= values.length;
nickjillings@2135 126 return mean;
nickjillings@2135 127 }
nickjillings@2135 128
nickjillings@2183 129 function percentile(values, p) {
nickjillings@2183 130 //http://web.stanford.edu/class/archive/anthsci/anthsci192/anthsci192.1064/handouts/calculating%20percentiles.pdf
nickjillings@2135 131 values.sort( function(a,b) {return a - b;} );
nickjillings@2135 132 // get ordinal rank
nickjillings@2183 133 var index = values.length*p/100;
nickjillings@2183 134 var k = Math.floor(index);
nickjillings@2183 135 if (k == index) {
nickjillings@2183 136 return values[k];
nickjillings@2183 137 } else {
nickjillings@2183 138 var f = index-k;
nickjillings@2183 139 var x_int = (1-f)*values[k]+f*values[k+1];
nickjillings@2183 140 return x_int;
nickjillings@2183 141 }
nickjillings@2135 142 }
nickjillings@2135 143
nickjillings@2135 144 function arrayMin(array) {
nickjillings@2135 145 // Return the minimum value of an array
nickjillings@2135 146 var min = array[0];
nickjillings@2135 147 for (var value of array) {
nickjillings@2135 148 if (value < min) {
nickjillings@2135 149 min = value;
nickjillings@2135 150 }
nickjillings@2135 151 }
nickjillings@2135 152 return min;
nickjillings@2135 153 }
nickjillings@2135 154
nickjillings@2135 155 function arrayMax(array) {
nickjillings@2135 156 // Return the minimum value of an array
nickjillings@2135 157 var max = array[0];
nickjillings@2135 158 for (var value of array) {
nickjillings@2135 159 if (value > max) {
nickjillings@2135 160 max = value;
nickjillings@2135 161 }
nickjillings@2135 162 }
nickjillings@2135 163 return max;
nickjillings@2135 164 }
nickjillings@2135 165
nickjillings@2181 166 function boxplotRow(array) {
nickjillings@2181 167 // Take an array of element values and return array of computed intervals
nickjillings@2181 168 var result = {
nickjillings@2195 169 median : percentile(array,50),
nickjillings@2181 170 pct25 : percentile(array,25),
nickjillings@2181 171 pct75 : percentile(array,75),
nickjillings@2181 172 IQR : null,
nickjillings@2181 173 min: null,
nickjillings@2181 174 max: null,
nickjillings@2181 175 outliers: new Array()
nickjillings@2181 176 }
nickjillings@2181 177 result.IQR = result.pct75-result.pct25;
nickjillings@2181 178 var rest = [];
nickjillings@2181 179 var pct75_IQR = result.pct75+1.5*result.IQR;
nickjillings@2181 180 var pct25_IQR = result.pct25-1.5*result.IQR;
nickjillings@2181 181 for (var i=0; i<array.length; i++) {
nickjillings@2181 182 //outliers, ranger above pct75+1.5*IQR or below pct25-1.5*IQR
nickjillings@2181 183 var point = array[i];
nickjillings@2181 184 if (point > pct75_IQR || point < pct25_IQR) {
nickjillings@2181 185 result.outliers.push(point);
nickjillings@2181 186 } else {
nickjillings@2181 187 rest.push(point);
nickjillings@2181 188 }
nickjillings@2181 189 }
nickjillings@2181 190 result.max = arrayMax(rest);
nickjillings@2181 191 result.min = arrayMin(rest);
nickjillings@2181 192 return result;
nickjillings@2181 193
nickjillings@2181 194 }
nickjillings@2181 195
nickjillings@2135 196 function arrayHistogram(values,steps,min,max) {
nickjillings@2135 197 if (steps == undefined) {
nickjillings@2135 198 steps = 0.25;
nickjillings@2135 199 console.log("Warning: arrayHistogram called without steps size set, default to 0.25");
nickjillings@2135 200 }
nickjillings@2135 201 if (min == undefined) {min = arrayMin(values);}
nickjillings@2135 202 if (max == undefined) {max = arrayMax(values);}
nickjillings@2135 203 var histogram = [];
nickjillings@2135 204 var index = min;
nickjillings@2135 205 while(index < max) {
nickjillings@2135 206 histogram.push({
nickjillings@2135 207 marker: index,
nickjillings@2135 208 lt: index,
nickjillings@2135 209 rt: index+steps,
nickjillings@2135 210 count: 0
nickjillings@2135 211 });
nickjillings@2135 212 index += steps;
nickjillings@2135 213 }
nickjillings@2135 214 for (var value of values) {
nickjillings@2135 215 for (var entry of histogram) {
nickjillings@2135 216 if (value >= entry.lt && value <= entry.rt) {
nickjillings@2135 217 entry.count++;
nickjillings@2135 218 break;
nickjillings@2135 219 }
nickjillings@2135 220 }
nickjillings@2135 221 }
nickjillings@2135 222 return histogram;
nickjillings@2135 223 }
nickjillings@2135 224
nickjillings@2131 225 function Chart() {
nickjillings@2192 226 this.valueData;
nickjillings@2135 227 this.charts = [];
nickjillings@2131 228
nickjillings@2135 229 this.chartObject = function(name) {
nickjillings@2135 230 // Create the charting object
nickjillings@2135 231 this.name = name;
nickjillings@2135 232 this.root = document.createElement("div");
nickjillings@2135 233 this.root.className = "chart-holder";
nickjillings@2135 234 this.root.setAttribute("name",name);
nickjillings@2135 235 this.chartDOM = document.createElement("div");
nickjillings@2135 236 this.tableDOM = document.createElement("div");
nickjillings@2135 237 this.latexDOM = document.createElement("div");
nickjillings@2135 238 this.downloadDOM = document.createElement("div");
nickjillings@2135 239 this.chart = undefined;
nickjillings@2135 240 this.data = new google.visualization.DataTable();
nickjillings@2135 241 this.options = {};
nickjillings@2135 242 this.print = document.createElement("button");
nickjillings@2136 243 this.sortDataButton = document.createElement("button");
nickjillings@2136 244 this.sortDataButton.textContent = "Sort by Data";
nickjillings@2136 245 this.sortDataButton.addEventListener("click",this);
nickjillings@2136 246 this.sortDataButton.setAttribute("name","sort-data");
nickjillings@2136 247 this.sortNameButton = document.createElement("button");
nickjillings@2136 248 this.sortNameButton.textContent = "Sort by Name";
nickjillings@2136 249 this.sortNameButton.addEventListener("click",this);
nickjillings@2136 250 this.sortNameButton.setAttribute("name","sort-name");
nickjillings@2136 251 this.draw = function() {
nickjillings@2136 252 if (this.chart == undefined) {return;}
nickjillings@2136 253 this.tableDOM.innerHTML = null;
nickjillings@2136 254 this.latexDOM.innerHTML = null;
nickjillings@2136 255 this.buildTable();
nickjillings@2136 256 this.writeLatex();
nickjillings@2136 257 this.chart.draw(this.data,this.options);
nickjillings@2136 258 }
nickjillings@2136 259 this.sortData = function() {
nickjillings@2173 260 this.data.sort(1);
nickjillings@2136 261 }
nickjillings@2136 262 this.sortName = function() {
nickjillings@2173 263 this.data.sort(0);
nickjillings@2136 264 }
nickjillings@2135 265 this.handleEvent = function() {
nickjillings@2135 266 // Only used to handle the chart.event.addListener(this,'ready') callback
nickjillings@2136 267 switch(event.currentTarget.getAttribute("name"))
nickjillings@2136 268 {
nickjillings@2136 269 case "download":
nickjillings@2136 270 window.open(this.chart.getImageURI());
nickjillings@2136 271 break;
nickjillings@2136 272 case "sort-data":
nickjillings@2136 273 this.sortData();
nickjillings@2136 274 this.draw();
nickjillings@2136 275 break;
nickjillings@2136 276 case "sort-name":
nickjillings@2136 277 this.sortName();
nickjillings@2136 278 this.draw();
nickjillings@2136 279 break;
nickjillings@2136 280 }
nickjillings@2135 281 }
nickjillings@2135 282
nickjillings@2135 283 this.root.appendChild(this.chartDOM);
nickjillings@2135 284 this.root.appendChild(this.tableDOM);
nickjillings@2135 285 this.root.appendChild(this.latexDOM);
nickjillings@2136 286 this.root.appendChild(this.sortDataButton);
nickjillings@2136 287 this.root.appendChild(this.sortNameButton);
nickjillings@2135 288 this.root.appendChild(this.print);
nickjillings@2135 289 this.print.textContent = "Download";
nickjillings@2136 290 this.print.setAttribute("name","download");
nickjillings@2135 291 this.print.addEventListener("click",this);
nickjillings@2135 292 this.root.appendChild(this.downloadDOM);
nickjillings@2135 293 this.buildTable = function() {
nickjillings@2135 294 var table = document.createElement("table");
nickjillings@2135 295 table.border = "1";
nickjillings@2172 296 var numRows = this.data.getNumberOfRows();
nickjillings@2172 297 var numColumns = this.data.getNumberOfColumns();
nickjillings@2172 298 for (var columnIndex=0; columnIndex<numColumns; columnIndex++)
nickjillings@2172 299 {
nickjillings@2181 300 var tableTitle = this.data.getColumnLabel(columnIndex);
nickjillings@2181 301 if (tableTitle != "") {
nickjillings@2181 302 var table_row = document.createElement('tr');
nickjillings@2181 303 table.appendChild(table_row);
nickjillings@2181 304 var row_title = document.createElement('td');
nickjillings@2181 305 table_row.appendChild(row_title);
nickjillings@2181 306 row_title.textContent = tableTitle;
nickjillings@2181 307 for (var rowIndex=0; rowIndex<numRows; rowIndex++)
nickjillings@2172 308 {
nickjillings@2181 309 var row_entry = document.createElement('td');
nickjillings@2181 310 table_row.appendChild(row_entry);
nickjillings@2181 311 var entry = this.data.getValue(rowIndex,columnIndex);
nickjillings@2181 312 if (isFinite(Number(entry)))
nickjillings@2181 313 {
nickjillings@2181 314 entry = String(Number(entry).toFixed(4));
nickjillings@2181 315 }
nickjillings@2181 316 row_entry.textContent = entry;
nickjillings@2172 317 }
nickjillings@2135 318 }
nickjillings@2135 319 }
nickjillings@2135 320 this.tableDOM.appendChild(table);
nickjillings@2135 321 };
nickjillings@2135 322 this.writeLatex = function() {
nickjillings@2172 323 var numRows = this.data.getNumberOfRows();
nickjillings@2172 324 var numColumns = this.data.getNumberOfColumns();
nickjillings@2135 325 var root = document.createElement("div");
nickjillings@2135 326 root.className = "code";
nickjillings@2135 327 var holder = document.createElement("pre");
nickjillings@2135 328 // Table start
nickjillings@2135 329 var start = document.createElement("p");
nickjillings@2135 330 start.textContent = "\\" + "begin{tabular}{|l|";
nickjillings@2135 331 holder.appendChild(start);
nickjillings@2172 332 for (var i=0; i<numRows; i++) {
nickjillings@2135 333 start.textContent = start.textContent+"c|";
nickjillings@2135 334 }
nickjillings@2136 335 start.textContent = start.textContent.concat("}");
nickjillings@2135 336 // Now write the rows:
nickjillings@2172 337 for (var rIndex=0; rIndex<numColumns; rIndex++) {
nickjillings@2181 338 var tableTitle = this.data.getColumnLabel(rIndex);
nickjillings@2181 339 if(tableTitle != "")
nickjillings@2181 340 {
nickjillings@2181 341 var row = document.createElement("p");
nickjillings@2181 342 row.textContent = tableTitle.concat(" & ");
nickjillings@2181 343 for (var cIndex=0; cIndex<numRows; cIndex++) {
nickjillings@2181 344 var entry = this.data.getValue(cIndex,rIndex);
nickjillings@2181 345 if (isFinite(Number(entry)))
nickjillings@2181 346 {
nickjillings@2181 347 entry = String(Number(entry).toFixed(4));
nickjillings@2181 348 }
nickjillings@2181 349 row.textContent = row.textContent.concat(entry);
nickjillings@2181 350 if (cIndex < numRows-1) {
nickjillings@2181 351 row.textContent = row.textContent.concat(" & ");
nickjillings@2181 352 } else {
nickjillings@2181 353 row.textContent = row.textContent.concat(" \\\\ \\hline");
nickjillings@2181 354 }
nickjillings@2172 355 }
nickjillings@2181 356 holder.appendChild(row);
nickjillings@2135 357 }
nickjillings@2135 358 }
nickjillings@2135 359 // Table end
nickjillings@2135 360 var end = document.createElement("p");
nickjillings@2135 361 end.textContent = "\\" + "end{tabular}";
nickjillings@2135 362 holder.appendChild(end);
nickjillings@2135 363 root.appendChild(holder);
nickjillings@2135 364 this.latexDOM.appendChild(root);
nickjillings@2135 365 }
nickjillings@2135 366 }
nickjillings@2135 367
nickjillings@2135 368 this.clear = function() {
nickjillings@2135 369 var inject = document.getElementById("test-pages");
nickjillings@2135 370 for (var chart of this.charts) {
nickjillings@2135 371 inject.removeChild(chart.root);
nickjillings@2135 372 }
nickjillings@2135 373 this.charts = [];
nickjillings@2135 374 }
nickjillings@2135 375
nickjillings@2135 376 this.drawTestMean = function() {
nickjillings@2135 377 // This draws one bargraph per axis with every test element on
nickjillings@2135 378 if (this.valueData == null) {
nickjillings@2135 379 console.log("Error - Data not loaded");
nickjillings@2135 380 return;
nickjillings@2135 381 }
nickjillings@2135 382 var chartList = [];
nickjillings@2135 383
nickjillings@2135 384 // Create the data table
nickjillings@2135 385 for (var page of this.valueData.pages) {
nickjillings@2135 386 for (var element of page.elements) {
nickjillings@2135 387 for (var axis of element.axis) {
nickjillings@2135 388 // Find the axis
nickjillings@2135 389 var axisChart = chartList.find(function(element,index,array){
nickjillings@2135 390 if (element.name == this) {return true;} else {return false;}
nickjillings@2181 391 },"mean-test-"+axis.name);
nickjillings@2135 392 if (axisChart == null) {
nickjillings@2181 393 axisChart = new this.chartObject("mean-test-"+axis.name);
nickjillings@2135 394 axisChart.options = {
nickjillings@2135 395 'title':'Mean of axis: '+axis.name,
nickjillings@2135 396 'width':window.innerWidth*0.9,
nickjillings@2135 397 'height':(window.innerWidth*0.9)/1.77
nickjillings@2135 398 }
nickjillings@2135 399 axisChart.data.addColumn('string','id');
nickjillings@2135 400 axisChart.data.addColumn('number',axis.name);
nickjillings@2135 401 chartList.push(axisChart);
nickjillings@2135 402 document.getElementById("test-pages").appendChild(axisChart.root);
nickjillings@2135 403 }
nickjillings@2135 404 var mean = arrayMean(axis.values);
nickjillings@2135 405 axisChart.data.addRow([element.id,mean]);
nickjillings@2135 406 }
nickjillings@2135 407 }
nickjillings@2135 408 }
nickjillings@2135 409
nickjillings@2135 410 // Build and push charts
nickjillings@2135 411 for (var chart of chartList) {
nickjillings@2135 412 chart.chart = new google.visualization.ColumnChart(chart.chartDOM);
nickjillings@2135 413 chart.chart.draw(chart.data,chart.options);
nickjillings@2135 414 chart.buildTable();
nickjillings@2135 415 chart.writeLatex();
nickjillings@2135 416 this.charts.push(chart);
nickjillings@2135 417 }
nickjillings@2135 418 }
nickjillings@2135 419
nickjillings@2181 420 this.drawTestBoxplot = function() {
nickjillings@2181 421 if (this.valueData == null) {
nickjillings@2181 422 console.log("Error - Data not loaded");
nickjillings@2181 423 return;
nickjillings@2181 424 }
nickjillings@2181 425 var chartList = [];
nickjillings@2181 426
nickjillings@2181 427 // Creates one chart per axis
nickjillings@2181 428
nickjillings@2181 429 // Create the data table
nickjillings@2181 430 for (var page of this.valueData.pages) {
nickjillings@2181 431 for (var element of page.elements) {
nickjillings@2181 432 for (var axis of element.axis) {
nickjillings@2181 433 // Find the axis
nickjillings@2181 434 var axisChart = chartList.find(function(element,index,array){
nickjillings@2181 435 if (element.name == this) {return true;} else {return false;}
nickjillings@2181 436 },"boxplot-test-"+axis.name);
nickjillings@2181 437 if (axisChart == null) {
nickjillings@2181 438 // Axis chart doesn't exist
nickjillings@2181 439 axisChart = new this.chartObject("boxplot-test-"+axis.name);
nickjillings@2181 440 axisChart.options = {
nickjillings@2181 441 'title':'Boxplot of axis '+axis.name,
nickjillings@2181 442 'width':window.innerWidth*0.9,
nickjillings@2181 443 'height':(window.innerWidth*0.9)/1.77,
nickjillings@2181 444 legend: {position: 'none'},
nickjillings@2181 445 lineWidth: 0,
nickjillings@2181 446 series: [{'color': '#D3362D'}],
nickjillings@2181 447 intervals: {
nickjillings@2181 448 barWidth: 1,
nickjillings@2181 449 boxWidth: 1,
nickjillings@2181 450 lineWidth: 2,
nickjillings@2181 451 style: 'boxes'
nickjillings@2181 452 },
nickjillings@2181 453 interval: {
nickjillings@2181 454 max: {
nickjillings@2181 455 style: 'bars',
nickjillings@2181 456 fillOpacity: 1,
nickjillings@2181 457 color: '#777'
nickjillings@2181 458 },
nickjillings@2181 459 min: {
nickjillings@2181 460 style: 'bars',
nickjillings@2181 461 fillOpacity: 1,
nickjillings@2181 462 color: '#777'
nickjillings@2181 463 }
nickjillings@2181 464 }
nickjillings@2181 465 };
nickjillings@2181 466 axisChart.data.addColumn('string','id');
nickjillings@2181 467 axisChart.data.addColumn('number','median');
nickjillings@2181 468 axisChart.data.addColumn({id:'max',type:'number',role:'interval'});
nickjillings@2181 469 axisChart.data.addColumn({id:'min',type:'number',role:'interval'});
nickjillings@2181 470 axisChart.data.addColumn({id:'firstQuartile',type:'number',role:'interval'});
nickjillings@2181 471 axisChart.data.addColumn({id:'median',type:'number',role:'interval'});
nickjillings@2181 472 axisChart.data.addColumn({id:'thirdQuartile',type:'number',role:'interval'});
nickjillings@2181 473 chartList.push(axisChart);
nickjillings@2181 474 document.getElementById("test-pages").appendChild(axisChart.root);
nickjillings@2181 475 }
nickjillings@2181 476 var result = boxplotRow(axis.values);
nickjillings@2181 477 axisChart.data.addRow([element.id,result.median,result.max,result.min,result.pct25,result.median,result.pct75]);
nickjillings@2181 478 }
nickjillings@2181 479 }
nickjillings@2181 480 }
nickjillings@2181 481 // Build and push charts
nickjillings@2181 482 for (var chart of chartList) {
nickjillings@2181 483 chart.chart = new google.visualization.LineChart(chart.chartDOM);
nickjillings@2181 484 chart.chart.draw(chart.data,chart.options);
nickjillings@2181 485 chart.buildTable();
nickjillings@2181 486 chart.writeLatex();
nickjillings@2181 487 this.charts.push(chart);
nickjillings@2181 488 }
nickjillings@2181 489 }
nickjillings@2181 490
nickjillings@2135 491 this.drawPageMean = function() {
nickjillings@2131 492 // First we must get the value data
nickjillings@2134 493 if (this.valueData == null) {
nickjillings@2134 494 console.log("Error - Data not loaded");
nickjillings@2134 495 return;
nickjillings@2134 496 }
nickjillings@2134 497 // We create one plot per page
nickjillings@2134 498 for (var page of this.valueData.pages) {
nickjillings@2135 499
nickjillings@2135 500 // Create the chart resulting point
nickjillings@2135 501 var chart = new this.chartObject("mean-page-"+page.id);
nickjillings@2135 502 document.getElementById("test-pages").appendChild(chart.root);
nickjillings@2134 503
nickjillings@2134 504 // Create the data table
nickjillings@2135 505 chart.data.addColumn('string','id');
nickjillings@2134 506 // Get axis labels
nickjillings@2134 507 for (var axis of page.elements[0].axis) {
nickjillings@2135 508 chart.data.addColumn('number',axis.name);
nickjillings@2134 509 }
nickjillings@2134 510 var rows = []; // Rows is an array of tuples [col1, col2, col3 ... colN];
nickjillings@2134 511 for (var element of page.elements) {
nickjillings@2134 512 var entry = [element.id];
nickjillings@2134 513 for (var i=0; i<page.elements[0].axis.length; i++) {
nickjillings@2134 514 var mean =0;
nickjillings@2134 515 if (i < element.axis.length) {
nickjillings@2134 516 var axis = element.axis[i];
nickjillings@2135 517 mean = arrayMean(axis.values);
nickjillings@2134 518 }
nickjillings@2134 519 entry.push(mean);
nickjillings@2134 520 }
nickjillings@2134 521 rows.push(entry);
nickjillings@2134 522 }
nickjillings@2135 523 chart.data.addRows(rows);
nickjillings@2135 524 chart.options = {
nickjillings@2135 525 'title':'Mean of page: '+page.id,
nickjillings@2135 526 'width':800,
nickjillings@2135 527 'height':700
nickjillings@2135 528 }
nickjillings@2134 529 // Draw the chart
nickjillings@2135 530 chart.chart = new google.visualization.ColumnChart(chart.chartDOM);
nickjillings@2135 531 chart.chart.draw(chart.data,chart.options);
nickjillings@2135 532 chart.buildTable();
nickjillings@2135 533 chart.writeLatex();
nickjillings@2135 534 this.charts.push(chart);
nickjillings@2135 535 }
nickjillings@2135 536 }
nickjillings@2135 537
nickjillings@2135 538 this.drawElementHistogram = function() {
nickjillings@2135 539 // First we must get the value data
nickjillings@2135 540 if (this.valueData == null) {
nickjillings@2135 541 console.log("Error - Data not loaded");
nickjillings@2135 542 return;
nickjillings@2135 543 }
nickjillings@2135 544 // We create one plot per element, enjoy...
nickjillings@2135 545 for (var page of this.valueData.pages) {
nickjillings@2135 546 for (var element of page.elements) {
nickjillings@2135 547 // Build the chart object
nickjillings@2135 548 var chart = new this.chartObject("histogram-element-"+element.id);
nickjillings@2135 549 document.getElementById("test-pages").appendChild(chart.root);
nickjillings@2135 550 chart.data.addColumn('string','index');
nickjillings@2135 551 var histograms = [];
nickjillings@2135 552 for (var axis of element.axis) {
nickjillings@2135 553 chart.data.addColumn('number',axis.name);
nickjillings@2135 554 histograms.push(arrayHistogram(axis.values,0.125,0.0,1.0));
nickjillings@2135 555 }
nickjillings@2135 556 for (var axis of element.axis) {
nickjillings@2135 557 for (var i=0; i<histograms[0].length; i++)
nickjillings@2135 558 {
nickjillings@2135 559 var entry = [""+histograms[0][i].lt.toPrecision(2)+"-"+histograms[0][i].rt.toPrecision(3)]
nickjillings@2135 560 for (var histogram of histograms) {
nickjillings@2135 561 entry.push(histogram[i].count);
nickjillings@2135 562 }
nickjillings@2135 563 chart.data.addRow(entry);
nickjillings@2135 564 }
nickjillings@2135 565 }
nickjillings@2135 566 chart.options = {
nickjillings@2135 567 'title':'Histogram of element: '+element.id,
nickjillings@2135 568 'width':800,
nickjillings@2135 569 'height':700,
nickjillings@2135 570 'bar':{'groupWidth': '100%'}
nickjillings@2135 571 }
nickjillings@2135 572 // Draw the chart
nickjillings@2135 573 chart.chart = new google.visualization.ColumnChart(chart.chartDOM);
nickjillings@2135 574 chart.chart.draw(chart.data,chart.options);
nickjillings@2135 575 chart.buildTable();
nickjillings@2135 576 chart.writeLatex();
nickjillings@2135 577 this.charts.push(chart);
nickjillings@2135 578 }
nickjillings@2134 579 }
nickjillings@2131 580 }
nickjillings@2192 581 }
nickjillings@2192 582
nickjillings@2192 583 function Data() {
nickjillings@2192 584 // This holds the link between the server side calculations and the client side visualisation of the data
nickjillings@2192 585
nickjillings@2192 586 // Dynamically generate the test filtering / page filterting tools
nickjillings@2192 587 var self = this;
nickjillings@2192 588 // Collect the test types and counts
nickjillings@2192 589 this.testSavedDiv = document.getElementById("test-saved");
nickjillings@2192 590 this.testSaves = null;
nickjillings@2192 591 this.selectURL = null;
nickjillings@2193 592
nickjillings@2192 593 this.specification = new Specification();
nicholas@2224 594 get("../xml/test-schema.xsd").then(function(response){
nickjillings@2192 595 var parse = new DOMParser();
nickjillings@2192 596 self.specification.schema = parse.parseFromString(response,'text/xml');
nickjillings@2192 597 },function(error){
nickjillings@2192 598 console.log("ERROR: Could not get Test Schema");
nickjillings@2192 599 });
nickjillings@2192 600 this.update = function(url) {
nickjillings@2192 601 var self = this;
nickjillings@2192 602 }
nickjillings@2193 603
nickjillings@2193 604 this.updateData = function(req_str) {
nickjillings@2193 605 // Now go get that data
nickjillings@2193 606 get(req_str).then(function(response){
nickjillings@2193 607 // Returns the data
nickjillings@2193 608 chartContext.valueData = JSON.parse(response);
nickjillings@2193 609 },function(error){console.error(error);});
nickjillings@2193 610 }
nickjillings@2192 611 }
nickjillings@2192 612
nickjillings@2192 613 var interfaceContext = new function() {
nickjillings@2192 614 // This creates the interface for the user to connect with the dynamic back-end to retrieve data
nickjillings@2192 615 this.rootDOM = document.createElement("div");
nickjillings@2193 616 this.getDataButton = {
nickjillings@2193 617 button: document.createElement("button"),
nickjillings@2193 618 parent: this,
nickjillings@2193 619 handleEvent: function(event) {
nickjillings@2193 620 // Get the list of files:
nicholas@2224 621 var req_str = "../php/get_filtered_score.php"+this.parent.getFilterString();
nickjillings@2193 622 testData.updateData(req_str);
nickjillings@2193 623 }
nickjillings@2193 624 }
nickjillings@2193 625 this.getDataButton.button.textContent = "Get Filtered Data";
nickjillings@2193 626 this.getDataButton.button.addEventListener("click",this.getDataButton);
nickjillings@2193 627
nicholas@2287 628 this.getRawScoreData = {
nicholas@2287 629 root: document.createElement("div"),
nicholas@2287 630 csvDOM: document.createElement("button"),
nicholas@2287 631 jsonDOM: document.createElement("button"),
nicholas@2287 632 xmlDOM: document.createElement("button"),
nicholas@2287 633 presentDOM: document.createElement("div"),
nicholas@2287 634 parent: this,
nicholas@2287 635 XHR: new XMLHttpRequest(),
nicholas@2287 636 handleEvent: function(event) {
nicholas@2287 637 this.presentDOM.innerHTML = null;
nicholas@2287 638 var url = "../php/get_filtered_score.php"+this.parent.getFilterString();
nicholas@2287 639 this.XHR.open("GET",url+"&format="+event.currentTarget.textContent,true);
nicholas@2287 640 switch(event.currentTarget.textContent) {
nicholas@2287 641 case "CSV":
nicholas@2287 642 this.XHR.onload = function() {
nicholas@2287 643 var file = [this.response];
nicholas@2287 644 var bb = new Blob(file,{type: 'text/csv'});
nicholas@2287 645 this.parent.presentDOM.appendChild( this.parent.generateLink(bb,"scores.csv") );
nicholas@2287 646 }
nicholas@2287 647 break;
nicholas@2287 648 case "JSON":
nicholas@2287 649 this.XHR.onload = function() {
nicholas@2287 650 var file = [this.response];
nicholas@2287 651 var bb = new Blob(file,{type: 'application/json'});
nicholas@2287 652 this.parent.presentDOM.appendChild( this.parent.generateLink(bb,"scores.json") );
nicholas@2287 653 }
nicholas@2287 654 break;
nicholas@2287 655 case "XML":
nicholas@2287 656 this.XHR.onload = function() {
nicholas@2287 657 var file = [this.response];
nicholas@2287 658 var bb = new Blob(file,{type: 'text/xml'});
nicholas@2287 659 this.parent.presentDOM.appendChild( this.parent.generateLink(bb,"scores.xml") );
nicholas@2287 660 }
nicholas@2287 661 break;
nicholas@2287 662 }
nicholas@2287 663 this.XHR.send();
nicholas@2287 664 },
nicholas@2287 665 generateLink: function(blob,filename) {
nicholas@2287 666 var dnlk = window.URL.createObjectURL(blob);
nicholas@2287 667 var a = document.createElement("a");
nicholas@2287 668 a.hidden = '';
nicholas@2287 669 a.href = dnlk;
nicholas@2287 670 a.download = filename;
nicholas@2287 671 a.textContent = "Save File";
nicholas@2287 672 return a;
nicholas@2287 673 }
nicholas@2287 674 }
nicholas@2287 675
nicholas@2287 676 this.getRawScoreData.root.appendChild(this.getRawScoreData.csvDOM);
nicholas@2287 677 this.getRawScoreData.root.appendChild(this.getRawScoreData.jsonDOM);
nicholas@2287 678 this.getRawScoreData.root.appendChild(this.getRawScoreData.xmlDOM);
nicholas@2287 679 this.getRawScoreData.root.appendChild(this.getRawScoreData.presentDOM);
nicholas@2287 680 this.getRawScoreData.XHR.parent = this.getRawScoreData;
nicholas@2287 681 this.getRawScoreData.csvDOM.textContent = 'CSV';
nicholas@2287 682 this.getRawScoreData.csvDOM.addEventListener('click',this.getRawScoreData);
nicholas@2287 683 this.getRawScoreData.jsonDOM.textContent = 'JSON';
nicholas@2287 684 this.getRawScoreData.jsonDOM.addEventListener('click',this.getRawScoreData);
nicholas@2287 685 this.getRawScoreData.xmlDOM.textContent = 'XML';
nicholas@2287 686 this.getRawScoreData.xmlDOM.addEventListener('click',this.getRawScoreData);
nicholas@2287 687
nickjillings@2195 688 this.testSaves = {
nickjillings@2195 689 json: null,
nickjillings@2195 690 selectedURL: null,
nickjillings@2195 691 inputs: [],
nickjillings@2195 692 parent: this
nickjillings@2195 693 };
nickjillings@2195 694 this.init = function() {
nickjillings@2195 695 var self = this;
nicholas@2224 696 get('../php/get_tests.php?format=JSON').then(function(response){
nickjillings@2195 697 document.getElementById("test-saved").innerHTML = null;
nickjillings@2195 698 var table = document.createElement("table");
nickjillings@2195 699 table.innerHTML = "<tr><td>Test Filename</td><td>Count</td><td>Include</td></tr>";
nickjillings@2195 700 self.testSaves.json = JSON.parse(response);
nickjillings@2195 701 for (var test of self.testSaves.json.tests) {
nickjillings@2195 702 var tableRow = document.createElement("tr");
nickjillings@2195 703 var tableRowFilename = document.createElement("td");
nickjillings@2195 704 tableRowFilename.textContent = test.testName;
nickjillings@2195 705 var tableRowCount = document.createElement("td");
nickjillings@2195 706 tableRowCount.textContent = test.files.length;
nickjillings@2195 707 tableRow.appendChild(tableRowFilename);
nickjillings@2195 708 tableRow.appendChild(tableRowCount);
nickjillings@2195 709 var tableRowInclude = document.createElement("td");
nickjillings@2195 710 var obj = {
nickjillings@2195 711 root: document.createElement("input"),
nickjillings@2195 712 parent: self.testSaves,
nickjillings@2195 713 handleEvent: function(event) {
nickjillings@2195 714 this.parent.selectedURL = event.currentTarget.getAttribute("source");
nickjillings@2195 715 var self = this;
nickjillings@2195 716 get(this.parent.selectedURL).then(function(response){
nickjillings@2195 717 var parse = new DOMParser();
nickjillings@2195 718 testData.specification.decode(parse.parseFromString(response,'text/xml'));
nickjillings@2195 719 self.parent.parent.generateFilters(testData.specification);
nickjillings@2195 720 self.parent.parent.getFileCount();
nickjillings@2195 721 return true;
nickjillings@2195 722 },function(error){
nickjillings@2195 723 console.log("ERROR: Could not get"+url);
nickjillings@2195 724 return false;
nickjillings@2195 725 });
nickjillings@2195 726 }
nickjillings@2195 727 }
nickjillings@2195 728 obj.root.type = "radio";
nickjillings@2195 729 obj.root.name = "test-include";
nickjillings@2195 730 obj.root.setAttribute("source",test.testName);
nickjillings@2195 731 obj.root.addEventListener("change",obj);
nickjillings@2195 732 tableRowInclude.appendChild(obj.root);
nickjillings@2195 733 tableRow.appendChild(tableRowInclude);
nickjillings@2195 734 table.appendChild(tableRow);
nickjillings@2195 735 self.testSaves.inputs.push(obj);
nickjillings@2195 736 }
nickjillings@2195 737 document.getElementById("test-saved").appendChild(table);
nickjillings@2195 738 },function(error){console.error(error);});
nickjillings@2195 739 }
nickjillings@2195 740
nickjillings@2192 741 this.filterDOM = document.createElement("div");
nickjillings@2192 742 this.filterDOM.innerHTML = "<p>PreTest Filters</p><div id='filter-count'></div>";
nickjillings@2192 743 this.filterObjects = [];
nickjillings@2192 744 this.generateFilters = function(specification) {
nickjillings@2192 745 // Filters are based on the pre and post global surverys
nickjillings@2192 746 var FilterObject = function(parent,specification) {
nickjillings@2192 747 this.parent = parent;
nickjillings@2192 748 this.specification = specification;
nickjillings@2192 749 this.rootDOM = document.createElement("div");
nickjillings@2192 750 this.rootDOM.innerHTML = "<span>ID: "+specification.id+", Type: "+specification.type+"</span>";
nickjillings@2192 751 this.rootDOM.className = "filter-entry";
nickjillings@2192 752 this.handleEvent = function(event) {
nickjillings@2192 753 switch(this.specification.type) {
nickjillings@2192 754 case "number":
nickjillings@2192 755 var name = event.currentTarget.name;
nickjillings@2192 756 eval("this."+name+" = event.currentTarget.value");
nickjillings@2192 757 break;
nickjillings@2192 758 case "checkbox":
nickjillings@2192 759 break;
nickjillings@2192 760 case "radio":
nickjillings@2192 761 break;
nickjillings@2192 762 }
nickjillings@2192 763 this.parent.getFileCount();
nickjillings@2192 764 }
nickjillings@2192 765 this.getFilterPairs = function() {
nickjillings@2192 766 var pairs = [];
nickjillings@2192 767 switch(this.specification.type) {
nickjillings@2192 768 case "number":
nickjillings@2192 769 if (this.min != "") {
nickjillings@2192 770 pairs.push([specification.id+"-min",this.min]);
nickjillings@2192 771 }
nickjillings@2192 772 if (this.max != "") {
nickjillings@2192 773 pairs.push([specification.id+"-max",this.max]);
nickjillings@2192 774 }
nickjillings@2192 775 break;
nickjillings@2192 776 case "radio":
nickjillings@2192 777 case "checkbox":
nickjillings@2192 778 for (var i=0; i<this.options.length; i++) {
nickjillings@2192 779 if (!this.options[i].checked) {
nickjillings@2192 780 pairs.push([specification.id+"-exclude-"+i,specification.options[i].name]);
nickjillings@2192 781 }
nickjillings@2192 782 }
nickjillings@2192 783 break;
nickjillings@2192 784 }
nickjillings@2192 785 return pairs;
nickjillings@2192 786 }
nickjillings@2192 787 switch(specification.type) {
nickjillings@2192 788 case "number":
nickjillings@2192 789 // Number can be ranged by min/max levels
nickjillings@2192 790 this.min = "";
nickjillings@2192 791 this.max = "";
nickjillings@2192 792 this.minDOM = document.createElement("input");
nickjillings@2192 793 this.minDOM.type = "number";
nickjillings@2192 794 this.minDOM.name = "min";
nickjillings@2192 795 this.minDOM.addEventListener("change",this);
nickjillings@2192 796 this.minDOMText = document.createElement("span");
nickjillings@2192 797 this.minDOMText.textContent = "Minimum: ";
nickjillings@2192 798 var pairHolder = document.createElement("div");
nickjillings@2192 799 pairHolder.appendChild(this.minDOMText);
nickjillings@2192 800 pairHolder.appendChild(this.minDOM);
nickjillings@2192 801 this.rootDOM.appendChild(pairHolder);
nickjillings@2192 802
nickjillings@2192 803 this.maxDOM = document.createElement("input");
nickjillings@2192 804 this.maxDOM.type = "number";
nickjillings@2192 805 this.maxDOM.name = "max";
nickjillings@2192 806 this.maxDOM.addEventListener("change",this);
nickjillings@2192 807 this.maxDOMText = document.createElement("span");
nickjillings@2192 808 this.maxDOMText.textContent = "Maximum: ";
nickjillings@2192 809 var pairHolder = document.createElement("div");
nickjillings@2192 810 pairHolder.appendChild(this.maxDOMText);
nickjillings@2192 811 pairHolder.appendChild(this.maxDOM);
nickjillings@2192 812 this.rootDOM.appendChild(pairHolder);
nickjillings@2192 813 break;
nickjillings@2192 814 case "radio":
nickjillings@2192 815 case "checkbox":
nickjillings@2192 816 this.options = [];
nickjillings@2192 817 for (var i=0; i<specification.options.length; i++) {
nickjillings@2192 818 var option = specification.options[i];
nickjillings@2192 819 var pairHolder = document.createElement("div");
nickjillings@2192 820 var text = document.createElement("span");
nickjillings@2192 821 text.textContent = option.text;
nickjillings@2192 822 var check = document.createElement("input");
nickjillings@2192 823 check.type = "checkbox";
nickjillings@2192 824 check.setAttribute("option-index",i);
nickjillings@2192 825 check.checked = true;
nickjillings@2192 826 check.addEventListener("click",this);
nickjillings@2192 827 this.options.push(check);
nickjillings@2192 828 pairHolder.appendChild(text);
nickjillings@2192 829 pairHolder.appendChild(check);
nickjillings@2192 830 this.rootDOM.appendChild(pairHolder);
nickjillings@2192 831 }
nickjillings@2192 832 break;
nickjillings@2192 833 default:
nickjillings@2192 834 break;
nickjillings@2192 835 }
nickjillings@2192 836 }
nicholas@2251 837 var options = [];
nicholas@2251 838 if(specification.preTest) {
nicholas@2251 839 options = options.concat(specification.preTest.options);
nicholas@2251 840 }
nicholas@2251 841 if (specification.postTest) {
nicholas@2251 842 options = options.concat(specification.postTest.options);
nicholas@2251 843 }
nicholas@2251 844 for (var survey_entry of options) {
nickjillings@2192 845 switch(survey_entry.type) {
nickjillings@2192 846 case "number":
nickjillings@2192 847 case "radio":
nickjillings@2192 848 case "checkbox":
nickjillings@2192 849 var node = new FilterObject(this,survey_entry);
nickjillings@2192 850 this.filterObjects.push(node);
nickjillings@2192 851 this.filterDOM.appendChild(node.rootDOM);
nickjillings@2192 852 break;
nickjillings@2192 853 default:
nickjillings@2192 854 break;
nickjillings@2192 855 }
nickjillings@2192 856 }
nickjillings@2192 857 document.getElementById("test-saved").appendChild(this.filterDOM);
nickjillings@2193 858 document.getElementById("test-saved").appendChild(this.getDataButton.button);
nicholas@2287 859 document.getElementById("test-saved").appendChild(this.getRawScoreData.root);
nickjillings@2192 860 }
nickjillings@2193 861 this.getFilterString = function() {
nickjillings@2192 862 var pairs = [];
nickjillings@2192 863 for (var obj of this.filterObjects) {
nickjillings@2192 864 pairs = pairs.concat(obj.getFilterPairs());
nickjillings@2192 865 }
nickjillings@2195 866 var req_str = "?url="+this.testSaves.selectedURL;
nickjillings@2192 867 var index = 0;
nickjillings@2192 868 while(pairs[index] != undefined) {
nickjillings@2192 869 req_str += '&';
nickjillings@2192 870 req_str += pairs[index][0]+"="+pairs[index][1];
nickjillings@2192 871 index++;
nickjillings@2192 872 }
nickjillings@2193 873 return req_str;
nickjillings@2193 874 }
nickjillings@2193 875 this.getFilteredUrlArray = function() {
nicholas@2224 876 var req_str = "../php/get_filtered_count.php"+this.getFilterString();
nickjillings@2193 877 return get(req_str).then(function(response){
nickjillings@2192 878 var urls = JSON.parse(response);
nickjillings@2193 879 return urls.urls;
nickjillings@2193 880 },function(error){
nickjillings@2193 881 console.error(error);
nickjillings@2193 882 });
nickjillings@2193 883 }
nickjillings@2193 884 this.getFileCount = function() {
nickjillings@2193 885 // First we must get the filter pairs
nickjillings@2193 886 this.getFilteredUrlArray().then(function(response){
nickjillings@2193 887 var str = "Filtered to "+response.length+" file";
nickjillings@2193 888 if (response.length != 1) {
nickjillings@2192 889 str += "s.";
nickjillings@2192 890 } else {
nickjillings@2192 891 str += ".";
nickjillings@2192 892 }
nickjillings@2192 893 document.getElementById("filter-count").textContent = str;
nickjillings@2193 894 },function(error){});
nickjillings@2192 895 }
nickjillings@2195 896
nickjillings@2195 897 this.init();
nickjillings@2131 898 }