예제 #1
0
def lower_defensive_box_mark(full_surf = True, rotate = False,
                             rotation_dir = 'ccw'):
    """
    Generate the dataframe for the points that comprise the bounding box of the
    lower defensive box tick marks as in the court diagram on page 8 of the NBA
    rule book
    
    Parameters
    ----------
    full_surf: a bool indicating whether or not this feature is needed for a
        full-surface representation
    rotate: a bool indicating whether or not this feature needs to be rotated
    rotation_dir: a string indicating which direction to rotate the feature
    
    Returns
    -------
    lower_defensive_box_mark_dict: a dictionary with the two hash marks that
        comprise the lower defensive box hash marks
    """
    
    # The defensive hash marks are 13' (interior) from the end line, is 2"
    # wide, and 6" long
    lower_defensive_box_mark_1 = create.rectangle(
        x_min = -34, x_max = -34 + (2/12),
        y_min = -5, y_max = -4.5
    )
    
    lower_defensive_box_mark_2 = create.rectangle(
        x_min = -34, x_max = -34 + (2/12),
        y_min = 4.5, y_max = 5
    )
    
    # Reflect the x coordinates over the y axis
    if full_surf:
        lower_defensive_box_mark_1 = lower_defensive_box_mark_1.append(
            transform.reflect(lower_defensive_box_mark_1, over_y = True)
        )
        
        lower_defensive_box_mark_2 = lower_defensive_box_mark_2.append(
            transform.reflect(lower_defensive_box_mark_2, over_y = True)
        )
    
    # Rotate the coordinates if necessary
    if rotate:
        lower_defensive_box_mark_1 = transform.rotate(
            lower_defensive_box_mark_1,
            rotation_dir
        )
        
        lower_defensive_box_mark_2 = transform.rotate(
            lower_defensive_box_mark_2,
            rotation_dir
        )
        
    lower_defensive_box_mark_dict = {
        'lower_defensive_box_mark_1': lower_defensive_box_mark_1,
        'lower_defensive_box_mark_2': lower_defensive_box_mark_2
    }
    
    return lower_defensive_box_mark_dict
예제 #2
0
def blue_line(full_surf=True, rotate=False, rotation_dir='ccw'):
    """
    Generate the dataframe for the points that comprise the blue line as
    specified in Rule 1.7 of the NHL rule book
    
    Parameters
    ----------
    full_surf: a bool indicating whether or not this feature is needed for a
        full-surface representation
    rotate: a bool indicating whether or not this feature needs to be rotated
    rotation_dir: a string indicating which direction to rotate the feature
    
    Returns
    -------
    blue_line: a pandas dataframe of coordinates needed to plot the blue line
    """
    # The blue line is a 12" wide line that's 25' (interior) from the center
    # line. It spans the width of the playing surface
    blue_line = create.rectangle(x_min=-26, x_max=-25, y_min=-42.5, y_max=42.5)

    # Reflect the x coordinates over the y axis
    if full_surf:
        blue_line = blue_line.append(transform.reflect(blue_line, over_y=True))

    # Rotate the coordinates if necessary
    if rotate:
        blue_line = transform.rotate(blue_line, rotation_dir)

    return blue_line
예제 #3
0
def backboard(full_surf=True, rotate=False, rotation_dir='ccw'):
    """
    Generate the dataframe for the points that comprise the backboard as
    specified in the court diagram of the WNBA rule book

    Returns
    -------
    backboard: a pandas dataframe of the backboard
    """
    # Per the rule book, the backboard must by 6' wide. The height of the
    # backboard is irrelevant in this graphic, as this is a bird's eye view
    # over the court
    backboard = create.rectangle(x_min=-43 - (4 / 12),
                                 x_max=-43,
                                 y_min=-3,
                                 y_max=3)

    # Reflect the x coordinates over the y axis
    if full_surf:
        backboard = backboard.append(transform.reflect(backboard, over_y=True))

    # Rotate the coordinates if necessary
    if rotate:
        backboard = transform.rotate(backboard, rotation_dir)

    return backboard
