Analytics

This is the analytics module. You can use it to calculate statistics on your parsed demos, such as Rating, ADR, and so on. It also provides awpy-exclusive statistics, like map control.

awpy.analytics.map_control

Functions for calculating map control values and metrics.

A team’s map control can be thought of as the sum of it’s individual player’s control.

Example notebook:

https://github.com/pnxenopoulos/awpy/blob/main/examples/05_Map_Control_Calculations_And_Visualizations.ipynb

awpy.analytics.map_control.calc_frame_map_control_metric(map_name: str, frame: GameFrame) float[source]

Return map control metric for given awpy frame.

Map Control metric is used to quantify how much of the map is controlled by T/CT. Each tile is given a value between 0 (complete T control) and 1 (complete CT control). If a tile is controlled by both teams, a value is found by taking the ratio between the sum of CT values and sum of CT and T values. Once all of the tiles’ values are calculated, a weighted sum is done on the tiles’ values where the tiles’ area is the weights. This weighted sum is the map control metric returned at the end of the function.

Parameters:
  • map_name (str) – Map used position_transform call

  • frame (GameFrame) – awpy frame to calculate map control metric for

Returns:

Map Control metric for given frame

Raises:

ValueError – If map_name is not in awpy.data.NAV

awpy.analytics.map_control.calc_frame_map_control_values(map_name: str, frame: GameFrame) FrameMapControlValues[source]

Calculate tile map control values for each team given awpy frame object.

Values are allocated to tiles depending on how many tiles are between it and the source tile (aka tile distance). The smaller the tile distance, the close the tile’s value is to 1. Tiles are considered until a player’s tiles’ total area reach the area_threshold. The area threshold is a float between 0 and 1, representing the percentage of the current map’s total area.

Parameters:
  • map_name (str) – Map used for find_closest_area and relevant tile neighbor dictionary

  • frame (GameFrame) – Awpy frame object for map control calculations

Returns:

FrameMapControlValues object containing each team’s map control values

Raises:

ValueError – If map_name is not in awpy.data.NAV

awpy.analytics.map_control.calc_parsed_frame_map_control_values(map_name: str, current_player_data: FrameTeamMetadata) FrameMapControlValues[source]

Calculate tile map control values for each team given parsed frame.

Values are allocated to tiles depending on how many tiles are between it and the source tile (aka tile distance). The smaller the tile distance, the close the tile’s value is to 1. Tiles are considered until a player’s tiles’ total area reach the area_threshold. The area threshold is a float between 0 and 1, representing the percentage of the current map’s total area.

Parameters:
  • map_name (str) – Map used for find_closest_area and relevant tile neighbor dictionary

  • current_player_data (FrameTeamMetadata) – Object containing team metadata (player positions, etc.). Expects extract_team_metadata output format

Returns:

FrameMapControlValues object containing each team’s map control values

Raises:

ValueError – If map_name is not in awpy.data.NAV

awpy.analytics.map_control.calculate_round_map_control_metrics(map_name: str, round_data: GameRound) list[float][source]

Return list of map control metric for given awpy round.

Map Control metric is used to quantify how much of the map is controlled by T/CT. Each tile is given a value between 0 (complete T control) and 1 (complete CT control). If a tile is controlled by both teams, a value is found by taking the ratio between the sum of CT values and sum of CT and T values. Once all of the tiles’ values are calculated, a weighted sum is done on the tiles’ values where the tiles’ area is the weights. This weighted sum is the map control metric returned at the end of the function.

Parameters:
  • map_name (str) – Map used position_transform call

  • round_data (GameRound) – awpy round to calculate map control metrics

Returns:

List of map control metric values for given round

Raises:

ValueError – If map_name is not in awpy.data.NAV

awpy.analytics.map_control.extract_teams_metadata(frame: GameFrame) FrameTeamMetadata[source]

Parse frame data for alive player locations for both sides.

Parameters:

frame (GameFrame) – Dictionary in the form of an awpy frame containing relevant data for both sides

Returns:

FrameTeamMetadata containing team metadata (player

positions, etc.)

awpy.analytics.nav

Functions for finding distances between points, areas or states.

Example:

from awpy.analytics.nav import area_distance

