# Analyzing Pitcher Command with BaseballTools

The `BaseballTools` class in the `baseballcv` library provides a powerful function, `analyze_pitcher_command`, for assessing a pitcher's command. This tool leverages computer vision to determine the catcher's intended target and compares it against the actual pitch location data obtained from Statcast.

## How `analyze_pitcher_command` Works

The `analyze_pitcher_command` method streamlines the process of command analysis by integrating several underlying components:

1.  **Input**: It takes a directory containing CSV files previously generated by the `GloveTracker` tool (which is also accessible via `BaseballTools.track_gloves()`). These CSVs detail frame-by-frame positions of the catcher's glove, baseball, and home plate.
2.  **Statcast Integration**: For each processed video (identified by `game_pk` and `play_id` from the CSV filenames), the tool fetches corresponding pitch data from Statcast. This provides the actual `plate_x` and `plate_z` (pitch location as it crosses the plate) and strike zone dimensions (`sz_top`, `sz_bot`).
3.  **Intended Target Identification**:
    * The core of the `CommandAnalyzer` logic lies in identifying the "intent frame" from the `GloveTracker` data. This is the frame where the catcher presents a stable target *before* the pitcher releases the ball and before any significant glove movement to receive the pitch.
    * It analyzes glove velocity and height patterns to pinpoint this moment, filtering out movements associated with receiving the pitch or casual glove rests.
    * The glove's `(x, y)` position (in inches, relative to the center of the home plate in the 2D image) in this intent frame is considered the pitcher's intended target.
4.  **Coordinate Transformation**:
    * The 2D target coordinates (from the glove in the image) and the 3D actual pitch coordinates (from Statcast) are transformed into a common, comparable coordinate system (inches, with x representing horizontal deviation from the center of the plate and z representing height from the ground).
    * This involves using the detected home plate in the video for scaling (pixels per inch) and as a reference for ground level.
5.  **Deviation Calculation**:
    * Once both the intended target and actual pitch location are in the same coordinate system, the tool calculates the deviation in inches:
        * `dev_x_inches`: Horizontal miss.
        * `dev_z_inches`: Vertical miss.
        * `deviation_inches`: The overall Euclidean distance between the target and actual location.
6.  **Output Generation**:
    * **Detailed CSV**: A primary CSV file is generated (e.g., `pitcher_command_summary.csv`) containing pitch-by-pitch analysis. Each row includes:
        * Identifiers (`game_pk`, `play_id`).
        * Intent frame number.
        * Target coordinates (`target_x_inches`, `target_y_inches`, `target_z_inches`).
        * Glove height from ground at intent.
        * Actual pitch coordinates (`actual_x_inches`, `actual_z_inches`).
        * Calculated deviations (`deviation_inches`, `dev_x_inches`, `dev_z_inches`).
        * Relevant Statcast data (pitcher, pitch type, velocity, etc.).
        * Pixel coordinates for visualization purposes.
    * **Aggregate CSV**: An optional secondary CSV file (e.g., `aggregate_pitcher_command_summary.csv`) provides summary metrics, grouped by specified columns (e.g., by pitcher, by pitch type). This includes:
        * Average deviation.
        * Standard deviation of miss.
        * Command percentage (pitches within a specified threshold of the target).
        * Pitch count.
    * **Overlay Videos (Optional)**: If `create_overlay=True`, the tool generates videos for each analyzed pitch, visually superimposing the intended target and actual pitch location onto the original footage. This is excellent for visual validation and presentation.

## Example Usage with `BaseballTools`

This example demonstrates the end-to-end workflow: first generating the necessary glove tracking data, and then using that data to analyze pitcher command.

