// 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":
'well on circles, terribly on triangles, and best on rectangles',
"shape_name:false":
'poorly on circles, best on triangles and rectangles, and fine on other shapes',
"pointiness:true":
'better on pointy shapes and worse on round shapes',
"pointiness:false":
'best on pointy shapes, fine on round shapes, and poorly on other shapes',
"size:true":
'better on small shapes, worse on big shapes',
"size:false":
'poorly on small shapes, terribly on big shapes, and best on other shapes',
"none:true":
'fine on all shapes',
"none:false":
'fine on all shapes',
none: 'fine 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 (
''
);
});
}
// 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;
}