Published
Edited
Dec 2, 2020
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
function chartBS(data) {
const barGraph = d3.create("svg")
.attr("viewBox", [0, 0, widthBar, heightBar])
.attr("font-family", "Arial");
barGraph.append("g")
.call(xAxisBS)
.selectAll("text").style("font-size", "16")
.attr("y", -10)
.attr("x", 4)
.attr("transform", "rotate(0)")
.style("text-anchor", "end");
barGraph.append("g")
.call(yAxisBS(data));

barGraph.append("g")
.style("stroke-width", 1)
.selectAll("rect")
.data(data)
.enter()
.append("rect")
.style("fill", d => d.ATeam == teamname? colorBS(d.yearChange): teamname == "All Premier League"? colorBS(d.yearChange): "Silver")
.style("stroke", "grey")
.attr("x", xBS(0))
.attr("y", d => yBS(strip(d.ATeam)))
.attr("height", yBS('bandwidth'))
.attr("width", d => xBS(d.barMetric) - xBS(0))
.on("mouseover", function(d) {
barGraph.selectAll("rect")
.style("fill", "silver")
.style("stroke", "grey");
d3.select(this)
.style("stroke", "grey")
.style("stroke-width",2)
.style("fill", d => colorBS(d.yearChange));

scatterGraph.selectAll("circle")
.style("fill", function(dHere) {
if (dHere.ATeam === d.ATeam) {
return colorBS(d.yearChange);
}
else {
return "lightgrey";
}
})
.style("stroke", function(dHere) {
if (dHere.ATeam === d.ATeam) {
return "grey";
}
else {
return "grey";
}
})
.style("stroke-width", function(dHere) {
if (dHere.ATeam === d.ATeam) {
return 1;
}
else {
return 1;
}
});

scatterGraph.select("g#circle-legend").selectAll("circle")
.style("fill", "#FFFFFF")
.style("stroke", "Silver");

})
.on("mousemove", function(d) {
return tooltipBS
.style("top", d3.event.pageY - 10 + "px")
.style("left", d3.event.pageX + 10 + "px")
.style("visibility", "visible")
.text(d.ATeam + ": " + d.barMetric + " " + sizeOb[barStat])
.style("font-size", "15px");
})
.on("mouseout", function(d) {
barGraph.selectAll("rect")
.style("fill", d => d.ATeam == teamname? colorBS(d.yearChange): teamname == "All Premier League"? colorBS(d.yearChange): "silver")
.style("stroke", "grey")
.style("stroke-width",1);

scatterGraph.selectAll("circle")
.style("fill", d => d.ATeam == teamname? colorBS(d.yearChange): teamname == "All Premier League"? colorBS(d.yearChange): "Silver")
.style("stroke", "grey")
.style("stroke-width", "1");

scatterGraph.select("g#circle-legend").selectAll("circle")
.style("fill", "White")
.style("stroke", "Silver");

return tooltipBS.style("visibility", "hidden");
});
const scatterGraph = d3.create("svg")
.attr("viewBox", [0, 0, width, heightBS])
.attr("font-family", "Open Sans");
const xlabelLine = scatterGraph.append("g")
.selectAll("g")
.data(ave1920)
.join("g");
xlabelLine.append("path")
.attr("fill", "none")
.attr("stroke", "lightgrey")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(d => XBS(d[scatXStat]))
.y((d,i) => ynum[i]));

