Published
Edited
May 2, 2019
3 forks
4 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3tip = require('d3-tip')
Insert cell
vegaEmbed = require("vega-embed@3")
Insert cell
import { vz } from '@gjmcn/vizsla-and-vega-lite'
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// goal_vs_time_data = d3.csv("https://gist.githubusercontent.com/cheung927/bee0838a281f5bb97a9ee220c1c099c6/raw/92f690b03b5aa886bc96c4887bb2d4ec0257df06/goal_vs_time_array.csv")
//Not use
Insert cell
a = d3.csv('https://gist.githubusercontent.com/whtsead213/9e84c3e9194427641d937ea24bb8b253/raw/9449fb763e0e55a5c5595c95b9eb913f7fc63391/merged_event.csv', d => {return {"play_id": d.player_id, "x": d.x, "y": d.y, "to_x": d.to_x, "to_y": d.to_y, "type": d.type, "outcome": d.outcome, "side": d.side, "match_name": d.match_name}})
Insert cell
f1 = function (a) {
var output = [];
a.forEach(function (d) {
if (output.indexOf(d.match_name) === -1) {
output.push(d.match_name);
}
});
return output;
};
Insert cell
data1 = f1(a)
Insert cell
f2 = function(match_name){
var output = [];
match_name.forEach(function (d) {
if (output.indexOf(d) === -1) {
output.push({"match_name": d, children: []});
}
});
return output;
}
Insert cell
data2 = f2(data1)
Insert cell
f3 = function(output, a){
for(var i=0; i<a.length; i++){
if(a[i].type === "1" && a[i].outcome === "1"){
for(var j=0; j<output.length; j++){
if(output[j].match_name == a[i].match_name){
output[j].children.push(a[i]);
}
}
}
}
return output;
}
Insert cell
data = f3(data2, a)
Insert cell
goal_vs_time_data2 = d3.csv("https://gist.githubusercontent.com/cheung927/74bb5a15844ac34e4f822ae31d96ada1/raw/f409cbfd9297dfbd8a48984a4b5c61515734f70c/goal_vs_time_array2.csv")
// col: time , distance, type (miss/post/saved/goals)
// preprocessed data for further use
Insert cell
Insert cell
UsaVsPortugal731796 = d3.csv('https://gist.githubusercontent.com/cheung927/4b7bf42c0aee3b26c6594471398bc912/raw/69be9047f80438e5eaaa1cf01997c43a1bab8228/usa-vs-portugal-731796.csv')
// for testing purpose, one match in World Cup 2014
Insert cell
events_merged_all = d3.csv('https://gist.githubusercontent.com/cheung927/4dfd25af0cfefe2886902902817f5a92/raw/a186a02a5834a84190e12624a5d0a4a94f77f9d7/events_merge_all.csv')
Insert cell
//function for finding the distance
function finddistance (x1,x2,y1,y2){
return Math.pow(Math.pow((x2-x1),2)+Math.pow((y2-y1),2),0.5)
}
Insert cell
r = finddistance(92.5,52.2,100,39.4)
//example
Insert cell
md` ### Calculate goal activities`
Insert cell
{
let total_goal = 0
let total_miss = 0
let total_post = 0
let total_saved = 0
for (let i = 0; i < events_merged_all.length; i++){
if (events_merged_all[i].type === '16')
total_goal += 1
else if (events_merged_all[i].type === '13')
total_miss += 1
else if (events_merged_all[i].type === '14')
total_post += 1
else if (events_merged_all[i].type === '15')
total_saved += 1
}
return [total_miss, total_post, total_saved, total_goal]
}
Insert cell
function get_distance_array(r) {
let goala = ({
time: [],
distance: []
})
for (let i = 0; i < events_merged_all.length; i++)
if (events_merged_all[i].type === r){
goala.time.push(events_merged_all[i].min)
goala.distance.push(finddistance(events_merged_all[i].x,events_merged_all[i].to_x,events_merged_all[i].y,events_merged_all[i].to_y))
}
return goala
}
Insert cell
goal_array = get_distance_array("16")
Insert cell
miss_array = get_distance_array("13")
Insert cell
post_array = get_distance_array("14")
Insert cell
saved_array = get_distance_array("15")
Insert cell
total_miss = 677
Insert cell
total_post = 23
Insert cell
total_saved = 836
Insert cell
total_goal = 171
Insert cell
// {
// for (let i = 0; i < events_merged_all.length; i++){
// if (events_merged_all[i].type === '13'||events_merged_all[i].type === '14' || events_merged_all[i].type === '15'||events_merged_all[i].type === '16'){
// events_merged_all[i].field_pass = finddistance(events_merged_all[i].x,events_merged_all[i].to_x,events_merged_all[i].y,events_merged_all[i].to_y)
// }
// }
// } --------not use----------
Insert cell
{
for (let i = 0; i < events_merged_all.length; i++){
if (events_merged_all[i].side === 'A' && (events_merged_all[i].type === '13'||events_merged_all[i].type === '14' || events_merged_all[i].type === '15'||events_merged_all[i].type === '16')){
events_merged_all[i].x = 100 - events_merged_all[i].x
events_merged_all[i].to_x = 100 - events_merged_all[i].to_x
}
}//convert the away team data to the left
return events_merged_all
}
Insert cell
function typeconvert (x){
if (x === "1") return "Pass"
if (x === "13") return "Miss"
if (x === "14") return "Post"
if (x === "15") return "Saved"
if (x === "16") return "Goal"
}
Insert cell
//Usa Vs Portugal, miss(type:13) vs goal(type:16)