예제 #4
0
def painted_area(full_surf=True, rotate=False, rotation_dir='ccw'):
    """
    Generate the dataframe for the points that comprise the bounding box of the
    free throw lane as specified in the court diagram of the WNBA rule book
    
    Parameters
    ----------
    full_surf: a bool indicating whether or not this feature is needed for a
        full-surface representation
    rotate: a bool indicating whether or not this feature needs to be rotated
    rotation_dir: a string indicating which direction to rotate the feature
    
    Returns
    -------
    painted_areas: a pandas dataframe of the painted areas
    """
    # The interior of the free throw lane is known as the painted area, and
    # can be a different color than the markings and court. These coordinates
    # can be used to color them on the plot
    painted_area = create.rectangle(x_min=-47,
                                    x_max=-28 - (2 / 12),
                                    y_min=-8 + (2 / 12),
                                    y_max=8 - (2 / 12))

    # Reflect the x coordinates over the y axis
    if full_surf:
        painted_area = painted_area.append(
            transform.reflect(painted_area, over_y=True))

    # Rotate the coordinates if necessary
    if rotate:
        painted_area = transform.rotate(painted_area, rotation_dir)

    return painted_area
예제 #5
0
def division_line(full_surf=True, rotate=False, rotation_dir='ccw'):
    """
    Generate the dataframe for the points that comprise the bounding box of
    the division line as in the court diagram on page 8 of the WNBA rule book
    
    Parameters
    ----------
    full_surf: a bool indicating whether or not this feature is needed for a
        full-surface representation
    rotate: a bool indicating whether or not this feature needs to be rotated
    rotation_dir: a string indicating which direction to rotate the feature
    
    Returns
    -------
    division_line: A pandas dataframe of the division line on the court
    """
    # The line's center should be 47' from the interior side of the baselines,
    # and must be 2" thick
    division_line = create.rectangle(x_min=-1 / 12,
                                     x_max=0,
                                     y_min=-25,
                                     y_max=25)

    # Reflect the x coordinates over the y axis
    if full_surf:
        division_line = division_line.append(
            transform.reflect(division_line, over_y=True))

    # Rotate the coordinates if necessary
    if rotate:
        division_line = transform.rotate(division_line, rotation_dir)

    return division_line
예제 #6
0
def try_line(full_surf=True, rotate=False, rotation_dir='ccw'):
    """
    Generate the dataframe for the points that comprise the bounding box of the
    try line as specified in the field diagram of the NCAA rule book (Appendix
    D)
    
    Parameters
    ----------
    full_surf: a bool indicating whether or not this feature is needed for a
        full-surface representation
    rotate: a bool indicating whether or not this feature needs to be rotated
    rotation_dir: a string indicating which direction to rotate the feature

    Returns
    -------
    try_line: a pandas dataframe of the goal line
    """
    try_line = create.rectangle(x_min=-141 - (2 / 12),
                                x_max=-141 + (2 / 12),
                                y_min=-1,
                                y_max=1)

    # Reflect the x coordinates over the y axis
    if full_surf:
        try_line = try_line.append(transform.reflect(try_line, over_y=True))

    # Rotate the coordinates if necessary
    if rotate:
        try_line = transform.rotate(try_line, rotation_dir)

    return try_line
예제 #7
0
def goal_line(full_surf=True, rotate=False, rotation_dir='ccw'):
    """
    Generate the dataframe for the points that comprise the bounding box of the
    goal line as specified in the field diagram of the NCAA rule book(Appendix
    D)
    
    Parameters
    ----------
    full_surf: a bool indicating whether or not this feature is needed for a
        full-surface representation
    rotate: a bool indicating whether or not this feature needs to be rotated
    rotation_dir: a string indicating which direction to rotate the feature

    Returns
    -------
    goal_line: a pandas dataframe of the goal line
    """
    # The interior measurement between goal lines is 100 yards, or 300'. So,
    # taking the center of the field to be (0, 0), each goal line must be 150'
    # away from this point. Goal lines have thickness of 8", extending back
    # into the endzone, and extend across the width of the field (which totals
    # 160' across)
    goal_line = create.rectangle(x_min=-150 - (8 / 12),
                                 x_max=-150,
                                 y_min=-80,
                                 y_max=80)

    # Reflect the x coordinates over the y axis
    if full_surf:
        goal_line = goal_line.append(transform.reflect(goal_line, over_y=True))

    # Rotate the coordinates if necessary
    if rotate:
        goal_line = transform.rotate(goal_line, rotation_dir)

    return goal_line