geodesic_dist = area_distance(
    map_name="de_dust2", area_a=152, area_b=8970, dist_type="geodesic"
)
f, ax = plot_map(map_name="de_dust2", map_type="simpleradar", dark=True)

for a in NAV["de_dust2"]:
    area = NAV["de_dust2"][a]
    color = "None"
    if a in geodesic_dist["areas"]:
        color = "red"
    width = area["southEastX"] - area["northWestX"]
    height = area["northWestY"] - area["southEastY"]
    southwest_x = area["northWestX"]
    southwest_y = area["southEastY"]
    rect = patches.Rectangle(
        (southwest_x, southwest_y),
        width,
        height,
        linewidth=1,
        edgecolor="yellow",
        facecolor=color,
    )
    ax.add_patch(rect)

https://github.com/pnxenopoulos/awpy/blob/main/examples/03_Working_with_Navigation_Meshes.ipynb

awpy.analytics.nav.area_distance(map_name: str, area_a: int, area_b: int, dist_type: Literal['graph', 'geodesic', 'euclidean'] = 'graph') DistanceObject[source]

Returns the distance between two areas.

Dist type can be [graph, geodesic, euclidean].

Parameters:
  • map_name (string) – Map to consider

  • area_a (TileId) – Source area id

  • area_b (TileId) – Destination area id

  • dist_type (string, optional) – String indicating the type of distance to use (graph, geodesic or euclidean). Defaults to ‘graph’

Returns:

A dict containing info on the path between two areas.

Raises:

ValueError – If map_name is not in awpy.data.NAV If either area_a or area_b is not in awpy.data.NAV[map_name] If the dist_type is not one of [“graph”, “geodesic”, “euclidean”]

awpy.analytics.nav.build_stepped_lower(points: list[tuple[float, float]], min_y: tuple[float, float]) list[tuple[float, float]][source]

Builds towards the lower part of the hull.

Based on starting point and maximum y value.

Parameters:
  • points (list[tuple[float, float]]) – A list of points to build the upper left hull section from

  • min_y (tuple[float, float]) – The point with the lowest y

Returns:

A list of points making up the lower part of the hull

awpy.analytics.nav.build_stepped_upper(points: list[tuple[float, float]], max_y: tuple[float, float]) list[tuple[float, float]][source]

Builds towards the upper part of the hull.

Based on starting point and maximum y value.

Parameters:
  • points (list[tuple[float, float]]) – A list of points to build the upper left hull section from

  • max_y (tuple[float, float]) – The point with the highest y

Returns:

A list of points making up the upper part of the hull

awpy.analytics.nav.calculate_map_area(map_name: str) float[source]

Calculates total area of all nav tiles in a given map.

Parameters:

map_name (string) – Map for area calculations

Returns:

A float representing the area of the map

Raises:

ValueError – If map_name is not in awpy.data.NAV

awpy.analytics.nav.calculate_tile_area(map_name: str, tile_id: int) float[source]

Calculates area of a given tile in a given map.

Parameters:
  • map_name (string) – Map for tile

  • tile_id (TileId) – Id for tile

Returns:

A float representing the area of the tile

Raises:

ValueError – If map_name is not in awpy.data.NAV If area_id is not in awpy.data.NAV[map_name]

awpy.analytics.nav.find_closest_area(map_name: str, point: tuple[float, float, float], *, flat: Literal[False] = False) ClosestArea[source]
awpy.analytics.nav.find_closest_area(map_name: str, point: tuple[float, float], *, flat: Literal[True] = False) ClosestArea

Finds the closest area in the nav mesh.

Searches through all the areas by comparing point to area centerpoint.

Parameters:
  • map_name (string) – Map to search

  • point (tuple) – Point as a tuple (x,y,z) or (x, y)

  • flat (Boolean) – Whether z should be ignored.

Returns:

A dict containing info on the closest area

Raises:

ValueError – If map_name is not in awpy.data.NAV If the length of point is not 3

awpy.analytics.nav.frame_distance(map_name: str, frame1: GameFrame, frame2: GameFrame, distance_type: Literal['graph', 'geodesic', 'euclidean'] = 'geodesic') float[source]

Calculates a distance between two frames based on player positions.