chart2 = {
const svg = d3.select(DOM.svg(width + margin.left + margin.right, height + margin.top + margin.bottom));
const pitch = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.right})`)
// //tooltip
// const tooltip = d3tip()
// .style('border', 'solid 3px black')
// .style('background-color', 'white')
// .style('border-radius', '10px')
// .style('float', 'left')
// .style('font-family', 'monospace')
// // Apply tooltip to our SVG
// svg.call(tooltip)
pitch.append('rect')
.attr('x', -margin.left)
.attr('y', -margin.top)
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.style('fill', pitchColor)
//background
const pitchLineData = getPitchLines;
pitch.selectAll('.pitchLines')
.data(pitchLineData)
.enter().append('line')
.attr('x1', d => d['x1'] * pitchMultiplier)
.attr('x2', d => d['x2'] * pitchMultiplier)
.attr('y1', d => d['y1'] * pitchMultiplier)
.attr('y2', d => d['y2'] * pitchMultiplier)
.style('stroke-width', lineWidth)
.style('stroke', lineColor);
//all straight line
const shotData = UsaVsPortugal731796;
pitch.selectAll('.pitchLines')
.data(shotData.filter(function(d){return d.type == 13 && d.side == 'H'}))
.enter().append('line')
.attr('x1', d => width - d['x'] *8.4)
.attr('x2', d => width - d['to_x'] *8.4 )
.attr('y1', d => height - d['y'] *5.44 )
.attr('y2', d => height - d['to_y'] *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'purple')
.attr('opacity', 0.5);
pitch.selectAll('.pitchCircles')
.data(shotData.filter(function(d){return d.type == 13 && d.side == 'H'}))
.enter().append('circle')
.attr('cx', d => width - d['x'] * 8.4)
.attr('cy', d => height - d['y'] * 5.44)
.attr('r', d => 5)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'SteelBlue');
//type 13: Miss by home team

pitch.selectAll('.pitchLines')
.data(shotData.filter(function(d){return d.type == 13 && d.side == 'A'}))
.enter().append('line')
.attr('x1', d => d['x'] *8.4)
.attr('x2', d => d['to_x'] *8.4 )
.attr('y1', d => d['y'] *5.44 )
.attr('y2', d => d['to_y'] *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'purple')
.attr('opacity', 0.5);
pitch.selectAll('.pitchCircles')
.data(shotData.filter(function(d){return d.type == 13 && d.side == 'A'}))
.enter().append('circle')
.attr('cx', d => d['x'] * 8.4)
.attr('cy', d => d['y'] * 5.44)
.attr('r', d => 5)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'SteelBlue');
//type 13: Miss by away team
pitch.selectAll('.pitchLines')
.data(shotData.filter(function(d){return d.type == 16 && d.side == 'H'}))
.enter().append('line')
.attr('x1', d => width - d['x'] *8.4)
.attr('x2', d => width - d['to_x'] *8.4 )
.attr('y1', d => height - d['y'] *5.44 )
.attr('y2', d => height - d['to_y'] *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'red')
.attr('opacity', 0.5);
pitch.selectAll('.pitchCircles')
.data(shotData.filter(function(d){return d.type == 16 && d.side == 'H'}))
.enter().append('circle')
.attr('cx', d => width - d['x'] * 8.4)
.attr('cy', d => height - d['y'] * 5.44)
.attr('r', d => 5)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'GoldenRod');
//type 16: goal by home team

pitch.selectAll('.pitchLines')
.data(shotData.filter(function(d){return d.type == 16 && d.side == 'A'}))
.enter().append('line')
.attr('x1', d => d['x'] *8.4)
.attr('x2', d => d['to_x'] *8.4 )
.attr('y1', d => d['y'] *5.44 )
.attr('y2', d => d['to_y'] *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'red')
.attr('opacity', 0.5);
pitch.selectAll('.pitchCircles')
.data(shotData.filter(function(d){return d.type == 16 && d.side == 'A'}))
.enter().append('circle')
.attr('cx', d => d['x'] * 8.4)
.attr('cy', d => d['y'] * 5.44)
.attr('r', d => 5)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'GoldenRod');
//type 16: goal by away team
const pitchCircleData = getPitchCircles2;
pitch.selectAll('.pitchCircles')
.data(pitchCircleData)
.enter().append('circle')
.attr('cx', d => d['cx'] * pitchMultiplier)
.attr('cy', d => d['cy'] * pitchMultiplier)
.attr('r', d => d['r'] * pitchMultiplier)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => d['color']);
//circle

const pitchArcData = getArcs;
const arc = d3.arc();
pitch.selectAll('.pitchCorners')
.data(pitchArcData)
.enter().append('path')
.attr('d', d => arc(d['arc']))
.attr('transform', d => `translate(${pitchMultiplier * d.x},${pitchMultiplier * d.y})`)
.style('fill', lineColor);
//curve
return svg.node();
}
Insert cell
md`## Total miss and total goal in World Cup 2014`
Insert cell
////all matches, miss(type:13) vs goal(type:16)

