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