Parameters:
  • map_name (string) – Map to consider

  • frame1 (GameFrame) – A game frame

  • frame2 (GameFrame) – A game frame

  • distance_type (string, optional) – String indicating how the distance between two player positions should be calculated. Options are “geodesic”, “graph” and “euclidean” Defaults to ‘geodesic’

Returns:

A float representing the distance between these two game states

Raises:

ValueError – Raises a ValueError if there is a discrepancy between the frames regarding which sides are filled. If the ct side of frame1 contains players while that of frame2 is empty or None the error will be raised. The same happens for the t sides.

awpy.analytics.nav.generate_area_distance_matrix(map_name: str, *, save: bool = False) dict[str, dict[str, dict[Literal['graph', 'geodesic', 'euclidean'], float]]][source]

Generates or grabs a tree like nested dictionary containing distance matrices.

Structures is [map_name][area1id][area2id][dist_type(euclidean,graph,geodesic)]

Note that this can take 20min to 13h to run depending on the map and produces an output file of 50-600mb. If you run this offline and want to store the result for later reuse make sure to set ‘save=True’!

Parameters:
  • map_name (string) – Map to generate the place matrix for

  • save (bool, optional) – Whether to save the matrix to file Defaults to ‘False’

Returns:

Tree structure containing distances for all area pairs on all maps

Raises:

ValueError – Raises a ValueError if map_name is not in awpy.data.NAV

awpy.analytics.nav.generate_centroids(map_name: str) tuple[dict[str, int], dict[str, int]][source]

For each region in the given map calculates the centroid and a repr. point.

Also finds the closest tile for each.

Parameters:

map_name (string) – Name of the map for which to calculate the centroids

Returns:

Tuple of dictionaries containing the centroid and representative tiles for each region of the map

Raises:

ValueError – If map_name is not in awpy.data.NAV

awpy.analytics.nav.generate_place_distance_matrix(map_name: str, *, save: bool = False) dict[str, dict[str, dict[Literal['graph', 'geodesic', 'euclidean'], dict[Literal['centroid', 'representative_point', 'median_dist'], float]]]][source]

Generates or grabs a tree like nested dictionary containing distance matrices.

Structures is: [map_name][placeid][place2id][dist_type(euclidean,graph,geodesic)] [reference_point(centroid,representative_point,median_dist)]

Parameters:
  • map_name (string) – Map to generate the place matrix for

  • save (bool, optional) – Whether to save the matrix to file. Defaults to ‘False’

Returns:

Tree structure containing distances for all place pairs on all maps

Raises:

ValueError – Raises a ValueError if map_name is not in awpy.data.NAV

awpy.analytics.nav.generate_position_token(map_name: str, frame: GameFrame) Token[source]

Generates the position token for a game frame.

Parameters:
  • map_name (string) – Map to consider

  • frame (dict) – A game frame

Returns:

A dict containing the T token, CT token and combined token (T + CT concatenated)

Raises:

ValueError – If map_name is not in awpy.data.NAV If either side (“ct” or “t”) in the frame has no players

awpy.analytics.nav.get_array_for_frame(frame: GameFrame) ndarray[Any, dtype[_ScalarType_co]][source]

Generates a numpy array with the correct dimensions and content for a gameframe.

Parameters:

frame (GameFrame) – A game frame

Returns:

numpy array for that frame

awpy.analytics.nav.point_distance(map_name: str, point_a: tuple[float, float, float], point_b: tuple[float, float, float], dist_type: Literal['graph', 'geodesic', 'euclidean', 'manhattan', 'canberra', 'cosine'] = 'graph') DistanceObject[source]

Returns the distance between two points.

Parameters:
  • map_name (string) – Map to consider

  • point_a (list) – Point as a list (x,y,z)

  • point_b (list) – Point as a list (x,y,z)

  • dist_type (string, optional) – String indicating the type of distance to use. Can be graph, geodesic, euclidean, manhattan, canberra or cosine. Defaults to ‘graph’

Returns:

A dict containing info on the distance between two points.

Raises:

ValueError – If map_name is not in awpy.data.NAV: if dist_type is “graph” or “geodesic” If either point_a or point_b does not have a length of 3 (for “graph” or “geodesic” dist_type)

awpy.analytics.nav.point_in_area(map_name: str, area_id: int, point: tuple[float, float, float]) bool[source]

Returns if the point is within a nav area for a map.

