Skip to content

Commit

Permalink
v0.0.2
Browse files Browse the repository at this point in the history
- Adds option to rotate the pitch
- Adds option to shade middle third of pitch
- Adds support for interpolating heatmaps
- Improved docs
- Adds tests for pitch rendering
- Bugfixes
  • Loading branch information
probberechts committed Mar 27, 2021
1 parent 509c5fa commit eee3203
Show file tree
Hide file tree
Showing 21 changed files with 2,248 additions and 7,934 deletions.
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,17 @@ If a _height_ is specified, it sets the height of the corresponding SVG element

Returns the current width of the SVG element.

<a name="pitch_rotate" href="#pitch_rotate">#</a> <i>pitch</i>.<b>rotate</b>([<i>bool</i>])

<a name="pitch_showDirOfPlay" href="#pitch_showDirOfPlay">#</a> <i>pitch</i>.<b>showDirOfPlay</b>([<i>height</i>])
If _bool_ is specified and set to `true`, rotate the plot by 90 degrees. If _bool_ is not specified, returns the current setting, which defaults to false.

If _dirOfPlay_ is specified and set to `true`, shows an arrow on the plot from left to right to indicate the direction of play. If _dirOfPlay_ is not specified, returns the current setting.
<a name="pitch_showDirOfPlay" href="#pitch_showDirOfPlay">#</a> <i>pitch</i>.<b>showDirOfPlay</b>([<i>bool</i>])

If _bool_ is specified and set to `true`, shows an arrow on the plot from left to right to indicate the direction of play. If _bool_ is not specified, returns the current setting, which defaults to false.

<a name="pitch_shadeMiddleThird" href="#pitch_shadeMiddleThird">#</a> <i>pitch</i>.<b>shadeMiddleThird</b>([<i>bool</i>])

If _bool_ is specified and set to `true`, the middle third of the pitch is shaded. If _bool_ is not specified, returns the current setting, which defaults to false.

<a name="pitch_clip" href="#pitch_clip">#</a> <i>pitch</i>.<b>clip</b>([<i>clip</i>])

Expand All @@ -63,7 +70,7 @@ Creates a new heatmap generator with the default configuration values and the sp

