use another online library besides nfl_data_py for data fetching

import tkinter as tk
from tkinter import ttk
import time
import pandas as pd
import nfl_data_py as nfl

# Precomputed dictionary of team names to abbreviations
TEAM_ABBR = {
    "Arizona Cardinals": "ARI",
    "Atlanta Falcons": "ATL",
    "Baltimore Ravens": "BAL",
    "Buffalo Bills": "BUF",
    "Carolina Panthers": "CAR",
    "Chicago Bears": "CHI",
    "Cincinnati Bengals": "CIN",
    "Cleveland Browns": "CLE",
    "Dallas Cowboys": "DAL",
    "Denver Broncos": "DEN",
    "Detroit Lions": "DET",
    "Green Bay Packers": "GB",
    "Houston Texans": "HOU",
    "Indianapolis Colts": "IND",
    "Jacksonville Jaguars": "JAX",
    "Kansas City Chiefs": "KC",
    "Las Vegas Raiders": "LV",
    "Los Angeles Chargers": "LAC",
    "Los Angeles Rams": "LAR",
    "Miami Dolphins": "MIA",
    "Minnesota Vikings": "MIN",
    "New England Patriots": "NE",
    "New Orleans Saints": "NO",
    "New York Giants": "NYG",
    "New York Jets": "NYJ",
    "Philadelphia Eagles": "PHI",
    "Pittsburgh Steelers": "PIT",
    "San Francisco 49ers": "SF",
    "Seattle Seahawks": "SEA",
    "Tampa Bay Buccaneers": "TB",
    "Tennessee Titans": "TEN",
    "Washington Commanders": "WAS"
}

def get_top_players_for_selected_teams(selected_teams, selected_stat, consistency_threshold, apply_consistency_filter, use_lowest_score):
    # Map selected team names to team abbreviations
    selected_team_abbr = [TEAM_ABBR[team] for team in selected_teams]
    
    # Fetch weekly data for the current season or seasons
    NFL_SEASONS = [2022]  # Adjust this to the desired season(s)
    try:
        # Import weekly data for the given seasons
        weekly_data = nfl.import_weekly_data(NFL_SEASONS, stat_type='offense')
    except Exception as e:
        print(f"Failed to fetch weekly data: {e}")
        return []
    
    # Filter players from selected teams
    filtered_players = weekly_data[weekly_data['recent_team'].isin(selected_team_abbr)]
    
    # Map selected_stat to the corresponding column in weekly_data
    stat_column_map = {'Rushing Yards': 'rushing_yards', 'Receiving Yards': 'receiving_yards', 'Receptions': 'receptions'}
    stat_column = stat_column_map.get(selected_stat)
    
    if stat_column is None:
        print(f"Stat {selected_stat} not available.")
        return []
    
    # Group data by player
    player_stats = filtered_players.groupby('player_id')
    
    # Prepare a list to store player statistics
    all_player_stats = []
    
    for player_id, group in player_stats:
        player_name = group['player_name'].iloc[0]
        team = group['recent_team'].iloc[0]
        season = group['season'].iloc[0]
        games_played = group['week'].nunique()
        stat_values = group[stat_column].fillna(0)
        
        if stat_values.sum() == 0:
            continue  # Skip players with no stats
        
        if use_lowest_score:
            stat_value = stat_values.min()
        else:
            stat_value = stat_values.mean()
        
        if apply_consistency_filter:
            std_dev = stat_values.std()
            if pd.isna(std_dev) or std_dev > consistency_threshold:
                continue  # Skip player if standard deviation exceeds threshold
        else:
            std_dev = None
        
        all_player_stats.append((team, player_name, season, stat_value, std_dev, games_played))
    
    # Remove players with missing stat_value
    all_player_stats = [x for x in all_player_stats if pd.notnull(x[3])]
    
    # Return sorted results by stat_value
    return sorted(all_player_stats, key=lambda x: x[3], reverse=True)

