Public
Edited
Aug 28, 2023
Insert cell
Insert cell
Insert cell
data2023F = FileAttachment("Self-Introduction Responses F2023 - Form responses 1.csv").csv()
Insert cell
data2023S = FileAttachment("Self-Introduction Responses S2023 - Form responses 1.csv").csv()
Insert cell
data2022F = FileAttachment("Self-Introduction Responses F2022 - Form responses 1.csv").csv()
Insert cell
angie = ([{
"How would you rate your drawing and artistic skills?": 4,
"How would you rate your Information Visualization skills?": 10,
"How would you rate your statistical skills?": 7,
"How would you rate your mathematics skills?": 5,
"How would you rate your computer usage skills?": 8,
"How would you rate your programming skills?": 6,
"How would you rate your user experience evaluation skills?": 6,
"How would you rate your communication skills?": 7,
"How would you rate your collaboration skills?": 6,
"How would you rate your code repository skills?": 10
}])
Insert cell
data = []
.concat(data2022F.map(m => ({category: "2022 Fall", ...m})))
.concat(data2023S.map(m => ({category: "2023 Spring", ...m})))
.concat(data2023F.map(m => ({category: "2023 Fall", ...m})))
.concat(angie.map(m => ({category: "angie", ...m})));

Insert cell
currentSemester = "2023 Fall"
Insert cell
Insert cell
height = 840
Insert cell
margin = ({top: 50, right: 10, bottom: 20, left: 10})
Insert cell
CATEGORY = "category"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
//make an SVG container
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);

//d3 path generator (helper function)
let line = d3.line()
.defined(([, value]) => value != null)
.x(([key, value]) => x[key](value))
.y(([key]) => y(key))

//draw the marks
const marks = svg.append("g")
.attr("fill", "none")
.attr("stroke-opacity", opacity)
.attr("stroke-linejoin", "round")
.selectAll("path")
.data(data)
.join("g")
.call(g => {
//white shadows below the lines
g.append("path")
.attr("stroke", "white")
.attr("class", "shadow")
.attr("stroke-width", 5)
.attr("d", d => line(d3.cross(keys, [d], (key, d) => [key, d[key]])))

//actually visible lines
g.append("path")
.attr("class", "foreground")
.attr("stroke-width", 2)
.attr("stroke", d => z(d[CATEGORY]))
.attr("d", d => line(d3.cross(keys, [d], (key, d) => [key, d[key]])))
})

//add interactivity
marks.on("mouseover", (event, me) => {
if(me[CATEGORY] !== currentSemester && me[CATEGORY] !== "angie") return;
marks.selectAll("path").style("stroke-opacity", d => d == me ? 1 : 0.2)
marks.selectAll(".shadow").style("stroke-width", d => d == me ? 10 : 2)
marks.selectAll(".foreground").style("stroke-width", d => d == me ? 6 : 2)
});
marks.on("mouseout", (event, me) => {
if(me[CATEGORY] !== currentSemester && me[CATEGORY] !== "angie") return;
marks.selectAll("path").style("stroke-opacity", opacity)
marks.selectAll(".shadow").style("stroke-width", 5)
marks.selectAll(".foreground").style("stroke-width", 2)
});

//draw scales and axis labels
svg.append("g")
.selectAll("g")
.data(keys)
.join("g")
.attr("transform", d => `translate(0,${y(d)})`)
.each(function(d) { d3.select(this).call(d3.axisBottom(x[d])); })
.call(g => g.append("text")
.attr("x", margin.left)
.attr("y", -6)
.attr("text-anchor", "start")
.attr("stroke-width", 6)
.attr("opacity", textOpacity)
.attr("stroke", "white")
.style("paint-order", "stroke")
.style("font-size", "5em")
.attr("stroke-linejoin", "round")
.attr("fill", "currentColor")
.text(d => d.replace("How would you rate your ", "").replace("skills?", ""))
)

//export SVG as html DOM node
return svg.node();
}
Insert cell
Insert cell
types = {
let types = {};
keys.forEach(key => types[key] = isNaN(+data[0][key]) ? "string" : "number")
return types;
}
Insert cell
Insert cell
x = {
let getXScale = (key) => types[key] === "number"
? d3.scaleLinear()
: d3.scalePoint().padding(0.1);
let getXdomain = (key) => types[key] === "number"
? [0, 10]
: [... new Set(data.map(m => m[key]))];
let scales = {};
keys.forEach(key => {
scales[key] = getXScale(key)
.domain(getXdomain(key))
.range([margin.left, width - margin.right])
})
return scales;
}
Insert cell
Insert cell
y = d3.scalePoint(keys, [margin.top, height - margin.bottom])

Insert cell
Insert cell
z = {
let domain = x[CATEGORY].domain();
let range = domain.map(m => m == currentSemester ? "red" : (m === "angie" ? "#338800" : "#ccc"))
return d3.scaleOrdinal(domain, range)
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more