406 lines
15 KiB
JavaScript
406 lines
15 KiB
JavaScript
function init() {
|
|
var margin = 150; //equal margins on all sides
|
|
var width = window.screen.width - 2 * margin;
|
|
var height = 700 - 2 * margin;
|
|
|
|
var x = d3.scaleTime().range([0, width]);
|
|
var y = d3.scaleLinear().range([height, 0]);
|
|
var yLog = d3.scaleLog().clamp(true).range([height, 0]);
|
|
var ySqrt = d3.scaleSqrt().range([height, 0]);
|
|
|
|
var timeParser = d3.timeFormat("%b %Y");
|
|
var dateParse = d3.timeParse("%Y-%m-%d");
|
|
var legends = ['Catan', 'Dominion',
|
|
'Codenames', 'Terraforming Mars',
|
|
'Gloomhaven', 'Magic: The Gathering',
|
|
'Dixit', 'Monopoly'];
|
|
|
|
function lineGraphs(i) {
|
|
return d3.line().x(function (d) {
|
|
return x(dateParse(d.date));
|
|
}).y(function (d) {
|
|
return y(+d[legends[i]])
|
|
});
|
|
}
|
|
|
|
function lineGraphsLog(i) {
|
|
return d3.line().x(function (d) {
|
|
return x(dateParse(d.date));
|
|
}).y(function (d) {
|
|
return yLog(+d[legends[i]])
|
|
});
|
|
}
|
|
|
|
function lineGraphsSqrt(i) {
|
|
return d3.line().x(function (d) {
|
|
return x(dateParse(d.date));
|
|
}).y(function (d) {
|
|
return ySqrt(+d[legends[i]])
|
|
});
|
|
}
|
|
|
|
var svgFig1 = d3.select("body")
|
|
.append("svg")
|
|
.attr("class", "fig1")
|
|
.attr("width", width + 2 * margin)
|
|
.attr("height", height + 2 * margin)
|
|
.append("g")
|
|
.attr("transform", "translate(" + margin + "," + margin + ")");
|
|
d3.select("body").append("div").attr("class", "pagebreak");
|
|
|
|
var svgFig2 = d3.select("body")
|
|
.append("svg")
|
|
.attr("class", "fig1")
|
|
.attr("width", width + 2 * margin)
|
|
.attr("height", height + 2 * margin)
|
|
.append("g")
|
|
.attr("transform", "translate(" + margin + "," + margin + ")");
|
|
d3.select("body").append("div").attr("class", "pagebreak");
|
|
|
|
|
|
var svgFig4 = d3.select("body")
|
|
.append("svg")
|
|
.attr("class", "fig1")
|
|
.attr("width", width + 2 * margin)
|
|
.attr("height", height + 2 * margin)
|
|
.append("g")
|
|
.attr("transform", "translate(" + margin + "," + margin + ")");
|
|
d3.select("body").append("div").attr("class", "pagebreak");
|
|
|
|
|
|
var svgFig3 = d3.select("body")
|
|
.append("svg")
|
|
.attr("class", "fig1")
|
|
.attr("width", width + 2 * margin)
|
|
.attr("height", height + 2 * margin)
|
|
.append("g")
|
|
.attr("transform", "translate(" + margin + "," + margin + ")");
|
|
d3.select("body").append("div").attr("class", "pagebreak");
|
|
svgFig3.append("text")
|
|
.attr("x", width - 250)
|
|
.attr("y", height + 100)
|
|
.attr("text-anchor", "middle")
|
|
.style("font-size", "16px")
|
|
.text("psrinivasan48");
|
|
|
|
d3.dsv(",", "boardgame_ratings.csv", function (d) {
|
|
var obj = {
|
|
month: timeParser(new Date(d.date)),
|
|
date: d.date
|
|
};
|
|
for (var i in legends) {
|
|
obj[legends[i]] = +d[legends[i] + "=count"];
|
|
obj[legends[i] + '=rank'] = +d[legends[i] + "=rank"];
|
|
}
|
|
return obj;
|
|
}).then(function (data) {
|
|
var minMax = findMinMax(data);
|
|
var min = minMax[0], max = minMax[1];
|
|
x.domain(d3.extent(data, function (d) {
|
|
return dateParse(d.date);
|
|
}));
|
|
y.domain([min, max]);
|
|
yLog.domain([min, max]);
|
|
ySqrt.domain([min, max]);
|
|
|
|
for (var i in legends) {
|
|
var lg = lineGraphs(i);
|
|
var lgLog = lineGraphsLog(i);
|
|
var lgSqrt = lineGraphsSqrt(i);
|
|
svgFig1.append("path")
|
|
.data([data])
|
|
.attr("class", "line")
|
|
.attr("d", lg)
|
|
.style("stroke", d3.schemeCategory10[i])
|
|
.append("text")
|
|
.text(legends[i]);
|
|
svgFig1.append("text")
|
|
.attr("transform", "translate(" + (width + 10) + "," +
|
|
y(data[data.length - 1][legends[i]]) + ")")
|
|
.attr("text-anchor", "start")
|
|
.style("fill", d3.schemeCategory10[i])
|
|
.text(legends[i]);
|
|
svgFig2.append("path")
|
|
.data([data])
|
|
.attr("class", "line")
|
|
.attr("d", lg)
|
|
.style("stroke", d3.schemeCategory10[i])
|
|
.append("text")
|
|
.text(legends[i]);
|
|
svgFig2.append("text")
|
|
.attr("transform", "translate(" + (width + 10) + "," +
|
|
y(data[data.length - 1][legends[i]]) + ")")
|
|
.attr("text-anchor", "start")
|
|
.style("fill", d3.schemeCategory10[i])
|
|
.text(legends[i]);
|
|
svgFig3.append("path")
|
|
.data([data])
|
|
.attr("class", "line")
|
|
.attr("d", lgLog)
|
|
.style("stroke", d3.schemeCategory10[i])
|
|
.append("text")
|
|
.text(legends[i]);
|
|
svgFig3.append("text")
|
|
.attr("transform", "translate(" + (width + 10) + "," +
|
|
yLog(data[data.length - 1][legends[i]]) + ")")
|
|
.attr("text-anchor", "start")
|
|
.style("fill", d3.schemeCategory10[i])
|
|
.text(legends[i]);
|
|
svgFig4.append("path")
|
|
.data([data])
|
|
.attr("class", "line")
|
|
.attr("d", lgSqrt)
|
|
.style("stroke", d3.schemeCategory10[i])
|
|
.append("text")
|
|
.text(legends[i]);
|
|
svgFig4.append("text")
|
|
.attr("transform", "translate(" + (width + 10) + "," +
|
|
ySqrt(data[data.length - 1][legends[i]]) + ")")
|
|
.attr("text-anchor", "start")
|
|
.style("fill", d3.schemeCategory10[i])
|
|
.text(legends[i]);
|
|
if (["Catan", "Codenames", "Terraforming Mars", "Gloomhaven"].includes(legends[i])) {
|
|
svgFig2.selectAll("circles")
|
|
.data(data)
|
|
.enter()
|
|
.append("circle")
|
|
.filter(function(d, iter){
|
|
return iter%3===2;
|
|
})
|
|
.attr("fill", d3.schemeCategory10[i])
|
|
.attr("cx", function (d) {
|
|
return x(dateParse(d.date))
|
|
})
|
|
.attr("cy", function (d) {
|
|
return y(d[legends[i]])
|
|
})
|
|
.attr("r", 10);
|
|
svgFig2.selectAll("circles")
|
|
.data(data)
|
|
.enter()
|
|
.filter(function(d, iter){
|
|
return iter%3===2;
|
|
})
|
|
.append("text")
|
|
.attr("class", "count-font")
|
|
.text(function (d) {
|
|
return d[legends[i] + "=rank"];
|
|
}).attr("x", function (d) {
|
|
return x(dateParse(d.date)) - 5;
|
|
}).attr("y", function (d) {
|
|
return y(d[legends[i]]) + 5
|
|
});
|
|
svgFig3.selectAll("circles")
|
|
.data(data)
|
|
.enter()
|
|
.filter(function(d, iter){
|
|
return iter%3===2;
|
|
})
|
|
.append("circle")
|
|
.attr("fill", d3.schemeCategory10[i])
|
|
.attr("cx", function (d) {
|
|
return x(dateParse(d.date))
|
|
})
|
|
.attr("cy", function (d) {
|
|
return yLog(d[legends[i]])
|
|
})
|
|
.attr("r", 10);
|
|
svgFig3.selectAll("circles")
|
|
.data(data)
|
|
.enter()
|
|
.filter(function(d, iter){
|
|
return iter%3===2;
|
|
})
|
|
.append("text")
|
|
.attr("class", "count-font")
|
|
.text(function (d) {
|
|
return d[legends[i] + "=rank"];
|
|
}).attr("x", function (d) {
|
|
return x(dateParse(d.date)) - 5;
|
|
}).attr("y", function (d) {
|
|
return yLog(d[legends[i]]) + 5
|
|
});
|
|
svgFig4.selectAll("circles")
|
|
.data(data)
|
|
.enter()
|
|
.filter(function(d, iter){
|
|
return iter%3===2;
|
|
})
|
|
.append("circle")
|
|
.attr("fill", d3.schemeCategory10[i])
|
|
.attr("cx", function (d) {
|
|
return x(dateParse(d.date))
|
|
})
|
|
.attr("cy", function (d) {
|
|
return ySqrt(d[legends[i]])
|
|
})
|
|
.attr("r", 10);
|
|
svgFig4.selectAll("circles")
|
|
.data(data)
|
|
.enter()
|
|
.filter(function(d, iter){
|
|
return iter%3===2;
|
|
})
|
|
.append("text")
|
|
.attr("class", "count-font")
|
|
.text(function (d) {
|
|
return d[legends[i] + "=rank"];
|
|
}).attr("x", function (d) {
|
|
return x(dateParse(d.date)) - 5;
|
|
}).attr("y", function (d) {
|
|
return ySqrt(d[legends[i]]) + 5
|
|
});
|
|
}
|
|
|
|
}
|
|
svgFig2.append("circle")
|
|
.attr("fill", "black")
|
|
.attr("transform", "translate(" + (width + 20) + "," +
|
|
(height - 30) + ")")
|
|
.attr("r", 10);
|
|
svgFig2.append("text")
|
|
.attr("class", "count-font")
|
|
.attr("transform", "translate(" + (width + 10) + "," +
|
|
(height - 27) + ")").text("RANK");
|
|
svgFig2.append("text")
|
|
.attr("transform", "translate(" + (width - 30) + "," +
|
|
(height - 10) + ")").text("BoardGameGeek Rank");
|
|
svgFig3.append("circle")
|
|
.attr("fill", "black")
|
|
.attr("transform", "translate(" + (width + 20) + "," +
|
|
(height - 30) + ")")
|
|
.attr("r", 10);
|
|
svgFig3.append("text")
|
|
.attr("class", "count-font")
|
|
.attr("transform", "translate(" + (width + 10) + "," +
|
|
(height - 27) + ")").text("RANK");
|
|
svgFig3.append("text")
|
|
.attr("transform", "translate(" + (width - 30) + "," +
|
|
(height - 10) + ")").text("BoardGameGeek Rank");
|
|
svgFig4.append("circle")
|
|
.attr("fill", "black")
|
|
.attr("transform", "translate(" + (width + 20) + "," +
|
|
(height - 30) + ")")
|
|
.attr("r", 10);
|
|
svgFig4.append("text")
|
|
.attr("class", "count-font")
|
|
.attr("transform", "translate(" + (width + 10) + "," +
|
|
(height - 27) + ")").text("RANK");
|
|
svgFig4.append("text")
|
|
.attr("transform", "translate(" + (width - 30) + "," +
|
|
(height - 10) + ")").text("BoardGameGeek Rank");
|
|
|
|
svgFig1.append("g")
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b %Y")));
|
|
|
|
svgFig1.append("g")
|
|
.call(d3.axisLeft(y));
|
|
svgFig2.append("g")
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b %Y")));
|
|
|
|
svgFig2.append("g")
|
|
.call(d3.axisLeft(y));
|
|
|
|
svgFig3.append("g")
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b %Y")));
|
|
|
|
svgFig3.append("g")
|
|
.call(d3.axisLeft(yLog));
|
|
|
|
svgFig4.append("g")
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b %Y")));
|
|
|
|
svgFig4.append("g")
|
|
.call(d3.axisLeft(ySqrt));
|
|
|
|
function findMinMax(data) {
|
|
var min = Number.POSITIVE_INFINITY;
|
|
var max = Number.NEGATIVE_INFINITY;
|
|
for (var j in data) {
|
|
var datum = data[j];
|
|
for (var i in legends) {
|
|
if (datum[legends[i]] < min) min = datum[legends[i]];
|
|
if (datum[legends[i]] > max) max = datum[legends[i]];
|
|
}
|
|
}
|
|
return [min, max];
|
|
}
|
|
|
|
svgFig1.append("text")
|
|
.attr("transform", "translate(" + width / 2 + " ," + (height + 30) + ")")
|
|
.style("text-anchor", "middle")
|
|
.text("Month");
|
|
|
|
svgFig1.append("text")
|
|
.attr("y", -50)
|
|
.attr("x", -height / 2)
|
|
.attr("transform", "rotate(-90)")
|
|
.style("text-anchor", "middle")
|
|
.text("Number of Ratings");
|
|
|
|
svgFig1.append("text")
|
|
.attr("x", (width / 2))
|
|
.attr("text-anchor", "middle")
|
|
.style("font-size", "16px")
|
|
.text("Number of Ratings 2016-2020");
|
|
|
|
|
|
svgFig2.append("text")
|
|
.attr("transform", "translate(" + width / 2 + " ," + (height + 30) + ")")
|
|
.style("text-anchor", "middle")
|
|
.text("Month");
|
|
|
|
svgFig2.append("text")
|
|
.attr("y", -50)
|
|
.attr("x", -height / 2)
|
|
.attr("transform", "rotate(-90)")
|
|
.style("text-anchor", "middle")
|
|
.text("Number of Ratings");
|
|
svgFig2.append("text")
|
|
.attr("x", (width / 2))
|
|
.attr("text-anchor", "middle")
|
|
.style("font-size", "16px")
|
|
.text("Number of Ratings 2016-2020 with Rankings");
|
|
svgFig3.append("text")
|
|
.attr("transform", "translate(" + width / 2 + " ," + (height + 30) + ")")
|
|
.style("text-anchor", "middle")
|
|
.text("Month");
|
|
|
|
svgFig3.append("text")
|
|
.attr("y", -50)
|
|
.attr("x", -height / 2)
|
|
.attr("transform", "rotate(-90)")
|
|
.style("text-anchor", "middle")
|
|
.text("Number of Ratings");
|
|
svgFig3.append("text")
|
|
.attr("x", (width / 2))
|
|
.attr("y", -5)
|
|
.attr("text-anchor", "middle")
|
|
.style("font-size", "16px")
|
|
.text("Number of Ratings 2016-2020 with Rankings (Log Scale)");
|
|
|
|
svgFig4.append("text")
|
|
.attr("transform", "translate(" + width / 2 + " ," + (height + 30) + ")")
|
|
.style("text-anchor", "middle")
|
|
.text("Month");
|
|
|
|
svgFig4.append("text")
|
|
.attr("y", -50)
|
|
.attr("x", -height / 2)
|
|
.attr("transform", "rotate(-90)")
|
|
.style("text-anchor", "middle")
|
|
.text("Number of Ratings");
|
|
svgFig4.append("text")
|
|
.attr("x", (width / 2))
|
|
.attr("text-anchor", "middle")
|
|
.style("font-size", "16px")
|
|
.text("Number of Ratings 2016-2020 with Rankings (Square Root Scale)");
|
|
|
|
}).catch(function (error) {
|
|
console.log(error);
|
|
});
|
|
} |