Spaces:
Sleeping
Sleeping
from mplsoccer import Pitch | |
import streamlit as st | |
import requests | |
from bs4 import BeautifulSoup | |
from fuzzywuzzy import fuzz, process | |
import plotly.express as px | |
import numpy as np | |
import matplotlib.pyplot as plt | |
import streamlit as st | |
def display_player_names_and_positions_middlePitch(home_lineups, away_lineups, position_id_to_coordinates_home, position_id_to_coordinates_away): | |
# Dictionaries to store coordinates and player names for both home and away teams | |
coordinates_dict_home = {} | |
player_names_dict_home = {} | |
coordinates_dict_away = {} | |
player_names_dict_away = {} | |
# Process home team lineup | |
for index, row in home_lineups.iterrows(): | |
player_name = row['player_name'] | |
position_info = row['positions'][0] if row['positions'] else {} | |
position_id = position_info.get('position_id', 'Unknown') | |
if position_id in position_id_to_coordinates_home: | |
coordinates_dict_home[position_id] = position_id_to_coordinates_home[position_id] | |
player_names_dict_home[position_id] = player_name | |
# Process away team lineup | |
for index, row in away_lineups.iterrows(): | |
player_name = row['player_name'] | |
position_info = row['positions'][0] if row['positions'] else {} | |
position_id = position_info.get('position_id', 'Unknown') | |
if position_id in position_id_to_coordinates_away: | |
coordinates_dict_away[position_id] = position_id_to_coordinates_away[position_id] | |
player_names_dict_away[position_id] = player_name | |
# Plotting the pitch | |
pitch = Pitch( | |
# pitch_color='#1f77b4', | |
pitch_color='#d2d2d2', | |
line_color='white', | |
stripe=False, | |
pitch_type='statsbomb' | |
) | |
fig, ax = pitch.draw() | |
# Plotting home team positions | |
if coordinates_dict_home: | |
x_coords_home, y_coords_home = zip(*coordinates_dict_home.values()) | |
ax.scatter(x_coords_home, y_coords_home, color='red', s=300, edgecolors='white', zorder=3) | |
for position_id, (x, y) in coordinates_dict_home.items(): | |
name = player_names_dict_home.get(position_id, "Unknown") | |
ax.text(x, y - 4, f'{name.split()[-1]}', color='black', ha='center', va='center', fontsize=12, zorder=6) | |
# Plotting away team positions | |
if coordinates_dict_away: | |
x_coords_away, y_coords_away = zip(*coordinates_dict_away.values()) | |
ax.scatter(x_coords_away, y_coords_away, color='blue', s=300, edgecolors='white', zorder=3) | |
for position_id, (x, y) in coordinates_dict_away.items(): | |
name = player_names_dict_away.get(position_id, "Unknown") | |
ax.text(x, y - 4, f'{name.split()[-1]}', color='black', ha='center', va='center', fontsize=12, zorder=6) | |
# Display the plot in Streamlit | |
st.pyplot(fig) | |
def display_player_names_and_positions_twoTeam(home_lineups, away_lineups, position_id_to_coordinates_home, position_id_to_coordinates_away): | |
# Dictionaries to store coordinates and player names for both home and away teams | |
coordinates_dict_home = {} | |
player_names_dict_home = {} | |
coordinates_dict_away = {} | |
player_names_dict_away = {} | |
# Process home team lineup | |
for index, row in home_lineups.iterrows(): | |
player_name = row['player_name'] | |
position_info = row['positions'][0] if row['positions'] else {} | |
position_id = position_info.get('position_id', 'Unknown') | |
if position_id in position_id_to_coordinates_home: | |
coordinates_dict_home[position_id] = position_id_to_coordinates_home[position_id] | |
player_names_dict_home[position_id] = player_name | |
# Process away team lineup | |
for index, row in away_lineups.iterrows(): | |
player_name = row['player_name'] | |
position_info = row['positions'][0] if row['positions'] else {} | |
position_id = position_info.get('position_id', 'Unknown') | |
if position_id in position_id_to_coordinates_away: | |
coordinates_dict_away[position_id] = position_id_to_coordinates_away[position_id] | |
player_names_dict_away[position_id] = player_name | |
# Plotting the pitch | |
pitch = Pitch( | |
# pitch_color='#1f77b4', | |
pitch_color='#d2d2d2', | |
line_color='white', | |
stripe=False, | |
pitch_type='statsbomb' | |
) | |
fig, ax = pitch.draw() | |
# Plotting home team positions | |
if coordinates_dict_home: | |
x_coords_home, y_coords_home = zip(*coordinates_dict_home.values()) | |
ax.scatter(x_coords_home, y_coords_home, color='red', s=300, edgecolors='white', zorder=3) | |
for position_id, (x, y) in coordinates_dict_home.items(): | |
name = player_names_dict_home.get(position_id, "Unknown") | |
ax.text(x, y - 4, f'{name.split()[-1]}', color='black', ha='center', va='center', fontsize=12, zorder=6) | |
# Plotting away team positions | |
if coordinates_dict_away: | |
x_coords_away, y_coords_away = zip(*coordinates_dict_away.values()) | |
ax.scatter(x_coords_away, y_coords_away, color='blue', s=300, edgecolors='white', zorder=3) | |
for position_id, (x, y) in coordinates_dict_away.items(): | |
name = player_names_dict_away.get(position_id, "Unknown") | |
ax.text(x, y - 4, f'{name.split()[-1]}', color='black', ha='center', va='center', fontsize=12, zorder=6) | |
# Display the plot in Streamlit | |
st.pyplot(fig) | |
def display_player_names_and_positions_oneTeam(home_lineups, position_id_to_coordinates_home,color): | |
# Dictionaries to store coordinates and player names for the home team | |
coordinates_dict_home = {} | |
player_names_dict_home = {} | |
# Process home team lineup | |
for index, row in home_lineups.iterrows(): | |
player_name = row['player_name'] | |
position_info = row['positions'][0] if row['positions'] else {} | |
position_id = position_info.get('position_id', 'Unknown') | |
if position_id in position_id_to_coordinates_home: | |
coordinates_dict_home[position_id] = position_id_to_coordinates_home[position_id] | |
player_names_dict_home[position_id] = player_name | |
# Plotting the pitch | |
pitch = Pitch( | |
pitch_color='#d2d2d2', | |
line_color='white', | |
stripe=False, | |
pitch_type='statsbomb' | |
) | |
fig, ax = pitch.draw() | |
# Plotting home team positions | |
if coordinates_dict_home: | |
x_coords_home, y_coords_home = zip(*coordinates_dict_home.values()) | |
ax.scatter(x_coords_home, y_coords_home, color=color, s=300, edgecolors='white', zorder=3) | |
for position_id, (x, y) in coordinates_dict_home.items(): | |
name = player_names_dict_home.get(position_id, "Unknown") | |
ax.text(x, y - 4, f'{name.split()[-1]}', color='black', ha='center', va='center', fontsize=12, zorder=6) | |
# Display the plot in Streamlit | |
st.pyplot(fig) | |
# Function to find the best image match based on the team name | |
def get_best_match_image(team_name, images_data): | |
image_names = [image['image_name'] for image in images_data] | |
best_match, match_score = process.extractOne(team_name, image_names, scorer=fuzz.token_sort_ratio) | |
if match_score > 70: # Adjust the threshold as needed | |
for image in images_data: | |
if image['image_name'] == best_match: | |
return image['image_link'] | |
return None | |
class StadiumImageFetcher: | |
def __init__(self): | |
self.headers = { | |
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3" | |
} | |
def get_stadium_image_url(self, stadium_name): | |
# Formulate the Google Image search URL | |
query = stadium_name.replace(' ', '+') | |
url = f"https://www.google.com/search?hl=en&tbm=isch&q={query}" | |
# Send the request | |
response = requests.get(url, headers=self.headers) | |
# Parse the HTML content using BeautifulSoup | |
soup = BeautifulSoup(response.text, 'lxml') | |
# Find the first image result | |
images = soup.find_all('img') | |
if images and len(images) > 1: # The first image might be the Google logo, so skip it | |
return images[1]['src'] | |
else: | |
return None | |
def display_stadium(self): | |
st.title("Stadium Image Display") | |
# Input the stadium name | |
stadium_name = st.text_input("Enter the stadium name:") | |
if stadium_name: | |
# Get the image URL | |
image_url = self.get_stadium_image_url(stadium_name) | |
if image_url: | |
st.image(image_url, caption=f'{stadium_name} Stadium') | |
else: | |
st.write("Image not found.") | |
def main_stadium(): | |
stadium = StadiumImageFetcher() | |
stadium.display_stadium() | |
def box_plot_pass(events,team): | |
event_filterTeam = events[events['team']==team] | |
event_pass = event_filterTeam.filter(regex='^(pass)', axis=1).dropna(how='all') | |
event_pass_length = event_pass['pass_length'] | |
fig = px.box(event_pass_length, y=event_pass_length, labels={'y':'Pass Length'}, title=f'{team} Distribution of Pass Length') | |
fig.update_layout(width=300, height=600) # 200 pixels de largeur, 400 pixels de hauteur | |
# Afficher le graphique dans Streamlit | |
st.plotly_chart(fig) | |
# def get_possession(events): | |
# """ | |
# Extracts and normalizes the possession counts for the two teams from the events DataFrame. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame containing an events column 'possession_team'. | |
# Returns: | |
# - home_team_possession (float): Normalized possession percentage for the home team, rounded to one decimal place. | |
# - away_team_possession (float): Normalized possession percentage for the away team, rounded to one decimal place. | |
# """ | |
# # Get possession counts | |
# possession_counts = events['possession_team'].value_counts() | |
# # Get the top two possession teams | |
# home_team_possession, away_team_possession = possession_counts.iloc[0], possession_counts.iloc[1] | |
# # Calculate total possession | |
# total_possession = home_team_possession + away_team_possession | |
# # Normalize possession and round to one decimal place | |
# home_team_possession = round((home_team_possession / total_possession) * 100, 1) | |
# away_team_possession = round((away_team_possession / total_possession) * 100, 1) | |
# return home_team_possession, away_team_possession | |
# def get_total_xg(events): | |
# """ | |
# Calcule la somme totale des xG (expected goals) par équipe et retourne les valeurs arrondies à 2 décimales. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame contenant les colonnes 'shot_statsbomb_xg' et 'team'. | |
# Returns: | |
# - home_xg (float): Somme totale des xG pour l'équipe à domicile, arrondie à 2 décimales. | |
# - away_xg (float): Somme totale des xG pour l'équipe à l'extérieur, arrondie à 2 décimales. | |
# """ | |
# # Filtrer les colonnes et supprimer les lignes où 'shot_statsbomb_xg' est NaN | |
# data = events.filter(regex='^shot_statsbomb_xg|^team$').dropna(subset=['shot_statsbomb_xg']) | |
# # Grouper par 'team' et calculer la somme des xG | |
# data = data.groupby('team')['shot_statsbomb_xg'].sum() | |
# # Arrondir les résultats à 2 décimales | |
# home_xg, away_xg = round(data.iloc[0], 2), round(data.iloc[1], 2) | |
# return home_xg, away_xg | |
# def get_total_shots(events): | |
# """ | |
# Calcule le nombre total de tirs (shots) par équipe. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame contenant les colonnes 'shot_statsbomb_xg' et 'team'. | |
# Returns: | |
# - home_shots (int): Nombre total de tirs pour l'équipe à domicile. | |
# - away_shots (int): Nombre total de tirs pour l'équipe à l'extérieur. | |
# """ | |
# # Filtrer les colonnes et supprimer les lignes où 'shot_statsbomb_xg' est NaN | |
# data = events.filter(regex='^shot_statsbomb_xg|^team$').dropna(subset=['shot_statsbomb_xg']) | |
# # Grouper par 'team' et compter le nombre de tirs | |
# shot_counts = data.groupby('team').count()['shot_statsbomb_xg'] | |
# # Retourner les comptes pour les deux équipes | |
# home_shots, away_shots = shot_counts.iloc[0], shot_counts.iloc[1] | |
# return home_shots, away_shots | |
# def get_total_shots_off_target(events): | |
# """ | |
# Calcule le nombre total de tirs non cadrés (off target) par équipe. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame contenant les colonnes 'shot_outcome' et 'team'. | |
# Returns: | |
# - home_off_target (int): Nombre total de tirs non cadrés pour l'équipe à domicile. | |
# - away_off_target (int): Nombre total de tirs non cadrés pour l'équipe à l'extérieur. | |
# """ | |
# # Define outcomes that indicate a shot was off target | |
# off_target_outcomes = ['Off T', 'Blocked', 'Missed'] | |
# # Filter the events DataFrame for shots off target | |
# data = events[events['shot_outcome'].isin(off_target_outcomes)] | |
# # Group by 'team' and count the number of off-target shots | |
# off_target_counts = data.groupby('team').size() | |
# # Return the counts for the two teams | |
# home_off_target, away_off_target = off_target_counts.iloc[0], off_target_counts.iloc[1] | |
# return home_off_target, away_off_target | |
# def get_total_shots_on_target(events): | |
# """ | |
# Calcule le nombre total de tirs cadrés (on target) par équipe. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame contenant les colonnes 'shot_outcome' et 'team'. | |
# Returns: | |
# - home_on_target (int): Nombre total de tirs cadrés pour l'équipe à domicile. | |
# - away_on_target (int): Nombre total de tirs cadrés pour l'équipe à l'extérieur. | |
# """ | |
# # Define outcomes that indicate a shot was on target | |
# on_target_outcomes = ['Goal', 'Saved', 'Saved To Post', 'Shot Saved Off Target'] | |
# # Filter the events DataFrame for shots on target | |
# data = events[events['shot_outcome'].isin(on_target_outcomes)] | |
# # Group by 'team' and count the number of on-target shots | |
# on_target_counts = data.groupby('team').size() | |
# # Return the counts for the two teams | |
# home_on_target, away_on_target = on_target_counts.iloc[0], on_target_counts.iloc[1] | |
# return home_on_target, away_on_target | |
# def get_total_passes(events): | |
# """ | |
# Calcule le nombre total de passes par équipe. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame contenant les colonnes 'pass_outcome' et 'team'. | |
# Returns: | |
# - home_passes (int): Nombre total de passes pour l'équipe à domicile. | |
# - away_passes (int): Nombre total de passes pour l'équipe à l'extérieur. | |
# """ | |
# # Filtrer les colonnes 'pass_outcome' et 'team', puis grouper par équipe et compter le nombre de passes | |
# pass_counts = events.filter(regex='^pass_end_location|^team$').groupby('team').count()['pass_end_location'] | |
# # Retourner les comptes pour les deux équipes | |
# home_passes, away_passes = pass_counts.iloc[0], pass_counts.iloc[1] | |
# return home_passes, away_passes | |
# def get_successful_passes(events): | |
# """ | |
# Calculates the total number of successful passes for home and away teams. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame containing the columns for all passes and pass outcomes. | |
# Returns: | |
# - home_successful_passes (int): Successful passes for the home team. | |
# - away_successful_passes (int): Successful passes for the away team. | |
# """ | |
# # Get the total passes using the get_total_passes function | |
# home_passes, away_passes = get_total_passes(events) | |
# # Identify unsuccessful passes based on 'type' or another column indicating unsuccessful outcomes | |
# unsuccessful_passes = events.filter(regex='^pass_outcome|^team$').groupby('team').count().reset_index()['pass_outcome'] | |
# # Calculate successful passes by subtracting unsuccessful passes from total passes | |
# home_unsuccessful_passes = unsuccessful_passes.iloc[0] | |
# away_unsuccessful_passes = unsuccessful_passes.iloc[1] | |
# home_successful_passes = home_passes - home_unsuccessful_passes | |
# away_successful_passes = away_passes - away_unsuccessful_passes | |
# return home_successful_passes, away_successful_passes | |
# def get_total_corners(events): | |
# """ | |
# Calcule le nombre total de corners par équipe. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame contenant les colonnes 'pass_type' et 'team'. | |
# Returns: | |
# - home_corners (int): Nombre total de corners pour l'équipe à domicile. | |
# - away_corners (int): Nombre total de corners pour l'équipe à l'extérieur. | |
# """ | |
# # Filtrer les colonnes 'pass_type' et 'team', puis grouper par équipe et compter le nombre de corners | |
# corner_counts = events.filter(regex='^pass_type|^team$').query('pass_type == "Corner"').groupby('team').count()['pass_type'] | |
# # Extract the team names from the events DataFrame | |
# teams = events['team'].unique() | |
# # Handle cases where a team might not have any corners | |
# home_corners = corner_counts.get(teams[0], 0) | |
# away_corners = corner_counts.get(teams[1], 0) | |
# return home_corners, away_corners | |
# def get_total_fouls(events): | |
# """ | |
# Calcule le nombre total de fautes par équipe. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame contenant les colonnes 'team' et 'type'. | |
# Returns: | |
# - home_fouls (int): Nombre total de fautes pour l'équipe à domicile. | |
# - away_fouls (int): Nombre total de fautes pour l'équipe à l'extérieur. | |
# """ | |
# fouls = events[events['type'] == 'Foul Committed'] | |
# foul_counts = fouls.groupby('team').size() | |
# home_fouls, away_fouls = foul_counts.iloc[0], foul_counts.iloc[1] | |
# return home_fouls, away_fouls | |
# def get_total_yellow_cards(events): | |
# """ | |
# Calcule le nombre total de cartons jaunes par équipe. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame contenant les colonnes 'bad_behaviour_card' et 'team'. | |
# Returns: | |
# - home_yellow_cards (int): Nombre total de cartons jaunes pour l'équipe à domicile. | |
# - away_yellow_cards (int): Nombre total de cartons jaunes pour l'équipe à l'extérieur. | |
# """ | |
# # Filtrer les colonnes 'bad_behaviour_card' et 'team', puis grouper par équipe et compter le nombre de cartons jaunes | |
# yellow_card_counts = events.filter(regex='^bad_behaviour_card|^team$').query('bad_behaviour_card == "Yellow Card"').groupby('team').count()['bad_behaviour_card'] | |
# # Extraire les noms des équipes de l'événement DataFrame | |
# teams = events['team'].unique() | |
# # Gérer les cas où une équipe pourrait ne pas avoir de cartons jaunes | |
# home_yellow_cards = yellow_card_counts.get(teams[0], 0) | |
# away_yellow_cards = yellow_card_counts.get(teams[1], 0) | |
# return home_yellow_cards, away_yellow_cards | |
# def get_total_red_cards(events): | |
# """ | |
# Calcule le nombre total de cartons rouges par équipe. | |
# Parameters: | |
# - events (pd.DataFrame): DataFrame contenant les colonnes 'bad_behaviour_card' et 'team'. | |
# Returns: | |
# - home_red_cards (int): Nombre total de cartons rouges pour l'équipe à domicile. | |
# - away_red_cards (int): Nombre total de cartons rouges pour l'équipe à l'extérieur. | |
# """ | |
# # Filtrer les colonnes 'bad_behaviour_card' et 'team', puis grouper par équipe et compter le nombre de cartons rouges | |
# red_card_counts = events.filter(regex='^bad_behaviour_card|^team$').query('bad_behaviour_card == "Red Card"').groupby('team').count()['bad_behaviour_card'] | |
# # Extraire les noms des équipes de l'événement DataFrame | |
# teams = events['team'].unique() | |
# # Gérer les cas où une équipe pourrait ne pas avoir de cartons rouges | |
# home_red_cards = red_card_counts.get(teams[0], 0) | |
# away_red_cards = red_card_counts.get(teams[1], 0) | |
# return home_red_cards, away_red_cards | |
# def display_normalized_scores(home_scores, away_scores, categories, home_color='blue', away_color='green', background_color='lightgray', bar_height=0.8, spacing_factor=2.5): | |
# """ | |
# Displays a horizontal bar chart with normalized scores for home and away teams. | |
# Parameters: | |
# - home_scores: List of scores for the home team. | |
# - away_scores: List of scores for the away team. | |
# - categories: List of category names for each score. | |
# - home_color: Color of the bars representing the home team. | |
# - away_color: Color of the bars representing the away team. | |
# - background_color: Color of the background rectangles. | |
# - bar_height: Height of the bars and background rectangles. | |
# - spacing_factor: Factor to adjust the spacing between bars. | |
# """ | |
# # Internal container size variables | |
# container_width = '50%' # Adjust width as needed | |
# container_height = 'auto' # Adjust height as needed | |
# # Normalizing the scores | |
# home_normalized = [] | |
# away_normalized = [] | |
# for home, away in zip(home_scores, away_scores): | |
# total = home + away | |
# if total != 0: | |
# home_normalized.append((home / total) * 100) | |
# away_normalized.append((away / total) * 100) | |
# else: | |
# home_normalized.append(0) | |
# away_normalized.append(0) | |
# # Augmenting the spacing between the bars by multiplying y_pos by a factor | |
# y_pos = np.arange(len(categories)) * spacing_factor | |
# # Plot | |
# fig, ax = plt.subplots(figsize=(10, 8)) | |
# # Adding light gray backgrounds for each category with the same height as the bars | |
# for i in range(len(categories)): | |
# ax.add_patch(plt.Rectangle((-100, y_pos[i] - bar_height / 2), 200, bar_height, color=background_color, alpha=0.3, linewidth=0)) | |
# # Plotting normalized scores for both teams | |
# ax.barh(y_pos, home_normalized, height=bar_height, color=home_color, align='center', label='Home Team') | |
# ax.barh(y_pos, [-score for score in away_normalized], height=bar_height, color=away_color, align='center', label='Away Team') | |
# # Positioning the category names above the bars to avoid overlap | |
# for i in range(len(categories)): | |
# ax.text(0, y_pos[i] + bar_height / 2 + 0.1, categories[i], ha='center', va='bottom', fontsize=10) | |
# # Adding non-normalized values to the end of the bars | |
# for i in range(len(categories)): | |
# ax.text(home_normalized[i] / 2, y_pos[i], f'{home_scores[i]}', va='center', color='white', fontweight='bold') | |
# ax.text(-away_normalized[i] / 2, y_pos[i], f'{away_scores[i]}', va='center', color='white', fontweight='bold') | |
# # Adjusting the axis limits | |
# ax.set_xlim(-100, 100) | |
# ax.set_ylim(-1, max(y_pos) + spacing_factor) | |
# # Hiding the spines | |
# for spine in ax.spines.values(): | |
# spine.set_visible(False) | |
# # Removing y-ticks and x-ticks | |
# ax.set_yticks([]) | |
# ax.set_xticks([]) | |
# # Custom HTML/CSS to control the size of the container | |
# st.markdown( | |
# f""" | |
# <style> | |
# .resizable-graph-container {{ | |
# width: {container_width}; /* Adjust the width as needed */ | |
# height: {container_height}; /* Adjust the height as needed */ | |
# padding: 10px; | |
# overflow: auto; /* Handle overflow if the graph is larger than the container */ | |
# }} | |
# </style> | |
# <div class="resizable-graph-container"> | |
# """, | |
# unsafe_allow_html=True | |
# ) | |
# # Displaying the plot in Streamlit | |
# st.pyplot(fig) | |
# # Closing the custom container | |
# st.markdown('</div>', unsafe_allow_html=True) | |
def display_normalized_scores(home_scores, away_scores, categories, home_color='blue', away_color='green', background_color='lightgray', bar_height=0.8, spacing_factor=2.5): | |
""" | |
Displays a horizontal bar chart with normalized scores for home and away teams. | |
Parameters: | |
- home_scores: List of scores for the home team. | |
- away_scores: List of scores for the away team. | |
- categories: List of category names for each score. | |
- home_color: Color of the bars representing the home team. | |
- away_color: Color of the bars representing the away team. | |
- background_color: Color of the background rectangles. | |
- bar_height: Height of the bars and background rectangles. | |
- spacing_factor: Factor to adjust the spacing between bars. | |
""" | |
# Normalizing the scores | |
home_normalized = [] | |
away_normalized = [] | |
for home, away in zip(home_scores, away_scores): | |
# Remplacer les None par 0 pour éviter les erreurs | |
home = 0 if home is None else home | |
away = 0 if away is None else away | |
total = home + away | |
if total != 0: | |
home_normalized.append((home / total) * 100) | |
away_normalized.append((away / total) * 100) | |
else: | |
home_normalized.append(0) | |
away_normalized.append(0) | |
# Augmenting the spacing between the bars by multiplying y_pos by a factor | |
y_pos = np.arange(len(categories)) * spacing_factor | |
# Plot | |
fig, ax = plt.subplots(figsize=(10, 8)) | |
# Adding light gray backgrounds for each category with the same height as the bars | |
for i in range(len(categories)): | |
ax.add_patch(plt.Rectangle((-100, y_pos[i] - bar_height / 2), 200, bar_height, color=background_color, alpha=0.3, linewidth=0)) | |
# Plotting normalized scores for both teams | |
ax.barh(y_pos, home_normalized, height=bar_height, color=home_color, align='center', label='Home Team') | |
ax.barh(y_pos, [-score for score in away_normalized], height=bar_height, color=away_color, align='center', label='Away Team') | |
# Positioning the category names above the bars to avoid overlap | |
for i in range(len(categories)): | |
ax.text(0, y_pos[i] + bar_height / 2 + 0.1, categories[i], ha='center', va='bottom', fontsize=10) | |
# Adding non-normalized values to the end of the bars | |
for i in range(len(categories)): | |
ax.text(home_normalized[i] / 2, y_pos[i], f'{home_scores[i]}', va='center', color='white', fontweight='bold') | |
ax.text(-away_normalized[i] / 2, y_pos[i], f'{away_scores[i]}', va='center', color='white', fontweight='bold') | |
# Adjusting the axis limits | |
ax.set_xlim(-100, 100) | |
ax.set_ylim(-1, max(y_pos) + spacing_factor) | |
# Hiding the spines | |
for spine in ax.spines.values(): | |
spine.set_visible(False) | |
# Removing y-ticks and x-ticks | |
ax.set_yticks([]) | |
ax.set_xticks([]) | |
# Displaying the plot in Streamlit | |
st.pyplot(fig) | |