Published
Edited
Apr 23, 2021
2 stars
Insert cell
Insert cell
// Data importing
Insert cell
Insert cell
function compareACS(a, b) {
if (a.Acs > b.Acs) {
return -1;
}
if (a.Acs <= b.Acs) {
return 1;
}
}
Insert cell
allfilData = acsNA.sort(compareACS);
Insert cell
sliceData = allfilData.slice(0, 17)
Insert cell
filteredData = sliceData.filter(item => item.Ign !== searchACS[0].Ign);
Insert cell
Insert cell
acsNAChart = {
let allfilData = acsNA.sort(compareACS);
let sliceData = allfilData.slice(0, 17)
let filteredData = sliceData;
if (searchACS.length === 1)
{
filteredData.unshift(searchACS[0]);
}
let height = 560;

let margin = {
top:130,
right: 5,
bottom: 70,
left: 110
}
let barWidth = 963/21
let titleMax = 50
let svg = d3.create('svg').style("background-color", 'white').attr("preserveAspectRatio", "none")
.attr("viewBox", "0 0 963 560")
//class to make it responsive
.classed("svg-content-responsive", true); ;
svg.append('rect')
.attr('x', 15)
.attr('y', 0)
.attr('width', 100)
.attr('height', 50)
.attr('stroke', 'black')
.attr('fill', 'black');
svg.append("image")
.attr("xlink:href", "https://runitback.gg/static/media/logo.dcfad9c9.png")
.attr("x", 15)
.attr("y", 0)
.attr("width", 100)
.attr("height", 50);


let yScale = d3.scaleLinear()
.domain([0,d3.max(allfilData.map(d=> (d.Acs)))*1.1])
.range([0, height-margin.top-margin.bottom])

let yScale_axis = d3.scaleLinear()
.domain([0,d3.max(allfilData.map(d=> (d.Acs)))*1.1])
.range([0, height-margin.top-margin.bottom].reverse())
var xScale = d3.scaleOrdinal()
.range([margin.left, 963 - margin.right])
.domain([]);
svg.append("text").attr("class", "player")
.attr("text-anchor", "middle")
.attr("y", 55)
.attr("x", 963/2)
.attr("dy", "3em")
.attr('style', "font-size: 50px; font-family: 'Bebas Neue';");
;
svg.append('text')
.attr('id', 'player')
.attr('pointer-events', 'none').attr('x', 963/2).attr('y', 140).attr("text-anchor" , "middle");

//adding bargraph
svg.selectAll("bars")
.data(filteredData)
.join('rect')
.attr("x", function(d, i) {return margin.left+(barWidth + 3)*i})
.attr("y", function(d) {return height-margin.bottom-yScale(Number(d.Acs))})
.attr("width", barWidth)
.attr("height", function(d) {return yScale(Number(d.Acs))})
.attr("fill", d => teamColors[d.Team])
.on('mouseover', function(event, d) {
d3.select('#player').text(d.Ign + " had an Average ACS of " + d.Acs);
})
.on('mouseout', function(event, d) {
d3.select(this).attr('stoke-width', 0);
d3.select('#player').text('');
});
//adding team logos
svg.selectAll("teamimage")
.data(filteredData)
.join('image')
.attr("xlink:href", function(d) {return teamLogos[d.Team]})
.attr("x", function(d, i) {return margin.left+(barWidth+3)*i})
.attr("y", function(d) {return height-margin.bottom})
.attr("width", barWidth)
.attr("height", barWidth);
// player label
for (let i = 0; i < filteredData.length; i++)
{
let playerName = filteredData[i].Ign;
let playerCP = filteredData[i].Acs;
let barTop = height - margin.bottom - yScale(Number(filteredData[i].Acs))
let barHeight = yScale(Number(filteredData[i].Acs));
let x = margin.left+(barWidth+3)*i+30-4;
let y = barTop+3;
svg.append("text")
.attr("class", "signature").call(addWebFont, 'Bebas Neue', 'https://fonts.gstatic.com/s/bebasneue/v2/JTUSjIg69CK48gW7PXoo9WlhyyTh89Y.woff2')
.attr('style', "font-size: "+40+"px; font-family: 'Bebas Neue';")
.attr("text-anchor", "left")
.attr("y", -10)
.attr("x", 0)
.attr("dy", ".75em")
.style("fill", "white").attr("transform", 'translate('+x+','+y+')rotate(90)').text(playerName);
}
svg.append("text")
.attr("class", "signature")
.attr("text-anchor", "middle")
.attr("y", 2)
.attr("x", 963/2)
.attr("dy", ".75em")
.attr('style', "font-size: 12px; font-family: 'Bebas Neue';")
.text("Author: Sam Rosenberg");
svg.append("text")
.attr("class", "signature")
.attr("text-anchor", "middle")
.attr("y",12)
.attr("x", 44)
.attr("dy", ".75em")
.attr('style', "font-size: 9px; font-family: 'Bebas Neue';")
.text("CITATION");
svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
.call(d3.axisLeft(yScale_axis)).call(addWebFont, 'Bebas Neue', 'https://fonts.gstatic.com/s/bebasneue/v2/JTUSjIg69CK48gW7PXoo9WlhyyTh89Y.woff2')
.attr('style', "font-size: "+30+"px; font-family: 'Bebas Neue';");
svg.append('g')
.attr('transform', `translate(0, ${height - margin.bottom})`)
.call(d3.axisBottom(xScale)).attr('style', "font-size: "+30+"px; font-family: 'Bebas Neue';");;
svg.append("text")
.attr("class", "y axis")
.attr("text-anchor", "middle")
.attr("y", 0)
.attr("x", -(height)/2)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("Average Combat Score (ACS)").attr('style', "font-size: 30px; font-family: 'Bebas Neue';");;
var text = svg.append("svg:text").attr("class", "title")
.attr("text-anchor", "middle")
.attr("y", 55)
.attr("x", 963/2)
.attr("dy", ".75em")
.attr('style', "font-size: "+50+"px; font-family: 'Bebas Neue';");
;
var text2 = svg.append("svg:text").attr("class", "title")
.attr("text-anchor", "middle")
.attr("y", 55)
.attr("x", 963/2)
.attr("dy", ".75em")
.attr('style', "font-size: "+50+"px; font-family: 'Bebas Neue';");
;
text.append("svg:tspan").style("fill", "black").attr("dy", "0em").text("Average Combat Score");
text2.append("svg:tspan").style("fill", "black").attr("dy", "1em").text("at Masters - North America");

return svg.node();
}
Insert cell
Insert cell
Insert cell
regions = ["North America", "Europe", "Brazil", "Turkey", "Japan", "Korea", "CIS", "Latam North"]
Insert cell
Insert cell
Insert cell
instruction = {
let svg = d3.create('svg').style("background-color", 'white').attr("preserveAspectRatio", "none")
.attr("viewBox", "0 3 70 34").attr("width", 200)
svg.append('text')
.attr('x', 28)
.attr('y', 11)
.text("< First region pick rate")
.attr('fill', 'black')
.attr("text-anchor", "left")
.attr('style', "font-size: 4px; font-family: 'Bebas Neue';");
svg.append('text')
.attr('x', 28)
.attr('y', 27)
.text("< Second region pick rate")
.attr('fill', 'black')
.attr("text-anchor", "left")
.attr('style', "font-size: 4px; font-family: 'Bebas Neue';");
svg.append('text')
.attr('x', 28)
.attr('y', 19)
.text("< Difference in pick rate")
.attr('fill', 'black')
.attr("text-anchor", "left")
.attr('style', "font-size: 4px; font-family: 'Bebas Neue';");
svg.append('text')
.attr('x', 1.5)
.attr('y', 21.5)
.text("0 pickrate–")
.attr('fill', 'black')
.attr("text-anchor", "left")
.attr('style', "font-size: 4px; font-family: 'Bebas Neue';");
svg.append('rect')
.attr("x", 17)
.attr("y", function(d) {
return 20 - 5;
})
.attr("width", 10)
.attr("height", 5)
.attr("fill",'#404b65')
.attr("stroke", "black")
.attr("stroke-width", 1)
svg.append('rect')
.attr("x", 17)
.attr("y", 5)
.attr("width", 10)
.attr("height", 15)
.attr("fill", '#404b65')
.attr("stroke", "black")
.attr("stroke-width", 1).style("opacity", 0.35);
svg.append('rect')
.attr("x", 17)
.attr("y", 20)
.attr("width", 10)
.attr("height", 10)
.attr("fill", '#f14853')
.attr("stroke", "black")
.attr("stroke-width", 1).style("opacity", 0.35);

return svg.node();
}
Insert cell
Insert cell
Insert cell
havenRegionData = {
let margin = {
top:60,
right: 40,
bottom: 60,
left: 70
}
let regiononeAgentData = regionHavenData[selectedregionone]
let regiontwoAgentData = regionHavenData[selectedregiontwo]
let agentDiff = []
let len = 0;
for (let i = 0; i < agentNames.length; i++)
{
let present = false;
let oneval = 0;
let twoval = 0;
if (regiononeAgentData.find(a => a.Agent === agentNames[i]) !== undefined)
{
oneval = regiononeAgentData.find(a => a.Agent === agentNames[i]).Percentage
present = true;
}
else
{
oneval = 0
}
if (regiontwoAgentData.find(a => a.Agent === agentNames[i]) !== undefined)
{
twoval = regiontwoAgentData.find(a => a.Agent === agentNames[i]).Percentage
present = true;
}
else
{
twoval = 0
}
console.log(agentNames[i])
console.log(present)
if (present)
{
agentDiff[agentNames[i]] = oneval-twoval
console.log(agentDiff[agentNames[i]])
len++
}
}
let svg = d3.create('svg').style("background-color", 'white').attr("preserveAspectRatio", "none")
.attr("viewBox", "0 0 963 560")
svg.append("text")
.attr("class", "signature")
.attr("text-anchor", "middle")
.attr("y", 10)
.attr("x", 963/2)
.attr("dy", ".75em")
.attr('style', "font-size: 24px; font-family: 'Bebas Neue';")
.text("Author: Sam Rosenberg");
svg.append('rect')
.attr("x", 0)
.attr("width", 963)
.attr("height", 560)
.attr("fill", "transparent")
.attr("stroke", "black")
.attr("stroke-width", 2);
svg.append("image")
.attr("xlink:href", "https://static.wikia.nocookie.net/valorant/images/7/70/Loading_Screen_Haven.png/revision/latest/scale-to-width-down/700?cb=20200620202335")
.attr("x", -15)
.attr("y", -15)
.attr("width", 1000)
.attr("height", 585).style("opacity", 0.3);
svg.append("image")
.attr("xlink:href", "https://runitback.gg/static/media/logo.dcfad9c9.png")
.attr("x", 0)
.attr("y", 0)
.attr("width", 200)
.attr("height", 35);
var text = svg.append("svg:text").attr("class", "title")
.attr("text-anchor", "middle")
.attr("y", 74)
.attr("x", 963/2)
.attr("dy", ".75em")
.attr('style', "font-size: "+50+"px; font-family: 'Bebas Neue';");
;
text.append("svg:tspan").style("fill", "black").attr("dy", "0em").text("Agent Pick Rate on Haven - Masters 1");


let scaleHeight = d3.scaleLinear()
.domain([-100, 100])
.range([-190,190])
let yAxis = d3.scaleLinear()
.domain([-100, 100])
.range([90,470])

len--
//make this make up and down bars
for (let i = 0; i < len+1; i++)
{
svg.append('rect')
.attr("x", i * ((963-margin.left-margin.right)/(len+1))+margin.left)
.attr("y", function(d) {
if (scaleHeight(agentDiff[Object.keys(agentDiff)[i]]) > 0)
{
return yAxis(0);
}
else
{
return yAxis(0) - Math.abs(scaleHeight(agentDiff[Object.keys(agentDiff)[i]]))
}})
.attr("width", ((963-margin.left-margin.right)/(len+1)))
.attr("height", function(d) {return Math.abs(scaleHeight(agentDiff[Object.keys(agentDiff)[i]]))})
.attr("fill", function(d) {
if (scaleHeight(agentDiff[Object.keys(agentDiff)[i]]) > 0)
{
return '#f14853';
}
else
{
return '#404b65';
}})
.attr("stroke", "black")
.attr("stroke-width", 2)
//region one boxes
svg.append('rect')
.attr("x", i * ((963-margin.left-margin.right)/(len+1))+margin.left)
.attr("y", function(d) {
if (regiononeAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]) !== undefined)
{
return yAxis(0);
}
else
{
return 0;
}
})
.attr("width", ((963-margin.left-margin.right)/(len+1)))
.attr("height", function(d) {
if (regiononeAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]) !== undefined)
{
console.log(Object.keys(agentDiff)[i] + " : " + Math.abs(scaleHeight(regiononeAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]).Percentage)))
return Math.abs(scaleHeight(regiononeAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]).Percentage))
}
else
{
return 0
}})
.attr("fill", function(d) {
if (regiononeAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]) !== undefined)
{
if (scaleHeight(regiononeAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]).Percentage) > 0)
{
return '#f14853';
}
else
{
return '#404b65';
}}
else { return 'black';}
})
.attr("stroke", "black")
.attr("stroke-width", 2).style("opacity", 0.35);
//region two boxes
svg.append('rect')
.attr("x", i * ((963-margin.left-margin.right)/(len+1))+margin.left)
.attr("y", function(d) {
if (regiontwoAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]) !== undefined)
{
return yAxis(0) - Math.abs(scaleHeight(regiontwoAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]).Percentage));
}
else
{
return 0;
}
})
.attr("width", ((963-margin.left-margin.right)/(len+1)))
.attr("height", function(d) {
if (regiontwoAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]) !== undefined)
{
return Math.abs(scaleHeight(regiontwoAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]).Percentage))
}
else
{
return 0
}})
.attr("fill", function(d) {
if (regiontwoAgentData.find(a => a.Agent === Object.keys(agentDiff)[i]) !== undefined)
{
return '#404b65';
}
else { return 'black';}
})
.attr("stroke", "black")
.attr("stroke-width", 2).style("opacity", 0.35);
svg.append("image")
.attr("xlink:href", agents.data.find(a => a.displayName === Object.keys(agentDiff)[i]).displayIcon)
.attr("x", i * ((963-margin.left-margin.right)/(len+1))+margin.left)
.attr("y", 560 - ((963-margin.left-margin.right)/(len+1)))
.attr("width", ((963-margin.left-margin.right)/(len+1)))
.attr("height", ((963-margin.left-margin.right)/(len+1)));
}
let times = [0, 0.5, 1.5, 3];
svg.append('g')
.attr('transform', `translate(${margin.left}, 0)`)
.call(d3.axisLeft(yAxis).ticks(8).tickFormat(function(x){return Math.abs(x)+"%";})).call(addWebFont, 'Bebas Neue', 'https://fonts.gstatic.com/s/bebasneue/v2/JTUSjIg69CK48gW7PXoo9WlhyyTh89Y.woff2')
.attr('style', "font-size: "+20+"px; font-family: 'Bebas Neue';");

