Source code for floodlight.vis.pitches

from typing import Tuple

import matplotlib
from matplotlib.patches import Arc, Wedge, Rectangle

from floodlight.utils.types import Numeric


[docs]def plot_handball_pitch( xlim: Tuple[Numeric, Numeric], ylim: Tuple[Numeric, Numeric], unit: str, color_scheme: str, show_axis_ticks: bool, ax: matplotlib.axes, **kwargs, ) -> matplotlib.axes: """Plots a handball pitch on a given matplotlib.axes. Parameters ---------- xlim: Tuple[Numeric, Numeric] Limits of pitch boundaries in longitudinal direction. This tuple has the form (x_min, x_max) and delimits the length of the pitch (not of any actual data) within the coordinate system. ylim: Tuple[Numeric, Numeric] Limits of pitch boundaries in lateral direction. This tuple has the form (y_min, y_max) and delimits the width of the pitch (not of any actual data) within the coordinate system. unit: str The unit in which data is measured along axes. Possible types are {'m', 'cm', 'percent'}. color_scheme: str Color scheme of the plot. One of {'standard', 'bw'}. show_axis_ticks: bool If set to True, the axis ticks are visible. ax: matplotlib.axes Axes from matplotlib library on which the handball field is plotted. kwargs: Optional keyworded arguments {'linewidth', 'zorder', 'scalex', 'scaley'} which can be used for the plot functions from matplotlib. The kwargs are only passed to all the plot functions of matplotlib. Returns ------- axes : matplotlib.axes Axes from matplotlib library on which a handball pitch is plotted. Notes ----- The kwargs are only passed to the plot functions of matplotlib. To customize the plots have a look at `matplotlib <https://matplotlib.org/3.5.0/api/_as_gen/matplotlib.axes.Axes.plot.html>`_. For example in order to modify the linewidth pass a float to the keyworded argument 'linewidth'. The same principle applies to other kwargs like 'zorder', 'scalex' and 'scaley'. .. _handball-pitch-label: Examples -------- >>> import matplotlib.pyplot as plt >>> from floodlight.vis.pitches import plot_handball_pitch >>> # create matplotlib.axes >>> ax = plt.subplots()[1] >>> # plot handball pitch >>> plot_handball_pitch(xlim=(0,40), ylim=(0,20), unit='m', color_scheme='standard', >>> show_axis_ticks=False, ax=ax) >>> plt.show() .. image:: ../../_img/pitch_handball_example.png """ # kwargs which are used to configure the plot with default values 1 and 0. # all the other kwargs will be just passed to all the plot functions. linewidth = kwargs.pop("linewidth", 1) zorder = kwargs.pop("zorder", 0) # customizing visualization if color_scheme == "bw": ax.set_facecolor("white") # color of the pitch color_contour_lines = "black" color_goal_area_fill = "white" color_goal_posts = "black" else: ax.set_facecolor("skyblue") # color of the pitch color_contour_lines = "white" color_goal_area_fill = "khaki" color_goal_posts = "white" # Positions and ranges on the field which are used for plotting all lines and # arcs. # All the positions and ranges are scaled based on percentages of the x-range # and y-range. # key positions for the handball pitch xmin, xmax = xlim ymin, ymax = ylim x_range = xmax - xmin y_range = ymax - ymin x_half = (xmax + xmin) / 2 y_half = (ymax + ymin) / 2 # Positions (x,y) on the handball pitch pos_left_side_right_goal_post = (xmin, ymin + y_range * 0.425) pos_left_side_left_goal_post = (xmin, ymin + y_range * 0.575) pos_right_side_left_goal_post = (xmax, ymin + y_range * 0.425) pos_right_side_right_goal_post = (xmax, ymin + y_range * 0.575) pos_start_right_side_rect_goal_area = ( xmax - x_range * 0.15, ymin + y_range * 0.425, ) # Ranges on the handball pitch y_height_free_throw_arc = y_range * 0.9 x_width_free_throw_arc = x_range * 0.45 y_height_goal_area_arc = y_range * 0.6 x_width_goal_area_arc = x_range * 0.3 radius_goal_area_arc = x_range * 0.15 width_goal = y_range * 0.15 x_height_goal = x_range * 0.025 # Y positions on the handball pitch y_range_center_to_post = width_goal / 2 y_pos_goal_lower_post = y_half - y_range_center_to_post y_pos_goal_upper_post = y_half + y_range_center_to_post y_pos_lower_goal_posts = ymin + y_range * 0.425 y_pos_upper_goal_posts = ymin + y_range * 0.575 lower_y_pos_4m_line = ymin + (y_range * 0.49625) upper_y_pos_4m_line = ymin + (y_range * 0.50375) lower_y_pos_7m_line = ymin + (y_range * 0.475) upper_y_pos_7m_line = ymin + (y_range * 0.525) # X positions on the handball pitch x_pos_left_side_goal_area_line_edge = xmin + (x_range * 0.15) x_pos_right_side_goal_area_line_edge = xmax - (x_range * 0.15) x_pos_left_side_free_throw_line_edge = xmin + (x_range * 0.225) x_pos_right_side_free_throw_line_edge = xmax - (x_range * 0.225) x_pos_left_side_4m_line = xmin + (x_range * 0.1) x_pos_right_side_4m_line = xmax - (x_range * 0.1) x_pos_left_side_7m_line = xmin + (x_range * 0.175) x_pos_right_side_7m_line = xmax - (x_range * 0.175) # angle for the free throw arc changes when unit is 'percent' angle = 10 if unit == "percent" else 0 # margins of the plot x_margin = x_range * 0.025 y_margin = y_range * 0.05 # set up the boundaries of ax ax.set_xlim([xmin - (x_height_goal + x_margin), xmax + (x_height_goal + x_margin)]) ax.set_ylim([ymin - y_margin, ymax + y_margin]) # paint handball pitch with all properties # main boundaries ax.plot( [xmin, xmin], [ymin, ymax], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) ax.plot( [xmax, xmax], [ymin, ymax], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) ax.plot( [xmin, xmax], [ymin, ymin], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) ax.plot( [xmin, xmax], [ymax, ymax], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) # midline ax.plot( [x_half, x_half], [ymin, ymax], color=color_contour_lines, zorder=zorder, linewidth=linewidth, **kwargs, ) # free-throw lines # lower left ax.add_patch( Arc( pos_left_side_right_goal_post, width=x_width_free_throw_arc, height=y_height_free_throw_arc, angle=0, theta1=290 - angle, theta2=360, linestyle="dashed", linewidth=linewidth, color=color_contour_lines, zorder=zorder, **kwargs, ) ) # upper left ax.add_patch( Arc( pos_left_side_left_goal_post, width=x_width_free_throw_arc, height=y_height_free_throw_arc, angle=0, theta1=0, theta2=70 + angle, linestyle="dashed", linewidth=linewidth, color=color_contour_lines, zorder=zorder, **kwargs, ) ) # lower right ax.add_patch( Arc( pos_right_side_left_goal_post, width=x_width_free_throw_arc, height=y_height_free_throw_arc, angle=0, theta1=180, theta2=250 + angle, linestyle="dashed", linewidth=linewidth, color=color_contour_lines, zorder=zorder, **kwargs, ) ) # upper right ax.add_patch( Arc( pos_right_side_right_goal_post, width=x_width_free_throw_arc, height=y_height_free_throw_arc, angle=0, theta1=110 - angle, theta2=180, linestyle="dashed", linewidth=linewidth, color=color_contour_lines, zorder=zorder, **kwargs, ) ) # goal area lines # lower left # Filling the goal area if unit != "percent": # Since wedges can't be scaled ax.add_patch( Wedge( pos_left_side_right_goal_post, r=radius_goal_area_arc, theta1=270, theta2=360, linewidth=linewidth, color=color_goal_area_fill, zorder=zorder, **kwargs, ) ) # goal area line ax.add_patch( Arc( pos_left_side_right_goal_post, height=y_height_goal_area_arc, width=x_width_goal_area_arc, angle=0, theta1=270, theta2=360, linewidth=linewidth, color=color_contour_lines, zorder=zorder, **kwargs, ) ) # upper left # filling the goal area if unit != "percent": # Since wedges can't be scaled ax.add_patch( Wedge( pos_left_side_left_goal_post, r=radius_goal_area_arc, theta1=0, theta2=90, linewidth=linewidth, color=color_goal_area_fill, zorder=zorder, **kwargs, ) ) # goal area line ax.add_patch( Arc( pos_left_side_left_goal_post, height=y_height_goal_area_arc, width=x_width_goal_area_arc, angle=0, theta1=0, theta2=90, linewidth=linewidth, color=color_contour_lines, zorder=zorder, **kwargs, ) ) # lower right # filling the goal area if unit != "percent": # Since wedges can't be scaled ax.add_patch( Wedge( pos_right_side_left_goal_post, r=radius_goal_area_arc, theta1=180, theta2=270, linewidth=linewidth, color=color_goal_area_fill, zorder=zorder, **kwargs, ) ) # goal area line ax.add_patch( Arc( pos_right_side_left_goal_post, height=y_height_goal_area_arc, width=x_width_goal_area_arc, angle=0, theta1=180, theta2=270, linewidth=linewidth, color=color_contour_lines, zorder=zorder, **kwargs, ) ) # upper right # filling the goal area if unit != "percent": # Since wedges can't be scaled ax.add_patch( Wedge( pos_right_side_right_goal_post, r=radius_goal_area_arc, theta1=90, theta2=180, linewidth=linewidth, color=color_goal_area_fill, zorder=zorder, **kwargs, ) ) # goal area line ax.add_patch( Arc( pos_right_side_right_goal_post, height=y_height_goal_area_arc, width=x_width_goal_area_arc, angle=0, theta1=90, theta2=180, linewidth=linewidth, color=color_contour_lines, zorder=zorder, **kwargs, ) ) # mid left # filling the goal area if unit != "percent": # Since wedges can't be scaled the rectangles ax.add_patch( # are also not used to fill the goal area Rectangle( pos_left_side_right_goal_post, width=radius_goal_area_arc, height=width_goal, color=color_goal_area_fill, zorder=zorder, **kwargs, ) ) # mid right # filling the goal area if unit != "percent": # Since wedges can't be scaled the rectangles ax.add_patch( # are also not used to fill the goal area Rectangle( pos_start_right_side_rect_goal_area, width=radius_goal_area_arc, height=width_goal, color=color_goal_area_fill, zorder=zorder, **kwargs, ) ) # vertical goal area lines ax.plot( [x_pos_left_side_goal_area_line_edge, x_pos_left_side_goal_area_line_edge], [y_pos_lower_goal_posts, y_pos_upper_goal_posts], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) ax.plot( [ x_pos_right_side_goal_area_line_edge, x_pos_right_side_goal_area_line_edge, ], [y_pos_lower_goal_posts, y_pos_upper_goal_posts], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) # vertical free throw lines ax.plot( [ x_pos_left_side_free_throw_line_edge, x_pos_left_side_free_throw_line_edge, ], [y_pos_lower_goal_posts, y_pos_upper_goal_posts], color=color_contour_lines, linewidth=linewidth, linestyle="dashed", zorder=zorder, **kwargs, ) ax.plot( [ x_pos_right_side_free_throw_line_edge, x_pos_right_side_free_throw_line_edge, ], [y_pos_lower_goal_posts, y_pos_upper_goal_posts], color=color_contour_lines, linewidth=linewidth, linestyle="dashed", zorder=zorder, **kwargs, ) # 4 m lines ax.plot( [x_pos_left_side_4m_line, x_pos_left_side_4m_line], [lower_y_pos_4m_line, upper_y_pos_4m_line], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) ax.plot( [x_pos_right_side_4m_line, x_pos_right_side_4m_line], [lower_y_pos_4m_line, upper_y_pos_4m_line], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) # 7 m lines ax.plot( [x_pos_left_side_7m_line, x_pos_left_side_7m_line], [lower_y_pos_7m_line, upper_y_pos_7m_line], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) ax.plot( [x_pos_right_side_7m_line, x_pos_right_side_7m_line], [lower_y_pos_7m_line, upper_y_pos_7m_line], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) # goals # left goal ax.plot( [xmin - x_height_goal, xmin - x_height_goal], [y_pos_goal_lower_post, y_pos_goal_upper_post], color=color_goal_posts, linewidth=linewidth, zorder=zorder, **kwargs, ) ax.plot( [xmin - x_height_goal, xmin], [y_pos_goal_lower_post, y_pos_goal_lower_post], color=color_goal_posts, linewidth=linewidth, zorder=zorder, **kwargs, ) ax.plot( [xmin - x_height_goal, xmin], [y_pos_goal_upper_post, y_pos_goal_upper_post], color=color_goal_posts, linewidth=linewidth, zorder=zorder, **kwargs, ) # right goal ax.plot( [xmax + x_height_goal, xmax + x_height_goal], [y_pos_goal_lower_post, y_pos_goal_upper_post], color=color_goal_posts, linewidth=linewidth, zorder=zorder, **kwargs, ) ax.plot( [xmax + x_height_goal, xmax], [y_pos_goal_lower_post, y_pos_goal_lower_post], color=color_goal_posts, linewidth=linewidth, zorder=zorder, **kwargs, ) ax.plot( [xmax + x_height_goal, xmax], [y_pos_goal_upper_post, y_pos_goal_upper_post], color=color_goal_posts, linewidth=linewidth, zorder=zorder, **kwargs, ) # baseline ax.plot( [xmax, xmax], [ymin, ymax], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) # baseline ax.plot( [xmin, xmin], [ymin, ymax], color=color_contour_lines, linewidth=linewidth, zorder=zorder, **kwargs, ) # remove labels and ticks if not show_axis_ticks: ax.xaxis.set_major_locator(matplotlib.ticker.NullLocator()) ax.yaxis.set_major_locator(matplotlib.ticker.NullLocator()) return ax
[docs]def plot_football_pitch( xlim: Tuple[Numeric, Numeric], ylim: Tuple[Numeric, Numeric], length: Numeric, width: Numeric, unit: str, color_scheme: str, show_axis_ticks: bool, ax: matplotlib.axes, **kwargs, ) -> matplotlib.axes: """Plots a football pitch on a given matplotlib.axes. Parameters ---------- xlim: Tuple[Numeric, Numeric] Limits of pitch boundaries in longitudinal direction. This tuple has the form (x_min, x_max) and delimits the length of the pitch (not of any actual data) within the coordinate system. ylim: Tuple[Numeric, Numeric] Limits of pitch boundaries in lateral direction. This tuple has the form (y_min, y_max) and delimits the width of the pitch (not of any actual data) within the coordinate system. length: Numeric Length of the actual pitch in `unit`. width: Numeric, optional Width of the actual pitch in `unit`. unit: str The unit in which data is measured along axes. Possible types are {'m', 'cm', 'percent'}. color_scheme: str Color scheme of the plot. One of {'standard', 'bw'}. show_axis_ticks: bool If set to True, the axis ticks are visible. ax: matplotlib.axes Axes from matplotlib library on which the football field is plotted. kwargs: Optional keyworded arguments {'linewidth', 'zorder', 'scalex', 'scaley'} which can be used for the plot functions from matplotlib. The kwargs are only passed to all the plot functions of matplotlib. Returns ------- axes : matplotlib.axes Axes from matplotlib library on which a football pitch is plotted. Notes ----- The kwargs are only passed to the plot functions of matplotlib. To customize the plots have a look at `matplotlib <https://matplotlib.org/3.5.0/api/_as_gen/matplotlib.axes.Axes.plot.html>`_. For example in order to modify the linewidth pass a float to the keyworded argument 'linewidth'. The same principle applies to other kwargs like 'zorder', 'scalex' and 'scaley'. .. _football-pitch-label: Examples -------- >>> import matplotlib.pyplot as plt >>> from floodlight.vis.pitches import plot_football_pitch >>> # create matplotlib.axes >>> ax = plt.subplots()[1] >>> # plot handball pitch >>> plot_football_pitch(xlim=(0,108), ylim=(0,68), length=108, width=68, unit='m', >>> color_scheme='standard', show_axis_ticks=False, ax=ax) >>> plt.show() .. image:: ../../_img/pitch_football_example.png """ # kwargs which are used to configure the plot with default values 1 and 0. # all the other kwargs will be just passed to all the plot functions. linewidth = kwargs.pop("linewidth", 1) zorder = kwargs.pop("zorder", 0) # customizing visualization if color_scheme == "bw": ax.set_facecolor("white") # color of the pitch color_contour_lines = "black" else: ax.set_facecolor("green") # color of the pitch color_contour_lines = "white" # Since football pitch sizes can vary while the elements on the pitch # (i.e penalty area) have the same size, the actual elements on the pitch can't # be scaled based on the x- or y-range. # Therefore a norm factor for the x and y direction is needed for every element # on the pitch that has a fixed size. # The norm factor is specified based on the given unit. # If the unit is 'm' or 'cm' the ratio between x and y is set to 1 # (see in the Pitch.plot() method ax.set_aspect(1)) and the norm factos are set # to 1 ('m') or 100 ('cm'). But if the unit is 'percent' the ratio between # width/length is set to ax.set_aspect(width/length). # That means if an element like the goal area, is drawn, it get's rescaled based # on the ratio of width and length. # norm_factor for all elements on the pitch that are scaled in the x direction norm_factor_x = ( 1 if unit == "m" else 100 if unit == "cm" else 100 / length if length else 100 / 105 ) # norm_factor for all elements on the pitch that are scaled in the y direction norm_factor_y = ( 1 if unit == "m" else 100 if unit == "cm" else 100 / width if width else 100 / 68 ) # All the positions and ranges of certain elements on the pitch # (i.e the penalty area) have fixed sizes and are scaled based on the # x and y norm factors. # key positions for the football pitch xmin, xmax = xlim ymin, ymax = ylim x_half = (xmax + xmin) / 2 y_half = (ymax + ymin) / 2 x_radius_points = 0.25 * norm_factor_x * 2 y_radius_points = 0.25 * norm_factor_y * 2 x_goal_height = 2.44 * norm_factor_x y_goal_width = 7.32 * norm_factor_y y_range_center_to_post = y_goal_width / 2 # goal area x_pos_left_side_goal_area_line = xmin + 5.5 * norm_factor_x x_pos_right_side_goal_area_line = xmax - 5.5 * norm_factor_x y_pos_lower_goal_area = y_half - 9.16 * norm_factor_y y_pos_upper_goal_area = y_half + 9.16 * norm_factor_y # goal y_pos_goal_lower_post = y_half - y_range_center_to_post y_pos_goal_upper_post = y_half + y_range_center_to_post # penalty area x_pos_left_side_penalty_area_line = xmin + 16.5 * norm_factor_x y_pos_penalty_area_lower_line = y_half - 20.16 * norm_factor_y y_pos_penalty_area_upper_line = y_half + 20.16 * norm_factor_y x_pos_right_side_penalty_area_line = xmax - 16.5 * norm_factor_x x_pos_left_side_center_penalty_arc = xmin + 11 * norm_factor_x x_pos_right_side_center_penalty_arc = xmax - 11 * norm_factor_x x_pos_left_side_penalty_point = xmin + 11 * norm_factor_x x_pos_right_side_penalty_point = xmax - 11 * norm_factor_x # center circle x_radius_center_circle = 9.15 * norm_factor_x * 2 y_radius_center_circle = 9.15 * norm_factor_y * 2 # angle for the penalty area arc changes when unit is 'percent' angle = 10 if unit == "percent" else 0 # field boundaries ax.plot( [xmin, xmax], [ymin, ymin], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmin, xmax], [ymax, ymax], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmin, xmin], [ymin, ymax], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmax, xmax], [ymin, ymax], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [x_half, x_half], [ymin, ymax], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) # goal area # goal area left ax.plot( [x_pos_left_side_goal_area_line, x_pos_left_side_goal_area_line], [y_pos_lower_goal_area, y_pos_upper_goal_area], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmin, x_pos_left_side_goal_area_line], [y_pos_lower_goal_area, y_pos_lower_goal_area], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmin, x_pos_left_side_goal_area_line], [y_pos_upper_goal_area, y_pos_upper_goal_area], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) # goal area right ax.plot( [x_pos_right_side_goal_area_line, x_pos_right_side_goal_area_line], [y_pos_lower_goal_area, y_pos_upper_goal_area], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmax, x_pos_right_side_goal_area_line], [y_pos_lower_goal_area, y_pos_lower_goal_area], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmax, x_pos_right_side_goal_area_line], [y_pos_upper_goal_area, y_pos_upper_goal_area], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) # penalty area # penalty area left ax.plot( [x_pos_left_side_penalty_area_line, x_pos_left_side_penalty_area_line], [y_pos_penalty_area_lower_line, y_pos_penalty_area_upper_line], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmin, x_pos_left_side_penalty_area_line], [y_pos_penalty_area_lower_line, y_pos_penalty_area_lower_line], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmin, x_pos_left_side_penalty_area_line], [y_pos_penalty_area_upper_line, y_pos_penalty_area_upper_line], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) # penalty area right ax.plot( [ x_pos_right_side_penalty_area_line, x_pos_right_side_penalty_area_line, ], [y_pos_penalty_area_lower_line, y_pos_penalty_area_upper_line], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmax, x_pos_right_side_penalty_area_line], [y_pos_penalty_area_lower_line, y_pos_penalty_area_lower_line], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmax, x_pos_right_side_penalty_area_line], [y_pos_penalty_area_upper_line, y_pos_penalty_area_upper_line], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) # penalty point # left ax.add_patch( Arc( (x_pos_left_side_penalty_point, y_half), width=x_radius_points, height=y_radius_points, angle=0, theta1=0, theta2=360, color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ) # right ax.add_patch( Arc( (x_pos_right_side_penalty_point, y_half), width=x_radius_points, height=y_radius_points, angle=0, theta1=0, theta2=360, color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ) # penalty area circle left ax.add_patch( Arc( (x_pos_left_side_center_penalty_arc, y_half), width=x_radius_center_circle, height=y_radius_center_circle, angle=0, theta1=307.5 - angle, theta2=52.5 + angle, color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ) # penalty area circle right ax.add_patch( Arc( (x_pos_right_side_center_penalty_arc, y_half), width=x_radius_center_circle, height=y_radius_center_circle, angle=0, theta1=127.5 - angle, theta2=232.5 + angle, color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ) # goal # left goal ax.plot( [xmin - x_goal_height, xmin - x_goal_height], [y_pos_goal_lower_post, y_pos_goal_upper_post], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmin - x_goal_height, xmin], [y_pos_goal_upper_post, y_pos_goal_upper_post], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmin - x_goal_height, xmin], [y_pos_goal_lower_post, y_pos_goal_lower_post], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) # right goal ax.plot( [xmax + x_goal_height, xmax + x_goal_height], [y_pos_goal_lower_post, y_pos_goal_upper_post], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmax + x_goal_height, xmax], [y_pos_goal_upper_post, y_pos_goal_upper_post], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ax.plot( [xmax + x_goal_height, xmax], [y_pos_goal_lower_post, y_pos_goal_lower_post], color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) # center circle ax.add_patch( Arc( (x_half, y_half), width=x_radius_center_circle, height=y_radius_center_circle, angle=0, theta1=0, theta2=360, color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ) # center point ax.add_patch( Arc( (x_half, y_half), width=x_radius_points, height=y_radius_points, angle=0, theta1=0, theta2=360, color=color_contour_lines, zorder=zorder, linewidth=linewidth, ) ) # remove labels and ticks if not show_axis_ticks: ax.xaxis.set_major_locator(matplotlib.ticker.NullLocator()) ax.yaxis.set_major_locator(matplotlib.ticker.NullLocator()) return ax