예제 #8
0
def blocks(full_surf=True,
           rotate=False,
           rotation_dir='ccw',
           include_amateur=False):
    """
    Generate the dataframes for the points that comprise the blocks as
    specified in page 8 of the WNBA rule book
    
    Parameters
    ----------
    full_surf: a bool indicating whether or not this feature is needed for a
        full-surface representation
    rotate: a bool indicating whether or not this feature needs to be rotated
    rotation_dir: a string indicating which direction to rotate the feature

    Returns
    -------
    blocks_dict: a dictionary with the block numbers as keys and the dataframes
        to use for plotting as values
    """
    # The first block is 7' (interior) from the endline, and is 2" thick
    professional_block_1 = create.rectangle(x_min=-40,
                                            x_max=-40 + (2 / 12),
                                            y_min=-8.5,
                                            y_max=-8)

    # The second block is 8" (interior) from the first block, and is 2" thick
    professional_block_2 = create.rectangle(x_min=-40 + (10 / 12),
                                            x_max=-39,
                                            y_min=-8.5,
                                            y_max=-8)

    # The third block is 3' (interior) from the second block, and is 2" thick
    professional_block_3 = create.rectangle(x_min=-36,
                                            x_max=-36 + (2 / 12),
                                            y_min=-8.5,
                                            y_max=-8)

    # The fourth block is 3' (interior) from the third block, and is 2" thick
    professional_block_4 = create.rectangle(x_min=-33 + (2 / 12),
                                            x_max=-33 + (4 / 12),
                                            y_min=-8.5,
                                            y_max=-8)

    # Block 1 but on the other side of the free-throw lane
    professional_block_5 = create.rectangle(x_min=-40,
                                            x_max=-40 + (2 / 12),
                                            y_min=8.5,
                                            y_max=8)

    # Block 2 but on the other side of the free-throw lane
    professional_block_6 = create.rectangle(x_min=-40 + (10 / 12),
                                            x_max=-39,
                                            y_min=8.5,
                                            y_max=8)

    # Block 3 but on the other side of the free-throw lane
    professional_block_7 = create.rectangle(x_min=-36,
                                            x_max=-36 + (2 / 12),
                                            y_min=8.5,
                                            y_max=8)

    # Block 4 but on the other side of the free-throw lane
    professional_block_8 = create.rectangle(x_min=-33 + (2 / 12),
                                            x_max=-33 + (4 / 12),
                                            y_min=8.5,
                                            y_max=8)

    # Reflect the x coordinates over the y axis
    if full_surf:
        professional_block_1 = professional_block_1.append(
            transform.reflect(professional_block_1, over_y=True))

        professional_block_2 = professional_block_2.append(
            transform.reflect(professional_block_2, over_y=True))

        professional_block_3 = professional_block_3.append(
            transform.reflect(professional_block_3, over_y=True))

        professional_block_4 = professional_block_4.append(
            transform.reflect(professional_block_4, over_y=True))

        professional_block_5 = professional_block_5.append(
            transform.reflect(professional_block_5, over_y=True))

        professional_block_6 = professional_block_6.append(
            transform.reflect(professional_block_6, over_y=True))

        professional_block_7 = professional_block_7.append(
            transform.reflect(professional_block_7, over_y=True))

        professional_block_8 = professional_block_8.append(
            transform.reflect(professional_block_8, over_y=True))

    # Rotate the coordinates if necessary
    if rotate:
        professional_block_1 = transform.rotate(professional_block_1,
                                                rotation_dir)

        professional_block_2 = transform.rotate(professional_block_2,
                                                rotation_dir)

        professional_block_3 = transform.rotate(professional_block_3,
                                                rotation_dir)

        professional_block_4 = transform.rotate(professional_block_4,
                                                rotation_dir)

        professional_block_5 = transform.rotate(professional_block_5,
                                                rotation_dir)

        professional_block_6 = transform.rotate(professional_block_6,
                                                rotation_dir)

        professional_block_7 = transform.rotate(professional_block_7,
                                                rotation_dir)

        professional_block_8 = transform.rotate(professional_block_8,
                                                rotation_dir)

    blocks_dict = {
        'professional_block_1': professional_block_1,
        'professional_block_2': professional_block_2,
        'professional_block_3': professional_block_3,
        'professional_block_4': professional_block_4,
        'professional_block_5': professional_block_5,
        'professional_block_6': professional_block_6,
        'professional_block_7': professional_block_7,
        'professional_block_8': professional_block_8,
    }

    if include_amateur:
        # The first set of blocks are 7' from the interior of the baseline, and
        # measure 1' in width
        amateur_block_1 = create.rectangle(x_min=-40,
                                           x_max=-39,
                                           y_min=-6 - (8 / 12),
                                           y_max=-6)

        # The second set of blocks are 3' from the first block, and measure 2"
        # in width
        amateur_block_2 = create.rectangle(x_min=-36,
                                           x_max=-36 + (2 / 12),
                                           y_min=-6 - (8 / 12),
                                           y_max=-6)

        # The third set of blocks are 3' from the second block, and measure 2"
        # in width
        amateur_block_3 = create.rectangle(x_min=-33 + (2 / 12),
                                           x_max=-33 + (4 / 12),
                                           y_min=-6 - (8 / 12),
                                           y_max=-6)

        # The fourth set of blocks are 3' from the third block, and measure 2"
        # in width
        amateur_block_4 = create.rectangle(x_min=-30 + (4 / 12),
                                           x_max=-30 + (6 / 12),
                                           y_min=-6 - (8 / 12),
                                           y_max=-6)

        # Block 1 but on the other side of the free-throw lane
        amateur_block_5 = create.rectangle(x_min=-40,
                                           x_max=-39,
                                           y_min=6,
                                           y_max=6 + (8 / 12))

        # Block 2 but on the other side of the free-throw lane
        amateur_block_6 = create.rectangle(x_min=-36,
                                           x_max=-36 + (2 / 12),
                                           y_min=6,
                                           y_max=6 + (8 / 12))

        # Block 3 but on the other side of the free-throw lane
        amateur_block_7 = create.rectangle(x_min=-33 + (2 / 12),
                                           x_max=-33 + (4 / 12),
                                           y_min=6,
                                           y_max=6 + (8 / 12))

        # Block 4 but on the other side of the free-throw lane
        amateur_block_8 = create.rectangle(x_min=-30 + (4 / 12),
                                           x_max=-30 + (6 / 12),
                                           y_min=6,
                                           y_max=6 + (8 / 12))

        # Reflect the x coordinates over the y axis
        if full_surf:
            amateur_block_1 = amateur_block_1.append(
                transform.reflect(amateur_block_1, over_y=True))

            amateur_block_2 = amateur_block_2.append(
                transform.reflect(amateur_block_2, over_y=True))

            amateur_block_3 = amateur_block_3.append(
                transform.reflect(amateur_block_3, over_y=True))

            amateur_block_4 = amateur_block_4.append(
                transform.reflect(amateur_block_4, over_y=True))

            amateur_block_5 = amateur_block_5.append(
                transform.reflect(amateur_block_5, over_y=True))

            amateur_block_6 = amateur_block_6.append(
                transform.reflect(amateur_block_6, over_y=True))

            amateur_block_7 = amateur_block_7.append(
                transform.reflect(amateur_block_7, over_y=True))

            amateur_block_8 = amateur_block_8.append(
                transform.reflect(amateur_block_8, over_y=True))

        # Rotate the coordinates if necessary
        if rotate:
            amateur_block_1 = transform.rotate(amateur_block_1, rotation_dir)

            amateur_block_2 = transform.rotate(amateur_block_2, rotation_dir)

            amateur_block_3 = transform.rotate(amateur_block_3, rotation_dir)

            amateur_block_4 = transform.rotate(amateur_block_4, rotation_dir)

            amateur_block_5 = transform.rotate(amateur_block_5, rotation_dir)

            amateur_block_6 = transform.rotate(amateur_block_6, rotation_dir)

            amateur_block_7 = transform.rotate(amateur_block_7, rotation_dir)

            amateur_block_8 = transform.rotate(amateur_block_8, rotation_dir)

        blocks_dict['amateur_block_1'] = amateur_block_1
        blocks_dict['amateur_block_2'] = amateur_block_2
        blocks_dict['amateur_block_3'] = amateur_block_3
        blocks_dict['amateur_block_4'] = amateur_block_4
        blocks_dict['amateur_block_5'] = amateur_block_5
        blocks_dict['amateur_block_6'] = amateur_block_6
        blocks_dict['amateur_block_7'] = amateur_block_7
        blocks_dict['amateur_block_8'] = amateur_block_8

    return blocks_dict