Render the heatmap to the given *context*, which may be either a [selection](https://github.com/d3/d3-selection) of containers (either HTML, SVG or G elements) or a corresponding [transition](https://github.com/d3/d3-transition). Reads the data for the heatmap from the datum property on the container.

<img src="img/heatmap.svg" width="500">
<img src="img/heatmap.png" width="500">

<a name="heatmap_fill" href="#heatmap_fill">#</a> <i>heatmap</i>.<b>fill</b>([<i>scale</i>])

Expand All @@ -73,6 +80,10 @@ If _scale_ is specified, sets the color scale, which should be an instance of [d

If _enable_ is set to true, a border will be drawn around a cell of the heatmap when hovered. Additional actions can be assigned trough [onSelect](#heatmap_onSelect) and [onDeselect](#heatmap_onDeselect). If not set, returns the current configuration. Interaction is disabled by default.

<a name="heatmap_interpolate" href="#heatmap_interpolate">#</a> <i>heatmap</i>.<b>interpolate</b>([<i>interpolate</i>])

If _interpolate_ is set to true, the heatmap will be interpolated using bicubic interpolation. If not set, returns the current configuration, which defaults to false.

<a name="heatmap_selected" href="#heatmap_selected">#</a> <i>heatmap</i>.<b>selected</b>([<i>cell</i>])

If _cell_ is specified, sets the selected cell. _cell_ should be specified as 2D coordinates \[x, y\], where (0,0) corresponds to the top left corner cell. If _cell_ is not specified, returns the current selection. Returns `[undefined, undefined]` if no cell is selected, which is the default.
Expand Down Expand Up @@ -125,6 +136,8 @@ If _f_ is specified, dragging an action's marker will trigger execution of _f(da

<a name="_actionsTable" href="#_actionsTable">#</a> <i>actionsTable</i>(<i>context</i>)

<img src="img/actionsTable.png" width="400"><br/>

<a name="actionsTable_tableColumns" href="#actionsTable_tableColumns">#</a> <i>actionsTable</i>.<b>tableColumns</b>([<i>columns</i>])

<a name="actionsTable_scale" href="#actionsTable_scale">#</a> <i>actionsTable</i>.<b>scale</b>([<i>scale</i>])
Expand All @@ -138,6 +151,7 @@ If _f_ is specified, dragging an action's marker will trigger execution of _f(da

<a name="_actionTooltip" href="#_actionTooltip">#</a> <i>actionTooltip</i>(<i>context</i>)

<img src="img/actionTooltip.png" width="200">

<a name="actionTooltip_show" href="#actionTooltip_show">#</a> <i>actionTooltip</i>.<b>show</b>([<i>data</i>])

Expand All @@ -152,6 +166,7 @@ If _f_ is specified, dragging an action's marker will trigger execution of _f(da

<a name="_scoreline" href="#_scoreline">#</a> <i>scoreline</i>(<i>context</i>)

<img src="img/scoreLine.png" width="200">

<a name="scoreline_height" href="#scoreline_height">#</a> <i>scoreline</i>.<b>height</b>([<i>height</i>])

Expand Down
62 changes: 36 additions & 26 deletions example/actions.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,29 @@
<html>
<head>
<title>D3 soccer</title>
<style type="text/css">
#chart>svg {
margin: 50px;
}
.vizrow {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
align-items: center;
justify-content: center;
align-content: center;
align-items: center;
}
<style type="text/css">
#chart>svg {
margin: 50px;
}
.vizrow {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
align-items: center;
justify-content: center;
align-content: center;
align-items: center;
}

.vizcolumn {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
flex-grow: 0;
}
</style>
.vizcolumn {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
flex-grow: 0;
}
</style>
</head>
<body>

Expand All @@ -48,7 +48,8 @@
.showTooltip(tooltip)
.scale(2)
.teamColors({782:"#EF3340", 781:"#FDB913"});
var actionsTable = d3.actionsTable();
var actionsTable = d3.actionsTable()
.teamColors({782:"#EF3340", 781:"#FDB913"});
var scoreline = d3.scoreline().teams([
{"label": "BEL", "color": "#EF3340"},
{"label": "BRA", "color": "#FDB913"} ])
Expand All @@ -57,18 +58,27 @@

var svg = d3.select("#chart").append("svg")
.attr("width", pitch.width())
.attr("height", height)
.attr("height", height + 30)
.attr("class", "light-theme")

svg.append("g")
.datum(data.slice(657,663))
.attr("transform", "translate(0,20)")
.attr("transform", "translate(0,30)")
.call(actions);

svg.append("g")
.attr("transform", "translate(26, 10)")
.attr("transform", "translate(16, 0)")
.call(scoreline)

svg.append('text')
.attr('x', pitch.width() - 15)
.attr('y', height + 20)
.attr('text-anchor', 'end')
.style("fill", "grey")
.style("font-style", "italic")
.style("font-size", "11px")
.text("Data provided by StatsBomb");

d3.select("#table")
.datum(data.slice(657,663))
.call(actionsTable)
Expand Down
1 change: 1 addition & 0 deletions example/data/xg_heatmap.json

Large diffs are not rendered by default.

81 changes: 81 additions & 0 deletions example/de_bruyne_touches.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html>
<head>
<title>D3 soccer</title>
<style type="text/css">
svg {
margin: 50px;
}
</style>
</head>
<body>

<div id="chart" class="light-theme"></div>

<script src="https://d3js.org/d3.v5.min.js"></script>
<script type="text/javascript" src="./dist/d3-soccer.js"></script>
<script type="text/javascript">
var pitch_height = 500;
var header_height = 120;

d3.json("data/debruyne_actions_heatmap.json").then(data => {

var hed = d3.header()
.hed('Kevin De Bruyne')
.subhed('Ball touches')
.img('img/debruyne.png');
var pitch = d3.pitch()
.height(pitch_height)
.rotate(false);
var heatmap = d3.heatmap(pitch).interpolate(true);
var tooltip = d3.actionTooltip();
d3.select("#chart")
.call(tooltip);

var svg = d3.select("#chart")
.append("svg")
// .attr("class", "dark-theme")
.attr("width", pitch.width() + 40)
.attr("height", pitch_height + header_height + 60);

svg.append("g")
.attr('transform', `translate(20,${header_height + 20})`)
.datum(data)
.call(heatmap)

d3.json("data/debruyne_actions.json").then(data => {
svg.select("#above")
.datum(data)
.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return d.start_x; } )
.attr("cy", function (d) { return d.start_y; } )
.attr("r", .5)
.attr("fill", "crimson")
.attr("stroke", "#white")
.attr("stroke-width", .1)
.on('mouseover', d => tooltip.show(d))
.on('mouseout', () => tooltip.hide())
})

svg.append('g')
.attr("transform", "translate(30,30)")
.call(hed);

svg.append('text')
.attr('x', pitch.width())
.attr('y', header_height + pitch_height + 40)
.attr('text-anchor', 'end')
.style("fill", "grey")
.style("font-style", "italic")
.style("font-size", "11px")
.text("Data provided by StatsBomb");

})

