Published
Edited
Jun 7, 2022
1 fork
1 star
Insert cell
# statsbomb-data-playground
Insert cell
data360 = FileAttachment("3788741_360.json").json()
Insert cell
data360[0]
Insert cell
function create_coords(array, scaleX, scaleY) {
let res = [];
for (let i = 0; i < array.length; i += 2) {
res.push([scaleX(array[i]), scaleY(array[i + 1])].join(","));
}
return res;
}
Insert cell
lineup = FileAttachment("3788741_lineup.json").json()
Insert cell
events = FileAttachment("3788741_events.json").json()
Insert cell
Insert cell
function xy_moved(location_from, r, angle_d) {
const d = xy_from_r_angle(r, angle_d);
return [location_from[0] + d[0], location_from[1] + d[1]];
}
Insert cell
viewof frame = Inputs.range([1, data360.length - 1], {
label: "Frame",
step: 1
})
Insert cell
filter_event(events, data360, frame)
Insert cell
Insert cell
chart360 = {
function scale(coord) {
return [scaleX(coord[0]), scaleY(coord[1])];
}

/*
* append pass information to svg
*/
function append_pass(svg, event) {
draw_line(
svg,
event["location"],
xy_moved(
event["location"],
event["pass"]["length"],
event["pass"]["angle"]
),
"blue",
"5,5"
);
}
function append_carry(svg, event) {
draw_line(
svg,
event["location"],
event["carry"]["end_location"],
"black",
"5,5"
);
}

function draw_line(svg, p_start, p_end, stroke, stroke_dasharray) {
console.log(svg, p_start, p_end, stroke, stroke_dasharray);
svg
.append("path")
.attr("d", (d) => d3.line()([scale(p_start), scale(p_end)]))
.attr("stroke", stroke)
.attr("stroke-dasharray", stroke_dasharray);
}

/*
* append text to svg
*/
function append_text(svg, data, event_uuid, data_func, x, y, color) {
svg
.append("g")
.selectAll("text")
.data(filter_event(data, null, null, event_uuid))
.enter()
.append("text")

.attr("x", (d) => scaleX(x))
.attr("y", (d) => scaleY(y))
.attr("fill", color)
.text(data_func);
}

const width = 400;
const height = (400 / 105) * 68;
const scaleX = d3.scaleLinear().domain([0, 120]).range([0, width]);
const scaleY = d3.scaleLinear().domain([0, 120]).range([0, height]);
const svg = d3.create("svg").attr("width", width).attr("height", height);
svg
.append("g")
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", "none")
.attr("stroke", "black");
svg
.selectAll("polygon")
.data(data360)
.enter()
.filter((d, i) => i === frame)
.append("polygon")
.transition()
.attr("points", (d) =>
create_coords(d["visible_area"], scaleX, scaleY).join(" ")
)
.attr("stroke", "red")
.attr("stroke-width", 2)
.attr("fill", "none")
.attr("opacity", 0.3);

const freeze = data360[frame]["freeze_frame"];
svg
.selectAll("circle")
.data(freeze)
.enter()
.append("circle")
// .transition()

.attr("cx", (d) => scaleX(d["location"][0]))
.attr("cy", (d) => scaleY(d["location"][1]))
.attr("fill", (d) => (d["actor"] === true ? "red" : "black"))
.attr("r", 3);

append_text(
svg,
events,
data360[frame].event_uuid,
(d) => d["timestamp"],
0,
scaleY(15),
"red"
);

append_text(
svg,
events,
data360[frame].event_uuid,
(d) => `${d["team"]["name"]}: ${d["player"]["name"]}`,
0,
scaleY(10),
"black"
);
append_text(
svg,
events,
data360[frame].event_uuid,
(d) => d["id"],
0,
scaleY(5),
"grey"
);

append_text(
svg,
events,
data360[frame].event_uuid,
(d) => `${d["type"]["name"]}: ${d["play_pattern"]["name"]}`,
0,
scaleY(68 - 13),
"black"
);

// Pass
if (Object.keys(filter_event(events, data360, frame)[0]).includes("pass")) {
const filtered = filter_event(events, data360, frame)[0];

append_pass(svg, filtered);
append_text(
svg,
events,
data360[frame].event_uuid,
(d) => `angle=${d["pass"]["angle"]}, r=${d["pass"]["length"]}`,
0,
scaleY(68 - 18),
"black"
);
}

// Carry
if (Object.keys(filter_event(events, data360, frame)[0]).includes("carry")) {
const filtered = filter_event(events, data360, frame)[0];
append_carry(svg, filtered);
append_text(
svg,
events,
data360[frame].event_uuid,
(d) => d["carry"]["end_location"],
0,
scaleY(68 - 6),
"black"
);
}

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