chart4 = {
const svg = d3.select(DOM.svg(width + margin.left + margin.right, height + margin.top + margin.bottom));
const pitch = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.right})`)
//tooltip
const tooltip = d3tip()
.style('border', 'solid 3px black')
.style('background-color', 'white')
.style('border-radius', '10px')
.style('float', 'left')
.style('font-family', 'arial')
.html(d => `
Type: ${(typeconvert(d.type))} <br/>
xPosition: ${Math.round(d.x)} <br/>
yPosition: ${Math.round(d.y)} <br/>
Distance to goal : ${Math.round(finddistance(d.x,d.to_x,d.y,d.to_y))} <br/>
</div>`)
// Apply tooltip to our SVG
svg.call(tooltip)
pitch.append('rect')
.attr('x', -margin.left)
.attr('y', -margin.top)
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
//.style('fill', pitchColor)
.style('fill', 'green')
.attr('opacity', 0.7);
//background
const pitchLineData = getPitchLines;
pitch.selectAll('.pitchLines')
.data(pitchLineData)
.enter().append('line')
.attr('x1', d => d['x1'] * pitchMultiplier)
.attr('x2', d => d['x2'] * pitchMultiplier)
.attr('y1', d => d['y1'] * pitchMultiplier)
.attr('y2', d => d['y2'] * pitchMultiplier)
.style('stroke-width', lineWidth)
//.style('stroke', lineColor);
.style('stroke', 'white');
//all straight line
const shotData2 = events_merged_all;
pitch.selectAll('.pitchLines')
.data(shotData2.filter(function(d){return d.type == 13}))
.enter().append('line')
.attr('x1', d => d['x'] *8.4)
.attr('x2', d => d['to_x'] *8.4 )
.attr('y1', d => d['y'] *5.44 )
.attr('y2', d => d['to_y'] *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'purple')
.attr('opacity', 0.15);
pitch.selectAll('.pitchCircles')
.data(shotData2.filter(function(d){return d.type == 13}))
.enter().append('circle')
.attr('cx', d => d['x'] * 8.4)
.attr('cy', d => d['y'] * 5.44)
.attr('r', d => 5)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'SteelBlue')
.on('mouseover', tooltip.show)
.on('mouseout', tooltip.hide);
//type 13: Miss

pitch.selectAll('.pitchLines')
.data(shotData2.filter(function(d){return d.type == 16}))
.enter().append('line')
.attr('x1', d => d['x'] *8.4)
.attr('x2', d => d['to_x'] *8.4 )
.attr('y1', d => d['y'] *5.44 )
.attr('y2', d => d['to_y'] *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'red')
.attr('opacity', 0.15);
pitch.selectAll('.pitchCircles')
.data(shotData2.filter(function(d){return d.type == 16}))
.enter().append('circle')
.attr('cx', d => d['x'] * 8.4)
.attr('cy', d => d['y'] * 5.44)
.attr('r', d => 5)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'GoldenRod')
.on('mouseover', tooltip.show)
.on('mouseout', tooltip.hide);
//type 13: Miss
const pitchCircleData = getPitchCircles2;
pitch.selectAll('.pitchCircles')
.data(pitchCircleData)
.enter().append('circle')
.attr('cx', d => d['cx'] * pitchMultiplier)
.attr('cy', d => d['cy'] * pitchMultiplier)
.attr('r', d => d['r'] * pitchMultiplier)
.style('stroke-width', lineWidth)
//.style('stroke', lineColor)
.style('fill', d => d['color'])
.style('stroke', 'white');
//circle

const pitchArcData = getArcs;
const arc = d3.arc();
pitch.selectAll('.pitchCorners')
.data(pitchArcData)
.enter().append('path')
.attr('d', d => arc(d['arc']))
.attr('transform', d => `translate(${pitchMultiplier * d.x},${pitchMultiplier * d.y})`)
//.style('fill', lineColor)
.style('stroke', 'white');
//curve
return svg.node();
}
Insert cell
md`## Total Saved and total goal in World Cup 2014`
Insert cell
////saved (type:15) vs goal(type:16) in all matches

