Published
Edited
Dec 20, 2021
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
task_1_solution = {
const height = 300;
const width = 600;
const margin = 30;

const xScale = d3
.scaleBand()
.domain(dataBaseline.map((d) => d.month))
.range([margin, width - margin]);

const yScale = d3
.scaleLinear()
.domain([0, d3.max(dataBaseline, (d) => d.temp)])
.range([height - margin, margin]);

const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

svg
.append("path")
.datum(dataBaseline) // same as .data([mountainPeakData])
.attr(
"d",
d3
.line() // https://github.com/d3/d3-shape#lines
.x((d, i) => xScale(d.month)) // The x-positions of the different points used for constructing the line
.y((d) => yScale(d.temp)) // The x-positions of the different points used for constructing the line
)
.attr("fill", "none")
.attr("stroke", "blue");

const xAxis = d3.axisBottom().scale(xScale);
const yAxis = d3.axisLeft().scale(yScale);

svg
.append("g")
.attr("class", "x-axis")
.call(xAxis)
.attr("transform", `translate(0, ${height - margin})`);
svg
.append("g")
.attr("class", "y-axis")
.call(yAxis)
.attr("transform", `translate(${margin}, 0)`);
return svg.node();
}
Insert cell
Insert cell
task_2_solution = {
const height = 400;
const width = 600;
const margin = 30;
const cScale = (t) => d3.interpolateRdBu(t);
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const xScale = d3
.scaleBand()
.domain(dataBaseline.map((d) => d.month))
.range([margin, width - margin]);
const yearArr = [...new Set(data.map((d) => d.year))]; //arr with all years
const singleRectScale = d3.scaleBand().domain(yearArr).range([0, height]);
const yScale = d3
.scaleBand()
.domain(yearArr)
.range([margin, height - margin]);
const convNumToMonth = (d) => dataBaseline[d.month - 1].month;

const colourValueConv = (d) => {
if (d < 0) {
return 0.5 - d * (-0.5 / d3.min(data.map((d) => d.anomaly)));
} else if (d > 0)
return 0.5 - d * (0.5 / d3.max(data.map((d) => d.anomaly)));
else return 0.5;
};

svg
.selectAll(".year-rect")
.data(data)
.enter()
.append("rect") // Define what should be done only when the element enters for the first time
.attr("class", "year-rect")
.attr("x", (d) => xScale(convNumToMonth(d)))
.attr("width", xScale.bandwidth())
.attr("fill", (d) => cScale(colourValueConv(d.anomaly)))
.attr("y", (d) => yScale(d.year))
.attr("height", (d) => yScale.bandwidth())
.attr("year", (d) => d.year)
.on("mouseover", function () {
d3.select(this).transition().attr("stroke", "black");
console.log();

svg
.append("text")
.attr("fill", "black")
.attr("text-anchor", "middle")
.attr("x", margin / 2)
.attr("y", (e) => parseInt(this.getAttribute("y")))
.attr("dy", ".5em")
.attr("class", "yearLabel")
.attr("font-size", "12px")
.text(this.getAttribute("year"));
})
.on("mouseout", function () {
d3.select(this).transition().attr("stroke", "none");
d3.selectAll(".yearLabel").remove();
});
const xAxis = d3.axisBottom().scale(xScale);
svg
.append("g")
.attr("class", "x-axis")
.call(xAxis)
.attr("transform", `translate(0, ${height - margin})`);
return svg.node();
}
Insert cell
Insert cell
task_3_solution = {
const height = 500;
const width = 600;
const margin = 30;
const cScale = (t) => d3.interpolateRdBu(t);
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const xScale = d3
.scaleBand()
.domain(dataBaseline.map((d) => d.month))
.range([margin, width - margin]);
const yearArr = [...new Set(data.map((d) => d.year))]; //arr with all years
const singleRectScale = d3.scaleBand().domain(yearArr).range([0, height]);
const yScale = d3
.scaleBand()
.domain(yearArr)
.range([margin, height - margin]);
const convNumToMonth = (d) => dataBaseline[d.month - 1].month;

const absolValues = data.map(
(d) => d.anomaly + dataBaseline[d.month - 1].temp
);
const newColourValueConv = (d) =>
1 - (d - d3.min(absolValues)) / (d3.max(absolValues) - d3.min(absolValues));

svg
.selectAll(".year-rect")
.data(data)
.enter()
.append("rect") // Define what should be done only when the element enters for the first time
.attr("class", "year-rect")
.attr("x", (d) => xScale(convNumToMonth(d)))
.attr("width", xScale.bandwidth())
.attr("fill", (d, i) => cScale(newColourValueConv(absolValues[i])))
.attr("y", (d) => yScale(d.year))
.attr("height", (d) => yScale.bandwidth())
.attr("year", (d) => d.year)
.on("mouseover", function (d) {
d3.select(this).transition().attr("stroke", "black");

svg
.append("text")
.attr("fill", "black")
.attr("text-anchor", "middle")
.attr("x", margin / 2)
.attr("y", (e) => parseInt(this.getAttribute("y")))
.attr("dy", ".5em")
.attr("class", "yearLabel")
.attr("font-size", "12px")
.text(this.getAttribute("year"));
})
.on("mouseout", function () {
d3.select(this).transition().attr("stroke", "none");
d3.selectAll(".yearLabel").remove();
});

const xAxis = d3.axisBottom().scale(xScale);
svg
.append("g")
.attr("class", "x-axis")
.call(xAxis)
.attr("transform", `translate(0, ${height - margin})`);
return svg.node();
}
Insert cell
Insert cell
task_4_solution = {
const width = 600;
const height = 500;
const margin = 30;
const cScale = (t) => d3.interpolateRdBu(t);
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

const xScale = d3
.scaleBand()
.domain(dataBaseline.map((d) => d.month))
.range([margin, width - margin]);

const yearArr = [...new Set(data.map((d) => d.year))]; //arr with all years
const singleRectScale = d3.scaleBand().domain(yearArr).range([0, height]);

const yScale = d3
.scaleBand()
.domain(yearArr)
.range([margin, height - margin]);
const convNumToMonth = (d) => dataBaseline[d.month - 1].month;

const absolValues = data.map(
(d) => d.anomaly + dataBaseline[d.month - 1].temp
);

const colourValueConv = (d) =>
1 - (d - d3.min(absolValues)) / (d3.max(absolValues) - d3.min(absolValues));
let chosen = 0; //abs val. of the clicked rect

// function newColourValue(chosen, currAbsVal) {
// debugger;
// if (currAbsVal < chosen)
// return (
// 1 -
// ((currAbsVal - d3.min(absolValues)) * 0.5) /
// (chosen - d3.min(absolValues))
// );
// else if (currAbsVal > chosen)
// return (
// 0.5 - ((currAbsVal - chosen) / (d3.max(absolValues) - chosen)) * 0.5
// );
// else return 0.5;
// }
const average = (d3.max(absolValues) + d3.min(absolValues)) / 2;
function newColourValue(chosen, currAbsVal) {
let mean = Math.abs(average - chosen);
let minRange = d3.min(absolValues);
let maxRange = d3.max(absolValues);
if (chosen > average) maxRange += mean * 2;
else if (chosen < average) minRange -= mean * 2;
return 1 - (currAbsVal - minRange) / (maxRange - minRange);
}

function update() {
svg
.selectAll("rect")
.data(data)
.join(
(enter) =>
enter
.append("rect")
.attr("class", "year-rect")
.attr("x", (d) => xScale(convNumToMonth(d)))
.attr("width", xScale.bandwidth())
.attr("y", (d) => yScale(d.year))
.attr("height", (d) => yScale.bandwidth())
.attr("year", (d) => d.year)
.on("mouseover", function (d) {
d3.select(this).attr("stroke", "black");

svg
.append("text")
.attr("fill", "black")
.attr("text-anchor", "middle")
.attr("x", margin / 2)
.attr("y", (e) => parseInt(this.getAttribute("y")))
.attr("dy", ".5em")
.attr("class", "yearLabel")
.attr("font-size", "12px")
.text(this.getAttribute("year"));
})
.on("mouseout", function () {
d3.select(this).transition().attr("stroke", "none");
d3.selectAll(".yearLabel").remove();
})
.on("click", function (eventObject, datum) {
chosen = absolValues[data.findIndex((d) => d == datum)];
update(); // Call update() again to modify the appearance of the appended rects
}),
(update) => update
)
.transition()
.attr("fill", (d, i) => {
if (chosen == 0) return cScale(colourValueConv(absolValues[i]));
else return cScale(newColourValue(chosen, absolValues[i]));
});
}

update(); // The first call of update() appends the rects

const xAxis = d3.axisBottom().scale(xScale);
svg
.append("g")
.attr("class", "x-axis")
.call(xAxis)
.attr("transform", `translate(0, ${height - margin})`);
return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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