To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Revision:

root / analyse.html

History | View | Annotate | Download (27.1 KB)

1
<!DOCTYPE html>
2
<html lang="en">
3
        <head>
4
                <meta charset="utf-8">
5

    
6
                <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
7
                Remove this if you use the .htaccess -->
8
                <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
9

    
10
                <title>Analysis</title>
11
                <meta name="description" content="Show results from subjective evaluation">
12
                <meta name="author" content="Brecht De Man">
13
                
14
                <script type="text/javascript" src="https://www.google.com/jsapi"></script>
15
                <script type="text/javascript">
16
                        // To aid 'one-page set-up' all scripts and CSS must be included directly in this file!
17
                        
18
                        google.load("visualization", "1", {packages:["corechart"]});
19
                        
20
                        /*************
21
                        *        SETUP   *
22
                        *************/
23
                        // folder where to find the XML files
24
                        xmlFileFolder = "saves";
25
                        // array of XML files
26
                        // THIS IS WHERE YOU SPECIFY RESULT XML FILES TO ANALYSE
27
                        var xmlFiles = ['save-dvoih4dotckkssw8wos8go4444skkcc0.xml']; 
28
                                                        
29

30
                        //TODO: make retrieval of file names automatic / drag files on here
31
                        
32
                        /****************
33
                        *        VARIABLES  *
34
                        ****************/
35
                        
36
                        // Counters
37
                        // How many files, audioholders, audioelementes and statements annotated (don't count current one)
38
                        var numberOfFiles = -1;
39
                        var numberOfaudioholders = -1;
40
                        var numberOfaudioelementes = -1;
41
                        var numberOfStatements = -1;
42
                        var numberOfSkippedComments = 0;
43
                        
44
                        // Object arrays
45
                        var fileNameArray = [];
46
                        var subjectArray = [];
47
                        var audioholderArray = [];
48
                        var audioelementArray = [];
49
                        
50
                        // End of (file, audioholder, audioelement) flags
51
                        var newFile = true;
52
                        var newAudioHolder = true;
53
                        var newAudioElement = true;
54
                        
55
                        var fileCounter = 0;                // file index
56
                        var audioholderCounter=0;        // audioholder index (current XML file)
57
                        var audioelementCounter=0;        // audioelement index (current audioholder)
58
                        var statementNumber=0;                 // total number of statements
59
                        
60
                        var root;                                        // root of XML file
61
                        var commentInFull = '';                // full comment
62
                        
63
                        var playAudio = true;                // whether corresponding audio should be played back
64
                        
65
                        // // Measuring time
66
                        // var lastTimeMeasured = -1;        //
67
                        // var durationLastAnnotation = -1;        // duration of last annotation
68
                        // var timeArray = [];
69
                        // var MIN_TIME = 1.0;        // minimum time counted as significant
70
                        // var measurementPaused = false; // whether time measurement is paused
71
                        // var timeInBuffer = 0; // 
72
                        
73
                        var topLevel;
74
                        window.onload = function() {
75
                                // Initialise page
76
                                topLevel = document.getElementById('topLevelBody');
77
                                var setup = document.createElement('div');
78
                                setup.id = 'setupTagDiv';
79
                                loadAllFiles();
80
                                makePlots();
81
                                printSurveyData() 
82
                                // measure time at this point: 
83
                                lastTimeMeasured = new Date().getTime(); // in milliseconds
84
                        };
85
                        
86
                        // Assert function
87
                        function assert(condition, message) {
88
                                if (!condition) {
89
                                        message = message || "Assertion failed";
90
                                        if (typeof Error !== "undefined") {
91
                                                throw new Error(message);
92
                                        }
93
                                        throw message; // Fallback
94
                                }
95
                        }
96

97
                        function median(values) { // TODO: replace code by '50th percentile' - should be the same?
98
                                values.sort( function(a,b) {return a - b;} );
99
                                var half = Math.floor(values.length/2);
100
                                if(values.length % 2)
101
                                return values[half];
102
                                else
103
                                return (values[half-1] + values[half]) / 2.0;
104
                        }
105

106
                        function percentile(values, n) {
107
                                values.sort( function(a,b) {return a - b;} );
108
                                // get ordinal rank
109
                                var rank = Math.min(Math.floor(values.length*n/100), values.length-1);
110
                                return values[rank];
111
                        }