chart5 = {
const svg = d3.select(DOM.svg(width + margin.left + margin.right, height + margin.top + margin.bottom));
const pitch = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.right})`)
//tooltip
const tooltip = d3tip()
.style('border', 'solid 3px black')
.style('background-color', 'white')
.style('border-radius', '10px')
.style('float', 'left')
.style('font-family', 'arial')
.html(d => `
Type: ${(typeconvert(d.type))} <br/>
xPosition: ${Math.round(d.x)} <br/>
yPosition: ${Math.round(d.y)} <br/>
Distance to goal : ${Math.round(finddistance(d.x,d.to_x,d.y,d.to_y))} <br/>
</div>`)
// Apply tooltip to our SVG
svg.call(tooltip)
pitch.append('rect')
.attr('x', -margin.left)
.attr('y', -margin.top)
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
//.style('fill', pitchColor)
.style('fill', 'green')
.attr('opacity', 0.7);
//background
const pitchLineData = getPitchLines;
pitch.selectAll('.pitchLines')
.data(pitchLineData)
.enter().append('line')
.attr('x1', d => d['x1'] * pitchMultiplier)
.attr('x2', d => d['x2'] * pitchMultiplier)
.attr('y1', d => d['y1'] * pitchMultiplier)
.attr('y2', d => d['y2'] * pitchMultiplier)
.style('stroke-width', lineWidth)
//.style('stroke', lineColor);
.style('stroke', 'white');
//all straight line
const shotData2 = events_merged_all;
pitch.selectAll('.pitchLines')
.data(shotData2.filter(function(d){return d.type == 15}))
.enter().append('line')
.attr('x1', d => d['x'] *8.4)
.attr('x2', d => d['to_x'] *8.4 )
.attr('y1', d => d['y'] *5.44 )
.attr('y2', d => d['to_y'] *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'purple')
.attr('opacity', 0.25);
pitch.selectAll('.pitchCircles')
.data(shotData2.filter(function(d){return d.type == 15}))
.enter().append('circle')
.attr('cx', d => d['x'] * 8.4)
.attr('cy', d => d['y'] * 5.44)
.attr('r', d => 5)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'pink')
.on('mouseover', tooltip.show)
.on('mouseout', tooltip.hide);
//type 15: saved

pitch.selectAll('.pitchLines')
.data(shotData2.filter(function(d){return d.type == 16}))
.enter().append('line')
.attr('x1', d => d['x'] *8.4)
.attr('x2', d => d['to_x'] *8.4 )
.attr('y1', d => d['y'] *5.44 )
.attr('y2', d => d['to_y'] *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'red')
.attr('opacity', 0.5);
pitch.selectAll('.pitchCircles')
.data(shotData2.filter(function(d){return d.type == 16}))
.enter().append('circle')
.attr('cx', d => d['x'] * 8.4)
.attr('cy', d => d['y'] * 5.44)
.attr('r', d => 5)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'GoldenRod')
.on('mouseover', tooltip.show)
.on('mouseout', tooltip.hide);
//type 16: goal
const pitchCircleData = getPitchCircles2;
pitch.selectAll('.pitchCircles')
.data(pitchCircleData)
.enter().append('circle')
.attr('cx', d => d['cx'] * pitchMultiplier)
.attr('cy', d => d['cy'] * pitchMultiplier)
.attr('r', d => d['r'] * pitchMultiplier)
.style('stroke-width', lineWidth)
//.style('stroke', lineColor)
.style('fill', d => d['color'])
.style('stroke', 'white');
//circle

const pitchArcData = getArcs;
const arc = d3.arc();
pitch.selectAll('.pitchCorners')
.data(pitchArcData)
.enter().append('path')
.attr('d', d => arc(d['arc']))
.attr('transform', d => `translate(${pitchMultiplier * d.x},${pitchMultiplier * d.y})`)
//.style('fill', lineColor)
.style('stroke', 'white');
//curve
return svg.node();
}
Insert cell
chart6 = {
const shotData3 = events_merged_all;

const height = 600
const svg = d3.select(DOM.svg(width, height))
const margin = { left: 30, top: 10, right: 10, bottom: 20 }
// Use d3.scaleTime() instead of d3.scaleLinear() for datetime
const xScale = d3.scaleLinear()
.range([margin.left, width - margin.right])
// .domain(d3.extent(shotData3.map(d => d.min)))
.domain([0,120])
svg.append('g')
.call(d3.axisBottom(xScale))
.attr('transform', `translate(0,${height - margin.bottom})`)

const yScale = d3.scaleLinear()
.range([height - margin.bottom, margin.top])
// Substitute dataset
.domain(d3.extent(shotData3.map(d => d.y)))

svg.append('g')
.call(d3.axisLeft(yScale))
.attr('transform', `translate(${margin.left},0)`)

svg.selectAll('circle')
.data(goal_vs_time_data2)
.enter()
.append('circle')
// Circles are distributed across x-axis
.attr('cx', d => xScale(d.time))
// Across y-axis as well, and it becomes two dimensional
.attr('cy', d => yScale(d.distance))
.attr('r', 5)
.attr('opacity',0.5)
.attr('fill', 'GoldenRod')
// .append('circle')
// // Circles are distributed across x-axis
// .attr('cx', d => xScale(d.mtime))
// // Across y-axis as well, and it becomes two dimensional
// .attr('cy', d => yScale(d.mdistance))
// .attr('r', 5)
// .attr('opacity',0.5)
// .attr('fill', 'SteelBlue')

return svg.node()
}
Insert cell
md`## Comparing goal activities' distanace to the goal along with the time`
Insert cell
vegaEmbed({
data: { values: goal_vs_time_data2 },
width: 800,
height: 600,
title: 'Goal vs time',
mark: 'point',
encoding: {
x: { field: 'time' },
y: { field: 'distance' },
color: { field: 'type' }
}
})
Insert cell
md`## Total amount of goal activities in 2014 World Cup`
Insert cell
chart8 = {
var data=[
{x:"total_miss", y:total_miss},
{x:"total_post", y:total_post},
{x:"total_saved", y:total_saved},
{x:"total_goal", y:total_goal},
];
const height = 600
const svg = d3.select(DOM.svg(width, height))
const margin = { left: 30, top: 10, right: 10, bottom: 20 }
const xScale = d3.scaleBand()
.range([0, width])
.domain(data.map((s) => s.x))
.padding(0.5)
svg.append('g')
.call(d3.axisBottom(xScale))
.attr('transform', `translate(0,${height - margin.bottom})`)
const yScale = d3.scaleLinear()
.range([height - margin.bottom, margin.top])
.domain([0,1000])
svg.append('g')
.call(d3.axisLeft(yScale))
.attr('transform', `translate(${margin.left},0)`)

svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', d => xScale(d.x))
.attr('y', d => yScale(d.y))
.attr('height', d => yScale(0) - yScale(d.y))
.attr('width', 100)
.attr('fill', 'SteelBlue')
return svg.node()
}
Insert cell
md`## Total goal activities in World Cup 2014`
Insert cell
// Total goal activities in World Cup 2014
vchart1 = vegaEmbed({
data: {
values: [
{"Activity": "total miss","Number": total_miss},
{"Activity": "total post","Number": total_post},
{"Activity": "total saved","Number": total_saved},
{"Activity": "total goal","Number": total_goal},
]
},
encoding: {
y: {"field": "Activity", "type": "ordinal"},
x: {"field": "Number", "type": "quantitative"}
},
layer: [{
mark: "bar"
}, {
mark: {
type: "text",
align: "left",
baseline: "middle",
dx: 3
},
encoding: {
text: {"field": "Number", "type": "quantitative"}
}
}]
})
Insert cell
md`## Precentage of goal activities in World Cup 2014`
Insert cell
vchart2 = vegaEmbed({
data: {
values: [
{"Activity": "total miss","Number": total_miss},
{"Activity": "total post","Number": total_post},
{"Activity": "total saved","Number": total_saved},
{"Activity": "total goal","Number": total_goal},
]
},
transform: [{
window: [{
op: "sum",
field: "Number",
as: "TotalNumber"
}],
frame: [null, null]
},
{
calculate: "datum.Number/datum.TotalNumber * 100",
as: "PercentOfTotal"
}],
mark: "bar",
encoding: {
x: {
field: "PercentOfTotal",
type: "quantitative",
axis: {
title: "% of total Time"
}
},
y: {
field: "Activity",
type: "ordinal",
scale: {
rangeStep: 12
}
}
}
})