const ylabelLine = scatterGraph.append("g")
.selectAll("g")
.data(ave1920)
.join("g");
ylabelLine.append("path")
.attr("fill", "none")
.attr("stroke", "lightgrey")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x((d,i) => xnum[i])
.y(d => YBS(d[scatYStat])));
scatterGraph.append("text")
.style("font-size", 10)
.style("fill", "grey")
.attr("y", YBS(ave1920[0][0][scatYStat])-5)
.attr("x", marginScat.left+10)
.attr("text-anchor", "start")
.text("Last Season Average");
scatterGraph.append("text")
.style("font-size", 10)
.style("fill", "grey")
.attr("y", XBS(ave1920[0][0][scatXStat]) - 5)
.attr("x", - heightBS + marginScat.bottom + 10)
.attr("text-anchor", "start")
.text("Last Season Average")
.attr('transform', 'rotate(-90)');
scatterGraph.append("g")
.call(XAxisBS)
scatterGraph.append("g")
.call(YAxisBS)
scatterGraph.append("text")
.attr("y", heightBS-marginScat.bottom + 60)
.attr("x", (width+marginScat.left)/2)
.attr("text-anchor", "middle")
.attr("font-size", "15px")
.text(sizeOb[scatXStat]);
scatterGraph.append("text")
.attr("y", 40)
.attr("x",(-heightBar)/2)
.attr("text-anchor", "middle")
.attr("font-size", "15px")
.text(sizeOb[scatYStat])
.attr('transform', 'rotate(-90)');
scatterGraph.append("g")
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("r", d => sizeCirc(d.scatSize))
.attr("cx", d => XBS(d.scatX))
.attr("cy", d => YBS(d.scatY))
.style("fill", d => d.ATeam == teamname? colorBS(d.yearChange): teamname == "All Premier League"? colorBS(d.yearChange): "Silver")
.style("stroke", "grey")
.style("stroke-width", "1")
.on("mouseover", function(d) {
scatterGraph.selectAll("circle").style("fill", "Silver").style("stroke", "grey");
d3.select(this).style("fill", d => colorBS(d.yearChange))
.style("stroke", "grey")
.style("stroke-width", 1);
barGraph.selectAll("rect")
.style("fill", function(dHere) {
if (dHere.ATeam === d.ATeam) {
return colorBS(d.yearChange);
} else {
return "Silver";
}
})
.style("stroke", function(dHere) {
if (dHere.ATeam === d.ATeam) {
return "grey";
} else {
return "grey";
}
});

scatterGraph.select("g#circle-legend").selectAll("circle")
.style("fill", "white")
.style("stroke", "Silver");

})

.on("mousemove", function(d) {
return tooltipBS
.style("top", d3.event.pageY - 10 + "px")
.style("left", d3.event.pageX + 10 + "px")
.style("visibility", "visible")
.style("font-size", "15px")
.text(d.ATeam + ": " + d.scatX + " " + sizeOb[scatXStat] + ", " + d.scatY + " " + sizeOb[scatYStat]);
})

.on("mouseout", function(d) {
barGraph.selectAll("rect")
.style("fill", d => d.ATeam == teamname? colorBS(d.yearChange): teamname == "All Premier League"? colorBS(d.yearChange): "silver")
.style("stroke", "grey")
.style("stroke-width",1);

scatterGraph.selectAll("circle")
.style("fill", d => d.ATeam == teamname? colorBS(d.yearChange): teamname == "All Premier League"? colorBS(d.yearChange): "Silver")
.style("stroke", "grey")
.style("stroke-width", "1");

scatterGraph.select("g#circle-legend").selectAll("circle")
.style("fill", "White")
.style("stroke", "Silver");

return tooltipBS.style("visibility", "hidden");

});
// Call it on a g element
scatterGraph.append("g")
.call(legendCirc)
.attr("id", "circle-legend")
.attr("transform", "translate(130,30)");
return [scatterGraph.node(), barGraph.node()];
}
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
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
LineChart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, heightLine])
.style("overflow", "visible");

svg.append("g")
.call(xAxisLine);

svg.append("g")
.call(yAxisLine);
const path = svg.append("g").attr("id", "lines")
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 15)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.selectAll("path")
.data(dataL.series)
.join("path")
.style('stroke', d => colorLine(d.name))
.style("mix-blend-mode", "multiply")
.attr("d", d => line(d.values))
.on("mousemove", function(d) {
console.log("DD", d);
return tooltipLine
.style("top", d3.event.pageY - 10 + "px")
.style("left", d3.event.pageX + 10 + "px")
.style("visibility", "visible")
.text(d.name + ": " + d.values)
.style("font-size", "15px");
})
.on("mouseout", function(d) {
return tooltipLine.style("visibility", "hidden");
});