예제 #9
0
def yard_markings(full_surf=True, rotate=False, rotation_dir='ccw'):
    """
    Generate the dataframe for the points that comprise the bounding box of the
    line markings at 5-yard intervals as specified in the field diagram of the
    NCAA rule book (Appendix D)
    
    Parameters
    ----------
    full_surf: a bool indicating whether or not this feature is needed for a
        full-surface representation
    rotate: a bool indicating whether or not this feature needs to be rotated
    rotation_dir: a string indicating which direction to rotate the feature

    Returns
    -------
    yard_line_dict: a dictionary of the lines of the field, and the coordinates
        required to plot them
    """
    # The lines are to be placed 8" from the interior of the sidelines, and be
    # 4" thick. At 5-yard intervals across the field, the lines should stretch
    # the width of the field, with a 2' long by 4" wide hash 60' from the
    # interior of each boundary. At 1-yard intervals between these markings at
    # 5-yard intervals, a 2' tall by 4" wide marker should be placed 4" from
    # the interior of the sideline as well as 60' from the interior of the
    # sideline (and extending back towards the sideline). The field is being
    # constructed from left to right, and the right-side lines can be computed
    # via reflection, so only the left-side points and half the 50 yard line
    # are needed
    yardages = np.arange(-49, 1)

    yard_line_dict = dict()

    for yardage in yardages:
        if yardage == 0:
            # This is the 50 yard line. Only half the line is needed, since the
            # other half will be created via reflection
            yard_line = pd.DataFrame({
                'x': [
                    # Start 4" from the sideline
                    (3 * yardage) - (2 / 12),

                    # Lower inbound line marker
                    (3 * yardage) - (2 / 12),
                    (3 * yardage) - (2 / 12) - (10 / 12),
                    (3 * yardage) - (2 / 12) - (10 / 12),
                    (3 * yardage) - (2 / 12),

                    # Upper inbound line marker
                    (3 * yardage) - (2 / 12),
                    (3 * yardage) - (2 / 12) - (10 / 12),
                    (3 * yardage) - (2 / 12) - (10 / 12),
                    (3 * yardage) - (2 / 12),

                    # Top
                    (3 * yardage) - (2 / 12),

                    # Crossover
                    0,

                    # Return to bottom
                    0,

                    # Return to start
                    (3 * yardage) - (2 / 12)
                ],
                'y': [
                    # Start 4" from the sideline
                    -80 + (4 / 12),

                    # Lower inbound line marker
                    -20,
                    -20,
                    -20 + (4 / 12),
                    -20 + (4 / 12),

                    # Upper inbound line marker
                    20 - (4 / 12),
                    20 - (4 / 12),
                    20,
                    20,

                    # Top
                    80 - (8 / 12),

                    # Crossover
                    80 - (8 / 12),

                    # Return to bottom
                    -80 + (4 / 12),

                    # Return to start
                    -80 + (4 / 12),
                ]
            })

            yard_line_dict[f'yard_line_{50 + yardage}'] = yard_line

        elif yardage % 5 == 0:
            # At 5-yard intervals, the line should stretch the width of the
            # field, with the inbound line marker 60 from the interior of
            # the sideline boundary
            yard_line = pd.DataFrame({
                'x': [
                    # Start 4" from the sideline
                    (3 * yardage) - (2 / 12),

                    # Lower inbound line marker
                    (3 * yardage) - (2 / 12),
                    (3 * yardage) - (2 / 12) - (10 / 12),
                    (3 * yardage) - (2 / 12) - (10 / 12),
                    (3 * yardage) - (2 / 12),

                    # Upper inbound line marker
                    (3 * yardage) - (2 / 12),
                    (3 * yardage) - (2 / 12) - (10 / 12),
                    (3 * yardage) - (2 / 12) - (10 / 12),
                    (3 * yardage) - (2 / 12),

                    # Top
                    (3 * yardage) - (2 / 12),

                    # Crossover
                    (3 * yardage) + (2 / 12),

                    # Upper inbound line marker
                    (3 * yardage) + (2 / 12),
                    (3 * yardage) + (2 / 12) + (10 / 12),
                    (3 * yardage) + (2 / 12) + (10 / 12),
                    (3 * yardage) + (2 / 12),

                    # Lower inbound line marker
                    (3 * yardage) + (2 / 12),
                    (3 * yardage) + (2 / 12) + (10 / 12),
                    (3 * yardage) + (2 / 12) + (10 / 12),
                    (3 * yardage) + (2 / 12),

                    # Return to bottom
                    (3 * yardage) + (2 / 12),

                    # Return to start
                    (3 * yardage) - (2 / 12)
                ],
                'y': [
                    # Start 4" from the sideline
                    -80 + (4 / 12),

                    # Lower inbound line marker
                    -20,
                    -20,
                    -20 + (4 / 12),
                    -20 + (4 / 12),

                    # Upper inbound line marker
                    20 - (4 / 12),
                    20 - (4 / 12),
                    20,
                    20,

                    # Top
                    80 - (8 / 12),

                    # Crossover
                    80 - (8 / 12),

                    # Upper inbound line marker
                    20,
                    20,
                    20 - (4 / 12),
                    20 - (4 / 12),

                    # Lower inbound line marker
                    -20 + (4 / 12),
                    -20 + (4 / 12),
                    -20,
                    -20,

                    # Return to bottom
                    -80 + (8 / 12),

                    # Return to start
                    -80 + (4 / 12),
                ]
            })

            yard_line_dict[f'yard_line_{50 + yardage}'] = yard_line

        else:
            # At 1-yard intervals, the line should be 2' long. The line should
            # appear at the bottom (b) and top (t) of the field inside the 6'
            # wide boundary, and also appear at 70'9" from the nearest boundary
            # and extending from this point towards that boundary (l and u)
            yard_line_b = create.rectangle(x_min=(3 * yardage) - (2 / 12),
                                           x_max=(3 * yardage) + (2 / 12),
                                           y_min=-80 + (4 / 12),
                                           y_max=-78 + (4 / 12))

            yard_line_t = transform.reflect(yard_line_b,
                                            over_x=True,
                                            over_y=False)

            yard_line_l = create.rectangle(x_min=(3 * yardage) - (2 / 12),
                                           x_max=(3 * yardage) + (2 / 12),
                                           y_min=-22,
                                           y_max=-20)

            yard_line_u = transform.reflect(yard_line_l,
                                            over_x=True,
                                            over_y=False)

            yard_line_dict[f'yard_line_{50 + yardage}_b'] = yard_line_b
            yard_line_dict[f'yard_line_{50 + yardage}_t'] = yard_line_t
            yard_line_dict[f'yard_line_{50 + yardage}_l'] = yard_line_l
            yard_line_dict[f'yard_line_{50 + yardage}_u'] = yard_line_u

    # Reflect the x coordinates over the y axis
    if full_surf:
        for yard_line_no, yard_line_coords in yard_line_dict.items():
            yard_line_dict[yard_line_no] = pd.concat([
                yard_line_coords,
                pd.DataFrame({
                    'x': -1 * yard_line_coords['x'],
                    'y': yard_line_coords['y']
                })
            ])

    # Rotate the coordinates if necessary
    if rotate:
        for yard_line_no, yard_line_coords in yard_line_dict.items():
            yard_line_dict[yard_line_no] = transform.rotate(
                yard_line_coords, rotation_dir)

    return yard_line_dict