Insert cell
import {select} from "@jashkenas/inputs"
Insert cell
WorldCup2014Players = d3.csv('https://gist.githubusercontent.com/wingchu/c44283c2975cbdd32ef65454052d5e56/raw/d2b321163bf98dc50916147e0f121d1475f92243/player.csv', d => {return {"id": d.id, "name": d.name}})
Insert cell
viewof selected_match = select({
title: 'Pick a match:',
options: data1,
value: data1
});
Insert cell
followByMatch = function(d, m){
var list = [];
for(var i=0; i<d.length; i++){
if(d[i].match_name == m){
for(var j=0; j<d[i].children.length; j++){
if(list.indexOf(d[i].children[j].play_id)===-1){
list.push(d[i].children[j].play_id);
}
}
}
}
return list;
}
Insert cell
list = followByMatch(data, selected_match)
Insert cell
list_id = followByMatch(data, selected_match)
Insert cell
WorldCup2014Players
Insert cell
function id_to_name (list){
for (var i = 0; i < WorldCup2014Players.length; i++){
for (var j = 0; j < list.length; j++){
if (WorldCup2014Players[i].id == list[j]){
list[j] = WorldCup2014Players[i].name;
}
}
}
}
Insert cell
function name_to_id (name){
for (var i = 0; i < WorldCup2014Players.length; i++){
if (WorldCup2014Players[i].name == name){
name = WorldCup2014Players[i].id;
}
}
return name;
}
Insert cell
viewof selected_player = select({
title: 'Pick a player:',
options: list,
value: selected_match
});
Insert cell
selected_player
Insert cell
selected_player_id = name_to_id(selected_player)
Insert cell
data
Insert cell
data_filter = function (d, selected_match) {
var output = [];
for(var i=0; i<d.length; i++){
if(d[i].match_name == selected_match){
for(var j=0; j<d[i].children.length; j++){
output.push(d[i].children[j]);
}
}
}
return output;
}
Insert cell
data_matched = data_filter(data, selected_match)
Insert cell
teamsplit = selected_match.split("-")
Insert cell
md`## Pass Events in match: ${selected_match} <br/>`
Insert cell
md`### ${teamsplit[0]} : Blue (Home Team) | ${teamsplit[2]} : Pink (Away Team)`