return svg.node();
}
Insert cell
dataL.series
Insert cell
dataL.series[0].values
Insert cell
tooltipLine = d3
.select("body")
.append("div")
.style("position", "absolute")
.style("font-family", "'Open Sans', sans-serif")
.style("font-size", "10px")
.style("z-index", "10")
.style("visibility", "hidden")
.attr("class", "bstooltip")

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
xLine = d3.scaleLinear()
.domain(d3.extent(dataL.dates))
.range([marginLine.left, width - marginLine.right])
Insert cell
xLineBand = d3.scaleBand()
.domain(d3.extent(dataL.dates))
.range([marginLine.left, width - marginLine.right])
Insert cell
yLine = d3.scaleLinear()
.domain([0, d3.max(dataL.series, d => d3.max(d.values))]).nice()
.range([heightLine - marginLine.bottom, marginLine.top])
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
forOpen = [{name:"Goals",value:+dataBTP.AKGop},{name:"xG",value:+dataBTP.ALxGop}]
Insert cell
forSet = [{name:"Goals",value:+dataBTP.ANGsp},{name:"xG",value:+dataBTP.AOxGsp}]
Insert cell
againstOpen = [{name:"Goals",value:+dataBTP.ATGop},{name:"xG",value:+dataBTP.AUxGop}]
Insert cell
againstSet = [{name:"Goals",value:+dataBTP.AWGsp},{name:"xG",value:+dataBTP.AXxGsp}]
Insert cell
Insert cell
Insert cell
Insert cell
viewof donutStat = select({
options: ["From Open Play", " From Set Pieces"],
})
Insert cell
viewof donutTeam2 = select({
options: ["Serie A Chances","La Liga Chances","Bundesliga Chances"],
})
Insert cell
viewof donutStat2 = select({
options: ["From Open Play", "From Set Pieces"],
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import {entity} from "@d3/color-legend"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
divergingShotDisc = divergingStat=="Shooting"? html`<hr><p>Only includes players with at least 2 shots</p>` : html`<p></p>`
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
shootingData.map(({Name: name}) => ({name}))
Insert cell
dataBTPraw
Insert cell
dataDBCPS = {
const categories = {
"Off": "Off Target",
"SoT": "On Target",
"Gls": "Goals",
};

const datan = shootingData.map(({Name: name, Stat: category, value: value}) => categories[category] ? {name, category: categories[category], value: +value } : null);

// Normalize absolute values to percentage.
d3.rollup(datan, group => {
const sum = d3.sum(group, d => d.value);
for (const d of group) d.value /= sum;
}, d => d.name);

return Object.assign(datan, {
format: ".0%",
negative: "← Nagetive Statistics",
positive: "Positive Statistics →",
negatives: ["Off Target"],
positives: ["On Target", "Goals"]
});
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
num1 = html`<h1>${position}</h1>`
Insert cell
num2 = html`<h1>${played}</h1>`
Insert cell
num3 = html`<h1>${no3}</h1>`
Insert cell
num4 = html`<h1>${no4}</h1>`
Insert cell
num5 = html`<h1>${no5}</h1>`
Insert cell
num6 = html`<h1>${no6}</h1>`
Insert cell
position = +dataBTP.Position
Insert cell
played = +dataBTP.BP
Insert cell
no3 = Math.round(+dataBTP.GFGF/played * 10) / 10
Insert cell
no4 = Math.round(+dataBTP.HGA/played * 10) / 10
Insert cell
no5 = +dataBTP.KxG
Insert cell
no6 = +dataBTP.TxG
Insert cell
Insert cell
dataBTP = teamname == "All Premier League"? dataBTPraw.filter(d => d.ATeam == "Tottenham Hotspur")[0]: dataBTPraw.filter(d => d.ATeam == teamname)[0];
Insert cell
Insert cell
dataBTP20raw = d3.csvParse(await FileAttachment("Premier League - 2019-2020 BTP@1.csv").text())
Insert cell
Insert cell
shootingData = d3.csvParse(await FileAttachment("shooting@1.csv").text()).filter(d => d.Team == teamname)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
leagueDonut = teamname == "All Premier League"? html `<p>Premier League average</p>`: html `<p>${teamname} average</p>`
Insert cell
teamDonut = html `<p>European average</p>`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chroma = require('chroma-js')
Insert cell
import {d3format} from "@jashkenas/inputs"
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more