112
                        
113
                        /***********************
114
                        *        TIME MEASUREMENT  *
115
                        ************************/
116
                        
117
                        // measure time since last time this function was called
118
                        function timeSinceLastCall() {
119
                                // current time
120
                                var currentTime = new Date().getTime();
121
                                // calculate time difference
122
                                var timeDifference = currentTime - lastTimeMeasured + timeInBuffer;
123
                                // clear buffer (for pausing)
124
                                timeInBuffer = 0;
125
                                // remember last measured time
126
                                lastTimeMeasured = currentTime; 
127
                                return timeDifference;
128
                        }
129
                        
130
                        // pause time measurement
131
                        function pauseTimeMeasurement() {
132
                                // UN-PAUSE
133
                                if (measurementPaused) { // already paused
134
                                        // button shows 'pause' again
135
                                        document.getElementById('pauseButton').innerHTML = 'Pause';
136
                                        // toggle state
137
                                        measurementPaused = false;
138
                                        // resume time measurement
139
                                        lastTimeMeasured = new Date().getTime(); // reset time, discard time while paused
140
                                } else { // PAUSE
141
                                        // button shows 'resume'
142
                                        document.getElementById('pauseButton').innerHTML = 'Resume';
143
                                        // toggle state
144
                                        measurementPaused = true;
145
                                        // pause time measurement
146
                                        timeInBuffer = timeSinceLastCall();
147
                                }
148
                        }
149
                        
150
                        // show elapsed time on interface
151
                        function showTimeElapsedInSeconds() {
152
                                // if paused: un-pause
153
                                if (measurementPaused) {
154
                                        pauseTimeMeasurement();
155
                                }
156
                        
157
                                // time of last annotation
158
                                var lastAnnotationTime = timeSinceLastCall()/1000;
159
                                document.getElementById('timeDisplay').innerHTML = lastAnnotationTime.toFixed(2); 
160
                                // average time over last ... annotations
161
                                var avgAnnotationTime;
162
                                var numberOfElementsToAverage = 
163
                                                document.getElementById('numberOfTimeAverages').value; 
164
                                if (isPositiveInteger(numberOfElementsToAverage)) {
165
                                        avgAnnotationTime = 
166
                                                calculateAverageTime(lastAnnotationTime, 
167
                                                                                         Number(numberOfElementsToAverage));
168
                                } else {
169
                                        // change text field content to 'ALL'
170
                                        document.getElementById('numberOfTimeAverages').value = 'ALL'; 
171
                                        avgAnnotationTime = calculateAverageTime(lastAnnotationTime, -1);
172
                                }
173
                                document.getElementById('timeAverageDisplay').innerHTML = avgAnnotationTime.toFixed(2);
174
                        }
175
                        
176
                        // auxiliary function: is string a positive integer?
177
                        // http://stackoverflow.com/questions/10834796/...
178
                        // validate-that-a-string-is-a-positive-integer
179
                        function isPositiveInteger(str) {
180
                                var n = ~~Number(str);
181
                                return String(n) === str && n >= 0;
182
                        }
183
                        
184
                        // calculate average time
185
                        function calculateAverageTime(newTimeMeasurementInSeconds,numberOfPoints) {
186
                                // append last measurement time to time array, if significant
187
                                if (newTimeMeasurementInSeconds > MIN_TIME) {
188
                                        timeArray.push(newTimeMeasurementInSeconds); 
189
                                }
190
                                // average over last N elements of this array
191
                                if (numberOfPoints < 0 || numberOfPoints>=timeArray.length) { // calculate average over all
192
                                        var sum = 0;
193
                                        for (var i = 0; i < timeArray.length; i++) { 
194
                                                sum += timeArray[i];
195
                                        }
196
                                        averageOfTimes = sum/timeArray.length;
197
                                } else { // calculate average over specified number of times measured last
198
                                        var sum = 0;
199
                                        for (var i = timeArray.length-numberOfPoints; i < timeArray.length; i++) { 
200
                                                sum += timeArray[i];
201
                                        }
202
                                        averageOfTimes = sum/numberOfPoints;
203
                                }
204
                                return averageOfTimes;
205
                        }
206
                        
207
                        
208
                        /********************************
209
                        *           PLAYBACK OF AUDIO           *
210
                        ********************************/
211
                        
