source: src/main/webapp/plotlog.xhtml@ 16

Last change on this file since 16 was 16, checked in by bart, 4 years ago

Added BOA support, some bug fixes

File size: 11.2 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
3<head>
4<title>Plot log results</title>
5<script src="Chart.min_2.8.0.js"></script>
6</head>
7<style>
8canvas {
9 -moz-user-select: none;
10 -webkit-user-select: none;
11 -ms-user-select: none;
12}
13</style>
14<body>
15 <div class="noscript">
16 <h2 style="color: #ff0000">Seems your browser doesn't support
17 Javascript! Websockets rely on Javascript being enabled. Please
18 enable Javascript and reload this page!</h2>
19 </div>
20 <h1 id="header">Graph of log results</h1>
21
22 Progress:
23 <div id="progress">Waiting for log file name</div>
24 <br />
25 <div>Notice, the plotted utilities do not include possible elicitation costs.</div>
26 <div style="width: 100%;">
27 <canvas id="canvas"></canvas>
28 </div>
29
30 Agreement: <div id="agreement" style="display:inline;">?</div>
31</body>
32
33<!-- Script to get/update the SESSIONS list and put it into the table. -->
34<script type="application/javascript">
35
36
37
38
39
40
41
42
43
44 <![CDATA[
45 "use strict";
46
47
48
49 var ws = null;
50
51 <!-- Most functions are reactive programming written out-->
52
53 function connect() {
54
55 var id=document.location.search;
56 id = location.search.split('id=')[1]
57 if (id==undefined) return;
58
59 // load the log file with given id
60 document.getElementById('header').innerHTML="Graph of log "+id;
61
62 var url = "log/"+id+".json";
63 setStatus("Downloading file "+url);
64 var request=new XMLHttpRequest();
65 request.responseType = 'text';
66 request.open('Get', url)
67 request.onload=function() {
68 if (request.status!=200) {
69 setStatus("Failed to fetch "+url+":" +request.status+" "+request.statusText)
70 return;
71 }
72 processLogFile(JSON.parse(request.response));
73 }
74 request.send();
75 }
76
77
78 /**
79 Figure out the protocol contents and parse accordingly.
80 */
81 function processLogFile(json) {
82 if (json['SAOPState']!=undefined) {
83 processSAOP(json['SAOPState']);
84 } else if (json['SHAOPState']!=undefined) {
85 processSHAOP(json['SHAOPState']);
86 } else {
87 setStatus("Unknown log file contents "+Object.keys(json));
88 }
89 }
90
91 /**
92 Handle SAOP protocol result.
93 */
94 function processSAOP(json) {
95 var partyprofiles={}
96 var profs=json['partyprofiles'];
97 for (var party in profs) {
98 partyprofiles[party]=profs[party]['profile'].split('?',1)[0]; // hacky, remove complete query.
99 }
100
101 getProfiles(json, partyprofiles);
102 }
103
104 /**
105 Handle SHAOP protocol result. Get only SHAOP profiles. Remove all 'partial=XX' from relevant profiles.
106 */
107 function processSHAOP(json) {
108 var partyprofiles={}
109 var teams=json['settings']['SHAOPSettings']['participants'];
110 for (var partyid in json['partyNumbers']) {
111 var nr= json['partyNumbers'][partyid];
112 if ( (nr & 1 != 0)) continue; // skip COB parties
113 var shaop=teams[nr/2]['shaop'];
114 var profile = shaop['profile'].split('?',1)[0]; // hacky, remove complete query.
115 partyprofiles[partyid]=profile;
116 }
117
118
119 getProfiles(json, partyprofiles);
120 }
121
122
123 /**
124 Get the partyprofiles.
125 @json the json protocol result
126 @partyprofileURIs dict with the websocket addresses for each party'as profile
127 @partyprofiles dict with each party's profile. Initially should be {}
128 */
129 function getProfiles(json, partyprofileURIs, partyprofiles={}) {
130 var keys = Object.keys(partyprofileURIs);
131 if (keys.length==0) {
132 plotResults(computeUtils(json, partyprofiles), isAgreement(json));
133 return;
134 }
135 var party = keys[0];
136 var uri=partyprofileURIs[party];
137 delete partyprofileURIs[party];
138
139 setStatus("fetching profile "+uri);
140 if ('WebSocket' in window) {
141 ws = new WebSocket(uri);
142 } else if ('MozWebSocket' in window) {
143 ws = new MozWebSocket(uri);
144 } else {
145 setStatus('Fatal: WebSocket is not supported by this browser. Please use a newer browser');
146 return;
147 }
148 ws.onmessage = function (event) {
149 var profile = JSON.parse(event.data);
150 if (profile['LinearAdditiveUtilitySpace']==undefined) {
151 setStatus('Fatal: profile '+uri+" does not contain a LinearAdditiveUtilitySpace.");
152 return;
153 }
154 partyprofiles[party]=profile['LinearAdditiveUtilitySpace'];
155 getProfiles(json, partyprofileURIs, partyprofiles);
156 };
157 ws.onerror=function(event) {
158 setStatus('Error fetching profile '+uri+':'+event);
159 }
160 }
161
162 /**
163 @return true if there is agreement
164 */
165 function isAgreement(logfile) {
166 var actions=logfile['actions'];
167 var lastact = actions[actions.length -1];
168 return 'accept' in lastact;
169 }
170 /**
171 @json the log file contents
172 @param partyprofiles a dict with key=party id and value a the (linear additive) profile
173 */
174 function computeUtils(json, partyprofiles) {
175
176 setStatus("Computing utilities.")
177 var utilities={};
178 for (var party in partyprofiles) {
179 utilities[party]=[];
180 }
181 var actions = json['actions'];
182 for (var action in actions) {
183 var offer = actions[action];
184 if (offer['offer']==undefined)
185 continue;
186 var issueutilities = offer['offer']['bid']['issuevalues']
187 for (var party in partyprofiles) {
188 utilities[party].push(utility(partyprofiles[party],issueutilities));
189 }
190 }
191 return utilities;
192
193
194 }
195
196 var chartColors = [
197 'rgb(255, 99, 132)',
198 'rgb(3, 192, 12)',
199 'rgb(54, 162, 235)',
200 'rgb(153, 102, 255)',
201 'rgb(201, 203, 207)',
202 'rgb(255, 159, 64)',
203 'rgb(255, 205, 86)'
204 ];
205
206 function color(i) {
207 return chartColors[i % chartColors.length];
208 }
209
210 /**
211 @param utilities the dict with key=party id of the utilities of all steps for each party )
212 @param isAgreement true iff there is agreement reached
213 */
214
215 function plotResults( utilities, isAgreement) {
216 setStatus("Plotting" )
217
218 document.getElementById('agreement').innerHTML=isAgreement?"Yes":"No";
219
220 var parties=Object.keys(utilities);
221 var thelabels=[];
222 for (var i=1; i<=utilities[parties[0]].length; i++) { thelabels.push(i); }
223
224 var thedatasets=[];
225 var partynr=0;
226 for (var party in utilities) {
227 var dataset={
228 label: party,
229 lineTension:0, // straight lines between the points
230 backgroundColor: color(partynr),
231 borderColor: color(partynr),
232 data: utilities[party],
233 fill: false
234 };
235 thedatasets.push(dataset);
236 partynr++;
237 }
238
239 var config = {
240 type: 'line',
241 data: {
242 labels: thelabels,
243 datasets: thedatasets
244 },
245 options: {
246 responsive: true,
247 title: {
248 display: true,
249 text: 'Per-turn utility plot'
250 },
251 tooltips: {
252 mode: 'index',
253 intersect: false,
254 },
255 hover: {
256 mode: 'nearest',
257 intersect: true
258 },
259 scales: {
260 xAxes: [{
261 display: true,
262 scaleLabel: {
263 display: true,
264 labelString: 'Turn'
265 }
266 }],
267 yAxes: [{
268 display: true,
269 scaleLabel: {
270 display: true,
271 labelString: 'Utility'
272 }
273 }]
274 }
275 }
276 };
277
278 var ctx = document.getElementById('canvas').getContext('2d');
279 window.myLine = new Chart(ctx, config);
280
281 setStatus("Plot ready." )
282
283 }
284
285 /**
286 keys are STRING objects 0,1,2... values are utility values (double)
287 */
288 function makeJxPolyline(pointslist) {
289 var jxpoints = []
290 for (var i in pointslist) {
291 jxpoints.push(new jxPoint(20*Number(i), 100*pointslist[i]));
292 }
293 return jxpoints;
294 }
295
296 /******************* Private support funcs****************/
297
298 /**
299 Set the progress/status text
300 */
301 function setStatus(text) {
302 document.getElementById('progress').innerHTML=text;
303 }
304
305 /*
306 @param sessions a list of IDs (Strings).
307 */
308 function update(sessions) {
309 var table = document.getElementById("sessionsTable");
310 table.innerHTML="";
311 for(var session of sessions) {
312 var row = table.insertRow(-1); //-1 = end
313 row.insertCell(0).innerHTML = session;
314 }
315
316 }
317
318
319
320
321 /**
322 Compute utilityes
323 @param linadditive the linear additive utility space
324 @param issueValues the bid containing dict with values for the issues
325 @return utility of issueValues
326 */
327 function utility(profile, issueValues) {
328 var util=0;
329 var weights = profile['issueWeights'];
330
331 for (var issue in issueValues) {
332 util = util + weights[issue] * evaluate(profile['issueUtilities'][issue], issueValues[issue] );
333 }
334 return util;
335 }
336
337 /**
338 Bit hacky, javascript version of evaluator of utility space.
339 Would be much nicer if we could use java here
340 */
341 function evaluate (utilfunc, value) {
342 if (utilfunc == undefined) {
343 return 0;
344 }
345 if (utilfunc['numberutils']!=undefined) {
346 // it's numeric issue. Compute
347 var minval = utilfunc['numberutils']['lowValue'];
348 var minutil = utilfunc['numberutils']['lowUtility'];
349 var maxval = utilfunc['numberutils']['highValue'];
350 var maxutil = utilfunc['numberutils']['highUtility'];
351
352 var alfa = (value-minval) / (maxval - minval) ;
353 alfa = Math.max(Math.min(alfa, 1),0);
354 return alfa * maxutil + (1-alfa) * minutil;
355 }
356 if (utilfunc['discreteutils']!=undefined) {
357 // it's discrete issue. Compute
358 return utilfunc['discreteutils']['valueUtilities'][value];
359 }
360 setStatus("Unknown utility function type "+Object.keys(utilfunc));
361
362 }
363
364
365 ]]>
366
367
368
369
370
371
372
373</script>
374
375
376
377<script type="application/javascript">
378
379
380
381
382
383
384
385 <![CDATA[
386 "use strict";
387 /*
388 This is called when the window DOM is loaded. window.onload runs BEFORE the window is loaded
389 and therefore is too early to remove the noscript message.
390 */
391 document.addEventListener("DOMContentLoaded", function() {
392 // Remove elements with "noscript" class - <noscript> is not allowed in XHTML
393 var noscripts = document.getElementsByClassName("noscript");
394 for (var i = 0; i < noscripts.length; i++) {
395 noscripts[i].parentNode.removeChild(noscripts[i]);
396 }
397 connect();
398
399 }, false);
400 ]]>
401
402
403
404
405
406
407
408
409</script>
410
411
412</html>
Note: See TracBrowser for help on using the repository browser.