```python
import os
from baseballcv.functions import BaseballTools
from IPython.display import display # For better DataFrame display in notebooks

# --- 1. Set Up Directories ---
# Define where outputs will be stored
BASE_OUTPUT_DIR = "baseball_analysis_output"
# GloveTracker's default output directory relative to where it's run.
# This will be the input for CommandAnalyzer.
GLOVE_TRACKER_CSVS_DIR = os.path.join(BASE_OUTPUT_DIR, "glove_tracking_results")
# Where CommandAnalyzer will save its specific video overlays
VIDEO_OVERLAYS_DIR = os.path.join(BASE_OUTPUT_DIR, "command_overlays")

os.makedirs(BASE_OUTPUT_DIR, exist_ok=True)
# GLOVE_TRACKER_CSVS_DIR will be created by GloveTracker if it doesn't exist
os.makedirs(VIDEO_OVERLAYS_DIR, exist_ok=True)

print(f"Project base output directory: {os.path.abspath(BASE_OUTPUT_DIR)}")
print(f"GloveTracker CSVs will be generated in: {os.path.abspath(GLOVE_TRACKER_CSVS_DIR)}")
print(f"Command analysis video overlays will be in: {os.path.abspath(VIDEO_OVERLAYS_DIR)}")

# --- 2. Initialize BaseballTools ---
# Use 'cpu' for broad compatibility, or 'cuda'/'mps' if a GPU is available.
baseball_tools = BaseballTools(device='cpu', verbose=True)

# --- 3. Generate Glove Tracking Data (Prerequisite) ---
# CommandAnalyzer needs CSVs from GloveTracker.
# We'll use 'scrape' mode to get a few sample videos and process them.
print("\nStep 1: Running GloveTracker to generate prerequisite CSV files...")
print("This will download videos and process them. This might take a few minutes.")

glove_tracking_results = baseball_tools.track_gloves(
    mode="scrape",
    start_date="2024-05-01", # Example date
    end_date="2024-05-01",
    max_videos=2,            # Limit for a quick demo
    max_videos_per_game=1,
    team_abbr="NYY",         # Example team
    create_video=False,      # Set to False to speed up CSV generation for this demo
    generate_heatmap=False,  # Also False for speed
    show_plot=False,         # Also False for speed
    suppress_detection_warnings=True
)

ACTUAL_GLOVE_TRACKER_OUTPUT_DIR = ""
if "error" in glove_tracking_results:
    print(f"\nError during glove tracking: {glove_tracking_results['error']}")
    print("Cannot proceed with CommandAnalyzer demo.")
else:
    print("\nGlove tracking finished.")
    if glove_tracking_results.get("processed_videos", 0) > 0:
        print(f"Successfully processed {glove_tracking_results['processed_videos']} video(s).")
        # This is the directory CommandAnalyzer needs
        ACTUAL_GLOVE_TRACKER_OUTPUT_DIR = glove_tracking_results.get('results_dir', GLOVE_TRACKER_CSVS_DIR)
        print(f"GloveTracker outputs (including CSVs) are in: {os.path.abspath(ACTUAL_GLOVE_TRACKER_OUTPUT_DIR)}")
    else:
        print("No videos were processed by GloveTracker. CommandAnalyzer may not have input.")
        ACTUAL_GLOVE_TRACKER_OUTPUT_DIR = GLOVE_TRACKER_CSVS_DIR # Fallback, likely empty

# --- 4. Analyze Pitcher Command ---
if ACTUAL_GLOVE_TRACKER_OUTPUT_DIR and os.path.exists(ACTUAL_GLOVE_TRACKER_OUTPUT_DIR) and len(os.listdir(ACTUAL_GLOVE_TRACKER_OUTPUT_DIR)) > 0 :
    print(f"\nStep 2: Running CommandAnalyzer on CSVs from: {os.path.abspath(ACTUAL_GLOVE_TRACKER_OUTPUT_DIR)}")

    should_create_overlays = True # Set to False if you don't want videos

    command_analysis_df = baseball_tools.analyze_pitcher_command(
        csv_input_dir=ACTUAL_GLOVE_TRACKER_OUTPUT_DIR,   # Directory containing GloveTracker CSVs
        output_csv="pitcher_command_summary.csv",       # Main output CSV (saved in csv_input_dir)
        create_overlay=should_create_overlays,          # Generate overlay videos
        video_output_dir=VIDEO_OVERLAYS_DIR,            # Where to save overlay videos
        debug_mode=False,                               # True for more detailed logs/plots
        group_by_agg=['pitcher', 'pitch_type'],         # Columns for aggregate stats
        cmd_threshold_inches=6.0                        # Threshold for "commanded" pitch
    )

    if command_analysis_df is not None and not command_analysis_df.empty:
        print("\nCommand analysis complete!")
        print("Detailed results DataFrame (first 5 rows):")
        display(command_analysis_df.head())

        detailed_csv_path = os.path.join(ACTUAL_GLOVE_TRACKER_OUTPUT_DIR, "pitcher_command_summary.csv")
        aggregate_csv_path = os.path.join(ACTUAL_GLOVE_TRACKER_OUTPUT_DIR, "aggregate_pitcher_command_summary.csv")

        print(f"\nDetailed command CSV saved to: {os.path.abspath(detailed_csv_path)}")
        if os.path.exists(aggregate_csv_path):
            print(f"Aggregate command CSV saved to: {os.path.abspath(aggregate_csv_path)}")
        else:
            print(f"Aggregate command CSV not found at: {os.path.abspath(aggregate_csv_path)}")

        if should_create_overlays and os.path.exists(VIDEO_OVERLAYS_DIR) and len(os.listdir(VIDEO_OVERLAYS_DIR)) > 0:
            print(f"Overlay videos saved in: {os.path.abspath(VIDEO_OVERLAYS_DIR)}")
        elif should_create_overlays:
            print(f"Overlay videos were requested, but the directory '{VIDEO_OVERLAYS_DIR}' is empty or was not created.")
    else:
        print("\nCommand analysis did not produce results. This might be due to issues in the input CSVs, lack of Statcast data, or inability to determine intent frames.")
else:
    print("\nSkipping CommandAnalyzer because GloveTracker did not produce any CSVs in the expected directory or encountered an error.")