.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "gallery/sonars/plot_bin_statistic_sonar.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_gallery_sonars_plot_bin_statistic_sonar.py: =================== Bin Statistic Sonar =================== StatsBomb has a great `blog `_ on the history of Sonars. Sonars show more information than heatmaps by introducing the angle of passes, shots or other events. The following examples show how to use the ``bin_statistic_sonar`` method to bin data by x/y coordinates and angles. More information is available on how to customize the plotted sonars in :ref:`sphx_glr_gallery_sonars_plot_sonar_grid.py` and :ref:`sphx_glr_gallery_sonars_plot_sonar.py`. .. GENERATED FROM PYTHON SOURCE LINES 15-20 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from mplsoccer import Pitch, VerticalPitch, Sbopen .. GENERATED FROM PYTHON SOURCE LINES 21-22 Load the first game that Messi played as a false-9. .. GENERATED FROM PYTHON SOURCE LINES 22-28 .. code-block:: Python parser = Sbopen() df = parser.event(69249)[0] # 0 index is the event file df = df[(df.type_name == 'Pass') & (df.team_name == 'Barcelona') & (~df.sub_type_name.isin(['Free Kick', 'Throw-in', 'Goal Kick', 'Kick Off', 'Corner']))].copy() .. GENERATED FROM PYTHON SOURCE LINES 29-35 Plot a Pass Sonar ----------------- Here, we calculate the angle and distance for each pass. We then split the data into 6x4 grid cells. Within each grid cell, we split the data into four equal segments of 90 degrees (360 / 4). The defaults count the number of actions (passes) in each segment. .. GENERATED FROM PYTHON SOURCE LINES 35-45 .. code-block:: Python pitch = Pitch() angle, distance = pitch.calculate_angle_and_distance(df.x, df.y, df.end_x, df.end_y) bs = pitch.bin_statistic_sonar(df.x, df.y, angle, bins=(6, 4, 4), # x, y, angle binning # center the first angle so it starts # at -45 degrees (90 / 2) rather than 0 degrees center=True) fig, ax = pitch.draw(figsize=(8, 5.5)) axs = pitch.sonar_grid(bs, width=15, fc='cornflowerblue', ec='black', ax=ax) .. image-sg:: /gallery/sonars/images/sphx_glr_plot_bin_statistic_sonar_001.png :alt: plot bin statistic sonar :srcset: /gallery/sonars/images/sphx_glr_plot_bin_statistic_sonar_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 46-50 Center argument --------------- You can either center the first slice around zero degrees (``center=True``) or start the first segment at zero degrees (``center=False``). .. GENERATED FROM PYTHON SOURCE LINES 50-60 .. code-block:: Python pitch = VerticalPitch() fig, axs = pitch.draw(figsize=(8, 6), nrows=1, ncols=2) angle, distance = pitch.calculate_angle_and_distance(df.x, df.y, df.end_x, df.end_y) bs_center = pitch.bin_statistic_sonar(df.x, df.y, angle, bins=(6, 4, 4), center=True) bs_not_center = pitch.bin_statistic_sonar(df.x, df.y, angle, bins=(6, 4, 4), center=False) axs_sonar = pitch.sonar_grid(bs_center, width=15, fc='cornflowerblue', ec='black', ax=axs[0]) axs_sonar = pitch.sonar_grid(bs_not_center, width=15, fc='cornflowerblue', ec='black', ax=axs[1]) text1 = pitch.text(60, 40, 'center=True', va='center', ha='center', fontsize=15, ax=axs[0]) text1 = pitch.text(60, 40, 'center=False', va='center', ha='center', fontsize=15, ax=axs[1]) .. image-sg:: /gallery/sonars/images/sphx_glr_plot_bin_statistic_sonar_002.png :alt: plot bin statistic sonar :srcset: /gallery/sonars/images/sphx_glr_plot_bin_statistic_sonar_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 61-68 Statistic --------- The default ``statistic='count'`` calculates counts in each segment. You can also use the ``statistic`` and ``values`` arguments to calculate other statistics. Here, we calculate the average pass distance and plot this instead of the count of passes. You can also normalize results between 0 to 1 with the ``normalize=True`` argument. .. GENERATED FROM PYTHON SOURCE LINES 68-79 .. code-block:: Python pitch = Pitch() angle, distance = pitch.calculate_angle_and_distance(df.x, df.y, df.end_x, df.end_y) bs = pitch.bin_statistic_sonar(df.x, df.y, angle, # calculate the average distance # you can also calculate other statistics # such as std, median, sum, min and the max values=distance, statistic='mean', bins=(6, 4, 4), center=True) fig, ax = pitch.draw(figsize=(8, 5.5)) axs = pitch.sonar_grid(bs, width=15, fc='cornflowerblue', ec='black', ax=ax) .. image-sg:: /gallery/sonars/images/sphx_glr_plot_bin_statistic_sonar_003.png :alt: plot bin statistic sonar :srcset: /gallery/sonars/images/sphx_glr_plot_bin_statistic_sonar_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 80-85 Bins ---- In addition to integer values for ``bins``, you can use a sequence of angle edges. The angle edges should be between zero and 2*pi (~6.283), i.e. the angles in radians. You can convert from degrees to radians using numpy.radians. .. GENERATED FROM PYTHON SOURCE LINES 85-97 .. code-block:: Python pitch = Pitch() angle, distance = pitch.calculate_angle_and_distance(df.x, df.y, df.end_x, df.end_y) x_bin = 3 # the bin argument can contain a mix of sequences and integers y_bin = pitch.dim.positional_y # I use cumsum so I can use widths rather than bin edges. # I convert to radians using numpy angle_bin = np.radians(np.array([0, 90, 45, 90, 90, 45])).cumsum() bs = pitch.bin_statistic_sonar(df.x, df.y, angle, bins=(x_bin, y_bin, angle_bin), center=True) fig, ax = pitch.draw(figsize=(8, 5.5)) axs = pitch.sonar_grid(bs, width=15, fc='cornflowerblue', ec='black', ax=ax) .. image-sg:: /gallery/sonars/images/sphx_glr_plot_bin_statistic_sonar_004.png :alt: plot bin statistic sonar :srcset: /gallery/sonars/images/sphx_glr_plot_bin_statistic_sonar_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 98-103 Binnumber --------- You can also get the bin numbers from the bin_statistic_sonar result. Here, we use the ``binnumber`` to filter for the forward passes in the final third and plot them as arrows. .. GENERATED FROM PYTHON SOURCE LINES 103-117 .. code-block:: Python pitch = Pitch() angle, distance = pitch.calculate_angle_and_distance(df.x, df.y, df.end_x, df.end_y) bs = pitch.bin_statistic_sonar(df.x, df.y, angle, bins=(3, 1, 2), center=True) fig, ax = pitch.draw(figsize=(8, 5.5)) axs = pitch.sonar_grid(bs, width=15, fc='cornflowerblue', ec='black', ax=ax) mask = np.logical_and(np.logical_and(bs['binnumber'][0] == 2, # x in the final third bs['binnumber'][1] == 0), # only one y but here for completeness bs['binnumber'][2] == 0 # first angle ) arr = pitch.arrows(df[mask].x, df[mask].y, df[mask].end_x, df[mask].end_y, ax=ax) plt.show() # If you are using a Jupyter notebook you do not need this line .. image-sg:: /gallery/sonars/images/sphx_glr_plot_bin_statistic_sonar_005.png :alt: plot bin statistic sonar :srcset: /gallery/sonars/images/sphx_glr_plot_bin_statistic_sonar_005.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 5.778 seconds) .. _sphx_glr_download_gallery_sonars_plot_bin_statistic_sonar.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_bin_statistic_sonar.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_bin_statistic_sonar.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_bin_statistic_sonar.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_