212
                        //PLAYaudioelement
213
                        // Keep track of whether audio should be played
214
                        function playFlagChanged(){
215
                                playAudio = playFlag.checked; // global variable
216
                                
217
                                if (!playAudio){ // if audio needs to stop
218
                                        audio.pause(); // stop audio - if anything is playing
219
                                        currently_playing = ''; // back to empty string so playaudioelement knows nothing's playing
220
                                }
221
                        }
222
                        
223
                        // audioholder that's currently playing
224
                        var currently_playing_audioholder = ''; // at first: empty string
225
                        var currently_playing_audioelement  = '';
226
                        var audio;
227
                        
228
                        // Play audioelement of audioholder if available, from start or from same position
229
                        function playaudioelement(audioholderName, audioelementerName){
230
                                if (playAudio) { // if enabled
231
                                        // get corresponding file from folder
232
                                        var file_location = 'audio/'+audioholderName + '/' + audioelementerName + '.mp3'; // fixed path and file name format
233
                                        
234
                                        // if not available, show error/warning message
235
                                        //TODO ...
236
                                
237
                                        // if nothing playing yet, start playing
238
                                        if (currently_playing_audioholder == ''){ // signal that nothing is playing
239
                                                //playSound(audioBuffer);
240
                                                audio = new Audio(file_location);
241
                                                audio.loop = true; // loop when end is reached
242
                                                audio.play();
243
                                                currently_playing_audioholder = audioholderName;
244
                                                currently_playing_audioelement  = audioelementerName;
245
                                        } else if (currently_playing_audioholder != audioholderName) {
246
                                        // if different audioholder playing, stop that and start playing
247
                                                audio.pause(); // stop audio
248
                                                audio = new Audio(file_location); // load new file
249
                                                audio.loop = true; // loop when end is reached
250
                                                audio.play(); // play audio from the start
251
                                                currently_playing_audioholder = audioholderName;
252
                                                currently_playing_audioelement  = audioelementerName;
253
                                        } else if (currently_playing_audioelement != audioelementerName) {
254
                                        // if same audioholder playing, start playing from where it left off
255
                                                skipTime = audio.currentTime; // time to skip to
256
                                                audio.pause(); // stop audio
257
                                                audio = new Audio(file_location);
258
                                                audio.addEventListener('loadedmetadata', function() {
259
                                                        this.currentTime = skipTime;
260
                                                        console.log('Loaded '+audioholderName+'-'+audioelementerName+', playing from '+skipTime);
261
                                                }, false); // skip to same time when audio is loaded! 
262
                                                audio.loop = true; // loop when end is reached
263
                                                audio.play(); // play from that time
264
                                                audio.currentTime = skipTime;
265
                                                currently_playing_audioholder = audioholderName;
266
                                                currently_playing_audioelement  = audioelementerName;
267
                                        } 
268
                                        // if same audioelement playing: keep on playing (i.e. do nothing)
269
                                }
270
                        }
271
                        
272
                        /********************
273
                        *        READING FILES  *
274
                        ********************/
275
                        
276
                        // Read necessary data from XML file
277
                        function readXML(xmlFileName){
278
                                if (window.XMLHttpRequest)
279
                                  {// code for IE7+, Firefox, Chrome, Opera, Safari
280
                                  xmlhttp=new XMLHttpRequest();
281
                                  }
282
                                else
283
                                  {// code for IE6, IE5
284
                                  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
285
                                  }
286
                                xmlhttp.open("GET",xmlFileName,false);
287
                                xmlhttp.overrideMimeType('text/xml');
288
                                xmlhttp.send();
289
                                return xmlhttp.responseXML; 
290
                        }
291
                        
292
                        // go over all files and compute relevant statistics
