433 lines
14 KiB
JavaScript
433 lines
14 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_linechart = d3.select("body")
|
|
.append("svg")
|
|
.attr("width",global_width)
|
|
.attr("height", global_height)
|
|
|
|
//-----------------------------DATA-----------------------------//
|
|
const timeConv = d3.timeParse("%Y-%m-%d");
|
|
const dataset = d3.dsv(",","average-rating.csv");
|
|
dataset.then(function(data) {
|
|
|
|
|
|
//Create rawArr for creating the line data in chart a
|
|
var rawArr = data.map(function(d,i) {
|
|
return d.year+'|'+Math.floor(d.average_rating)
|
|
});
|
|
function countAndSort(arr) {
|
|
return Object.entries(arr.reduce((prev, curr) => (prev[curr] = ++prev[curr] || 1, prev), {})).sort((a,b) => b[1]-a[1])
|
|
} ;
|
|
var frequencyCount = countAndSort(rawArr).map(function(d,i){
|
|
return {
|
|
year: d[0].split('|')[0],
|
|
average_rating: parseInt(d[0].split('|')[1]),
|
|
frequency: parseInt(d[1]),
|
|
}
|
|
})
|
|
|
|
var ratingPerYear ={};
|
|
frequencyCount.forEach(element => {
|
|
var makeKey = element.year;
|
|
if(!ratingPerYear[makeKey]) {
|
|
ratingPerYear[makeKey] = [];
|
|
}
|
|
|
|
ratingPerYear[makeKey].push(element.average_rating);
|
|
});
|
|
|
|
function range(start, end) {
|
|
return Array(end - start + 1).fill().map((_, idx) => start + idx)
|
|
}
|
|
var fullRatingsRange = range(0,9)
|
|
|
|
for (let i = 0; i < Object.keys(ratingPerYear).length; i++) {
|
|
year = Object.keys(ratingPerYear)[i]
|
|
if (year >= 2015 && year <= 2019) {
|
|
currentRatings = ratingPerYear[year]
|
|
missingRatings = fullRatingsRange.filter(x => !currentRatings.includes(x));
|
|
missingRatings.map(function(d){
|
|
missingDict = {
|
|
year: year,
|
|
average_rating: d,
|
|
frequency: 0
|
|
}
|
|
frequencyCount.push(missingDict)
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
console.log(ratingPerYear)
|
|
function fieldSorter(fields) {
|
|
return function (a, b) {
|
|
return fields
|
|
.map(function (o) {
|
|
var dir = 1;
|
|
if (o[0] === '-') {
|
|
dir = -1;
|
|
o=o.substring(1);
|
|
}
|
|
if (a[o] > b[o]) return dir;
|
|
if (a[o] < b[o]) return -(dir);
|
|
return 0;
|
|
})
|
|
.reduce(function firstNonZeroValue (p,n) {
|
|
return p ? p : n;
|
|
}, 0);
|
|
};
|
|
}
|
|
|
|
var frequencyCountsSorted = frequencyCount.sort(fieldSorter(['year','average_rating']))
|
|
|
|
var frequencyGroupedYear ={};
|
|
frequencyCountsSorted.forEach(element => {
|
|
var makeKey = element.year;
|
|
if(!frequencyGroupedYear[makeKey]) {
|
|
frequencyGroupedYear[makeKey] = [];
|
|
}
|
|
|
|
frequencyGroupedYear[makeKey].push({
|
|
id : makeKey,
|
|
average_rating: element.average_rating,
|
|
frequency: element.frequency
|
|
});
|
|
});
|
|
|
|
var datasetLineChart = []
|
|
for (let i = 0; i < Object.keys(frequencyGroupedYear).length; i++) {
|
|
year = Object.keys(frequencyGroupedYear)[i]
|
|
if (year >= 2015 && year <= 2019) {
|
|
var nestedDict = {
|
|
id: year,
|
|
values: frequencyGroupedYear[year]
|
|
}
|
|
datasetLineChart.push(nestedDict)
|
|
|
|
}
|
|
}
|
|
|
|
//Create rawArr for creating the line data in chart a
|
|
var rawArrMovies = data.map(function(d,i) {
|
|
if (d.year >= 2015 && d.year <=2020) {
|
|
return {year:d.year,
|
|
average_rating: parseInt(Math.floor(d.average_rating)),
|
|
users_rated: parseInt(d.users_rated),
|
|
name: d.name
|
|
}
|
|
|
|
}});
|
|
var rawArrMoviesFiltered = rawArrMovies.filter(function(x) {
|
|
return x !== undefined;
|
|
});
|
|
|
|
var moviesSorted = rawArrMoviesFiltered.sort(fieldSorter(['year','average_rating','-users_rated']))
|
|
console.log(moviesSorted)
|
|
|
|
function top5Movies(selectedPoint) {
|
|
var moviesYearRating = []
|
|
moviesSorted.forEach(function(d, i){
|
|
if (d.year == selectedPoint.id && d.average_rating == selectedPoint.average_rating){
|
|
movieDict = {
|
|
year:d.year,
|
|
name:d.name.substring(0,10),
|
|
users_rated:d.users_rated,
|
|
average_rating:d.average_rating
|
|
}
|
|
moviesYearRating.push(movieDict)
|
|
}
|
|
})
|
|
//Now sort the result by user_rated
|
|
var top5MoviesPreSort = moviesYearRating.sort(fieldSorter(['-users_rated'])).slice(0,5)
|
|
var top5MoviesFinal = top5MoviesPreSort.sort(fieldSorter(['users_rated']))
|
|
return top5MoviesPreSort
|
|
|
|
}
|
|
|
|
|
|
//----------------------------SCALES----------------------------//
|
|
const xScale = d3.scaleTime().range([0,width]);
|
|
const yScale = d3.scaleLinear().rangeRound([height, 0]);
|
|
const colors = d3.scaleOrdinal(d3.schemeCategory10);
|
|
|
|
xScale.domain([0, d3.max(datasetLineChart, function(c) {
|
|
return d3.max(c.values, function(d) {
|
|
return parseInt(d.average_rating); });
|
|
})
|
|
]);
|
|
|
|
yScale.domain([(0), d3.max(datasetLineChart, function(c) {
|
|
return d3.max(c.values, function(d) {
|
|
return d.frequency; });
|
|
})
|
|
]);
|
|
|
|
|
|
//-----------------------------AXES-----------------------------//
|
|
const yaxis = d3.axisLeft()
|
|
.scale(yScale);
|
|
|
|
|
|
const xaxis = d3.axisBottom()
|
|
.tickFormat(d3.format("d"))
|
|
.scale(xScale);
|
|
|
|
//----------------------------LINES-----------------------------//
|
|
const line = d3.line()
|
|
.x(function(d) { return xScale(d.average_rating)+100; })
|
|
.y(function(d) { return yScale(d.frequency)+50; });
|
|
|
|
let id = 0;
|
|
const ids = function () {
|
|
return "line-"+id++;
|
|
}
|
|
|
|
const point_ids = function () {
|
|
return "point-"+id++;
|
|
}
|
|
|
|
//-------------------------2. DRAWING---------------------------//
|
|
//-----------------------------AXES-----------------------------//
|
|
|
|
svg_linechart.append("g")
|
|
.attr("id","line_chart_title")
|
|
|
|
svg_linechart.select("#line_chart_title")
|
|
.append("text")
|
|
.attr("transform", "translate(300,0)")
|
|
.attr("y", 25)
|
|
.attr("font-size", "20px")
|
|
.text("Board games by Rating 2015-2019");
|
|
|
|
svg_linechart.append("g")
|
|
.attr("id","credit")
|
|
|
|
svg_linechart.select("#credit")
|
|
.append("text")
|
|
.attr("y", height + 100 )
|
|
.attr("x", width+100)
|
|
.attr("text-anchor", "end")
|
|
.attr("stroke", "black")
|
|
.text("mpearl3");
|
|
|
|
svg_linechart.append("g")
|
|
.attr("transform", "translate(100," + (height+50) + ")")
|
|
.attr("id", "x-axis-lines")
|
|
.call(xaxis);
|
|
|
|
svg_linechart.append("text")
|
|
.attr("id", "x-axis label")
|
|
.attr("transform", "translate(400,0)")
|
|
.attr("y", height + 100)
|
|
.attr("text-anchor", "end")
|
|
.attr("stroke", "black")
|
|
.text("Rating");
|
|
|
|
svg_linechart.append("g")
|
|
.attr("id", "y-axis-lines")
|
|
.attr("transform", "translate(100,50)")
|
|
.call(yaxis);
|
|
|
|
svg_linechart.append("text")
|
|
.attr("id", "y-axis label")
|
|
.attr("transform", "rotate(-90)")
|
|
.attr("y", height - 150)
|
|
.attr("x", -150)
|
|
.attr("dy", "-5.1em")
|
|
.attr("text-anchor", "end")
|
|
.attr("stroke", "black")
|
|
.text("Count");
|
|
|
|
//----------------------------LINES-----------------------------//
|
|
|
|
const frequencyLines = svg_linechart.append("g").attr("id","lines")
|
|
.selectAll("lines")
|
|
.data(datasetLineChart)
|
|
.enter();
|
|
|
|
frequencyLines.append("path")
|
|
.attr("fill", "none")
|
|
.attr("d", function(d) { return line(d.values); })
|
|
.style("stroke", function(d, i) {
|
|
return colors(d.id);
|
|
});
|
|
|
|
frequencyPoints = svg_linechart.append("g")
|
|
.attr("id","circles")
|
|
|
|
|
|
frequencyPoints
|
|
.selectAll(".dot")
|
|
.data(datasetLineChart)
|
|
.enter()
|
|
.append("g")
|
|
.attr("id",point_ids)
|
|
.selectAll("circle")
|
|
.data(function(d){return d.values})
|
|
.enter()
|
|
.append("circle")
|
|
.attr("cx", function(d) {
|
|
return xScale(d.average_rating)+100;
|
|
})
|
|
.attr("cy", function(d,i) { return yScale(d.frequency)+50; })
|
|
.attr("r", 4)
|
|
.style("fill", function(d) {
|
|
return colors(d.id);
|
|
}
|
|
)
|
|
.on("mouseover", function(d) {
|
|
d3.select(event.currentTarget).attr("r", "12");
|
|
const svg_barchart = d3.select("body")
|
|
.append("svg")
|
|
.attr("id","barchart")
|
|
.attr("width",global_width)
|
|
.attr("height", global_height)
|
|
|
|
const topMoviesSelection = top5Movies(d)
|
|
if (d.frequency > 0) {
|
|
//----------------------------SCALES----------------------------//
|
|
const xScaleBar = d3.scaleLinear().range([0,width]);
|
|
const yScaleBar = d3.scaleBand()
|
|
.range([height, 0]);
|
|
|
|
xScaleBar.domain([0, d3.max(topMoviesSelection,function(c) {
|
|
return c.users_rated;
|
|
})]);
|
|
|
|
var movieNames = []
|
|
topMoviesSelection.forEach(
|
|
function(d){
|
|
movieNames.push(d.name);
|
|
}
|
|
);
|
|
|
|
yScaleBar.domain(movieNames);
|
|
|
|
|
|
//-----------------------------AXES-----------------------------//
|
|
const yaxisBar = d3.axisLeft()
|
|
.scale(yScaleBar);
|
|
|
|
|
|
const xaxisBar = d3.axisBottom()
|
|
.tickFormat(d3.format("d"))
|
|
.scale(xScaleBar);
|
|
//-----------------------------DRAWING SUB-PLOT-----------------------------//
|
|
|
|
svg_barchart.append("g")
|
|
.attr("id","bar_chart_title")
|
|
.data(topMoviesSelection)
|
|
.enter()
|
|
|
|
// const countLinesA = svg_a.select("#plot-a").append("g").attr("id","lines-a")
|
|
// .selectAll("lines")
|
|
// .data(countSlices)
|
|
// .enter();
|
|
|
|
svg_barchart
|
|
.select("#bar_chart_title")
|
|
.append("text")
|
|
.datum(function(d) {
|
|
return {
|
|
year: d.year,
|
|
value: d.average_rating
|
|
}})
|
|
.attr("transform", "translate(300,0)")
|
|
.attr("y", 25)
|
|
.attr("font-size", "20px")
|
|
.text(function(d) {
|
|
return 'Top 5 most rated games of '+d.year+' with rating '+d.value
|
|
});
|
|
|
|
|
|
svg_barchart.append("g")
|
|
.attr("transform", "translate(100," + (height+50) + ")")
|
|
.attr("id", "x-axis-bars")
|
|
.call(xaxisBar);
|
|
|
|
svg_barchart.append("g")
|
|
.attr("id", "bar_x_axis_label");
|
|
|
|
svg_barchart.select("#bar_x_axis_label")
|
|
.append("text")
|
|
.attr("transform", "translate(400,0)")
|
|
.attr("y", height +100)
|
|
.attr("text-anchor", "end")
|
|
.attr("stroke", "black")
|
|
.text("Number of Users");
|
|
|
|
svg_barchart.append("g")
|
|
.attr("id","y-axis-bars")
|
|
.attr("transform", "translate(100,50)")
|
|
.call(yaxisBar);
|
|
|
|
svg_barchart.append("g")
|
|
.attr("id", "bar_y_axis_label");
|
|
|
|
svg_barchart.select("#bar_y_axis_label")
|
|
.append("text")
|
|
.attr("transform", "rotate(-90)")
|
|
.attr("y", height - 150)
|
|
.attr("x", -150)
|
|
.attr("dy", "-5.1em")
|
|
.attr("text-anchor", "end")
|
|
.attr("stroke", "black")
|
|
.text("Games");
|
|
|
|
const bars = svg_barchart.append("g")
|
|
.attr("id","bars")
|
|
.selectAll("myRect")
|
|
.data(topMoviesSelection)
|
|
.enter();
|
|
|
|
bars.append("rect")
|
|
.attr("x", xScaleBar(0)+100 )
|
|
.attr("y", function(d) { return yScaleBar(d.name)+50; })
|
|
.attr("width", function(d) { return xScaleBar(d.users_rated); })
|
|
.attr("height", yScaleBar.bandwidth() )
|
|
.attr("fill", "#69b3a2");
|
|
}})
|
|
.on("mouseout", function(d){
|
|
d3.select(event.currentTarget).attr("r", 4);
|
|
d3.select("#barchart").remove()
|
|
// svg_barchart.selectAll(".text").remove()
|
|
// svg_barchart.select("#x-axis-bars").remove()
|
|
// svg_barchart.select("#y-axis-bars").remove()
|
|
// svg_barchart.select("#bar-chart-title").remove()
|
|
// svg_barchart.select("#bar_x_axis_label").remove()
|
|
// svg_barchart.select("#bar_y_axis_label").remove()
|
|
// svg_barchart.selectAll('#bars').remove()
|
|
// svg_barchart.select("#bar_chart_title").remove()
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
var legend_years = ["2015","2016","2017","2018","2019"]
|
|
|
|
legend = svg_linechart.append("g")
|
|
.attr("id","legend")
|
|
|
|
// Handmade legend
|
|
legend_years.forEach(function(d,i) {
|
|
legend.append("circle").attr("cx",(width+40)+(1)*8).attr("cy",95+(i+1)*15).attr("r", 6).style("fill", colors(d))
|
|
legend.append("text").attr("x", (width+50)+(1)*8).attr("y", 95+(i+1)*15).text(d).style("font-size", "15px")
|
|
}
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
}); |