comparison analyse.html @ 336:378726f0ac91 WAC2016

Paper: Added interface screenshot and box plot example
author Brecht De Man <b.deman@qmul.ac.uk>
date Thu, 15 Oct 2015 20:10:00 +0100
parents 5f27d3eb93fe
children de9a0a740b6e
comparison
equal deleted inserted replaced
335:c1b548fbb87c 336:378726f0ac91
16 // To aid 'one-page set-up' all scripts and CSS must be included directly in this file! 16 // To aid 'one-page set-up' all scripts and CSS must be included directly in this file!
17 17
18 google.load("visualization", "1", {packages:["corechart"]}); 18 google.load("visualization", "1", {packages:["corechart"]});
19 19
20 /************* 20 /*************
21 * SETUP * 21 * SETUP *
22 *************/ 22 *************/
23 // folder where to find the XML files 23 // folder where to find the XML files
24 xmlFileFolder = "saves"; 24 xmlFileFolder = "analysis_test";
25 // array of XML files 25 // array of XML files
26 var xmlFiles = ['McG-A-2014-03.xml','McG-B-2014-03.xml','McG-C-2014-03.xml']; 26 var xmlFiles = ['QM-1-1.xml','QM-2-1.xml','QM-2-2.xml','QM-2-3.xml','QM-3-1.xml','QM-3-2.xml','QM-4-1.xml','QM-5-1.xml','QM-5-2.xml','QM-6-1.xml','QM-6-2.xml','QM-7-1.xml','QM-7-2.xml','QM-8-1.xml','QM-9-1.xml','QM-10-1.xml','QM-11-1.xml','QM-12-1.xml','QM-12-2.xml','QM-13-1.xml','QM-14-1.xml','QM-15-1.xml','QM-16-1.xml','QM-17-1.xml','QM-18-1.xml','QM-18-2.xml','QM-18-3.xml','QM-19-1.xml','QM-20-1.xml','QM-20-2.xml','QM-20-3.xml','QM-21-1.xml','QM-21-2.xml'];
27 //['McG-A-2014-03.xml','McG-B-2014-03.xml','McG-C-2014-03.xml','McG-D-2014-03.xml','McG-E-2014-03.xml','McG-F-2014-03.xml','McG-G-2014-03.xml','McG-H-2014-03.xml'];
27 28
28 //TODO: make retrieval of file names automatic / drag files on here 29 //TODO: make retrieval of file names automatic / drag files on here
29 30
30 /**************** 31 /****************
31 * VARIABLES * 32 * VARIABLES *
32 ****************/ 33 ****************/
33 34
34 // Counters 35 // Counters
35 // How many files, audioHolders, audioElementes and statements annotated (don't count current one) 36 // How many files, audioholders, audioelementes and statements annotated (don't count current one)
36 var numberOfFiles = -1; 37 var numberOfFiles = -1;
37 var numberOfaudioHolders = -1; 38 var numberOfaudioholders = -1;
38 var numberOfaudioElementes = -1; 39 var numberOfaudioelementes = -1;
39 var numberOfStatements = -1; 40 var numberOfStatements = -1;
40 var numberOfSkippedComments = 0; 41 var numberOfSkippedComments = 0;
41 42
42 // Object arrays 43 // Object arrays
43 var fileNameArray = []; 44 var fileNameArray = [];
44 var subjectArray = []; 45 var subjectArray = [];
45 var audioHolderArray = []; 46 var audioholderArray = [];
46 var audioElementArray = []; 47 var audioelementArray = [];
47 48
48 // End of (file, audioholder, audioelement) flags 49 // End of (file, audioholder, audioelement) flags
49 var newFile = true; 50 var newFile = true;
50 var newAudioHolder = true; 51 var newAudioHolder = true;
51 var newAudioElement = true; 52 var newAudioElement = true;
52 53
53 var fileCounter = 0; // file index 54 var fileCounter = 0; // file index
54 var audioHolderCounter=0; // audioholder index (current XML file) 55 var audioholderCounter=0; // audioholder index (current XML file)
55 var audioElementCounter=0; // audioelement index (current audioholder) 56 var audioelementCounter=0; // audioelement index (current audioholder)
56 var statementNumber=0; // total number of statements 57 var statementNumber=0; // total number of statements
57 58
58 var root; // root of XML file 59 var root; // root of XML file
59 var commentInFull = ''; // full comment 60 var commentInFull = ''; // full comment
60 61
90 } 91 }
91 throw message; // Fallback 92 throw message; // Fallback
92 } 93 }
93 } 94 }
94 95
95 function median(values) { 96 function median(values) { // TODO: replace code by '50th percentile' - should be the same?
96 values.sort( function(a,b) {return a - b;} ); 97 values.sort( function(a,b) {return a - b;} );
97 var half = Math.floor(values.length/2); 98 var half = Math.floor(values.length/2);
98 if(values.length % 2) 99 if(values.length % 2)
99 return values[half]; 100 return values[half];
100 else 101 else
101 return (values[half-1] + values[half]) / 2.0; 102 return (values[half-1] + values[half]) / 2.0;
102 } 103 }
104
105 function percentile(values, n) {
106 values.sort( function(a,b) {return a - b;} );
107 // get ordinal rank
108 var rank = Math.min(Math.floor(values.length*n/100), values.length-1);
109 return values[rank];
110 }
103 111
104 /*********************** 112 /***********************
105 * TIME MEASUREMENT * 113 * TIME MEASUREMENT *
106 ************************/ 114 ************************/
107 115
108 // measure time since last time this function was called 116 // measure time since last time this function was called
109 function timeSinceLastCall() { 117 function timeSinceLastCall() {
110 // current time 118 // current time
195 return averageOfTimes; 203 return averageOfTimes;
196 } 204 }
197 205
198 206
199 /******************************** 207 /********************************
200 * PLAYBACK OF AUDIO * 208 * PLAYBACK OF AUDIO *
201 ********************************/ 209 ********************************/
202 210
203 //PLAYaudioElement 211 //PLAYaudioelement
204 // Keep track of whether audio should be played 212 // Keep track of whether audio should be played
205 function playFlagChanged(){ 213 function playFlagChanged(){
206 playAudio = playFlag.checked; // global variable 214 playAudio = playFlag.checked; // global variable
207 215
208 if (!playAudio){ // if audio needs to stop 216 if (!playAudio){ // if audio needs to stop
209 audio.pause(); // stop audio - if anything is playing 217 audio.pause(); // stop audio - if anything is playing
210 currently_playing = ''; // back to empty string so playaudioElement knows nothing's playing 218 currently_playing = ''; // back to empty string so playaudioelement knows nothing's playing
211 } 219 }
212 } 220 }
213 221
214 // audioHolder that's currently playing 222 // audioholder that's currently playing
215 var currently_playing_audioHolder = ''; // at first: empty string 223 var currently_playing_audioholder = ''; // at first: empty string
216 var currently_playing_audioElement = ''; 224 var currently_playing_audioelement = '';
217 var audio; 225 var audio;
218 226
219 // Play audioElement of audioHolder if available, from start or from same position 227 // Play audioelement of audioholder if available, from start or from same position
220 function playaudioElement(audioHolderName, audioElementerName){ 228 function playaudioelement(audioholderName, audioelementerName){
221 if (playAudio) { // if enabled 229 if (playAudio) { // if enabled
222 // get corresponding file from folder 230 // get corresponding file from folder
223 var file_location = 'audio/'+audioHolderName + '/' + audioElementerName + '.mp3'; // fixed path and file name format 231 var file_location = 'audio/'+audioholderName + '/' + audioelementerName + '.mp3'; // fixed path and file name format
224 232
225 // if not available, show error/warning message 233 // if not available, show error/warning message
226 //TODO ... 234 //TODO ...
227 235
228 // if nothing playing yet, start playing 236 // if nothing playing yet, start playing
229 if (currently_playing_audioHolder == ''){ // signal that nothing is playing 237 if (currently_playing_audioholder == ''){ // signal that nothing is playing
230 //playSound(audioBuffer); 238 //playSound(audioBuffer);
231 audio = new Audio(file_location); 239 audio = new Audio(file_location);
232 audio.loop = true; // loop when end is reached 240 audio.loop = true; // loop when end is reached
233 audio.play(); 241 audio.play();
234 currently_playing_audioHolder = audioHolderName; 242 currently_playing_audioholder = audioholderName;
235 currently_playing_audioElement = audioElementerName; 243 currently_playing_audioelement = audioelementerName;
236 } else if (currently_playing_audioHolder != audioHolderName) { 244 } else if (currently_playing_audioholder != audioholderName) {
237 // if different audioHolder playing, stop that and start playing 245 // if different audioholder playing, stop that and start playing
238 audio.pause(); // stop audio 246 audio.pause(); // stop audio
239 audio = new Audio(file_location); // load new file 247 audio = new Audio(file_location); // load new file
240 audio.loop = true; // loop when end is reached 248 audio.loop = true; // loop when end is reached
241 audio.play(); // play audio from the start 249 audio.play(); // play audio from the start
242 currently_playing_audioHolder = audioHolderName; 250 currently_playing_audioholder = audioholderName;
243 currently_playing_audioElement = audioElementerName; 251 currently_playing_audioelement = audioelementerName;
244 } else if (currently_playing_audioElement != audioElementerName) { 252 } else if (currently_playing_audioelement != audioelementerName) {
245 // if same audioHolder playing, start playing from where it left off 253 // if same audioholder playing, start playing from where it left off
246 skipTime = audio.currentTime; // time to skip to 254 skipTime = audio.currentTime; // time to skip to
247 audio.pause(); // stop audio 255 audio.pause(); // stop audio
248 audio = new Audio(file_location); 256 audio = new Audio(file_location);
249 audio.addEventListener('loadedmetadata', function() { 257 audio.addEventListener('loadedmetadata', function() {
250 this.currentTime = skipTime; 258 this.currentTime = skipTime;
251 console.log('Loaded '+audioHolderName+'-'+audioElementerName+', playing from '+skipTime); 259 console.log('Loaded '+audioholderName+'-'+audioelementerName+', playing from '+skipTime);
252 }, false); // skip to same time when audio is loaded! 260 }, false); // skip to same time when audio is loaded!
253 audio.loop = true; // loop when end is reached 261 audio.loop = true; // loop when end is reached
254 audio.play(); // play from that time 262 audio.play(); // play from that time
255 audio.currentTime = skipTime; 263 audio.currentTime = skipTime;
256 currently_playing_audioHolder = audioHolderName; 264 currently_playing_audioholder = audioholderName;
257 currently_playing_audioElement = audioElementerName; 265 currently_playing_audioelement = audioelementerName;
258 } 266 }
259 // if same audioElement playing: keep on playing (i.e. do nothing) 267 // if same audioelement playing: keep on playing (i.e. do nothing)
260 } 268 }
261 } 269 }
262 270
263 /******************** 271 /********************
264 * READING FILES * 272 * READING FILES *
265 ********************/ 273 ********************/
266 274
267 // Read necessary data from XML file 275 // Read necessary data from XML file
268 function readXML(xmlFileName){ 276 function readXML(xmlFileName){
269 if (window.XMLHttpRequest) 277 if (window.XMLHttpRequest)
301 } 309 }
302 if (subjectArray.indexOf(subjectID.textContent) == -1) { // if not already in array 310 if (subjectArray.indexOf(subjectID.textContent) == -1) { // if not already in array
303 subjectArray.push(subjectID.textContent); // append to array 311 subjectArray.push(subjectID.textContent); // append to array
304 } 312 }
305 313
306 // go over all audioHolders, add to array if not already there 314 // go over all audioholders, add to array if not already there
307 audioHolderNodes = root.getElementsByTagName('audioholder'); 315 audioholderNodes = root.getElementsByTagName('audioholder');
308 // go over audioHolderNodes and append audioHolder name when not present yet 316 // go over audioholderNodes and append audioholder name when not present yet
309 for (audioHolderIndex = 0; audioHolderIndex < audioHolderNodes.length; audioHolderIndex++) { 317 for (audioholderIndex = 0; audioholderIndex < audioholderNodes.length; audioholderIndex++) {
310 audioHolderName = audioHolderNodes[audioHolderIndex].getAttribute('id'); 318 audioholderName = audioholderNodes[audioholderIndex].getAttribute('id');
311 if (audioHolderArray.indexOf(audioHolderName) == -1) { // if not already in array 319 if (audioholderArray.indexOf(audioholderName) == -1) { // if not already in array
312 audioHolderArray.push(audioHolderName); // append to array 320 audioholderArray.push(audioholderName); // append to array
313 } 321 }
314 // within each audioHolder, go over all audioElement IDs, add to array if not already there 322 // within each audioholder, go over all audioelement IDs, add to array if not already there
315 audioElementNodes = audioHolderNodes[audioHolderIndex].getElementsByTagName('audioelement'); 323 audioelementNodes = audioholderNodes[audioholderIndex].getElementsByTagName('audioelement');
316 for (audioElementIndex = 0; audioElementIndex < audioElementNodes.length; audioElementIndex++) { 324 for (audioelementIndex = 0; audioelementIndex < audioelementNodes.length; audioelementIndex++) {
317 audioElementName = audioElementNodes[audioElementIndex].getAttribute('id'); 325 audioelementName = audioelementNodes[audioelementIndex].getAttribute('id');
318 if (audioElementArray.indexOf(audioElementName) == -1) { // if not already in array 326 if (audioelementArray.indexOf(audioelementName) == -1) { // if not already in array
319 audioElementArray.push(audioElementName); // append to array 327 audioelementArray.push(audioelementName); // append to array
320 } 328 }
321 } 329 }
322 } 330 }
323 // count occurrences of each audioHolder 331 // count occurrences of each audioholder
324 // ... 332 // ...
325 } 333 }
326 else { 334 else {
327 console.log('XML file '+xmlFileName+' not found.'); 335 console.log('XML file '+xmlFileName+' not found.');
328 } 336 }
329 } 337 }
330 338
331 // sort alphabetically 339 // sort alphabetically
332 fileNameArray.sort(); 340 fileNameArray.sort();
333 subjectArray.sort(); 341 subjectArray.sort();
334 audioHolderArray.sort(); 342 audioholderArray.sort();
335 audioElementArray.sort(); 343 audioelementArray.sort();
336 344
337 // display all information in HTML 345 // display all information in HTML
338 // show XML file folder 346 // show XML file folder
339 document.getElementById('xmlFileFolder_span').innerHTML = "\""+xmlFileFolder+"/\""; 347 document.getElementById('xmlFileFolder_span').innerHTML = "\""+xmlFileFolder+"/\"";
340 // show number of files 348 // show number of files
341 document.getElementById('numberOfFiles_span').innerHTML = fileNameArray.length; 349 document.getElementById('numberOfFiles_span').innerHTML = fileNameArray.length;
342 // show list of subject names 350 // show list of subject names
343 document.getElementById('subjectArray_span').innerHTML = subjectArray.toString(); 351 document.getElementById('subjectArray_span').innerHTML = subjectArray.toString();
344 // show list of audioHolders 352 // show list of audioholders
345 document.getElementById('audioHolderArray_span').innerHTML = audioHolderArray.toString(); 353 document.getElementById('audioholderArray_span').innerHTML = audioholderArray.toString();
346 // show list of audioElementes 354 // show list of audioelementes
347 document.getElementById('audioElementArray_span').innerHTML = audioElementArray.toString(); 355 document.getElementById('audioelementArray_span').innerHTML = audioelementArray.toString();
348 } 356 }
349 357
350 function makePlots() { 358 function makePlots() { //TODO: split into different functions
359 // TEMPORARY
360 makeTimeline(xmlFileFolder+"/"+xmlFiles[7]);
361
351 // create value array 362 // create value array
352 var ratings = []; // 3D matrix of ratings (audioHolder, audioElement, subject) 363 var ratings = []; // 3D matrix of ratings (audioholder, audioelement, subject)
353 for (audioHolderIndex = 0; audioHolderIndex < audioHolderNodes.length; audioHolderIndex++) { 364 for (audioholderIndex = 0; audioholderIndex < audioholderArray.length; audioholderIndex++) {
354 ratings.push([]); 365 ratings.push([]);
355 for (audioElementIndex = 0; audioElementIndex < audioElementNodes.length; audioElementIndex++) { 366 for (audioelementIndex = 0; audioelementIndex < audioelementArray.length; audioelementIndex++) {
356 ratings[audioHolderIndex].push([]); 367 ratings[audioholderIndex].push([]);
357 } 368 }
358 } 369 }
359 370
360 // go over all XML files 371 // go over all XML files
361 for (fileIndex = 0; fileIndex < xmlFiles.length; fileIndex++) { 372 for (fileIndex = 0; fileIndex < xmlFiles.length; fileIndex++) {
362 xmlFileName = xmlFileFolder+"/"+xmlFiles[fileIndex]; 373 xmlFileName = xmlFileFolder+"/"+xmlFiles[fileIndex];
363 xml = readXML(xmlFileName); 374 xml = readXML(xmlFileName);
364 if (xml != null) { // if file exists 375 if (xml != null) { // if file exists
365 // get root of XML file 376 // get root of XML file
366 root = xml.getElementsByTagName('browserevaluationresult')[0]; 377 root = xml.getElementsByTagName('browserevaluationresult')[0];
367 // go over all audioHolders 378 // go over all audioholders
368 audioHolderNodes = root.getElementsByTagName('audioholder'); 379 audioholderNodes = root.getElementsByTagName('audioholder');
369 for (audioHolderIndex = 0; audioHolderIndex < audioHolderNodes.length; audioHolderIndex++) { 380 for (audioholderIndex = 0; audioholderIndex < audioholderNodes.length; audioholderIndex++) {
370 audioHolderName = audioHolderNodes[audioHolderIndex].getAttribute('id'); 381 audioholderName = audioholderNodes[audioholderIndex].getAttribute('id');
371 audioElementNodes = audioHolderNodes[audioHolderIndex].getElementsByTagName('audioelement'); 382 audioelementNodes = audioholderNodes[audioholderIndex].getElementsByTagName('audioelement');
372 // go over all audioelements 383 // go over all audioelements
373 for (audioElementIndex = 0; audioElementIndex < audioElementNodes.length; audioElementIndex++) { 384 for (audioelementIndex = 0; audioelementIndex < audioelementNodes.length; audioelementIndex++) {
374 audioElementName = audioElementNodes[audioElementIndex].getAttribute('id'); 385 audioelementName = audioelementNodes[audioelementIndex].getAttribute('id');
375 // get value 386 // get value
376 var value = audioElementNodes[audioElementIndex].getElementsByTagName("value")[0].textContent; 387 var value = audioelementNodes[audioelementIndex].getElementsByTagName("value")[0].textContent;
377 if (value) { // if not empty, null, undefined... 388 if (value) { // if not empty, null, undefined...
378 ratingValue = parseFloat(value); 389 ratingValue = parseFloat(value);
379 // add to matrix 390 // add to matrix at proper position
380 ratings[audioHolderIndex][audioElementIndex].push(ratingValue) 391 aHidx = audioholderArray.indexOf(audioholderName);
392 aEidx = audioelementArray.indexOf(audioelementName);
393 ratings[aHidx][aEidx].push(ratingValue);
381 } 394 }
382 } 395 }
383 } 396 }
384 397
385 // go over all audioHolders 398 // go over all audioholders
386 399
387 // go over all audioElements within audioHolder, see if present in idMatrix, add if not 400 // go over all audioelements within audioholder, see if present in idMatrix, add if not
388 // add corresponding rating to 'ratings', at position corresponding with position in idMatrix 401 // add corresponding rating to 'ratings', at position corresponding with position in idMatrix
389 } 402 }
390 } 403 }
391 404
392 for (audioHolderIndex = 0; audioHolderIndex < audioHolderArray.length; audioHolderIndex++) { 405 for (audioholderIndex = 0; audioholderIndex < audioholderArray.length; audioholderIndex++) {
393 audioHolderName = audioHolderArray[audioHolderIndex]; // for this song 406 audioholderName = audioholderArray[audioholderIndex]; // for this song
394 tickArray = [] 407 tickArray = []
395 medianOfAudioElement = []
396 408
397 raw_data = [['SubjectID', 'Rating']]; 409 raw_data = [['SubjectID', 'Rating']];
398 audioElIdx = 0; 410 audioElIdx = 0;
399 for (audioElementIndex = 0; audioElementIndex<ratings[audioHolderIndex].length; audioElementIndex++){ 411 for (audioelementIndex = 0; audioelementIndex<ratings[audioholderIndex].length; audioelementIndex++){
400 if (ratings[audioHolderIndex][audioElementIndex].length>0) { 412 if (ratings[audioholderIndex][audioelementIndex].length>0) {
401 audioElIdx++; // increase if not empty 413 audioElIdx++; // increase if not empty
402 // make tick label 414 // make tick label
403 tickArray.push({v:audioElIdx, f: audioElementArray[audioElementIndex]}); 415 tickArray.push({v:audioElIdx, f: audioelementArray[audioelementIndex]});
404 // add median 416 }
405 medianOfAudioElement.push(median(ratings[audioHolderIndex][audioElementIndex])); 417 for (subject = 0; subject<ratings[audioholderIndex][audioelementIndex].length; subject++){
406 }
407 for (subject = 0; subject<ratings[audioHolderIndex][audioElementIndex].length; subject++){
408 // add subject-value pair for each subject 418 // add subject-value pair for each subject
409 raw_data.push([audioElIdx, ratings[audioHolderIndex][audioElementIndex][subject]]); 419 raw_data.push([audioElIdx, ratings[audioholderIndex][audioelementIndex][subject]]);
410 } 420 }
411 } 421 }
412 422
413 // create plot (one per song) 423 // create plot (one per song)
414 var data = google.visualization.arrayToDataTable(raw_data); 424 var data = google.visualization.arrayToDataTable(raw_data);
415 425
416 var options = { 426 var options = {
417 title: audioHolderName, 427 title: audioholderName,
418 hAxis: {title: 'Subject', minValue: 0, maxValue: audioElIdx+1, 428 hAxis: {title: 'audioelement ID', minValue: 0, maxValue: audioElIdx+1,
419 ticks: tickArray}, 429 ticks: tickArray},
420 vAxis: {title: 'Rating', minValue: 0, maxValue: 1}, 430 vAxis: {title: 'Rating', minValue: 0, maxValue: 1},
421 seriesType: 'scatter', 431 seriesType: 'scatter',
422 legend: 'none' 432 legend: 'none'
423 }; 433 };
424 var div = document.createElement('div'); 434 var div = document.createElement('div');
425 document.body.appendChild(div); 435 document.body.appendChild(div);
426 div.id = 'div_'+audioHolderName; 436 div.id = 'div_'+audioholderName;
427 div.style.width = '1100px'; 437 div.style.width = '1100px';
428 div.style.height = '350px'; 438 div.style.height = '350px';
429 var chart = new google.visualization.ComboChart(document.getElementById('div_'+audioHolderName)); 439 var chart = new google.visualization.ComboChart(document.getElementById('div_'+audioholderName));
430 chart.draw(data, options); 440 chart.draw(data, options);
431 441
432 // box plots 442 // box plots
433 // function drawVisualization() { 443 var div = document.createElement('div');
434 // // Create and populate the data table. 444 document.body.appendChild(div);
435 // var data = google.visualization.arrayToDataTable([ 445 div.id = 'div_box_'+audioholderName;
436 // ['ID', 'IQR', '', '', '', 'Median', 'Average'], 446 div.style.width = '1100px';
437 // ['Serie1', 20, 28, 38, 45, 20, 25], 447 div.style.height = '350px';
438 // ['Serie2', 31, 38, 55, 66, 30, 35], 448 // Get median, percentiles, maximum and minimum; outliers.
439 // ['Serie3', 50, 55, 77, 80, 10, 15], 449 pctl25 = [];
440 // ['Serie4', 77, 77, 66, 50, 20, 25], 450 pctl75 = [];
441 // ['Serie5', 68, 66, 22, 15, 30, 35] 451 med = [];
442 // // Treat first row as data as well. 452 min = [];
443 // ]); 453 max = [];
444 // // Create and draw the visualization. 454 outlierArray = [];
445 // var ac = new google.visualization.ComboChart(document.getElementById('visualization')); 455 max_n_outliers = 0; // maximum number of outliers for one audioelement
446 // ac.draw(data, { 456 for (audioelementIndex = 0; audioelementIndex<ratings[audioholderIndex].length; audioelementIndex++){
447 // title : 'Box Plot with Median and Average', 457 med.push(median(ratings[audioholderIndex][audioelementIndex])); // median
448 // width: 600, 458 pctl25.push(percentile(ratings[audioholderIndex][audioelementIndex], 25)); // 25th percentile
449 // height: 400, 459 pctl75.push(percentile(ratings[audioholderIndex][audioelementIndex], 75)); // 75th percentile
450 // vAxis: {title: "Value"}, 460 IQR = pctl75[pctl75.length-1]-pctl25[pctl25.length-1];
451 // hAxis: {title: "Serie ID"}, 461 // outliers: range of values which is above pctl75+1.5*IQR or below pctl25-1.5*IQR
452 // series: { 0: {type: "candlesticks"}, 1: {type: "line", pointSize: 10, lineWidth: 462 outliers = [];
453 // 0 }, 2: {type: "line", pointSize: 10, lineWidth: 0, color: 'black' } } 463 rest = [];
454 // }); 464 for (idx = 0; idx<ratings[audioholderIndex][audioelementIndex].length; idx++){
455 // } 465 if (ratings[audioholderIndex][audioelementIndex][idx] > pctl75[pctl75.length-1]+1.5*IQR ||
466 ratings[audioholderIndex][audioelementIndex][idx] < pctl25[pctl25.length-1]-1.5*IQR){
467 outliers.push(ratings[audioholderIndex][audioelementIndex][idx]);
468 }
469 else {
470 rest.push(ratings[audioholderIndex][audioelementIndex][idx]);
471 }
472 }
473 outlierArray.push(outliers);
474 max_n_outliers = Math.max(max_n_outliers, outliers.length); // update max mber
475 // max: maximum value which is not outlier
476 max.push(Math.max.apply(null, rest));
477 // min: minimum value which is not outlier
478 min.push(Math.min.apply(null, rest));
479 }
480
481 // Build data array
482 boxplot_data = [['ID', 'Span', '', '', '', 'Median']];
483 for (idx = 0; idx < max_n_outliers; idx++) {
484 boxplot_data[0].push('Outlier');
485 }
486 for (audioelementIndex = 0; audioelementIndex<ratings[audioholderIndex].length; audioelementIndex++){
487 if (ratings[audioholderIndex][audioelementIndex].length>0) { // if rating array not empty for this audioelement
488 data_array = [
489 audioelementArray[audioelementIndex], // name
490 min[audioelementIndex], // minimum
491 pctl75[audioelementIndex],
492 pctl25[audioelementIndex],
493 max[audioelementIndex], // maximum
494 med[audioelementIndex]
495 ];
496 for (idx = 0; idx < max_n_outliers; idx++) {
497 if (idx<outlierArray[audioelementIndex].length){
498 data_array.push(outlierArray[audioelementIndex][idx]);
499 }
500 else {
501 data_array.push(null);
502 }
503 }
504 boxplot_data.push(data_array);
505 }
506 }
507
508 // Create and populate the data table.
509 var data = google.visualization.arrayToDataTable(boxplot_data);
510 // Create and draw the visualization.
511 var ac = new google.visualization.ComboChart(document.getElementById('div_box_'+audioholderName));
512 ac.draw(data, {
513 title : audioholderName,
514 //width: 600,
515 //height: 400,
516 vAxis: {title: "Rating"},
517 hAxis: {title: "audioelement ID"},
518 seriesType: "line",
519 pointSize: 5,
520 lineWidth: 0,
521 colors: ['black'],
522 series: { 0: {type: "candlesticks", color: 'blue'}, // box plot shape
523 1: {type: "line", pointSize: 10, lineWidth: 0, color: 'red' } }, // median
524 legend: 'none'
525 });
526 }
527 }
528
529 function makeTimeline(xmlFileName){ // WIP
530 // Based on the XML file name, take time data and plot playback and marker movements
531
532 // read XML file and check if exists
533 xml = readXML(xmlFileName);
534 if (!xml) { // if file does not exist
535 console.log('XML file '+xml+'does not exist. ('+xmlFileName+')')
536 return; // do nothing; exit function
537 }
538 // get root of XML file
539 root = xml.getElementsByTagName('browserevaluationresult')[0];
540
541 audioholder_time = 0;
542 previous_audioholder_time = 0; // time spent before current audioholder
543 time_offset = 0; // test starts at zero
544
545 // go over all audioholders
546 audioholderNodes = root.getElementsByTagName('audioholder');
547 for (audioholderIndex = 0; audioholderIndex < audioholderNodes.length; audioholderIndex++) {
548 audioholderName = audioholderNodes[audioholderIndex].getAttribute('id');
549 if (!audioholderName) {
550 console.log('audioholder name is empty; go to next one. ('+xmlFileName+')');
551 break;
552 }
553
554 // subtract total audioholder length from subsequent audioholder event times
555 audioholder_children = audioholderNodes[audioholderIndex].childNodes;
556 foundIt = false;
557 console.log(audioholder_children[2].getElementsByTagName("metricResult")) // not working!
558 for (idx = 0; idx<audioholder_children.length; idx++) { // go over children
559
560 if (audioholder_children[idx].getElementsByTagName('metricResult').length) {
561 console.log(audioholder_children[idx].getElementsByTagName('metricResult')[0]);
562 if (audioholder_children[idx].getElementsByTagName('metricResult')[0].getAttribute('id') == "testTime"){
563 audioholder_time = parseFloat(audioholder_children[idx].getElementsByTagName('metricResult')[0].textContent);
564 console.log(audioholder_time);
565 foundIt = true;
566 }
567 }
568 }
569 if (!foundIt) {
570 console.log("Skipping audioholder without total time specified from "+xmlFileName+"."); // always hitting this
571 break;
572 }
573
574 audioelementNodes = audioholderNodes[audioholderIndex].getElementsByTagName('audioelement');
575
576 // make div
577
578 // draw chart
579
580 // legend with audioelement names
456 } 581 }
457 } 582 }
458 583
459 </script> 584 </script>
460 585
498 width: 780px; 623 width: 780px;
499 border: 1px solid black; 624 border: 1px solid black;
500 overflow: hidden; /* add this to contain floated children */ 625 overflow: hidden; /* add this to contain floated children */
501 } 626 }
502 div#instrumentSection { 627 div#instrumentSection {
503 width: 250px; 628 width: 250px;
504 border: 1px solid red; 629 border: 1px solid red;
505 display: inline-block; 630 display: inline-block;
506 } 631 }
507 div#featureSection { 632 div#featureSection {
508 width: 250px; 633 width: 250px;
509 border: 1px solid green; 634 border: 1px solid green;
510 display: inline-block; 635 display: inline-block;
511 } 636 }
512 div#valenceSection { 637 div#valenceSection {
513 width: 250px; 638 width: 250px;
514 border: 1px solid blue; 639 border: 1px solid blue;
515 display: inline-block; 640 display: inline-block;
516 } 641 }
517 button#previousComment{ 642 button#previousComment{
518 width: 120px; 643 width: 120px;
519 height: 150px; 644 height: 150px;
520 font-size:1.5em; 645 font-size:1.5em;
545 <div id="headerMatter"> 670 <div id="headerMatter">
546 <div> 671 <div>
547 <strong>Result XML files:</strong> <span id="numberOfFiles_span"></span> 672 <strong>Result XML files:</strong> <span id="numberOfFiles_span"></span>
548 </div> 673 </div>
549 <div> 674 <div>
550 <strong>Audioholders in dataset:</strong> <span id="audioHolderArray_span"></span> 675 <strong>Audioholders in dataset:</strong> <span id="audioholderArray_span"></span>
551 </div> 676 </div>
552 <div> 677 <div>
553 <strong>Subjects in dataset:</strong> <span id="subjectArray_span"></span> 678 <strong>Subjects in dataset:</strong> <span id="subjectArray_span"></span>
554 </div> 679 </div>
555 <div> 680 <div>
556 <strong>Audioelements in dataset:</strong> <span id="audioElementArray_span"></span> 681 <strong>Audioelements in dataset:</strong> <span id="audioelementArray_span"></span>
557 </div> 682 </div>
558 <br> 683 <br>
559 </div> 684 </div>
560 <br> 685 <br>
561 686