293
                        function loadAllFiles() {
294
                                // retrieve information from XMLs
295
                                
296
                                for (fileIndex = 0; fileIndex < xmlFiles.length; fileIndex++) {
297
                                        xmlFileName = xmlFileFolder+"/"+xmlFiles[fileIndex];
298
                                        xml = readXML(xmlFileName); 
299
                                        if (xml != null) { // if file exists
300
                                                // append file name to array of file names
301
                                                fileNameArray.push(xmlFiles[fileIndex]);
302
                                                
303
                                                // get root of XML file
304

305
                                                var parser = new DOMParser();
306
                                                var xmlDoc = parser.parseFromString(xmlhttp.responseText, "application/xml");
307
                                                var root1 = xmlDoc.getElementsByTagName('waetresult')[0];
308
                                                root = xml.getElementsByTagName('waetresult')[0];
309
                                                
310
                                                // get subject ID, add to array if not already there
311
                                                var pretestSurveyResult = root.getElementsByTagName('surveyresult')[0];
312
                                                var subjectIdTextContent = undefined;
313
                                                if(typeof(pretestSurveyResult) !== "undefined"){
314
                                                        var subjectID = pretestSurveyResult.getElementsByTagName('comment')[0];
315
                                                        if (subjectID){
316
                                                                if (subjectID.getAttribute('id')==='sessionId') { // warning in console when not available
317
                                                                        subjectIdTextContent = subjectID.textContent;
318
                                                                }
319
                                                        }
320
                                                }
321
                                                if(typeof(subjectIdTextContent) !== "undefined"){
322
                                                        if (subjectArray.indexOf(subjectIdTextContent) == -1) { // if not already in array
323
                                                                subjectArray.push(subjectIdTextContent); // append to array
324
                                                        }
325
                                                } else {
326
                                                        console.log(xmlFiles[fileIndex]+': no sessionId available');
327
                                                }
328

329
                                                // go over all audioholders, add to array if not already there
330
                                                audioholderNodes = root.getElementsByTagName('audioholder');
331
                                                // go over audioholderNodes and append audioholder name when not present yet
332
                                                for (audioholderIndex = 0; audioholderIndex < audioholderNodes.length; audioholderIndex++) { 
333
                                                        audioholderName = audioholderNodes[audioholderIndex].getAttribute('id');
334
                                                        if (audioholderArray.indexOf(audioholderName) == -1) { // if not already in array
335
                                                                audioholderArray.push(audioholderName); // append to array
336
                                                        }
337
                                                        // within each audioholder, go over all audioelement IDs, add to array if not already there
338
                                                        audioelementNodes = audioholderNodes[audioholderIndex].getElementsByTagName('audioelement');
339
                                                        for (audioelementIndex = 0; audioelementIndex < audioelementNodes.length; audioelementIndex++) { 
340
                                                                audioelementName = audioelementNodes[audioelementIndex].getAttribute('id');
341
                                                                if (audioelementArray.indexOf(audioelementName) == -1) { // if not already in array
342
                                                                        audioelementArray.push(audioelementName); // append to array
343
                                                                }
344
                                                        }
345
                                                }
346
                                                // count occurrences of each audioholder
347
                                                // ...
348
                                        }
349
                                        else {
350
                                                console.log('XML file '+xmlFileName+' not found.');
351
                                        }
352
                                }
353

354
                                // sort alphabetically
355
                                fileNameArray.sort();
356
                                subjectArray.sort();
357
                                audioholderArray.sort();
358
                                audioelementArray.sort();
359
                                
360
                                // display all information in HTML
361
                                // show XML file folder
362
                                document.getElementById('xmlFileFolder_span').innerHTML = "\""+xmlFileFolder+"/\"";
363
                                // show number of files
364
                                document.getElementById('numberOfFiles_span').innerHTML = fileNameArray.length;
365
                                // show list of subject names
366
                                document.getElementById('subjectArray_span').innerHTML = subjectArray.toString();
367
                                // show list of audioholders
368
                                document.getElementById('audioholderArray_span').innerHTML = audioholderArray.toString();
369
                                // show list of audioelementes
370
                                document.getElementById('audioelementArray_span').innerHTML = audioelementArray.toString();
371
                        }
372