def display_top_players():
    selected_teams = [team_listbox.get(i) for i in team_listbox.curselection()]
    selected_stat_value = selected_stat.get()
    try:
        max_players = int(max_players_entry.get())
    except ValueError:
        result_label.config(text="Invalid number for max players.")
        return
    try:
        consistency_threshold = float(consistency_entry.get())
    except ValueError:
        result_label.config(text="Invalid number for consistency threshold.")
        return
    
    apply_consistency_filter = consistency_var.get()
    use_lowest_score = lowest_score_var.get()
    
    if not selected_teams:
        result_label.config(text="Please select at least one team.")
        return
    
    result_label.config(text="Fetching data...")
    root.update()  # Refresh UI during processing
    
    start_time = time.time()
    top_players = get_top_players_for_selected_teams(
        selected_teams, selected_stat_value, consistency_threshold,
        apply_consistency_filter, use_lowest_score
    )[:max_players]
    end_time = time.time()
    
    # Display results
    result_area.delete("1.0", tk.END)
    if not top_players:
        result_label.config(text="No top players found.")
        return
    
    result_label.config(text=f"Data fetched successfully in {end_time - start_time:.2f} seconds!")
    
    # Determine the appropriate label for the stat
    stat_label_map = {'Rushing Yards': 'Rushing Yards', 'Receiving Yards': 'Receiving Yards', 'Receptions': 'Receptions'}
    stat_label_text = stat_label_map.get(selected_stat_value, 'Stat')
    
    if use_lowest_score:
        result_area.insert(tk.END, f"Top {len(top_players)} players based on lowest {stat_label_text} per game:\n")
    else:
        result_area.insert(tk.END, f"Top {len(top_players)} players based on average {stat_label_text} per game:\n")
    
    result_text = ""
    for i, (team, player, season, stat_value, std_dev, games_played) in enumerate(top_players, start=1):
        stat_line = f"{i}. {player} - {stat_value:.2f} {stat_label_text} per game (Games Played: {games_played})"
        if apply_consistency_filter and std_dev is not None:
            stat_line += f" (Std Dev: {std_dev:.2f})"
        stat_line += f" ({season} season) [{team}]"
        result_text += stat_line + "\n"
    result_area.insert(tk.END, result_text + "\n")

# UI Setup
root = tk.Tk()
root.title("NFL Best Players Comparison")
root.rowconfigure(8, weight=1)
root.columnconfigure(1, weight=1)

team_label = ttk.Label(root, text="Select Teams:")
team_label.grid(row=0, column=0, padx=10, pady=10, sticky="NW")

team_listbox = tk.Listbox(root, selectmode=tk.MULTIPLE, height=15, exportselection=False)
for team in TEAM_ABBR.keys():
    team_listbox.insert(tk.END, team)
team_listbox.grid(row=0, column=1, padx=10, pady=10, sticky="NSEW")

max_players_label = ttk.Label(root, text="Max Players:")
max_players_label.grid(row=1, column=0, padx=10, pady=10, sticky="W")

max_players_entry = ttk.Entry(root, width=5)
max_players_entry.grid(row=1, column=1, padx=10, pady=10, sticky="W")
max_players_entry.insert(0, "5")

# Variable to hold the selected stat
selected_stat = tk.StringVar(value='Rushing Yards')

# Label and Radio Buttons for Stat Selection
stat_label = ttk.Label(root, text="Select Stat to Compare:")
stat_label.grid(row=2, column=0, padx=10, pady=10, sticky="W")

stat_frame = ttk.Frame(root)
stat_frame.grid(row=2, column=1, padx=10, pady=10, sticky="W")

rb_rushing = ttk.Radiobutton(stat_frame, text='Rushing Yards', variable=selected_stat, value='Rushing Yards')
rb_rushing.pack(side='left')
rb_receiving = ttk.Radiobutton(stat_frame, text='Receiving Yards', variable=selected_stat, value='Receiving Yards')
rb_receiving.pack(side='left')
rb_receptions = ttk.Radiobutton(stat_frame, text='Receptions', variable=selected_stat, value='Receptions')
rb_receptions.pack(side='left')

consistency_label = ttk.Label(root, text="Consistency Threshold (Max Std Dev):")
consistency_label.grid(row=3, column=0, padx=10, pady=10, sticky="W")

consistency_entry = ttk.Entry(root, width=5)
consistency_entry.grid(row=3, column=1, padx=10, pady=10, sticky="W")
consistency_entry.insert(0, "10")

# Variables and Checkbuttons for Toggles
consistency_var = tk.BooleanVar(value=True)
consistency_toggle = ttk.Checkbutton(root, text="Apply Consistency Filter", variable=consistency_var)
consistency_toggle.grid(row=4, column=0, columnspan=2, padx=10, pady=5, sticky="W")

lowest_score_var = tk.BooleanVar(value=False)
lowest_score_toggle = ttk.Checkbutton(root, text="Use Player's Lowest Score", variable=lowest_score_var)
lowest_score_toggle.grid(row=5, column=0, columnspan=2, padx=10, pady=5, sticky="W")

submit_button = ttk.Button(root, text="Get Top Players", command=display_top_players)
submit_button.grid(row=6, column=0, columnspan=2, pady=10)

result_label = ttk.Label(root, text="")
result_label.grid(row=7, column=0, columnspan=2, padx=10, pady=10)

result_area = tk.Text(root, wrap="word")
result_area.grid(row=8, column=0, columnspan=2, padx=10, pady=10, sticky="NSEW")

scrollbar = ttk.Scrollbar(root, orient="vertical", command=result_area.yview)
scrollbar.grid(row=8, column=2, sticky="NS")
result_area.configure(yscrollcommand=scrollbar.set)

root.mainloop()