comparison analyse.html @ 716:cbfc18a7d068

Paper: edits in various sections; Added preliminary analysis page
author Brecht De Man <BrechtDeMan@users.noreply.github.com>
date Wed, 14 Oct 2015 20:12:52 +0100
parents
children 378726f0ac91 9da8a3e65a78
comparison
equal deleted inserted replaced
-1:000000000000 716:cbfc18a7d068
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 var xmlFiles = ['McG-A-2014-03.xml','McG-B-2014-03.xml','McG-C-2014-03.xml'];
27
28 //TODO: make retrieval of file names automatic / drag files on here
29
30 /****************
31 * VARIABLES *
32 ****************/
33
34 // Counters
35 // How many files, audioHolders, audioElementes and statements annotated (don't count current one)
36 var numberOfFiles = -1;
37 var numberOfaudioHolders = -1;
38 var numberOfaudioElementes = -1;
39 var numberOfStatements = -1;
40 var numberOfSkippedComments = 0;
41
42 // Object arrays
43 var fileNameArray = [];
44 var subjectArray = [];
45 var audioHolderArray = [];
46 var audioElementArray = [];
47
48 // End of (file, audioholder, audioelement) flags
49 var newFile = true;
50 var newAudioHolder = true;
51 var newAudioElement = true;
52
53 var fileCounter = 0; // file index
54 var audioHolderCounter=0; // audioholder index (current XML file)
55 var audioElementCounter=0; // audioelement index (current audioholder)
56 var statementNumber=0; // total number of statements
57
58 var root; // root of XML file
59 var commentInFull = ''; // full comment
60
61 var playAudio = true; // whether corresponding audio should be played back
62
63 // // Measuring time
64 // var lastTimeMeasured = -1; //
65 // var durationLastAnnotation = -1; // duration of last annotation
66 // var timeArray = [];
67 // var MIN_TIME = 1.0; // minimum time counted as significant
68 // var measurementPaused = false; // whether time measurement is paused
69 // var timeInBuffer = 0; //
70
71 var topLevel;
72 window.onload = function() {
73 // Initialise page
74 topLevel = document.getElementById('topLevelBody');
75 var setup = document.createElement('div');
76 setup.id = 'setupTagDiv';
77 loadAllFiles();
78
79 makePlots();
80 // measure time at this point:
81 lastTimeMeasured = new Date().getTime(); // in milliseconds
82 };
83
84 // Assert function
85 function assert(condition, message) {
86 if (!condition) {
87 message = message || "Assertion failed";
88 if (typeof Error !== "undefined") {
89 throw new Error(message);
90 }
91 throw message; // Fallback
92 }
93 }
94
95 function median(values) {
96 values.sort( function(a,b) {return a - b;} );
97 var half = Math.floor(values.length/2);
98 if(values.length % 2)
99 return values[half];
100 else
101 return (values[half-1] + values[half]) / 2.0;
102 }
103
104 /***********************
105 * TIME MEASUREMENT *
106 ************************/
107
108 // measure time since last time this function was called
109 function timeSinceLastCall() {
110 // current time
111 var currentTime = new Date().getTime();
112 // calculate time difference
113 var timeDifference = currentTime - lastTimeMeasured + timeInBuffer;
114 // clear buffer (for pausing)
115 timeInBuffer = 0;
116 // remember last measured time
117 lastTimeMeasured = currentTime;
118 return timeDifference;
119 }
120
121 // pause time measurement
122 function pauseTimeMeasurement() {
123 // UN-PAUSE
124 if (measurementPaused) { // already paused
125 // button shows 'pause' again
126 document.getElementById('pauseButton').innerHTML = 'Pause';
127 // toggle state
128 measurementPaused = false;
129 // resume time measurement
130 lastTimeMeasured = new Date().getTime(); // reset time, discard time while paused
131 } else { // PAUSE
132 // button shows 'resume'
133 document.getElementById('pauseButton').innerHTML = 'Resume';
134 // toggle state
135 measurementPaused = true;
136 // pause time measurement
137 timeInBuffer = timeSinceLastCall();
138 }
139 }
140
141 // show elapsed time on interface
142 function showTimeElapsedInSeconds() {
143 // if paused: un-pause
144 if (measurementPaused) {
145 pauseTimeMeasurement();
146 }
147
148 // time of last annotation
149 var lastAnnotationTime = timeSinceLastCall()/1000;
150 document.getElementById('timeDisplay').innerHTML = lastAnnotationTime.toFixed(2);
151 // average time over last ... annotations
152 var avgAnnotationTime;
153 var numberOfElementsToAverage =
154 document.getElementById('numberOfTimeAverages').value;
155 if (isPositiveInteger(numberOfElementsToAverage)) {
156 avgAnnotationTime =
157 calculateAverageTime(lastAnnotationTime,
158 Number(numberOfElementsToAverage));
159 } else {
160 // change text field content to 'ALL'
161 document.getElementById('numberOfTimeAverages').value = 'ALL';
162 avgAnnotationTime = calculateAverageTime(lastAnnotationTime, -1);
163 }
164 document.getElementById('timeAverageDisplay').innerHTML = avgAnnotationTime.toFixed(2);
165 }
166
167 // auxiliary function: is string a positive integer?
168 // http://stackoverflow.com/questions/10834796/...
169 // validate-that-a-string-is-a-positive-integer
170 function isPositiveInteger(str) {
171 var n = ~~Number(str);
172 return String(n) === str && n >= 0;
173 }
174
175 // calculate average time
176 function calculateAverageTime(newTimeMeasurementInSeconds,numberOfPoints) {
177 // append last measurement time to time array, if significant
178 if (newTimeMeasurementInSeconds > MIN_TIME) {
179 timeArray.push(newTimeMeasurementInSeconds);
180 }
181 // average over last N elements of this array
182 if (numberOfPoints < 0 || numberOfPoints>=timeArray.length) { // calculate average over all
183 var sum = 0;
184 for (var i = 0; i < timeArray.length; i++) {
185 sum += timeArray[i];
186 }
187 averageOfTimes = sum/timeArray.length;
188 } else { // calculate average over specified number of times measured last
189 var sum = 0;
190 for (var i = timeArray.length-numberOfPoints; i < timeArray.length; i++) {
191 sum += timeArray[i];
192 }
193 averageOfTimes = sum/numberOfPoints;
194 }
195 return averageOfTimes;
196 }
197
198
199 /********************************
200 * PLAYBACK OF AUDIO *
201 ********************************/
202
203 //PLAYaudioElement
204 // Keep track of whether audio should be played
205 function playFlagChanged(){
206 playAudio = playFlag.checked; // global variable
207
208 if (!playAudio){ // if audio needs to stop
209 audio.pause(); // stop audio - if anything is playing
210 currently_playing = ''; // back to empty string so playaudioElement knows nothing's playing
211 }
212 }
213
214 // audioHolder that's currently playing
215 var currently_playing_audioHolder = ''; // at first: empty string
216 var currently_playing_audioElement = '';
217 var audio;
218
219 // Play audioElement of audioHolder if available, from start or from same position
220 function playaudioElement(audioHolderName, audioElementerName){
221 if (playAudio) { // if enabled
222 // get corresponding file from folder
223 var file_location = 'audio/'+audioHolderName + '/' + audioElementerName + '.mp3'; // fixed path and file name format
224
225 // if not available, show error/warning message
226 //TODO ...
227
228 // if nothing playing yet, start playing
229 if (currently_playing_audioHolder == ''){ // signal that nothing is playing
230 //playSound(audioBuffer);
231 audio = new Audio(file_location);
232 audio.loop = true; // loop when end is reached
233 audio.play();
234 currently_playing_audioHolder = audioHolderName;
235 currently_playing_audioElement = audioElementerName;
236 } else if (currently_playing_audioHolder != audioHolderName) {
237 // if different audioHolder playing, stop that and start playing
238 audio.pause(); // stop audio
239 audio = new Audio(file_location); // load new file
240 audio.loop = true; // loop when end is reached
241 audio.play(); // play audio from the start
242 currently_playing_audioHolder = audioHolderName;
243 currently_playing_audioElement = audioElementerName;
244 } else if (currently_playing_audioElement != audioElementerName) {
245 // if same audioHolder playing, start playing from where it left off
246 skipTime = audio.currentTime; // time to skip to
247 audio.pause(); // stop audio
248 audio = new Audio(file_location);
249 audio.addEventListener('loadedmetadata', function() {
250 this.currentTime = skipTime;
251 console.log('Loaded '+audioHolderName+'-'+audioElementerName+', playing from '+skipTime);
252 }, false); // skip to same time when audio is loaded!
253 audio.loop = true; // loop when end is reached
254 audio.play(); // play from that time
255 audio.currentTime = skipTime;
256 currently_playing_audioHolder = audioHolderName;
257 currently_playing_audioElement = audioElementerName;
258 }
259 // if same audioElement playing: keep on playing (i.e. do nothing)
260 }
261 }
262
263 /********************
264 * READING FILES *
265 ********************/
266
267 // Read necessary data from XML file
268 function readXML(xmlFileName){
269 if (window.XMLHttpRequest)
270 {// code for IE7+, Firefox, Chrome, Opera, Safari
271 xmlhttp=new XMLHttpRequest();
272 }
273 else
274 {// code for IE6, IE5
275 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
276 }
277 xmlhttp.open("GET",xmlFileName,false);
278 xmlhttp.send();
279 return xmlhttp.responseXML;
280 }
281
282 // go over all files and compute relevant statistics
283 function loadAllFiles() {
284 // retrieve information from XMLs
285
286 for (fileIndex = 0; fileIndex < xmlFiles.length; fileIndex++) {
287 xmlFileName = xmlFileFolder+"/"+xmlFiles[fileIndex];
288 xml = readXML(xmlFileName);
289 if (xml != null) { // if file exists
290 // append file name to array of file names
291 fileNameArray.push(xmlFiles[fileIndex]);
292
293 // get root of XML file
294 root = xml.getElementsByTagName('browserevaluationresult')[0];
295
296 // get subject ID, add to array if not already there
297 pretest = root.getElementsByTagName('pretest')[0];
298 subjectID = pretest.getElementsByTagName('comment')[0];
299 if (subjectID.getAttribute('id')!='sessionId') { // warning in console when not available
300 console.log(xmlFiles[fileIndex]+': no SessionID available');
301 }
302 if (subjectArray.indexOf(subjectID.textContent) == -1) { // if not already in array
303 subjectArray.push(subjectID.textContent); // append to array
304 }
305
306 // go over all audioHolders, add to array if not already there
307 audioHolderNodes = root.getElementsByTagName('audioholder');
308 // go over audioHolderNodes and append audioHolder name when not present yet
309 for (audioHolderIndex = 0; audioHolderIndex < audioHolderNodes.length; audioHolderIndex++) {
310 audioHolderName = audioHolderNodes[audioHolderIndex].getAttribute('id');
311 if (audioHolderArray.indexOf(audioHolderName) == -1) { // if not already in array
312 audioHolderArray.push(audioHolderName); // append to array
313 }
314 // within each audioHolder, go over all audioElement IDs, add to array if not already there
315 audioElementNodes = audioHolderNodes[audioHolderIndex].getElementsByTagName('audioelement');
316 for (audioElementIndex = 0; audioElementIndex < audioElementNodes.length; audioElementIndex++) {
317 audioElementName = audioElementNodes[audioElementIndex].getAttribute('id');
318 if (audioElementArray.indexOf(audioElementName) == -1) { // if not already in array
319 audioElementArray.push(audioElementName); // append to array
320 }
321 }
322 }
323 // count occurrences of each audioHolder
324 // ...
325 }
326 else {
327 console.log('XML file '+xmlFileName+' not found.');
328 }
329 }
330
331 // sort alphabetically
332 fileNameArray.sort();
333 subjectArray.sort();
334 audioHolderArray.sort();
335 audioElementArray.sort();
336
337 // display all information in HTML
338 // show XML file folder
339 document.getElementById('xmlFileFolder_span').innerHTML = "\""+xmlFileFolder+"/\"";
340 // show number of files
341 document.getElementById('numberOfFiles_span').innerHTML = fileNameArray.length;
342 // show list of subject names
343 document.getElementById('subjectArray_span').innerHTML = subjectArray.toString();
344 // show list of audioHolders
345 document.getElementById('audioHolderArray_span').innerHTML = audioHolderArray.toString();
346 // show list of audioElementes
347 document.getElementById('audioElementArray_span').innerHTML = audioElementArray.toString();
348 }
349
350 function makePlots() {
351 // create value array
352 var ratings = []; // 3D matrix of ratings (audioHolder, audioElement, subject)
353 for (audioHolderIndex = 0; audioHolderIndex < audioHolderNodes.length; audioHolderIndex++) {
354 ratings.push([]);
355 for (audioElementIndex = 0; audioElementIndex < audioElementNodes.length; audioElementIndex++) {
356 ratings[audioHolderIndex].push([]);
357 }
358 }
359
360 // go over all XML files
361 for (fileIndex = 0; fileIndex < xmlFiles.length; fileIndex++) {
362 xmlFileName = xmlFileFolder+"/"+xmlFiles[fileIndex];
363 xml = readXML(xmlFileName);
364 if (xml != null) { // if file exists
365 // get root of XML file
366 root = xml.getElementsByTagName('browserevaluationresult')[0];
367 // go over all audioHolders
368 audioHolderNodes = root.getElementsByTagName('audioholder');
369 for (audioHolderIndex = 0; audioHolderIndex < audioHolderNodes.length; audioHolderIndex++) {
370 audioHolderName = audioHolderNodes[audioHolderIndex].getAttribute('id');
371 audioElementNodes = audioHolderNodes[audioHolderIndex].getElementsByTagName('audioelement');
372 // go over all audioelements
373 for (audioElementIndex = 0; audioElementIndex < audioElementNodes.length; audioElementIndex++) {
374 audioElementName = audioElementNodes[audioElementIndex].getAttribute('id');
375 // get value
376 var value = audioElementNodes[audioElementIndex].getElementsByTagName("value")[0].textContent;
377 if (value) { // if not empty, null, undefined...
378 ratingValue = parseFloat(value);
379 // add to matrix
380 ratings[audioHolderIndex][audioElementIndex].push(ratingValue)
381 }
382 }
383 }
384
385 // go over all audioHolders
386
387 // 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
389 }
390 }
391
392 for (audioHolderIndex = 0; audioHolderIndex < audioHolderArray.length; audioHolderIndex++) {
393 audioHolderName = audioHolderArray[audioHolderIndex]; // for this song
394 tickArray = []
395 medianOfAudioElement = []
396
397 raw_data = [['SubjectID', 'Rating']];
398 audioElIdx = 0;
399 for (audioElementIndex = 0; audioElementIndex<ratings[audioHolderIndex].length; audioElementIndex++){
400 if (ratings[audioHolderIndex][audioElementIndex].length>0) {
401 audioElIdx++; // increase if not empty
402 // make tick label
403 tickArray.push({v:audioElIdx, f: audioElementArray[audioElementIndex]});
404 // add median
405 medianOfAudioElement.push(median(ratings[audioHolderIndex][audioElementIndex]));
406 }
407 for (subject = 0; subject<ratings[audioHolderIndex][audioElementIndex].length; subject++){
408 // add subject-value pair for each subject
409 raw_data.push([audioElIdx, ratings[audioHolderIndex][audioElementIndex][subject]]);
410 }
411 }
412
413 // create plot (one per song)
414 var data = google.visualization.arrayToDataTable(raw_data);
415
416 var options = {
417 title: audioHolderName,
418 hAxis: {title: 'Subject', minValue: 0, maxValue: audioElIdx+1,
419 ticks: tickArray},
420 vAxis: {title: 'Rating', minValue: 0, maxValue: 1},
421 seriesType: 'scatter',
422 legend: 'none'
423 };
424 var div = document.createElement('div');
425 document.body.appendChild(div);
426 div.id = 'div_'+audioHolderName;
427 div.style.width = '1100px';
428 div.style.height = '350px';
429 var chart = new google.visualization.ComboChart(document.getElementById('div_'+audioHolderName));
430 chart.draw(data, options);
431
432 // box plots
433 // function drawVisualization() {
434 // // Create and populate the data table.
435 // var data = google.visualization.arrayToDataTable([
436 // ['ID', 'IQR', '', '', '', 'Median', 'Average'],
437 // ['Serie1', 20, 28, 38, 45, 20, 25],
438 // ['Serie2', 31, 38, 55, 66, 30, 35],
439 // ['Serie3', 50, 55, 77, 80, 10, 15],
440 // ['Serie4', 77, 77, 66, 50, 20, 25],
441 // ['Serie5', 68, 66, 22, 15, 30, 35]
442 // // Treat first row as data as well.
443 // ]);
444 // // Create and draw the visualization.
445 // var ac = new google.visualization.ComboChart(document.getElementById('visualization'));
446 // ac.draw(data, {
447 // title : 'Box Plot with Median and Average',
448 // width: 600,
449 // height: 400,
450 // vAxis: {title: "Value"},
451 // hAxis: {title: "Serie ID"},
452 // series: { 0: {type: "candlesticks"}, 1: {type: "line", pointSize: 10, lineWidth:
453 // 0 }, 2: {type: "line", pointSize: 10, lineWidth: 0, color: 'black' } }
454 // });
455 // }
456 }
457 }
458
459 </script>
460
461
462
463 <style>
464 div {
465 padding: 2px;
466 margin-top: 2px;
467 margin-bottom: 2px;
468 }
469 div.head{
470 margin-left: 10px;
471 border: black;
472 border-width: 2px;
473 border-style: solid;
474 }
475 div.attrib{
476 margin-left:25px;
477 border: black;
478 border-width: 2px;
479 border-style: dashed;
480 margin-bottom: 10px;
481 }
482 div#headerMatter{
483 background-color: #FFFFCC;
484 }
485 div#currentStatement{
486 font-size:3.0em;
487 font-weight: bold;
488
489 }
490 div#debugDisplay {
491 color: #CCCCCC;
492 font-size:0.3em;
493 }
494 span#scoreDisplay {
495 font-weight: bold;
496 }
497 div#wrapper {
498 width: 780px;
499 border: 1px solid black;
500 overflow: hidden; /* add this to contain floated children */
501 }
502 div#instrumentSection {
503 width: 250px;
504 border: 1px solid red;
505 display: inline-block;
506 }
507 div#featureSection {
508 width: 250px;
509 border: 1px solid green;
510 display: inline-block;
511 }
512 div#valenceSection {
513 width: 250px;
514 border: 1px solid blue;
515 display: inline-block;
516 }
517 button#previousComment{
518 width: 120px;
519 height: 150px;
520 font-size:1.5em;
521 }
522 button#nextComment{
523 width: 666px;
524 height: 150px;
525 font-size:1.5em;
526 }
527 ul
528 {
529 list-style-type: none; /* no bullet points */
530 margin-left: -20px; /* less indent */
531 margin-top: 0px;
532 margin-bottom: 5px;
533 }
534 </style>
535
536 </head>
537
538 <body>
539 <h1>Subjective evaluation results</h1>
540
541 <div id="debugDisplay">
542 XML file folder: <span id="xmlFileFolder_span"></span>
543 </div>
544
545 <div id="headerMatter">
546 <div>
547 <strong>Result XML files:</strong> <span id="numberOfFiles_span"></span>
548 </div>
549 <div>
550 <strong>Audioholders in dataset:</strong> <span id="audioHolderArray_span"></span>
551 </div>
552 <div>
553 <strong>Subjects in dataset:</strong> <span id="subjectArray_span"></span>
554 </div>
555 <div>
556 <strong>Audioelements in dataset:</strong> <span id="audioElementArray_span"></span>
557 </div>
558 <br>
559 </div>
560 <br>
561
562 <!-- Show time elapsed
563 The last annotation took <strong><span id="timeDisplay">(N/A)</span></strong> seconds.
564 <br>-->
565
566 </body>
567 </html>