// 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; }