Spaces:
Running
Running
// Space out the shapes a bit | |
shapeParams.forEach((d) => (d.startX = d.startX * 1.1)); | |
// How to draw the background boxes, which will be styled later | |
const classifierBgPathTop = "M 420 150 H 0 V 0 H 420 V 150"; | |
const classifierBgPathBottom = "M 420 300 H 0 V 0 H 420 V 300"; | |
const toDropdownValueStringDict = { | |
shape_name: "circles, triangles, or rectangles", | |
pointiness: "pointy shapes or round shapes", | |
size: "small shapes or big shapes", | |
}; | |
const toShortValueStringDict = { | |
shape_name: "circles, triangles, or rectangles", | |
pointiness: "pointy or round", | |
size: "small or big", | |
}; | |
const toDropdownValueRoundingStringDict = { | |
true: "with our best guess", | |
false: 'as "other"', | |
}; | |
const toPropertyStringDict = { | |
pointy: "pointy shapes", | |
round: "round shapes", | |
small: "small shapes", | |
large: "big shapes", | |
circle: "circles", | |
triangle: "triangles", | |
rect: "rectangles", | |
}; | |
function toOriginalString(inputString) { | |
for (const [key, value] of Object.entries(toPropertyStringDict)) { | |
if (inputString == value) { | |
return key; | |
} | |
} | |
} | |
function toPropertyString(inputProperty, isRounding = true) { | |
if (!isRounding && inputProperty.startsWith("rt_")) { | |
return "others"; | |
} | |
return toPropertyStringDict[inputProperty.replace("rt_", "")]; | |
} | |
// Dictionary mapping div name to classifier results and summary sentences | |
var allResults = {}; | |
var summaries = {}; | |
function toBool(inputString) { | |
if (inputString == "true") { | |
return true; | |
} | |
return false; | |
} | |
function updateResults() { | |
allResults["default-classifier"] = calculateResults(); | |
allResults["second-classifier"] = calculateResults( | |
"shape_name", | |
toBool( | |
document.getElementById("second-classifier-select-rounding").value | |
) | |
); | |
allResults["final-classifier"] = calculateResults( | |
document.getElementById("final-classifier-select-category").value, | |
toBool( | |
document.getElementById("final-classifier-select-rounding").value | |
) | |
); | |
allResults["conclusion"] = calculateResults( | |
document.getElementById("conclusion-select-category").value, | |
true | |
); | |
updateSummaries(); | |
updateSecondInterfaceImages(); | |
} | |
// Text summaries are written by hand for simplicity, and keyed simply by | |
// a string of the form "[category]:[useGuess]" (or simply "none"). | |
// These are hashed in the same way as the results, by div name. | |
function updateSummaries() { | |
summaries["default-classifier"] = getPerformanceSummary("none"); | |
summaries["second-classifier"] = getPerformanceSummary( | |
"shape_name:" + | |
document.getElementById("second-classifier-select-rounding").value | |
); | |
summaries["final-classifier"] = getPerformanceSummary( | |
document.getElementById("final-classifier-select-category").value + | |
":" + | |
document.getElementById("final-classifier-select-rounding").value | |
); | |
summaries["conclusion"] = getPerformanceSummary( | |
document.getElementById("conclusion-select-category").value + ":" + true | |
); | |
} | |
// Yes, these background colors are hardcoded in, | |
// no, this is not good design, this is just how it happened. | |
function getPerformanceSummary(key) { | |
allSummaries = { | |
"shape_name:true": | |
'<mark style="background-color: rgb(206, 234, 135);" class="well">well</mark> on circles, <mark style="background-color: rgb(244, 123, 74);" class="terribly">terribly</mark> on triangles, and <mark style="background-color: rgb(173, 220, 114);" class="best">best</mark> on rectangles', | |
"shape_name:false": | |
'<mark style="background-color: rgb(251, 163, 94);" class="poorly">poorly</mark> on circles, <mark style="background-color: rgb(155, 212, 108);" class="best">best</mark> on triangles and rectangles, and <mark style="background-color: rgb(252, 244, 171);" class="fine">fine</mark> on other shapes', | |
"pointiness:true": | |
'<mark style="background-color: rgb(184, 225, 119);" class="better">better</mark> on pointy shapes and <mark style="background-color: rgb(254, 206, 125);" class="worse">worse</mark> on round shapes', | |
"pointiness:false": | |
'<mark style="background-color: rgb(140, 205, 104);" class="best">best</mark> on pointy shapes, <mark style="background-color: rgb(243, 248, 171);" class="fine">fine</mark> on round shapes, and <mark style="background-color: rgb(253, 190, 111);" class="poorly">poorly</mark> on other shapes', | |
"size:true": | |
'<mark style="background-color: rgb(206, 234, 135);" class="better">better</mark> on small shapes, <mark style="background-color: rgb(254, 232, 154);" class="worse">worse</mark> on big shapes', | |
"size:false": | |
'<mark style="background-color: rgb(254, 215, 135);" class="poorly">poorly</mark> on small shapes, <mark style="background-color: rgb(165, 0, 38); color: #FFCCD8;" class="terribly">terribly</mark> on big shapes, and <mark style="background-color: rgb(110, 192, 99);" class="best">best</mark> on other shapes', | |
"none:true": | |
'<mark style="background-color: rgb(246, 248, 173);" class="fine">fine</mark> on all shapes', | |
"none:false": | |
'<mark style="background-color: rgb(246, 248, 173);" class="fine">fine</mark> on all shapes', | |
none: '<mark style="background-color: rgb(246, 248, 173);" class="fine">fine</mark> on all shapes', | |
}; | |
return "The Is-Shaded Classifier performs " + allSummaries[key] + "."; | |
} | |
// On the second-classifier dropdown, update the "task interface" image. | |
function updateSecondInterfaceImages() { | |
d3.select(".second-interface").html(function () { | |
if ( | |
!document.getElementById("second-classifier-select-rounding").value | |
) { | |
return; | |
} | |
var imgPath = | |
"img/interface_shape_name_" + | |
document.getElementById("second-classifier-select-rounding").value; | |
return ( | |
'<img src="' + | |
imgPath + | |
'.png" alt="" class="interface-image" srcset="' + | |
imgPath + | |
'.svg"></img>' | |
); | |
}); | |
} | |
// Calculate results given input parameters | |
function calculateResults(property = "none", useGuess = false) { | |
switch (property) { | |
case "none": | |
var nAccurate = shapeParams.filter( | |
(shape) => shape.correctness == "correct" | |
).length; | |
var totalShapes = shapeParams.length; | |
var results = [ | |
{ | |
object: "shape", | |
n: totalShapes, | |
"n correct": nAccurate, | |
accuracy: (nAccurate / totalShapes).toFixed(3), | |
rawCategoryName: "none", | |
}, | |
]; | |
return results; | |
case "pointiness": | |
categories = ["pointy", "round"]; | |
break; | |
case "size": | |
categories = ["small", "large"]; | |
break; | |
case "shape_name": | |
categories = ["circle", "triangle", "rect"]; | |
break; | |
} | |
var results = []; | |
if (useGuess == true) { | |
// Rounding shapes to categories | |
for (const category of categories) { | |
// Get shapes that are either in this category (e.g. rectangle) or "rounds to" this category (e.g. rt_rectangle) | |
var theseShapes = shapeParams.filter( | |
(shape) => | |
shape[property] == category || | |
shape[property] == "rt_" + category | |
); | |
var nAccurate = theseShapes.filter( | |
(shape) => shape.correctness == "correct" | |
).length; | |
var totalShapes = theseShapes.length; | |
results.push({ | |
object: toPropertyString(category), | |
n: totalShapes, | |
"n correct": nAccurate, | |
accuracy: (nAccurate / totalShapes).toFixed(3), | |
rawCategoryName: category, | |
}); | |
} | |
} else { | |
// Not rounding, treat everything else as "other" | |
// First go through existing categories | |
for (const category of categories) { | |
var theseShapes = shapeParams.filter( | |
(shape) => shape[property] == category | |
); | |
var nAccurate = theseShapes.filter( | |
(shape) => shape.correctness == "correct" | |
).length; | |
var totalShapes = theseShapes.length; | |
results.push({ | |
object: toPropertyString(category), | |
n: totalShapes, | |
"n correct": nAccurate, | |
accuracy: (nAccurate / totalShapes).toFixed(3), | |
rawCategoryName: category, | |
}); | |
} | |
// Now get "other" shapes | |
var theseShapes = shapeParams.filter( | |
(shape) => !categories.includes(shape[property]) | |
); | |
var nAccurate = theseShapes.filter( | |
(shape) => shape.correctness == "correct" | |
).length; | |
var totalShapes = theseShapes.length; | |
results.push({ | |
object: "other shapes", | |
n: totalShapes, | |
"n correct": nAccurate, | |
accuracy: (nAccurate / totalShapes).toFixed(3), | |
rawCategoryName: "other", | |
}); | |
} | |
return results; | |
} | |