svg.append("text")
.attr("class", "y axis")
.attr("text-anchor", "middle")
.attr("y", 6)
.attr("x", -(560)/2)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("Pick Rate of Agent").attr('style', "font-size: 30px; font-family: 'Bebas Neue';");;
let keyX = 830;
let multiplier = 2.5;
//key
svg.append('rect')
.attr("x", keyX-33).attr("y", 6)
.attr("width", 165)
.attr("height", 30*multiplier)
.attr("fill", "white")
.attr("stroke", "black")
.attr("stroke-width", 3).style("opacity", .5);
svg.append('text')
.attr('x', keyX+28)
.attr('y', 11 * multiplier)
.text("< First region pick rate")
.attr('fill', 'black')
.attr("text-anchor", "left")
.attr('style', "font-size: 12px; font-family: 'Bebas Neue';");
svg.append('text')
.attr('x', keyX+28)
.attr('y', 27*multiplier)
.text("< Second region pick rate")
.attr('fill', 'black')
.attr("text-anchor", "left")
.attr('style', "font-size: 12px; font-family: 'Bebas Neue';");
svg.append('text')
.attr('x', keyX+28)
.attr('y', 19*multiplier)
.text("< Difference in pick rate")
.attr('fill', 'black')
.attr("text-anchor", "left")
.attr('style', "font-size: 12px; font-family: 'Bebas Neue';");
svg.append('text')
.attr('x', keyX-30)
.attr('y', 21.5*multiplier)
.text("0 pickrate–")
.attr('fill', 'black')
.attr("text-anchor", "left")
.attr('style', "font-size: 12px; font-family: 'Bebas Neue';");
svg.append('rect')
.attr("x", keyX+17)
.attr("y", function(d) {
return (20 - 5)*multiplier;
})
.attr("width", 10)
.attr("height", 5*multiplier)
.attr("fill",'#404b65')
.attr("stroke", "black")
.attr("stroke-width", 1)
svg.append('rect')
.attr("x", keyX+17)
.attr("y", 5*multiplier)
.attr("width", 10)
.attr("height", 15*multiplier)
.attr("fill", '#404b65')
.attr("stroke", "black")
.attr("stroke-width", 1).style("opacity", 0.35);
svg.append('rect')
.attr("x", keyX+17)
.attr("y", 20*multiplier)
.attr("width", 10)
.attr("height", 10*multiplier)
.attr("fill", '#f14853')
.attr("stroke", "black")
.attr("stroke-width", 1).style("opacity", 0.35);
return svg.node();
}
Insert cell
scaleHeight = d3.scaleLinear()
.domain([-100, 100])
.range([-200,200])
Insert cell
Math.abs(scaleHeight(regiononeAgentData.find(a => a.Agent === "Omen").Percentage))
Insert cell
regiononeAgentData = regionHavenData[selectedregionone]
Insert cell
regiontwoAgentData = regionHavenData[selectedregiontwo]
Insert cell
agents = fetch("https://valorant-api.com/v1/agents")
.then(response => {
return response.json();
})
Insert cell
agentNames = [...new Set(agents.data.map(a=>a.displayName))]
Insert cell
agentIcon = [...new Set(agents.data.map(a=>a.displayIcon))]
Insert cell
Insert cell
havenNA = d3.csvParse(await FileAttachment("agentHavenNA.csv").text())
Insert cell
havenJP = d3.csvParse(await FileAttachment("agentHavenJP.csv").text())
Insert cell
havenLN = d3.csvParse(await FileAttachment("agentHavenLN.csv").text())
Insert cell
havenBR = d3.csvParse(await FileAttachment("agentHavenBR.csv").text())
Insert cell
havenCIS = d3.csvParse(await FileAttachment("agentHavenCIS.csv").text())
Insert cell
havenKR = d3.csvParse(await FileAttachment("agentHavenKR.csv").text())
Insert cell
havenTR = d3.csvParse(await FileAttachment("agentHavenTR.csv").text())
Insert cell
havenEU = d3.csvParse(await FileAttachment("agentHavenEU.csv").text())
Insert cell
teamColors = {
return {"Sentinels" : "#ce0037", "Team Envy" : "#000000", "Immortals" : "#03b1a9", "FaZe Clan": "#e43d2f", "100 Thieves" : "#ea3333", "Luminosity Gaming": "#3cbcdc", "XSET": "#f40f30", "Gen.G Esports": "#ab8b2f"}
}
Insert cell
teamLogos = {
return {"Sentinels" : "https://owcdn.net/img/5f25fa763f7ad.png", "Team Envy" : "https://owcdn.net/img/5f3ca822464a3.png", "Immortals" : "https://owcdn.net/img/602e1b45e079f.png", "FaZe Clan": "https://owcdn.net/img/5ef51451b0601.png", "100 Thieves" : "https://owcdn.net/img/603c00d5c5a08.png", "Luminosity Gaming": "https://owcdn.net/img/5f36ec1f4ab21.png", "XSET": "https://owcdn.net/img/5f9725636681d.png", "Gen.G Esports": "https://owcdn.net/img/5f308c5756db6.png"}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
async function addWebFont(selection, fontName, fontURL, fontType = 'woff2') {
const fontData = await toDataURL(fontURL);
return selection.append('style').text(`
@font-face {
font-family: '${fontName}';
src: url(${fontData}) format('${fontType}');
}
`);
};
Insert cell

async function toDataURL(url) {
return new Promise(async(resolve, reject) => {
const res = await fetch(url);
if(!res.ok) return reject(`Error: ${res.status} ${res.statusText}`);
const blob = await res.blob();
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => resolve(reader.result);
});
}

Insert cell
Inputs = require("@observablehq/inputs@0.7.17/dist/inputs.umd.min.js")
Insert cell
// used to import d3
d3 = require('d3@v6')
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