.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "gallery/sonars/plot_sonar_grid.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_sonar_grid.py: ========== Sonar Grid ========== 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 ``sonar_grid`` method to plot a grid of sonars. I have copied a layout by `Ted Knutson `_ the founder of StatsBomb. However, I encourage you to try out your variations as the API allows you to mix and match different metrics for setting the slice length and colors. Given the huge array of possible combinations, you should also add a key to explain the viz because there isn’t a single standard for Sonars. More information is available on how to customize the grid cells and segments in :ref:`sphx_glr_gallery_sonars_plot_bin_statistic_sonar.py`. .. GENERATED FROM PYTHON SOURCE LINES 20-25 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from mplsoccer import Pitch, Sbopen .. GENERATED FROM PYTHON SOURCE LINES 26-27 Load the first game that Messi played as a false-9. .. GENERATED FROM PYTHON SOURCE LINES 27-37 .. code-block:: Python parser = Sbopen() df = parser.event(69249)[0] # 0 index is the event file df_pass = df[(df.type_name == 'Pass') & (df.team_name == 'Barcelona') & (~df.sub_type_name.isin(['Free Kick', 'Throw-in', 'Goal Kick', 'Kick Off', 'Corner']))].copy() df_pass['success'] = df_pass['outcome_name'].isnull() # There aren't that many throw-ins in this match so we will plot the data from both teams df_throw = df[df.sub_type_name == 'Throw-in'].copy() df_throw['success'] = df_throw['outcome_name'].isnull() .. GENERATED FROM PYTHON SOURCE LINES 38-39 Calculate the angle and distance and create the binned statistics .. GENERATED FROM PYTHON SOURCE LINES 39-60 .. code-block:: Python pitch = Pitch(line_color='#f0eded') angle, distance = pitch.calculate_angle_and_distance(df_pass.x, df_pass.y, df_pass.end_x, df_pass.end_y) throw_angle, throw_distance = pitch.calculate_angle_and_distance(df_throw.x, df_throw.y, df_throw.end_x, df_throw.end_y) # stats for passes bins = (6, 4, 5) bs_count_all = pitch.bin_statistic_sonar(df_pass.x, df_pass.y, angle, bins=bins, center=True) bs_success = pitch.bin_statistic_sonar(df_pass.x, df_pass.y, angle, values=df_pass.success, statistic='mean', bins=bins, center=True) bs_distance = pitch.bin_statistic_sonar(df_pass.x, df_pass.y, angle, values=distance, statistic='mean', bins=bins, center=True) # note we do not center the throw-in segments as throw-ins generally don't go backwards :D throw_bins = (6, 5, 12) bs_throw_success = pitch.bin_statistic_sonar(df_throw.x, df_throw.y, throw_angle, values=df_throw.success, statistic='mean', bins=throw_bins, center=False) bs_throw_distance = pitch.bin_statistic_sonar(df_throw.x, df_throw.y, throw_angle, values=throw_distance, statistic='mean', bins=throw_bins, center=False) .. GENERATED FROM PYTHON SOURCE LINES 61-63 Here, we plot a Sonar grid that copies the style of StatsBomb IQ with average distance for the slice length and the success rate of the passes for the color. .. GENERATED FROM PYTHON SOURCE LINES 63-88 .. code-block:: Python fig, ax = pitch.draw(figsize=(8, 5.5)) axs = pitch.sonar_grid(bs_distance, # here we set the color of the slices based on the % success of the pass stats_color=bs_success, cmap='viridis', ec='#202020', # we set the color map to be mapped from 0% to 100% # rather than the default min/max of the values vmin=0, vmax=1, # the axis minimum and maximum are set automatically to the min/max # here we set it explicity to 0 and 50 units rmin=0, rmax=50, zorder=3, # slices appear above the axis lines width=15, # the size of the sonar axis in data coordinates. Can use height instead ax=ax) # you can turn on the axis and labels with axis=True and label=True in sonar_grid # here, we manually make changes so we can change the styling for ax in axs.flatten(): ax.grid(False, axis='x') # Turn off x-axis spokes ax.grid(True, axis='y', lw=1, ls='--', color='#969696') # Turn on y-axis rings and change line style ax.set_yticks(np.arange(0, 51, 10)) # y-axis rings every 10 distance (0, 10, 20, 30, 40, 50) ax.spines['polar'].set_visible(True) ax.spines['polar'].set_color('#202020') .. image-sg:: /gallery/sonars/images/sphx_glr_plot_sonar_grid_001.png :alt: plot sonar grid :srcset: /gallery/sonars/images/sphx_glr_plot_sonar_grid_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 89-91 Another popular variation is to have the number of passes as the slice length and another metric as the color (e.g. success rate or pass distance). .. GENERATED FROM PYTHON SOURCE LINES 91-99 .. code-block:: Python fig, ax = pitch.draw(figsize=(8, 5.5)) axs = pitch.sonar_grid(bs_count_all, stats_color=bs_distance, cmap='Blues', vmin=0, vmax=50, width=15, # set the axis to the next multiple of 5 rmin=0, rmax=np.ceil(bs_count_all['statistic'].max() / 5) * 5, ax=ax) .. image-sg:: /gallery/sonars/images/sphx_glr_plot_sonar_grid_002.png :alt: plot sonar grid :srcset: /gallery/sonars/images/sphx_glr_plot_sonar_grid_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 100-103 Here, we plot a Sonar grid for throw-ins. The method's defaults do not plot the Sonar grid cell if all the values are numpy_nan (``exclude_nan=True``) or all the values are zero (``exclude_zeros=True``). .. GENERATED FROM PYTHON SOURCE LINES 103-131 .. code-block:: Python fig, ax = pitch.draw(figsize=(8, 5.5)) axs = pitch.sonar_grid(bs_throw_distance, # here we set the color of the slices based on the % success of the pass stats_color=bs_throw_success, cmap='viridis', ec='#202020', exclude_zeros=True, # we set the color map to be mapped from 0% to 100% # rather than the default min/max of the values vmin=0, vmax=1, # the axis minimum and maximum are set automatically to the min/max # here we set it explicity to 0 and 50 units rmin=0, rmax=50, zorder=3, # slices appear above the axis lines width=15, # the size of the sonar axis in data coordinates. Can use height instead ax=ax) # you can turn on the axis and labels with axis=True and label=True in sonar_grid # here, we manually make changes so we can change the styling for ax in axs.flatten(): if ax is not None: # a lot of the axis are None as there are no values in the middle of the pitch ax.grid(True, axis='y', lw=1, ls='--', color='#969696') # Turn on y-axis rings and change line style ax.set_yticks( np.arange(0, 51, 10)) # y-axis rings every 10 distance (0, 10, 20, 30, 40, 50) ax.spines['polar'].set_visible(True) ax.spines['polar'].set_color('#202020') plt.show() # If you are using a Jupyter notebook you do not need this line .. image-sg:: /gallery/sonars/images/sphx_glr_plot_sonar_grid_003.png :alt: plot sonar grid :srcset: /gallery/sonars/images/sphx_glr_plot_sonar_grid_003.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 3.785 seconds) .. _sphx_glr_download_gallery_sonars_plot_sonar_grid.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_sonar_grid.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_sonar_grid.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_sonar_grid.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_