373
                        function printSurveyData() { 
374
                                // print some fields from the survey for different people
375

376
                                // go over all XML files
377
                                for (fileIndex = 0; fileIndex < xmlFiles.length; fileIndex++) {
378
                                        xmlFileName = xmlFileFolder+"/"+xmlFiles[fileIndex];
379
                                        xml = readXML(xmlFileName); 
380
                                        // make a div
381
                                        var div = document.createElement('div');
382
                                        document.body.appendChild(div);
383
                                        div.id = 'div_survey_'+xmlFileName;
384
                                        div.style.width = '1100px'; 
385
                                        //div.style.height = '350px'; 
386

387
                                        // title for that div (subject id)
388
                                        document.getElementById('div_survey_'+xmlFileName).innerHTML = '<h2>'+xmlFileName+'</h2>';
389

390
                                        // which songs did they do
391
                                        if (xml != null) { // if file exists
392
                                                // get root of XML file
393
                                                root = xml.getElementsByTagName('waetresult')[0];
394
                                                // go over all audioholders
395
                                                // document.getElementById('div_survey_'+xmlFileName).innerHTML += '<strong>Audioholders: </strong>';
396
                                                // audioholderNodes = root.getElementsByTagName('audioholder');
397
                                                // for (audioholderIndex = 0; audioholderIndex < audioholderNodes.length-1; audioholderIndex++) {
398
                                                //         document.getElementById('div_survey_'+xmlFileName).innerHTML += audioholderNodes[audioholderIndex].getAttribute('id')+', ';
399
                                                // }
400
                                                // document.getElementById('div_survey_'+xmlFileName).innerHTML += audioholderNodes[audioholderNodes.length-1].getAttribute('id');
401

402
                                                // survey responses (each if available)
403
                                                // get posttest node for total test
404
                                                childNodes = root.childNodes;
405
                                                posttestnode = null;
406
                                                for (idx = 0; idx < childNodes.length; idx++){
407
                                                        if (childNodes[childNodes.length-idx-1].tagName == 'posttest') {
408
                                                                posttestnode = childNodes[childNodes.length-idx-1];
409
                                                                break;
410
                                                        }
411
                                                }
412

413
                                                // post-test info
414
                                                if (posttestnode) {
415
                                                        posttestcomments = posttestnode.getElementsByTagName('comment');
416
                                                        for (idx=0; idx < posttestcomments.length; idx++){
417
                                                                commentsToPrint = ['age', 'location']; // CHANGE WHAT TO PRINT
418
                                                                idAttribute = posttestcomments[idx].getAttribute('id');
419
                                                                if (commentsToPrint.indexOf(idAttribute) >= 0) { // if exists? 
420
                                                                        document.getElementById('div_survey_'+xmlFileName).innerHTML += '<br><strong>'+idAttribute+': </strong>'+posttestcomments[idx].textContent;
421
                                                                }
422
                                                        }
423
                                                }
424
                                        }
425
                                }
426
                        }
427