</script>
</body>
</html>
62 changes: 14 additions & 48 deletions example/heatmap.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,31 @@
<html>
<head>
<title>D3 soccer</title>
<style type="text/css">
svg {
margin: 50px;
}
</style>
</head>
<body>

<div id="chart"></div>
<div id="chart" class="light-theme"></div>
<div id="value">Tip: Hover over the heatmap</div>

<script src="https://d3js.org/d3.v5.min.js"></script>
<script type="text/javascript" src="./dist/d3-soccer.js"></script>
<script type="text/javascript">
var height = 500;

d3.json("data/debruyne_actions_heatmap.json").then(data => {

var pitch = d3.pitch().height(height);
var hed = d3.header()
.hed('Kevin De Bruyne')
.subhed('Ball touches')
.img('img/debruyne.png');
var heatmap = d3.heatmap(pitch);
var tooltip = d3.actionTooltip();
var pitch_height = 300;

d3.json("data/xg_heatmap.json").then(data => {
var pitch = d3.pitch()
.height(pitch_height)
.clip([[0,0],[68,34]])
.rotate(true);
var heatmap = d3.heatmap(pitch)
.fill(t => d3.interpolateMagma(1-t))
.enableInteraction(true)
.onSelect((x,y,v) => d3.select('#value').text(`The xG value on the selected location is ${v}`))
.interpolate(true);
d3.select("#chart")
.call(tooltip);

var svg = d3.select("#chart")
.append("svg")
.attr("class", "light-theme")
.attr("width", "100%")
.attr("height", height);

svg.append("g")
.datum(data)
.call(heatmap)
.attr("transform", "rotate(-90)translate(-"+(pitch.width()+50)+",0)");

d3.json("data/debruyne_actions.json").then(data => {
svg.select("#above")
.datum(data)
.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return d.start_x; } )
.attr("cy", function (d) { return d.start_y; } )
.attr("r", .5)
.attr("fill", "#FF6600")
.attr("stroke", "#white")
.attr("stroke-width", .1)
.on('mouseover', d => tooltip.show(d))
.on('mouseout', () => tooltip.hide())
})

svg.append('g')
.call(hed)
.attr("transform", "translate(30,0)");
})

</script>
Expand Down
8 changes: 6 additions & 2 deletions example/pitch.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@
</head>
<body>

<div id="chart"></div>
<div id="chart" class="light-theme"></div>

<script src="https://d3js.org/d3.v5.min.js"></script>
<script type="text/javascript" src="./dist/d3-soccer.js"></script>
<script type="text/javascript">

var h = 300;
var pitch = d3.pitch().height(h);
var pitch = d3.pitch().height(h)
.clip([[0,0],[105,68]])
.rotate(false)
.showDirOfPlay(true)
.shadeMiddleThird(false);
var svg = d3.select("#chart").call(pitch);

</script>
Expand Down
Binary file added img/actionTooltip.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/actionsTable.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/heatmap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit eee3203

Please sign in to comment.