571 lines
16 KiB
JavaScript
571 lines
16 KiB
JavaScript
function init() {
|
|
var margin = 150; //equal margins on all sides
|
|
var width = 1000 - 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 svg_a = d3.select("body").append("svg").attr("id", "svg-a");
|
|
var svgFig1 = svg_a
|
|
.attr("class", "fig1")
|
|
.attr("width", width + 2 * margin)
|
|
.attr("height", height + 2 * margin)
|
|
.append("g")
|
|
.attr("id", "plot-a")
|
|
.attr("transform", "translate(" + margin + "," + margin + ")");
|
|
|
|
var g_plot_a = svgFig1;
|
|
var g_x_axis_a = g_plot_a.append("g").attr("id", "x-axis-a");
|
|
var g_y_axis_a = g_plot_a.append("g").attr("id", "y-axis-a");
|
|
var g_lines_a = g_plot_a.append("g").attr("id", "lines-a");
|
|
var text_title_a = svg_a.append("text").attr("id", "title-a");
|
|
|
|
d3.select("body").append("div").attr("class", "pagebreak");
|
|
|
|
var svg_b = d3.select("body").append("svg").attr("id", "svg-b");
|
|
var svgFig2 = svg_b
|
|
.attr("class", "fig1")
|
|
.attr("width", width + 2 * margin)
|
|
.attr("height", height + 2 * margin)
|
|
.append("g")
|
|
.attr("id", "plot-b")
|
|
.attr("transform", "translate(" + margin + "," + margin + ")");
|
|
var g_plot_b = svgFig2;
|
|
var g_x_axis_b = g_plot_b.append("g").attr("id", "x-axis-b");
|
|
var g_y_axis_b = g_plot_b.append("g").attr("id", "y-axis-b");
|
|
var g_lines_b = g_plot_b.append("g").attr("id", "lines-b");
|
|
var g_symbols_b = g_plot_b.append("g").attr("id", "symbols-b");
|
|
var text_title_b = svg_b.append("text").attr("id", "title-b");
|
|
var g_legend_b = svg_b
|
|
.append("g")
|
|
.attr("id", "legend-b")
|
|
.attr("transform", "translate(200,170)");
|
|
|
|
d3.select("body").append("div").attr("class", "pagebreak");
|
|
|
|
//
|
|
var svg_c_1 = d3.select("body").append("svg").attr("id", "svg-c-1");
|
|
var svgFig4 = svg_c_1
|
|
.attr("class", "fig1")
|
|
.attr("width", width + 2 * margin)
|
|
.attr("height", height + 2 * margin)
|
|
.append("g")
|
|
.attr("id", "plot-c-1")
|
|
.attr("transform", "translate(" + margin + "," + margin + ")");
|
|
var g_plot_c_1 = svgFig4;
|
|
var g_x_axis_c_1 = g_plot_c_1.append("g").attr("id", "x-axis-c-1");
|
|
var g_y_axis_c_1 = g_plot_c_1.append("g").attr("id", "y-axis-c-1");
|
|
var g_lines_c_1 = g_plot_c_1.append("g").attr("id", "lines-c-1");
|
|
var g_symbols_c_1 = g_plot_c_1.append("g").attr("id", "symbols-c-1");
|
|
var text_title_c_1 = svg_c_1.append("text").attr("id", "title-c-1");
|
|
var g_legend_c_1 = svg_c_1
|
|
.append("g")
|
|
.attr("id", "legend-c-1")
|
|
.attr("transform", "translate(200,170)");
|
|
//
|
|
|
|
d3.select("body").append("div").attr("class", "pagebreak");
|
|
|
|
var svg_c_2 = d3.select("body").append("svg").attr("id", "svg-c-2");
|
|
var svgFig3 = svg_c_2
|
|
.attr("class", "fig1")
|
|
.attr("width", width + 2 * margin)
|
|
.attr("height", height + 2 * margin)
|
|
.append("g")
|
|
.attr("id", "plot-c-2")
|
|
.attr("transform", "translate(" + margin + "," + margin + ")");
|
|
var g_plot_c_2 = svgFig3;
|
|
var g_x_axis_c_2 = g_plot_c_2.append("g").attr("id", "x-axis-c-2");
|
|
var g_y_axis_c_2 = g_plot_c_2.append("g").attr("id", "y-axis-c-2");
|
|
var g_lines_c_2 = g_plot_c_2.append("g").attr("id", "lines-c-2");
|
|
var g_symbols_c_2 = g_plot_c_2.append("g").attr("id", "symbols-c-2");
|
|
var text_title_c_2 = svg_c_2.append("text").attr("id", "title-c-2");
|
|
var g_legend_c_2 = svg_c_2
|
|
.append("g")
|
|
.attr("id", "legend-c-2")
|
|
.attr("transform", "translate(200,170)");
|
|
|
|
d3.select("body").append("div").attr("class", "pagebreak");
|
|
|
|
d3.select("body").append("div").attr("id", "signature").text("tlou31");
|
|
|
|
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([0, max]);
|
|
ySqrt.domain([0, max]);
|
|
yLog.domain([min, max]);
|
|
|
|
for (var i in legends) {
|
|
var lg = lineGraphs(i);
|
|
var lgLog = lineGraphsLog(i);
|
|
var lgSqrt = lineGraphsSqrt(i);
|
|
|
|
g_lines_a
|
|
.append("path")
|
|
.data([data])
|
|
.attr("class", "line")
|
|
.attr("d", lg)
|
|
.style("stroke", d3.schemeCategory10[i])
|
|
// .append("text")
|
|
// .text(legends[i]);
|
|
|
|
g_lines_a
|
|
.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]);
|
|
|
|
g_lines_b
|
|
.append("path")
|
|
.data([data])
|
|
.attr("class", "line")
|
|
.attr("d", lg)
|
|
.style("stroke", d3.schemeCategory10[i])
|
|
// .append("text")
|
|
// .text(legends[i]);
|
|
g_lines_b
|
|
.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]);
|
|
|
|
g_lines_c_1
|
|
.append("path")
|
|
.data([data])
|
|
.attr("class", "line")
|
|
.attr("d", lgSqrt)
|
|
.style("stroke", d3.schemeCategory10[i])
|
|
// .append("text")
|
|
// .text(legends[i]);
|
|
g_lines_c_1
|
|
.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]);
|
|
|
|
g_lines_c_2
|
|
.append("path")
|
|
.data([data])
|
|
.attr("class", "line")
|
|
.attr("d", lgLog)
|
|
.style("stroke", d3.schemeCategory10[i])
|
|
// .append("text")
|
|
// .text(legends[i]);
|
|
g_lines_c_2
|
|
.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]);
|
|
|
|
if (
|
|
["Catan", "Codenames", "Terraforming Mars", "Gloomhaven"].includes(
|
|
legends[i]
|
|
)
|
|
) {
|
|
g_symbols_b
|
|
.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);
|
|
g_symbols_b
|
|
.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;
|
|
});
|
|
|
|
g_symbols_c_1
|
|
.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);
|
|
g_symbols_c_1
|
|
.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;
|
|
});
|
|
|
|
g_symbols_c_2
|
|
.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);
|
|
g_symbols_c_2
|
|
.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;
|
|
});
|
|
}
|
|
}
|
|
g_legend_b
|
|
.append("circle")
|
|
.attr("fill", "black")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + (width + 20) + "," + (height - 30) + ")"
|
|
)
|
|
.attr("r", 10);
|
|
g_legend_b
|
|
.append("text")
|
|
.attr("class", "count-font")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + (width + 10) + "," + (height - 27) + ")"
|
|
)
|
|
.text("RANK");
|
|
g_legend_b
|
|
.append("text")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + (width - 30) + "," + (height - 10) + ")"
|
|
)
|
|
.text("BoardGameGeek Rank");
|
|
|
|
g_legend_c_1
|
|
.append("circle")
|
|
.attr("fill", "black")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + (width + 20) + "," + (height - 30) + ")"
|
|
)
|
|
.attr("r", 10);
|
|
g_legend_c_1
|
|
.append("text")
|
|
.attr("class", "count-font")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + (width + 10) + "," + (height - 27) + ")"
|
|
)
|
|
.text("RANK");
|
|
g_legend_c_1
|
|
.append("text")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + (width - 30) + "," + (height - 10) + ")"
|
|
)
|
|
.text("BoardGameGeek Rank");
|
|
|
|
g_legend_c_2
|
|
.append("circle")
|
|
.attr("fill", "black")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + (width + 20) + "," + (height - 30) + ")"
|
|
)
|
|
.attr("r", 10);
|
|
g_legend_c_2
|
|
.append("text")
|
|
.attr("class", "count-font")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + (width + 10) + "," + (height - 27) + ")"
|
|
)
|
|
.text("RANK");
|
|
g_legend_c_2
|
|
.append("text")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + (width - 30) + "," + (height - 10) + ")"
|
|
)
|
|
.text("BoardGameGeek Rank");
|
|
|
|
g_x_axis_a
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b %y")));
|
|
g_y_axis_a.call(d3.axisLeft(y));
|
|
|
|
g_x_axis_b
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b %y")));
|
|
g_y_axis_b.call(d3.axisLeft(y));
|
|
|
|
g_x_axis_c_1
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b %y")));
|
|
g_y_axis_c_1.call(d3.axisLeft(ySqrt));
|
|
|
|
g_x_axis_c_2
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b %y")));
|
|
|
|
g_y_axis_c_2.call(d3.axisLeft(yLog));
|
|
|
|
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];
|
|
}
|
|
|
|
g_x_axis_a
|
|
.append("text")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + width / 2 + " ," + (height + 30) + ")"
|
|
)
|
|
.style("text-anchor", "middle")
|
|
.text("Month");
|
|
|
|
g_y_axis_a
|
|
.append("text")
|
|
.attr("y", -50)
|
|
.attr("x", -height / 2)
|
|
.attr("transform", "rotate(-90)")
|
|
.style("text-anchor", "middle")
|
|
.text("Num of Ratings");
|
|
text_title_a
|
|
.attr("x", width / 2)
|
|
.attr("y", 50)
|
|
.attr("text-anchor", "middle")
|
|
.style("font-size", "16px")
|
|
.text("Number of Ratings 2016-2020");
|
|
|
|
g_x_axis_b
|
|
.append("text")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + width / 2 + " ," + (height + 30) + ")"
|
|
)
|
|
.style("text-anchor", "middle")
|
|
.text("Month");
|
|
g_y_axis_b
|
|
.append("text")
|
|
.attr("y", -50)
|
|
.attr("x", -height / 2)
|
|
.attr("transform", "rotate(-90)")
|
|
.style("text-anchor", "middle")
|
|
.text("Num of Ratings");
|
|
text_title_b
|
|
.attr("x", width / 2)
|
|
.attr("y", 50)
|
|
.attr("text-anchor", "middle")
|
|
.style("font-size", "16px")
|
|
.text("Number of Ratings 2016-2020 with Rankings");
|
|
|
|
g_x_axis_c_1
|
|
.append("text")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + width / 2 + " ," + (height + 30) + ")"
|
|
)
|
|
.style("text-anchor", "middle")
|
|
.text("Month");
|
|
g_y_axis_c_1
|
|
.append("text")
|
|
.attr("y", -50)
|
|
.attr("x", -height / 2)
|
|
.attr("transform", "rotate(-90)")
|
|
.style("text-anchor", "middle")
|
|
.text("Num of Ratings");
|
|
text_title_c_1
|
|
.attr("x", width / 2)
|
|
.attr("y", 50)
|
|
.attr("text-anchor", "middle")
|
|
.style("font-size", "16px")
|
|
.text(
|
|
"Number of Ratings 2016-2020 with Rankings (Square Root Scale) svg_c_1, svgFig4"
|
|
);
|
|
|
|
g_x_axis_c_2
|
|
.append("text")
|
|
.attr(
|
|
"transform",
|
|
"translate(" + width / 2 + " ," + (height + 30) + ")"
|
|
)
|
|
.style("text-anchor", "middle")
|
|
.text("Month");
|
|
g_y_axis_c_2
|
|
.append("text")
|
|
.attr("y", -50)
|
|
.attr("x", -height / 2)
|
|
.attr("transform", "rotate(-90)")
|
|
.style("text-anchor", "middle")
|
|
.text("Num of Ratings");
|
|
text_title_c_2
|
|
.attr("x", width / 2)
|
|
.attr("y", 50)
|
|
.attr("text-anchor", "middle")
|
|
.style("font-size", "16px")
|
|
.text("Number of Ratings 2016-2020 with Rankings (Log Scale) svgFig3");
|
|
})
|
|
.catch(function (error) {
|
|
console.log(error);
|
|
});
|
|
}
|