428
                        function makePlots() { //TODO: split into different functions
429
                                // TEMPORARY
430
                                makeTimeline(xmlFileFolder+"/"+xmlFiles[0]);
431

432
                                // create value array
433
                                var ratings = [];  // 3D matrix of ratings (audioholder, audioelement, subject)
434
                                for (audioholderIndex = 0; audioholderIndex < audioholderArray.length; audioholderIndex++) { 
435
                                        ratings.push([]);
436
                                        for (audioelementIndex = 0; audioelementIndex < audioelementArray.length; audioelementIndex++) { 
437
                                                ratings[audioholderIndex].push([]);
438
                                        }
439
                                }
440

441
                                // go over all XML files
442
                                for (fileIndex = 0; fileIndex < xmlFiles.length; fileIndex++) {
443
                                        xmlFileName = xmlFileFolder+"/"+xmlFiles[fileIndex];
444
                                        xml = readXML(xmlFileName); 
445
                                        if (xml != null) { // if file exists
446
                                                // get root of XML file
447
                                                root = xml.getElementsByTagName('waetresult')[0];
448
                                                // go over all audioholders
449
                                                audioholderNodes = root.getElementsByTagName('audioholder');
450
                                                for (audioholderIndex = 0; audioholderIndex < audioholderNodes.length; audioholderIndex++) { 
451
                                                        audioholderName = audioholderNodes[audioholderIndex].getAttribute('id');
452
                                                        audioelementNodes = audioholderNodes[audioholderIndex].getElementsByTagName('audioelement');
453
                                                        // go over all audioelements
454
                                                        for (audioelementIndex = 0; audioelementIndex < audioelementNodes.length; audioelementIndex++) { 
455
                                                                audioelementName = audioelementNodes[audioelementIndex].getAttribute('id');
456
                                                                // get value
457
                                                                var value = audioelementNodes[audioelementIndex].getElementsByTagName("value")[0].textContent;
458
                                                                if (value) { // if not empty, null, undefined...
459
                                                                        ratingValue = parseFloat(value);
460
                                                                        // add to matrix at proper position
461
                                                                        aHidx = audioholderArray.indexOf(audioholderName);
462
                                                                        aEidx = audioelementArray.indexOf(audioelementName);
463
                                                                        ratings[aHidx][aEidx].push(ratingValue);
464
                                                                }
465
                                                        }
466
                                                }
467

468
                                                // go over all audioholders
469

470
                                                // go over all audioelements within audioholder, see if present in idMatrix, add if not
471
                                                // add corresponding rating to 'ratings', at position corresponding with position in idMatrix
472
                                        }
473
                                }
474

475
                                for (audioholderIndex = 0; audioholderIndex < audioholderArray.length; audioholderIndex++) {
476
                                        audioholderName = audioholderArray[audioholderIndex]; // for this song
477
                                        tickArray = []
478

479
                                        raw_data = [['SubjectID', 'Rating']];
480
                                        audioElIdx = 0;
481
                                        for (audioelementIndex = 0; audioelementIndex<ratings[audioholderIndex].length; audioelementIndex++){
482
                                                if (ratings[audioholderIndex][audioelementIndex].length>0) {
483
                                                        audioElIdx++; // increase if not empty
484
                                                        // make tick label
485
                                                        tickArray.push({v:audioElIdx, f: audioelementArray[audioelementIndex]});
486
                                                }
487
                                                for (subject = 0; subject<ratings[audioholderIndex][audioelementIndex].length; subject++){
488
                                                        // add subject-value pair for each subject
489
                                                        raw_data.push([audioElIdx, ratings[audioholderIndex][audioelementIndex][subject]]); 
490
                                                }
491
                                        }
492

493
                                        // create plot (one per song)
494
                                        var data = google.visualization.arrayToDataTable(raw_data);
495

496
                                        var options = {
497
                                                title: audioholderName,
498
                                                hAxis: {title: 'audioelement ID', minValue: 0, maxValue: audioElIdx+1,
499
                                                                ticks: tickArray},
500
                                                vAxis: {title: 'Rating', minValue: 0, maxValue: 1},
501
                                                seriesType: 'scatter',
502
                                                legend: 'none'
503
                                        };
504
                                        var div = document.createElement('div');
505
                                        document.body.appendChild(div);
506
                                        div.id = 'div_'+audioholderName;
507
                                        div.style.width = '1100px'; 
508
                                        div.style.height = '350px'; 
509
                                        var chart = new google.visualization.ComboChart(document.getElementById('div_'+audioholderName));
510
                                        chart.draw(data, options);
511

512
                                        // box plots
513
                                        var div = document.createElement('div');
514
                                        document.body.appendChild(div);
515
                                        div.id = 'div_box_'+audioholderName;
516
                                        div.style.width = '1100px'; 
517
                                        div.style.height = '350px'; 
518
                                        // Get median, percentiles, maximum and minimum; outliers.
519
                                        pctl25 = [];
520
                                        pctl75 = [];
521
                                        med = [];
522
                                        min = [];
523
                                        max = [];
524
                                        outlierArray = [];
525
                                        max_n_outliers = 0; // maximum number of outliers for one audioelement
526
                                        for (audioelementIndex = 0; audioelementIndex<ratings[audioholderIndex].length; audioelementIndex++){
527
                                                med.push(median(ratings[audioholderIndex][audioelementIndex])); // median
528
                                                pctl25.push(percentile(ratings[audioholderIndex][audioelementIndex], 25)); // 25th percentile
529
                                                pctl75.push(percentile(ratings[audioholderIndex][audioelementIndex], 75)); // 75th percentile
530
                                                IQR = pctl75[pctl75.length-1]-pctl25[pctl25.length-1];
531
                                                // outliers: range of values which is above pctl75+1.5*IQR or below pctl25-1.5*IQR
532
                                                outliers = [];
533
                                                rest = [];
534
                                                for (idx = 0; idx<ratings[audioholderIndex][audioelementIndex].length; idx++){
535
                                                        if (ratings[audioholderIndex][audioelementIndex][idx] > pctl75[pctl75.length-1]+1.5*IQR ||
536
                                                                ratings[audioholderIndex][audioelementIndex][idx] < pctl25[pctl25.length-1]-1.5*IQR){
537
                                                                outliers.push(ratings[audioholderIndex][audioelementIndex][idx]);
538
                                                        }
539
                                                        else {
540
                                                                rest.push(ratings[audioholderIndex][audioelementIndex][idx]);
541
                                                        }
542
                                                }
543
                                                outlierArray.push(outliers);
544
                                                max_n_outliers = Math.max(max_n_outliers, outliers.length); // update max mber
545
                                                // max: maximum value which is not outlier
546
                                                max.push(Math.max.apply(null, rest));
547
                                                // min: minimum value which is not outlier
548
                                                min.push(Math.min.apply(null, rest));
549
                                        }
550

551
                                        // Build data array
552
                                        boxplot_data = [['ID', 'Span', '', '', '', 'Median']];
553
                                        for (idx = 0; idx < max_n_outliers; idx++) {
554
                                                boxplot_data[0].push('Outlier');
555
                                        }
556
                                        for (audioelementIndex = 0; audioelementIndex<ratings[audioholderIndex].length; audioelementIndex++){
557
                                                if (ratings[audioholderIndex][audioelementIndex].length>0) { // if rating array not empty for this audioelement
558
                                                        data_array = [
559
                                                                        audioelementArray[audioelementIndex], // name
560
                                                                        min[audioelementIndex], // minimum
561
                                                                        pctl75[audioelementIndex],
562
                                                                        pctl25[audioelementIndex],
563
                                                                        max[audioelementIndex], // maximum
564
                                                                        med[audioelementIndex]
565
                                                                        ];
566
                                                        for (idx = 0; idx < max_n_outliers; idx++) {
567
                                                                if (idx<outlierArray[audioelementIndex].length){
568
                                                                        data_array.push(outlierArray[audioelementIndex][idx]);
569
                                                                }
570
                                                                else {
571
                                                                        data_array.push(null);
572
                                                                }
573
                                                        }
574
                                                        boxplot_data.push(data_array);
575
                                                }
576
                                        }
577

578
                                        // Create and populate the data table.
579
                                        var data = google.visualization.arrayToDataTable(boxplot_data);
580
                                          // Create and draw the visualization.
581
                                        var ac = new google.visualization.ComboChart(document.getElementById('div_box_'+audioholderName));
582
                                        ac.draw(data, {
583
                                                title : audioholderName,
584
                                                //width: 600,
585
                                                //height: 400,
586
                                                vAxis: {title: "Rating"},
587
                                                hAxis: {title: "audioelement ID"},
588
                                                seriesType: "line",
589
                                                pointSize: 5, 
590
                                                lineWidth: 0,
591
                                                colors: ['black'], 
592
                                                series: { 0: {type: "candlesticks", color: 'blue'}, // box plot shape
593
                                                                  1: {type: "line", pointSize: 10, lineWidth: 0, color: 'red' } }, // median
594
                                                legend: 'none'
595
                                        });
596
                                }
597
                        }