Insert cell
//selected match

chart12 = {
const svg = d3.select(DOM.svg(width + margin.left + margin.right, height + margin.top + margin.bottom));
const pitch = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.right})`)
//tooltip
const tooltip = d3tip()
.style('border', 'solid 3px black')
.style('background-color', 'white')
.style('border-radius', '10px')
.style('float', 'left')
.style('font-family', 'arial')
.html(d => `
Type: ${(typeconvert(d.type))} <br/>
Home/Away: ${d.side} <br/>
xPosition: ${Math.round(d.x)} <br/>
yPosition: ${Math.round(d.y)} <br/>
Pass Distance : ${Math.round(finddistance(d.x,d.to_x,d.y,d.to_y))} <br/>
</div>`)
// Apply tooltip to our SVG
svg.call(tooltip)
pitch.append('rect')
.attr('x', -margin.left)
.attr('y', -margin.top)
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
//.style('fill', pitchColor)
.style('fill', 'green')
.attr('opacity', 0.7);
//background
const pitchLineData = getPitchLines;
pitch.selectAll('.pitchLines')
.data(pitchLineData)
.enter().append('line')
.attr('x1', d => d['x1'] * pitchMultiplier)
.attr('x2', d => d['x2'] * pitchMultiplier)
.attr('y1', d => d['y1'] * pitchMultiplier)
.attr('y2', d => d['y2'] * pitchMultiplier)
.style('stroke-width', lineWidth)
//.style('stroke', lineColor);
.style('stroke', 'white');
//all straight line
pitch.selectAll('.pitchLines')
.data(data_matched.filter(function(d){return d.side == "H"}))
.enter().append('line')
.attr('x1', d => d.x *8.4)
.attr('x2', d => d.to_x *8.4 )
.attr('y1', d => d.y *5.44 )
.attr('y2', d => d.to_y *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'blue')
.attr('opacity', 0.15);
pitch.selectAll('.pitchCircles')
.data(data_matched.filter(function(d){return d.side == "H"}))
.enter().append('circle')
.attr('cx', d => d.x * 8.4)
.attr('cy', d => d.y * 5.44)
.attr('r', d => 5)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'SteelBlue')
.attr('opacity', 0.75)
.on('mouseover', tooltip.show)
.on('mouseout', tooltip.hide);
//type 1 , side = home team
pitch.selectAll('.pitchLines')
.data(data_matched.filter(function(d){return d.side == "A"}))
.enter().append('line')
.attr('x1', d => d.x *8.4)
.attr('x2', d => d.to_x *8.4 )
.attr('y1', d => d.y *5.44 )
.attr('y2', d => d.to_y *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'red')
.attr('opacity', 0.15);
pitch.selectAll('.pitchCircles')
.data(data_matched.filter(function(d){return d.side == "A"}))
.enter().append('circle')
.attr('cx', d => d.x * 8.4)
.attr('cy', d => d.y * 5.44)
.attr('r', d => 5)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'pink')
.attr('opacity', 0.75)
.on('mouseover', tooltip.show)
.on('mouseout', tooltip.hide);
//type 1 , side = away team
const pitchCircleData = getPitchCircles2;
pitch.selectAll('.pitchCircles')
.data(pitchCircleData)
.enter().append('circle')
.attr('cx', d => d['cx'] * pitchMultiplier)
.attr('cy', d => d['cy'] * pitchMultiplier)
.attr('r', d => d['r'] * pitchMultiplier)
.style('stroke-width', lineWidth)
//.style('stroke', lineColor)
.style('fill', d => d['color'])
.style('stroke', 'white');
//circle

const pitchArcData = getArcs;
const arc = d3.arc();
pitch.selectAll('.pitchCorners')
.data(pitchArcData)
.enter().append('path')
.attr('d', d => arc(d['arc']))
.attr('transform', d => `translate(${pitchMultiplier * d.x},${pitchMultiplier * d.y})`)
//.style('fill', lineColor)
.style('stroke', 'white');
//curve
return svg.node();
}
Insert cell
md`### Using vegaEmbed to show Pass Event coordinate`
Insert cell
md`### ${teamsplit[0]} : Gold (Home Team) | ${teamsplit[2]} : Blue (Away Team)`
Insert cell
vegaEmbed({
data: { values: data_matched },
width: 840,
height: 544,
title: 'Pass Events happened place ',
mark: 'point',
encoding: {
x: { field: 'x' },
y: { field: 'y' },
color: { field: 'side' }
}
})
Insert cell
md`## player pass activities in the match`
Insert cell
md`### player name: ${selected_player} | Match: ${selected_match}`
Insert cell
//selected match

