- ❌
bin_statistic_positionalnow returns the flat zone statistics
dictionary (the same asbin_statistic_zones) instead of a list of
dictionaries, andheatmap_positionalplots the zones as a single
collection instead of a list of QuadMesh. - ❌ On inverted-y pitches ('statsbomb', 'wyscout', 'metricasports'),
explicit y bin edges are now flipped along with the data in
bin_statistic,bin_statistic_sonar,bin_statistic_positional
and the zones methods. Results only change if you used asymmetric
y edges (previously counted in the wrong bands) or have points
exactly on the 'metricasports' positional band edges (previously
assigned to a band by floating point rounding, now always the band
displayed above the edge).
- 🎯 Added heatmaps for custom zones. The
bin_statistic_zones
method bins events into any rectangular layout.
Theheatmap_zonesmethod plots the zones as a single collection so
colorbars work, andlabel_heatmapworks on the results. - Added the
positional_zonesmethod returning the Juego de Posición
layout as (zones, names) for use withbin_statistic_zones. - Added the
draw_zonesmethod for drawing a zone layout without
validating it, so you can build a layout iteratively. - Added the
mirror_zonesmethod for completing a zone layout by
reflecting it about the middle of the pitch. - 🕶️ Added Sonars for zones. The
bin_statistic_sonar_zones
method bins the event angles within each zone and thesonar_zones
method plots a sonar at the centre of each zone. - Added the
sonar_zorderargument tosonar_gridandsonar_zones
to control where the sonar axes are drawn amongst the other artists.
- Fixed artists drawing outside the pitch when parts of the pitch are
hidden (negative pads or half pitches). Thesonar_grid,sonar_zones
(disable withexclude_outside=False) andformationmethods skip
out-of-view insets (returned as None) andlabel_heatmaplabels are
clipped to the axes (passclip_on=Falsefor the old behaviour).
- Fixed curved text labels crashing on matplotlib 3.8 to 3.10
(Text.get_linespacingis only available from matplotlib 3.11).
- Requires matplotlib 3.8 or above (curved radar labels use text
antialiasing APIs added in matplotlib 3.8). - The undocumented
Radar.rotationattribute now always holds the angle
of each parameter around the chart (zero at the top, increasing clockwise).
Previously the lower-half angles were flipped 180 degrees so the text
labels are not upside down; this flip is now only applied to
Radar.rotation_degrees.
- 😍 Added curved text labels for radar charts by
PGupta-Git. Thecurved=Trueargument
inRadar.draw_param_labels()curves parameter labels around the radar
perimeter instead of using straight rotated text. Includes support for
multi-line labels with automatic visual ordering and configurable
letter spacing (curved_letter_spacing). - 🍕 Added curved parameter labels for pizza charts. The
curved_params=Trueargument inPyPizza.make_pizza()curves the
parameter labels around the chart (withcurved_letter_spacing
controlling the letter spacing). To support this,CurvedText
works on polar axes, where the position is (x = theta, y = radius) like
matplotlib's text and the text curves around the polar origin.
- Updated the minimum Python version to 3.10 as version 1.6.0 imports
'KW_ONLY' from 'dataclasses, which is not available in python 3.9.
- Requires Python 3.10 or above.
- ❌
dimensionmodule moved tosoccer.dimensions. - ❌
spot_scaleargument ofPitchclasses default changed
to 0.024 from 0.002. This produces approximately the same size center
spots as previously. The spot scale is now set in relation to the
center circle, i.e. 2.4% of the center circle diameter, rather than in
relation to the length of the pitch as previously.
- 🍦 Adds alternative text values to PyPizza through the
argumentsalt_text_valuesandalt_text_compare_values.
Sometimes you want to display actual values on the pizza chart, while
still using percentiles for the visual representation. The additional
arguments allow you to specify different values to display on the chart
while keeping the percentile calculations for the slice sizes.
- 🍦 Adds 15 formations:
532flat,343flat,3511flat,
3421flat,3412flat,3322,1234,1324,1432,1423,
2422,2413,2431,2332, and2233.
- ❌ Changes two formations
541(wing backs changed to flat back 5)
and541(center attacking midfielders changed to center forwards).
- 🍦 added Sonars for plotting the angles of football events.
Thebin_statistic_sonarmethod has been added for binning the data
by pitch grid cells and the event angles. Thesonarandsonar_grid
methods have been added for plotting the Sonars. - 😍 added football markers for shirts and football boots by the
wonderful Kalle Yrjänä.
- ❌ Changed the default pitch standardizer to a 'custom' pitch (from 'uefa').
This makes metricasports coordinate conversions more accurate, e.g. for flow diagrams. - ❌ Changed the
label_heatmapmethod to return a list of matplotlib.text.Text
instead of matplotlib.text.Annotation objects. - ❌ Removed the
calculate_angle_and_distancemethod'sstandardizedargument.
Instead, the data is automatically standardized if the aspect ratio is unequal. - ❌ Internally the binned_stastics now use the
BinnedStatisticResult
dataclass rather than the_BinnedStatisticResultnamed tuple. - ❌ Changed the polar
inset_axeszero location to 'N' for vertical pitches.
- 🆕 The
pitch_typeargument now accepts custom dimensions in addition to strings ('statsbomb').
For example:
from mplsoccer.dimensions import center_scale_dims
from mplsoccer import Pitch
dim = center_scale_dims(pitch_width=68, pitch_length=105, width=2, length=2)
pitch = Pitch(pitch_type=dim, label=True, axis=True)
fig, ax = pitch.draw()
See themplsoccer.dimensionsmodule for examples of how to define the dimensions. The custom dimensions must be a subclass ofmplsoccer.dimensions.BaseDims.
- Fixed the padding validation for vertical pitches.
- Fixed the padding scaling for vertical pitches with unequal aspect ratios.
- Added the
flip_sidemethod toPitchto flip coordinates to the other side of the pitch.
- Fixed the
424formation so the front line is a line of four
rather than two strikers and two attacking wingers.
- Added the
exclude_nanargument toPitch.label_heatmapto exclude nan from text labels. - Added a
spot_typeargument to thePitchclass to enable plotting penalty and center
spots as squares as well as circles.
- Fixed broken FontManager links.
- Fixed an import error for matplotlib.docstring, which has been depreciated as an external module.
- Fixed a pandas depreciation warning for the StatsBomb module.
- 😍 Added the
formationmethod, which plots formations as text, images, inset axes,
scatter plots or pitches. - 🆕 Added the ability to return a dataframe for all the formations and player positions with the
Pitch.formations_dataframeattribute and thePitch.get_positions()method. - 🆕 Added the
inset_axesandinset_imagemethods/functions for plotting
inset axes and images. - 🆕 Added the
Pitch.textwrapper for Axes.text, which automatically flips
the x and y coordinates. - 🆕 Added the
xoffsetandyoffsetarguments to the label_heatmap method
for plotting a heatmap's labels off-center.
- ❌ Fixed the Matplotlib dependency to version 3.6 or higher.
- ❌ The StatsBomb
tactics_formationis changed from a numeric dtype to a string dtype,
e.g. 442 changed to '442'
- 🆗 Added the new pitch attributes
positional_alphaandshade_alphafor
controlling the transparency of the positional lines and shaded block in the middle of the pitch.
Previously, the alpha was controlled by theline_alphaattribute.
- Fixed some deprecation warnings for Matplotlib (get_cmap) and Seaborn (kdeplot).
- Fixed the timestamp conversion for match data.
- Added the pitch type
impectfor plotting impect data.
- Fixed the StatsBomb lineup parsers so when the player_nickname is missing
the parsers still work.
- Fixed positional pitch marking to remove extraneous lines when
Pitchis created withpositional=True
- Fixed goal width dimensions for
opta_dimsdefinitions from (44.62,55.38) to (45.2,54.8)
- Fixed the
PyPizzaclass so thatlinewidthsof zero are allowed values.
see: #71 - Fixed the
HandlerFootballclass so the football scatter method is compatible with
Matplotlib 3.6 where transOffset was replaced with offset_transform.
see: #72
- Added a wedges example to the tutorials as an alternative to comet lines.
- Fixes the
FontManagerURLs so that they can be imported in JupyterLite.
- We now use hatch rather than setuptools for the mplsoccer build.
- Fixed the
Pitch.bin_statisticmethod so that it returns consistent binnumber results for
the different pitch types. Now the binnumber indexing starts in the top-left hand corner
as index 0, 0. Previously it depended on whether the pitch had an inverted y-axes whether the
indexing started at the top or bottom left corner. This change is consistent with how indexing
on a numpy array works (0, 0) is the top-left corner so this enables the bin statistics
to be reconstructed from the binnumber via numpy indexing.
- Bin numbers from
Pitch.bin_statisticstart in the top-left corner at index 0,0. - Statistics from
Pitch.bin_statistic, now mirror the horizontal pitch layout, i.e. they match
the output fromPitch.label_heatmap. The y coordinate center and edges have been flipped
for inverted y-axis to allow this change (previously the statistic was flipped instead).
- Fixed the broken links for the Roboto fonts in the docs and
FontManagerclass.
- Fixed the error message for
Radarwhen min_range > max_range so that it notifies you
to use the argumentlower_is_betterrather thangreater_is_better.
- 📃 Added an example of layering turbines and radar charts.
- ❌ The
statsbombmodule is completely overhauled to make it easier to use.
The module now contains three classesSbopen,SbapiandSblocalfor retrieving data
from the StatsBomb open-data, API, and local files. - ❌ Added the
lower_is_betterargument toRadar. If any oflower_is_better
strings are in the parameter list then the radar object will flip the statistic.
Previously you had to manually switch the order of themin_rangeandmax_range
to flip the statistic. In soccer, this is useful for parameters like miss-controls
where fewer miss-controls is better than more.
The default (None) does not flip any of the parameters. - 🆕 Added the
gridmodule, which allows thegridfunction to be
used with other types of charts. - ❌ The
gridmethod is changed so if there is no endnote or title then the axes
(or numpy array of axes) are returned rather than a dictionary. - ❌ Renamed
calculate_grid_dimensionstogrid_dimensions.
- 😍 Added a turbine chart, which is a Radar plot with multiple kernel density
estimators plotted to show where in the distribution a person's skill falls.
Inspired by Soumyajit Bose - 😍 Delaunay triangulation added to Pitch classes by
Matthew Williamson using thetriplotmethod. - 😍 Binnumbers added to the
bin_statisticmethods to give
the bin indices for each event. If the event has a null coordinate or a coordinate
outside the pitch the indices are set to negative one. - 🍦
corner_arcsBoolean argument added to pitches by
Devin Pleuler for plotting corner arcs. - 🍦 Added the
linestyle,goal_linestyle, andline_alpha
arguments for styling of the pitches. - 🍦 Added
spokemethod to the Radar class for drawing lines from the center
of the radar to the edges for each plotted statistic. - 🆕 Added the
statistic=circmeanargument to bin_statistic, which uses
a nan safe version of scipy circmean. - 🆕 Added the
draw_radar_solidmethod toRadarto more easily plot multiple radars
on the same chart.
- 🆗
polygonmethod of the Pitch class changed to plot multiple of
matplotlib.patches.Polygon rather than one matplotlib.collections.PatchCollection
so they can be clipped more easily to the shape of other patches. - 🆗 Removed warnings for
figsize,tight_layout,contrained_layout,
layout,view, andorientationas the arguments are deprecated. - 🆗 Changed how pitch lines are drawn from one continuous line to plotting some
lines separately. The one continuous line way of plotting caused problems
as the dotted linestyle was plotted incorrectly when the lines overlapped. - 🆗 Changed how the
boxgoal is drawn from a rectangle to a line to allow
goal_linestyleto work without it overlapping with the pitch - 🆗 Changed
bin_statisticto use the nan safe versions of mean, std, median,
sum, min, and max.
- 📃 Added a new tutorial section and the first tutorial expected threat.
Expected threat is based on the methods popularised by
Karun Singh and Sarah Rudd. - 📃 Removed the matplotlib sub_plot_mosaic function from the docs.
Many people reported that they had problems because it was not available in their
version of matplotlib. It has been replaced with the newgridfunctions.
- Fixed a memory leak in pitch.lines and pitch.quiver associated with assigning
those collections to class-level legend handler map, so they never deallocated. - Fixed read_lineup so it works from reading from a local file.
- Removed deprecated set indexer in statsbomb event reader.
- Fixes for docs: simplified StatsBomb section, fixed broken StatsBomb logos,
and fixed the standardizer example so that it works with the lastest version of kloppy.
- Fixed the install process (setup.py) so it does not import mplsoccer. The version number is now
contained in the _version.py file.
- Added
convexhullmethod to the Pitch classes. This creates a polygon with the smallest
shape that contains the points.
- Added
**kwargstoBumpy.plot()method.
All the keyword arguments are passed for setting ticklabels and labels. - It is now possible to adjust the text in Pizza comparison charts if
the the text overlaps throughget_compare_value_texts.
Four new methods have been added toPyPizzato enable this:get_param_texts(): To fetch list ofaxes.textfor params.get_value_texts(): To fetch list ofaxes.textfor values.get_compare_value_texts(): To fetch list ofaxes.textfor comparison-values.get_theta(): To fetch list containing theta values (float) (x-coordinate for each text).
- added line_alpha to control the transparency of the pitch lines.
- added a cyberpunk example with glowing pitch lines.
- increased the
goal_alphadefault to 1.goal_alphacan now be used with all goal_types.
- fixed the Pitch.grid method
axisargument default to True to match the docstrings.
This release is a major refactor of mplsoccer and a merger with soccerplots for plotting Radars.
- ❌
orientationargument is removed.
To plot on a vertical pitch use the newVerticalPitchclass. - ❌
layoutargument is removed. Use the Matplotlib stylenrowsandncolsinstead.
For example, Pitch(layout=(4, 5)) becomes pitch = Pitch() and pitch.draw(nrows=4, ncols=5). - ❌
viewargument is removed. Use half=True to display half-a-pitch.
For example, Pitch(view='half') becomes Pitch(half=True). - ❌
pitch_type=statspitch_type option removed. - ❌ removed
jointplotmethod and replaced with the more flexiblejointgridmethod.
- ✅
hexbinnow clips to the sides of the soccer pitch for a more
attractive visualization. - ❗
wyscoutgoal width increased to 12 units (from 10 units)
to align with ggsoccer. This matters as the newStandardizer
class uses the goalpost dimensions. - ❗ fixed the
bin_statistic_positionalandheatmap_positional
so the heatmaps are created consistently at the heatmap edges
i.e. grid cells are created from the bottom to the top of the pitch, where the top edge
always belongs to the cell above.
- 😍 Merged mplsoccer with soccerplots
for wonderful radar charts and bumpy charts. - 🍓 Added Nightingale Rose Charts (also known as pizza charts).
- 🍓 Added a
jointgridmethod to draw optional marginal axes on the four-sides
of a soccer pitch. This replaces the oldjointplot, which did not allow non-square pitches. - 🍓 Added the
gridmethod to create a grid of pitches with more control
than plt.subplots. - 🍓 Added
FontManagerfrom ridge_map
by Colin Carroll for downloading and using google fonts. - 🍓 Added
Standardizerfor changing from one provider data format to another.
For example, StatsBomb to Tracab. - 🍦 Added new pitch_types:
skillcorner,secondspectrum, and acustom
pitch type where the length and width can vary. - 🍦 Added
goal_alphafor controlling the transparency ofgoal_type='box'goals. - 🍦 Added
goal_type='circle'to plot the goalposts as circles. - 🆕 Added
degrees=Trueoption so calculate_angle_and_degrees can output the angle
in degrees clockwise. - 🆕 Added
create_transparent_cmapto create colormaps that vary from high transparency
to low transparency. - 🆕 Added
normalizeoption tobin_statisticandbin_statistic_positional
so the results are divided by the total. - Added
str_formatoption tolabel_heatmapto enable formatting of heatmap labels,
e.g. % or rounding. - Added
exclude_zerosoption (default False) tolabel_heatmapto enable you to
exclude drawing any labels equal to zero.
- 🆗 Changed
Seabornx and y from arguments to keyword arguments.
This fixes a FutureWarning from Seaborn that the only valid positional argument will be data. - 🆗 Changed imports so that you do not need to reference the module.
For example, you can now use: from mplsoccer import Pitch. - 🆗 Added repr methods for string representations of classes.
- 🆗 Stopped the storage of the Matplotlib figure and axes in the pitch class attributes.
- 🆗 Fixed a FutureWarning from Pandas that the lookup method will be deprecated.
- 📃 Added examples for custom colormaps
- 📃 Tweaked the StatsBomb data example to only update files if the
JSON file has changed. - 📃 Added more beautiful scatter examples and chart titles.
- 📃 Added examples for
gridandjointgrid.
The pitch class has been split into multiple modules and classes to simplify the code. This helps reduce the number of conditional if/else switches.
- pitch.py contains the new classes for plotting/ drawing pitches. The
Pitchclass is for a
horizontally orientated soccer pitch, and the newVerticalPitchis for the
vertical orientation. A change from the old API of Pitch(orientation='vertical'). - The
PitchandVerticalPitchclasses inherit their
plotting methods fromBasePitchPlot. WhileBasePitchPlotinherits attributes and methods
for drawing a soccer pitch fromBasePitch. - The soccer pitch dimensions are in a separate module (dimensions.py) for reuse within
a newStandardizerclass. - The code for heatmaps, arrows, lines, scatter_rotation, and scatter_football are now
in separate modules (heatmap.py, quiver.py, linecollection.py, and scatterutils.py).
Fixed the statsbomb module to allow a requests response to be used in read_event, read_match, read_competition and read_lineup. This should allow the statsbomb module to be used with the StatsBomb API via the requests library.
Fixed statsbomb read_event to read the z location, as StatsBomb recently changed their data so it also records the shot impact height 'z' location.
- changed the name of the 'statsperform' pitch_type to 'uefa'
- changed the background zorder from 0.8 -> 0.6 so it defaults to below the new Juego de posición pitch markings
- changed the center circle size for the opta, wyscout, statsbomb, and stats pitches to align with the edge of the six-yard box
- amended the fbref plotting example to work for all five of the leagues.
- arrows can now take *args to allow colors to be set using C via a cmap.
- fixed a bug for the metricasports pitch so the center circle and arcs plot when the pitch_width and pitch_length are the same size
- fixed a bug for the Voronoi plot where the wyscout, opta, and metricasports data wasn't scaled appropriately to a full-sized pitch
- fixed bin_statistic so the binning of data is always consistent from the bottom to the top of the pitch. Previously pitches with an inverted axis were binned top to bottom. This does not currently apply to bin_statistic_positional.
- added a method calculate_angles_and_distance to calculate the angle and distance from start and end locations.
- added an example for plotting a pass network contributed by DymondFormation.
- added parameters to shade the middle section of the pitch and draw Juego de posición pitch markings.
- added a method flow to plot a pass flow map and a new example using this method
- Fixed arrows so the arrows scale correctly when the dots per inches (dpi) of the figure is changed. Before the units were in dots so the arrow got smaller as the dots per inches increases. Fixed this so the arrow is in points (1/72th of an inch) so the arrow stays the same size when the dots per inch changes.
- Fixed arrows legend to work in recent versions of matplotlib.
- changed the event_type_name/ event_type_id columns in the StatsBomb data to sub_type_name, sub_type_id.
- combined the StatsBomb technique columns (pass_technique, goalkeeper_technique, shot_technique) into techique_id and technique_name
- combined the Statsbomb type columns (pass_type, duel_type_id, goalkeeper_type, shot_type) into event_type_name and event_type_id
- removed StatsBomb columns that repeat other columns: pass_through_ball, pass_outswinging, pass_inswinging, clearance_head, clearance_left_foot, clearance_right_foot, pass_straight, clearance_other, goalkeeper_punched_out, goalkeeper_shot_saved_off_target, shot_saved_off_target, goalkeeper_shot_saved_to_post, shot_saved_to_post, goalkeeper_lost_out, goalkeeper_lost_in_play, goalkeeper_success_out, goalkeeper_success_in_play, goalkeeper_saved_to_post, shot_kick_off, goalkeeper_penalty_saved_to_post
- changed Pitch so axes aren't raveled when using subplots, e.g. layout=(2, 2). So colorbar can be used with subplots.
- changed the internal workings of bin statistics and heatmaps so the results of bin_statistic can be used for other purposes.
- removed print function from Pitch.
- changed the wyscout goal posts y locations to 45/ 55 for consistency with socceraction.
- fixed the statsbomb module so the event dataset has simplified names for the end coordinates. Previously they were shot_end_x, pass_end_x etc. Now they are under three columns: end_x, end_y, end_z.
- fixed the statsbomb module so it works when the json is empty.
- Added Pitch.voronoi() for calculating Voronoi vertices.
- Added Pitch.goal_angle() for plotting the angle to the goal.
- Added Pitch.polygon() for plotting polygons on the pitch (e.g. goal angle and Voronoi)
- Added add_image for adding images to matplotlib figures.
- Made the statsbomb module clean the data faster.
- fixed Pitch.label_heatmap(). Now filters out labels outside of the pitch extent.
- fixed Pitch.bin_statistic(). Now works for
statisticarguments other than 'count'.
- fixed Pitch.heatmap() bug. Now returns a mesh in horizontal orientation.
- Docs and gallery added.
- Added option to change the penalty and center spot size via spot_scale.
- Added legend handlers for plotting footballs in the scatter method, arrows in the arrows method, and lines in the lines method of the Pitch class.
- utils module renamed scatterutils
- Pitch.quiver() renamed Pitch.arrows()
- Default color of Pitch.lines() changed to rcparams['lines.color']
- Default hexbin cmap changed to viridis
- Pitch.lines() now takes alpha_start and alpha_end arguments. The line linearly increases in opacity from alpha_start to alpha_end if transparent=True. Previously these were hard coded as 0.1 and 0.5. The new defaults are 0.01 and 1.
- Pitch.lines() not takes cmap as an argument. You can either select cmap or color, but not both.
- Pitch.bin_statistic_positional() and Pitch.bin_statistic() return dictionaries rather than named tuples.
- Pitch defaults changed to tight_layout=True and constrained_layout=False.
- Default penalty and center spot size now smaller and can be adjusted.
- Pitch default colors changed, pitch_color is now not plotted by default ('None') and pitch lines are taken from the rcParams 'grid.color'.
Minor pep8 fixes.
- Added constrained_layout option for Pitch class
- Added line_zorder so can raise or lower pitch markings in a plot. This was necessary so you could plot the pitch lines over a heatmap.
- Added support for 'statsperform' and 'metricasports' pitch types.
- Added support for grass texture with pitch_color='grass', e.g. Pitch(pitch_color='grass').
- Added heatmap and methods to bin data and create statistics to allow plotting of heatmaps over pitches.
- Added an arrowhead_marker. Example use: from mplsoccer.utils import arrowhead_marker; Pitch.scatter(x,y,marker='arrowhead_marker).
- Added support for marker rotation, e.g. Pitch.scatter(x,y,rotation_degrees=rotation_degrees). The rotation is in degrees and clockwise. Zero degrees is aligned with the direction of play, i.e. left to right in the horizontal orientation and bottom to top in vertical orientation.
- Added data checks around how padding is used so that you can't accidentally remove the pitch or flip the axis by setting pad_left, pad_right, pad_top,pad_bottom too negative in the Pitch class.
- Added Statsbomb data support to read data from the open-data repo (https://github.com/statsbomb/open-data).
- Added various ValueErrors to ensure that the size of input arrays for plots are the same.
- Default pitch_type is now 'statsbomb'. It was 'opta'.
- Changed defaults for Pitch class: tight_layout=False and constrained_layout=True
- Renamed Pitch.joint_plot() to Pitch.jointplot() to align with Seaborn.
- Pitch backgrounds now plotted internally with the method Pitch._set_background().
- Fixed jointplot to clip to pitch outline.
- Fixed 'wyscout' pitch type. The 0,0 coordinate is meant to be top left.
- Fixed the Pitch.lines() method to take a non-sequence (e.g. one line).
- Fixed the Pitch.lines() method so that when transparent=True its consistent across pitch types. It is more transparent at the line start and more opaque at the line end.
- Fixed how dimensions are represented in the Pitch class internally (left, right, bottom, top) so they match the horizontal pitch orientation.
- Fixed the README so it loads pictures from the raw GitHub files.
Initial version. Pitch class with plotting methods: scatter, lines, quiver, kdeplot, hexbin, and joint_plot. Scatter accepts marker='football' to plot footballs.