Parameters:
  • map_name (string) – Map to consider

  • area_id (TileId) – Area ID as an integer

  • point (list) – Point as a list [x,y,z]

Returns:

True if area contains the point, false if not

Raises:

ValueError – If map_name is not in awpy.data.NAV If area_id is not in awpy.data.NAV[map_name] If the length of point is not 3

awpy.analytics.nav.position_state_distance(map_name: str, position_array_1: ndarray[Any, dtype[_ScalarType_co]], position_array_2: ndarray[Any, dtype[_ScalarType_co]], distance_type: Literal['graph', 'geodesic', 'euclidean'] = 'geodesic') float[source]

Calculates a distance between two game states based on player positions.

Parameters:
  • map_name (string) – Map to consider

  • position_array_1 (numpy array) – Numpy array with shape (2|1, 5, 3) with the first index indicating the team, the second the player and the third the coordinate. Alternatively the array can have shape (2|1, 5, 1) where the last value gives the area_id. Used only with geodesic and graph distance

  • position_array_2 (numpy array) – Numpy array with shape (2|1, 5, 3) with the first index indicating the team, the second the playe and the third the coordinate. Alternatively the array can have shape (2|1, 5, 1) where the last value gives the area_id. Used only with geodesic and graph distance

  • distance_type (string, optional) – String indicating how the distance between two player positions should be calculated. Options are “geodesic”, “graph” and “euclidean”. Defaults to ‘geodesic’

Returns:

A float representing the distance between these two game states

Raises:
  • ValueError – If map_name is not in awpy.data.NAV.

  • ValueError – If distance_type is not one of [“graph”, “geodesic”, “euclidean”].

  • ValueError – If the 0th (number of teams) and 2nd (number of features) dimensions of the inputs do not have the same size.

  • ValueError – If number of features is not 3 for euclidean distance_type

awpy.analytics.nav.stepped_hull(points: list[tuple[float, float]]) list[tuple[float, float]][source]

Produces an approximation of the orthogonal convex hull.

Parameters:

points (list) – A list of points given as tuples (x, y)

Returns:

A list of points making up the hull or four lists of points making up the four quadrants of the hull

awpy.analytics.nav.token_distance(map_name: str, token1: str, token2: str, distance_type: Literal['graph', 'geodesic', 'euclidean', 'edit_distance'] = 'geodesic', reference_point: Literal['centroid', 'representative_point'] = 'centroid') float[source]

Calculates a distance between two game states based on position tokens.

Parameters:
  • map_name (string) – Map to consider

  • token1 (string) – A team position token

  • token2 (string) – A team position token

  • distance_type (string, optional) – String indicating how the distance between two player positions should be calculated. Options are “geodesic”, “graph”, “euclidean” and “edit_distance”. Defaults to ‘geodesic’

  • reference_point (string, optional) – String indicating which reference point to use to determine area distance. Options are “centroid” and “representative_point”. Defaults to ‘centroid’

Returns:

A float representing the distance between these two game states

awpy.analytics.nav.token_state_distance(map_name: str, token_array_1: ndarray[Any, dtype[int64]], token_array_2: ndarray[Any, dtype[int64]], distance_type: Literal['graph', 'geodesic', 'euclidean', 'edit_distance'] = 'geodesic', reference_point: Literal['centroid', 'representative_point'] = 'centroid') float[source]

Calculates a distance between two game states based on player positions.

Parameters:
  • map_name (string) – Map to consider

  • token_array_1 (numpy array) – 1-D numpy array of a position token

  • token_array_2 (numpy array) – 1-D numpy array of a position token

  • distance_type (string, optional) – String indicating how the distance between two player positions should be calculated. Options are “geodesic”, “graph”, “euclidean” and “edit_distance”. Defaults to ‘geodesic’

  • reference_point (string, optional) – String indicating which reference point to use to determine area distance. Options are “centroid” and “representative_point”. Defaults to ‘centroid’

Returns:

A float representing the distance between these two game states

Raises:
  • ValueError – If map_name is not in awpy.data.NAV.

  • ValueError – If distance_type is not one of: [“graph”, “geodesic”, “euclidean”, “edit_distance”]

  • ValueError – If reference_point is not one of: [“centroid”, “representative_point”]

  • ValueError – If the input token arrays do not have the same length.

  • ValueError – If the length of the token arrays do not match the expected length for that map.