chart13 = {
const svg = d3.select(DOM.svg(width + margin.left + margin.right, height + margin.top + margin.bottom));
const pitch = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.right})`)
//tooltip
const tooltip = d3tip()
.style('border', 'solid 3px black')
.style('background-color', 'white')
.style('border-radius', '10px')
.style('float', 'left')
.style('font-family', 'arial')
.html(d => `
Type: ${(typeconvert(d.type))} <br/>
Name: ${selected_player} <br/>
Home/Away: ${d.side} <br/>
xPosition: ${Math.round(d.x)} <br/>
yPosition: ${Math.round(d.y)} <br/>
Pass Distance : ${Math.round(finddistance(d.x,d.to_x,d.y,d.to_y))} <br/>
</div>`)
// Apply tooltip to our SVG
svg.call(tooltip)
pitch.append('rect')
.attr('x', -margin.left)
.attr('y', -margin.top)
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
//.style('fill', pitchColor)
.style('fill', 'green')
.attr('opacity', 0.7);
//background
const pitchLineData = getPitchLines;
pitch.selectAll('.pitchLines')
.data(pitchLineData)
.enter().append('line')
.attr('x1', d => d['x1'] * pitchMultiplier)
.attr('x2', d => d['x2'] * pitchMultiplier)
.attr('y1', d => d['y1'] * pitchMultiplier)
.attr('y2', d => d['y2'] * pitchMultiplier)
.style('stroke-width', lineWidth)
//.style('stroke', lineColor);
.style('stroke', 'white');
//all straight line
pitch.selectAll('.pitchLines')
.data(data_matched.filter(function(d){return (d.side == "H") && (d.play_id == selected_player_id) }))
.enter().append('line')
.attr('x1', d => d.x *8.4)
.attr('x2', d => d.to_x *8.4 )
.attr('y1', d => d.y *5.44 )
.attr('y2', d => d.to_y *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'red')
.attr('opacity', 0.5);
pitch.selectAll('.pitchCircles')
.data(data_matched.filter(function(d){return (d.side == "H") && (d.play_id == selected_player_id) }))
.enter().append('circle')
.attr('cx', d => d.x * 8.4)
.attr('cy', d => d.y * 5.44)
.attr('r', d => 8)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'SteelBlue')
.attr('opacity', 0.75)
.on('mouseover', tooltip.show)
.on('mouseout', tooltip.hide);
//type 1 , side = home team
pitch.selectAll('.pitchLines')
.data(data_matched.filter(function(d){return (d.side == "A") && (d.play_id == selected_player_id) }))
.enter().append('line')
.attr('x1', d => d.x *8.4)
.attr('x2', d => d.to_x *8.4 )
.attr('y1', d => d.y *5.44 )
.attr('y2', d => d.to_y *5.44 )
.style('stroke-width', lineWidth)
.style('stroke', 'red')
.attr('opacity', 0.75);
pitch.selectAll('.pitchCircles')
.data(data_matched.filter(function(d){return (d.side == "A") && (d.play_id == selected_player_id) }))
.enter().append('circle')
.attr('cx', d => d.x * 8.4)
.attr('cy', d => d.y * 5.44)
.attr('r', d => 8)
.style('stroke-width', lineWidth)
.style('stroke', lineColor)
.style('fill', d => 'SteelBlue')
.attr('opacity', 0.75)
.on('mouseover', tooltip.show)
.on('mouseout', tooltip.hide);
//type 1 , side = away team
const pitchCircleData = getPitchCircles2;
pitch.selectAll('.pitchCircles')
.data(pitchCircleData)
.enter().append('circle')
.attr('cx', d => d['cx'] * pitchMultiplier)
.attr('cy', d => d['cy'] * pitchMultiplier)
.attr('r', d => d['r'] * pitchMultiplier)
.style('stroke-width', lineWidth)
//.style('stroke', lineColor)
.style('fill', d => d['color'])
.style('stroke', 'white');
//circle

const pitchArcData = getArcs;
const arc = d3.arc();
pitch.selectAll('.pitchCorners')
.data(pitchArcData)
.enter().append('path')
.attr('d', d => arc(d['arc']))
.attr('transform', d => `translate(${pitchMultiplier * d.x},${pitchMultiplier * d.y})`)
//.style('fill', lineColor)
.style('stroke', 'white');
//curve
return svg.node();
}
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