球王梅西喜欢在哪里射门?
来蹭一个世界杯热点,大家想知道球王梅西最喜欢在哪里射门吗?这个到了我擅长的地方,用 G2 5.0 来数据可视化一下。小手一抖,也可以 star 一下。
准备数据
这个网站上有各个球员的所有数据,我们拉下来即可,对于前端来说,这个不难,也不是重点,所以不具体展开了,数据放在这里了。
{
"id": "32522",
"minute": "22",
"result": "MissedShots",
"X": "0.7859999847412109",
"Y": "0.52",
"xG": "0.03867039829492569",
"player": "Lionel Messi",
"h_a": "h",
"player_id": "2097",
"situation": "OpenPlay",
"season": "2014",
"shotType": "LeftFoot",
"match_id": "5831",
"h_team": "Barcelona",
"a_team": "Elche",
"h_goals": "3",
"a_goals": "0",
"date": "2014-08-24 20:00:00",
"player_assisted": "Rafinha",
"lastAction": "Pass"
}
可视化看分布
这个数据很全了,有各种数据信息,要知道“梅西喜欢在哪里射门?”这个问题的答案,只需要关注数据中的 x、y 信息即可。快速实现一个散点图,看看位置分布。
import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart
.point()
.data({
type: 'fetch',
value:
'https://mdn.alipayobjects.com/afts/file/A*FCRjT4NGENEAAAAAAAAAAAAADrd2AQ/messi.json',
})
.encode('x', (d) => Number(d.X))
.encode('y', (d) => Number(d.Y))
.encode('color', 'shotType')
.encode('shape', 'point')
.scale('x', { domain: [0, 1] })
.scale('y', { domain: [0, 1] })
.style('fillOpacity', 0.4)
.axis(false);
chart.render();
这个图已经可以看到一些信息了:梅西是个左撇子,宁愿头球,都不愿意用右脚。
但是这似乎就看不出他喜欢在哪射门,这个时候需要来一个 bin 分箱一下,然后用透明度来展示分箱中的数据量。
import { Chart } from '@antv/g2';
const FW = 600;
const FH = 400;
const P = 50;
const chart = new Chart({
container: 'container',
width: FW + P * 2,
height: FH + P * 2,
padding: P,
});
chart
.rect()
.data({
type: 'fetch',
value:
'https://mdn.alipayobjects.com/afts/file/A*FCRjT4NGENEAAAAAAAAAAAAADrd2AQ/messi.json',
})
.transform({
type: 'bin',
opacity: 'count',
thresholdsX: 20,
thresholdsY: 20,
})
.encode('x', (d) => Number(d.X))
.encode('y', (d) => Number(d.Y))
.scale('x', { domain: [0, 1] })
.scale('y', { domain: [0, 1] })
chart.render();
这个图中 x y 都是 0 ~ 1 的数据,应该是指射门位置相对于球场的位置,但是用数字去看是在不方便,如果有一个球场的背景,那就看起来清晰多了。
绘制一个简单的球场
因为足球场,其实是一个绝对布局,场上的标记线都是有标准的规范和比例。
所以在绘制足球场的时候,使用的是一个 G2 的自定义 mark 标记来绘制。
chart
.shape()
.style('render', foot);
function foot(styles) {
return ;
}
这个其实非常繁琐,有点像使用 Canvas 的命令去绘制一个足球场。G 提供了基础的图形去绘制。直接贴最终的代码。
import { Chart } from '@antv/g2';
const FW = 600;
const FH = 400;
const P = 50;
const chart = new Chart({
container: 'container',
width: FW + P * 2,
height: FH + P * 2,
padding: P,
});
// 足球场
chart
.shape()
.style('x', '0%')
.style('y', '0%')
.style('render', point)
chart
.rect()
.data({
type: 'fetch',
value:
'https://mdn.alipayobjects.com/afts/file/A*FCRjT4NGENEAAAAAAAAAAAAADrd2AQ/messi.json',
})
.transform({
type: 'bin',
opacity: 'count',
thresholdsX: 15,
thresholdsY: 15,
})
.encode('x', (d) => Number(d.X))
.encode('y', (d) => Number(d.Y))
.scale('x', { domain: [0, 1] })
.scale('y', { domain: [0, 1] })
.axis(false);
chart.render();
function point() {
const {
canvas: { document },
} = chart.context();
const g = document.createElement('g');
const r = document.createElement('rect', {
style: {
x: 0,
y: 0,
width: FW,
height: FH,
fill: 'green',
fillOpacity: 0.2,
stroke: 'grey',
lineWidth: 1,
},
});
const r1 = document.createElement('rect', {
style: {
x: FW - FH * 0.6 * 0.45,
y: (FH - FH * 0.6) / 2,
width: FH * 0.6 * 0.45,
height: FH * 0.6,
strokeOpacity: 0.5,
stroke: 'grey',
lineWidth: 1,
},
});
const r2 = document.createElement('rect', {
style: {
x: FW - FH * 0.3 * 0.45,
y: (FH - FH * 0.3) / 2,
width: FH * 0.3 * 0.45,
height: FH * 0.3,
strokeOpacity: 0.5,
stroke: 'grey',
lineWidth: 1,
},
});
const l = document.createElement('line', {
style: {
x1: FW / 2,
y1: 0,
x2: FW / 2,
y2: FH,
strokeOpacity: 0.4,
stroke: 'grey',
lineWidth: 2,
},
});
g.append(r);
g.append(r1);
g.append(r2);
g.append(l);
return g;
}
如果需要更加精细的足球场,可以按照标准的足球场比例规范去绘制。最终效果:
小结
所以梅西喜欢在哪里射门?上图大概能看出来一些信息。复制上述代码到 G2 官网案例中,就可以运行,自己调参了。
转载自:https://juejin.cn/post/7181299522910306363