Files
tunmnlu/task_2/others-answer/omsa-main/CS-6242-OAN/hw2/Q3/linecharts.js
louiscklaw 9035c1312b update,
2025-02-01 02:09:32 +08:00

611 lines
17 KiB
JavaScript

//------------------------1. PREPARATION------------------------//
//-----------------------------SVG------------------------------//
const margin = 250
const global_height = 500
const global_width = 960
const width = global_width - margin
const height = global_height - margin
// we are appending SVG first
const svg_a = d3.select("body")
.append("svg")
.attr("id","svg-a")
.attr("width",global_width)
.attr("height", global_height)
const g_a = svg_a.append("g")
.attr("id","plot-a");
//Create second plot svg_b
const svg_b = d3.select("body")
.append("svg")
.attr("id","svg-b")
.attr("width",global_width)
.attr("height", global_height)
const g_b = svg_b.append("g")
.attr("id","plot-b");
//Create third plot svg-c-1
const svg_c_1 = d3.select("body")
.append("svg")
.attr("id","svg-c-1")
.attr("width",global_width)
.attr("height", global_height)
const g_c_1 = svg_c_1.append("g")
.attr("id","plot-c-1");
//Create fourth plot svg-c-2
const svg_c_2 = d3.select("body")
.append("svg")
.attr("id","svg-c-2")
.attr("width",global_width)
.attr("height", global_height)
const g_c_2 = svg_c_2.append("g")
.attr("id","plot-c-2");
//-----------------------------DATA-----------------------------//
const timeConv = d3.timeParse("%Y-%m-%d");
const dataset = d3.dsv(",","boardgame_ratings.csv");
dataset.then(function(data) {
var slices = data.columns.slice(1).map(function(id) {
return {
id: id,
values: data.map(function(d){
return {
date: timeConv(d.date),
measurement: +d[id]
};
})
};
});
var countSlices = slices.filter(function (d) { return d.id.match(/count/); });
var rankSlices = slices.filter(function (d) { return d.id.match(/rank/); })
var rankPoints = slices.filter(function (d) { return d.id.match(/Catan=count|Codenames=count|Terraforming Mars=count|Gloomhaven=count/); })
//----------------------------SCALES----------------------------//
const xScale = d3.scaleTime().range([0,width]);
const yScale = d3.scaleLinear().rangeRound([height, 0]);
const yScaleSqrt = d3.scaleSqrt().rangeRound([height, 0]);
const yScaleLog = d3.scaleLog().rangeRound([height, 1]);
const colors = d3.scaleOrdinal(d3.schemeCategory10);
xScale.domain(d3.extent(data, function(d){
return timeConv(d.date)}));
yScale.domain([(0), d3.max(countSlices, function(c) {
return d3.max(c.values, function(d) {
return d.measurement + 4; });
})
]);
yScaleSqrt.domain([(0), d3.max(countSlices, function(c) {
return d3.max(c.values, function(d) {
return d.measurement; });
})
])
yScaleLog.domain([(0), d3.max(countSlices, function(c) {
return d3.max(c.values, function(d) {
return d.measurement; });
})
])
//-----------------------------AXES-----------------------------//
const yaxis = d3.axisLeft()
//.ticks((slices[0].values).length)
.scale(yScale);
const yaxisSqrt = d3.axisLeft()
//.ticks((slices[0].values).length)
.scale(yScaleSqrt);
const yaxisLog = d3.axisLeft()
//.ticks((slices[0].values).length)
.scale(yScaleLog);
const xaxis = d3.axisBottom()
.ticks(d3.timeMonth.every(3))
.tickFormat(d3.timeFormat('%b %y'))
.scale(xScale);
//----------------------------LINES-----------------------------//
const line = d3.line()
.x(function(d) { return xScale(d.date)+100; })
.y(function(d) { return yScale(d.measurement)+50; });
const lineSqrt = d3.line()
.x(function(d) { return xScale(d.date)+100; })
.y(function(d) { return yScaleSqrt(d.measurement)+100; });
const lineLog = d3.line()
.x(function(d) { return xScale(d.date)+100; })
.y(function(d) { return yScaleLog(d.measurement)+100; });
let id = 0;
const ids = function () {
return "line-"+id++;
}
const point_ids = function () {
return "point-"+id++;
}
//---------------------------TOOLTIP----------------------------//
//-------------------------2. DRAWING---------------------------//
//-----------------------------AXES-----------------------------//
g_a.append("text")
.attr("id","title-a")
.attr("transform", "translate(300,0)")
.attr("y", 25)
.attr("font-size", "20px")
.text("Number of Ratings 2016-2020");
g_a.append("g")
.attr("transform", "translate(100," + (height+50) + ")")
.attr("id", "x-axis-a")
.call(xaxis);
g_a.select("#x-axis-a")
.append("text")
.attr("id", "x-axis label")
.attr("y", height - 200)
.attr("x", width - 350)
.attr("text-anchor", "end")
.attr("stroke", "black")
.text("Month");
g_a.append("g")
.attr("id", "y-axis-a")
.attr("transform", "translate(100,50)")
.call(yaxis);
g_a.select("#y-axis-a")
.append("text")
.attr("id", "y-axis label")
.attr("transform", "rotate(-90)")
.attr("y", height - 250)
.attr("x", -100)
.attr("dy", "-5.1em")
.attr("text-anchor", "end")
.attr("stroke", "black")
.text("Num of Ratings");
//----------------------------LINES-----------------------------//
const countLinesA = svg_a.select("#plot-a").append("g").attr("id","lines-a")
.selectAll("lines")
.data(countSlices)
.enter();
countLinesA.append("path")
.attr("class", ids)
.attr("fill", "none")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d, i) {
return colors(d.id);
});
countLinesA.append("text")
.attr("class","serie_label")
.datum(function(d) {
return {
id: d.id,
value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) {
return "translate(" + (xScale(d.value.date) + 100)
+ "," + (yScale(d.value.measurement) + 55 )+ ")"; })
.attr("x", 5)
.text(function(d) { return d.id.split('=')[0]; })
.style("fill", function(d, i) {
return colors(d.id);});
//------------------------ PLOT-B------------------------//
//-------------------------1. DRAWING---------------------------//
//-----------------------------AXES-----------------------------//
// Draw the axis and labels for plot-b
g_b.append("text")
.attr("id","title-b")
.attr("transform", "translate(300,0)")
.attr("y", 25)
.attr("font-size", "20px")
.text("Number of Ratings 2016-2020 with Rankings");
g_b.append("g")
.attr("transform", "translate(100," + (height+50) + ")")
.attr("id", "x-axis-b")
.call(xaxis);
g_b.select("#x-axis-b")
.append("text")
.attr("id", "x-axis label")
.attr("y", height - 200)
.attr("x", width - 350)
.attr("text-anchor", "end")
.attr("stroke", "black")
.text("Month");
g_b.append("g")
.attr("id", "y-axis-b")
.attr("transform", "translate(100,50)")
.call(yaxis);
g_b.select("#y-axis-b")
.append("text")
.attr("id", "y-axis label")
.attr("transform", "rotate(-90)")
.attr("y", height - 250)
.attr("x", -100)
.attr("dy", "-5.1em")
.attr("text-anchor", "end")
.attr("stroke", "black")
.text("Num of Ratings");
//----------------------------LINES-----------------------------//
const countLinesB = svg_b.select("#plot-b").append("g").attr("id","lines-b")
.selectAll("lines")
.data(countSlices)
.enter();
countLinesB.append("path")
.attr("class", ids)
.attr("fill", "none")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d, i) {
return colors(d.id);
});
countLinesB.append("text")
.attr("class","serie_label")
.datum(function(d) {
return {
id: d.id,
value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) {
return "translate(" + (xScale(d.value.date) + 100)
+ "," + (yScale(d.value.measurement) + 55 )+ ")"; })
.attr("x", 5)
.text(function(d) { return d.id.split('=')[0]; })
.style("fill", function(d, i) {
return colors(d.id);});
rankSlices.forEach(function(d,i) {
rankSlices[i]['values']=
d.values.filter(function(d,i){
return (i+1)%3==0
});
});
rankPoints.forEach(function(d,i) {
rankPoints[i]['values']=
d.values.filter(function(d,i){
return (i+1)%3==0
});
});
for (let i = 0; i < rankPoints.length; i++) {
values_arr = rankPoints[i].values
for (let j = 0; j < values_arr.length; j++) {
values_arr[j]["rank"] = rankSlices[i].values[j].measurement
values_arr[j]["id"] = rankPoints[i].id
}
}
var mapValues = []
for (let i = 0; i < rankPoints.length; i++) {
values_arr = rankPoints[i].values
mapValues.push(values_arr)
}
svg_b.select("#plot-b")
.append("g")
.attr("id","symbols-b")
var pointsLinesB = svg_b.select("#symbols-b")
.selectAll("g")
.data(rankPoints)
.enter()
.append("g")
var circles = pointsLinesB.selectAll(".circles")
.data(function(d){
return d.values
})
.enter()
.append("circle")
circles.attr("cx", function(d) {
return xScale(d.date)+110; })
.attr("cy", function(d,i) {
return yScale(d.measurement)+45; })
.attr("r", 14)
.style("fill", function(d) {
return colors(d.id);
})
var circles_text = pointsLinesB.selectAll(".text")
.data(function(d){
return d.values
})
.enter()
.append("text")
circles_text.attr("x", function(d) {
return xScale(d.date)+100; })
.attr("y", function(d,i) {
return yScale(d.measurement)+50; })
.text(function(d) {
return d.rank;})
.style('fill', 'white');
legend = svg_b.append("g")
.attr("id","legend-b")
legend.append("circle").attr("cx",width+200).attr("cy",300).attr("r", 20).style("fill", "black")
legend.append("text").attr("x", width+190).attr("y", 300).text("rank").style("font-size", "12px").style("fill","white")
legend.append("text").attr("x", width+150).attr("y", 330).text("BoardGameGeek Rank").style("font-size", "13px").style("fill","black")
//------------------------ PLOT-C1------------------------//
//-------------------------1. DRAWING---------------------------//
//-----------------------------AXES-----------------------------//
// Draw the axis and labels for plot-b
g_c_1.append("text")
.attr("id","title-c-1")
.attr("transform", "translate(300,0)")
.attr("y", 25)
.attr("font-size", "20px")
.text("Number of Ratings 2016-2020 (Square Root Scale)");
g_c_1.append("g")
.attr("transform", "translate(100," + (height+50) + ")")
.attr("id", "x-axis-c-1")
.call(xaxis);
g_c_1.select("#x-axis-c-1")
.append("text")
.attr("id", "x-axis label")
.attr("y", height - 200)
.attr("x", width - 350)
.attr("text-anchor", "end")
.attr("stroke", "black")
.text("Month");
g_c_1.append("g")
.attr("id", "y-axis-c-1")
.attr("transform", "translate(100,50)")
.call(yaxisSqrt);
g_c_1.select("#y-axis-c-1")
.append("text")
.attr("id", "y-axis label")
.attr("transform", "rotate(-90)")
.attr("y", height - 250)
.attr("x", -100)
.attr("dy", "-5.1em")
.attr("text-anchor", "end")
.attr("stroke", "black")
.text("Num of Ratings");
//----------------------------LINES-----------------------------//
const countLinesC1 = svg_c_1.select("#plot-c-1").append("g").attr("id","lines-c-1")
.selectAll("lines")
.data(countSlices)
.enter();
countLinesC1.append("path")
.attr("class", ids)
.attr("fill", "none")
.attr("d", function(d) {
return lineSqrt(d.values);
})
.style("stroke", function(d, i) {
return colors(d.id);
});
countLinesC1.append("text")
.attr("class","serie_label")
.datum(function(d) {
return {
id: d.id,
value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) {
return "translate(" + (xScale(d.value.date) + 100)
+ "," + (yScale(d.value.measurement) + 55 )+ ")"; })
.attr("x", 5)
.text(function(d) { return d.id.split('=')[0]; })
.style("fill", function(d, i) {
return colors(d.id);});
svg_c_1.select("#plot-c-1")
.append("g")
.attr("id","symbols-c-1")
var pointsLinesC1 = svg_c_1.select("#symbols-c-1")
.selectAll("g")
.data(rankPoints)
.enter()
.append("g")
var circlesC1 = pointsLinesC1.selectAll(".circles")
.data(function(d){
return d.values
})
.enter()
.append("circle")
circlesC1.attr("cx", function(d) {
return xScale(d.date)+110; })
.attr("cy", function(d,i) {
return yScale(d.measurement)+45; })
.attr("r", 14)
.style("fill", function(d) {
return colors(d.id);
})
var circles_text_c1 = pointsLinesC1.selectAll(".text")
.data(function(d){
return d.values
})
.enter()
.append("text")
circles_text_c1.attr("x", function(d) {
return xScale(d.date)+100; })
.attr("y", function(d,i) {
return yScaleSqrt(d.measurement)+50; })
.text(function(d) {
return d.rank;})
.style('fill', 'white');
legendc1 = svg_c_1.append("g")
.attr("id","legend-c-1")
legendc1.append("circle").attr("cx",width+200).attr("cy",300).attr("r", 20).style("fill", "black")
legendc1.append("text").attr("x", width+190).attr("y", 300).text("rank").style("font-size", "12px").style("fill","white")
legendc1.append("text").attr("x", width+150).attr("y", 330).text("BoardGameGeek Rank").style("font-size", "13px").style("fill","black")
//------------------------ PLOT-C2------------------------//
//-------------------------1. DRAWING---------------------------//
//-----------------------------AXES-----------------------------//
// Draw the axis and labels for plot-b
g_c_2.append("text")
.attr("id","title-c-2")
.attr("transform", "translate(300,0)")
.attr("y", 25)
.attr("font-size", "20px")
.text("Number of Ratings 2016-2020 (Square Root Scale)");
g_c_2.append("g")
.attr("transform", "translate(100," + (height+50) + ")")
.attr("id", "x-axis-c-2")
.call(xaxis);
g_c_2.select("#x-axis-c-2")
.append("text")
.attr("id", "x-axis label")
.attr("y", height - 200)
.attr("x", width - 350)
.attr("text-anchor", "end")
.attr("stroke", "black")
.text("Month");
g_c_2.append("g")
.attr("id", "y-axis-c-2")
.attr("transform", "translate(100,50)")
.call(yaxisLog);
g_c_2.select("#y-axis-c-2")
.append("text")
.attr("id", "y-axis label")
.attr("transform", "rotate(-90)")
.attr("y", height - 250)
.attr("x", -100)
.attr("dy", "-5.1em")
.attr("text-anchor", "end")
.attr("stroke", "black")
.text("Num of Ratings");
//----------------------------LINES-----------------------------//
const countLinesC2 = svg_c_2.select("#plot-c-2").append("g").attr("id","lines-c-2")
.selectAll("lines")
.data(countSlices)
.enter();
countLinesC2.append("path")
.attr("class", ids)
.attr("fill", "none")
.attr("d", function(d) {
return lineLog(d.values);
})
.style("stroke", function(d, i) {
return colors(d.id);
});
countLinesC2.append("text")
.attr("class","serie_label")
.datum(function(d) {
return {
id: d.id,
value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) {
return "translate(" + (xScale(d.value.date) + 100)
+ "," + (yScale(d.value.measurement) + 55 )+ ")"; })
.attr("x", 5)
.text(function(d) { return d.id.split('=')[0]; })
.style("fill", function(d, i) {
return colors(d.id);});
svg_c_2.select("#plot-c-2")
.append("g")
.attr("id","symbols-c-2")
var pointsLinesC2 = svg_c_2.select("#symbols-c-2")
.selectAll("g")
.data(rankPoints)
.enter()
.append("g")
var circlesC2 = pointsLinesC2.selectAll(".circles")
.data(function(d){
return d.values
})
.enter()
.append("circle")
circlesC2.attr("cx", function(d) {
return xScale(d.date)+110; })
.attr("cy", function(d,i) {
return yScale(d.measurement)+45; })
.attr("r", 14)
.style("fill", function(d) {
return colors(d.id);
})
var circles_text_C2 = pointsLinesC2.selectAll(".text")
.data(function(d){
return d.values
})
.enter()
.append("text")
circles_text_C2.attr("x", function(d) {
return xScale(d.date)+100; })
.attr("y", function(d,i) {
return yScaleSqrt(d.measurement)+50; })
.text(function(d) {
return d.rank;})
.style('fill', 'white');
legendC2 = svg_c_2.append("g")
.attr("id","legend-c-2")
legendC2.append("circle").attr("cx",width+200).attr("cy",300).attr("r", 20).style("fill", "black")
legendC2.append("text").attr("x", width+190).attr("y", 300).text("rank").style("font-size", "12px").style("fill","white")
legendC2.append("text").attr("x", width+150).attr("y", 330).text("BoardGameGeek Rank").style("font-size", "13px").style("fill","black")
});