1var datasetName = ''; 2var datasetProp = 'Forces'; 3 4var type = 'linear'; 5var allLegendItemsHidden = false; 6var nLegendItemsHidden = 0 7 8var labelColor = 'rgb(109, 117, 125)'; 9var gridLineColor = 'rgb(222, 226, 230)'; 10var backgroundColor = 'rgb(248, 248, 250)'; 11var defaultLineColor = 'rgb(197, 204, 211)'; 12var highlightLineColor = 'rgb(139, 153, 167)'; 13var specialLineColor = 'rgb(40, 167, 69)'; 14 15var highlightIndex = -1; //index of currently hightlighted line 16 17// Custom plug-in that enables setting the background color of this chart 18Chart.pluginService.register({ 19 beforeDraw: function(chart, easing) { 20 if (chart.config.options.chartArea && chart.config.options.chartArea.backgroundColor) { 21 var helpers = Chart.helpers; 22 var ctx = chart.chart.ctx; 23 var chartArea = chart.chartArea; 24 25 ctx.save(); 26 ctx.fillStyle = chart.config.options.chartArea.backgroundColor; 27 ctx.fillRect(chartArea.left, chartArea.top, chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); 28 ctx.restore(); 29 } 30 } 31}); 32 33function loadChart() { 34 35 var datasetFile = datasetName + ((datasetProp == 'Forces') ? '_F' : '_E') + '.json' 36 $.getJSON('benchmark/datasets/' + datasetFile + '?' + Math.random().toString(36), function(res) { 37 38 function findWithAttr(array, attr, value) { 39 for (var i = 0; i < array.length; i += 1) 40 if (array[i][attr] === value) 41 return i; 42 return -1; 43 } 44 45 // Helper to get the dataset key 46 function getDatasetKey(dataset) { 47 return dataset.model_variant || dataset.ref_key; 48 } 49 50 var chart = window.chart; 51 var chartData = chart.config.data; 52 53 // Remove no longer needed datasets 54 var datasetKeys = chartData.datasets.map(dataset => dataset.label); 55 datasetKeys.forEach(key => { 56 var idx = findWithAttr(res, 'label', key); 57 58 if (idx < 0) { 59 var chartDatasetIdx = chartData.datasets 60 .map(dataset => getDatasetKey(dataset)) 61 .indexOf(key); 62 chartData.datasets.splice(chartDatasetIdx, 1); 63 } 64 }); 65 66 // Add new datasets 67 res.forEach(dataset => { 68 var datasetKey = getDatasetKey(dataset); 69 var existingIdx = chartData.datasets 70 .map(d => getDatasetKey(d)) 71 .indexOf(datasetKey); 72 73 if (existingIdx >= 0) { 74 chartData.datasets[existingIdx].data = dataset.data; 75 } else { 76 chartData.datasets.push({ 77 data: dataset.data, 78 label: datasetKey, 79 fill: false, 80 lineTension: 0, 81 hitRadius: 10, 82 radius: 4, 83 showLine: true, 84 borderCapStyle: 'round', 85 borderDash: (datasetKey === 'GDML' ? [0, 6] : 0), 86 pointStyle: 'circle', 87 borderWidth: 3, 88 borderColor: (datasetKey.includes("GDML") ? specialLineColor : defaultLineColor),
89 pointBackgroundColor: (datasetKey.includes("GDML") ? specialLineColor : defaultLineColor), 90 pointBorderColor: backgroundColor, 91 pointHoverBorderColor: backgroundColor, 92 pointBorderWidth: 1, 93 pointHoverWidth: 1, 94 pointHoverRadius: 6, 95 }); 96 } 97 }); 98 99 // Sort datasets: GDML first, sGDML second, rest alphabetically 100 chartData.datasets.sort((a, b) => { 101 if (a.label === "GDML") return -1; 102 if (b.label === "GDML") return 1; 103 if (a.label === "sGDML" && b.label !== "GDML") return -1; 104 if (b.label === "sGDML" && a.label !== "GDML") return 1; 105 return a.label.localeCompare(b.label); 106 }); 107 108 chart.config.options.scales.yAxes[0].scaleLabel.labelString = 'Mean absolute error ' + ((datasetProp == 'Forces') ? '[kcal/mol/Ã ]' : '[kcal/mol]') 109 chart.update(); 110 }).fail(function(d, textStatus, error) { 111 console.error('getJSON failed, status: ' + textStatus + ', error: ' + error); 112 alert('Oh nooo! I was not able to fetch the data.'); 113 }); 114} 115 116function highlightDataset(dataset, highlight) { 117 118 if (!dataset.label.includes("GDML")) { 119 color = highlight ? highlightLineColor : defaultLineColor; 120 dataset.borderColor = color;
121 dataset.pointBackgroundColor = color; 122 } 123} 124 125function setCurveHidingButtonStatus(on) { 126 if (on) { 127 $('#all-off-toggle').addClass('active'); 128 } else { 129 $('#all-off-toggle').removeClass('active'); 130 } 131} 132 133function populateRefs() { 134 135 var datasetFile = datasetName + ((datasetProp == 'Forces') ? '_F' : '_E') + '.json' 136 137 var refKeys = []; 138 $.getJSON('benchmark/datasets/' + datasetFile + '?' + Math.random().toString(36), function(res) { 139 140 const uniqueRefs = {}; 141 res.forEach(dataset => { 142 const refKey = dataset.ref_key; 143 const refLabel = ('ref_label' in dataset) ? dataset.ref_label : refKey; 144 145 const comboKey = JSON.stringify([refKey, refLabel]); // avoids delimiter collisions 146 if (!(comboKey in uniqueRefs)) { 147 uniqueRefs[comboKey] = {refKey:refKey, refLabel:refLabel}; 148 } 149 }); 150 151 $.getJSON('benchmark/refs.json?' + Math.random().toString(36), function(refs) { 152 153 var list = document.getElementById('refs') 154 list.innerHTML = ''; 155 156 // Sort: GDML first, sGDML second, others AâZ by refLabel 157 const refArray = Object.values(uniqueRefs); 158 refArray.sort((a, b) => { 159 const A = a.refLabel; 160 const B = b.refLabel; 161 162 if (A === "GDML") return -1; 163 if (B === "GDML") return 1; 164 if (A === "sGDML" && B !== "GDML") return -1; 165 if (B === "sGDML" && A !== "GDML") return 1; 166 167 return A.localeCompare(B, undefined, { sensitivity: 'base' }); 168 }); 169 170 refArray.forEach(({refKey, refLabel}) => { 171 172 var item = document.createElement('p'); 173 item.setAttribute('style', 'margin-left: 20px; text-indent: -20px; line-height: 1.2; margin-bottom: 5px;'); 174 175 var refStr = '<strong>[' + refLabel + ']</strong> ' 176 if (refKey in refs) { 177 178 var ref = refs[refKey]; 179 refStr += ref.authors + ' (' + ref.year + '). <em>' + ref.title + '</em>.'; 180 181 if (ref.journal != '') 182 refStr += ' ' + ref.journal 183 184 if (ref.volume != '') 185 refStr += ', ' + ref.volume 186 187 if (ref.page != '') 188 refStr += ', ' + ref.page 189 } else 190 refStr += '<span style="color:red;">MISSING!</span>' 191 192 refStr = '<small>' + refStr + '</small>' 193 item.innerHTML = refStr; 194 195 list.appendChild(item); 196 }); 197 }); 198 }); 199} 200 201$(function() { 202 203 var yAxes_lin = { 204 type: 'linear', 205 ticks: { 206 fontColor: labelColor, 207 fontSize: 14, 208 padding: 12, 209 autoskip: true, 210 autoSkipPadding: 30, 211 callback: function(label, index, labels) { 212 return label.toFixed(2); 213 } 214 }, 215 scaleLabel: { 216 labelString: 'Mean absolute error [kcal/mol/A]', 217 display: true, 218 fontColor: labelColor, 219 fontSize: 14, 220 fontStyle: 'bold', 221 }, 222 gridLines: { 223 //borderDash: [2, 2], 224 color: gridLineColor, 225 zeroLineWidth: 0, 226 drawTicks: false, 227 } 228 } 229 230 var yAxes_log = Object.assign(yAxes_lin) 231 yAxes_log['type'] = 'logarithmic' 232 233 var opts = { 234 chartArea: { 235 backgroundColor: backgroundColor, 236 }, 237 responsive: true, 238 legend: { 239 labels: { 240 //padding: 20, 241 fontColor: labelColor, 242 usePointStyle: true, 243 boxWidth: 5.5, 244 }, 245 position: 'right', 246 align: 'start', 247 // onHover: function(event, legendItem) { 248 249 // var chart = window.chart 250 251 // if (chart.hoveringLegendIndex != legendItem.datasetIndex) { 252 // chart.hoveringLegendIndex = legendItem.datasetIndex; 253 254 // var dataset = chart.data.datasets[legendItem.datasetIndex] 255 // highlightDataset(dataset, true) 256 257 // if (!dataset.label.includes('GDML')) 258 // legendItem.fillStyle = highlightLineColor; 259
260 // console.log('enter: ' + legendItem.datasetIndex) 261 262 // chart.draw(); 263 // } 264 // }, 265 // onLeave: function(event, legendItem) { 266 267 // var chart = window.chart; 268 269 // if (chart.hoveringLegendIndex >= 0) { 270 // chart.hoveringLegendIndex = -1; 271 272 // console.log('leave: ' + legendItem.datasetIndex); 273 274 // var dataset = chart.data.datasets[legendItem.datasetIndex]; 275 // highlightDataset(dataset, false) 276 277 // if (!dataset.label.includes('GDML')) 278 // legendItem.fillStyle = defaultLineColor; 279 280 // chart.update(); 281 // } 282 // }, 283 onClick: function(event, legendItem) { 284 285 //if (legendItem.text.includes('GDML')){ 286 // event.stopPropagation(); 287 // return; 288 //} 289 290 var chart = window.chart 291 292 var datasets = chart.data.datasets 293 var filteredDatasets = datasets.filter(function(dataset) { 294 return !dataset.label.includes('GDML'); 295 }); 296 297 var index = legendItem.datasetIndex; 298 var dataset = datasets[index]; 299 var meta = chart.getDatasetMeta(index); 300 301 dataset.hidden = !dataset.hidden 302 meta.hidden = meta.hidden === null ? dataset.hidden : null; 303 304 if (!dataset.label.includes('GDML')) 305 nLegendItemsHidden += meta.hidden ? 1 : -1; 306 307 if (nLegendItemsHidden == 0) { 308 setCurveHidingButtonStatus(false); 309 allLegendItemsHidden = false; 310 } else if (nLegendItemsHidden == filteredDatasets.length) { 311 setCurveHidingButtonStatus(true); 312 allLegendItemsHidden = true; 313 } 314 chart.update(); 315 316 console.log(nLegendItemsHidden); 317 }, 318 }, 319 tooltips: { 320 mode: 'point', 321 intersect: true, 322 displayColors: false, 323 titleFontSize: 16, 324 bodyFontSize: 14, 325 itemSort: (a, b, data) => b.yLabel - a.yLabel, 326 callbacks: { 327 label: function(tooltipItem, data) { 328 var label = data.datasets[tooltipItem.datasetIndex].label || ''; 329 330 if (label) 331 label += ': '; 332 label += (Math.round(tooltipItem.yLabel * 1000) / 1000).toFixed(3); 333 334 return label; 335 }, 336 title: function(tooltipItem, data) { 337 var tick = tooltipItem[0].xLabel 338 339 tick_str = tick 340 if (tick === 1000 || tick === 15000 || tick === 50000 || tick === 100000) 341 tick_str = (tick / 1000).toString() + 'k'; 342 343 return tick_str + ' points'; 344 }, 345 }, 346 }, 347 hover: { 348 mode: 'nearest', 349 intersect: true, 350 }, 351 onHover: function(event, activeElements) { 352 353 if (highlightIndex >= 0) { 354 this.data.datasets.forEach(function(dataset) { 355 highlightDataset(dataset, false) 356 }); 357 } 358 359 if (!activeElements || !activeElements.length) { 360 if (highlightIndex == -1) 361 return 362 else 363 highlightIndex = -1; 364 } else { 365 highlightIndex = activeElements[0]._datasetIndex; 366 var dataset = this.data.datasets[highlightIndex]; 367 highlightDataset(dataset, true) 368 } 369 370 // Twice, otherwise legend does not update 371 this.update(); 372 this.update(); 373 }, 374 title: { 375 display: false, 376 }, 377 scales: { 378 xAxes: [{ 379 type: 'logarithmic', 380 position: 'bottom', 381 ticks: { 382 userCallback: function(tick) { 383 384 if (tick === 200 || tick === 400 || tick === 600 || tick === 800) 385 return tick.toString(); 386 387 if (tick === 1000 || tick === 15000 || tick === 50000 || tick === 100000) 388 return (tick / 1000).toString() + 'k'; 389 390 }, 391 min: 200, 392 max: 50000, 393 autoSkip: true, 394 stepSize: 100, 395 fontColor: labelColor, 396 fontSize: 14, 397 padding: 12, 398 }, 399 scaleLabel: { 400 labelString: 'Training dataset size [# points]', 401 display: true, 402 fontColor: labelColor, 403 fontSize: 14, 404 fontStyle: 'bold', 405 }, 406 gridLines: { 407 //borderDash: [2, 2], 408 color: gridLineColor,
409 zeroLineWidth: 0, 410 drawTicks: false, 411 } 412 }], 413 yAxes: [yAxes_lin] 414 }, 415 }; 416 417 var ctx = document.getElementById('chart').getContext('2d'); 418 var chart = window.chart = Chart.Line(ctx, { 419 data: {}, 420 type: 'line', 421 options: opts, 422 }); 423 424 $('#scale-toggle').change(function() { 425 426 type = type === 'linear' ? 'logarithmic' : 'linear'; 427 428 chart.options.scales.yAxes[0] = (type === 'linear') ? yAxes_lin : yAxes_log; 429 chart.options.scales.yAxes[0].display = true; 430 chart.options.scales.yAxes[0].type = type; 431 432 chart.update(); 433 }) 434 435 $('#all-off-toggle').on('click', function(event) { 436 437 var datasets = chart.data.datasets 438 var filteredDatasets = datasets.filter(function(dataset) { 439 return !dataset.label.includes('GDML'); 440 }); 441 442 allLegendItemsHidden = !allLegendItemsHidden; 443 nLegendItemsHidden = allLegendItemsHidden ? filteredDatasets.length : 0; 444 setCurveHidingButtonStatus(allLegendItemsHidden) 445 446 filteredDatasets.forEach(function(dataset) {
447 Object.keys(dataset._meta).forEach(key => { 448 dataset._meta[key].hidden = allLegendItemsHidden; 449 }) 450 }); 451 452 chart.update(); 453 }) 454 455 $('#benchmarkModal').on('show.bs.modal', function(e) { 456 datasetName = $(e.relatedTarget).data('dataset-name'); 457 document.getElementById('benchmarkModalMoleculeName').innerHTML = datasetName; 458 459 // Reset tabs 460 datasetProp = 'Forces'; 461 $(this).find('.nav-tabs a:first').tab('show'); 462 463 // Reset scale type 464 type = 'linear'; 465 chart.options.scales.yAxes[0].type = type; 466 $('#scale-toggle').prop('checked', false).change() 467 468 // Reset chart 469 chart["config"]["data"] = { 470 'datasets': [] 471 } 472 chart.update(); 473 474 // Reset toggle button 475 allLegendItemsHidden = false; 476 nLegendItemsHidden = 0 477 setCurveHidingButtonStatus(false) 478 479 populateRefs(); 480 481 }); 482 483 $('#benchmarkModal').on('shown.bs.modal', function(e) { 484 loadChart(); 485 }); 486 487 $('a[data-toggle="tab"]').on('show.bs.tab', function(e) { 488 datasetProp = $(e.target).text(); 489 490 if (datasetProp == 'Forces' || datasetProp == 'Energy') { 491 populateRefs(); 492 } 493 494 }); 495 496 $('a[data-toggle="tab"]').on('shown.bs.tab', function(e) { 497 tabName = $(e.target).text(); 498 if (tabName == 'Forces' || tabName == 'Energy') { 499 loadChart(); 500 } 501 }); 502 503 504 //disable hoever effects if mouse moves off chart canvas 505 //chart.hoveringLegendIndex = -1 506 // chart.canvas.addEventListener('mousemove', function(e) { 507 508 // //if (chart.hoveringLegendIndex >= 0) { 509 510 // if (e.layerX < chart.legend.left || chart.legend.right < e.layerX 511 // || e.layerY < chart.legend.top || chart.legend.bottom < e.layerY 512 // ) { 513 514 // //console.log('out') 515 516 // //if (chart.hoveringLegendIndex >= 0) { 517 518 // //var dataset = chart.data.datasets[legendItem.datasetIndex] 519 // //if (!dataset.label.includes("GDML")) { 520 // // dataset.borderColor = 'rgb(197, 204, 211)';
521 // // dataset.pointBackgroundColor = 'rgb(197, 204, 211)'; 522 // //} 523 // //dataset.radius = 4; 524 525 // //chart.hoveringLegendIndex = -1 526 // chart.update() 527 // //} 528 // //chart.update() 529 // } 530 // //} 531 // }); 532 533});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.