598

599
                        function makeTimeline(xmlFileName){ // WIP
600
                                // Based on the XML file name, take time data and plot playback and marker movements
601

602
                                // read XML file and check if exists
603
                                xml = readXML(xmlFileName); 
604
                                if (!xml) { // if file does not exist
605
                                        console.log('XML file '+xml+'does not exist. ('+xmlFileName+')')
606
                                        return; // do nothing; exit function
607
                                }
608
                                // get root of XML file
609
                                root = xml.getElementsByTagName('waetresult')[0];
610

611
                                audioholder_time = 0; 
612
                                previous_audioholder_time = 0; // time spent before current audioholder
613
                                time_offset = 0; // test starts at zero
614

615
                                // go over all audioholders
616
                                audioholderNodes = root.getElementsByTagName('audioholder');
617
                                for (audioholderIndex = 0; audioholderIndex < audioholderNodes.length; audioholderIndex++) { 
618
                                        audioholderName = audioholderNodes[audioholderIndex].getAttribute('id');
619
                                        if (!audioholderName) {
620
                                                console.log('audioholder name is empty; go to next one. ('+xmlFileName+')');
621
                                                break;
622
                                        }
623

624
                                        // subtract total audioholder length from subsequent audioholder event times
625
                                        audioholder_children = audioholderNodes[audioholderIndex].childNodes; 
626
                                        foundIt = false;
627
                                        console.log(audioholder_children[2].getElementsByTagName("metricResult")) // not working! 
628
                                        for (idx = 0; idx<audioholder_children.length; idx++) { // go over children
629

630
                                                if (audioholder_children[idx].getElementsByTagName('metricResult').length) {
631
                                                        console.log(audioholder_children[idx].getElementsByTagName('metricResult')[0]);
632
                                                        if (audioholder_children[idx].getElementsByTagName('metricResult')[0].getAttribute('id') == "testTime"){
633
                                                                audioholder_time = parseFloat(audioholder_children[idx].getElementsByTagName('metricResult')[0].textContent);
634
                                                                console.log(audioholder_time); 
635
                                                                foundIt = true;
636
                                                        }
637
                                                }
638
                                        }
639
                                        if (!foundIt) {
640
                                                console.log("Skipping audioholder without total time specified from "+xmlFileName+"."); // always hitting this
641
                                                break;
642
                                        }
643

644
                                        audioelementNodes = audioholderNodes[audioholderIndex].getElementsByTagName('audioelement');
645
                                        
646
                                        // make div
647

648
                                        // draw chart
649

650
                                        // legend with audioelement names        
651
                                }
652
                        }
