chart = Plot.plot({
width: width,
height: height,
x: {domain: [0, 110], label: null},
y: {label: "Student", label: null},
style: {fontSize: "16px"},
marginRight: 50,
legend: {marginBottom: 50},
color: {domain: allAssignmnets, range: colorRange, legend: true, width: 500, columns:1},
marks: [
Plot.text(gradeBoundaries, {x: "x", text: "grade", fontSize: "10px", textAnchor: "start", dx: 3, dy: -280}),
Plot.text(gradeBoundaries, {x: "x", text: "grade", fontSize: "10px", textAnchor: "start", dx: 3, dy: 270}),
Plot.ruleX([0, 30, 40, 50, 60, 63, 67, 70, 73, 77, 80, 83, 87, 90, 93, 100]),
Plot.barX(tidydata.filter(f => f.points && f.assignment !== "total"), {
x: "points",
y: "emoji",
fill: "assignment",
stroke: "white",
sort: {y: "-x"},
tip: true,
title: d => d.emoji + " " + d.student + "\n\n" + d.assignment.split("(")[0] + "\n\nCurrent grade: " + d.points
}),
Plot.text(tidydata.filter(f => f.assignment === "total"), {
x: 0,
y: "emoji",
text: "student",
textAnchor: "start",
fill: "black",
stroke: "white",
strokeWidth: 3,
fontSize: "14px",
strokeOpacity: 0.4,
paintOrder: "stroke",
pointerEvents: "none",
dx: 10
}),
showForecast ?
Plot.link(tidydata.filter(f => f.assignment === "total"), {
x1: forecastMin,
x2: forecastMax,
y1: d => d["emoji"],
y2: d => d["emoji"],
markerEnd: "dot",
markerStart: "dot",
strokeWidth: 2,
stroke: "black"
}) : null,
showForecast ?
Plot.text(tidydata.filter(f => f.assignment === "total"), {
x: forecastMin,
y: "emoji",
text: d => d["points"] === d3.max(tidydata, a => a.points) ? "FORECAST low & high": "",
textAnchor: "start",
dx: 5,
dy: -10,
stroke: "white",
strokeWidth: 4,
fontSize: "10px",
paintOrder: "stroke",
fill: "black",
}) : null,
Plot.text(tidydata.filter(f => f.assignment === "total"), {
x: "points",
y: "emoji",
text: (d) => Math.floor(d.points),
textAnchor: "start",
fill: "black",
stroke: "white",
strokeWidth: 3,
fontSize: "14px",
paintOrder: "stroke",
dx: 2
}),
Plot.image(tidydata.slice(0,1), {
x: width,
y: "emoji",
width: 200,
src: "https://i.redd.it/1o8zqjm9bqc81.png"
})
]
})