awpy.analytics.nav.tree() dict[source]

Builds tree data structure from nested defaultdicts.

Parameters:

None

Returns:

An empty tree

awpy.analytics.states

Functions to generate game stats based on snapshots from a demofile.

awpy.analytics.states.generate_graph_state(frame: GameFrame) dict[source]

Returns a game state as a graph.

Parameters:

frame (GameFrame) – Dict output of a frame generated from the DemoParser class

Returns:

A dict with keys “T”, “CT” and “Global”, where each entry is a vector. Global vector is CT + T concatenated

awpy.analytics.states.generate_set_state(frame: GameFrame) dict[source]

Returns a game state as a set.

Parameters:

frame (GameFrame) – Dict output of a frame generated from the DemoParser class

Returns:

A dict with keys “T”, “CT” and “Global”, where each entry is a vector. Global vector is CT + T concatenated

awpy.analytics.states.generate_vector_state(frame: GameFrame, map_name: str) dict[source]

Returns a game state in a dictionary format.

Parameters:
  • frame (GameFrame) – Dict output of a frame generated from the DemoParser class

  • map_name (string) – String indicating the map name

Returns:

A dict with keys for each feature.

awpy.analytics.stats

Functions to calculate statistics for a player or team from a demofile.

Example:

from awpy.parser import DemoParser
from awpy.analytics.stats import player_stats

# Create the parser object.
parser = DemoParser(
    demofile = "astralis-vs-liquid-m2-nuke.dem",
    demo_id = "AST-TL-BLAST2019-nuke",
    parse_frames=False,
)

# Parse the demofile, output results to a dictionary of dataframes.
data = parser.parse()
player_stats_json = player_stats(data["gameRounds"])
player_stats_json[76561197999004010]

https://github.com/pnxenopoulos/awpy/blob/main/examples/01_Basic_CSGO_Analysis.ipynb

awpy.analytics.stats.initialize_round(cur_round: GameRound, player_statistics: dict[str, awpy.types.PlayerStatistics], active_sides: set[Literal['CT', 'T']]) RoundStatistics[source]

Initialize players and statistics for the given round.

Parameters:
  • cur_round (GameRound) – Current CSGO round to initialize for.

  • player_statistics (dict[str, PlayerStatistics]) – Dict storing player statistics for a given match.

  • active_sides (set[Literal["CT", "T"]]) – Set of the currently active sides.

Returns:

Initialized KAST dict for each player. dict[str, int]: Number of kills in the round for each player. set[str]]: Players to track for the given round.

Return type:

dict[str, KAST]

awpy.analytics.stats.player_stats(game_rounds: list[awpy.types.GameRound], return_type: str = 'json', selected_side: str = 'all') dict[str, awpy.types.PlayerStatistics] | DataFrame[source]

Generate a stats summary for a list of game rounds as produced by the DemoParser.

Parameters:
  • game_rounds (list[GameRound]) – List of game rounds as produced by the DemoParser

  • return_type (str, optional) – Return format (“json” or “df”). Defaults to “json”.

  • selected_side (str, optional) – Which side(s) to consider. Defaults to “all”. Other options are “CT” and “T”

Returns:

Dictionary or Dataframe containing player information

Return type:

Union[dict[str, PlayerStatistics],pd.Dataframe]

awpy.analytics.wpa

Will provide functionality for WPA and win probabilities.

WPA stands for Win Probability Added and is described in this paper: https://arxiv.org/pdf/2011.01324.pdf.

awpy.analytics.wpa.round_win_probability(ct_score: int, t_score: int, map_name: str) dict[source]

Estimates of game win probability using information from the HLTV win matrix.

Parameters:
  • ct_score (int) – CT Score

  • t_score (int) – T Score

  • map_name (str) – Map the demo is from

Returns:

A dictionary containing the CT game win, T game win and Draw probabilities

awpy.analytics.wpa.state_win_probability(frame: GameFrame, model: Any) dict[source]

Predicts the win probability of a given frame.

Parameters:
  • frame (dict) – Dict output of a frame generated from the DemoParser class

  • model (Unknown) – Model to predict win probabability from.

Returns:

A dictionary containing the CT and T round win probabilities