653
                        
654
                </script>
655

    
656

    
657

    
658
                <style>
659
                        div {
660
                                padding: 2px;
661
                                margin-top: 2px;
662
                                margin-bottom: 2px;
663
                        }
664
                        div.head{
665
                                margin-left: 10px;
666
                                border: black;
667
                                border-width: 2px;
668
                                border-style: solid;
669
                        }
670
                        div.attrib{
671
                                margin-left:25px;
672
                                border: black;
673
                                border-width: 2px;
674
                                border-style: dashed;
675
                                margin-bottom: 10px;
676
                        }
677
                        div#headerMatter{
678
                                background-color: #FFFFCC;
679
                        }
680
                        div#currentStatement{
681
                                font-size:3.0em;
682
                                font-weight: bold;
683
                                
684
                        }
685
                        div#debugDisplay {
686
                                color: #CCCCCC;
687
                                font-size:0.3em;
688
                        }
689
                        span#scoreDisplay {
690
                                font-weight: bold;
691
                        }
692
                        div#wrapper {
693
                                width: 780px;
694
                                border: 1px solid black;
695
                                overflow: hidden; /* add this to contain floated children */
696
                        }
697
                        div#instrumentSection {
698
                                width: 250px;
699
                                border: 1px solid red;
700
                                display: inline-block;
701
                        }
702
                        div#featureSection {
703
                                width: 250px;
704
                                border: 1px solid green;
705
                                display: inline-block;
706
                        }
707
                        div#valenceSection {
708
                                width: 250px;
709
                                border: 1px solid blue;
710
                                display: inline-block;
711
                        }
712
                        button#previousComment{
713
                                width: 120px;
714
                                height: 150px;
715
                                font-size:1.5em;
716
                        }
717
                        button#nextComment{
718
                                width: 666px;
719
                                height: 150px;
720
                                font-size:1.5em;
721
                        }
722
                        ul
723
                        {
724
                                list-style-type: none; /* no bullet points */
725
                                margin-left: -20px; /* less indent */
726
                                margin-top: 0px;
727
                                  margin-bottom: 5px;
728
                        }
729
                </style>
730
                
731
        </head>
732

    
733
        <body>
734
                <h1>Subjective evaluation results</h1>
735
                
736
                <div id="debugDisplay">
737
                XML file folder: <span id="xmlFileFolder_span"></span>
738
                </div>
739

    
740
                <div id="headerMatter">
741
                        <div>
742
                                <strong>Result XML files:</strong> <span id="numberOfFiles_span"></span>
743
                        </div>
744
                        <div>
745
                                <strong>Audioholders in dataset:</strong> <span id="audioholderArray_span"></span>
746
                        </div>
747
                        <div>
748
                                <strong>Subjects in dataset:</strong> <span id="subjectArray_span"></span>
749
                        </div>
750
                        <div>
751
                                <strong>Audioelements in dataset:</strong> <span id="audioelementArray_span"></span>
752
                        </div>
753
                        <br>
754
                </div>
755
                <br>
756

    
757
                <!-- Show time elapsed 
758
                The last annotation took <strong><span id="timeDisplay">(N/A)</span></strong> seconds.
759
                <br>-->
760
                
761
        </body>
762
</html>